BSE: new features and update manual (#3781)

This commit is contained in:
Max Graml 2024-11-20 16:34:36 +01:00 committed by GitHub
parent 52af7ed493
commit 4dc10b3491
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 3600 additions and 876 deletions

View file

@ -10,60 +10,277 @@ input file of a BSE calculation and the corresponding output. For reviews on BSE
## 1. Theory and implementation of BSE
A central goal of a BSE calculation is to compute electronic excitation energies
$\Omega^{(n)}, n=1,2,\ldots$.
### 1.1 Electronic excitation energies and the excitation wave function
The following ingredients are necessary for computing $\Omega^{(n)}$:
A central goal of a BSE calculation is to compute excited state properties such as the electronic
excitation energies $\Omega^{(n)} (n=1,2,\ldots)$.
The following ingredients are necessary for such a computation:
- Occupied Kohn-Sham (KS) orbitals $\varphi_i(\mathbf{r})$ and empty KS orbitals
$\varphi_a(\mathbf{r})$ from a DFT calculation, where $i=1,\ldots,N_\mathrm{occ}$ and
$a=N_\mathrm{occ}+1,\ldots,N_\mathrm{occ}+N_\mathrm{empty}$,
- *GW* eigenvalues $\varepsilon_i^{GW}$ and $\varepsilon_a^{GW}$ of corresponding KS orbitals.
It is possible to use *G*<sub>0</sub>*W*<sub>0</sub>, ev*GW*<sub>0</sub> or ev*GW* eigenvalues, see
details in [GW] and in Ref. \[[](#Golze2019)\], i.e. we perform
BSE@*G*<sub>0</sub>*W*<sub>0</sub>/ev*GW*<sub>0</sub>/ev*GW*@DFT. Thus, also input parameters for a
DFT and *GW* calculation influence the BSE calcualation (see full input in Sec.
[3.1](#header-input-file)). We obtain optical properties from BSE solving the following generalized
It is possible to use *G*<sub>0</sub>*W*<sub>0 </sub>, ev*GW*<sub>0</sub> or ev*GW* eigenvalues, see
details in [GW] and in Ref. \[[](#Golze2019)\], i.e. we perform BSE@*G* <sub>0
</sub>*W*<sub>0</sub>/ev*GW*<sub>0</sub>/ev*GW*@DFT. Thus, also input parameters for a DFT and *GW*
calculation influence the BSE calculation (see full input in Sec. [3.1](#header-input-file)). We
obtain the properties of the excited states from the BSE by solving the following generalized
eigenvalue problem that involves the block matrix $ABBA$:
$$\left( \begin{array}{cc}A & B\\B & A\end{array} \right)\left( \begin{array}{cc}\mathbf{X}^{(n)}\\\mathbf{Y}^{(n)}\end{array} \right) = \Omega^{(n)}\left(\begin{array}{cc}1&0\\0&-1\end{array}\right)\left(\begin{array}{cc}\mathbf{X}^{(n)}\\\mathbf{Y}^{(n)}\end{array}\right) \quad .$$
$$
\left( \begin{array}{cc}A & B\\B & A\end{array} \right)\left( \begin{array}{cc}\mathbf{X}^{(n)}\\\mathbf{Y}^{(n)}\end{array} \right) = \Omega^{(n)}\left(\begin{array}{cc}1&0\\0&-1\end{array}\right)\left(\begin{array}{cc}\mathbf{X}^{(n)}\\\mathbf{Y}^{(n)}\end{array}\right) \quad .
$$
We abbreviate $A$ and $B$ as matrices with index $A_{ia,jb}$, i.e. they have
$N_\mathrm{occ}N_\mathrm{empty}$ rows and $N_\mathrm{occ}N_\mathrm{empty}$ columns. The entries of
$A$ and
$$ \begin{align}
$$
\begin{align}
A_{ia,jb} &= (\varepsilon_a^{GW}-\varepsilon_i^{GW})\delta_{ij}\delta_{ab} + \alpha^\mathrm{S/T}
v_{ia,jb} - W_{ij,ab}(\omega=0) \quad ,\\
B_{ia,jb} &= \alpha^\mathrm{(S/T)} v_{ia,bj} - W_{ib,aj}(\omega=0) \quad .
\end{align}$$
\end{align}
$$
where $\delta_{ij}$ is the Kronecker delta. The user sets $\alpha^S=2$ for computing singlet
excitations and $\alpha^T=0$ for computing triplet excitations. $v_{pq,rs}$ is the bare Coulomb
interaction and $W_{pq,rs}(\omega=0)$ the statically ($\omega=0$) screened Coulomb interaction ,
where $p,q,r,s \in [ 1, N_\mathrm{occ}+N_\mathrm{empty}]$ are KS orbital indices.
$(\mathbf{X}^{(n)},\mathbf{Y}^{(n)})$ with elements $X_{ia}^{(n)}$ and $Y_{ia}^{(n)}$ are the
eigenvectors of the excitation $n$ which relate to the wavefunction of the electronic excitation
\[[](#Blase2020)\],
interaction and $W_{pq,rs}(\omega=0)$ the statically ($\omega=0$) screened Coulomb interaction,
where $p,q,r,s \in [ 1, N_\mathrm{occ}+N_\mathrm{empty}]$ are KS orbital indices. Note here, that
the screened Coulomb interaction is always computed from DFT quantitites, i.e. $W_{0}(\omega=0)$
enters the BSE. $(\mathbf{X}^{(n)},\mathbf{Y}^{(n)})$ with elements $X_{ia}^{(n)}$ and
$Y_{ia}^{(n)}$ are the eigenvectors of the excitation $n$, which relate to the wave function of the
electronic excitation \[[](#Blase2020)\],
$$ \begin{align}
$$
\begin{align}
\Psi_\text{excitation}^{(n)}(\mathbf{r}_e,\mathbf{r}_h) = \sum_{ia} X_{ia}^{(n)} \varphi_i(\mathbf{r}_h) \varphi_a(\mathbf{r}_e) + Y_{ia}^{(n)} \varphi_i(\mathbf{r}_e) \varphi_a(\mathbf{r}_h) \quad ,
\end{align}$$
\end{align}
$$
i.e. $X_{ia}^{(n)}$ and $Y_{ia}^{(n)}$ describe the transition amplitude between occupied orbital
$\varphi_i$ and empty orbital $\varphi_a$ of the $n$-th excitation.
The Tamm-Dancoff approximation (TDA) is also implemented, which constrains $B=0$. In case $A$ is
positive definite, and excitation energies $\Omega^{(n)}>0$, we have $\mathbf{Y}=0$ and $\mathbf{X}$
can be computed from the Hermitian eigenvalue problem
The Tamm-Dancoff approximation (TDA) is also implemented, which constrains $B=0$ and
$\mathbf{Y}^{(n)}=0$. In TDA, $\Omega^{(n)}_\mathrm{TDA}$ and $\mathbf{X}^{(n)}_\mathrm{TDA}$ can be
computed from the Hermitian eigenvalue problem
$$ A \mathbf{X}^{(n)}_\mathbf{TDA} = \Omega^{(n)}_\mathbf{TDA} \mathbf{X}^{(n)}_\mathbf{TDA} \quad .$$
$$
A \mathbf{X}^{(n)}_\mathrm{TDA} = \Omega^{(n)}_\mathrm{TDA} \mathbf{X}^{(n)}_\mathrm{TDA} \quad .
$$
Diagonalizing $A$ in TDA, or the full block-matrix $ABBA$, takes in the order of
$(N_\mathrm{occ} N_\mathrm{empty})^3$ floating point operations. This translates to a computational
scaling of $O(N^6)$ in the system size $N$.
### 1.2 Optical properties
The BSE further allows the investigation of optical properties. For example, the optical absorption
spectrum can be computed as the imaginary part of the dynamical dipole polarizability tensor
$\alpha_{\mu,\mu'}(\omega) $ with $(\mu,\mu'\in\{x,y,z\})$:
$$
\begin{align}
\alpha_{\mu,\mu'}(\omega)
= \sum_n \frac{2 \Omega^{(n)} d^{(n)}_{\mu} d^{(n)}_{\mu'}}{(\omega+i\eta)^2-\left(\Omega^{(n)}\right)^2}
\quad ,
\end{align}
$$
where we have introduced an artificial broadening $\eta$. The transition moments $d^{(n)}_{\mu}$ are
computed in the length gauge $(\mu\in\{x,y,z\})$ as
$$
\begin{align}
d^{(n)}_{\mu} = \sqrt{2} \sum_{i,a} \langle \varphi_i|\hat{\mu}| \varphi_a \rangle (X_{ia}^{(n)} + Y_{ia}^{(n)})
\quad .
\end{align}
$$
When the molecules are not aligned, e.g. for gas phase and liquids, the spatial average is
sufficient, i.e. the optical absorption spectrum can be computed as
$$
\begin{align}
\mathrm{Im}\left[\bar{\alpha}(\omega)\right] = \frac{1}{3} \sum_{\mu\in\{x,y,z\}} \mathrm{Im}\left[\alpha_{\mu,\mu}(\omega)\right]
\quad .
\end{align}
$$
We can rewrite the last equation as
$$
\begin{align}
\mathrm{Im}\left[\bar{\alpha}(\omega)\right]
= \mathrm{Im}\left[
\sum_n \frac{f^{(n)}}{(\omega+i\eta)^2-\left(\Omega^{(n)}\right)^2}
\right]
\quad .
\end{align}
$$
where we introduced the oscillator strengths $f^{(n)}$, which are defined by
$$
\begin{align}
f^{(n)} = \frac{2}{3} \Omega^{(n)} \sum_{\mu\in\{x,y,z\}} | d^{(n)}_{\mu} |^2
\quad .
\end{align}
$$
### 1.3 Visualizing excited states using Natural Transition Orbitals (NTOs)
In order to represent the exciton wave function independent of a specific choice of the molecular
orbitals $\varphi_p(\mathbf{r})$, we can rewrite it as
$$
\begin{align}
\Psi_\text{excitation}^{(n)}(\mathbf{r}_e,\mathbf{r}_h) =
\sum_I {\lambda_I^{(n)}} \phi_I^{(n)}(\mathbf{r}_e) \chi_I^{(n)}(\mathbf{r}_h)
\quad .
\end{align}
$$
in terms of the natural transitions orbitals (NTOs) $\phi_I^{(n)}(\mathbf{r}_e) $ and
$\chi_I^{(n)}(\mathbf{r}_h)$. Here, we introduce the idea of electron and holes: In the excitation
process, an electron leaves a hole behind in the (formerly) occupied orbitals
$\chi_I^{(n)}(\mathbf{r}_h)$ and is afterwards located in the empty orbitals
$\phi_I^{(n)}(\mathbf{r}_e) $. We call $\phi_I^{(n)}(\mathbf{r}_e) $ and
$\chi_I^{(n)}(\mathbf{r}_h)$ a NTO pair of electron and hole with a weight $\lambda_I^{(n)}$, where
$I=1,\cdots,N_b$ with $N_b=N_\mathrm{occ}+N_\mathrm{empty}$.
The weights $\lambda_I^{(n)}$ are sorted in decreasing order, i.e.:
$$\lambda_1^{(n)} \ge \lambda_2^{(n)} \ge \cdots \ge 0$$
For many cases, we observe $\lambda_1^{(n)} \gg \lambda_2^{(n)}$, which indicates a dominant
single-particle excitation character for this $n$ and allows a visual analysis of a small number of
NTO pairs.
Assuming $\lambda_1^{(n)} = 1$ and $\lambda_{I\neq 1}=0$, the excitation wave function simply is
given as a product
$$
\begin{align}
\Psi_\text{excitation}^{(n)}(\mathbf{r}_e,\mathbf{r}_h) =
\phi_1^{(n)}(\mathbf{r}_e) \chi_1^{(n)}(\mathbf{r}_h)
\quad .
\end{align}
$$
In this case, the electron is excited from the occupied NTO $\chi_1^{(n)}(\mathbf{r}_h)$ to the
empty state $\phi_1^{(n)}(\mathbf{r}_e)$. This process leaves a hole at $\mathbf{r}_h$ and creates
an excited electron at $\mathbf{r}_e$.
Computationally, the NTO pairs $\phi_I^{(n)}(\mathbf{r}_e) $ and $\chi_I^{(n)}(\mathbf{r}_h)$ as
well as $\lambda_I^{(n)}$ are obtained by a singular value decomposition of the transition density
matrix
$$
T = \begin{pmatrix}
0 & {X}^{(n)}\\
\left({Y}^{(n)} \right)^T & 0
\end{pmatrix} \quad ,
$$
i.e.:
$$
\begin{align}
{T}^{(n)} &=
{U}^{(n)}
{\Lambda^{(n)}}
\left({V}^{(n)}\right)^T
\\
\phi_I^{(n)}(\mathbf{r}_e) &= \sum_{p=1}^{N_b} \varphi_p(\mathbf{r}_e) V_{p,I}^{(n)} \quad ,
\\
\chi_I^{(n)}(\mathbf{r}_h) &= \sum_{q=1}^{N_b} \varphi_q(\mathbf{r}_h) U_{q,I}^{(n)} \quad .
\end{align}
$$
### 1.4 Measures for the size of an excited state
In this subsection, we introduce several measures, which allow us to analyse the wave function of an
excited state $\Psi_\text{excitation}^{(n)}(\mathbf{r}_e,\mathbf{r}_h)$ and its spatial properties,
following Ref. \[[](#Mewes2018)\].
To that end, we define the exciton expectation value with respect to a generic operator $\hat{O}$ as
$$
\begin{align}
\langle \hat{O} \rangle _\text{exc}^{(n)}
=
\frac{
\langle \Psi_\text{excitation}^{(n)} | \hat{O} | \Psi_\text{excitation}^{(n)}\rangle
}{
\langle \Psi_\text{excitation}^{(n)} | \Psi_\text{excitation}^{(n)}\rangle
}
\quad ,
\end{align}
$$
where we drop the excitation index $n$ from now on for better readability.
For each excitation level $n$, we have then several quantities, which allow us to quantify the
spatial extend of the electron, the hole and their combined two-particle character as combined
electron-hole pair, i.e. as an exciton. By that, we can often determine the type of the excited
state, i.e. distinguish between, e.g., valence, Rydberg or charge-transfer states
\[[](#Mewes2018)\].
First, we define the distance between electron and hole as
$$
\begin{align}
d_{h \rightarrow e} = | \langle \mathbf{r}_h - \mathbf{r}_e \rangle_\mathrm{exc} | \quad ,
\end{align}
$$
which can be used to distinguish different classes of excitations: For example in a charge-transfer
state, electron and hole sit on different parts of the molecule and therefore have a non-vanishing
electron-hole distance $d_{h \rightarrow e}$.
Further, we can measure the size of electron and hole, respectively, as
$$
\begin{align}
\sigma_{e/h} = \sqrt{
\langle \mathbf{r}_{e/h}^2 \rangle_\mathrm{exc}
- \langle \mathbf{r}_{e/h} \rangle_\mathrm{exc} ^2
} \quad ,
\end{align}
$$
which allow us to distinguish between Rydberg states, where $\sigma_h \ll \sigma_e$, and valence
states, where $\sigma_h \approx \sigma_e$.
Closely related to these quantities, we can also define the exciton size
$$
\begin{align}
d_\mathrm{exc} = \sqrt{ \langle |\mathbf{r}_h - \mathbf{r}_e|^2 \rangle_\mathrm{exc} } \quad .
\end{align}
$$
which quantifies the spatial extent of the combined electron-hole pair. As one would expect, the
exciton size $d_\mathrm{exc}$ increases when $d_{h \rightarrow e}$, $\sigma_{e}$ or $\sigma_{h}$
increase.
Finally, we quantify the correlation of electron and hole by the electron-hole correlation
coefficient
$$
\begin{align}
R_{eh} = \frac{1}{\sigma_e \sigma_h} \left( \langle \mathbf{r}_h \cdot \mathbf{r}_e \rangle_\mathrm{exc}
- \langle \mathbf{r}_h \rangle_\mathrm{exc} \cdot \langle \mathbf{r}_e \rangle_\mathrm{exc} \right)
\quad ,
\end{align}
$$
which allows us to distinguish between correlated ($R_{eh}>0$) motion, i.e. bound excitons, and
anticorrelated ($R_{eh}<0$) motion, where electron and hole try to avoid each other.
(header-input)=
## 2. BSE input
@ -73,13 +290,22 @@ For starting a BSE calculation one needs to set the [RUN_TYPE](#CP2K_INPUT.GLOBA
```
&GW
SELF_CONSISTENCY G0W0 ! can be changed to EV_GW0 or EV_GW
SELF_CONSISTENCY evGW0 ! We strongly recommend to use evGW0 (and PBE) for BSE runs
&BSE
TDA TDA+ABBA ! Diagonalizing ABBA and A
SPIN_CONFIG SINGLET ! or TRIPLET
NUM_PRINT_EXC 20 ! Number of printed excitations
ENERGY_CUTOFF_OCC -1 ! Set to positive numbers (eV) to
ENERGY_CUTOFF_EMPTY -1 ! truncate matrices A_ia,jb and B_ia,jb
TDA TDA+ABBA ! Diagonalizing ABBA and A
SPIN_CONFIG SINGLET ! or TRIPLET
NUM_PRINT_EXC 15 ! Number of printed excitations
ENERGY_CUTOFF_OCC -1 ! Set to positive numbers (eV) to
ENERGY_CUTOFF_EMPTY -1 ! truncate matrices A_ia,jb and B_ia,jb
NUM_PRINT_EXC_DESCR -1 ! Number of printed exciton descriptors, -1 to default to NUM_PRINT_EXC
&BSE_SPECTRUM ! Activates computation and output of optical absorption spectrum
ETA_LIST 0.01 0.02 ! Multiple broadenings can be specified within one run
&END BSE_SPECTRUM
&NTO_ANALYSIS
STATE_LIST 1 2 ! List of states for which NTOs are computed
CUBE_FILES T ! Write cube files for NTOs
STRIDE 6 6 6 ! Coarse grid for smaller example cube files
&END NTO_ANALYSIS
&END BSE
&END GW
```
@ -89,7 +315,9 @@ In the upper GW/BSE section, the following keywords have been used:
- [SELF_CONSISTENCY](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.SELF_CONSISTENCY):
Determines which *GW* self-consistency (*G*<sub>0</sub>*W*<sub>0</sub>, ev*GW*<sub>0</sub> or
ev*GW*) is used to calculate the single-particle *GW* energies $\varepsilon_p^{GW}$ needed in the
BSE calculation.
BSE calculation. We recommend to always use ev*GW*<sub>0</sub> for BSE runs. The screened coulomb
interaction is always computed from the DFT level, i.e. $W_0(\omega=0)$ is used for the
$ABBA$-matrix, including BSE@ev*GW*@DFT.
- [TDA](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.TDA): Three options available:
@ -120,29 +348,61 @@ In the upper GW/BSE section, the following keywords have been used:
empty states in the interval
$\varepsilon_a\in[\varepsilon_{a=\text{LUMO}}^{GW},\varepsilon_{a=\text{LUMO}}^{GW}+E_\text{cut}^\text{empty}]$.
The following settings from DFT will also have an influence on the BSE excitation energies:
- [NUM_PRINT_EXC_DESCR](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.NUM_PRINT_EXC_DESCR):
Number of excitations, for which the exciton descriptors are printed.
- [BSE_SPECTRUM](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.BSE_SPECTRUM): Activates
computation and printing of the optical absorption spectrum. For each chosen option in
[TDA](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.TDA), a file is printed with
columns frequency $\omega$, $\mathrm{Im}\left[\bar{\alpha}(\omega)\right]$ and the imaginary part
of the elements of the dynamical dipole polarizability tensor
$\mathrm{Im}\left[{\alpha_{\mu,\mu'}}(\omega)\right]$. The frequency range, step size and the
broadening $\eta$ can be specified by the user (cf. keywords in
[BSE_SPECTRUM](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.BSE_SPECTRUM)). Further,
multiple broadenings $\eta$ can be given for one cp2k run
([ETA_LIST](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.BSE_SPECTRUM.ETA_LIST)),
resulting in one file per specified $\eta$ and
[TDA](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.TDA) (see Sec.
[3.2](#header-output)).
- [NTO_ANALYSIS](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.NTO_ANALYSIS): Activates
computation and printing of the natural transition orbitals. Within this section, the user can
specify the NTO pairs, which should be printed, e.g. by the excitation indices of the desired
levels $n$, their minimum oscillator strength $f^{(n)}$ or by the minimum weight of their NTO
coefficient $\lambda_I$. For each NTO pair $\phi_I^{(n)}(\mathbf{r}_e) $ and
$\chi_I^{(n)}(\mathbf{r}_h)$ of a certain excitation $n$, which fulfills these requirements, and
the chosen options in [TDA](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.TDA), the
NTO coefficients $\lambda_I$ are computed and the corresponding NTOs are printed to separate files
if
[CUBE_FILES](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.NTO_ANALYSIS.CUBE_FILES)
is activated.
The following settings from DFT will also have an influence on the BSE excitation energies and
optical properties:
- [XC_FUNCTIONAL](#CP2K_INPUT.FORCE_EVAL.DFT.XC.XC_FUNCTIONAL): Choose between one of the available
xc-functionals. The starting point can have a profound influence on the excitation energies
\[[Bruneval2015](#Bruneval2015), [](#Gui2018), [](#Jacquemin2017)\]. We either recommend the PBE
functional as DFT starting point when using BSE@ev*GW*<sub>0</sub>@PBE or the PBE0 functional,
when using BSE@*G*<sub>0</sub>*W*<sub>0</sub>@PBE0 (see also
\[[](#Knysh2024)\]. Motivated by the discussion in \[[](#Schambeck2024)\], we strongly recommend
to use BSE@ev*GW*<sub>0</sub>@PBE, i.e. the PBE functional as DFT starting point (see also
[SELF_CONSISTENCY](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.SELF_CONSISTENCY)).
- [BASIS_SET](#CP2K_INPUT.FORCE_EVAL.SUBSYS.KIND.BASIS_SET): Specify the basis set, which affects
$N_\mathrm{empty}$ and thus the size of the matrices $A_{ia,jb}$ and $B_{ia,jb}$. The
<a href="https://www.basissetexchange.org/basis/aug-cc-pvdz/format/cp2k/?version=1&elements=1" target="_blank">`aug-cc-pVDZ`</a>
basis set should be sufficient for most calculations, but needs to be checked regarding
convergence, e.g. using
<a href="https://www.basissetexchange.org/basis/aug-cc-pvtz/format/cp2k/?version=1&elements=1" target="_blank">`aug-cc-pVTZ`</a>.
<a href="https://www.basissetexchange.org/basis/aug-cc-pvtz/format/cp2k/?version=1&elements=1" target="_blank">`aug-cc-pVTZ`</a>
.
The memory consumption of the BSE algorithm is large, it is approximately
$100 \cdot N_\mathrm{occ}^2 N_\mathrm{empty}^2$ Bytes. You can see $N_\mathrm{occ}$,
$N_\mathrm{empty}$ and the estimated memory consumption from the BSE output. The BSE implementation
is well parallelized, i.e. you can use several nodes that can provide the memory.
We have benchmarked the numerical precision of our BSE implementation and we found excellent
agreement within only 10 meV compared to the BSE implementation in FHI aims \[[](#Liu2020)\].
We have benchmarked the numerical precision of our BSE implementation and compared its results to
the BSE implementation in FHI aims \[[](#Liu2020)\]. For our recommended settings, i.e.
BSE@ev*GW*<sub>0</sub>@PBE with the aug-cc-pVDZ basis set, we have found excellent agreement with
less than 5 meV mean absolute deviation over the first 10 excitation levels and the 28 molecules in
*Thiel's set*.
The current BSE implementation in CP2K works for molecules. The inclusion of periodic boundary
conditions in a Γ-only approach and with full *k*-point sampling is work in progress.
@ -156,7 +416,7 @@ conditions in a Γ-only approach and with full *k*-point sampling is work in pro
### 3.1 Input file
In this section, we provide a minimal example of a BSE calculation on H<sub>2</sub>. For the
calculation you need the input file BSE_H2.inp and the aug-cc-DZVP basis
calculation you need the input file BSE_H2.inp and the aug-cc-pVDZ basis
([Download](https://github.com/cp2k/cp2k-examples/tree/master/bethe-salpeter/H2)).
Please copy both files into your working directory and run CP2K by
@ -165,82 +425,165 @@ Please copy both files into your working directory and run CP2K by
mpirun -n 1 cp2k.psmp BSE_H2.inp
```
which requires 12 GB RAM and takes roughly 2 minutes on 1 core. You can find the input and output
which requires 5 GB RAM and takes roughly 45 seconds on 1 core. You can find the input and output
file [here](https://github.com/cp2k/cp2k-examples/tree/master/bethe-salpeter/H2). We use the basis
sets `aug-cc-pVDZ` and `aug-cc-pVDZ-RIFIT` from the file `BASIS-aug`. These basis sets can be
obtained from the Basis Set Exchange Library:
<a href="https://www.basissetexchange.org/basis/aug-cc-pvdz/format/cp2k/?version=1&elements=1" target="_blank">aug-cc-pVDZ</a>,
<a href="https://www.basissetexchange.org/basis/aug-cc-pvdz-rifit/format/cp2k/?version=1&elements=1" target="_blank">aug-cc-pVDZ-RIFIT</a>.
<a href="https://www.basissetexchange.org/basis/aug-cc-pvdz/format/cp2k/?version=1&elements=1" target="_blank">`aug-cc-pVDZ`</a>,
<a href="https://www.basissetexchange.org/basis/aug-cc-pvdz-rifit/format/cp2k/?version=1&elements=1" target="_blank">`aug-cc-pVDZ-RIFIT`</a>.
The geometry for H<sub>2</sub> was taken from \[[](#vanSetten2015)\].
(header-output)=
### 3.2 Output
The BSE calculation outputs the excitation energies $\Omega^{(n)}$ for *n* = 1, ...,
$N_\text{exc}^\text{print}$:
```none
BSE| Excitation energies from solving the BSE without the TDA:
BSE|
BSE| Excitation n Multiplet TDA/full BSE Excitation energy Ω (eV)
BSE| 1 Singlet State -full- 11.8621
BSE| 2 Singlet State -full- 12.8264
BSE| 3 Singlet State -full- 15.6415
BSE| 4 Singlet State -full- 15.6415
BSE| Excitation energies from solving the BSE without the TDA:
BSE|
BSE| Excitation n Spin Config TDA/ABBA Excitation energy Ω^n (eV)
BSE| 1 Singlet -ABBA- 12.0361
BSE| 2 Singlet -ABBA- 13.0327
BSE| 3 Singlet -ABBA- 15.8729
BSE| 4 Singlet -ABBA- 15.8729
```
Afterwards, the single-particle transitions, i.e. the eigenvector elements $X_{ia}^{(n)}$, with
$|X_{ia}^{(n)}|$ > [EPS_X](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.EPS_X), are
printed:
Afterwards, the single-particle transitions, i.e. the eigenvector elements $X_{ia}^{(n)}$ and
$Y_{ia}^{(n)}$, with $|X_{ia}^{(n)}|$ >
[EPS_X](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.EPS_X) or $|Y_{ia}^{(n)}|$ >
[EPS_X](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.EPS_X), are printed. The third
column is either
- $\Rightarrow$: for excitations, i.e. entries of X_ia^n, or
- $\Leftarrow$: for deexcitations, i.e. entries of Y_ia^n.
```none
BSE| Excitations are built up by the following single-particle transitions,
BSE| neglecting contributions where |X_ia^n| < 0.10 :
BSE| -- Quick reminder: HOMO i = 1 and LUMO a = 2 --
BSE|
BSE| Excitation n i => a TDA/full BSE |X_ia^n|
BSE|
BSE| 1 1 => 2 -full- 0.6630
BSE| 1 1 => 4 -full- 0.2549
BSE|
BSE| 2 1 => 3 -full- 0.7059
BSE|
BSE| 3 1 => 6 -full- 0.7076
BSE|
BSE| 4 1 => 5 -full- 0.7076
BSE| The following single-particle transitions have significant contributions,
BSE| i.e. |X_ia^n| > 0.100 or |Y_ia^n| > 0.100, respectively :
BSE| -- Quick reminder: HOMO i = 1 and LUMO a = 2 --
BSE|
BSE| Excitation n i =>/<= a TDA/ABBA |X_ia^n|/|Y_ia^n|
BSE|
BSE| 1 1 => 2 -ABBA- 0.6687
BSE| 1 1 => 4 -ABBA- 0.2431
BSE|
BSE| 2 1 => 3 -ABBA- 0.7061
BSE|
BSE| 3 1 => 5 -ABBA- 0.7077
BSE|
BSE| 4 1 => 6 -ABBA- 0.7077
```
In the case of H<sub>2</sub>, the lowest excitation *n* = 1 is mainly built up by a transition from
the HOMO (i=1) to the LUMO (a=2), what is apparent from
$X_{i=\text{HOMO},a=\text{LUMO}}^{(n=1)}=0.663$, and also contains a considerable contribution from
the 1=>4 (HOMO=>LUMO+2) transition ($X_{i=\text{HOMO},a=\text{LUMO+2}}^{(n=1)}=0.2549$ ).
$X_{i=\text{HOMO},a=\text{LUMO}}^{(n=1)}= 0.6687$, and also contains a considerable contribution
from the 1=>4 (HOMO=>LUMO+2) transition ($X_{i=\text{HOMO},a=\text{LUMO+2}}^{(n=1)}=0.2431$ ).
In the next section, the optical properties, i.e. the transition moments $d^{(n)}_{r}$ and the
oscillator strengths $f^{(n)}$, are printed:
```none
BSE| Optical properties from solving the BSE without the TDA:
BSE|
BSE| Excitation n TDA/ABBA d_x^n d_y^n d_z^n Osc. strength f^n
BSE| 1 -ABBA- 0.000 -0.000 -1.191 0.418
BSE| 2 -ABBA- 0.000 0.000 0.000 0.000
BSE| 3 -ABBA- -0.836 0.713 -0.000 0.469
BSE| 4 -ABBA- -0.713 -0.836 -0.000 0.469
```
We can see that $n=1,3,4$ are optically active since they have a nonzero oscillator strength
$f^{(n)}$.
In case [BSE_SPECTRUM](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.BSE_SPECTRUM) is
invoked, the frequency-resolved optical absorption spectrum is printed in addition. For each
specified $\eta$ in
[ETA_LIST](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.BSE_SPECTRUM.ETA_LIST), a
separate file, e.g. `BSE-ABBA-eta=0.010.spectrum`, is created, which starts with
```none
# Imaginary part of polarizability α_{µ µ'}(ω) = \sum_n [2 Ω^n d_µ^n d_µ'^n] / [(ω+iη)²- (Ω^n)²] from Bethe Salpeter equation for method -ABBA-
# Frequency (eV) Im{α_{avg}(ω)} Im{α_xx(ω)} Im{α_xy(ω)} Im{α_xz(ω)} Im{α_yx(ω)} Im{α_yy(ω)} Im{α_yz(ω)} Im{α_zx(ω)} Im{α_zy(ω)} Im{α_zz(ω)}
0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
0.10000000 0.00005283 0.00003298 -0.00000000 0.00000000 -0.00000000 0.00003298 0.00000000 0.00000000 0.00000000 0.00009251
```
The next table summarizes some of the exciton descriptors of each excitation level $n$:
```none
BSE| Exciton descriptors from solving the BSE without the TDA:
BSE|
BSE| n c_n d_eh [Å] σ_e [Å] σ_h [Å] d_exc [Å] R_eh
BSE| 1 1.026 0.0000 2.0542 0.8576 2.2521 -0.0176
BSE| 2 1.004 0.0000 2.9922 0.8578 3.1127 -0.0000
BSE| 3 1.005 0.0000 1.5859 0.8568 1.8134 -0.0077
BSE| 4 1.005 0.0000 1.5859 0.8568 1.8134 -0.0077
```
where we obtain the normalization factor
$c_n = \langle \Psi_\text{excitation}^{(n)} | \Psi_\text{excitation}^{(n)}\rangle $, the vectorial
distance between electron and hole $d_{e\rightarrow h}$, sizes of electron $\sigma_e$ and hole
$\sigma_h$, the exciton size $d_\mathrm{exc}$ and the electron-hole correlation coefficient
$R_{eh}$.
Further, the expectation values $\langle \mathbf{r}_e \rangle_\mathrm{exc}$ and
$\langle \mathbf{r}_h \rangle_\mathrm{exc}$ as well as the reference point of origin and the atomic
geometry are printed.
The last section summarizes the characteristics of the NTO analysis:
```none
BSE| Number of excitations, for which NTOs are computed 2
BSE| Threshold for oscillator strength f^n ---
BSE| Threshold for NTO weights (λ_I)^2 0.010
BSE|
BSE| NTOs from solving the BSE without the TDA:
BSE|
BSE| Excitation n TDA/ABBA Index of NTO I NTO weights (λ_I)^2
BSE|
BSE| 1 -ABBA- 1 1.01320
BSE| 1 -ABBA- 2 0.01320
BSE|
BSE| 2 -ABBA- 1 1.00210
```
In the input file, we have specified a list of three excitation levels, no constraint on the
oscillator strengths $f^{(n)}$ and used the default threshold on the weights, given by
$\lambda_I^2 \leq 0.010$, which is repeated at the beginning of the section. Therefore, we obtain
two NTO pairs for $n=1$ with significant weight and one NTO pair for $n=2$ and $n=8$, respectively.
For $n=1$, we can verify that the NTO weights satisfy
$1.01320 + 0.01320 \approx \sum_I {\left( \lambda_I^{(n)}\right)}^2 = c_n \approx 1.026$ when
comparing to the output of the exciton descriptor section.
### 3.3 Large scale calculations
Going to larger systems is a challenge for a *GW*+BSE-calculation, since the memory consumption
increases with $N_\mathrm{occ}^2 N_\mathrm{empty}^2$. The used $N_\mathrm{occ}$, $N_\mathrm{empty}$
and the required memory of a calculation are printed in the output file to estimate the memory
consumption. We recommend to use several nodes to provide the required memory. In the following, we
provide a sample output of a BSE calculation on a nanographene with 206 atoms which has a memory
requirement of 2.2 TB RAM:
consumption. [Here](https://github.com/cp2k/cp2k-examples/tree/master/bethe-salpeter/Nanographene),
you can find a sample output of a BSE@evGW0@PBE calculation on a nanographene with 206 atoms, which
has a peak memory requirement of 2.5 TB RAM:
```none
BSE| Cutoff occupied orbitals [eV] 80.000
BSE| Cutoff empty orbitals [eV] 10.000
BSE| First occupied index 155
BSE| Last empty index (not MO index!) 517
BSE| Energy of first occupied index [eV] -24.774
BSE| Energy of last empty index [eV] 7.863
BSE| Energy difference of first occupied index to HOMO [eV] 19.487
BSE| Energy difference of last empty index to LUMO [eV] 9.639
BSE| Number of GW-corrected occupied MOs 400
BSE| Number of GW-corrected empty MOs 600
BSE|
BSE| Total peak memory estimate from BSE [GB] 2221.591
BSE| Peak memory estimate per MPI rank from BSE [GB] 4.628
BSE| Cutoff occupied orbitals [eV] 80.000
BSE| Cutoff empty orbitals [eV] 10.000
BSE| First occupied index 155
BSE| Last empty index (not MO index!) 324
BSE| Energy of first occupied index [eV] -25.080
BSE| Energy of last empty index [eV] 9.632
BSE| Energy difference of first occupied index to HOMO [eV] 20.289
BSE| Energy difference of last empty index to LUMO [eV] 10.549
BSE| Number of GW-corrected occupied MOs 334
BSE| Number of GW-corrected empty MOs 324
BSE|
BSE| Total peak memory estimate from BSE [GB] 8.725E+02
BSE| Peak memory estimate per MPI rank from BSE [GB] 5.453
```
To enable BSE calculations on large molecules, we recommend to use a large supercomputer and setting
the keywords
To enable BSE calculations on large molecules, we recommend to use large clusters with increased RAM
and explicitly setting the keywords
[ENERGY_CUTOFF_OCC](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.ENERGY_CUTOFF_OCC)
and
[ENERGY_CUTOFF_EMPTY](#CP2K_INPUT.FORCE_EVAL.DFT.XC.WF_CORRELATION.RI_RPA.GW.BSE.ENERGY_CUTOFF_EMPTY),

View file

@ -72,6 +72,8 @@ list(
bse_main.F
bse_full_diag.F
bse_iterative.F
bse_print.F
bse_properties.F
bse_util.F
bsse.F
cell_methods.F

View file

@ -13,11 +13,18 @@
! **************************************************************************************************
MODULE bse_full_diag
USE bse_print, ONLY: print_excitation_energies,&
print_exciton_descriptors,&
print_optical_properties,&
print_output_header,&
print_transition_amplitudes
USE bse_properties, ONLY: calculate_NTOs,&
exciton_descr_type,&
get_exciton_descriptors,&
get_oscillator_strengths
USE bse_util, ONLY: comp_eigvec_coeff_BSE,&
compute_absorption_spectrum,&
fm_general_add_bse,&
get_oscillator_strengths,&
print_transition_probabilities
get_multipoles_mo
USE cp_blacs_env, ONLY: cp_blacs_env_create,&
cp_blacs_env_release,&
cp_blacs_env_type
@ -39,7 +46,6 @@ MODULE bse_full_diag
USE message_passing, ONLY: mp_para_env_type
USE mp2_types, ONLY: mp2_type
USE parallel_gemm_api, ONLY: parallel_gemm
USE physcon, ONLY: evolt
USE qs_environment_types, ONLY: qs_environment_type
#include "./base/base_uses.f90"
@ -100,12 +106,12 @@ CONTAINS
CALL timeset(routineN, handle)
IF (unit_nr > 0 .AND. mp2_env%ri_g0w0%bse_debug_print) THEN
IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
WRITE (unit_nr, '(T2,A10,T13,A10)') 'BSE|DEBUG|', 'Creating A'
END IF
!Determines factor of exchange term, depending on requested spin configuration (cf. input_constants.F)
SELECT CASE (mp2_env%ri_g0w0%bse_spin_config)
SELECT CASE (mp2_env%bse%bse_spin_config)
CASE (bse_singlet)
alpha = 2.0_dp
CASE (bse_triplet)
@ -138,7 +144,7 @@ CONTAINS
matrix_a=fm_mat_S_ia_bse, matrix_b=fm_mat_S_ia_bse, beta=0.0_dp, &
matrix_c=fm_A)
IF (unit_nr > 0 .AND. mp2_env%ri_g0w0%bse_debug_print) THEN
IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
WRITE (unit_nr, '(T2,A10,T13,A16)') 'BSE|DEBUG|', 'Allocated A_iajb'
END IF
@ -147,7 +153,7 @@ CONTAINS
matrix_a=fm_mat_S_bar_ij_bse, matrix_b=fm_mat_S_ab_bse, beta=0.0_dp, &
matrix_c=fm_W)
IF (unit_nr > 0 .AND. mp2_env%ri_g0w0%bse_debug_print) THEN
IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
WRITE (unit_nr, '(T2,A10,T13,A16)') 'BSE|DEBUG|', 'Allocated W_ijab'
END IF
@ -227,12 +233,12 @@ CONTAINS
CALL timeset(routineN, handle)
IF (unit_nr > 0 .AND. mp2_env%ri_g0w0%bse_debug_print) THEN
IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
WRITE (unit_nr, '(T2,A10,T13,A10)') 'BSE|DEBUG|', 'Creating B'
END IF
! Determines factor of exchange term, depending on requested spin configuration (cf. input_constants.F)
SELECT CASE (mp2_env%ri_g0w0%bse_spin_config)
SELECT CASE (mp2_env%bse%bse_spin_config)
CASE (bse_singlet)
alpha = 2.0_dp
CASE (bse_triplet)
@ -247,7 +253,7 @@ CONTAINS
CALL cp_fm_create(fm_W, fm_struct_v, name="fm_W_ibaj")
CALL cp_fm_set_all(fm_W, 0.0_dp)
IF (unit_nr > 0 .AND. mp2_env%ri_g0w0%bse_debug_print) THEN
IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
WRITE (unit_nr, '(T2,A10,T13,A16)') 'BSE|DEBUG|', 'Allocated B_iajb'
END IF
! v_ia,jb = \sum_P B^P_ia B^P_jb
@ -335,7 +341,7 @@ CONTAINS
CALL cp_fm_create(fm_work_product, fm_A%matrix_struct)
IF (unit_nr > 0 .AND. mp2_env%ri_g0w0%bse_debug_print) THEN
IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
WRITE (unit_nr, '(T2,A10,T13,A19)') 'BSE|DEBUG|', 'Created work arrays'
END IF
@ -385,7 +391,7 @@ CONTAINS
fm_C)
CALL cp_fm_release(fm_work_product)
IF (unit_nr > 0 .AND. mp2_env%ri_g0w0%bse_debug_print) THEN
IF (unit_nr > 0 .AND. mp2_env%bse%bse_debug_print) THEN
WRITE (unit_nr, '(T2,A10,T13,A36)') 'BSE|DEBUG|', 'Filled C=(A-B)^0.5 (A+B) (A-B)^0.5'
END IF
@ -469,6 +475,7 @@ CONTAINS
matrix_a=fm_sqrt_A_minus_B, matrix_b=fm_eigvec_Z, beta=0.0_dp, &
matrix_c=fm_mat_eigvec_transform_sum)
CALL cp_fm_release(fm_sqrt_A_minus_B)
! This normalizes the eigenvectors
CALL comp_eigvec_coeff_BSE(fm_mat_eigvec_transform_sum, Exc_ens, -0.5_dp, gamma=2.0_dp, do_transpose=.TRUE.)
! Second, Eq. II from (A10) from Furche: (X-Y)_n = (Ω_n)^0.5 (A-B)^-0.5 T_n
@ -479,6 +486,8 @@ CONTAINS
matrix_c=fm_mat_eigvec_transform_diff)
CALL cp_fm_release(fm_inv_sqrt_A_minus_B)
CALL cp_fm_release(fm_eigvec_Z)
! This normalizes the eigenvectors
CALL comp_eigvec_coeff_BSE(fm_mat_eigvec_transform_diff, Exc_ens, 0.5_dp, gamma=2.0_dp, do_transpose=.TRUE.)
! Now, we add the two equations to obtain X_n
@ -497,7 +506,7 @@ CONTAINS
CALL cp_fm_release(fm_mat_eigvec_transform_diff)
CALL cp_fm_release(fm_mat_eigvec_transform_sum)
CALL success_message(Exc_ens, fm_eigvec_X, mp2_env, qs_env, mo_coeff, &
CALL postprocess_bse(Exc_ens, fm_eigvec_X, mp2_env, qs_env, mo_coeff, &
homo, virtual, homo_irred, unit_nr, &
.FALSE., fm_eigvec_Y)
@ -553,7 +562,7 @@ CONTAINS
CALL choose_eigv_solver(fm_A, fm_eigvec, Exc_ens, diag_info)
CPASSERT(diag_info == 0)
CALL success_message(Exc_ens, fm_eigvec, mp2_env, qs_env, mo_coeff, &
CALL postprocess_bse(Exc_ens, fm_eigvec, mp2_env, qs_env, mo_coeff, &
homo, virtual, homo_irred, unit_nr, .TRUE.)
CALL cp_fm_release(fm_eigvec)
@ -577,7 +586,7 @@ CONTAINS
!> \param flag_TDA ...
!> \param fm_eigvec_Y ...
! **************************************************************************************************
SUBROUTINE success_message(Exc_ens, fm_eigvec_X, mp2_env, qs_env, mo_coeff, &
SUBROUTINE postprocess_bse(Exc_ens, fm_eigvec_X, mp2_env, qs_env, mo_coeff, &
homo, virtual, homo_irred, unit_nr, &
flag_TDA, fm_eigvec_Y)
@ -590,18 +599,23 @@ CONTAINS
LOGICAL, OPTIONAL :: flag_TDA
TYPE(cp_fm_type), INTENT(IN), OPTIONAL :: fm_eigvec_Y
CHARACTER(LEN=*), PARAMETER :: routineN = 'success_message'
CHARACTER(LEN=*), PARAMETER :: routineN = 'postprocess_bse'
CHARACTER(LEN=10) :: info_approximation, multiplet
INTEGER :: handle, i_exc
INTEGER :: handle, idir, n_moments_di, &
n_moments_quad
REAL(KIND=dp) :: alpha
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: oscill_str
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: dipole_exc
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: oscill_str, ref_point_multipole
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: polarizability_residues, trans_mom_bse
TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: fm_dipole_ab_trunc, fm_dipole_ai_trunc, &
fm_dipole_ij_trunc, fm_quadpole_ab_trunc, fm_quadpole_ai_trunc, fm_quadpole_ij_trunc
TYPE(exciton_descr_type), ALLOCATABLE, &
DIMENSION(:) :: exc_descr
CALL timeset(routineN, handle)
!Prepare variables for printing
IF (mp2_env%ri_g0w0%bse_spin_config == 0) THEN
IF (mp2_env%bse%bse_spin_config == 0) THEN
multiplet = "Singlet"
alpha = 2.0_dp
ELSE
@ -617,190 +631,97 @@ CONTAINS
info_approximation = "-ABBA-"
END IF
!Get information about eigenvector
n_moments_di = 3
n_moments_quad = 9
! Compute BSE dipoles and oscillator strengths - Keep in memory for later usage
! Need dipoles also for spatial expectation values, which are well-defined also for triplets
ALLOCATE (fm_dipole_ij_trunc(n_moments_di))
ALLOCATE (fm_dipole_ab_trunc(n_moments_di))
ALLOCATE (fm_dipole_ai_trunc(n_moments_di))
ALLOCATE (ref_point_multipole(3))
! Obtain dipoles in MO basis
CALL get_multipoles_mo(fm_dipole_ai_trunc, fm_dipole_ij_trunc, fm_dipole_ab_trunc, &
qs_env, mo_coeff, ref_point_multipole, 1, &
homo, virtual, fm_eigvec_X%matrix_struct%context)
! Compute exciton descriptors from these multipoles
IF (mp2_env%bse%num_print_exc_descr > 0) THEN
! Obtain quadrupoles in MO basis
ALLOCATE (fm_quadpole_ij_trunc(n_moments_quad))
ALLOCATE (fm_quadpole_ab_trunc(n_moments_quad))
ALLOCATE (fm_quadpole_ai_trunc(n_moments_quad))
CALL get_multipoles_mo(fm_quadpole_ai_trunc, fm_quadpole_ij_trunc, fm_quadpole_ab_trunc, &
qs_env, mo_coeff, ref_point_multipole, 2, &
homo, virtual, fm_eigvec_X%matrix_struct%context)
CALL get_exciton_descriptors(exc_descr, fm_eigvec_X, &
fm_dipole_ij_trunc, fm_dipole_ab_trunc, fm_dipole_ai_trunc, &
fm_quadpole_ij_trunc, fm_quadpole_ab_trunc, &
homo, virtual, unit_nr, &
mp2_env, qs_env, &
fm_eigvec_Y)
END IF
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
IF (flag_TDA) THEN
WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '**************************************************************************'
WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '* Bethe Salpeter equation (BSE) with Tamm Dancoff approximation (TDA) *'
WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '**************************************************************************'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A48,A23)') 'BSE|', 'The excitations are calculated by diagonalizing ', &
'the BSE within the TDA:'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T29,A16)') 'BSE|', 'A X^n = Ω^n X^n'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A23)') 'BSE|', 'i.e. in index notation:'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A41)') 'BSE|', 'sum_jb ( A_ia,jb X_jb^n ) = Ω^n X_ia^n'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A30)') 'BSE|', 'prelim Ref.: Eq. (36) with B=0'
WRITE (unit_nr, '(T2,A4,T7,A71)') 'BSE|', 'in PRB 92,045209 (2015); http://dx.doi.org/10.1103/PhysRevB.92.045209 .'
ELSE
WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '**************************************************************************'
WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '* Full ("ABBA") Bethe Salpeter equation (BSE) (i.e. without TDA) *'
WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '**************************************************************************'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A48,A24)') 'BSE|', 'The excitations are calculated by diagonalizing ', &
'the BSE without the TDA:'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T22,A30)') 'BSE|', '|A B| |X^n| |1 0| |X^n|'
WRITE (unit_nr, '(T2,A4,T22,A31)') 'BSE|', '|B A| |Y^n| = Ω^n |0 -1| |Y^n|'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A23)') 'BSE|', 'i.e. in index notation:'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A62)') 'BSE|', ' sum_jb ( A_ia,jb X_jb^n + B_ia,jb Y_jb^n ) = Ω^n X_ia^n'
WRITE (unit_nr, '(T2,A4,T7,A62)') 'BSE|', '- sum_jb ( B_ia,jb X_jb^n + A_ia,jb Y_jb^n ) = Ω^n Y_ia^n'
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A4,T18,A42,T70,A1,I4,A1,I4,A1)') 'BSE|', 'i,j:', &
'occupied molecular orbitals, i.e. state in', '[', homo_irred - homo + 1, ',', homo_irred, ']'
WRITE (unit_nr, '(T2,A4,T7,A4,T18,A44,T70,A1,I4,A1,I4,A1)') 'BSE|', 'a,b:', &
'unoccupied molecular orbitals, i.e. state in', '[', homo_irred + 1, ',', homo_irred + virtual, ']'
WRITE (unit_nr, '(T2,A4,T7,A2,T18,A16)') 'BSE|', 'n:', 'Excitation index'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A58)') 'BSE|', 'A_ia,jb = (ε_a-ε_i) δ_ij δ_ab + α * v_ia,jb - W_ij,ab'
IF (.NOT. flag_TDA) THEN
WRITE (unit_nr, '(T2,A4,T7,A32)') 'BSE|', 'B_ia,jb = α * v_ia,jb - W_ib,aj'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A35)') 'BSE|', 'prelim Ref.: Eqs. (24-27),(30),(35)'
WRITE (unit_nr, '(T2,A4,T7,A71)') 'BSE|', 'in PRB 92,045209 (2015); http://dx.doi.org/10.1103/PhysRevB.92.045209 .'
END IF
IF (.NOT. flag_TDA) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', 'The BSE is solved for Ω^n and X_ia^n as a hermitian problem, e.g. Eq.(42)'
WRITE (unit_nr, '(T2,A4,T7,A71)') 'BSE|', 'in PRB 92,045209 (2015); http://dx.doi.org/10.1103/PhysRevB.92.045209 .'
! WRITE (unit_nr, '(T2,A4,T7,A69)') 'BSE|', 'C_ia,jb = sum_kc,ld ((A-B)^0.5)_ia,kc (A+B)_kc,ld ((A-B)^0.5)_ld,jb'
! WRITE (unit_nr, '(T2,A4)') 'BSE|'
! WRITE (unit_nr, '(T2,A4,T7,A58)') 'BSE|', '(X+Y)_ia,n = sum_jb,m ((A-B)^0.5)ia,jb Z_jb,m (Ω_m)^-0.5'
! WRITE (unit_nr, '(T2,A4,T7,A58)') 'BSE|', '(X-Y)_ia,n = sum_jb,m ((A-B)^-0.5)ia,jb Z_jb,m (Ω_m)^0.5'
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A7,T19,A23)') 'BSE|', 'ε_...:', 'GW quasiparticle energy'
WRITE (unit_nr, '(T2,A4,T7,A7,T19,A15)') 'BSE|', 'δ_...:', 'Kronecker delta'
WRITE (unit_nr, '(T2,A4,T7,A3,T19,A21)') 'BSE|', 'α:', 'spin-dependent factor (Singlet/Triplet)'
WRITE (unit_nr, '(T2,A4,T7,A6,T18,A34)') 'BSE|', 'v_...:', 'Electron-hole exchange interaction'
WRITE (unit_nr, '(T2,A4,T7,A6,T18,A27)') 'BSE|', 'W_...:', 'Screened direct interaction'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A47,A7,A9,F3.1)') 'BSE|', &
'The spin-dependent factor is for the requested ', multiplet, " is α = ", alpha
WRITE (unit_nr, '(T2,A4)') 'BSE|'
IF (flag_TDA) THEN
WRITE (unit_nr, '(T2,A4,T7,A56)') 'BSE|', 'Excitation energies from solving the BSE within the TDA:'
ELSE
WRITE (unit_nr, '(T2,A4,T7,A57)') 'BSE|', 'Excitation energies from solving the BSE without the TDA:'
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T11,A12,T26,A11,T44,A8,T55,A27)') 'BSE|', &
'Excitation n', "Spin Config", 'TDA/ABBA', 'Excitation energy Ω^n (eV)'
IF (mp2_env%bse%bse_spin_config == 0) THEN
CALL get_oscillator_strengths(fm_eigvec_X, Exc_ens, fm_dipole_ai_trunc, &
trans_mom_bse, oscill_str, polarizability_residues, &
mp2_env, homo, virtual, unit_nr, &
fm_eigvec_Y)
END IF
!prints actual energies values
IF (unit_nr > 0) THEN
DO i_exc = 1, MIN(homo*virtual, mp2_env%ri_g0w0%num_print_exc)
WRITE (unit_nr, '(T2,A4,T7,I16,T30,A7,T46,A6,T59,F22.4)') &
'BSE|', i_exc, multiplet, info_approximation, Exc_ens(i_exc)*evolt
END DO
END IF
!prints single particle transitions
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A61)') &
'BSE|', "Single-particle transitions are built up by (de-)excitations,"
WRITE (unit_nr, '(T2,A4,T7,A18)') &
'BSE|', "which we denote by"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T20,A2,T30,A40)') &
'BSE|', "=>", "for excitations, i.e. entries of X_ia^n,"
WRITE (unit_nr, '(T2,A4,T20,A2,T30,A42)') &
'BSE|', "<=", "for deexcitations, i.e. entries of Y_ia^n."
WRITE (unit_nr, '(T2,A4)') &
'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A73)') &
'BSE|', "The following single-particle transitions have significant contributions,"
WRITE (unit_nr, '(T2,A4,T7,A16,F5.3,A15,F5.3,A16)') &
'BSE|', "i.e. |X_ia^n| < ", mp2_env%ri_g0w0%eps_x, " or |Y_ia^n| < ", &
mp2_env%ri_g0w0%eps_x, ", respectively :"
WRITE (unit_nr, '(T2,A4,T15,A27,I5,A13,I5,A3)') 'BSE|', '-- Quick reminder: HOMO i =', &
homo_irred, ' and LUMO a =', homo_irred + 1, " --"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A12,T30,A1,T32,A5,T42,A1,T49,A8,T64,A17)') &
"BSE|", "Excitation n", "i", "=>/<=", "a", 'TDA/ABBA', "|X_ia^n|/|Y_ia^n|"
! Prints basic definitions used in BSE calculation
CALL print_output_header(homo, virtual, homo_irred, flag_TDA, &
multiplet, alpha, unit_nr)
! Prints excitation energies up to user-specified number
CALL print_excitation_energies(Exc_ens, homo, virtual, flag_TDA, multiplet, &
info_approximation, mp2_env, unit_nr)
! Print single particle transition amplitudes, i.e. components of eigenvectors X and Y
CALL print_transition_amplitudes(fm_eigvec_X, homo, virtual, homo_irred, &
info_approximation, mp2_env, unit_nr, fm_eigvec_Y)
! Prints optical properties, if state is a singlet
CALL print_optical_properties(Exc_ens, oscill_str, trans_mom_bse, polarizability_residues, &
homo, virtual, homo_irred, flag_TDA, &
info_approximation, mp2_env, unit_nr)
! Print exciton descriptors if keyword is invoked
IF (mp2_env%bse%num_print_exc_descr > 0) THEN
CALL print_exciton_descriptors(exc_descr, ref_point_multipole, unit_nr, mp2_env, qs_env)
END IF
DO i_exc = 1, MIN(homo*virtual, mp2_env%ri_g0w0%num_print_exc)
! Compute and print excitation wavefunctions
IF (mp2_env%bse%do_nto_analysis) THEN
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A47)') &
'BSE|', "Calculating Natural Transition Orbitals (NTOs)."
WRITE (unit_nr, '(T2,A4)') 'BSE|'
END IF
!Iterate through eigenvector and print values above threshold
CALL print_transition_probabilities(fm_eigvec_X, "=>", info_approximation, &
i_exc, virtual, homo, homo_irred, &
unit_nr, mp2_env)
IF (PRESENT(fm_eigvec_Y)) THEN
CALL print_transition_probabilities(fm_eigvec_Y, "<=", info_approximation, &
i_exc, virtual, homo, homo_irred, &
unit_nr, mp2_env)
END IF
END DO
! Compute BSE dipoles and oscillator strengths
CALL get_oscillator_strengths(fm_eigvec_X, Exc_ens, &
dipole_exc, oscill_str, &
mp2_env, qs_env, mo_coeff, &
homo, virtual, unit_nr, &
fm_eigvec_Y)
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A63)') &
'BSE|', "Dipoles d_r^n and oscillator strength f^n of excitation level n"
WRITE (unit_nr, '(T2,A4,T7,A17)') &
'BSE|', "are obtained from"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
IF (flag_TDA) THEN
WRITE (unit_nr, '(T2,A4,T12,A51)') &
'BSE|', "d_r^n = sqrt(2) sum_ia < ψ_i | µ | ψ_a > X_ia^n"
ELSE
WRITE (unit_nr, '(T2,A4,T12,A63)') &
'BSE|', "d_r^n = sqrt(2) sum_ia < ψ_i | µ | ψ_a > ( X_ia^n + Y_ia^n )"
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T20,A44)') &
'BSE|', "f^n = 2/3 * Ω^n sum_r∈(x,y,z) ( d_r^n )^2"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A19)') &
'BSE|', "where we introduced"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A5,T15,A28)') &
'BSE|', "ψ_i:", "occupied molecular orbitals,"
WRITE (unit_nr, '(T2,A4,T7,A5,T15,A28)') &
'BSE|', "ψ_a:", "empty molecular orbitals and"
WRITE (unit_nr, '(T2,A4,T7,A3,T15,A16)') &
'BSE|', "µ:", "dipole operator."
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A28)') &
'BSE|', "prelim Ref.: Eqs. (23), (24)"
WRITE (unit_nr, '(T2,A4,T7,A71)') &
'BSE|', "in J. Chem. Phys. 152, 044105 (2020); https://doi.org/10.1063/1.5123290"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T8,A12,T22,A8,T35,A8,T45,A8,T55,A8,T65,A16)') 'BSE|', &
'Excitation n', "TDA/ABBA", "Dipole X", "Dipole Y", "Dipole Z", 'Osc. strength'
DO i_exc = 1, MIN(homo*virtual, mp2_env%ri_g0w0%num_print_exc)
WRITE (unit_nr, '(T2,A4,T8,I12,T24,A6,T35,F8.3,T45,F8.3,T55,F8.3,T65,F16.3)') &
'BSE|', i_exc, info_approximation, dipole_exc(1, 1, i_exc), dipole_exc(2, 1, i_exc), &
dipole_exc(3, 1, i_exc), oscill_str(i_exc)
END DO
WRITE (unit_nr, '(T2,A4)') 'BSE|'
CALL calculate_NTOs(fm_eigvec_X, fm_eigvec_Y, &
mo_coeff, homo, virtual, &
info_approximation, &
oscill_str, &
qs_env, unit_nr, mp2_env)
END IF
! Compute and print the absorption spectrum to external file
IF (mp2_env%ri_g0w0%bse_print_spectrum) THEN
CALL compute_absorption_spectrum(oscill_str, Exc_ens, &
info_approximation, unit_nr, mp2_env)
DO idir = 1, n_moments_di
CALL cp_fm_release(fm_dipole_ai_trunc(idir))
CALL cp_fm_release(fm_dipole_ij_trunc(idir))
CALL cp_fm_release(fm_dipole_ab_trunc(idir))
END DO
IF (mp2_env%bse%num_print_exc_descr > 0) THEN
DO idir = 1, n_moments_quad
CALL cp_fm_release(fm_quadpole_ai_trunc(idir))
CALL cp_fm_release(fm_quadpole_ij_trunc(idir))
CALL cp_fm_release(fm_quadpole_ab_trunc(idir))
END DO
DEALLOCATE (fm_quadpole_ai_trunc, fm_quadpole_ij_trunc, fm_quadpole_ab_trunc)
DEALLOCATE (exc_descr)
END IF
DEALLOCATE (fm_dipole_ai_trunc, fm_dipole_ij_trunc, fm_dipole_ab_trunc)
DEALLOCATE (ref_point_multipole)
IF (mp2_env%bse%bse_spin_config == 0) THEN
DEALLOCATE (oscill_str, trans_mom_bse, polarizability_residues)
END IF
DEALLOCATE (oscill_str, dipole_exc)
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
@ -808,6 +729,6 @@ CONTAINS
CALL timestop(handle)
END SUBROUTINE success_message
END SUBROUTINE postprocess_bse
END MODULE bse_full_diag

View file

@ -89,15 +89,15 @@ CONTAINS
num_res_unconverged = -1
num_exact_en_unconverged = -1
bse_davidson_abort_cond = mp2_env%ri_g0w0%davidson_abort_cond
num_exc_en = mp2_env%ri_g0w0%num_exc_en
num_add_start_z_space = mp2_env%ri_g0w0%num_add_start_z_space
fac_max_z_space = mp2_env%ri_g0w0%fac_max_z_space
num_new_t = mp2_env%ri_g0w0%num_new_t
num_davidson_iter = mp2_env%ri_g0w0%num_davidson_iter
eps_res = mp2_env%ri_g0w0%eps_res
eps_exc_en = mp2_env%ri_g0w0%eps_exc_en
z_space_energy_cutoff = mp2_env%ri_g0w0%z_space_energy_cutoff
bse_davidson_abort_cond = mp2_env%bse%davidson_abort_cond
num_exc_en = mp2_env%bse%num_exc_en
num_add_start_z_space = mp2_env%bse%num_add_start_z_space
fac_max_z_space = mp2_env%bse%fac_max_z_space
num_new_t = mp2_env%bse%num_new_t
num_davidson_iter = mp2_env%bse%num_davidson_iter
eps_res = mp2_env%bse%eps_res
eps_exc_en = mp2_env%bse%eps_exc_en
z_space_energy_cutoff = mp2_env%bse%z_space_energy_cutoff
num_Z_vectors_init = num_exc_en + num_add_start_z_space
@ -244,7 +244,7 @@ CONTAINS
END IF
IF (davidson_converged == 1) THEN
CALL success_message(Subspace_full_eigenval, num_new_t, eps_res, num_res_unconverged, &
CALL postprocess_bse(Subspace_full_eigenval, num_new_t, eps_res, num_res_unconverged, &
bse_spin_config, unit_nr, num_exc_en, num_Z_vectors_init, &
num_davidson_iter, i_iter, num_Z_vectors, num_max_z_space, max_res_norm, &
max_en_diff, num_en_unconverged, bse_davidson_abort_cond_string, &
@ -469,7 +469,7 @@ CONTAINS
!> \param success_abort_string ...
!> \param z_space_energy_cutoff ...
! **************************************************************************************************
SUBROUTINE success_message(Subspace_full_eigenval, num_new_t, eps_res, num_res_unconverged, &
SUBROUTINE postprocess_bse(Subspace_full_eigenval, num_new_t, eps_res, num_res_unconverged, &
bse_spin_config, unit_nr, num_exc_en, num_Z_vectors_init, &
num_davidson_iter, i_iter, num_Z_vectors, num_max_z_space, max_res_norm, &
max_en_diff, num_en_unconverged, bse_davidson_abort_cond_string, &
@ -487,7 +487,7 @@ CONTAINS
CHARACTER(LEN=10) :: success_abort_string
REAL(KIND=dp) :: z_space_energy_cutoff
CHARACTER(LEN=*), PARAMETER :: routineN = 'success_message'
CHARACTER(LEN=*), PARAMETER :: routineN = 'postprocess_bse'
CHARACTER(LEN=10) :: multiplet
INTEGER :: handle, i

View file

@ -20,10 +20,11 @@ MODULE bse_main
diagonalize_C
USE bse_iterative, ONLY: do_subspace_iterations,&
fill_local_3c_arrays
USE bse_util, ONLY: deallocate_matrices_bse,&
USE bse_print, ONLY: print_BSE_start_flag
USE bse_util, ONLY: adapt_BSE_input_params,&
deallocate_matrices_bse,&
estimate_BSE_resources,&
mult_B_with_W,&
print_BSE_start_flag,&
truncate_BSE_matrices
USE cp_fm_types, ONLY: cp_fm_release,&
cp_fm_type
@ -116,7 +117,7 @@ CONTAINS
my_do_tda = .FALSE.
my_do_abba = .FALSE.
!Method: Iterative or full diagonalization
SELECT CASE (mp2_env%ri_g0w0%bse_diag_method)
SELECT CASE (mp2_env%bse%bse_diag_method)
CASE (bse_iterdiag)
my_do_iterat_diag = .TRUE.
!MG: Basics of the Davidson solver are implemented, but not rigorously checked.
@ -125,7 +126,7 @@ CONTAINS
my_do_fulldiag = .TRUE.
END SELECT
!Approximation: TDA and/or full ABBA matrix
SELECT CASE (mp2_env%ri_g0w0%flag_tda)
SELECT CASE (mp2_env%bse%flag_tda)
CASE (bse_tda)
my_do_tda = .TRUE.
CASE (bse_abba)
@ -140,7 +141,7 @@ CONTAINS
! Link BSE debug flag against debug print level
logger => cp_get_default_logger()
IF (logger%iter_info%print_level == debug_print_level) THEN
mp2_env%ri_g0w0%bse_debug_print = .TRUE.
mp2_env%bse%bse_debug_print = .TRUE.
END IF
CALL fm_mat_S_ia_bse%matrix_struct%para_env%sync()
@ -168,6 +169,8 @@ CONTAINS
gd_array, color_sub, para_env)
END IF
CALL adapt_BSE_input_params(homo_red, virtual_red, unit_nr, mp2_env)
IF (my_do_fulldiag) THEN
! Quick estimate of memory consumption and runtime of diagonalizations
CALL estimate_BSE_resources(homo_red, virtual_red, unit_nr, my_do_abba, &
@ -220,12 +223,12 @@ CONTAINS
CALL deallocate_matrices_bse(fm_mat_S_bar_ia_bse, fm_mat_S_bar_ij_bse, &
fm_mat_S_ia_trunc, fm_mat_S_ij_trunc, fm_mat_S_ab_trunc, &
fm_mat_Q_static_bse_gemm)
fm_mat_Q_static_bse_gemm, mp2_env)
DEALLOCATE (Eigenval_reduced)
IF (my_do_iterat_diag) THEN
! Contains untested Block-Davidson algorithm
CALL do_subspace_iterations(B_bar_ijQ_bse_local, B_abQ_bse_local, B_bar_iaQ_bse_local, &
B_iaQ_bse_local, homo(1), virtual(1), mp2_env%ri_g0w0%bse_spin_config, unit_nr, &
B_iaQ_bse_local, homo(1), virtual(1), mp2_env%bse%bse_spin_config, unit_nr, &
Eigenval(:, 1, 1), para_env, mp2_env)
! Deallocate local 3c-B-matrices
DEALLOCATE (B_bar_ijQ_bse_local, B_abQ_bse_local, B_bar_iaQ_bse_local, B_iaQ_bse_local)

793
src/bse_print.F Normal file
View file

@ -0,0 +1,793 @@
!--------------------------------------------------------------------------------------------------!
! CP2K: A general program to perform molecular dynamics simulations !
! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
! !
! SPDX-License-Identifier: GPL-2.0-or-later !
!--------------------------------------------------------------------------------------------------!
! **************************************************************************************************
!> \brief Routines for printing information in context of the BSE calculation
!> \par History
!> 10.2024 created [Maximilian Graml]
! **************************************************************************************************
MODULE bse_print
USE atomic_kind_types, ONLY: get_atomic_kind
USE bse_properties, ONLY: compute_absorption_spectrum,&
exciton_descr_type
USE bse_util, ONLY: filter_eigvec_contrib
USE cp_fm_types, ONLY: cp_fm_get_info,&
cp_fm_type
USE kinds, ONLY: dp
USE mp2_types, ONLY: mp2_type
USE particle_types, ONLY: particle_type
USE physcon, ONLY: angstrom,&
evolt
USE qs_environment_types, ONLY: get_qs_env,&
qs_environment_type
#include "./base/base_uses.f90"
IMPLICIT NONE
PRIVATE
CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'bse_print'
PUBLIC :: print_BSE_start_flag, fm_write_thresh, print_excitation_energies, &
print_output_header, print_transition_amplitudes, print_optical_properties, &
print_exciton_descriptors
CONTAINS
! **************************************************************************************************
!> \brief ...
!> \param bse_tda ...
!> \param bse_abba ...
!> \param unit_nr ...
! **************************************************************************************************
SUBROUTINE print_BSE_start_flag(bse_tda, bse_abba, unit_nr)
LOGICAL, INTENT(IN) :: bse_tda, bse_abba
INTEGER, INTENT(IN) :: unit_nr
CHARACTER(LEN=*), PARAMETER :: routineN = 'print_BSE_start_flag'
INTEGER :: handle
CALL timeset(routineN, handle)
IF (unit_nr > 0) THEN
WRITE (unit_nr, *) ' '
WRITE (unit_nr, '(T2,A79)') '*******************************************************************************'
WRITE (unit_nr, '(T2,A79)') '** **'
WRITE (unit_nr, '(T2,A79)') '** Bethe Salpeter equation (BSE) for excitation energies **'
IF (bse_tda .AND. bse_abba) THEN
WRITE (unit_nr, '(T2,A79)') '** solved with and without Tamm-Dancoff approximation (TDA) **'
ELSE IF (bse_tda) THEN
WRITE (unit_nr, '(T2,A79)') '** solved with Tamm-Dancoff approximation (TDA) **'
ELSE
WRITE (unit_nr, '(T2,A79)') '** solved without Tamm-Dancoff approximation (TDA) **'
END IF
WRITE (unit_nr, '(T2,A79)') '** **'
WRITE (unit_nr, '(T2,A79)') '*******************************************************************************'
WRITE (unit_nr, *) ' '
END IF
CALL timestop(handle)
END SUBROUTINE
! **************************************************************************************************
!> \brief ...
!> \param homo ...
!> \param virtual ...
!> \param homo_irred ...
!> \param flag_TDA ...
!> \param multiplet ...
!> \param alpha ...
!> \param unit_nr ...
! **************************************************************************************************
SUBROUTINE print_output_header(homo, virtual, homo_irred, flag_TDA, &
multiplet, alpha, unit_nr)
INTEGER, INTENT(IN) :: homo, virtual, homo_irred
LOGICAL, INTENT(IN) :: flag_TDA
CHARACTER(LEN=10), INTENT(IN) :: multiplet
REAL(KIND=dp), INTENT(IN) :: alpha
INTEGER, INTENT(IN) :: unit_nr
CHARACTER(LEN=*), PARAMETER :: routineN = 'print_output_header'
INTEGER :: handle
CALL timeset(routineN, handle)
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
IF (flag_TDA) THEN
WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '**************************************************************************'
WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '* Bethe Salpeter equation (BSE) with Tamm Dancoff approximation (TDA) *'
WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '**************************************************************************'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A48,A23)') 'BSE|', 'The excitations are calculated by diagonalizing ', &
'the BSE within the TDA:'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T29,A16)') 'BSE|', 'A X^n = Ω^n X^n'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A23)') 'BSE|', 'i.e. in index notation:'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A41)') 'BSE|', 'sum_jb ( A_ia,jb X_jb^n ) = Ω^n X_ia^n'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A30)') 'BSE|', 'prelim Ref.: Eq. (36) with B=0'
WRITE (unit_nr, '(T2,A4,T7,A71)') 'BSE|', 'in PRB 92,045209 (2015); http://dx.doi.org/10.1103/PhysRevB.92.045209 .'
ELSE
WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '**************************************************************************'
WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '* Full ("ABBA") Bethe Salpeter equation (BSE) (i.e. without TDA) *'
WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', '**************************************************************************'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A48,A24)') 'BSE|', 'The excitations are calculated by diagonalizing ', &
'the BSE without the TDA:'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T22,A30)') 'BSE|', '|A B| |X^n| |1 0| |X^n|'
WRITE (unit_nr, '(T2,A4,T22,A31)') 'BSE|', '|B A| |Y^n| = Ω^n |0 -1| |Y^n|'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A23)') 'BSE|', 'i.e. in index notation:'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A62)') 'BSE|', ' sum_jb ( A_ia,jb X_jb^n + B_ia,jb Y_jb^n ) = Ω^n X_ia^n'
WRITE (unit_nr, '(T2,A4,T7,A62)') 'BSE|', '- sum_jb ( B_ia,jb X_jb^n + A_ia,jb Y_jb^n ) = Ω^n Y_ia^n'
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A4,T18,A42,T70,A1,I4,A1,I4,A1)') 'BSE|', 'i,j:', &
'occupied molecular orbitals, i.e. state in', '[', homo_irred - homo + 1, ',', homo_irred, ']'
WRITE (unit_nr, '(T2,A4,T7,A4,T18,A44,T70,A1,I4,A1,I4,A1)') 'BSE|', 'a,b:', &
'unoccupied molecular orbitals, i.e. state in', '[', homo_irred + 1, ',', homo_irred + virtual, ']'
WRITE (unit_nr, '(T2,A4,T7,A2,T18,A16)') 'BSE|', 'n:', 'Excitation index'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A58)') 'BSE|', 'A_ia,jb = (ε_a-ε_i) δ_ij δ_ab + α * v_ia,jb - W_ij,ab'
IF (.NOT. flag_TDA) THEN
WRITE (unit_nr, '(T2,A4,T7,A32)') 'BSE|', 'B_ia,jb = α * v_ia,jb - W_ib,aj'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A35)') 'BSE|', 'prelim Ref.: Eqs. (24-27),(30),(35)'
WRITE (unit_nr, '(T2,A4,T7,A71)') 'BSE|', 'in PRB 92,045209 (2015); http://dx.doi.org/10.1103/PhysRevB.92.045209 .'
END IF
IF (.NOT. flag_TDA) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A74)') 'BSE|', 'The BSE is solved for Ω^n and X_ia^n as a hermitian problem, e.g. Eq.(42)'
WRITE (unit_nr, '(T2,A4,T7,A71)') 'BSE|', 'in PRB 92,045209 (2015); http://dx.doi.org/10.1103/PhysRevB.92.045209 .'
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A7,T19,A23)') 'BSE|', 'ε_...:', 'GW quasiparticle energy'
WRITE (unit_nr, '(T2,A4,T7,A7,T19,A15)') 'BSE|', 'δ_...:', 'Kronecker delta'
WRITE (unit_nr, '(T2,A4,T7,A3,T19,A21)') 'BSE|', 'α:', 'spin-dependent factor (Singlet/Triplet)'
WRITE (unit_nr, '(T2,A4,T7,A6,T18,A34)') 'BSE|', 'v_...:', 'Electron-hole exchange interaction'
WRITE (unit_nr, '(T2,A4,T7,A6,T18,A27)') 'BSE|', 'W_...:', 'Screened direct interaction'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A47,A7,A9,F3.1)') 'BSE|', &
'The spin-dependent factor is for the requested ', multiplet, " is α = ", alpha
WRITE (unit_nr, '(T2,A4)') 'BSE|'
END IF
CALL timestop(handle)
END SUBROUTINE
! **************************************************************************************************
!> \brief ...
!> \param Exc_ens ...
!> \param homo ...
!> \param virtual ...
!> \param flag_TDA ...
!> \param multiplet ...
!> \param info_approximation ...
!> \param mp2_env ...
!> \param unit_nr ...
! **************************************************************************************************
SUBROUTINE print_excitation_energies(Exc_ens, homo, virtual, flag_TDA, multiplet, &
info_approximation, mp2_env, unit_nr)
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: Exc_ens
INTEGER, INTENT(IN) :: homo, virtual
LOGICAL, INTENT(IN) :: flag_TDA
CHARACTER(LEN=10), INTENT(IN) :: multiplet, info_approximation
TYPE(mp2_type), INTENT(INOUT) :: mp2_env
INTEGER, INTENT(IN) :: unit_nr
CHARACTER(LEN=*), PARAMETER :: routineN = 'print_excitation_energies'
INTEGER :: handle, i_exc
CALL timeset(routineN, handle)
IF (unit_nr > 0) THEN
IF (flag_TDA) THEN
WRITE (unit_nr, '(T2,A4,T7,A56)') 'BSE|', 'Excitation energies from solving the BSE within the TDA:'
ELSE
WRITE (unit_nr, '(T2,A4,T7,A57)') 'BSE|', 'Excitation energies from solving the BSE without the TDA:'
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T11,A12,T26,A11,T44,A8,T55,A27)') 'BSE|', &
'Excitation n', "Spin Config", 'TDA/ABBA', 'Excitation energy Ω^n (eV)'
END IF
!prints actual energies values
IF (unit_nr > 0) THEN
DO i_exc = 1, MIN(homo*virtual, mp2_env%bse%num_print_exc)
WRITE (unit_nr, '(T2,A4,T7,I16,T30,A7,T46,A6,T59,F22.4)') &
'BSE|', i_exc, multiplet, info_approximation, Exc_ens(i_exc)*evolt
END DO
END IF
CALL timestop(handle)
END SUBROUTINE print_excitation_energies
! **************************************************************************************************
!> \brief ...
!> \param fm_eigvec_X ...
!> \param homo ...
!> \param virtual ...
!> \param homo_irred ...
!> \param info_approximation ...
!> \param mp2_env ...
!> \param unit_nr ...
!> \param fm_eigvec_Y ...
! **************************************************************************************************
SUBROUTINE print_transition_amplitudes(fm_eigvec_X, homo, virtual, homo_irred, &
info_approximation, mp2_env, unit_nr, fm_eigvec_Y)
TYPE(cp_fm_type), INTENT(IN) :: fm_eigvec_X
INTEGER, INTENT(IN) :: homo, virtual, homo_irred
CHARACTER(LEN=10), INTENT(IN) :: info_approximation
TYPE(mp2_type), INTENT(INOUT) :: mp2_env
INTEGER, INTENT(IN) :: unit_nr
TYPE(cp_fm_type), INTENT(IN), OPTIONAL :: fm_eigvec_Y
CHARACTER(LEN=*), PARAMETER :: routineN = 'print_transition_amplitudes'
INTEGER :: handle, i_exc
CALL timeset(routineN, handle)
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A61)') &
'BSE|', "Single-particle transitions are built up by (de-)excitations,"
WRITE (unit_nr, '(T2,A4,T7,A18)') &
'BSE|', "which we denote by"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T20,A2,T30,A40)') &
'BSE|', "=>", "for excitations, i.e. entries of X_ia^n,"
WRITE (unit_nr, '(T2,A4,T20,A2,T30,A42)') &
'BSE|', "<=", "for deexcitations, i.e. entries of Y_ia^n."
WRITE (unit_nr, '(T2,A4)') &
'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A73)') &
'BSE|', "The following single-particle transitions have significant contributions,"
WRITE (unit_nr, '(T2,A4,T7,A16,F5.3,A15,F5.3,A16)') &
'BSE|', "i.e. |X_ia^n| > ", mp2_env%bse%eps_x, " or |Y_ia^n| > ", &
mp2_env%bse%eps_x, ", respectively :"
WRITE (unit_nr, '(T2,A4,T15,A27,I5,A13,I5,A3)') 'BSE|', '-- Quick reminder: HOMO i =', &
homo_irred, ' and LUMO a =', homo_irred + 1, " --"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A12,T30,A1,T32,A5,T42,A1,T49,A8,T64,A17)') &
"BSE|", "Excitation n", "i", "=>/<=", "a", 'TDA/ABBA', "|X_ia^n|/|Y_ia^n|"
END IF
DO i_exc = 1, MIN(homo*virtual, mp2_env%bse%num_print_exc)
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
END IF
!Iterate through eigenvector and print values above threshold
CALL print_transition_amplitudes_core(fm_eigvec_X, "=>", info_approximation, &
i_exc, virtual, homo, homo_irred, &
unit_nr, mp2_env)
IF (PRESENT(fm_eigvec_Y)) THEN
CALL print_transition_amplitudes_core(fm_eigvec_Y, "<=", info_approximation, &
i_exc, virtual, homo, homo_irred, &
unit_nr, mp2_env)
END IF
END DO
CALL timestop(handle)
END SUBROUTINE print_transition_amplitudes
! **************************************************************************************************
!> \brief ...
!> \param Exc_ens ...
!> \param oscill_str ...
!> \param trans_mom_bse ...
!> \param polarizability_residues ...
!> \param homo ...
!> \param virtual ...
!> \param homo_irred ...
!> \param flag_TDA ...
!> \param info_approximation ...
!> \param mp2_env ...
!> \param unit_nr ...
! **************************************************************************************************
SUBROUTINE print_optical_properties(Exc_ens, oscill_str, trans_mom_bse, polarizability_residues, &
homo, virtual, homo_irred, flag_TDA, &
info_approximation, mp2_env, unit_nr)
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: Exc_ens, oscill_str
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: trans_mom_bse, polarizability_residues
INTEGER, INTENT(IN) :: homo, virtual, homo_irred
LOGICAL, INTENT(IN) :: flag_TDA
CHARACTER(LEN=10), INTENT(IN) :: info_approximation
TYPE(mp2_type), INTENT(INOUT) :: mp2_env
INTEGER, INTENT(IN) :: unit_nr
CHARACTER(LEN=*), PARAMETER :: routineN = 'print_optical_properties'
INTEGER :: handle, i_exc
CALL timeset(routineN, handle)
! Discriminate between singlet and triplet, since triplet state can't couple to light
! and therefore calculations of dipoles etc are not necessary
IF (mp2_env%bse%bse_spin_config == 0) THEN
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A60)') &
'BSE|', "Transition moments d_r^n (with r∈(x,y,z), in atomic units)"
WRITE (unit_nr, '(T2,A4,T7,A67)') &
'BSE|', "and oscillator strength f^n of excitation level n are obtained from"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
IF (flag_TDA) THEN
WRITE (unit_nr, '(T2,A4,T10,A)') &
'BSE|', "d_r^n = sqrt(2) sum_ia < ψ_i | r | ψ_a > X_ia^n"
ELSE
WRITE (unit_nr, '(T2,A4,T10,A)') &
'BSE|', "d_r^n = sum_ia sqrt(2) < ψ_i | r | ψ_a > ( X_ia^n + Y_ia^n )"
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T14,A)') &
'BSE|', "f^n = 2/3 * Ω^n sum_r∈(x,y,z) ( d_r^n )^2"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A19)') &
'BSE|', "where we introduced"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A5,T15,A28)') &
'BSE|', "ψ_i:", "occupied molecular orbitals,"
WRITE (unit_nr, '(T2,A4,T7,A5,T15,A28)') &
'BSE|', "ψ_a:", "empty molecular orbitals and"
WRITE (unit_nr, '(T2,A4,T9,A2,T14,A18)') &
'BSE|', "r:", "position operator."
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A28)') &
'BSE|', "prelim Ref.: Eqs. (23), (24)"
WRITE (unit_nr, '(T2,A4,T7,A71)') &
'BSE|', "in J. Chem. Phys. 152, 044105 (2020); https://doi.org/10.1063/1.5123290"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
IF (flag_TDA) THEN
WRITE (unit_nr, '(T2,A4,T7,A55)') 'BSE|', &
'Optical properties from solving the BSE within the TDA:'
ELSE
WRITE (unit_nr, '(T2,A4,T7,A56)') 'BSE|', &
'Optical properties from solving the BSE without the TDA:'
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T8,A12,T22,A8,T38,A5,T48,A5,T58,A5,T64,A17)') 'BSE|', &
'Excitation n', "TDA/ABBA", "d_x^n", "d_y^n", "d_z^n", 'Osc. strength f^n'
DO i_exc = 1, MIN(homo*virtual, mp2_env%bse%num_print_exc)
WRITE (unit_nr, '(T2,A4,T8,I12,T24,A6,T35,F8.3,T45,F8.3,T55,F8.3,T65,F16.3)') &
'BSE|', i_exc, info_approximation, trans_mom_bse(1, 1, i_exc), trans_mom_bse(2, 1, i_exc), &
trans_mom_bse(3, 1, i_exc), oscill_str(i_exc)
END DO
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'Check for Thomas-Reiche-Kuhn sum rule'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T35,A)') 'BSE|', &
'N_e = Σ_n f^n'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A24,T65,I16)') 'BSE|', &
'Number of electrons N_e:', homo_irred*2
WRITE (unit_nr, '(T2,A4,T7,A,T66,F16.3)') 'BSE|', &
'Sum over oscillator strengths Σ_n f^n :', SUM(oscill_str)
WRITE (unit_nr, '(T2,A4)') 'BSE|'
IF (mp2_env%bse%bse_cutoff_occ > 0 .OR. mp2_env%bse%bse_cutoff_empty > 0) THEN
CALL cp_warn(__LOCATION__, &
"Accuracy of TRK sum rule might suffer from cutoffs.")
END IF
END IF
! Compute and print the absorption spectrum to external file
IF (mp2_env%bse%bse_print_spectrum) THEN
CALL compute_absorption_spectrum(oscill_str, polarizability_residues, Exc_ens, &
info_approximation, unit_nr, mp2_env)
END IF
ELSE
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
CALL cp_warn(__LOCATION__, &
"Requested triplet excitation cannot couple to light. "// &
"Skipping calculation of transition moments, "// &
"oscillator strengths, and spectrum.")
END IF
END IF
CALL timestop(handle)
END SUBROUTINE print_optical_properties
! **************************************************************************************************
!> \brief ...
!> \param fm_eigvec ...
!> \param direction_excitation ...
!> \param info_approximation ...
!> \param i_exc ...
!> \param virtual ...
!> \param homo ...
!> \param homo_irred ...
!> \param unit_nr ...
!> \param mp2_env ...
! **************************************************************************************************
SUBROUTINE print_transition_amplitudes_core(fm_eigvec, direction_excitation, info_approximation, &
i_exc, virtual, homo, homo_irred, &
unit_nr, mp2_env)
TYPE(cp_fm_type), INTENT(IN) :: fm_eigvec
CHARACTER(LEN=2), INTENT(IN) :: direction_excitation
CHARACTER(LEN=10), INTENT(IN) :: info_approximation
INTEGER :: i_exc, virtual, homo, homo_irred
INTEGER, INTENT(IN) :: unit_nr
TYPE(mp2_type), INTENT(INOUT) :: mp2_env
CHARACTER(LEN=*), PARAMETER :: routineN = 'print_transition_amplitudes_core'
INTEGER :: handle, k, num_entries
INTEGER, ALLOCATABLE, DIMENSION(:) :: idx_homo, idx_virt
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eigvec_entries
CALL timeset(routineN, handle)
CALL filter_eigvec_contrib(fm_eigvec, idx_homo, idx_virt, eigvec_entries, &
i_exc, virtual, num_entries, mp2_env)
! direction_excitation can be either => (means excitation; from fm_eigvec_X)
! or <= (means deexcitation; from fm_eigvec_Y)
IF (unit_nr > 0) THEN
DO k = 1, num_entries
WRITE (unit_nr, '(T2,A4,T14,I5,T26,I5,T35,A2,T38,I5,T51,A6,T65,F16.4)') &
"BSE|", i_exc, homo_irred - homo + idx_homo(k), direction_excitation, &
homo_irred + idx_virt(k), info_approximation, ABS(eigvec_entries(k))
END DO
END IF
DEALLOCATE (idx_homo)
DEALLOCATE (idx_virt)
DEALLOCATE (eigvec_entries)
CALL timestop(handle)
END SUBROUTINE
! **************************************************************************************************
!> \brief ...
!> \param exc_descr ...
!> \param ref_point_multipole ...
!> \param unit_nr ...
!> \param mp2_env ...
!> \param qs_env ...
! **************************************************************************************************
SUBROUTINE print_exciton_descriptors(exc_descr, ref_point_multipole, unit_nr, mp2_env, qs_env)
TYPE(exciton_descr_type), ALLOCATABLE, &
DIMENSION(:) :: exc_descr
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
INTENT(IN) :: ref_point_multipole
INTEGER, INTENT(IN) :: unit_nr
TYPE(mp2_type), INTENT(INOUT) :: mp2_env
TYPE(qs_environment_type), POINTER :: qs_env
CHARACTER(LEN=*), PARAMETER :: routineN = 'print_exciton_descriptors'
CHARACTER(LEN=1), DIMENSION(3) :: array_direction_str
INTEGER :: handle, i_dir, i_exc
REAL(KIND=dp) :: d_eh_dir, d_exc_dir, sigma_e_dir, &
sigma_h_dir
TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
CALL timeset(routineN, handle)
CALL get_qs_env(qs_env, particle_set=particle_set)
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'Exciton descriptors for excitation level n are given by'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'd_eh = | <r_h - r_e>_exc |'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'σ_e = sqrt( <r_e^2>_exc - <r_e>_exc^2 )'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'σ_h = sqrt( <r_h^2>_exc - <r_h>_exc^2 )'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'COV_eh = <r_e r_h>_exc - <r_e>_exc <r_h>_exc'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'd_exc = sqrt( | < |r_h - r_e|^2 >_exc )'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
' = sqrt( d_eh^2 + σ_e^2 + σ_h^2 - 2 * COV_eh )'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'R_eh = COV_eh / (σ_e * σ_h)'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'where the expectation values <.>_exc are taken with respect to the '
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'exciton wavefunction of excitation n:'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
IF (exc_descr(1)%flag_TDA) THEN
WRITE (unit_nr, '(T2,A4,T20,A)') 'BSE|', &
'𝚿_n(r_e,r_h) = Σ_{i,a} X_ia^n ψ_i(r_h) ψ_a(r_e) ,'
ELSE
WRITE (unit_nr, '(T2,A4,T20,A)') 'BSE|', &
'𝚿_n(r_e,r_h) = Σ_{i,a} X_ia^n ψ_i(r_h) ψ_a(r_e)'
WRITE (unit_nr, '(T2,A4,T40,A)') 'BSE|', &
'+ Y_ia^n ψ_a(r_h) ψ_i(r_e) ,'
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'i.e.'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T20,A)') 'BSE|', &
'< O >_exc = < 𝚿_n | O | 𝚿_n > / < 𝚿_n | 𝚿_n > ,'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
IF (exc_descr(1)%flag_TDA) THEN
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'where c_n = < 𝚿_n | 𝚿_n > = 1 within TDA.'
ELSE
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'where c_n = < 𝚿_n | 𝚿_n > deviates from 1 without TDA.'
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'Here, we introduced'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A5,T15,A)') &
'BSE|', "ψ_i:", "occupied molecular orbitals,"
WRITE (unit_nr, '(T2,A4,T7,A5,T15,A)') &
'BSE|', "ψ_a:", "empty molecular orbitals and"
WRITE (unit_nr, '(T2,A4,T9,A2,T14,A)') &
'BSE|', "r:", "position operator."
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'prelim Ref.: Eqs. (15)-(22)'
WRITE (unit_nr, '(T2,A4,T7,A,A)') 'BSE|', &
'JCTC 2018, 14, 710-725; ', &
'http://doi.org/10.1021/acs.jctc.7b01145'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
IF (exc_descr(1)%flag_TDA) THEN
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'Exciton descriptors from solving the BSE within the TDA:'
ELSE
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'Exciton descriptors from solving the BSE without the TDA:'
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T10,A1,6X,A3,1X,4X,A10,5X,A10,5X,A10,3X,A11,8X,A4)') 'BSE|', &
'n', 'c_n', 'd_eh [Å]', 'σ_e [Å]', 'σ_h []', 'd_exc [Å]', 'R_eh'
DO i_exc = 1, mp2_env%bse%num_print_exc_descr
WRITE (unit_nr, '(T2,A4,T7,I4,4X,F5.3,1X,5(2X,F10.4))') &
'BSE|', i_exc, exc_descr(i_exc)%norm_XpY, &
exc_descr(i_exc)%diff_r_abs*angstrom, &
exc_descr(i_exc)%sigma_e*angstrom, exc_descr(i_exc)%sigma_h*angstrom, &
exc_descr(i_exc)%diff_r_sqr*angstrom, exc_descr(i_exc)%corr_e_h*angstrom
END DO
WRITE (unit_nr, '(T2,A4)') 'BSE|'
! For debug runs, print first d_exc separately to allow the regtests to read in
IF (mp2_env%bse%bse_debug_print) THEN
IF (exc_descr(1)%flag_TDA) THEN
WRITE (unit_nr, '(T2,A10,T13,A,T65,F16.4)') 'BSE|DEBUG|', &
'Exciton descriptor d_exc with TDA for n=1 is', exc_descr(1)%diff_r_sqr*angstrom
ELSE
WRITE (unit_nr, '(T2,A10,T13,A,T65,F16.4)') 'BSE|DEBUG|', &
'Exciton descriptor d_exc without TDA for n=1 is', exc_descr(1)%diff_r_sqr*angstrom
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
! Print exciton descriptor resolved per direction
IF (mp2_env%bse%print_directional_exc_descr) THEN
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'We can restrict the exciton descriptors to a specific direction,'
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'e.g. the x-components are:'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'd_eh^x = | <x_h - x_e>_exc |'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'σ_e^x = sqrt( <x_e^2>_exc - <x_e>_exc^2 )'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'σ_h^x = sqrt( <x_h^2>_exc - <x_h>_exc^2 )'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'COV_eh^x = <x_e x_h>_exc - <x_e>_exc <x_h>_exc'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'd_exc^x = sqrt( | < |x_h - x_e|^2 >_exc )'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
' = sqrt( (d_eh^x)^2 + (σ_e^x)^2'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
' + (σ_h^x)^2 - 2 * (COV_eh^x) )'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
IF (exc_descr(1)%flag_TDA) THEN
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'Exciton descriptors per direction from solving the BSE within the TDA:'
ELSE
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'Exciton descriptors per direction from solving the BSE without the TDA:'
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T12,A1,2X,A9,5X,A12,5X,A12,5X,A12,3X,A13)') 'BSE|', &
'n', 'r = x/y/z', 'd_eh^r [Å]', 'σ_e^r [Å]', 'σ_h^r [Å]', 'd_exc^r []'
DO i_exc = 1, mp2_env%bse%num_print_exc_descr
DO i_dir = 1, 3
array_direction_str = (/"x", "y", "z"/)
d_eh_dir = ABS(exc_descr(i_exc)%r_h(i_dir) - exc_descr(i_exc)%r_e(i_dir))
sigma_e_dir = SQRT(exc_descr(i_exc)%r_e_sq(i_dir) - exc_descr(i_exc)%r_e(i_dir)**2)
sigma_h_dir = SQRT(exc_descr(i_exc)%r_h_sq(i_dir) - exc_descr(i_exc)%r_h(i_dir)**2)
d_exc_dir = SQRT(d_eh_dir**2 + sigma_e_dir**2 + sigma_h_dir**2 &
- 2*exc_descr(i_exc)%cov_e_h(i_dir))
WRITE (unit_nr, '(T2,A4,T9,I4,10X,A1,1X,4(4X,F10.4))') &
'BSE|', i_exc, array_direction_str(i_dir), &
d_eh_dir*angstrom, &
sigma_e_dir*angstrom, sigma_h_dir*angstrom, &
d_exc_dir*angstrom
END DO
WRITE (unit_nr, '(T2,A4)') 'BSE|'
END DO
WRITE (unit_nr, '(T2,A4)') 'BSE|'
END IF
! Print the reference atomic geometry for the exciton descriptors
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'With the center of charge as reference point r_0,'
WRITE (unit_nr, '(T2,A4,T15,A7,F10.4,A2,F10.4,A2,F10.4,A1)') 'BSE|', &
'r_0 = (', ref_point_multipole(1)*angstrom, ', ', ref_point_multipole(2)*angstrom, ', ', &
ref_point_multipole(3)*angstrom, ')'
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'we further obtain r_e and r_h from solving the BSE within the TDA'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T8,A12,1X,13X,A9,13X,A9,13X,A9)') 'BSE|', &
'Excitation n', 'x_e [Å]', 'y_e [Å]', 'z_e [Å]'
DO i_exc = 1, mp2_env%bse%num_print_exc_descr
WRITE (unit_nr, '(T2,A4,T8,I12,1X,3(5X,F15.4))') &
'BSE|', i_exc, &
exc_descr(i_exc)%r_e_shift(:)*angstrom
END DO
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T8,A12,1X,13X,A9,13X,A9,13X,A9)') 'BSE|', &
'Excitation n', 'x_h [Å]', 'y_h [Å]', 'z_h [Å]'
DO i_exc = 1, mp2_env%bse%num_print_exc_descr
WRITE (unit_nr, '(T2,A4,T8,I12,1X,3(5X,F15.4))') &
'BSE|', i_exc, &
exc_descr(i_exc)%r_h_shift(:)*angstrom
END DO
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'The reference atomic geometry for these values is given by'
END IF
CALL write_qs_particle_coordinates_bse(particle_set, unit_nr)
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
END IF
CALL timestop(handle)
END SUBROUTINE print_exciton_descriptors
! **************************************************************************************************
!> \brief Debug function to write elements of a full matrix to file, if they are larger than a given threshold
!> \param fm ...
!> \param thresh ...
!> \param header ...
!> \param unit_nr ...
!> \param abs_vals ...
! **************************************************************************************************
SUBROUTINE fm_write_thresh(fm, thresh, header, unit_nr, abs_vals)
TYPE(cp_fm_type), INTENT(IN) :: fm
REAL(KIND=dp), INTENT(IN) :: thresh
CHARACTER(LEN=*), INTENT(IN) :: header
INTEGER, INTENT(IN) :: unit_nr
LOGICAL, OPTIONAL :: abs_vals
CHARACTER(LEN=*), PARAMETER :: my_footer = " | ENDING WRITING OF MATRIX", &
routineN = 'fm_write_thresh'
INTEGER :: handle, i, j, ncol_local, nrow_local
INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
LOGICAL :: my_abs_vals
CALL timeset(routineN, handle)
IF (PRESENT(abs_vals)) THEN
my_abs_vals = abs_vals
ELSE
my_abs_vals = .FALSE.
END IF
CALL cp_fm_get_info(matrix=fm, &
nrow_local=nrow_local, &
ncol_local=ncol_local, &
row_indices=row_indices, &
col_indices=col_indices)
IF (unit_nr > 0) THEN
WRITE (unit_nr, *) header
END IF
IF (my_abs_vals) THEN
DO i = 1, nrow_local
DO j = 1, ncol_local
IF (ABS(fm%local_data(i, j)) > thresh) THEN
WRITE (unit_nr, "(A7,T10,I5,T20,I5,T30,F13.5)") header, row_indices(i), col_indices(j), &
ABS(fm%local_data(i, j))
END IF
END DO
END DO
ELSE
DO i = 1, nrow_local
DO j = 1, ncol_local
IF (ABS(fm%local_data(i, j)) > thresh) THEN
WRITE (unit_nr, "(A7,T10,I5,T20,I5,T30,F13.5)") header, row_indices(i), col_indices(j), &
fm%local_data(i, j)
END IF
END DO
END DO
END IF
CALL fm%matrix_struct%para_env%sync()
IF (unit_nr > 0) THEN
WRITE (unit_nr, *) my_footer
END IF
CALL timestop(handle)
END SUBROUTINE
! **************************************************************************************************
!> \brief Write the atomic coordinates to the output unit.
!> \param particle_set ...
!> \note Adapted from particle_methods.F [MG]
!> \param unit_nr ...
! **************************************************************************************************
SUBROUTINE write_qs_particle_coordinates_bse(particle_set, unit_nr)
TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
INTEGER, INTENT(IN) :: unit_nr
CHARACTER(len=*), PARAMETER :: routineN = 'write_qs_particle_coordinates_bse'
CHARACTER(LEN=2) :: element_symbol
INTEGER :: handle, iatom, natom
CALL timeset(routineN, handle)
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T13,A7,16X,A7,15X,A7,15X,A7)') 'BSE|', &
'Element', 'x [Å]', 'y [Å]', 'z [Å]'
natom = SIZE(particle_set)
DO iatom = 1, natom
CALL get_atomic_kind(atomic_kind=particle_set(iatom)%atomic_kind, &
element_symbol=element_symbol)
WRITE (unit_nr, '(T2,A4,T8,A12,1X,3(5X,F15.4))') &
'BSE|', element_symbol, particle_set(iatom)%r(1:3)*angstrom
END DO
END IF
CALL timestop(handle)
END SUBROUTINE write_qs_particle_coordinates_bse
END MODULE bse_print

981
src/bse_properties.F Normal file
View file

@ -0,0 +1,981 @@
!--------------------------------------------------------------------------------------------------!
! CP2K: A general program to perform molecular dynamics simulations !
! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
! !
! SPDX-License-Identifier: GPL-2.0-or-later !
!--------------------------------------------------------------------------------------------------!
! **************************************************************************************************
!> \brief Routines for computing excitonic properties, e.g. exciton diameter, from the BSE
!> \par History
!> 10.2024 created [Maximilian Graml]
! **************************************************************************************************
MODULE bse_properties
USE bse_util, ONLY: fm_general_add_bse,&
print_bse_nto_cubes,&
reshuffle_eigvec,&
trace_exciton_descr
USE cp_files, ONLY: close_file,&
open_file
USE cp_fm_basic_linalg, ONLY: cp_fm_scale_and_add,&
cp_fm_trace
USE cp_fm_diag, ONLY: cp_fm_svd
USE cp_fm_struct, ONLY: cp_fm_struct_create,&
cp_fm_struct_release,&
cp_fm_struct_type
USE cp_fm_types, ONLY: cp_fm_create,&
cp_fm_get_submatrix,&
cp_fm_release,&
cp_fm_set_all,&
cp_fm_to_fm,&
cp_fm_to_fm_submat,&
cp_fm_to_fm_submat_general,&
cp_fm_type
USE cp_log_handling, ONLY: cp_get_default_logger,&
cp_logger_get_default_unit_nr,&
cp_logger_type
USE input_section_types, ONLY: section_vals_get_subs_vals,&
section_vals_type,&
section_vals_val_get
USE kinds, ONLY: dp
USE mp2_types, ONLY: mp2_type
USE parallel_gemm_api, ONLY: parallel_gemm
USE particle_methods, ONLY: write_qs_particle_coordinates
USE particle_types, ONLY: particle_type
USE physcon, ONLY: evolt
USE qs_environment_types, ONLY: get_qs_env,&
qs_environment_type
USE qs_kind_types, ONLY: qs_kind_type
USE qs_mo_types, ONLY: allocate_mo_set,&
deallocate_mo_set,&
init_mo_set,&
mo_set_type
#include "./base/base_uses.f90"
IMPLICIT NONE
PRIVATE
CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'bse_properties'
PUBLIC :: exciton_descr_type
PUBLIC :: get_exciton_descriptors, get_oscillator_strengths, compute_absorption_spectrum, &
calculate_NTOs
! TYPE definitions for exciton wavefunction descriptors
TYPE exciton_descr_type
REAL(KIND=dp), DIMENSION(3) :: r_e, r_h, &
r_e_sq, r_h_sq, r_e_h, &
r_e_shift, r_h_shift, &
cov_e_h
REAL(KIND=dp) :: sigma_e, sigma_h, &
cov_e_h_sum, corr_e_h, &
diff_r_abs, diff_r_sqr, &
norm_XpY
LOGICAL :: flag_TDA
END TYPE exciton_descr_type
CONTAINS
! **************************************************************************************************
!> \brief Compute and return BSE dipoles d_r^n = sqrt(2) sum_ia < ψ_i | r | ψ_a > ( X_ia^n + Y_ia^n )
!> and oscillator strengths f^n = 2/3 * Ω^n sum_r∈(x,y,z) ( d_r^n )^2
!> Prelim Ref.: Eqs. (23), (24)
!> in J. Chem. Phys. 152, 044105 (2020); https://doi.org/10.1063/1.5123290
!> \param fm_eigvec_X ...
!> \param Exc_ens ...
!> \param fm_dipole_ai_trunc ...
!> \param trans_mom_bse BSE dipole vectors in real space per excitation level
!> \param oscill_str Oscillator strength per excitation level
!> \param polarizability_residues Residues of polarizability ("tensorial oscillator strength")
!> per excitation level
!> \param mp2_env ...
!> \param homo_red ...
!> \param virtual_red ...
!> \param unit_nr ...
!> \param fm_eigvec_Y ...
! **************************************************************************************************
SUBROUTINE get_oscillator_strengths(fm_eigvec_X, Exc_ens, fm_dipole_ai_trunc, &
trans_mom_bse, oscill_str, polarizability_residues, &
mp2_env, homo_red, virtual_red, unit_nr, &
fm_eigvec_Y)
TYPE(cp_fm_type), INTENT(IN) :: fm_eigvec_X
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
INTENT(IN) :: Exc_ens
TYPE(cp_fm_type), DIMENSION(3) :: fm_dipole_ai_trunc
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
INTENT(OUT) :: trans_mom_bse
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
INTENT(OUT) :: oscill_str
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
INTENT(OUT) :: polarizability_residues
TYPE(mp2_type), INTENT(IN) :: mp2_env
INTEGER, INTENT(IN) :: homo_red, virtual_red, unit_nr
TYPE(cp_fm_type), INTENT(IN), OPTIONAL :: fm_eigvec_Y
CHARACTER(LEN=*), PARAMETER :: routineN = 'get_oscillator_strengths'
INTEGER :: handle, idir, jdir, n
TYPE(cp_fm_struct_type), POINTER :: fm_struct_dipole_MO_trunc_reordered, &
fm_struct_trans_mom_bse
TYPE(cp_fm_type) :: fm_eigvec_XYsum
TYPE(cp_fm_type), DIMENSION(3) :: fm_dipole_MO_trunc_reordered, &
fm_dipole_per_dir, fm_trans_mom_bse
CALL timeset(routineN, handle)
CALL cp_fm_struct_create(fm_struct_dipole_MO_trunc_reordered, fm_eigvec_X%matrix_struct%para_env, &
fm_eigvec_X%matrix_struct%context, 1, homo_red*virtual_red)
CALL cp_fm_struct_create(fm_struct_trans_mom_bse, fm_eigvec_X%matrix_struct%para_env, &
fm_eigvec_X%matrix_struct%context, 1, homo_red*virtual_red)
! Include excitonic amplitudes in dipoles, i.e. obtain "BSE dipoles":
! \vec{D}_n = sqrt(2) * sum_{i,a} \vec{D}_ai (X_{ai}^{(n)} + Y_{ai}^{(n)})
! Reorder dipoles in order to execute the sum over i and a by parallel gemm
DO idir = 1, 3
CALL cp_fm_create(fm_dipole_MO_trunc_reordered(idir), matrix_struct=fm_struct_dipole_MO_trunc_reordered, &
name="dipoles_mo_reordered")
CALL cp_fm_set_all(fm_dipole_MO_trunc_reordered(idir), 0.0_dp)
CALL fm_general_add_bse(fm_dipole_MO_trunc_reordered(idir), fm_dipole_ai_trunc(idir), 1.0_dp, &
1, 1, &
1, virtual_red, &
unit_nr, (/2, 4, 3, 1/), mp2_env)
CALL cp_fm_release(fm_dipole_per_dir(idir))
END DO
DO idir = 1, 3
CALL cp_fm_create(fm_trans_mom_bse(idir), matrix_struct=fm_struct_trans_mom_bse, &
name="excitonic_dipoles")
CALL cp_fm_set_all(fm_trans_mom_bse(idir), 0.0_dp)
END DO
! If TDA is invoked, Y is not present as it is simply 0
CALL cp_fm_create(fm_eigvec_XYsum, matrix_struct=fm_eigvec_X%matrix_struct, name="excit_amplitude_sum")
CALL cp_fm_set_all(fm_eigvec_XYsum, 0.0_dp)
CALL cp_fm_to_fm(fm_eigvec_X, fm_eigvec_XYsum)
IF (PRESENT(fm_eigvec_Y)) THEN
CALL cp_fm_scale_and_add(1.0_dp, fm_eigvec_XYsum, 1.0_dp, fm_eigvec_Y)
END IF
DO idir = 1, 3
CALL parallel_gemm('N', 'N', 1, homo_red*virtual_red, homo_red*virtual_red, SQRT(2.0_dp), &
fm_dipole_MO_trunc_reordered(idir), fm_eigvec_XYsum, 0.0_dp, fm_trans_mom_bse(idir))
END DO
! Get oscillator strengths themselves
ALLOCATE (oscill_str(homo_red*virtual_red))
ALLOCATE (trans_mom_bse(3, 1, homo_red*virtual_red))
ALLOCATE (polarizability_residues(3, 3, homo_red*virtual_red))
trans_mom_bse(:, :, :) = 0.0_dp
! Sum over all directions
DO idir = 1, 3
CALL cp_fm_get_submatrix(fm_trans_mom_bse(idir), trans_mom_bse(idir, :, :))
END DO
DO n = 1, homo_red*virtual_red
DO idir = 1, 3
DO jdir = 1, 3
polarizability_residues(idir, jdir, n) = 2.0_dp*Exc_ens(n)*trans_mom_bse(idir, 1, n)*trans_mom_bse(jdir, 1, n)
END DO
END DO
oscill_str(n) = 2.0_dp/3.0_dp*Exc_ens(n)*SUM(ABS(trans_mom_bse(:, :, n))**2)
END DO
CALL cp_fm_struct_release(fm_struct_dipole_MO_trunc_reordered)
CALL cp_fm_struct_release(fm_struct_trans_mom_bse)
DO idir = 1, 3
CALL cp_fm_release(fm_dipole_MO_trunc_reordered(idir))
CALL cp_fm_release(fm_trans_mom_bse(idir))
CALL cp_fm_release(fm_dipole_ai_trunc(idir))
END DO
CALL cp_fm_release(fm_eigvec_XYsum)
CALL timestop(handle)
END SUBROUTINE get_oscillator_strengths
! **************************************************************************************************
!> \brief Computes and returns absorption spectrum for the frequency range and broadening
!> provided by the user.
!> Prelim Ref.: C. Ullrich, Time-Dependent Density-Functional Theory: Concepts and Applications
!> (Oxford University Press, Oxford, 2012), Eq. 7.51
!> \param oscill_str ...
!> \param polarizability_residues ...
!> \param Exc_ens ...
!> \param info_approximation ...
!> \param unit_nr ...
!> \param mp2_env ...
! **************************************************************************************************
SUBROUTINE compute_absorption_spectrum(oscill_str, polarizability_residues, Exc_ens, &
info_approximation, unit_nr, mp2_env)
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
INTENT(IN) :: oscill_str
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :), &
INTENT(IN) :: polarizability_residues
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:), &
INTENT(IN) :: Exc_ens
CHARACTER(LEN=10) :: info_approximation
INTEGER, INTENT(IN) :: unit_nr
TYPE(mp2_type), INTENT(INOUT) :: mp2_env
CHARACTER(LEN=*), PARAMETER :: routineN = 'compute_absorption_spectrum'
CHARACTER(LEN=10) :: eta_str, width_eta_format_str
CHARACTER(LEN=30) :: file_name_spectrum
INTEGER :: handle, i, idir, j, jdir, k, num_steps, &
unit_nr_file, width_eta
REAL(KIND=dp) :: eta, freq_end, freq_start, freq_step, &
omega
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: abs_spectrum
REAL(KIND=dp), DIMENSION(:), POINTER :: eta_list
TYPE(cp_logger_type), POINTER :: logger
CALL timeset(routineN, handle)
freq_step = mp2_env%bse%bse_spectrum_freq_step_size
freq_start = mp2_env%bse%bse_spectrum_freq_start
freq_end = mp2_env%bse%bse_spectrum_freq_end
eta_list => mp2_env%bse%bse_eta_spectrum_list
! Calculate number of steps to fit given frequency range
num_steps = NINT((freq_end - freq_start)/freq_step) + 1
DO k = 1, SIZE(eta_list)
eta = eta_list(k)
! Some magic to get a nice formatting of the eta value in filenames
width_eta = MAX(1, INT(LOG10(eta)) + 1) + 4
WRITE (width_eta_format_str, "(A2,I0,A3)") '(F', width_eta, '.3)'
WRITE (eta_str, width_eta_format_str) eta*evolt
! Filename itself
file_name_spectrum = 'BSE'//TRIM(ADJUSTL(info_approximation))//'eta='//TRIM(eta_str)//'.spectrum'
! First column is frequency in eV, second column is imaginary part of the trace of the polarizability
! The following 9 columns are the entries of the polarizability tensor
ALLOCATE (abs_spectrum(num_steps, 11))
abs_spectrum(:, :) = 0.0_dp
! Calculate the imaginary part of the mean dipole polarizability α_{avg}(ω)
! which is given by (cf. C. Ullrichs Book on TDDFT, Eq. 7.51)
! α_{avg}(ω) = \sum_{n=1}^{N_exc} \frac{f_n}{(ω+iη)² - (Ω^n)²}
! and then the imaginary part is (in the limit η -> 0)
! Im[α_{avg}(ω)] = \sum_{n=1}^{N_exc} f_n * η / ((ω - Ω^n)² + η²)
! where f_n are the oscillator strengths and E_exc the excitation energies
! For the full polarizability tensor, we have
! α_{µ µ'}(ω) = \sum_n [2 Ω^n d^n_µ d^n_µ'] / [(ω+iη)^2- (Ω^n)^2]
DO i = 1, num_steps
omega = freq_start + (i - 1)*freq_step
abs_spectrum(i, 1) = omega
DO j = 1, SIZE(oscill_str)
abs_spectrum(i, 2) = abs_spectrum(i, 2) - oscill_str(j)* &
AIMAG(1/((omega + CMPLX(0.0, eta, kind=dp))**2 - Exc_ens(j)**2))
DO idir = 1, 3
DO jdir = 1, 3
abs_spectrum(i, 2 + (idir - 1)*3 + jdir) = abs_spectrum(i, 2 + (idir - 1)*3 + jdir) &
- polarizability_residues(idir, jdir, j)* &
AIMAG(1/((omega + CMPLX(0.0, eta, kind=dp))**2 - Exc_ens(j)**2))
END DO
END DO
END DO
END DO
! Print it to file
logger => cp_get_default_logger()
IF (logger%para_env%is_source()) THEN
unit_nr_file = cp_logger_get_default_unit_nr()
ELSE
unit_nr_file = -1
END IF
IF (unit_nr_file > 0) THEN
CALL open_file(file_name_spectrum, unit_number=unit_nr_file, &
file_status="UNKNOWN", file_action="WRITE")
WRITE (unit_nr_file, '(A,A6)') "# Imaginary part of polarizability α_{µ µ'}(ω) = \sum_n "// &
"[2 Ω^n d_µ^n d_µ'^n] / [(ω+iη)²- (Ω^n)²] from Bethe Salpeter equation for method ", &
TRIM(ADJUSTL(info_approximation))
WRITE (unit_nr_file, '(A20,1X,10(2X,A20,1X))') "# Frequency (eV)", "Im{α_{avg}(ω)}", "Im{α_xx(ω)}", &
"Im{α_xy(ω)}", "Im{α_xz(ω)}", "Im{α_yx(ω)}", "Im{α_yy(ω)}", "Im{α_yz(ω)}", "Im{α_zx(ω)}", &
"Im{α_zy(ω)}", "Im{α_zz(ω)}"
DO i = 1, num_steps
WRITE (unit_nr_file, '(11(F20.8,1X))') abs_spectrum(i, 1)*evolt, abs_spectrum(i, 2:11)
END DO
CALL close_file(unit_nr_file)
END IF
DEALLOCATE (abs_spectrum)
END DO
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A50,A)') &
'BSE|', "Printed optical absorption spectrum to local file ", file_name_spectrum
WRITE (unit_nr, '(T2,A4,T7,A50)') &
'BSE|', "using the Eq. 7.51 from C. Ullrichs Book on TDDFT:"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T10,A73)') &
'BSE|', "Im{α_{avg}(ω)} = Im{\sum_{n=1}^{N_exc} \frac{f_n}{(ω+iη)² - (Ω^n)²}}"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A)') &
'BSE|', "or for the full polarizability tensor:"
WRITE (unit_nr, '(T2,A4,T10,A)') &
'BSE|', "α_{µ µ'}(ω) = \sum_n [2 Ω^n d_µ^n d_µ'^n] / [(ω+iη)²- (Ω^n)²]"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A)') &
'BSE|', "with transition moments d_µ^n, oscillator strengths f_n,"
WRITE (unit_nr, '(T2,A4,T7,A)') &
'BSE|', "and excitation energies Ω^n."
WRITE (unit_nr, '(T2,A4)') 'BSE|'
END IF
CALL timestop(handle)
END SUBROUTINE
! **************************************************************************************************
!> \brief ...
!> \param fm_X ...
!> \param fm_Y ...
!> \param mo_coeff ...
!> \param homo ...
!> \param virtual ...
!> \param info_approximation ...
!> \param oscill_str ...
!> \param qs_env ...
!> \param unit_nr ...
!> \param mp2_env ...
! **************************************************************************************************
SUBROUTINE calculate_NTOs(fm_X, fm_Y, &
mo_coeff, homo, virtual, &
info_approximation, &
oscill_str, &
qs_env, unit_nr, mp2_env)
TYPE(cp_fm_type), INTENT(IN) :: fm_X
TYPE(cp_fm_type), INTENT(IN), OPTIONAL :: fm_Y
TYPE(cp_fm_type), DIMENSION(:), INTENT(IN) :: mo_coeff
INTEGER, INTENT(IN) :: homo, virtual
CHARACTER(LEN=10) :: info_approximation
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: oscill_str
TYPE(qs_environment_type), POINTER :: qs_env
INTEGER, INTENT(IN) :: unit_nr
TYPE(mp2_type), INTENT(INOUT) :: mp2_env
CHARACTER(LEN=*), PARAMETER :: routineN = 'calculate_NTOs'
CHARACTER(LEN=20), DIMENSION(2) :: nto_name
INTEGER :: handle, homo_irred, i, i_nto, info_svd, &
j, n_exc, n_nto, nao_full, nao_trunc
INTEGER, DIMENSION(:), POINTER :: stride
LOGICAL :: append_cube, cube_file
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: eigval_svd_squ
REAL(KIND=dp), DIMENSION(:), POINTER :: eigval_svd
TYPE(cp_fm_struct_type), POINTER :: fm_struct_m, fm_struct_mo_coeff, &
fm_struct_nto_holes, &
fm_struct_nto_particles, &
fm_struct_nto_set
TYPE(cp_fm_type) :: fm_eigvl, fm_eigvr_t, fm_m, fm_mo_coeff, fm_nto_coeff_holes, &
fm_nto_coeff_particles, fm_nto_set, fm_X_ia, fm_Y_ai
TYPE(mo_set_type), ALLOCATABLE, DIMENSION(:) :: nto_set
TYPE(section_vals_type), POINTER :: bse_section, input, nto_section
CALL timeset(routineN, handle)
CALL get_qs_env(qs_env=qs_env, &
input=input)
bse_section => section_vals_get_subs_vals(input, "DFT%XC%WF_CORRELATION%RI_RPA%GW%BSE")
nao_full = qs_env%mos(1)%nao
nao_trunc = homo + virtual
! This is not influenced by the BSE cutoff
homo_irred = qs_env%mos(1)%homo
! M will have a block structure and is quadratic in homo+virtual, i.e.
! occ virt
! | 0 X_i,a | occ = homo
! M = | Y_a,i 0 | virt = virtual
!
! X and Y are here not the eigenvectors X_ia,n - instead we fix n and reshape the combined ia index
! Notice the index structure of the lower block, i.e. X is transposed
CALL cp_fm_struct_create(fm_struct_m, &
fm_X%matrix_struct%para_env, fm_X%matrix_struct%context, &
nao_trunc, nao_trunc)
CALL cp_fm_struct_create(fm_struct_mo_coeff, &
fm_X%matrix_struct%para_env, fm_X%matrix_struct%context, &
nao_full, nao_trunc)
CALL cp_fm_struct_create(fm_struct_nto_holes, &
fm_X%matrix_struct%para_env, fm_X%matrix_struct%context, &
nao_full, nao_trunc)
CALL cp_fm_struct_create(fm_struct_nto_particles, &
fm_X%matrix_struct%para_env, fm_X%matrix_struct%context, &
nao_full, nao_trunc)
CALL cp_fm_create(fm_mo_coeff, matrix_struct=fm_struct_mo_coeff, &
name="mo_coeff")
! Here, we take care of possible cutoffs
! Simply truncating the matrix causes problems with the print function
! Therefore, we keep the dimension, but set the coefficients of truncated indices to 0
CALL cp_fm_to_fm_submat_general(mo_coeff(1), fm_mo_coeff, &
nao_full, nao_trunc, &
1, homo_irred - homo + 1, &
1, 1, &
mo_coeff(1)%matrix_struct%context)
! Print some information about the NTOs
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'The Natural Transition Orbital (NTO) pairs φ_I(r_e) and χ_I(r_h) for a fixed'
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'excitation index n are obtained by singular value decomposition of T'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
' = (0 X)'
IF (PRESENT(fm_Y)) THEN
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'T = (Y^T 0)'
ELSE
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'T = (0 0)'
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'T = U Λ V^T'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'φ_I(r_e) = \sum_p V_pI ψ_p(r_e)'
WRITE (unit_nr, '(T2,A4,T15,A)') 'BSE|', &
'χ_I(r_h) = \sum_p U_pI ψ_p(r_e)'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'where we have introduced'
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A,T20,A)') &
'BSE|', "ψ_p:", "occupied and virtual molecular orbitals,"
WRITE (unit_nr, '(T2,A4,T7,A,T20,A)') &
'BSE|', "φ_I(r_e):", "NTO state for the electron,"
WRITE (unit_nr, '(T2,A4,T7,A,T20,A)') &
'BSE|', "χ_I(r_h):", "NTO state for the hole,"
WRITE (unit_nr, '(T2,A4,T7,A,T20,A)') &
'BSE|', "Λ:", "diagonal matrix of NTO weights λ_I,"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
"The NTOs are calculated with the following settings:"
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T7,A,T71,I10)') 'BSE|', 'Number of excitations, for which NTOs are computed', &
mp2_env%bse%num_print_exc_ntos
IF (mp2_env%bse%eps_nto_osc_str > 0.0_dp) THEN
WRITE (unit_nr, '(T2,A4,T7,A,T71,F10.3)') 'BSE|', 'Threshold for oscillator strength f^n', &
mp2_env%bse%eps_nto_osc_str
ELSE
WRITE (unit_nr, '(T2,A4,T7,A,T71,A10)') 'BSE|', 'Threshold for oscillator strength f^n', &
ADJUSTL("---")
END IF
WRITE (unit_nr, '(T2,A4,T7,A,T72,F10.3)') 'BSE|', 'Threshold for NTO weights (λ_I)^2', &
mp2_env%bse%eps_nto_eigval
END IF
! Write the header of NTO info table
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
IF (.NOT. PRESENT(fm_Y)) THEN
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'NTOs from solving the BSE within the TDA:'
ELSE
WRITE (unit_nr, '(T2,A4,T7,A)') 'BSE|', &
'NTOs from solving the BSE without the TDA:'
END IF
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T8,A12,T22,A8,T33,A14,T62,A)') 'BSE|', &
'Excitation n', "TDA/ABBA", "Index of NTO I", 'NTO weights (λ_I)^2'
END IF
DO j = 1, mp2_env%bse%num_print_exc_ntos
n_exc = mp2_env%bse%bse_nto_state_list_final(j)
! Takes care of unallocated oscill_str array in case of Triplet
IF (mp2_env%bse%eps_nto_osc_str > 0.0_dp) THEN
! Check actual values
IF (oscill_str(n_exc) < mp2_env%bse%eps_nto_osc_str) THEN
! Print skipped levels to table
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
WRITE (unit_nr, '(T2,A4,T8,I12,T24,A6,T42,A39)') 'BSE|', &
n_exc, info_approximation, "Skipped (Oscillator strength too small)"
END IF
CYCLE
END IF
END IF
CALL cp_fm_create(fm_m, matrix_struct=fm_struct_m, &
name="single_part_trans_dm")
CALL cp_fm_set_all(fm_m, 0.0_dp)
CALL cp_fm_create(fm_nto_coeff_holes, matrix_struct=fm_struct_nto_holes, &
name="nto_coeffs_holes")
CALL cp_fm_set_all(fm_nto_coeff_holes, 0.0_dp)
CALL cp_fm_create(fm_nto_coeff_particles, matrix_struct=fm_struct_nto_particles, &
name="nto_coeffs_particles")
CALL cp_fm_set_all(fm_nto_coeff_particles, 0.0_dp)
! Reshuffle from X_ia,n_exc to X_i,a
CALL reshuffle_eigvec(fm_X, fm_X_ia, homo, virtual, n_exc, &
.FALSE., unit_nr, mp2_env)
! Copy X to upper block in M, i.e. starting from column homo+1
CALL cp_fm_to_fm_submat(fm_X_ia, fm_m, &
homo, virtual, &
1, 1, &
1, homo + 1)
CALL cp_fm_release(fm_X_ia)
! Copy Y if present
IF (PRESENT(fm_Y)) THEN
! Reshuffle from Y_ia,n_exc to Y_a,i
CALL reshuffle_eigvec(fm_Y, fm_Y_ai, homo, virtual, n_exc, &
.TRUE., unit_nr, mp2_env)
! Copy Y^T to lower block in M, i.e. starting from row homo+1
CALL cp_fm_to_fm_submat(fm_Y_ai, fm_m, &
virtual, homo, &
1, 1, &
homo + 1, 1)
CALL cp_fm_release(fm_Y_ai)
END IF
! Now we compute the SVD of M_{occ+virt,occ+virt}, which yields
! M = U * Lambda * V^T
! Initialize matrices and arrays to store left/right eigenvectors and singular values
CALL cp_fm_create(matrix=fm_eigvl, &
matrix_struct=fm_m%matrix_struct, &
name="LEFT_SINGULAR_MATRIX")
CALL cp_fm_set_all(fm_eigvl, alpha=0.0_dp)
CALL cp_fm_create(matrix=fm_eigvr_t, &
matrix_struct=fm_m%matrix_struct, &
name="RIGHT_SINGULAR_MATRIX")
CALL cp_fm_set_all(fm_eigvr_t, alpha=0.0_dp)
ALLOCATE (eigval_svd(nao_trunc))
eigval_svd(:) = 0.0_dp
info_svd = 0
CALL cp_fm_svd(fm_m, fm_eigvl, fm_eigvr_t, eigval_svd, info_svd)
IF (info_svd /= 0) THEN
IF (unit_nr > 0) THEN
CALL cp_warn(__LOCATION__, &
"SVD for computation of NTOs not successful. "// &
"Skipping print of NTOs.")
IF (info_svd > 0) THEN
CALL cp_warn(__LOCATION__, &
"PDGESVD detected heterogeneity. "// &
"Decreasing number of MPI ranks might solve this issue.")
END IF
END IF
! Release matrices to avoid memory leaks
CALL cp_fm_release(fm_m)
CALL cp_fm_release(fm_nto_coeff_holes)
CALL cp_fm_release(fm_nto_coeff_particles)
ELSE
! Rescale singular values as done in Martin2003 (10.1063/1.1558471)
ALLOCATE (eigval_svd_squ(nao_trunc))
eigval_svd_squ(:) = eigval_svd(:)**2
! Sanity check for TDA: In case of TDA, the sum should be \sum_ia |X_ia|^2 = 1
IF (.NOT. PRESENT(fm_Y)) THEN
IF (ABS(SUM(eigval_svd_squ) - 1) >= 1e-5) THEN
CPWARN("Sum of NTO coefficients deviates from 1!")
END IF
END IF
! Create NTO coefficients for later print to grid via TDDFT routine
! Apply U = fm_eigvl to MO coeffs, which yields hole states
CALL parallel_gemm("N", "N", nao_full, nao_trunc, nao_trunc, 1.0_dp, fm_mo_coeff, fm_eigvl, 0.0_dp, &
fm_nto_coeff_holes)
! Apply V^T = fm_eigvr_t to MO coeffs, which yields particle states
CALL parallel_gemm("N", "T", nao_full, nao_trunc, nao_trunc, 1.0_dp, fm_mo_coeff, fm_eigvr_t, 0.0_dp, &
fm_nto_coeff_particles)
!Release intermediary work matrices
CALL cp_fm_release(fm_m)
CALL cp_fm_release(fm_eigvl)
CALL cp_fm_release(fm_eigvr_t)
! Transfer NTO coefficients to sets
nto_name(1) = 'Hole_coord'
nto_name(2) = 'Particle_coord'
ALLOCATE (nto_set(2))
! Extract number of significant NTOs
n_nto = 0
DO i_nto = 1, nao_trunc
IF (eigval_svd_squ(i_nto) > mp2_env%bse%eps_nto_eigval) THEN
n_nto = n_nto + 1
ELSE
! Since svd orders in descending order, we can exit the loop if smaller
EXIT
END IF
END DO
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A4)') 'BSE|'
DO i_nto = 1, n_nto
WRITE (unit_nr, '(T2,A4,T8,I12,T24,A6,T41,I6,T71,F10.5)') 'BSE|', &
n_exc, info_approximation, i_nto, eigval_svd_squ(i_nto)
END DO
END IF
CALL cp_fm_struct_create(fm_struct_nto_set, template_fmstruct=fm_struct_nto_holes, &
ncol_global=n_nto)
CALL cp_fm_create(fm_nto_set, fm_struct_nto_set)
DO i = 1, 2
CALL allocate_mo_set(nto_set(i), nao_trunc, n_nto, 0, 0.0_dp, 2.0_dp, 0.0_dp)
CALL init_mo_set(nto_set(i), fm_ref=fm_nto_set, name=nto_name(i))
END DO
CALL cp_fm_release(fm_nto_set)
CALL cp_fm_struct_release(fm_struct_nto_set)
! Fill NTO sets
CALL cp_fm_to_fm(fm_nto_coeff_holes, nto_set(1)%mo_coeff, ncol=n_nto)
CALL cp_fm_to_fm(fm_nto_coeff_particles, nto_set(2)%mo_coeff, ncol=n_nto)
! Cube files
nto_section => section_vals_get_subs_vals(bse_section, "NTO_ANALYSIS")
CALL section_vals_val_get(nto_section, "CUBE_FILES", l_val=cube_file)
CALL section_vals_val_get(nto_section, "STRIDE", i_vals=stride)
CALL section_vals_val_get(nto_section, "APPEND", l_val=append_cube)
IF (cube_file) THEN
CALL print_bse_nto_cubes(qs_env, nto_set, n_exc, info_approximation, &
stride, append_cube, nto_section)
END IF
CALL cp_fm_release(fm_nto_coeff_holes)
CALL cp_fm_release(fm_nto_coeff_particles)
DEALLOCATE (eigval_svd)
DEALLOCATE (eigval_svd_squ)
DO i = 1, 2
CALL deallocate_mo_set(nto_set(i))
END DO
DEALLOCATE (nto_set)
END IF
END DO
CALL cp_fm_release(fm_mo_coeff)
CALL cp_fm_struct_release(fm_struct_m)
CALL cp_fm_struct_release(fm_struct_nto_holes)
CALL cp_fm_struct_release(fm_struct_nto_particles)
CALL cp_fm_struct_release(fm_struct_mo_coeff)
CALL timestop(handle)
END SUBROUTINE calculate_NTOs
! **************************************************************************************************
!> \brief ...
!> \param exc_descr ...
!> \param fm_eigvec_X ...
!> \param fm_dipole_ij_trunc ...
!> \param fm_dipole_ab_trunc ...
!> \param fm_dipole_ai_trunc ...
!> \param fm_quadpole_ij_trunc ...
!> \param fm_quadpole_ab_trunc ...
!> \param homo ...
!> \param virtual ...
!> \param unit_nr ...
!> \param mp2_env ...
!> \param qs_env ...
!> \param fm_eigvec_Y ...
! **************************************************************************************************
SUBROUTINE get_exciton_descriptors(exc_descr, fm_eigvec_X, &
fm_dipole_ij_trunc, fm_dipole_ab_trunc, fm_dipole_ai_trunc, &
fm_quadpole_ij_trunc, fm_quadpole_ab_trunc, &
homo, virtual, unit_nr, &
mp2_env, qs_env, &
fm_eigvec_Y)
TYPE(exciton_descr_type), ALLOCATABLE, &
DIMENSION(:) :: exc_descr
TYPE(cp_fm_type), INTENT(IN) :: fm_eigvec_X
TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:), &
INTENT(IN) :: fm_dipole_ij_trunc, fm_dipole_ab_trunc, &
fm_dipole_ai_trunc, &
fm_quadpole_ij_trunc, &
fm_quadpole_ab_trunc
INTEGER, INTENT(IN) :: homo, virtual, unit_nr
TYPE(mp2_type), INTENT(INOUT) :: mp2_env
TYPE(qs_environment_type), POINTER :: qs_env
TYPE(cp_fm_type), INTENT(IN), OPTIONAL :: fm_eigvec_Y
CHARACTER(LEN=*), PARAMETER :: routineN = 'get_exciton_descriptors'
INTEGER :: handle, i_dir, i_exc, n_exc
INTEGER, DIMENSION(3) :: mask_quadrupole
LOGICAL :: flag_TDA
REAL(KIND=dp) :: norm_X, norm_XpY, norm_Y
REAL(KIND=dp), DIMENSION(3) :: r_e_h_XX, r_e_h_XY, r_e_h_YX, r_e_h_YY, &
r_e_sq_X, r_e_sq_Y, r_e_X, r_e_Y, &
r_h_sq_X, r_h_sq_Y, r_h_X, r_h_Y
TYPE(cp_fm_struct_type), POINTER :: fm_struct_ab, fm_struct_ia
TYPE(cp_fm_type) :: fm_work_ba, fm_work_ia, fm_work_ia_2, &
fm_X_ia, fm_Y_ia
TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
TYPE(section_vals_type), POINTER :: input, subsys_section
CALL timeset(routineN, handle)
n_exc = homo*virtual
IF (PRESENT(fm_eigvec_Y)) THEN
flag_TDA = .FALSE.
ELSE
flag_TDA = .TRUE.
END IF
! translates 1,2,3 to diagonal entries of quadrupoles xx, yy, zz
! Ordering in quadrupole moments is x, y, z, xx, xy, xz, yy, yz, zz
mask_quadrupole = (/4, 7, 9/)
ALLOCATE (exc_descr(mp2_env%bse%num_print_exc_descr))
CALL cp_fm_struct_create(fm_struct_ia, &
fm_eigvec_X%matrix_struct%para_env, fm_eigvec_X%matrix_struct%context, &
homo, virtual)
CALL cp_fm_struct_create(fm_struct_ab, &
fm_eigvec_X%matrix_struct%para_env, fm_eigvec_X%matrix_struct%context, &
virtual, virtual)
! print actual coords (might be centered and differing from input xyz) for debug runs
IF (mp2_env%bse%bse_debug_print) THEN
CALL get_qs_env(qs_env, particle_set=particle_set, &
qs_kind_set=qs_kind_set, input=input)
subsys_section => section_vals_get_subs_vals(input, "SUBSYS")
IF (unit_nr > 0) THEN
WRITE (unit_nr, '(T2,A10,T13,A)') 'BSE|DEBUG|', &
'Printing internal geometry for debug purposes'
END IF
CALL write_qs_particle_coordinates(particle_set, qs_kind_set, subsys_section, label="BSE")
END IF
DO i_exc = 1, mp2_env%bse%num_print_exc_descr
r_e_X(:) = 0.0_dp
r_e_Y(:) = 0.0_dp
r_h_X(:) = 0.0_dp
r_h_Y(:) = 0.0_dp
r_e_sq_X(:) = 0.0_dp
r_h_sq_X(:) = 0.0_dp
r_e_sq_Y(:) = 0.0_dp
r_h_sq_Y(:) = 0.0_dp
r_e_h_XX(:) = 0.0_dp
r_e_h_XY(:) = 0.0_dp
r_e_h_YX(:) = 0.0_dp
r_e_h_YY(:) = 0.0_dp
norm_X = 0.0_dp
norm_Y = 0.0_dp
norm_XpY = 0.0_dp
! Initialize values of exciton descriptors
exc_descr(i_exc)%r_e(:) = 0.0_dp
exc_descr(i_exc)%r_h(:) = 0.0_dp
exc_descr(i_exc)%r_e_sq(:) = 0.0_dp
exc_descr(i_exc)%r_h_sq(:) = 0.0_dp
exc_descr(i_exc)%r_e_h(:) = 0.0_dp
exc_descr(i_exc)%flag_TDA = flag_TDA
exc_descr(i_exc)%norm_XpY = 0.0_dp
CALL reshuffle_eigvec(fm_eigvec_X, fm_X_ia, homo, virtual, i_exc, &
.FALSE., unit_nr, mp2_env)
! Norm of X
CALL cp_fm_trace(fm_X_ia, fm_X_ia, norm_X)
norm_XpY = norm_X
IF (.NOT. flag_TDA) THEN
CALL reshuffle_eigvec(fm_eigvec_Y, fm_Y_ia, homo, virtual, i_exc, &
.FALSE., unit_nr, mp2_env)
! Norm of Y
CALL cp_fm_trace(fm_Y_ia, fm_Y_ia, norm_Y)
norm_XpY = norm_XpY + norm_Y
END IF
exc_descr(i_exc)%norm_XpY = norm_XpY
! <r_h>_X = Tr[ X^T µ_ij X + Y µ_ab Y^T ] = X_ai µ_ij X_ja + Y_ia µ_ab Y_bi
DO i_dir = 1, 3
! <r_h>_X = X_ai µ_ij X_ja + ...
CALL trace_exciton_descr(fm_X_ia, fm_dipole_ij_trunc(i_dir), fm_X_ia, r_h_X(i_dir))
r_h_X(i_dir) = r_h_X(i_dir)/norm_XpY
IF (.NOT. flag_TDA) THEN
! <r_h>_X = ... + Y_ia µ_ab Y_bi
CALL trace_exciton_descr(fm_Y_ia, fm_Y_ia, fm_dipole_ab_trunc(i_dir), r_h_Y(i_dir))
r_h_Y(i_dir) = r_h_Y(i_dir)/norm_XpY
END IF
END DO
exc_descr(i_exc)%r_h(:) = r_h_X(:) + r_h_Y(:)
! <r_e>_X = Tr[ X µ_ab X^T + Y^T µ_ij Y ] = X_ia µ_ab X_bi + Y_ai µ_ij Y_ja
DO i_dir = 1, 3
! <r_e>_X = work_ib X_bi + ... = X_ib^T work_ib + ...
CALL trace_exciton_descr(fm_X_ia, fm_X_ia, fm_dipole_ab_trunc(i_dir), r_e_X(i_dir))
r_e_X(i_dir) = r_e_X(i_dir)/norm_XpY
IF (.NOT. flag_TDA) THEN
! <r_e>_X = ... + Y_ai µ_ij Y_ja
CALL trace_exciton_descr(fm_Y_ia, fm_dipole_ij_trunc(i_dir), fm_Y_ia, r_e_Y(i_dir))
r_e_Y(i_dir) = r_e_Y(i_dir)/norm_XpY
END IF
END DO
exc_descr(i_exc)%r_e(:) = r_e_X(:) + r_e_Y(:)
! <r_h^2>_X = Tr[ X^T M_ij X + Y M_ab Y^T ] = X_ai M_ij X_ja + Y_ia M_ab Y_bi
DO i_dir = 1, 3
! <r_h^2>_X = X_ai M_ij X_ja + ...
CALL trace_exciton_descr(fm_X_ia, fm_quadpole_ij_trunc(mask_quadrupole(i_dir)), &
fm_X_ia, r_h_sq_X(i_dir))
r_h_sq_X(i_dir) = r_h_sq_X(i_dir)/norm_XpY
IF (.NOT. flag_TDA) THEN
! <r_h^2>_X = ... + Y_ia M_ab Y_bi
CALL trace_exciton_descr(fm_Y_ia, fm_Y_ia, &
fm_quadpole_ab_trunc(mask_quadrupole(i_dir)), r_h_sq_Y(i_dir))
r_h_sq_Y(i_dir) = r_h_sq_Y(i_dir)/norm_XpY
END IF
END DO
exc_descr(i_exc)%r_h_sq(:) = r_h_sq_X(:) + r_h_sq_Y(:)
! <r_e^2>_X = Tr[ X M_ab X^T + Y^T M_ij Y ] = X_ia M_ab X_bi + Y_ai M_ij Y_ja
DO i_dir = 1, 3
! <r_e^2>_X = work_ib X_bi + ... = X_ib^T work_ib + ...
CALL trace_exciton_descr(fm_X_ia, fm_X_ia, &
fm_quadpole_ab_trunc(mask_quadrupole(i_dir)), r_e_sq_X(i_dir))
r_e_sq_X(i_dir) = r_e_sq_X(i_dir)/norm_XpY
IF (.NOT. flag_TDA) THEN
! <r_e^2>_X = ... + Y_ai M_ij Y_ja
CALL trace_exciton_descr(fm_Y_ia, fm_quadpole_ij_trunc(mask_quadrupole(i_dir)), &
fm_Y_ia, r_e_sq_Y(i_dir))
r_e_sq_Y(i_dir) = r_e_sq_Y(i_dir)/norm_XpY
END IF
END DO
exc_descr(i_exc)%r_e_sq(:) = r_e_sq_X(:) + r_e_sq_Y(:)
! <r_h r_e>_X
! = Tr[ X^T µ_ij X µ_ab + Y^T µ_ij Y µ_ab + X µ_ai Y µ_ai + Y µ_ai X µ_ai]
! = X_bj µ_ji X_ia µ_ab + Y_bj µ_ji Y_ia µ_ab + X_ia µ_aj Y_jb µ_bi + Y_ia µ_aj X_jb µ_bi
CALL cp_fm_create(fm_work_ia, fm_struct_ia)
CALL cp_fm_create(fm_work_ia_2, fm_struct_ia)
CALL cp_fm_create(fm_work_ba, fm_struct_ab)
DO i_dir = 1, 3
! First term - X^T µ_ij X µ_ab
CALL cp_fm_set_all(fm_work_ia, 0.0_dp)
CALL cp_fm_set_all(fm_work_ia_2, 0.0_dp)
! work_ib = X_ia µ_ab
CALL parallel_gemm("N", "N", homo, virtual, virtual, 1.0_dp, &
fm_X_ia, fm_dipole_ab_trunc(i_dir), 0.0_dp, fm_work_ia)
! work_ja_2 = µ_ji work_ia
CALL parallel_gemm("N", "N", homo, virtual, homo, 1.0_dp, &
fm_dipole_ij_trunc(i_dir), fm_work_ia, 0.0_dp, fm_work_ia_2)
! <r_h r_e>_X = work_ia_2 X_bj + ... = X^T work_ia_2 + ...
CALL cp_fm_trace(fm_X_ia, fm_work_ia_2, r_e_h_XX(i_dir))
r_e_h_XX(i_dir) = r_e_h_XX(i_dir)/norm_XpY
IF (.NOT. flag_TDA) THEN
! Second term - Y^T µ_ij Y µ_ab
CALL cp_fm_set_all(fm_work_ia, 0.0_dp)
CALL cp_fm_set_all(fm_work_ia_2, 0.0_dp)
! work_ib = Y_ia µ_ab
CALL parallel_gemm("N", "N", homo, virtual, virtual, 1.0_dp, &
fm_Y_ia, fm_dipole_ab_trunc(i_dir), 0.0_dp, fm_work_ia)
! work_ja_2 = µ_ji work_ia
CALL parallel_gemm("N", "N", homo, virtual, homo, 1.0_dp, &
fm_dipole_ij_trunc(i_dir), fm_work_ia, 0.0_dp, fm_work_ia_2)
! <r_h r_e>_X = work_ia_2 Y_bj + ... = Y^T work_ia_2 + ...
CALL cp_fm_trace(fm_Y_ia, fm_work_ia_2, r_e_h_YY(i_dir))
r_e_h_YY(i_dir) = r_e_h_YY(i_dir)/norm_XpY
! Third term - X µ_ai Y µ_ai = X_ia µ_aj Y_jb µ_bi
! Reshuffle for usage of trace (where first argument is transposed)
! = µ_aj Y_jb µ_bi X_ia =
! \__________/
! fm_work_ai
! fm_work_ai = µ_aj Y_jb µ_bi
! fm_work_ia = µ_ib Y_bj µ_ja
! \_____/
! fm_work_ba
CALL cp_fm_set_all(fm_work_ba, 0.0_dp)
CALL cp_fm_set_all(fm_work_ia, 0.0_dp)
! fm_work_ba = Y_bj µ_ja
CALL parallel_gemm("T", "T", virtual, virtual, homo, 1.0_dp, &
fm_Y_ia, fm_dipole_ai_trunc(i_dir), 0.0_dp, fm_work_ba)
! fm_work_ia = µ_ib fm_work_ba
CALL parallel_gemm("T", "N", homo, virtual, virtual, 1.0_dp, &
fm_dipole_ai_trunc(i_dir), fm_work_ba, 0.0_dp, fm_work_ia)
! <r_h r_e>_X = ... + X_ia µ_aj Y_jb µ_bi
CALL cp_fm_trace(fm_work_ia, fm_X_ia, r_e_h_XY(i_dir))
r_e_h_XY(i_dir) = r_e_h_XY(i_dir)/norm_XpY
! Fourth term - Y µ_ai X µ_ai = Y_ia µ_aj X_jb µ_bi
! Reshuffle for usage of trace (where first argument is transposed)
! = µ_aj X_jb µ_bi Y_ia =
! \__________/
! fm_work_ai
! fm_work_ai = µ_aj X_jb µ_bi
! fm_work_ia = µ_ib X_bj µ_ja
! \_____/
! fm_work_ba
CALL cp_fm_set_all(fm_work_ba, 0.0_dp)
CALL cp_fm_set_all(fm_work_ia, 0.0_dp)
! fm_work_ba = Y_bj µ_ja
CALL parallel_gemm("T", "T", virtual, virtual, homo, 1.0_dp, &
fm_X_ia, fm_dipole_ai_trunc(i_dir), 0.0_dp, fm_work_ba)
! fm_work_ia = µ_ib fm_work_ba
CALL parallel_gemm("T", "N", homo, virtual, virtual, 1.0_dp, &
fm_dipole_ai_trunc(i_dir), fm_work_ba, 0.0_dp, fm_work_ia)
! <r_h r_e>_X = ... + X_ia µ_aj Y_jb µ_bi
CALL cp_fm_trace(fm_work_ia, fm_Y_ia, r_e_h_YX(i_dir))
r_e_h_YX(i_dir) = r_e_h_YX(i_dir)/norm_XpY
END IF
END DO
exc_descr(i_exc)%r_e_h(:) = r_e_h_XX(:) + r_e_h_XY(:) + r_e_h_YX(:) + r_e_h_YY(:)
CALL cp_fm_release(fm_work_ia)
CALL cp_fm_release(fm_work_ia_2)
CALL cp_fm_release(fm_work_ba)
! diff_r_abs = |<r_h>_X - <r_e>_X|
exc_descr(i_exc)%diff_r_abs = SQRT(SUM((exc_descr(i_exc)%r_h(:) - exc_descr(i_exc)%r_e(:))**2))
! σ_e = sqrt( <r_e^2>_X - <r_e>_X^2 )
exc_descr(i_exc)%sigma_e = SQRT(SUM(exc_descr(i_exc)%r_e_sq(:)) - SUM(exc_descr(i_exc)%r_e(:)**2))
! σ_h = sqrt( <r_h^2>_X - <r_h>_X^2 )
exc_descr(i_exc)%sigma_h = SQRT(SUM(exc_descr(i_exc)%r_h_sq(:)) - SUM(exc_descr(i_exc)%r_h(:)**2))
! COV(r_e, r_h) = < r_e r_h >_X - < r_e >_X < r_h >_X
exc_descr(i_exc)%cov_e_h_sum = 0.0_dp
exc_descr(i_exc)%cov_e_h(:) = 0.0_dp
DO i_dir = 1, 3
exc_descr(i_exc)%cov_e_h(i_dir) = exc_descr(i_exc)%r_e_h(i_dir) &
- exc_descr(i_exc)%r_e(i_dir)*exc_descr(i_exc)%r_h(i_dir)
exc_descr(i_exc)%cov_e_h_sum = exc_descr(i_exc)%cov_e_h_sum + &
exc_descr(i_exc)%r_e_h(i_dir) - exc_descr(i_exc)%r_e(i_dir)*exc_descr(i_exc)%r_h(i_dir)
END DO
! root-mean-square e-h separation
exc_descr(i_exc)%diff_r_sqr = SQRT(exc_descr(i_exc)%diff_r_abs**2 + &
exc_descr(i_exc)%sigma_e**2 + exc_descr(i_exc)%sigma_h**2 &
- 2*exc_descr(i_exc)%cov_e_h_sum)
! e-h-correlation coefficient R_eh = COV(r_e, r_h) / ( σ_e σ_h )
exc_descr(i_exc)%corr_e_h = exc_descr(i_exc)%cov_e_h_sum/(exc_descr(i_exc)%sigma_e*exc_descr(i_exc)%sigma_h)
! Expectation values of r_e and r_h
exc_descr(i_exc)%r_e_shift(:) = exc_descr(i_exc)%r_e(:)
exc_descr(i_exc)%r_h_shift(:) = exc_descr(i_exc)%r_h(:)
CALL cp_fm_release(fm_X_ia)
IF (.NOT. flag_TDA) THEN
CALL cp_fm_release(fm_Y_ia)
END IF
END DO
CALL cp_fm_struct_release(fm_struct_ia)
CALL cp_fm_struct_release(fm_struct_ab)
CALL timestop(handle)
END SUBROUTINE get_exciton_descriptors
END MODULE bse_properties

File diff suppressed because it is too large Load diff

View file

@ -88,7 +88,8 @@ MODULE bibliography
Caldeweyher2017, Caldeweyher2019, Caldeweyher2020, Freeman1977, Gruneis2009, &
Stein2022, Stein2024, Pracht2019, &
Blase2018, Blase2020, Bruneval2015, Golze2019, Gui2018, Jacquemin2017, Liu2020, &
Sander2015, Schreiber2008, vanSetten2015, Setyawan2010, Ahart2024
Sander2015, Schreiber2008, vanSetten2015, Setyawan2010, Ahart2024, Knysh2024, &
Schambeck2024, Mewes2018
CONTAINS
@ -1884,12 +1885,32 @@ CONTAINS
source="J. Chem. Theory Comput.", volume="20", pages="6772-6780", &
year=2024, doi="10.1021/acs.jctc.4c00371")
CALL add_reference(key=Knysh2024, &
authors=s2a("I. Knysh", "F. Lipparini", "A. Blondel", "I. Duchemin", "X. Blase", &
"P.-F. Loos", "D. Jacquemin"), &
title="Reference CC3 Excitation Energies for Organic Chromophores: "// &
"Benchmarking TD-DFT, BSE/GW, and Wave Function Methods", &
source="J. Chem. Theory Comput.", volume="20", pages="8152-8174", &
year=2024, doi="10.1021/acs.jctc.4c00906")
CALL add_reference(key=Schambeck2024, &
authors=s2a("M. Schambeck", "D. Golze", "J. Wilhelm"), &
title="Solving multipole challenges in the GW 100 benchmark enables precise low-scaling GW calculations", &
source="Phys. Rev. B", volume="110", pages="125146", &
year=2024, doi="10.1103/PhysRevB.110.125146")
CALL add_reference(key=Pracht2019, &
authors=s2a("P. Pracht", "E. Caldeweyher", "S. Ehlert", "S. Grimme"), &
title="A Robust Non-Self-Consistent Tight-Binding Quantum Chemistry Method for large Molecules", &
source="ChemRxiv", volume="", pages="", &
year=2019, doi="10.26434/chemrxiv.8326202.v1")
CALL add_reference(key=Mewes2018, &
authors=s2a("S. Mewes", "F. Plasser", "A. Krylov", "A. Dreuw"), &
title="Benchmarking Excited-State Calculations Using Exciton Properties", &
source="J. Chem. Theory Comput.", volume="14", pages="710-725", &
year=2018, doi="10.1021/acs.jctc.7b01145 ")
END SUBROUTINE add_all_references
END MODULE bibliography

View file

@ -41,7 +41,23 @@ MODULE cp_fm_diag
USE cp_fm_types, ONLY: cp_fm_get_info, &
cp_fm_set_element, &
cp_fm_to_fm, &
cp_fm_type, &
cp_fm_create, &
cp_fm_get_info, &
cp_fm_release, &
cp_fm_set_all, &
cp_fm_to_fm, &
cp_fm_to_fm_submat, &
cp_fm_type
USE cp_fm_struct, ONLY: cp_fm_struct_equivalent, &
cp_fm_struct_create, &
cp_fm_struct_release, &
cp_fm_struct_type
USE cp_log_handling, ONLY: cp_logger_get_default_unit_nr, &
cp_get_default_logger, &
cp_logger_get_default_io_unit, &
cp_logger_type, &
cp_to_string
USE cp_log_handling, ONLY: cp_get_default_logger, &
cp_logger_get_default_unit_nr, &
cp_logger_get_unit_nr, &
@ -104,6 +120,7 @@ MODULE cp_fm_diag
cp_fm_power, &
cp_fm_syevd, &
cp_fm_syevx, &
cp_fm_svd, &
cp_fm_geeig, &
cp_fm_geeig_canon, &
diag_init, &
@ -882,6 +899,127 @@ CONTAINS
END SUBROUTINE cp_fm_syevx
! **************************************************************************************************
!> \brief decomposes a quadratic matrix into its singular value decomposition
!> \param matrix_a ...
!> \param matrix_eigvl ...
!> \param matrix_eigvr_t ...
!> \param eigval ...
!> \param info ...
!> \author Maximilian Graml
! **************************************************************************************************
SUBROUTINE cp_fm_svd(matrix_a, matrix_eigvl, matrix_eigvr_t, eigval, info)
TYPE(cp_fm_type), INTENT(IN) :: matrix_a
TYPE(cp_fm_type), INTENT(INOUT) :: matrix_eigvl, matrix_eigvr_t
REAL(KIND=dp), DIMENSION(:), POINTER, &
INTENT(INOUT) :: eigval
INTEGER, INTENT(OUT), OPTIONAL :: info
CHARACTER(LEN=*), PARAMETER :: routineN = 'cp_fm_svd'
CHARACTER(LEN=2*default_string_length) :: message
INTEGER :: handle, n, m, myinfo, lwork
REAL(KIND=dp), DIMENSION(:, :), POINTER :: a
TYPE(cp_fm_type) :: matrix_lu
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: work
#if defined(__parallel)
INTEGER, DIMENSION(9) :: desca, descu, descvt
#endif
CALL timeset(routineN, handle)
CALL cp_fm_create(matrix=matrix_lu, &
matrix_struct=matrix_a%matrix_struct, &
name="A_lu"//TRIM(ADJUSTL(cp_to_string(1)))//"MATRIX")
CALL cp_fm_to_fm(matrix_a, matrix_lu)
a => matrix_lu%local_data
m = matrix_lu%matrix_struct%nrow_global
n = matrix_lu%matrix_struct%ncol_global
! Assert that incoming matrix is quadratic
CPASSERT(m == n)
! Prepare for workspace queries
myinfo = 0
lwork = -1
ALLOCATE (work(1))
work(:) = 0.0_dp
#if defined(__parallel)
! To do: That might need a redistribution check as in cp_fm_syevd
desca(:) = matrix_lu%matrix_struct%descriptor(:)
descu(:) = matrix_eigvl%matrix_struct%descriptor(:)
descvt(:) = matrix_eigvr_t%matrix_struct%descriptor(:)
! Workspace query
CALL pdgesvd('V', 'V', m, m, matrix_lu%local_data, 1, 1, desca, eigval, matrix_eigvl%local_data, &
1, 1, descu, matrix_eigvr_t%local_data, 1, 1, descvt, work, lwork, myinfo)
IF (matrix_lu%matrix_struct%para_env%is_source() .AND. (myinfo /= 0)) THEN
WRITE (message, "(A,I0,A)") "ERROR in PDGESVD: Work space query failed (INFO = ", myinfo, ")"
IF (PRESENT(info)) THEN
CPWARN(TRIM(message))
ELSE
CPABORT(TRIM(message))
END IF
END IF
lwork = INT(work(1))
DEALLOCATE (work)
ALLOCATE (work(lwork))
! SVD
CALL pdgesvd('V', 'V', m, m, matrix_lu%local_data, 1, 1, desca, eigval, matrix_eigvl%local_data, &
1, 1, descu, matrix_eigvr_t%local_data, 1, 1, descvt, work, lwork, myinfo)
IF (matrix_lu%matrix_struct%para_env%is_source() .AND. (myinfo /= 0)) THEN
WRITE (message, "(A,I0,A)") "ERROR in PDGESVD: Matrix diagonalization failed (INFO = ", myinfo, ")"
IF (PRESENT(info)) THEN
CPWARN(TRIM(message))
ELSE
CPABORT(TRIM(message))
END IF
END IF
#else
! Workspace query
CALL dgesvd('S', 'S', m, m, matrix_lu%local_data, m, eigval, matrix_eigvl%local_data, &
m, matrix_eigvr_t%local_data, m, work, lwork, myinfo)
IF (myinfo /= 0) THEN
WRITE (message, "(A,I0,A)") "ERROR in DGESVD: Work space query failed (INFO = ", myinfo, ")"
IF (PRESENT(info)) THEN
CPWARN(TRIM(message))
ELSE
CPABORT(TRIM(message))
END IF
END IF
! SVD
lwork = INT(work(1))
DEALLOCATE (work)
ALLOCATE (work(lwork))
work(:) = 0.0_dp
CALL dgesvd('S', 'S', m, m, matrix_lu%local_data, m, eigval, matrix_eigvl%local_data, &
m, matrix_eigvr_t%local_data, m, work, lwork, myinfo)
IF (myinfo /= 0) THEN
WRITE (message, "(A,I0,A)") "ERROR in DGESVD: Matrix diagonalization failed (INFO = ", myinfo, ")"
IF (PRESENT(info)) THEN
CPWARN(TRIM(message))
ELSE
CPABORT(TRIM(message))
END IF
END IF
#endif
! Release intermediary matrices
DEALLOCATE (work)
CALL cp_fm_release(matrix_lu)
IF (PRESENT(info)) info = myinfo
CALL timestop(handle)
END SUBROUTINE cp_fm_svd
! **************************************************************************************************
!> \brief ...
!> \param matrix ...

View file

@ -49,7 +49,10 @@ MODULE input_cp2k_mp2
section_create, &
section_release, &
section_type
USE input_val_types, ONLY: integer_t, &
USE input_val_types, ONLY: char_t, &
integer_t, &
logical_t, &
real_t
USE kinds, ONLY: dp
USE string_utilities, ONLY: newline, &
@ -1109,7 +1112,7 @@ CONTAINS
CALL keyword_create(keyword, __LOCATION__, name="LOWER_BOUND", &
description="Lower bound for GW-DOS in eV.", &
usage="GW_DOS_LOWER_BOUND -20.0", &
usage="LOWER_BOUND -20.0", &
default_r_val=cp_unit_to_cp2k(value=-20.0_dp, unit_str="eV"), &
unit_str="eV")
CALL section_add_keyword(gw_dos_section, keyword)
@ -1117,7 +1120,7 @@ CONTAINS
CALL keyword_create(keyword, __LOCATION__, name="UPPER_BOUND", &
description="Upper bound for GW-DOS in eV.", &
usage="GW_DOS_UPPER_BOUND 5.0", &
usage="UPPER_BOUND 5.0", &
default_r_val=cp_unit_to_cp2k(value=0.0_dp, unit_str="eV"), &
unit_str="eV")
CALL section_add_keyword(gw_dos_section, keyword)
@ -1125,7 +1128,7 @@ CONTAINS
CALL keyword_create(keyword, __LOCATION__, name="STEP", &
description="Difference of two consecutive energy levels for GW-DOS.", &
usage="GW_DOS_PRECISION 0.1", &
usage="STEP 0.1", &
default_r_val=cp_unit_to_cp2k(value=0.0_dp, unit_str="eV"), &
unit_str="eV")
CALL section_add_keyword(gw_dos_section, keyword)
@ -1133,14 +1136,14 @@ CONTAINS
CALL keyword_create(keyword, __LOCATION__, name="MIN_LEVEL_SPECTRAL", &
description="Lowest energy level to print the self energy to files.", &
usage="MIN_LEVEL_SELF_ENERGY 3", &
usage="MIN_LEVEL_SPECTRAL 3", &
default_i_val=1)
CALL section_add_keyword(gw_dos_section, keyword)
CALL keyword_release(keyword)
CALL keyword_create(keyword, __LOCATION__, name="MAX_LEVEL_SPECTRAL", &
description="Highest energy level to print the self energy to files.", &
usage="MAX_LEVEL_SELF_ENERGY 6", &
usage="MAX_LEVEL_SPECTRAL 6", &
default_i_val=0)
CALL section_add_keyword(gw_dos_section, keyword)
CALL keyword_release(keyword)
@ -1298,7 +1301,8 @@ CONTAINS
"$\left( \begin{array}{cc}\mathbf{X}^{(n)}\\\mathbf{Y}^{(n)}\end{array} \right) = "// &
"\Omega^{(n)}\left(\begin{array}{cc}1&0\\0&-1\end{array}\right)$ "// &
"$\left(\begin{array}{cc}\mathbf{X}^{(n)}\\\mathbf{Y}^{(n)}\end{array}\right)$ "// &
"enables of electronic excitation energies $\Omega^{(n)}$. The BSE can be solved by diagonalizing "// &
"enables, for example, the computation of electronic excitation energies $\Omega^{(n)}$ "// &
"as well as optical properties. The BSE can be solved by diagonalizing "// &
"the full ABBA-matrix or by setting B=0, i.e. within the Tamm-Dancoff approximation (TDA). "// &
"Preliminary reference: Eq. (35) in PRB 92, 045209 (2015); http://dx.doi.org/10.1103/PhysRevB.92.045209", &
n_keywords=8, n_subsections=3, repeats=.FALSE.)
@ -1376,12 +1380,29 @@ CONTAINS
CALL keyword_release(keyword)
CALL keyword_create(keyword, __LOCATION__, name="NUM_PRINT_EXC", &
description="Number of printed excitation energies. Does not affect computation time.", &
description="Number of printed excitation levels with respective "// &
"energies and oscillator strengths. Does not affect computation time.", &
usage="NUM_PRINT_EXC 25", &
default_i_val=25)
CALL section_add_keyword(section, keyword)
CALL keyword_release(keyword)
CALL keyword_create(keyword, __LOCATION__, name="NUM_PRINT_EXC_DESCR", &
description="Number of excitation levels for which the exciton "// &
"descriptors are computed. Negative or too large "// &
"NUM_PRINT_EXC_DESCR defaults to NUM_PRINT_EXC.", &
usage="NUM_PRINT_EXC_DESCR 5", &
default_i_val=0)
CALL section_add_keyword(section, keyword)
CALL keyword_release(keyword)
CALL keyword_create(keyword, __LOCATION__, name="PRINT_DIRECTIONAL_EXC_DESCR", &
description="Activates printing of exciton descriptors per direction.", &
usage="&PRINT_DIRECTIONAL_EXC_DESCR .TRUE.", &
default_l_val=.FALSE., lone_keyword_l_val=.TRUE.)
CALL section_add_keyword(section, keyword)
CALL keyword_release(keyword)
CALL keyword_create(keyword, __LOCATION__, name="EPS_X", &
description="Threshold for printing contributions of singleparticle "// &
"transitions, i.e. elements of the eigenvectors $X_{ia}^{(n)}$ and $Y_{ia}^{(n)}$.", &
@ -1400,8 +1421,96 @@ CONTAINS
CALL section_add_subsection(section, subsection)
CALL section_release(subsection)
NULLIFY (subsection)
CALL create_bse_nto_section(subsection)
CALL section_add_subsection(section, subsection)
CALL section_release(subsection)
END SUBROUTINE
SUBROUTINE create_bse_nto_section(print_key)
TYPE(section_type), POINTER :: print_key
TYPE(keyword_type), POINTER :: keyword
CPASSERT(.NOT. ASSOCIATED(print_key))
CALL cp_print_key_section_create(print_key, __LOCATION__, name="NTO_ANALYSIS", &
description="Perform a natural transition orbital analysis, i.e. the transition density matrix "// &
"$T^{(n)}=\left( \begin{array}{cc}0& {X}^{(n)}\\ \left({Y}^{(n)} \right)^T & 0\end{array} \right)$ "// &
"is decomposed into its singular values "// &
"$T^{(n)} = {U}^{(n)} {\Lambda^{(n)}} \left({V}^{(n)}\right)^T$ "// &
"in order to compute the NTO pairs "// &
"$\phi_I^{(n)}(\mathbf{r}_e) = \sum_{p=1}^{N_b} \varphi_p(\mathbf{r}_e) V_{p,I}^{(n)}$ for the electron and "// &
"$\chi_I^{(n)}(\mathbf{r}_h) = \sum_{q=1}^{N_b} \varphi_q(\mathbf{r}_h) U_{q,I}^{(n)}$ for the hole.", &
print_level=debug_print_level + 1, & ! Corresponds to "off" as default behavior
filename="BSE-NTO_ANALYSIS") ! All other print levels will trigger the analysis
! cf. input/cp_output_handling.F:cp_print_key_section_create
NULLIFY (keyword)
CALL keyword_create(keyword, __LOCATION__, name="EPS_NTO_EIGVAL", &
description="Threshold for NTO eigenvalues, i.e. only "// &
"${\left(\lambda_I^{(n)}\right)}^2$ > EPS_NTO_EIGVAL are considered.", &
usage="EPS_NTO_EIGVAL 0.01", &
n_var=1, &
type_of_var=real_t, &
default_r_val=0.01_dp)
CALL section_add_keyword(print_key, keyword)
CALL keyword_release(keyword)
CALL keyword_create(keyword, __LOCATION__, name="EPS_OSC_STR", &
description="Threshold of oscillator strengths $f^{(n)}$ for an excitation level. "// &
"In case, the excitation level n has a smaller oscillator strength, the "// &
"NTOs for this excitation level are not printed.", &
usage="EPS_OSC_STR 0.01", &
n_var=1, &
type_of_var=real_t, &
default_r_val=-1.0_dp)
CALL section_add_keyword(print_key, keyword)
CALL keyword_release(keyword)
CALL keyword_create(keyword, __LOCATION__, name="NUM_PRINT_EXC_NTOS", &
description="Number of excitation level $n$ up to which NTOs are printed. "// &
"By default, this is set to NUM_PRINT_EXC. Negative or too large "// &
"NUM_PRINT_EXC_NTOS defaults to NUM_PRINT_EXC.", &
usage="NUM_PRINT_EXC_NTOS 5", &
n_var=1, &
type_of_var=integer_t, &
default_i_val=-1)
CALL section_add_keyword(print_key, keyword)
CALL keyword_release(keyword)
CALL keyword_create(keyword, __LOCATION__, name="STATE_LIST", &
description="Specifies a list of excitation levels $n$ for which NTOs are printed. "// &
"Overrides NUM_PRINT_EXC_NTOS.", &
usage="STATE_LIST {integer} {integer} .. {integer}", &
n_var=-1, type_of_var=integer_t)
CALL section_add_keyword(print_key, keyword)
CALL keyword_release(keyword)
CALL keyword_create(keyword, __LOCATION__, name="CUBE_FILES", &
description="Print NTOs on Cube Files", &
usage="CUBE_FILES {logical}", repeats=.FALSE., n_var=1, &
default_l_val=.TRUE., lone_keyword_l_val=.TRUE., type_of_var=logical_t)
CALL section_add_keyword(print_key, keyword)
CALL keyword_release(keyword)
CALL keyword_create(keyword, __LOCATION__, name="STRIDE", &
description="The stride (X,Y,Z) used to write the cube file "// &
"(larger values result in smaller cube files). Provide 3 numbers (for X,Y,Z) or"// &
" 1 number valid for all components.", &
usage="STRIDE 2 2 2", n_var=-1, default_i_vals=(/2, 2, 2/), type_of_var=integer_t)
CALL section_add_keyword(print_key, keyword)
CALL keyword_release(keyword)
CALL keyword_create(keyword, __LOCATION__, name="APPEND", &
description="append the cube files when they already exist", &
default_l_val=.FALSE., lone_keyword_l_val=.TRUE.)
CALL section_add_keyword(print_key, keyword)
CALL keyword_release(keyword)
END SUBROUTINE create_bse_nto_section
SUBROUTINE create_bse_spectrum_section(section)
TYPE(section_type), POINTER :: section
@ -1409,21 +1518,27 @@ CONTAINS
CPASSERT(.NOT. ASSOCIATED(section))
CALL section_create(section, __LOCATION__, name="BSE_SPECTRUM", &
description="Parameters influencing the output of the optical spectrum "// &
"obtained from a BSE calculation.", &
description="Parameters influencing the output of the optical absorption spectrum, i.e. "// &
"the dynamical dipole polarizability tensor $\alpha_{\mu,\mu'}(\omega)$ "// &
"($\mu,\mu'\in\{x,y,z\}$), obtained from a BSE calculation, which is defined as "// &
"$ \alpha_{\mu,\mu'}(\omega) = \sum_n \frac{2 E^{(n)} d^{(n)}_{\mu} d^{(n)}_{\mu'}} "// &
"{(\omega+i\eta)^2-\left(\Omega^{(n)}\right)^2} $. "// &
"The printed file will contain the specified frequency range $\omega$ and the "// &
"corresponding imaginary part of the average $\bar{\alpha}(\omega)=\frac{1}{3}\mathrm{Tr} "// &
"\left[ \alpha_{\mu,\mu'}(\omega)\right]$ as well as of the elements of $\alpha_{\mu,\mu'}(\omega)$.", &
n_keywords=9, n_subsections=0, repeats=.FALSE.)
NULLIFY (keyword)
CALL keyword_create(keyword, __LOCATION__, name="_SECTION_PARAMETERS_", &
description="Activates printing of optical spectrum after a BSE calculation.", &
description="Activates printing of optical absorption spectrum from the BSE calculation.", &
usage="&BSE .TRUE.", &
default_l_val=.FALSE., lone_keyword_l_val=.TRUE.)
CALL section_add_keyword(section, keyword)
CALL keyword_release(keyword)
CALL keyword_create(keyword, __LOCATION__, name="FREQUENCY_STEP_SIZE", &
description="Step size of frequencies for the optical spectrum.", &
description="Step size of frequencies for the optical absorption spectrum.", &
usage="FREQUENCY_STEP_SIZE 0.1", unit_str="eV", &
type_of_var=real_t, &
default_r_val=cp_unit_to_cp2k(value=0.1_dp, unit_str="eV"))
@ -1431,14 +1546,14 @@ CONTAINS
CALL keyword_release(keyword)
CALL keyword_create(keyword, __LOCATION__, name="FREQUENCY_STARTING_POINT", &
description="First frequency to print in the optical spectrum.", &
description="First frequency to print in the optical absorption spectrum.", &
usage="FREQUENCY_STARTING_POINT 0", unit_str="eV", &
type_of_var=real_t, default_r_val=0.0_dp)
CALL section_add_keyword(section, keyword)
CALL keyword_release(keyword)
CALL keyword_create(keyword, __LOCATION__, name="FREQUENCY_END_POINT", &
description="Last frequency to print in the optical spectrum.", &
description="Last frequency to print in the optical absorption spectrum.", &
usage="FREQUENCY_END_POINT 0", unit_str="eV", &
type_of_var=real_t, &
default_r_val=cp_unit_to_cp2k(value=100.0_dp, unit_str="eV"))
@ -1446,7 +1561,7 @@ CONTAINS
CALL keyword_release(keyword)
CALL keyword_create(keyword, __LOCATION__, name="ETA_LIST", &
description="List of broadening of the peaks in the optical spectrum.", &
description="List of broadening of the peaks in the optical absorption spectrum.", &
usage="ETA_LIST 0.01 ...", unit_str="eV", &
default_r_vals=(/cp_unit_to_cp2k(value=0.01_dp, unit_str="eV")/), &
type_of_var=real_t, n_var=-1)

View file

@ -212,7 +212,7 @@ CONTAINS
! check if we want to do imaginary time
do_im_time = mp2_env%do_im_time
do_bse = qs_env%mp2_env%ri_g0w0%do_bse
do_bse = qs_env%mp2_env%bse%do_bse
do_kpoints_cubic_RPA = qs_env%mp2_env%ri_rpa_im_time%do_im_time_kpoints
IF (do_kpoints_cubic_RPA .AND. mp2_env%ri_rpa%do_ri_g0w0) THEN
@ -301,11 +301,13 @@ CONTAINS
CALL m_flush(unit_nr)
END IF
IF (.NOT. mp2_env%ri_g0w0%print_local_bandgap) THEN
! MG: Disable logger layer for BSE, misses some key information to print cube files properly
IF (.NOT. (mp2_env%ri_g0w0%print_local_bandgap .OR. mp2_env%bse%do_nto_analysis)) THEN
! a logger
NULLIFY (logger_sub)
CALL cp_logger_create(logger_sub, para_env=para_env_sub, &
default_global_unit_nr=local_unit_nr, close_global_unit_on_dealloc=.FALSE.)
default_global_unit_nr=local_unit_nr, &
close_global_unit_on_dealloc=.FALSE.)
CALL cp_logger_set(logger_sub, local_filename="MP2_localLog")
! set to a custom print level (we could also have a different print level for para_env%source)
logger_sub%iter_info%print_level = mp2_env%mp2_gpw%print_level
@ -639,7 +641,7 @@ CONTAINS
CALL cp_blacs_env_release(blacs_env_sub)
IF (.NOT. mp2_env%ri_g0w0%print_local_bandgap) THEN
IF (.NOT. (mp2_env%ri_g0w0%print_local_bandgap .OR. mp2_env%bse%do_nto_analysis)) THEN
CALL cp_rm_default_logger()
CALL cp_logger_release(logger_sub)
END IF

View file

@ -18,7 +18,8 @@ MODULE mp2_setup
USE cp_output_handling, ONLY: cp_p_file,&
cp_print_key_finished_output,&
cp_print_key_should_output,&
cp_print_key_unit_nr
cp_print_key_unit_nr,&
debug_print_level
USE cp_parser_methods, ONLY: read_float_object
USE input_constants, ONLY: &
do_eri_mme, do_potential_short, evGW, evGW0, mp2_method_direct, mp2_method_gpw, &
@ -67,7 +68,7 @@ CONTAINS
DIMENSION(:), POINTER :: string_pointer
CHARACTER(LEN=max_line_length) :: error_message
INTEGER :: gw_sc, handle, i, i_special_kp, ival, &
unit_nr
print_level_NTO_analysis, unit_nr
INTEGER, DIMENSION(:), POINTER :: tmplist
LOGICAL :: do_mp2, do_opt_ri_basis, do_ri_mp2, &
do_ri_sos_mp2, do_rpa
@ -190,51 +191,76 @@ CONTAINS
NULLIFY (bse_section)
bse_section => section_vals_get_subs_vals(mp2_section, "RI_RPA%GW%BSE")
CALL section_vals_val_get(bse_section, "_SECTION_PARAMETERS_", &
l_val=mp2_env%ri_g0w0%do_bse)
l_val=mp2_env%bse%do_bse)
CALL section_vals_val_get(bse_section, "SPIN_CONFIG", &
i_val=mp2_env%ri_g0w0%bse_spin_config)
i_val=mp2_env%bse%bse_spin_config)
CALL section_vals_val_get(bse_section, "ENERGY_CUTOFF_OCC", &
r_val=mp2_env%ri_g0w0%bse_cutoff_occ)
r_val=mp2_env%bse%bse_cutoff_occ)
CALL section_vals_val_get(bse_section, "ENERGY_CUTOFF_EMPTY", &
r_val=mp2_env%ri_g0w0%bse_cutoff_empty)
r_val=mp2_env%bse%bse_cutoff_empty)
CALL section_vals_val_get(bse_section, "NUM_PRINT_EXC", &
i_val=mp2_env%ri_g0w0%num_print_exc)
i_val=mp2_env%bse%num_print_exc)
CALL section_vals_val_get(bse_section, "NUM_PRINT_EXC_DESCR", &
i_val=mp2_env%bse%num_print_exc_descr)
CALL section_vals_val_get(bse_section, "PRINT_DIRECTIONAL_EXC_DESCR", &
l_val=mp2_env%bse%print_directional_exc_descr)
CALL section_vals_val_get(bse_section, "EPS_X", &
r_val=mp2_env%ri_g0w0%eps_x)
r_val=mp2_env%bse%eps_x)
CALL section_vals_val_get(bse_section, "BSE_ITERAT%DAVIDSON_ABORT_COND", &
i_val=mp2_env%ri_g0w0%davidson_abort_cond)
i_val=mp2_env%bse%davidson_abort_cond)
CALL section_vals_val_get(bse_section, "BSE_ITERAT%NUM_EXC_EN", &
i_val=mp2_env%ri_g0w0%num_exc_en)
i_val=mp2_env%bse%num_exc_en)
CALL section_vals_val_get(bse_section, "BSE_ITERAT%NUM_ADD_START_Z_SPACE", &
i_val=mp2_env%ri_g0w0%num_add_start_z_space)
i_val=mp2_env%bse%num_add_start_z_space)
CALL section_vals_val_get(bse_section, "BSE_ITERAT%FAC_MAX_Z_SPACE", &
i_val=mp2_env%ri_g0w0%fac_max_z_space)
i_val=mp2_env%bse%fac_max_z_space)
CALL section_vals_val_get(bse_section, "BSE_ITERAT%NUM_NEW_T", &
i_val=mp2_env%ri_g0w0%num_new_t)
i_val=mp2_env%bse%num_new_t)
CALL section_vals_val_get(bse_section, "BSE_ITERAT%EPS_RES", &
r_val=mp2_env%ri_g0w0%eps_res)
r_val=mp2_env%bse%eps_res)
CALL section_vals_val_get(bse_section, "BSE_ITERAT%EPS_EXC_EN", &
r_val=mp2_env%ri_g0w0%eps_exc_en)
r_val=mp2_env%bse%eps_exc_en)
CALL section_vals_val_get(bse_section, "BSE_ITERAT%NUM_DAVIDSON_ITER", &
i_val=mp2_env%ri_g0w0%num_davidson_iter)
i_val=mp2_env%bse%num_davidson_iter)
CALL section_vals_val_get(bse_section, "BSE_ITERAT%Z_SPACE_ENERGY_CUTOFF", &
r_val=mp2_env%ri_g0w0%z_space_energy_cutoff)
r_val=mp2_env%bse%z_space_energy_cutoff)
CALL section_vals_val_get(bse_section, "BSE_DIAG_METHOD", &
i_val=mp2_env%ri_g0w0%bse_diag_method)
i_val=mp2_env%bse%bse_diag_method)
CALL section_vals_val_get(bse_section, "TDA", &
i_val=mp2_env%ri_g0w0%flag_tda)
i_val=mp2_env%bse%flag_tda)
CALL section_vals_val_get(bse_section, "BSE_DEBUG_PRINT", &
l_val=mp2_env%ri_g0w0%bse_debug_print)
l_val=mp2_env%bse%bse_debug_print)
CALL section_vals_val_get(bse_section, "BSE_SPECTRUM%_SECTION_PARAMETERS_", &
l_val=mp2_env%ri_g0w0%bse_print_spectrum)
l_val=mp2_env%bse%bse_print_spectrum)
CALL section_vals_val_get(bse_section, "BSE_SPECTRUM%FREQUENCY_STEP_SIZE", &
r_val=mp2_env%ri_g0w0%bse_spectrum_freq_step_size)
r_val=mp2_env%bse%bse_spectrum_freq_step_size)
CALL section_vals_val_get(bse_section, "BSE_SPECTRUM%FREQUENCY_STARTING_POINT", &
r_val=mp2_env%ri_g0w0%bse_spectrum_freq_start)
r_val=mp2_env%bse%bse_spectrum_freq_start)
CALL section_vals_val_get(bse_section, "BSE_SPECTRUM%FREQUENCY_END_POINT", &
r_val=mp2_env%ri_g0w0%bse_spectrum_freq_end)
r_val=mp2_env%bse%bse_spectrum_freq_end)
CALL section_vals_val_get(bse_section, "BSE_SPECTRUM%ETA_LIST", &
r_vals=mp2_env%ri_g0w0%bse_eta_spectrum_list)
r_vals=mp2_env%bse%bse_eta_spectrum_list)
CALL section_vals_val_get(bse_section, "NTO_ANALYSIS%_SECTION_PARAMETERS_", &
i_val=print_level_NTO_analysis)
! All other print levels besides "off" should trigger the analysis
! cf. input/cp_output_handling.F:cp_print_key_section_create
IF (print_level_NTO_analysis /= debug_print_level + 1) THEN
mp2_env%bse%do_nto_analysis = .TRUE.
ELSE
mp2_env%bse%do_nto_analysis = .FALSE.
END IF
CALL section_vals_val_get(bse_section, "NTO_ANALYSIS%EPS_NTO_EIGVAL", &
r_val=mp2_env%bse%eps_nto_eigval)
CALL section_vals_val_get(bse_section, "NTO_ANALYSIS%EPS_OSC_STR", &
r_val=mp2_env%bse%eps_nto_osc_str)
CALL section_vals_val_get(bse_section, "NTO_ANALYSIS%NUM_PRINT_EXC_NTOS", &
i_val=mp2_env%bse%num_print_exc_ntos)
CALL section_vals_val_get(bse_section, "NTO_ANALYSIS%STATE_LIST", &
EXPLICIT=mp2_env%bse%explicit_nto_list)
IF (mp2_env%bse%explicit_nto_list) THEN
CALL section_vals_val_get(bse_section, "NTO_ANALYSIS%STATE_LIST", &
i_vals=mp2_env%bse%bse_nto_state_list)
END IF
CALL section_vals_val_get(mp2_section, "RI_RPA%GW%IMAGE_CHARGE_MODEL", &
l_val=mp2_env%ri_g0w0%do_ic_model)

View file

@ -226,25 +226,7 @@ MODULE mp2_types
do_aux_bas_gw = .FALSE.
REAL(KIND=dp) :: frac_aux_mos = 0.0_dp
INTEGER :: num_omega_points = 0
INTEGER :: bse_spin_config = 0, &
bse_diag_method = 0, &
flag_tda = 0, &
num_exc_en = 0, &
num_print_exc = 0, &
num_add_start_z_space = 0, &
fac_max_z_space = 0, &
num_new_t = 0, &
num_davidson_iter = 0, &
davidson_abort_cond = 0
REAL(KIND=dp) :: eps_res = 0.0_dp, &
eps_exc_en = 0.0_dp, &
eps_x = 0.0_dp, &
bse_cutoff_occ = 0.0_dp, &
bse_cutoff_empty = 0.0_dp, &
z_space_energy_cutoff = 0.0_dp
LOGICAL :: do_bse = .FALSE., &
bse_debug_print = .FALSE., &
do_ic_model = .FALSE., &
LOGICAL :: do_ic_model = .FALSE., &
print_ic_values = .FALSE.
REAL(KIND=dp) :: eps_dist = 0.0_dp
TYPE(one_dim_real_array), DIMENSION(2) :: ic_corr_list = one_dim_real_array(NULL())
@ -270,13 +252,6 @@ MODULE mp2_types
soc_energy_window = 0.0_dp
INTEGER, DIMENSION(:), POINTER :: stride_loc_bandgap => NULL()
!BSE optical spectrum
REAL(KIND=dp) :: bse_spectrum_freq_step_size = 0.0_dp, &
bse_spectrum_freq_start = 0.0_dp, &
bse_spectrum_freq_end = 0.0_dp
LOGICAL :: bse_print_spectrum = .FALSE.
REAL(KIND=dp), DIMENSION(:), POINTER :: bse_eta_spectrum_list => NULL()
!GW_DOS
REAL(KIND=dp) :: dos_upper = 0.0_dp, &
dos_lower = 0.0_dp, &
@ -326,6 +301,44 @@ MODULE mp2_types
INTEGER :: max_parallel_comm = 0
END TYPE grad_util
TYPE bse_type
INTEGER :: bse_spin_config = 0, &
bse_diag_method = 0, &
flag_tda = 0, &
num_exc_en = 0, &
num_print_exc = 0, &
num_print_exc_descr = 0, &
num_add_start_z_space = 0, &
fac_max_z_space = 0, &
num_new_t = 0, &
num_davidson_iter = 0, &
davidson_abort_cond = 0
REAL(KIND=dp) :: eps_res = 0.0_dp, &
eps_exc_en = 0.0_dp, &
eps_x = 0.0_dp, &
bse_cutoff_occ = 0.0_dp, &
bse_cutoff_empty = 0.0_dp, &
z_space_energy_cutoff = 0.0_dp
LOGICAL :: do_bse = .FALSE., &
bse_debug_print = .FALSE., &
print_directional_exc_descr = .FALSE.
!BSE optical spectrum
REAL(KIND=dp) :: bse_spectrum_freq_step_size = 0.0_dp, &
bse_spectrum_freq_start = 0.0_dp, &
bse_spectrum_freq_end = 0.0_dp
LOGICAL :: bse_print_spectrum = .FALSE.
REAL(KIND=dp), DIMENSION(:), POINTER :: bse_eta_spectrum_list => NULL()
!BSE NTO prints
LOGICAL :: do_nto_analysis = .FALSE., &
explicit_nto_list = .FALSE.
REAL(KIND=dp) :: eps_nto_eigval = 0.0_dp, &
eps_nto_osc_str = 0.0_dp
INTEGER :: num_print_exc_ntos = 0
INTEGER, DIMENSION(:), POINTER :: bse_nto_state_list => NULL()
INTEGER, DIMENSION(:), ALLOCATABLE :: bse_nto_state_list_final
END TYPE bse_type
TYPE mp2_type
INTEGER :: method = mp2_method_none
TYPE(mp2_laplace_type) :: ri_laplace = mp2_laplace_type()
@ -358,11 +371,13 @@ MODULE mp2_types
mo_coeff_o=NULL(), &
mo_coeff_v=NULL(), &
P_mo=NULL(), W_mo=NULL(), L_jb=NULL())
TYPE(bse_type) :: bse = bse_type(bse_nto_state_list_final=NULL())
#else
TYPE(ri_rpa_im_time_type) :: ri_rpa_im_time = ri_rpa_im_time_type()
TYPE(ri_g0w0_type) :: ri_g0w0 = ri_g0w0_type()
TYPE(ri_basis_opt) :: ri_opt_param = ri_basis_opt()
TYPE(grad_util) :: ri_grad = grad_util()
TYPE(bse_type) :: bse = bse_type()
#endif
REAL(KIND=dp) :: mp2_memory = 0.0_dp, &
scale_S = 0.0_dp, &

View file

@ -1298,6 +1298,7 @@ CONTAINS
E_CBM_SCF, E_CBM_SCF_beta, E_VBM_GW, E_VBM_GW_beta, E_VBM_SCF, E_VBM_SCF_beta, stop_crit
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: vec_gw_dos
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :, :) :: m_value, vec_gw_energ, z_value
TYPE(cp_logger_type), POINTER :: logger
TYPE(kpoint_type), POINTER :: kpoints_Sigma
CALL timeset(routineN, handle)
@ -1560,7 +1561,12 @@ CONTAINS
homo, unit_nr, do_soc_gw=.TRUE., do_soc_scf=.FALSE.)
END IF
iunit = cp_logger_get_default_unit_nr()
logger => cp_get_default_logger()
IF (logger%para_env%is_source()) THEN
iunit = cp_logger_get_default_unit_nr()
ELSE
iunit = -1
END IF
IF (dos_precision /= 0.0_dp) THEN
IF (iunit > 0) THEN
@ -4341,6 +4347,7 @@ CONTAINS
REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: vec_omega_fit_gw_sign, &
vec_omega_fit_gw_sign_reorder, &
vec_sigma_imag, vec_sigma_real
TYPE(cp_logger_type), POINTER :: logger
CALL timeset(routineN, handle)
@ -4437,7 +4444,12 @@ CONTAINS
IF (ndos /= 0) THEN
! Hedin shift not implemented
CPASSERT(.NOT. do_hedin_shift)
iunit = cp_logger_get_default_unit_nr()
logger => cp_get_default_logger()
IF (logger%para_env%is_source()) THEN
iunit = cp_logger_get_default_unit_nr()
ELSE
iunit = -1
END IF
DO idos = 1, ndos
omega_dos = dos_lower_bound + REAL(idos - 1, KIND=dp)*dos_precision
omega_dos_pade_eval = omega_dos - e_fermi
@ -4469,7 +4481,12 @@ CONTAINS
END IF
IF (PRESENT(min_level_self_energy) .AND. PRESENT(max_level_self_energy)) THEN
iunit = cp_logger_get_default_unit_nr()
logger => cp_get_default_logger()
IF (logger%para_env%is_source()) THEN
iunit = cp_logger_get_default_unit_nr()
ELSE
iunit = -1
END IF
IF (n_level_gw_ref >= min_level_self_energy .AND. &
n_level_gw_ref <= max_level_self_energy .AND. iunit > 0) THEN
@ -4561,7 +4578,12 @@ CONTAINS
END IF
iunit = cp_logger_get_default_unit_nr()
logger => cp_get_default_logger()
IF (logger%para_env%is_source()) THEN
iunit = cp_logger_get_default_unit_nr()
ELSE
iunit = -1
END IF
CALL open_file(TRIM(filename), unit_number=iunit, file_status="UNKNOWN", file_action="WRITE")
num_omega = 10000

View file

@ -555,12 +555,12 @@ CONTAINS
gw_corr_lev_virt = mp2_env%ri_g0w0%corr_mos_virt
! If BSE is invoked, manipulate corrected MO number
IF (mp2_env%ri_g0w0%do_bse) THEN
IF (mp2_env%bse%do_bse) THEN
! Logic: If cutoff is negative, all MOs are included in BSE, i.e. we need to correct them all
! If cutoff is positive, we can reduce the number of MOs to be corrected and force gw_corr_lev_...
! to a sufficiently large number by setting it to -2 and read indices afterwards
! Handling for occupied levels
IF (mp2_env%ri_g0w0%bse_cutoff_occ < 0) THEN
IF (mp2_env%bse%bse_cutoff_occ < 0) THEN
gw_corr_lev_occ = -1
ELSE
IF (gw_corr_lev_occ > 0) THEN
@ -568,7 +568,7 @@ CONTAINS
END IF
END IF
! Handling for virtual levels
IF (mp2_env%ri_g0w0%bse_cutoff_empty < 0) THEN
IF (mp2_env%bse%bse_cutoff_empty < 0) THEN
gw_corr_lev_virt = -1
ELSE
IF (gw_corr_lev_virt > 0) THEN

View file

@ -979,7 +979,11 @@ CONTAINS
END IF
! release blacs_env
IF (.NOT. my_blacs_S_ext) CALL cp_blacs_env_release(blacs_env)
IF (.NOT. my_blacs_S_ext) THEN
CALL cp_blacs_env_release(blacs_env)
ELSE
NULLIFY (blacs_env)
END IF
CALL timestop(handle)

View file

@ -0,0 +1,83 @@
&GLOBAL
PRINT_LEVEL MEDIUM
PROJECT BSE_H2O_PBE
RUN_TYPE ENERGY
&TIMINGS
THRESHOLD 0.01
&END TIMINGS
&END GLOBAL
&FORCE_EVAL
METHOD Quickstep
&DFT
BASIS_SET_FILE_NAME HFX_BASIS
POTENTIAL_FILE_NAME GTH_POTENTIALS
&MGRID
CUTOFF 100
REL_CUTOFF 20
&END MGRID
&POISSON
PERIODIC NONE
POISSON_SOLVER WAVELET
&END POISSON
&QS
EPS_DEFAULT 1.0E-15
EPS_PGF_ORB 1.0E-30
METHOD GPW
&END QS
&SCF
EPS_SCF 1.0E-7
MAX_SCF 100
SCF_GUESS ATOMIC
&PRINT
&RESTART OFF
&END RESTART
&END PRINT
&END SCF
&XC
&WF_CORRELATION
&RI_RPA
QUADRATURE_POINTS 100
&GW
CORR_MOS_OCC 1000
CORR_MOS_VIRT 1000
RI_SIGMA_X
SELF_CONSISTENCY G0W0
&BSE
BSE_DEBUG_PRINT
BSE_DIAG_METHOD FULLDIAG
ENERGY_CUTOFF_EMPTY 50.0
ENERGY_CUTOFF_OCC 60.0
NUM_PRINT_EXC_DESCR -1
TDA OFF
&END BSE
&END GW
&END RI_RPA
&END WF_CORRELATION
&XC_FUNCTIONAL PBE
&END XC_FUNCTIONAL
&END XC
&END DFT
&SUBSYS
&CELL
ABC [angstrom] 6.000 6.000 6.000
PERIODIC NONE
&END CELL
&KIND H
BASIS_SET DZVP-GTH
BASIS_SET RI_AUX RI_DZVP-GTH
POTENTIAL GTH-PBE-q1
&END KIND
&KIND O
BASIS_SET DZVP-GTH
BASIS_SET RI_AUX RI_DZVP-GTH
POTENTIAL GTH-PBE-q6
&END KIND
&TOPOLOGY
COORD_FILE_FORMAT xyz
COORD_FILE_NAME H2O_gas.xyz
&CENTER_COORDINATES
&END CENTER_COORDINATES
&END TOPOLOGY
&END SUBSYS
&END FORCE_EVAL

View file

@ -0,0 +1,84 @@
&GLOBAL
PRINT_LEVEL MEDIUM
PROJECT BSE_H2O_PBE
RUN_TYPE ENERGY
&TIMINGS
THRESHOLD 0.01
&END TIMINGS
&END GLOBAL
&FORCE_EVAL
METHOD Quickstep
&DFT
BASIS_SET_FILE_NAME HFX_BASIS
POTENTIAL_FILE_NAME GTH_POTENTIALS
&MGRID
CUTOFF 100
REL_CUTOFF 20
&END MGRID
&POISSON
PERIODIC NONE
POISSON_SOLVER WAVELET
&END POISSON
&QS
EPS_DEFAULT 1.0E-15
EPS_PGF_ORB 1.0E-30
METHOD GPW
&END QS
&SCF
EPS_SCF 1.0E-7
MAX_SCF 100
SCF_GUESS ATOMIC
&PRINT
&RESTART OFF
&END RESTART
&END PRINT
&END SCF
&XC
&WF_CORRELATION
&RI_RPA
QUADRATURE_POINTS 100
&GW
CORR_MOS_OCC 1000
CORR_MOS_VIRT 1000
RI_SIGMA_X
SELF_CONSISTENCY G0W0
&BSE
BSE_DIAG_METHOD FULLDIAG
ENERGY_CUTOFF_EMPTY 50.0
ENERGY_CUTOFF_OCC 60.0
TDA OFF
&NTO_ANALYSIS
CUBE_FILES F
&END NTO_ANALYSIS
&END BSE
&END GW
&END RI_RPA
&END WF_CORRELATION
&XC_FUNCTIONAL PBE
&END XC_FUNCTIONAL
&END XC
&END DFT
&SUBSYS
&CELL
ABC [angstrom] 6.000 6.000 6.000
PERIODIC NONE
&END CELL
&KIND H
BASIS_SET DZVP-GTH
BASIS_SET RI_AUX RI_DZVP-GTH
POTENTIAL GTH-PBE-q1
&END KIND
&KIND O
BASIS_SET DZVP-GTH
BASIS_SET RI_AUX RI_DZVP-GTH
POTENTIAL GTH-PBE-q6
&END KIND
&TOPOLOGY
COORD_FILE_FORMAT xyz
COORD_FILE_NAME H2O_gas.xyz
&CENTER_COORDINATES
&END CENTER_COORDINATES
&END TOPOLOGY
&END SUBSYS
&END FORCE_EVAL

View file

@ -0,0 +1,83 @@
&GLOBAL
PRINT_LEVEL MEDIUM
PROJECT BSE_H2O_PBE
RUN_TYPE ENERGY
&TIMINGS
THRESHOLD 0.01
&END TIMINGS
&END GLOBAL
&FORCE_EVAL
METHOD Quickstep
&DFT
BASIS_SET_FILE_NAME HFX_BASIS
POTENTIAL_FILE_NAME GTH_POTENTIALS
&MGRID
CUTOFF 100
REL_CUTOFF 20
&END MGRID
&POISSON
PERIODIC NONE
POISSON_SOLVER WAVELET
&END POISSON
&QS
EPS_DEFAULT 1.0E-15
EPS_PGF_ORB 1.0E-30
METHOD GPW
&END QS
&SCF
EPS_SCF 1.0E-7
MAX_SCF 100
SCF_GUESS ATOMIC
&PRINT
&RESTART OFF
&END RESTART
&END PRINT
&END SCF
&XC
&WF_CORRELATION
&RI_RPA
QUADRATURE_POINTS 100
&GW
CORR_MOS_OCC 1000
CORR_MOS_VIRT 1000
RI_SIGMA_X
SELF_CONSISTENCY G0W0
&BSE
BSE_DEBUG_PRINT
BSE_DIAG_METHOD FULLDIAG
ENERGY_CUTOFF_EMPTY 50.0
ENERGY_CUTOFF_OCC 60.0
NUM_PRINT_EXC_DESCR -1
TDA ON
&END BSE
&END GW
&END RI_RPA
&END WF_CORRELATION
&XC_FUNCTIONAL PBE
&END XC_FUNCTIONAL
&END XC
&END DFT
&SUBSYS
&CELL
ABC [angstrom] 6.000 6.000 6.000
PERIODIC NONE
&END CELL
&KIND H
BASIS_SET DZVP-GTH
BASIS_SET RI_AUX RI_DZVP-GTH
POTENTIAL GTH-PBE-q1
&END KIND
&KIND O
BASIS_SET DZVP-GTH
BASIS_SET RI_AUX RI_DZVP-GTH
POTENTIAL GTH-PBE-q6
&END KIND
&TOPOLOGY
COORD_FILE_FORMAT xyz
COORD_FILE_NAME H2O_gas.xyz
&CENTER_COORDINATES
&END CENTER_COORDINATES
&END TOPOLOGY
&END SUBSYS
&END FORCE_EVAL

View file

@ -0,0 +1,84 @@
&GLOBAL
PRINT_LEVEL MEDIUM
PROJECT BSE_H2O_PBE
RUN_TYPE ENERGY
&TIMINGS
THRESHOLD 0.01
&END TIMINGS
&END GLOBAL
&FORCE_EVAL
METHOD Quickstep
&DFT
BASIS_SET_FILE_NAME HFX_BASIS
POTENTIAL_FILE_NAME GTH_POTENTIALS
&MGRID
CUTOFF 100
REL_CUTOFF 20
&END MGRID
&POISSON
PERIODIC NONE
POISSON_SOLVER WAVELET
&END POISSON
&QS
EPS_DEFAULT 1.0E-15
EPS_PGF_ORB 1.0E-30
METHOD GPW
&END QS
&SCF
EPS_SCF 1.0E-7
MAX_SCF 100
SCF_GUESS ATOMIC
&PRINT
&RESTART OFF
&END RESTART
&END PRINT
&END SCF
&XC
&WF_CORRELATION
&RI_RPA
QUADRATURE_POINTS 100
&GW
CORR_MOS_OCC 1000
CORR_MOS_VIRT 1000
RI_SIGMA_X
SELF_CONSISTENCY G0W0
&BSE
BSE_DIAG_METHOD FULLDIAG
ENERGY_CUTOFF_EMPTY 50.0
ENERGY_CUTOFF_OCC 60.0
TDA ON
&NTO_ANALYSIS
CUBE_FILES F
&END NTO_ANALYSIS
&END BSE
&END GW
&END RI_RPA
&END WF_CORRELATION
&XC_FUNCTIONAL PBE
&END XC_FUNCTIONAL
&END XC
&END DFT
&SUBSYS
&CELL
ABC [angstrom] 6.000 6.000 6.000
PERIODIC NONE
&END CELL
&KIND H
BASIS_SET DZVP-GTH
BASIS_SET RI_AUX RI_DZVP-GTH
POTENTIAL GTH-PBE-q1
&END KIND
&KIND O
BASIS_SET DZVP-GTH
BASIS_SET RI_AUX RI_DZVP-GTH
POTENTIAL GTH-PBE-q6
&END KIND
&TOPOLOGY
COORD_FILE_FORMAT xyz
COORD_FILE_NAME H2O_gas.xyz
&CENTER_COORDINATES
&END CENTER_COORDINATES
&END TOPOLOGY
&END SUBSYS
&END FORCE_EVAL

View file

@ -10,9 +10,15 @@ TDA_H2O_PBE_evGW.inp 113 7e-02
BSE_H2O_PBE_G0W0.inp 114 2e-05 0.014
BSE_H2O_PBE_evGW0.inp 114 2e-05 0.015
BSE_H2O_PBE_evGW.inp 114 2e-04 0.016
TDA_H2O_PBE_G0W0_NTOs.inp 121 2e-03 0.01983
BSE_H2O_PBE_G0W0_NTOs.inp 122 2e-03 0.01164
TDA_H2O_PBE_G0W0_EXC_DESCR.inp 123 5e-04 1.8290
BSE_H2O_PBE_G0W0_EXC_DESCR.inp 124 5e-04 1.8258
#EOF
#Low convergence criteria for evGW make a higher threshold necessary for these tests
#Logic: Absolute errors (for G0W0/evGW0) should be within 1e-4, i.e. relative errors are
# in the range of 2e-5 for energies.
# For oscillator strengths, they should be within 1e-3, so relative errors
# are in the range of 7e-2
# First 6 check excitation energies, then 6 checking oscillator strengths, two check NTOs
# and the last one checks exciton descriptors in TDA

View file

@ -1,4 +1,4 @@
120
124
Total energy:!3
MD| Potential energy!5
Total energy \[eV\]:!4
@ -119,6 +119,10 @@ MOMENTS_TRACE_RE| 0.20000000E+000!3
POLARIZABILITY| 0.32436607E+002!4
DEBUG:: Total Force !6
SMEAGOL| Number of electrons: !5
BSE| 3 -TDA- 2 !5
BSE| 3 -ABBA- 2 !5
BSE|DEBUG| Exciton descriptor d_exc with TDA for n=1 is !10
BSE|DEBUG| Exciton descriptor d_exc without TDA for n=1 is !10
#
# these are the tests the can be selected for regtesting.
# do regtest will grep for test_grep (first column) and look if the numeric value