diff --git a/docs/advanced/input_files/input-main.md b/docs/advanced/input_files/input-main.md
index b4aaed03a4..0ed67ff2b7 100644
--- a/docs/advanced/input_files/input-main.md
+++ b/docs/advanced/input_files/input-main.md
@@ -476,6 +476,12 @@
- [td\_trigo\_amp](#td_trigo_amp)
- [td\_heavi\_t0](#td_heavi_t0)
- [td\_heavi\_amp](#td_heavi_amp)
+ - [td\_supsine\_amp](#td_supsine_amp)
+ - [td\_supsine\_freq](#td_supsine_freq)
+ - [td\_supsine\_phase](#td_supsine_phase)
+ - [td\_supsine\_sigma](#td_supsine_sigma)
+ - [td\_supsine\_tstart](#td_supsine_tstart)
+ - [td\_supsine\_tend](#td_supsine_tend)
- [init\_vecpot\_file](#init_vecpot_file)
- [ocp](#ocp)
- [ocp\_set](#ocp_set)
@@ -4143,48 +4149,51 @@
### td_dt
- **Type**: Real
-- **Description**: The time step used in electronic propagation. Setting td_dt will reset the value of md_dt to td_dt * estep_per_md.
+- **Description**: The time step used for electronic propagation. If td_dt is not specified, it is set to md_dt / estep_per_md. If td_dt is specified explicitly, md_dt is reset to td_dt * estep_per_md.
- **Default**: md_dt / estep_per_md
- **Unit**: fs
### td_edm
- **Type**: Integer
-- **Description**: Method to calculate the energy-density matrix, mainly affects the calculation of force and stress.
- - 0: Using the original formula.
- - 1: Using the formula for ground state (deprecated). Note that this usually does not hold if wave function is not the eigenstate of the Hamiltonian.
+- **Description**: Method used to calculate the energy-density matrix for the overlap contribution to forces in LCAO RT-TDDFT.
+ - 0: Use $\mathrm{EDM}_{\boldsymbol{k}}=\frac{1}{2}\left(S_{\boldsymbol{k}}^{-1}H_{\boldsymbol{k}}\rho_{\boldsymbol{k}}+\rho_{\boldsymbol{k}}H_{\boldsymbol{k}}S_{\boldsymbol{k}}^{-1}\right)$.
+ - 1: Use the ground-state eigenvalue-weighted expression $\mathrm{EDM}_{\mu\nu,\boldsymbol{k}}=\sum_i w_{i\boldsymbol{k}}\epsilon_{i\boldsymbol{k}}C_{\mu i,\boldsymbol{k}}C_{\nu i,\boldsymbol{k}}^*$. This expression is deprecated for RT-TDDFT and is generally not valid when the propagated wave functions are not Hamiltonian eigenstates.
- **Default**: 0
### td_print_eij
- **Type**: Real
-- **Description**: Controls the printing of Hamiltonian matrix elements.
- - < 0: Suppress all output.
- - >= 0: Print only elements with either i or j exceeding td_print_eij.
+- **Description**: Controls output of the propagated-state Hamiltonian matrix elements $E_{ij}=\Braket{\psi_i | \hat{H} | \psi_j}$ to the running log. The printed band indices $i$ and $j$ are one-based global indices. Both the threshold and the printed matrix elements are in Ry.
+ - $\lt 0$: Disable the output.
+ - $\geqslant 0$: Print an element when either $\left|\operatorname{Re}E_{ij}\right|$ or $\left|\operatorname{Im}E_{ij}\right|$ is greater than or equal to td_print_eij.
- **Default**: -1
- **Unit**: Ry
### td_propagator
- **Type**: Integer
-- **Description**: Methods of electronic propagation.
- - 0: Crank-Nicolson, based on matrix inversion.
- - 1: 4th-order Taylor expansion of exponential.
- - 2: Enforced time-reversal symmetry (ETRS).
- - 3: Crank-Nicolson, based on solving linear equation.
+- **Description**: Method used to propagate the electronic states in a nonorthogonal LCAO basis. The formulas below use Hartree atomic units, with $S$, $H$, and $\Delta t=\mathtt{td\_dt}$ evaluated as required by each approximation.
+ - 0: Crank-Nicolson through an explicitly constructed evolution matrix, $U=\left[S+\mathrm{i}H\Delta t/2\right]^{-1}\left[S-\mathrm{i}H\Delta t/2\right]$.
+ - 1: Fourth-order Taylor approximation to the exponential. With $\mathcal{A}=-\mathrm{i}S^{-1}H\Delta t$, $U=I+\mathcal{A}+\mathcal{A}^2/2+\mathcal{A}^3/6+\mathcal{A}^4/24$.
+ - 2: Enforced time-reversal symmetry (ETRS), $U(t+\Delta t,t)=\exp\left[-\mathrm{i}S^{-1}H(t+\Delta t)\Delta t/2\right]\exp\left[-\mathrm{i}S^{-1}H(t)\Delta t/2\right]$. In the implementation, each exponential is replaced by the fourth-order Taylor polynomial from method 1 evaluated with a half time step.
+ - 3: Crank-Nicolson by directly solving $\left[S+\mathrm{i}H\Delta t/2\right]\psi(t+\Delta t)=\left[S-\mathrm{i}H\Delta t/2\right]\psi(t)$.
+
+ > Note: GPU execution currently supports only method 0 in both single-GPU and multi-GPU solver configurations. CPU execution supports methods 0 through 3.
- **Default**: 0
### td_vext
- **Type**: Boolean
-- **Description**: - True: Add a laser-material interaction (external electric field).
+- **Description**: Controls whether a time-dependent external electric field is applied.
+ - True: Add a laser-material interaction (external electric field).
- False: No external electric field.
- **Default**: False
### td_vext_dire
-- **Type**: String
-- **Description**: Specifies the direction(s) of the external electric field when td_vext is enabled. For example, td_vext_dire 1 2 indicates that external electric fields are applied to both the x and y directions simultaneously. Electric field parameters can also be written as strings. For example, td_gauss_phase 0 1.5707963 indicates that the Gaussian type electric fields in the x and y directions have a phase delay of pi/2.
+- **Type**: Vector of Integer
+- **Description**: Specifies one absolute Cartesian direction for each external electric field when td_vext is enabled. Unlike the ground-state efield_dir parameter, these directions are not defined by lattice or reciprocal-lattice vectors. The number of values must equal that of td_ttype, and repeated directions are allowed; fields assigned to the same direction are added. For example, td_vext_dire 1 2 applies one field along Cartesian x and one along Cartesian y.
- 1: The external field direction is along the x-axis.
- 2: The external field direction is along the y-axis.
- 3: The external field direction is along the z-axis.
@@ -4201,217 +4210,296 @@
### td_ttype
-- **Type**: String
-- **Description**: Type of electric field in the time domain.
- - 0: Gaussian type function.
- - 1: Trapezoid type function.
- - 2: Trigonometric type function.
- - 3: Heaviside type function.
+- **Type**: Vector of Integer
+- **Description**: Specifies one time-domain type for each external electric field. Its number of values must equal that of td_vext_dire. Parameters belonging to each type must provide exactly one value for every occurrence of that type, in occurrence order; fields with a repeated direction are added.
+
+ The formulas below use Hartree atomic units. For every ordinary input frequency $f$, $\omega=2\pi f$; $\Delta t=\mathtt{td\_dt}$; and $E_0$ denotes the corresponding amplitude parameter. A step-valued parameter $n_q$ represents the physical time $t_q=n_q\Delta t$.
+
+ - 0: Gaussian pulse, $E(t)=E_0\cos\left[\omega(t-t_0)+\varphi\right]\mathrm{e}^{-(t-t_0)^2/(2\sigma^2)}$, where $t_0=\mathtt{td\_gauss\_t0}\Delta t$.
+ - 1: Trapezoid pulse, $E(t)=E_0g(t)\cos(\omega t+\varphi)$. With $t_1=\mathtt{td\_trape\_t1}\Delta t$, $t_2=\mathtt{td\_trape\_t2}\Delta t$, and $t_3=\mathtt{td\_trape\_t3}\Delta t$, the envelope is $g(t)=t/t_1$ for $0\leqslant t\lt t_1$, $g(t)=1$ for $t_1\leqslant t\lt t_2$, $g(t)=(t_3-t)/(t_3-t_2)$ for $t_2\leqslant t\lt t_3$, and $g(t)=0$ otherwise.
+ - 2: Trigonometric pulse, $E(t)=E_0\cos(\omega_1t+\varphi_1)\sin^2(\omega_2t+\varphi_2)$.
+ - 3: Heaviside pulse defined on electronic steps. With $n_0=\mathtt{td\_heavi\_t0}$, $E(n)=E_0$ for $n\lt n_0$ and $E(n)=0$ for $n\geqslant n_0$.
+ - 4: Finite-support supersine pulse. For $t_{\mathrm{s}}\lt t\lt t_{\mathrm{e}}$, the envelope is $f(t)=\left\{\sin\left[\pi\frac{t-t_{\mathrm{s}}}{t_{\mathrm{e}}-t_{\mathrm{s}}}\right]\right\}^{\frac{\pi}{\sigma}\left|\frac{t-t_{\mathrm{s}}}{t_{\mathrm{e}}-t_{\mathrm{s}}}-\frac{1}{2}\right|}$ and the electric field is $E(t)=E_0\left\{f(t)\cos\left[\omega\left(t-\frac{t_{\mathrm{s}}+t_{\mathrm{e}}}{2}\right)+\varphi\right]+\frac{\dot{f}(t)}{\omega}\sin\left[\omega\left(t-\frac{t_{\mathrm{s}}+t_{\mathrm{e}}}{2}\right)+\varphi\right]\right\}$. The corresponding analytic vector potential is $\boldsymbol{A}(t)=-\frac{E_0}{\omega}f(t)\sin\left[\omega\left(t-\frac{t_{\mathrm{s}}+t_{\mathrm{e}}}{2}\right)+\varphi\right]\hat{\boldsymbol{e}}$, with $\boldsymbol{E}(t)=-\partial\boldsymbol{A}(t)/\partial t$. The envelope, electric field, and vector potential are zero at the pulse boundaries and outside the interval.
+
+ In the velocity and hybrid gauges, ABACUS obtains the vector potential actually used in propagation by Simpson integration of the selected electric fields, including the supersine field, so a residual at the numerical-quadrature accuracy scale may remain.
- **Default**: 0
### td_tstart
- **Type**: Integer
-- **Description**: The initial time step when the time-dependent electric field is activated.
+- **Description**: First electronic step at which the time-dependent electric field is active. The interval from td_tstart through td_tend includes both endpoints. On each active step $n$, the velocity and hybrid gauges integrate the field over $[n\Delta t,(n+1)\Delta t]$, where $\Delta t=\mathtt{td\_dt}$.
- **Default**: 1
### td_tend
- **Type**: Integer
-- **Description**: The final time step when the time-dependent electric field is deactivated. The field remains active between td_tstart and td_tend.
+- **Description**: Last electronic step at which the time-dependent electric field is active. The interval from td_tstart through td_tend includes both endpoints. On each active step $n$, the velocity and hybrid gauges integrate the field over $[n\Delta t,(n+1)\Delta t]$, where $\Delta t=\mathtt{td\_dt}$.
- **Default**: 1000
### td_lcut1
- **Type**: Real
-- **Description**: The lower bound of the interval in the length gauge RT-TDDFT, where the coordinate is the fractional coordinate.
+- **Description**: Lower fractional-coordinate cutoff for the periodic spatial modulation used in the length gauge. Let $c_1=\mathtt{td\_lcut1}$, $c_2=\mathtt{td\_lcut2}$, $D=c_2-c_1$, and $G=c_1+1-c_2$. For a fractional coordinate $x$, the field factor is $\eta(x)=1$ when $c_1\leqslant x\lt c_2$ and $\eta(x)=-D/G$ elsewhere. The reversed outer interval makes the potential periodic and continuous and gives the field zero cell average.
- **Default**: 0.05
### td_lcut2
- **Type**: Real
-- **Description**: The upper bound of the interval in the length gauge RT-TDDFT, where the coordinate is the fractional coordinate.
+- **Description**: Upper fractional-coordinate cutoff for the periodic spatial modulation used in the length gauge. Let $c_1=\mathtt{td\_lcut1}$, $c_2=\mathtt{td\_lcut2}$, $D=c_2-c_1$, and $G=c_1+1-c_2$. For a fractional coordinate $x$, the field factor is $\eta(x)=1$ when $c_1\leqslant x\lt c_2$ and $\eta(x)=-D/G$ elsewhere. The reversed outer interval makes the potential periodic and continuous and gives the field zero cell average.
- **Default**: 0.95
### td_gauss_freq
-- **Type**: String
-- **Description**: Frequency of the Gaussian type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 0*
+- **Description**: Ordinary frequency $f$ in the Gaussian-pulse formula, with $\omega=2\pi f$. Supply exactly one value for each td_ttype 0 occurrence, in occurrence order.
- **Default**: 22.13
- **Unit**: 1/fs
### td_gauss_phase
-- **Type**: String
-- **Description**: Phase of the Gaussian type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 0*
+- **Description**: Carrier phase $\varphi$ in the Gaussian-pulse formula. Supply exactly one value for each td_ttype 0 occurrence, in occurrence order.
- **Default**: 0.0
+- **Unit**: rad
### td_gauss_sigma
-- **Type**: String
-- **Description**: Pulse width (standard deviation) of the Gaussian type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 0*
+- **Description**: Nonzero standard deviation $\sigma$ of the Gaussian envelope. Supply exactly one value for each td_ttype 0 occurrence, in occurrence order.
- **Default**: 30.0
- **Unit**: fs
### td_gauss_t0
-- **Type**: String
-- **Description**: Step number of the time center of the Gaussian type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 0*
+- **Description**: Electronic-step position of the Gaussian center, which defines $t_0=\mathtt{td\_gauss\_t0}\Delta t$. Supply exactly one value for each td_ttype 0 occurrence, in occurrence order.
- **Default**: 100
### td_gauss_amp
-- **Type**: String
-- **Description**: Amplitude of the Gaussian type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 0*
+- **Description**: Electric-field scale $E_0$ in the Gaussian-pulse formula. Supply exactly one value for each td_ttype 0 occurrence, in occurrence order.
- **Default**: 0.25
- **Unit**: V/Angstrom
### td_trape_freq
-- **Type**: String
-- **Description**: Frequency of the trapezoid type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 1*
+- **Description**: Ordinary carrier frequency $f$ in the trapezoid-pulse formula, with $\omega=2\pi f$. Supply exactly one value for each td_ttype 1 occurrence, in occurrence order.
- **Default**: 1.60
- **Unit**: 1/fs
### td_trape_phase
-- **Type**: String
-- **Description**: Phase of the trapezoid type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 1*
+- **Description**: Carrier phase $\varphi$ in the trapezoid-pulse formula. Supply exactly one value for each td_ttype 1 occurrence, in occurrence order.
- **Default**: 0.0
+- **Unit**: rad
### td_trape_t1
-- **Type**: String
-- **Description**: Step number of the time interval t1 of the trapezoid type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 1*
+- **Description**: Electronic step defining the end of the linear rise, $t_1=\mathtt{td\_trape\_t1}\Delta t$. Each field must satisfy td_trape_t1 <= td_trape_t2 <= td_trape_t3. Supply exactly one value for each td_ttype 1 occurrence, in occurrence order.
- **Default**: 1875
### td_trape_t2
-- **Type**: String
-- **Description**: Step number of the time interval t2 of the trapezoid type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 1*
+- **Description**: Electronic step defining the end of the plateau, $t_2=\mathtt{td\_trape\_t2}\Delta t$. Each field must satisfy td_trape_t1 <= td_trape_t2 <= td_trape_t3. Supply exactly one value for each td_ttype 1 occurrence, in occurrence order.
- **Default**: 5625
### td_trape_t3
-- **Type**: String
-- **Description**: Step number of the time interval t3 of the trapezoid type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 1*
+- **Description**: Electronic step defining the end of the linear fall, $t_3=\mathtt{td\_trape\_t3}\Delta t$. Each field must satisfy td_trape_t1 <= td_trape_t2 <= td_trape_t3. Supply exactly one value for each td_ttype 1 occurrence, in occurrence order.
- **Default**: 7500
### td_trape_amp
-- **Type**: String
-- **Description**: Amplitude of the trapezoid type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 1*
+- **Description**: Electric-field scale $E_0$ in the trapezoid-pulse formula. Supply exactly one value for each td_ttype 1 occurrence, in occurrence order.
- **Default**: 2.74
- **Unit**: V/Angstrom
### td_trigo_freq1
-- **Type**: String
-- **Description**: Frequency 1 of the trigonometric type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 2*
+- **Description**: First ordinary frequency $f_1$ in the trigonometric-pulse formula, with $\omega_1=2\pi f_1$. Supply exactly one value for each td_ttype 2 occurrence, in occurrence order.
- **Default**: 1.164656
- **Unit**: 1/fs
### td_trigo_freq2
-- **Type**: String
-- **Description**: Frequency 2 of the trigonometric type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 2*
+- **Description**: Second ordinary frequency $f_2$ in the trigonometric-pulse formula, with $\omega_2=2\pi f_2$. Supply exactly one value for each td_ttype 2 occurrence, in occurrence order.
- **Default**: 0.029116
- **Unit**: 1/fs
### td_trigo_phase1
-- **Type**: String
-- **Description**: Phase 1 of the trigonometric type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 2*
+- **Description**: Carrier phase $\varphi_1$ in the cosine factor of the trigonometric-pulse formula. Supply exactly one value for each td_ttype 2 occurrence, in occurrence order.
- **Default**: 0.0
+- **Unit**: rad
### td_trigo_phase2
-- **Type**: String
-- **Description**: Phase 2 of the trigonometric type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 2*
+- **Description**: Envelope phase $\varphi_2$ in the sine-squared factor of the trigonometric-pulse formula. Supply exactly one value for each td_ttype 2 occurrence, in occurrence order.
- **Default**: 0.0
+- **Unit**: rad
### td_trigo_amp
-- **Type**: String
-- **Description**: Amplitude of the trigonometric type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 2*
+- **Description**: Electric-field scale $E_0$ in the trigonometric-pulse formula. Supply exactly one value for each td_ttype 2 occurrence, in occurrence order.
- **Default**: 2.74
- **Unit**: V/Angstrom
### td_heavi_t0
-- **Type**: String
-- **Description**: Step number of the switch time of the Heaviside type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 3*
+- **Description**: Electronic switch step $n_0$ in the Heaviside-pulse definition. The field is $E_0$ for $n\lt n_0$ and zero for $n\geqslant n_0$. Supply exactly one value for each td_ttype 3 occurrence, in occurrence order.
- **Default**: 100
### td_heavi_amp
-- **Type**: String
-- **Description**: Amplitude of the Heaviside type electric field.
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 3*
+- **Description**: Electric-field scale $E_0$ in the Heaviside-pulse definition. Supply exactly one value for each td_ttype 3 occurrence, in occurrence order.
- **Default**: 1.0
- **Unit**: V/Angstrom
+### td_supsine_amp
+
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 4*
+- **Description**: Carrier electric-field scale $E_0$ of each supersine pulse. This is not a normalization of the complete waveform maximum, because the envelope-derivative term also contributes. Supply exactly one value for each td_ttype 4 occurrence, in occurrence order.
+- **Default**: 0.27
+- **Unit**: V/Angstrom
+
+### td_supsine_freq
+
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 4*
+- **Description**: Nonzero ordinary carrier frequency $f$ of each supersine pulse, with $\omega=2\pi f$. Supply exactly one value for each td_ttype 4 occurrence, in occurrence order.
+- **Default**: 0.18737028625
+- **Unit**: 1/fs
+
+### td_supsine_phase
+
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 4*
+- **Description**: Electric-field carrier phase $\varphi$ at the center of each supersine envelope. A value of 0 places a cosine carrier maximum at the envelope center. Supply exactly one value for each td_ttype 4 occurrence, in occurrence order.
+- **Default**: 0.0
+- **Unit**: rad
+
+### td_supsine_sigma
+
+- **Type**: Vector of Real
+- **Availability**: *td_ttype contains 4*
+- **Description**: Dimensionless shape parameter $\sigma$ of each supersine envelope. It must satisfy $0\lt\sigma\lt\pi/2$ so that the electric field approaches zero at the pulse boundaries. Supply exactly one value for each td_ttype 4 occurrence, in occurrence order.
+- **Default**: 0.75
+
+### td_supsine_tstart
+
+- **Type**: Vector of String
+- **Availability**: *td_ttype contains 4*
+- **Description**: Integer electronic step at the left, exactly zero boundary of each supersine pulse, defining $t_{\mathrm{s}}=\mathtt{td\_supsine\_tstart}\Delta t$. Supply exactly one integer or default token for each td_ttype 4 occurrence, in occurrence order; each default token inherits td_tstart. The complete pulse support must lie inside the inclusive global td_tstart to td_tend interval; hard truncation of a supersine pulse is rejected.
+- **Default**: default
+
+### td_supsine_tend
+
+- **Type**: Vector of String
+- **Availability**: *td_ttype contains 4*
+- **Description**: Integer electronic step at the right, exactly zero boundary of each supersine pulse, defining $t_{\mathrm{e}}=\mathtt{td\_supsine\_tend}\Delta t$. Supply exactly one integer or default token for each td_ttype 4 occurrence, in occurrence order; each default token inherits td_tend. The complete pulse support must lie inside the inclusive global td_tstart to td_tend interval; hard truncation of a supersine pulse is rejected.
+- **Default**: default
+
### init_vecpot_file
- **Type**: Boolean
-- **Description**: Initialize vector potential through file or not.
- - True: Initialize vector potential from file At.dat (unit: a.u.). It consists of four columns, representing the step number and vector potential on each direction.
- - False: Calculate vector potential by integrating the electric field.
+- **Description**: Selects the source of the Cartesian vector potential used by LCAO RT-TDDFT.
+ - True: Read vector_pot.txt from the calculation working directory. Each non-comment line must contain four columns: a conventionally one-based electronic-step label followed by $A_x$, $A_y$, and $A_z$ in atomic units. Rows are consumed sequentially; the first column is read as a label and is not used for lookup. If propagation continues beyond the available rows, the last row is reused.
+ - False: Obtain the vector potential by integrating the configured electric field.
- **Default**: False
### ocp
- **Type**: Boolean
-- **Description**: - True: Fixes the band occupations based on the values specified in ocp_set.
- - False: Does not fix the band occupations.
+- **Description**: Controls fixed band occupations. In calculations other than LCAO RT-TDDFT, fixed values are applied during electronic-state setup. In LCAO RT-TDDFT, the initial ground-state SCF determines occupations normally, and fixed values from ocp_set are applied during the subsequent real-time propagation steps.
+ - True: Use the fixed occupations specified by ocp_set during propagation.
+ - False: Keep the occupations determined by the initial SCF.
- **Default**: False
### ocp_set
- **Type**: String
-- **Description**: If ocp is set to 1, ocp_set must be provided as a string specifying the occupation numbers for each band across all k-points. The format follows a space-separated pattern, where occupations are assigned sequentially to bands for each k-point. A shorthand notation Nx can be used to repeat a value x for N bands.
- - Example:
- 1 10*1 0 1 represents occupations for 13 bands, where the 12th band is fully unoccupied (0), and all others are occupied (1).
- - For a system with multiple k-points, the occupations must be specified for all k-points, following their order in the output file kpoints (may lead to fractional occupations).
- - Incorrect specification of ocp_set could lead to inconsistencies in electron counting, causing the calculation to terminate with an error.
+- **Description**: Fixed occupation weights used when ocp is true. Values are assigned band by band for each k-point, following k-point order. In LCAO RT-TDDFT, the initial ground-state SCF uses its normally determined occupations, and this array is applied only during subsequent real-time propagation steps. The repetition syntax N*x expands to N copies of x.
+ - Example: 1 10*1 0 1 expands to 13 values, with the 12th value equal to 0 and all other values equal to 1.
+ - After expansion, the array length must equal nks * nbands.
+ - The sum of all weights must equal nelec; otherwise the calculation terminates with an error.
- **Default**: None
### out_dipole
- **Type**: Boolean
-- **Description**: - True: Output electric dipole moment.
- - False: Do not output electric dipole moment.
+- **Description**: Controls electric-dipole output. In RT-TDDFT, each enabled spin channel is written to OUT.{suffix}/dipole_s[spin].txt using a one-based spin number. Every row contains the one-based electronic-step index followed by the Cartesian electronic-dipole components $P_x$, $P_y$, and $P_z$ in atomic units. The running log additionally reports the electronic, ionic, and total dipoles and the norm of the total dipole.
+ - True: Output the electric dipole information.
+ - False: Do not output the electric dipole information.
- **Default**: False
### out_current
- **Type**: Integer
-- **Description**: Controls the current-density output method for LCAO RT-TDDFT.
+- **Availability**: *basis_type==lcao and esolver_type==tddft*
+- **Description**: Controls the current-density output method for LCAO RT-TDDFT. Output rows contain the one-based electronic-step index followed by $J_x$, $J_y$, and $J_z$ in atomic units.
- 0: Do not output current.
- - 1: Explicitly construct the velocity operator from the momentum, vector-potential, and KB nonlocal-pseudopotential terms using two-center integral / spherical grid integral: $\hat{v}_{\alpha}=-\mathrm{i}\nabla_{\alpha}+A_{\alpha}(t)+\mathrm{i}\left[\widetilde{V}_{\mathrm{NL}}^{\mathrm{KB}},r_{\alpha}\right]$, where $\widetilde{V}_{\mathrm{NL}}^{\mathrm{KB}}=\mathrm{e}^{-\mathrm{i}\boldsymbol{A}(t)\cdot\boldsymbol{r}}\hat{V}_{\mathrm{NL}}^{\mathrm{KB}}\mathrm{e}^{\mathrm{i}\boldsymbol{A}(t)\cdot\boldsymbol{r}}$. $\boldsymbol{A}(t)$ is nonzero only for the velocity gauge (td_stype=1); otherwise $\boldsymbol{A}(t)=0$. Other nonlocal Hamiltonian terms (e.g., EXX) are not included explicitly.
- - 2: Use the full Hamiltonian to construct the generalized velocity matrix in a nonorthogonal NAO basis: $\widetilde{v}_{\alpha}=\partial_{\alpha}H+\mathrm{i}HS^{-1}\mathcal{R}_{\alpha}-\mathrm{i}\mathcal{R}_{\alpha}S^{-1}H-HS^{-1}\partial_{\alpha}S$. This includes all contributions available in the real-space Hamiltonian matrix when enabled. This method is more general but more expensive.
+ - 1: Explicitly construct the velocity operator from the momentum, vector-potential, and KB nonlocal-pseudopotential terms using two-center and spherical-grid integrals: $\hat{v}_{\alpha}=-\mathrm{i}\nabla_{\alpha}+A_{\alpha}(t)+\mathrm{i}\left[\widetilde{V}_{\mathrm{NL}}^{\mathrm{KB}},r_{\alpha}\right]$, where $\widetilde{V}_{\mathrm{NL}}^{\mathrm{KB}}=\mathrm{e}^{-\mathrm{i}\boldsymbol{A}(t)\cdot\boldsymbol{r}}\hat{V}_{\mathrm{NL}}^{\mathrm{KB}}\mathrm{e}^{\mathrm{i}\boldsymbol{A}(t)\cdot\boldsymbol{r}}$. $\boldsymbol{A}(t)$ is nonzero only for the velocity gauge (td_stype=1); otherwise $\boldsymbol{A}(t)=0$. Other nonlocal Hamiltonian terms, such as EXX, are not included explicitly. The total current is written to OUT.{suffix}/current_tot.txt.
+ - 2: Use the full Hamiltonian to construct the generalized velocity matrix in a nonorthogonal NAO basis, $\widetilde{v}_{\alpha}=\partial_{\alpha}H+\mathrm{i}HS^{-1}\mathcal{R}_{\alpha}-\mathrm{i}\mathcal{R}_{\alpha}S^{-1}H-HS^{-1}\partial_{\alpha}S$. This includes all contributions available in the real-space Hamiltonian matrix when enabled. This method is more general but more expensive. The total current is written to OUT.{suffix}/current_tot_comm.txt.
- **Default**: 0
### out_current_k
- **Type**: Boolean
-- **Description**: - True: Output current for each k-points separately.
- - False: Output current in total.
+- **Availability**: *basis_type==lcao and esolver_type==tddft and out_current>0*
+- **Description**: Controls whether LCAO RT-TDDFT current density is also resolved by spin and k-point. The total-current file is always written when out_current is 1 or 2.
+ - True: In addition to the total, out_current=1 writes OUT.{suffix}/current_s[spin]k[kpoint].txt; out_current=2 writes OUT.{suffix}/current_s[spin]k[kpoint]_comm.txt. Both use one-based spin and k-point numbers, with k-points numbered independently within each spin channel. Each row contains the one-based electronic-step index followed by $J_x$, $J_y$, and $J_z$ in atomic units.
+ - False: Output only current_tot.txt for out_current=1 or current_tot_comm.txt for out_current=2.
- **Default**: False
### out_efield
- **Type**: Boolean
-- **Description**: Whether to output the electric field data to files. When enabled, writes real-time electric field values (unit: V/A) into files named efield_[num].txt, where [num] is the sequential index of the electric field ranges from 0 to N-1 for N configured fields. It is noteworthy that the field type sequence follows td_ttype, while the direction sequence follows td_vext_dire.
- - True: Output electric field.
- - False: Do not output electric field.
+- **Availability**: *esolver_type==tddft and td_vext==true*
+- **Description**: Controls time-dependent electric-field output. For each configured field, OUT.{suffix}/efield_[index].txt contains two columns: physical time in fs and the field value in V/Angstrom. The one-based field index follows the occurrence order shared by td_ttype and td_vext_dire, so fields assigned to the same direction remain in separate files. At initialization, a fresh calculation with md_restart=False truncates the files corresponding to the currently configured fields, whereas a calculation with md_restart=True preserves them and appends new samples.
+ - True: Output electric-field values on active electronic steps.
+ - False: Do not output electric-field values.
- **Default**: False
### out_vecpot
- **Type**: Boolean
-- **Description**: Output vector potential or not (unit: a.u.).
- - True: Output vector potential into file At.dat.
- - False: Do not output vector potential.
+- **Availability**: *basis_type==lcao and esolver_type==tddft*
+- **Description**: Controls Cartesian vector-potential output for LCAO RT-TDDFT. OUT.{suffix}/vector_pot.txt contains four columns: the one-based electronic-step index followed by $A_x$, $A_y$, and $A_z$ in atomic units. At initialization, a fresh calculation with md_restart=False truncates the file and writes a new header, whereas a calculation with md_restart=True preserves a nonempty existing file and appends new samples. If the restart output file is missing or empty, a new file with a header is created.
+ - True: Write vector-potential samples on electronic propagation steps.
+ - False: Do not output the vector potential.
- **Default**: False
[back to top](#full-list-of-input-keywords)
diff --git a/docs/parameters.yaml b/docs/parameters.yaml
index a87375c033..7c142a45cb 100644
--- a/docs/parameters.yaml
+++ b/docs/parameters.yaml
@@ -2407,7 +2407,7 @@ parameters:
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Real
description: |
- The time step used in electronic propagation. Setting td_dt will reset the value of md_dt to td_dt * estep_per_md.
+ The time step used for electronic propagation. If td_dt is not specified, it is set to md_dt / estep_per_md. If td_dt is specified explicitly, md_dt is reset to td_dt * estep_per_md.
default_value: md_dt / estep_per_md
unit: fs
availability: ""
@@ -2415,9 +2415,9 @@ parameters:
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Integer
description: |
- Method to calculate the energy-density matrix, mainly affects the calculation of force and stress.
- * 0: Using the original formula.
- * 1: Using the formula for ground state (deprecated). Note that this usually does not hold if wave function is not the eigenstate of the Hamiltonian.
+ Method used to calculate the energy-density matrix for the overlap contribution to forces in LCAO RT-TDDFT.
+ * 0: Use $\mathrm{EDM}_{\boldsymbol{k}}=\frac{1}{2}\left(S_{\boldsymbol{k}}^{-1}H_{\boldsymbol{k}}\rho_{\boldsymbol{k}}+\rho_{\boldsymbol{k}}H_{\boldsymbol{k}}S_{\boldsymbol{k}}^{-1}\right)$.
+ * 1: Use the ground-state eigenvalue-weighted expression $\mathrm{EDM}_{\mu\nu,\boldsymbol{k}}=\sum_i w_{i\boldsymbol{k}}\epsilon_{i\boldsymbol{k}}C_{\mu i,\boldsymbol{k}}C_{\nu i,\boldsymbol{k}}^*$. This expression is deprecated for RT-TDDFT and is generally not valid when the propagated wave functions are not Hamiltonian eigenstates.
default_value: "0"
unit: ""
availability: ""
@@ -2425,9 +2425,9 @@ parameters:
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Real
description: |
- Controls the printing of Hamiltonian matrix elements.
- * < 0: Suppress all output.
- * >= 0: Print only elements with either i or j exceeding td_print_eij.
+ Controls output of the propagated-state Hamiltonian matrix elements $E_{ij}=\Braket{\psi_i | \hat{H} | \psi_j}$ to the running log. The printed band indices $i$ and $j$ are one-based global indices. Both the threshold and the printed matrix elements are in Ry.
+ * $\lt 0$: Disable the output.
+ * $\geqslant 0$: Print an element when either $\left|\operatorname{Re}E_{ij}\right|$ or $\left|\operatorname{Im}E_{ij}\right|$ is greater than or equal to td_print_eij.
default_value: "-1"
unit: Ry
availability: ""
@@ -2435,11 +2435,13 @@ parameters:
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Integer
description: |
- Methods of electronic propagation.
- * 0: Crank-Nicolson, based on matrix inversion.
- * 1: 4th-order Taylor expansion of exponential.
- * 2: Enforced time-reversal symmetry (ETRS).
- * 3: Crank-Nicolson, based on solving linear equation.
+ Method used to propagate the electronic states in a nonorthogonal LCAO basis. The formulas below use Hartree atomic units, with $S$, $H$, and $\Delta t=\mathtt{td\_dt}$ evaluated as required by each approximation.
+ * 0: Crank-Nicolson through an explicitly constructed evolution matrix, $U=\left[S+\mathrm{i}H\Delta t/2\right]^{-1}\left[S-\mathrm{i}H\Delta t/2\right]$.
+ * 1: Fourth-order Taylor approximation to the exponential. With $\mathcal{A}=-\mathrm{i}S^{-1}H\Delta t$, $U=I+\mathcal{A}+\mathcal{A}^2/2+\mathcal{A}^3/6+\mathcal{A}^4/24$.
+ * 2: Enforced time-reversal symmetry (ETRS), $U(t+\Delta t,t)=\exp\left[-\mathrm{i}S^{-1}H(t+\Delta t)\Delta t/2\right]\exp\left[-\mathrm{i}S^{-1}H(t)\Delta t/2\right]$. In the implementation, each exponential is replaced by the fourth-order Taylor polynomial from method 1 evaluated with a half time step.
+ * 3: Crank-Nicolson by directly solving $\left[S+\mathrm{i}H\Delta t/2\right]\psi(t+\Delta t)=\left[S-\mathrm{i}H\Delta t/2\right]\psi(t)$.
+
+ [NOTE] GPU execution currently supports only method 0 in both single-GPU and multi-GPU solver configurations. CPU execution supports methods 0 through 3.
default_value: "0"
unit: ""
availability: ""
@@ -2447,6 +2449,7 @@ parameters:
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Boolean
description: |
+ Controls whether a time-dependent external electric field is applied.
* True: Add a laser-material interaction (external electric field).
* False: No external electric field.
default_value: "False"
@@ -2454,9 +2457,9 @@ parameters:
availability: ""
- name: td_vext_dire
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Integer
description: |
- Specifies the direction(s) of the external electric field when td_vext is enabled. For example, td_vext_dire 1 2 indicates that external electric fields are applied to both the x and y directions simultaneously. Electric field parameters can also be written as strings. For example, td_gauss_phase 0 1.5707963 indicates that the Gaussian type electric fields in the x and y directions have a phase delay of pi/2.
+ Specifies one absolute Cartesian direction for each external electric field when td_vext is enabled. Unlike the ground-state efield_dir parameter, these directions are not defined by lattice or reciprocal-lattice vectors. The number of values must equal that of td_ttype, and repeated directions are allowed; fields assigned to the same direction are added. For example, td_vext_dire 1 2 applies one field along Cartesian x and one along Cartesian y.
* 1: The external field direction is along the x-axis.
* 2: The external field direction is along the y-axis.
* 3: The external field direction is along the z-axis.
@@ -2476,13 +2479,18 @@ parameters:
availability: ""
- name: td_ttype
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Integer
description: |
- Type of electric field in the time domain.
- * 0: Gaussian type function.
- * 1: Trapezoid type function.
- * 2: Trigonometric type function.
- * 3: Heaviside type function.
+ Specifies one time-domain type for each external electric field. Its number of values must equal that of td_vext_dire. Parameters belonging to each type must provide exactly one value for every occurrence of that type, in occurrence order; fields with a repeated direction are added.
+
+ The formulas below use Hartree atomic units. For every ordinary input frequency $f$, $\omega=2\pi f$; $\Delta t=\mathtt{td\_dt}$; and $E_0$ denotes the corresponding amplitude parameter. A step-valued parameter $n_q$ represents the physical time $t_q=n_q\Delta t$.
+ * 0: Gaussian pulse, $E(t)=E_0\cos\left[\omega(t-t_0)+\varphi\right]\mathrm{e}^{-(t-t_0)^2/(2\sigma^2)}$, where $t_0=\mathtt{td\_gauss\_t0}\Delta t$.
+ * 1: Trapezoid pulse, $E(t)=E_0g(t)\cos(\omega t+\varphi)$. With $t_1=\mathtt{td\_trape\_t1}\Delta t$, $t_2=\mathtt{td\_trape\_t2}\Delta t$, and $t_3=\mathtt{td\_trape\_t3}\Delta t$, the envelope is $g(t)=t/t_1$ for $0\leqslant t\lt t_1$, $g(t)=1$ for $t_1\leqslant t\lt t_2$, $g(t)=(t_3-t)/(t_3-t_2)$ for $t_2\leqslant t\lt t_3$, and $g(t)=0$ otherwise.
+ * 2: Trigonometric pulse, $E(t)=E_0\cos(\omega_1t+\varphi_1)\sin^2(\omega_2t+\varphi_2)$.
+ * 3: Heaviside pulse defined on electronic steps. With $n_0=\mathtt{td\_heavi\_t0}$, $E(n)=E_0$ for $n\lt n_0$ and $E(n)=0$ for $n\geqslant n_0$.
+ * 4: Finite-support supersine pulse. For $t_{\mathrm{s}}\lt t\lt t_{\mathrm{e}}$, the envelope is $f(t)=\left\{\sin\left[\pi\frac{t-t_{\mathrm{s}}}{t_{\mathrm{e}}-t_{\mathrm{s}}}\right]\right\}^{\frac{\pi}{\sigma}\left|\frac{t-t_{\mathrm{s}}}{t_{\mathrm{e}}-t_{\mathrm{s}}}-\frac{1}{2}\right|}$ and the electric field is $E(t)=E_0\left\{f(t)\cos\left[\omega\left(t-\frac{t_{\mathrm{s}}+t_{\mathrm{e}}}{2}\right)+\varphi\right]+\frac{\dot{f}(t)}{\omega}\sin\left[\omega\left(t-\frac{t_{\mathrm{s}}+t_{\mathrm{e}}}{2}\right)+\varphi\right]\right\}$. The corresponding analytic vector potential is $\boldsymbol{A}(t)=-\frac{E_0}{\omega}f(t)\sin\left[\omega\left(t-\frac{t_{\mathrm{s}}+t_{\mathrm{e}}}{2}\right)+\varphi\right]\hat{\boldsymbol{e}}$, with $\boldsymbol{E}(t)=-\partial\boldsymbol{A}(t)/\partial t$. The envelope, electric field, and vector potential are zero at the pulse boundaries and outside the interval.
+
+ In the velocity and hybrid gauges, ABACUS obtains the vector potential actually used in propagation by Simpson integration of the selected electric fields, including the supersine field, so a residual at the numerical-quadrature accuracy scale may remain.
default_value: "0"
unit: ""
availability: ""
@@ -2490,7 +2498,7 @@ parameters:
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Integer
description: |
- The initial time step when the time-dependent electric field is activated.
+ First electronic step at which the time-dependent electric field is active. The interval from td_tstart through td_tend includes both endpoints. On each active step $n$, the velocity and hybrid gauges integrate the field over $[n\Delta t,(n+1)\Delta t]$, where $\Delta t=\mathtt{td\_dt}$.
default_value: "1"
unit: ""
availability: ""
@@ -2498,7 +2506,7 @@ parameters:
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Integer
description: |
- The final time step when the time-dependent electric field is deactivated. The field remains active between td_tstart and td_tend.
+ Last electronic step at which the time-dependent electric field is active. The interval from td_tstart through td_tend includes both endpoints. On each active step $n$, the velocity and hybrid gauges integrate the field over $[n\Delta t,(n+1)\Delta t]$, where $\Delta t=\mathtt{td\_dt}$.
default_value: "1000"
unit: ""
availability: ""
@@ -2506,7 +2514,7 @@ parameters:
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Real
description: |
- The lower bound of the interval in the length gauge RT-TDDFT, where the coordinate is the fractional coordinate.
+ Lower fractional-coordinate cutoff for the periodic spatial modulation used in the length gauge. Let $c_1=\mathtt{td\_lcut1}$, $c_2=\mathtt{td\_lcut2}$, $D=c_2-c_1$, and $G=c_1+1-c_2$. For a fractional coordinate $x$, the field factor is $\eta(x)=1$ when $c_1\leqslant x\lt c_2$ and $\eta(x)=-D/G$ elsewhere. The reversed outer interval makes the potential periodic and continuous and gives the field zero cell average.
default_value: "0.05"
unit: ""
availability: ""
@@ -2514,161 +2522,209 @@ parameters:
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Real
description: |
- The upper bound of the interval in the length gauge RT-TDDFT, where the coordinate is the fractional coordinate.
+ Upper fractional-coordinate cutoff for the periodic spatial modulation used in the length gauge. Let $c_1=\mathtt{td\_lcut1}$, $c_2=\mathtt{td\_lcut2}$, $D=c_2-c_1$, and $G=c_1+1-c_2$. For a fractional coordinate $x$, the field factor is $\eta(x)=1$ when $c_1\leqslant x\lt c_2$ and $\eta(x)=-D/G$ elsewhere. The reversed outer interval makes the potential periodic and continuous and gives the field zero cell average.
default_value: "0.95"
unit: ""
availability: ""
- name: td_gauss_freq
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Frequency of the Gaussian type electric field.
+ Ordinary frequency $f$ in the Gaussian-pulse formula, with $\omega=2\pi f$. Supply exactly one value for each td_ttype 0 occurrence, in occurrence order.
default_value: "22.13"
unit: 1/fs
- availability: ""
+ availability: td_ttype contains 0
- name: td_gauss_phase
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Phase of the Gaussian type electric field.
+ Carrier phase $\varphi$ in the Gaussian-pulse formula. Supply exactly one value for each td_ttype 0 occurrence, in occurrence order.
default_value: "0.0"
- unit: ""
- availability: ""
+ unit: rad
+ availability: td_ttype contains 0
- name: td_gauss_sigma
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Pulse width (standard deviation) of the Gaussian type electric field.
+ Nonzero standard deviation $\sigma$ of the Gaussian envelope. Supply exactly one value for each td_ttype 0 occurrence, in occurrence order.
default_value: "30.0"
unit: fs
- availability: ""
+ availability: td_ttype contains 0
- name: td_gauss_t0
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Step number of the time center of the Gaussian type electric field.
+ Electronic-step position of the Gaussian center, which defines $t_0=\mathtt{td\_gauss\_t0}\Delta t$. Supply exactly one value for each td_ttype 0 occurrence, in occurrence order.
default_value: "100"
unit: ""
- availability: ""
+ availability: td_ttype contains 0
- name: td_gauss_amp
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Amplitude of the Gaussian type electric field.
+ Electric-field scale $E_0$ in the Gaussian-pulse formula. Supply exactly one value for each td_ttype 0 occurrence, in occurrence order.
default_value: "0.25"
unit: V/Angstrom
- availability: ""
+ availability: td_ttype contains 0
- name: td_trape_freq
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Frequency of the trapezoid type electric field.
+ Ordinary carrier frequency $f$ in the trapezoid-pulse formula, with $\omega=2\pi f$. Supply exactly one value for each td_ttype 1 occurrence, in occurrence order.
default_value: "1.60"
unit: 1/fs
- availability: ""
+ availability: td_ttype contains 1
- name: td_trape_phase
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Phase of the trapezoid type electric field.
+ Carrier phase $\varphi$ in the trapezoid-pulse formula. Supply exactly one value for each td_ttype 1 occurrence, in occurrence order.
default_value: "0.0"
- unit: ""
- availability: ""
+ unit: rad
+ availability: td_ttype contains 1
- name: td_trape_t1
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Step number of the time interval t1 of the trapezoid type electric field.
+ Electronic step defining the end of the linear rise, $t_1=\mathtt{td\_trape\_t1}\Delta t$. Each field must satisfy td_trape_t1 <= td_trape_t2 <= td_trape_t3. Supply exactly one value for each td_ttype 1 occurrence, in occurrence order.
default_value: "1875"
unit: ""
- availability: ""
+ availability: td_ttype contains 1
- name: td_trape_t2
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Step number of the time interval t2 of the trapezoid type electric field.
+ Electronic step defining the end of the plateau, $t_2=\mathtt{td\_trape\_t2}\Delta t$. Each field must satisfy td_trape_t1 <= td_trape_t2 <= td_trape_t3. Supply exactly one value for each td_ttype 1 occurrence, in occurrence order.
default_value: "5625"
unit: ""
- availability: ""
+ availability: td_ttype contains 1
- name: td_trape_t3
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Step number of the time interval t3 of the trapezoid type electric field.
+ Electronic step defining the end of the linear fall, $t_3=\mathtt{td\_trape\_t3}\Delta t$. Each field must satisfy td_trape_t1 <= td_trape_t2 <= td_trape_t3. Supply exactly one value for each td_ttype 1 occurrence, in occurrence order.
default_value: "7500"
unit: ""
- availability: ""
+ availability: td_ttype contains 1
- name: td_trape_amp
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Amplitude of the trapezoid type electric field.
+ Electric-field scale $E_0$ in the trapezoid-pulse formula. Supply exactly one value for each td_ttype 1 occurrence, in occurrence order.
default_value: "2.74"
unit: V/Angstrom
- availability: ""
+ availability: td_ttype contains 1
- name: td_trigo_freq1
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Frequency 1 of the trigonometric type electric field.
+ First ordinary frequency $f_1$ in the trigonometric-pulse formula, with $\omega_1=2\pi f_1$. Supply exactly one value for each td_ttype 2 occurrence, in occurrence order.
default_value: "1.164656"
unit: 1/fs
- availability: ""
+ availability: td_ttype contains 2
- name: td_trigo_freq2
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Frequency 2 of the trigonometric type electric field.
+ Second ordinary frequency $f_2$ in the trigonometric-pulse formula, with $\omega_2=2\pi f_2$. Supply exactly one value for each td_ttype 2 occurrence, in occurrence order.
default_value: "0.029116"
unit: 1/fs
- availability: ""
+ availability: td_ttype contains 2
- name: td_trigo_phase1
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Phase 1 of the trigonometric type electric field.
+ Carrier phase $\varphi_1$ in the cosine factor of the trigonometric-pulse formula. Supply exactly one value for each td_ttype 2 occurrence, in occurrence order.
default_value: "0.0"
- unit: ""
- availability: ""
+ unit: rad
+ availability: td_ttype contains 2
- name: td_trigo_phase2
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Phase 2 of the trigonometric type electric field.
+ Envelope phase $\varphi_2$ in the sine-squared factor of the trigonometric-pulse formula. Supply exactly one value for each td_ttype 2 occurrence, in occurrence order.
default_value: "0.0"
- unit: ""
- availability: ""
+ unit: rad
+ availability: td_ttype contains 2
- name: td_trigo_amp
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Amplitude of the trigonometric type electric field.
+ Electric-field scale $E_0$ in the trigonometric-pulse formula. Supply exactly one value for each td_ttype 2 occurrence, in occurrence order.
default_value: "2.74"
unit: V/Angstrom
- availability: ""
+ availability: td_ttype contains 2
- name: td_heavi_t0
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Step number of the switch time of the Heaviside type electric field.
+ Electronic switch step $n_0$ in the Heaviside-pulse definition. The field is $E_0$ for $n\lt n_0$ and zero for $n\geqslant n_0$. Supply exactly one value for each td_ttype 3 occurrence, in occurrence order.
default_value: "100"
unit: ""
- availability: ""
+ availability: td_ttype contains 3
- name: td_heavi_amp
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
- type: String
+ type: Vector of Real
description: |
- Amplitude of the Heaviside type electric field.
+ Electric-field scale $E_0$ in the Heaviside-pulse definition. Supply exactly one value for each td_ttype 3 occurrence, in occurrence order.
default_value: "1.0"
unit: V/Angstrom
- availability: ""
+ availability: td_ttype contains 3
+ - name: td_supsine_amp
+ category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
+ type: Vector of Real
+ description: |
+ Carrier electric-field scale $E_0$ of each supersine pulse. This is not a normalization of the complete waveform maximum, because the envelope-derivative term also contributes. Supply exactly one value for each td_ttype 4 occurrence, in occurrence order.
+ default_value: "0.27"
+ unit: V/Angstrom
+ availability: td_ttype contains 4
+ - name: td_supsine_freq
+ category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
+ type: Vector of Real
+ description: |
+ Nonzero ordinary carrier frequency $f$ of each supersine pulse, with $\omega=2\pi f$. Supply exactly one value for each td_ttype 4 occurrence, in occurrence order.
+ default_value: "0.18737028625"
+ unit: 1/fs
+ availability: td_ttype contains 4
+ - name: td_supsine_phase
+ category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
+ type: Vector of Real
+ description: |
+ Electric-field carrier phase $\varphi$ at the center of each supersine envelope. A value of 0 places a cosine carrier maximum at the envelope center. Supply exactly one value for each td_ttype 4 occurrence, in occurrence order.
+ default_value: "0.0"
+ unit: rad
+ availability: td_ttype contains 4
+ - name: td_supsine_sigma
+ category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
+ type: Vector of Real
+ description: |
+ Dimensionless shape parameter $\sigma$ of each supersine envelope. It must satisfy $0\lt\sigma\lt\pi/2$ so that the electric field approaches zero at the pulse boundaries. Supply exactly one value for each td_ttype 4 occurrence, in occurrence order.
+ default_value: "0.75"
+ unit: ""
+ availability: td_ttype contains 4
+ - name: td_supsine_tstart
+ category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
+ type: Vector of String
+ description: |
+ Integer electronic step at the left, exactly zero boundary of each supersine pulse, defining $t_{\mathrm{s}}=\mathtt{td\_supsine\_tstart}\Delta t$. Supply exactly one integer or default token for each td_ttype 4 occurrence, in occurrence order; each default token inherits td_tstart. The complete pulse support must lie inside the inclusive global td_tstart to td_tend interval; hard truncation of a supersine pulse is rejected.
+ default_value: default
+ unit: ""
+ availability: td_ttype contains 4
+ - name: td_supsine_tend
+ category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
+ type: Vector of String
+ description: |
+ Integer electronic step at the right, exactly zero boundary of each supersine pulse, defining $t_{\mathrm{e}}=\mathtt{td\_supsine\_tend}\Delta t$. Supply exactly one integer or default token for each td_ttype 4 occurrence, in occurrence order; each default token inherits td_tend. The complete pulse support must lie inside the inclusive global td_tstart to td_tend interval; hard truncation of a supersine pulse is rejected.
+ default_value: default
+ unit: ""
+ availability: td_ttype contains 4
- name: init_vecpot_file
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Boolean
description: |
- Initialize vector potential through file or not.
- * True: Initialize vector potential from file At.dat (unit: a.u.). It consists of four columns, representing the step number and vector potential on each direction.
- * False: Calculate vector potential by integrating the electric field.
+ Selects the source of the Cartesian vector potential used by LCAO RT-TDDFT.
+ * True: Read vector_pot.txt from the calculation working directory. Each non-comment line must contain four columns: a conventionally one-based electronic-step label followed by $A_x$, $A_y$, and $A_z$ in atomic units. Rows are consumed sequentially; the first column is read as a label and is not used for lookup. If propagation continues beyond the available rows, the last row is reused.
+ * False: Obtain the vector potential by integrating the configured electric field.
default_value: "False"
unit: ""
availability: ""
@@ -2676,8 +2732,9 @@ parameters:
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Boolean
description: |
- * True: Fixes the band occupations based on the values specified in ocp_set.
- * False: Does not fix the band occupations.
+ Controls fixed band occupations. In calculations other than LCAO RT-TDDFT, fixed values are applied during electronic-state setup. In LCAO RT-TDDFT, the initial ground-state SCF determines occupations normally, and fixed values from ocp_set are applied during the subsequent real-time propagation steps.
+ * True: Use the fixed occupations specified by ocp_set during propagation.
+ * False: Keep the occupations determined by the initial SCF.
default_value: "False"
unit: ""
availability: ""
@@ -2685,11 +2742,10 @@ parameters:
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: String
description: |
- If ocp is set to 1, ocp_set must be provided as a string specifying the occupation numbers for each band across all k-points. The format follows a space-separated pattern, where occupations are assigned sequentially to bands for each k-point. A shorthand notation Nx can be used to repeat a value x for N bands.
- * Example:
- 1 10*1 0 1 represents occupations for 13 bands, where the 12th band is fully unoccupied (0), and all others are occupied (1).
- * For a system with multiple k-points, the occupations must be specified for all k-points, following their order in the output file kpoints (may lead to fractional occupations).
- * Incorrect specification of ocp_set could lead to inconsistencies in electron counting, causing the calculation to terminate with an error.
+ Fixed occupation weights used when ocp is true. Values are assigned band by band for each k-point, following k-point order. In LCAO RT-TDDFT, the initial ground-state SCF uses its normally determined occupations, and this array is applied only during subsequent real-time propagation steps. The repetition syntax N*x expands to N copies of x.
+ * Example: 1 10*1 0 1 expands to 13 values, with the 12th value equal to 0 and all other values equal to 1.
+ * After expansion, the array length must equal nks * nbands.
+ * The sum of all weights must equal nelec; otherwise the calculation terminates with an error.
default_value: None
unit: ""
availability: ""
@@ -3471,8 +3527,9 @@ parameters:
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Boolean
description: |
- * True: Output electric dipole moment.
- * False: Do not output electric dipole moment.
+ Controls electric-dipole output. In RT-TDDFT, each enabled spin channel is written to OUT.{suffix}/dipole_s[spin].txt using a one-based spin number. Every row contains the one-based electronic-step index followed by the Cartesian electronic-dipole components $P_x$, $P_y$, and $P_z$ in atomic units. The running log additionally reports the electronic, ionic, and total dipoles and the norm of the total dipole.
+ * True: Output the electric dipole information.
+ * False: Do not output the electric dipole information.
default_value: "False"
unit: ""
availability: ""
@@ -3480,42 +3537,43 @@ parameters:
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Integer
description: |
- Controls the current-density output method for LCAO RT-TDDFT.
+ Controls the current-density output method for LCAO RT-TDDFT. Output rows contain the one-based electronic-step index followed by $J_x$, $J_y$, and $J_z$ in atomic units.
* 0: Do not output current.
- * 1: Explicitly construct the velocity operator from the momentum, vector-potential, and KB nonlocal-pseudopotential terms using two-center integral / spherical grid integral: $\hat{v}_{\alpha}=-\mathrm{i}\nabla_{\alpha}+A_{\alpha}(t)+\mathrm{i}\left[\widetilde{V}_{\mathrm{NL}}^{\mathrm{KB}},r_{\alpha}\right]$, where $\widetilde{V}_{\mathrm{NL}}^{\mathrm{KB}}=\mathrm{e}^{-\mathrm{i}\boldsymbol{A}(t)\cdot\boldsymbol{r}}\hat{V}_{\mathrm{NL}}^{\mathrm{KB}}\mathrm{e}^{\mathrm{i}\boldsymbol{A}(t)\cdot\boldsymbol{r}}$. $\boldsymbol{A}(t)$ is nonzero only for the velocity gauge (td_stype=1); otherwise $\boldsymbol{A}(t)=0$. Other nonlocal Hamiltonian terms (e.g., EXX) are not included explicitly.
- * 2: Use the full Hamiltonian to construct the generalized velocity matrix in a nonorthogonal NAO basis: $\widetilde{v}_{\alpha}=\partial_{\alpha}H+\mathrm{i}HS^{-1}\mathcal{R}_{\alpha}-\mathrm{i}\mathcal{R}_{\alpha}S^{-1}H-HS^{-1}\partial_{\alpha}S$. This includes all contributions available in the real-space Hamiltonian matrix when enabled. This method is more general but more expensive.
+ * 1: Explicitly construct the velocity operator from the momentum, vector-potential, and KB nonlocal-pseudopotential terms using two-center and spherical-grid integrals: $\hat{v}_{\alpha}=-\mathrm{i}\nabla_{\alpha}+A_{\alpha}(t)+\mathrm{i}\left[\widetilde{V}_{\mathrm{NL}}^{\mathrm{KB}},r_{\alpha}\right]$, where $\widetilde{V}_{\mathrm{NL}}^{\mathrm{KB}}=\mathrm{e}^{-\mathrm{i}\boldsymbol{A}(t)\cdot\boldsymbol{r}}\hat{V}_{\mathrm{NL}}^{\mathrm{KB}}\mathrm{e}^{\mathrm{i}\boldsymbol{A}(t)\cdot\boldsymbol{r}}$. $\boldsymbol{A}(t)$ is nonzero only for the velocity gauge (td_stype=1); otherwise $\boldsymbol{A}(t)=0$. Other nonlocal Hamiltonian terms, such as EXX, are not included explicitly. The total current is written to OUT.{suffix}/current_tot.txt.
+ * 2: Use the full Hamiltonian to construct the generalized velocity matrix in a nonorthogonal NAO basis, $\widetilde{v}_{\alpha}=\partial_{\alpha}H+\mathrm{i}HS^{-1}\mathcal{R}_{\alpha}-\mathrm{i}\mathcal{R}_{\alpha}S^{-1}H-HS^{-1}\partial_{\alpha}S$. This includes all contributions available in the real-space Hamiltonian matrix when enabled. This method is more general but more expensive. The total current is written to OUT.{suffix}/current_tot_comm.txt.
default_value: "0"
unit: ""
- availability: ""
+ availability: basis_type==lcao and esolver_type==tddft
- name: out_current_k
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Boolean
description: |
- * True: Output current for each k-points separately.
- * False: Output current in total.
+ Controls whether LCAO RT-TDDFT current density is also resolved by spin and k-point. The total-current file is always written when out_current is 1 or 2.
+ * True: In addition to the total, out_current=1 writes OUT.{suffix}/current_s[spin]k[kpoint].txt; out_current=2 writes OUT.{suffix}/current_s[spin]k[kpoint]_comm.txt. Both use one-based spin and k-point numbers, with k-points numbered independently within each spin channel. Each row contains the one-based electronic-step index followed by $J_x$, $J_y$, and $J_z$ in atomic units.
+ * False: Output only current_tot.txt for out_current=1 or current_tot_comm.txt for out_current=2.
default_value: "False"
unit: ""
- availability: ""
+ availability: "basis_type==lcao and esolver_type==tddft and out_current>0"
- name: out_efield
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Boolean
description: |
- Whether to output the electric field data to files. When enabled, writes real-time electric field values (unit: V/A) into files named efield_[num].txt, where [num] is the sequential index of the electric field ranges from 0 to N-1 for N configured fields. It is noteworthy that the field type sequence follows td_ttype, while the direction sequence follows td_vext_dire.
- * True: Output electric field.
- * False: Do not output electric field.
+ Controls time-dependent electric-field output. For each configured field, OUT.{suffix}/efield_[index].txt contains two columns: physical time in fs and the field value in V/Angstrom. The one-based field index follows the occurrence order shared by td_ttype and td_vext_dire, so fields assigned to the same direction remain in separate files. At initialization, a fresh calculation with md_restart=False truncates the files corresponding to the currently configured fields, whereas a calculation with md_restart=True preserves them and appends new samples.
+ * True: Output electric-field values on active electronic steps.
+ * False: Do not output electric-field values.
default_value: "False"
unit: ""
- availability: ""
+ availability: esolver_type==tddft and td_vext==true
- name: out_vecpot
category: "RT-TDDFT: Real-Time Time-Dependent Density Functional Theory"
type: Boolean
description: |
- Output vector potential or not (unit: a.u.).
- * True: Output vector potential into file At.dat.
- * False: Do not output vector potential.
+ Controls Cartesian vector-potential output for LCAO RT-TDDFT. OUT.{suffix}/vector_pot.txt contains four columns: the one-based electronic-step index followed by $A_x$, $A_y$, and $A_z$ in atomic units. At initialization, a fresh calculation with md_restart=False truncates the file and writes a new header, whereas a calculation with md_restart=True preserves a nonempty existing file and appends new samples. If the restart output file is missing or empty, a new file with a header is created.
+ * True: Write vector-potential samples on electronic propagation steps.
+ * False: Do not output the vector potential.
default_value: "False"
unit: ""
- availability: ""
+ availability: basis_type==lcao and esolver_type==tddft
- name: cal_symm_repr
category: System variables
type: "Integer \\[Integer\\](optional)"
diff --git a/source/Makefile.Objects b/source/Makefile.Objects
index 6aeaa0c75a..771396233d 100644
--- a/source/Makefile.Objects
+++ b/source/Makefile.Objects
@@ -69,6 +69,7 @@ VPATH=./src_global:\
./src_ri:\
./source_lcao/module_ri:\
./source_io/module_parameter:\
+./source_io/module_efield:\
./source_lcao/module_lr:\
./source_lcao/module_lr/ao_to_mo_transformer:\
./source_lcao/module_lr/dm_trans:\
@@ -578,6 +579,8 @@ OBJS_IO=module_parameter/input_conv.o\
write_init.o\
td_current_io.o\
td_current_io_comm.o\
+ td_efield_io.o\
+ td_vector_pot_io.o\
write_libxc_r.o\
output_log.o\
output_mat_sparse.o\
diff --git a/source/source_esolver/esolver_ks_lcao_tddft.cpp b/source/source_esolver/esolver_ks_lcao_tddft.cpp
index 154a3a65e2..44c835c12a 100644
--- a/source/source_esolver/esolver_ks_lcao_tddft.cpp
+++ b/source/source_esolver/esolver_ks_lcao_tddft.cpp
@@ -1,11 +1,15 @@
#include "esolver_ks_lcao_tddft.h"
+#include "source_base/constants.h"
#include "source_lcao/module_rt/boundary_fix.h"
//----------------IO-----------------
#include "source_base/global_variable.h"
#include "source_io/module_ctrl/ctrl_output_td.h"
+#include "source_io/module_efield/td_efield_io.h"
+#include "source_io/module_efield/td_vector_pot_io.h"
#include "source_io/module_output/output_log.h"
+#include "source_io/module_parameter/parameter.h"
#include "source_io/module_wf/read_wfc_nao.h"
//------LCAO HSolver ElecState-------
#include "source_estate/elecstate_tools.h"
@@ -13,6 +17,8 @@
#include "source_estate/module_dm/cal_dm_psi.h"
#include "source_estate/module_dm/cal_edm_tddft.h"
#include "source_estate/module_pot/H_TDDFT_pw.h"
+#include "source_estate/module_pot/potential_new.h"
+#include "source_estate/module_pot/td_field_manager.h"
#include "source_hsolver/hsolver_lcao.h"
#include "source_lcao/module_rt/evolve_elec.h"
#include "source_lcao/rho_tau_lcao.h"
@@ -72,8 +78,27 @@ void ESolver_KS_LCAO_TDDFT
::before_all_runners(BaseCell& basecell, c
basecell.require_kind(BaseCell::Kind::unit_cell, __FUNCTION__);
UnitCell& ucell = static_cast(basecell);
+ // Build the shared field state before the base ESolver registers potential
+ // components. Both propagation gauges and the length-gauge potential must
+ // observe the same electronic-step counter.
+ td_field_manager_ = elecstate::create_td_field_manager(inp);
+ if (inp.mdp.md_restart)
+ {
+ td_field_manager_->read_restart(PARAM.globalv.global_readin_dir);
+ }
+ if (inp.out_efield && GlobalV::MY_RANK == 0)
+ {
+ ModuleIO::prepare_td_field_output(PARAM.globalv.global_out_dir, td_field_manager_->fields().size(), inp.mdp.md_restart);
+ }
+ if (inp.out_vecpot && GlobalV::MY_RANK == 0)
+ {
+ ModuleIO::prepare_td_vector_pot_output(PARAM.globalv.global_out_dir, inp.mdp.md_restart);
+ }
+ elecstate::H_TDDFT_pw::sync_compatibility_state(*td_field_manager_);
+
// Run before_all_runners in ESolver_KS_LCAO
ESolver_KS_LCAO, TR>::before_all_runners(ucell, inp);
+ this->pelec->pot->set_td_field_manager(td_field_manager_);
td_p = new TD_info(&ucell, this->pv, this->orb_);
TD_info::td_vel_op = td_p;
@@ -110,13 +135,8 @@ void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int ist
// 1) before_scf (electronic iteration loops)
//----------------------------------------------------------------
this->before_scf(ucell, istep); // From ESolver_KS_LCAO
- td_p->initialize_phase_hybrid(ucell,
- dynamic_cast, TR>*>(this->p_hamilt)->getHR());
- td_p->calculate_grad_overlap(this->pv,
- ucell,
- this->gd,
- this->orb_.cutoffs(),
- this->two_center_bundle_.overlap_orb.get());
+ td_p->initialize_phase_hybrid(ucell, dynamic_cast, TR>*>(this->p_hamilt)->getHR());
+ td_p->calculate_grad_overlap(this->pv, ucell, this->gd, this->orb_.cutoffs(), this->two_center_bundle_.overlap_orb.get());
// Initialize the moving spatial gauge
if (use_td_moving_gauge && this->td_mg_ == nullptr)
{
@@ -140,11 +160,7 @@ void ESolver_KS_LCAO_TDDFT::runner(BaseCell& basecell, const int ist
if (PARAM.inp.td_stype != 1 && TD_info::out_current == 1)
{
// initialize the velocity operator
- velocity_mat = new Velocity_op
(&ucell,
- &(this->gd),
- &this->pv,
- this->orb_,
- this->two_center_bundle_.overlap_orb.get());
+ velocity_mat = new Velocity_op
(&ucell, &(this->gd), &this->pv, this->orb_, this->two_center_bundle_.overlap_orb.get());
// calculate velocity operator
velocity_mat->calculate_grad_term();
velocity_mat->calculate_vcomm_r();
@@ -159,13 +175,7 @@ void ESolver_KS_LCAO_TDDFT
::runner(BaseCell& basecell, const int ist
// Reset laststep matrix and wfc, if any atom cross the boundary
// Apply a phase correction to H, S, and psi to keep consistency when atoms cross periodic boundaries
const size_t len_hs_ik = use_tensor && use_lapack ? PARAM.globalv.nlocal * PARAM.globalv.nlocal : this->pv.nloc;
- module_rt::reset_matrix_boundary(ucell,
- this->kv,
- &(this->pv),
- this->Hk_laststep,
- this->Sk_laststep,
- this->psi_laststep,
- len_hs_ik);
+ module_rt::reset_matrix_boundary(ucell, this->kv, &(this->pv), this->Hk_laststep, this->Sk_laststep, this->psi_laststep, len_hs_ik);
for (int estep = 0; estep < estep_max; estep++)
{
@@ -175,7 +185,14 @@ void ESolver_KS_LCAO_TDDFT
::runner(BaseCell& basecell, const int ist
// update At
if (PARAM.inp.td_stype > 0)
{
- elecstate::H_TDDFT_pw::update_At();
+ // TDFieldManager owns the midpoint-vector-potential update. Static
+ // mirrors are synchronized afterward for legacy RT-TDDFT clients.
+ td_field_manager_->advance_vector_gauge();
+ elecstate::H_TDDFT_pw::sync_compatibility_state(*td_field_manager_);
+ if (PARAM.inp.out_efield && GlobalV::MY_RANK == 0)
+ {
+ ModuleIO::write_td_field_values(*td_field_manager_, PARAM.globalv.global_out_dir);
+ }
td_p->cal_cart_At(elecstate::H_TDDFT_pw::At);
ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "Cartesian vector potential Ax(t)", TD_info::cart_At[0]);
ModuleBase::GlobalFunc::OUT(GlobalV::ofs_running, "Cartesian vector potential Ay(t)", TD_info::cart_At[1]);
@@ -185,12 +202,7 @@ void ESolver_KS_LCAO_TDDFT
::runner(BaseCell& basecell, const int ist
if (estep != 0)
{
this->CE.update_all_dis(ucell);
- this->CE.extrapolate_charge(&this->Pgrid,
- ucell,
- &this->chr,
- &this->sf,
- GlobalV::ofs_running,
- GlobalV::ofs_warning);
+ this->CE.extrapolate_charge(&this->Pgrid, ucell, &this->chr, &this->sf, GlobalV::ofs_running, GlobalV::ofs_warning);
this->exx_nao.before_scf(ucell, this->kv, this->orb_, this->p_chgmix, totstep, PARAM.inp);
elecstate::init_scf(ucell,
this->Pgrid,
@@ -276,10 +288,7 @@ void ESolver_KS_LCAO_TDDFT
::print_step()
}
template
-void ESolver_KS_LCAO_TDDFT::hamilt2rho_single(UnitCell& ucell,
- const int istep,
- const int iter,
- const double ethr)
+void ESolver_KS_LCAO_TDDFT
::hamilt2rho_single(UnitCell& ucell, const int istep, const int iter, const double ethr)
{
// Update the moving spatial gauge
if (use_td_moving_gauge)
@@ -293,26 +302,25 @@ void ESolver_KS_LCAO_TDDFT
::hamilt2rho_single(UnitCell& ucell,
{
if (istep >= TD_info::estep_shift + 1)
{
- module_rt::Evolve_elec::solve_psi(
- istep,
- PARAM.inp.nbands,
- PARAM.globalv.nlocal,
- this->kv.get_nks(),
- static_cast>*>(this->p_hamilt),
- this->pv,
- this->psi,
- this->psi_laststep,
- this->Hk_laststep,
- this->Sk_laststep,
- this->pelec->ekb,
- GlobalV::ofs_running,
- PARAM.inp.propagator,
- use_tensor,
- use_lapack,
- this->td_mg_,
- &ucell,
- this->kv.kvec_d,
- use_td_moving_gauge);
+ module_rt::Evolve_elec::solve_psi(istep,
+ PARAM.inp.nbands,
+ PARAM.globalv.nlocal,
+ this->kv.get_nks(),
+ static_cast>*>(this->p_hamilt),
+ this->pv,
+ this->psi,
+ this->psi_laststep,
+ this->Hk_laststep,
+ this->Sk_laststep,
+ this->pelec->ekb,
+ GlobalV::ofs_running,
+ PARAM.inp.propagator,
+ use_tensor,
+ use_lapack,
+ this->td_mg_,
+ &ucell,
+ this->kv.kvec_d,
+ use_td_moving_gauge);
}
this->weight_dm_rho(ucell);
}
@@ -397,8 +405,8 @@ void ESolver_KS_LCAO_TDDFT::iter_finish(UnitCell& ucell,
{
for (int ib = 0; ib < PARAM.inp.nbands; ib++)
{
- GlobalV::ofs_running << " " << std::setw(9) << ik + 1 << std::setw(8) << ib + 1 << std::setw(12)
- << this->pelec->wg(ik, ib) << std::endl;
+ GlobalV::ofs_running << " " << std::setw(9) << ik + 1 << std::setw(8) << ib + 1 << std::setw(12) << this->pelec->wg(ik, ib)
+ << std::endl;
}
}
GlobalV::ofs_running << std::endl;
@@ -412,32 +420,25 @@ void ESolver_KS_LCAO_TDDFT
::iter_finish(UnitCell& ucell,
this->store_h_s_psi(ucell, istep, iter, force_save);
// Calculate energy-density matrix for RT-TDDFT
- if (conv_esolver && estep == estep_max - 1 && istep >= (PARAM.inp.init_wfc == "file" ? 0 : 1)
- && PARAM.inp.td_edm == 0 && PARAM.inp.td_stype != 2)
+ if (conv_esolver && estep == estep_max - 1 && istep >= (PARAM.inp.init_wfc == "file" ? 0 : 1) && PARAM.inp.td_edm == 0
+ && PARAM.inp.td_stype != 2)
{
if (use_tensor && use_lapack)
{
- elecstate::cal_edm_tddft_tensor_lapack(
- this->pv,
- this->dmat,
- this->kv,
- static_cast>*>(this->p_hamilt));
+ elecstate::cal_edm_tddft_tensor_lapack(this->pv,
+ this->dmat,
+ this->kv,
+ static_cast>*>(this->p_hamilt));
}
else
{
- elecstate::cal_edm_tddft(this->pv,
- this->dmat,
- this->kv,
- static_cast>*>(this->p_hamilt));
+ elecstate::cal_edm_tddft(this->pv, this->dmat, this->kv, static_cast>*>(this->p_hamilt));
}
}
}
template
-void ESolver_KS_LCAO_TDDFT::store_h_s_psi(UnitCell& ucell,
- const int istep,
- const int iter,
- const bool conv_esolver)
+void ESolver_KS_LCAO_TDDFT
::store_h_s_psi(UnitCell& ucell, const int istep, const int iter, const bool conv_esolver)
{
const int nbands = PARAM.inp.nbands;
const int nlocal = PARAM.globalv.nlocal;
@@ -466,18 +467,16 @@ void ESolver_KS_LCAO_TDDFT
::store_h_s_psi(UnitCell& ucell,
// Allocate memory for Hk_laststep, if (use_tensor && use_lapack), should be global
if (this->Hk_laststep.NumElements() != len_HS_all)
{
- this->Hk_laststep = ct::Tensor(ct::DataType::DT_COMPLEX_DOUBLE,
- ct_device_type_hs,
- ct::TensorShape({this->kv.get_nks(), len_HS_ik}));
+ this->Hk_laststep
+ = ct::Tensor(ct::DataType::DT_COMPLEX_DOUBLE, ct_device_type_hs, ct::TensorShape({this->kv.get_nks(), len_HS_ik}));
this->Hk_laststep.zero();
}
// Allocate memory for Sk_laststep, if (use_tensor && use_lapack), should be global
if (this->Sk_laststep.NumElements() != len_HS_all)
{
- this->Sk_laststep = ct::Tensor(ct::DataType::DT_COMPLEX_DOUBLE,
- ct_device_type_hs,
- ct::TensorShape({this->kv.get_nks(), len_HS_ik}));
+ this->Sk_laststep
+ = ct::Tensor(ct::DataType::DT_COMPLEX_DOUBLE, ct_device_type_hs, ct::TensorShape({this->kv.get_nks(), len_HS_ik}));
this->Sk_laststep.zero();
}
@@ -537,34 +536,18 @@ void ESolver_KS_LCAO_TDDFT
::store_h_s_psi(UnitCell& ucell,
// Only the root process (myid == 0) performs the copy
if (myid == 0 && h_ptr != nullptr && s_ptr != nullptr)
{
- BlasConnector::copy(len_HS_ik,
- h_ptr,
- 1,
- this->Hk_laststep.template data>() + ik * len_HS_ik,
- 1);
- BlasConnector::copy(len_HS_ik,
- s_ptr,
- 1,
- this->Sk_laststep.template data>() + ik * len_HS_ik,
- 1);
+ BlasConnector::copy(len_HS_ik, h_ptr, 1, this->Hk_laststep.template data>() + ik * len_HS_ik, 1);
+ BlasConnector::copy(len_HS_ik, s_ptr, 1, this->Sk_laststep.template data>() + ik * len_HS_ik, 1);
}
#endif
}
else
{
- BlasConnector::copy(len_HS_ik,
- h_mat.p,
- 1,
- this->Hk_laststep.template data>() + ik * len_HS_ik,
- 1);
- BlasConnector::copy(len_HS_ik,
- s_mat.p,
- 1,
- this->Sk_laststep.template data>() + ik * len_HS_ik,
- 1);
+ BlasConnector::copy(len_HS_ik, h_mat.p, 1, this->Hk_laststep.template data>() + ik * len_HS_ik, 1);
+ BlasConnector::copy(len_HS_ik, s_mat.p, 1, this->Sk_laststep.template data>() + ik * len_HS_ik, 1);
} // end use_tensor
- } // end ik
- } // conv_esolver
+ } // end ik
+ } // conv_esolver
}
template
diff --git a/source/source_esolver/esolver_ks_lcao_tddft.h b/source/source_esolver/esolver_ks_lcao_tddft.h
index 07c8199cca..b321d60117 100644
--- a/source/source_esolver/esolver_ks_lcao_tddft.h
+++ b/source/source_esolver/esolver_ks_lcao_tddft.h
@@ -8,6 +8,13 @@
#include "source_lcao/module_rt/td_moving_gauge.h"
#include "source_lcao/module_rt/velocity_op.h"
+#include
+
+namespace elecstate
+{
+class TDFieldManager;
+}
+
namespace ModuleESolver
{
@@ -28,12 +35,7 @@ class ESolver_KS_LCAO_TDDFT : public ESolver_KS_LCAO, TR>
void store_h_s_psi(UnitCell& ucell, const int istep, const int iter, const bool conv_esolver);
- void iter_finish(UnitCell& ucell,
- const int istep,
- const int estep,
- const int estep_max,
- int& iter,
- bool& conv_esolver);
+ void iter_finish(UnitCell& ucell, const int istep, const int estep, const int estep_max, int& iter, bool& conv_esolver);
virtual void after_scf(UnitCell& ucell, const int istep, const bool conv_esolver) override;
@@ -72,6 +74,8 @@ class ESolver_KS_LCAO_TDDFT : public ESolver_KS_LCAO, TR>
//! Restart flag
bool restart_done = false;
+ std::shared_ptr td_field_manager_;
+
private:
void weight_dm_rho(const UnitCell& ucell);
};
diff --git a/source/source_estate/CMakeLists.txt b/source/source_estate/CMakeLists.txt
index 7d8e836bb1..34bf85cb6c 100644
--- a/source/source_estate/CMakeLists.txt
+++ b/source/source_estate/CMakeLists.txt
@@ -13,6 +13,7 @@ list(APPEND objects
module_pot/gatefield.cpp
module_pot/efield.cpp
module_pot/H_Hartree_pw.cpp
+ module_pot/H_TDDFT_pw.cpp
module_pot/pot_xc.cpp
module_pot/pot_local.cpp
module_pot/potential_new.cpp
@@ -22,6 +23,9 @@ list(APPEND objects
module_pot/pot_sep.cpp
module_pot/pot_xc_fdm.cpp
module_pot/pot_cosikr.cpp
+ module_pot/td_field.cpp
+ module_pot/td_field_profiles.cpp
+ module_pot/td_field_manager.cpp
module_charge/chgmixing.cpp
module_charge/gint_precision_controller.cpp
module_charge/charge.cpp
@@ -46,7 +50,6 @@ list(APPEND objects
if(ENABLE_LCAO)
list(APPEND objects
elecstate_lcao.cpp
- module_pot/H_TDDFT_pw.cpp
module_dm/init_dm.cpp
module_dm/density_matrix.cpp
module_dm/density_matrix_io.cpp
diff --git a/source/source_estate/module_pot/H_TDDFT_pw.cpp b/source/source_estate/module_pot/H_TDDFT_pw.cpp
index 5d2e0a940a..d56bcd13a8 100644
--- a/source/source_estate/module_pot/H_TDDFT_pw.cpp
+++ b/source/source_estate/module_pot/H_TDDFT_pw.cpp
@@ -1,490 +1,149 @@
#include "H_TDDFT_pw.h"
-#include "source_base/constants.h"
-#include "source_base/math_integral.h"
+#include "source_base/global_variable.h"
#include "source_base/timer.h"
+#include "source_base/tool_quit.h"
+#include "source_io/module_efield/td_efield_io.h"
#include "source_io/module_parameter/parameter.h"
+#include "td_field_manager.h"
namespace elecstate
{
-int H_TDDFT_pw::istep = -1;
-bool H_TDDFT_pw::is_initialized = false;
-
-double H_TDDFT_pw::amp;
-
-// Used for calculating electric field force on ions, summing over directions
-std::vector H_TDDFT_pw::global_vext_time = {0.0, 0.0, 0.0};
-
-int H_TDDFT_pw::stype; // 0 : length gauge 1: velocity gauge
-
-std::vector H_TDDFT_pw::ttype;
-// 0: Gaussian type function.
-// 1: Trapezoid type function.
-// 2: Trigonometric functions, sin^2.
-// 3: Heaviside step function.
-
-int H_TDDFT_pw::tstart;
-int H_TDDFT_pw::tend;
-double H_TDDFT_pw::dt;
-// cut dt for integral
-double H_TDDFT_pw::dt_int;
-int H_TDDFT_pw::istep_int;
-// space domain parameters
-
-// length gauge
-double H_TDDFT_pw::lcut1;
-double H_TDDFT_pw::lcut2;
-
-// velocity gauge
+int H_TDDFT_pw::stype = 0;
ModuleBase::Vector3 H_TDDFT_pw::At;
ModuleBase::Vector3 H_TDDFT_pw::At_laststep;
-// hybrid gauge
ModuleBase::Vector3 H_TDDFT_pw::Et;
-// time domain parameters
-
-// Gauss
-int H_TDDFT_pw::gauss_count;
-std::vector H_TDDFT_pw::gauss_omega; // time(a.u.)^-1
-std::vector H_TDDFT_pw::gauss_phase;
-std::vector H_TDDFT_pw::gauss_sigma; // time(a.u.)
-std::vector H_TDDFT_pw::gauss_t0;
-std::vector H_TDDFT_pw::gauss_amp; // Ry/bohr
-std::vector H_TDDFT_pw::gauss_ncut; // cut for integral
-
-// trapezoid
-int H_TDDFT_pw::trape_count;
-std::vector H_TDDFT_pw::trape_omega; // time(a.u.)^-1
-std::vector H_TDDFT_pw::trape_phase;
-std::vector H_TDDFT_pw::trape_t1;
-std::vector H_TDDFT_pw::trape_t2;
-std::vector H_TDDFT_pw::trape_t3;
-std::vector H_TDDFT_pw::trape_amp; // Ry/bohr
-std::vector H_TDDFT_pw::trape_ncut; // cut for integral
-
-// Trigonometric
-int H_TDDFT_pw::trigo_count;
-std::vector H_TDDFT_pw::trigo_omega1; // time(a.u.)^-1
-std::vector H_TDDFT_pw::trigo_omega2; // time(a.u.)^-1
-std::vector H_TDDFT_pw::trigo_phase1;
-std::vector H_TDDFT_pw::trigo_phase2;
-std::vector H_TDDFT_pw::trigo_amp; // Ry/bohr
-std::vector H_TDDFT_pw::trigo_ncut; // cut for integral
-
-// Heaviside
-int H_TDDFT_pw::heavi_count;
-std::vector H_TDDFT_pw::heavi_t0;
-std::vector H_TDDFT_pw::heavi_amp; // Ry/bohr
+std::vector H_TDDFT_pw::global_vext_time = {0.0, 0.0, 0.0};
-void H_TDDFT_pw::current_step_info(const std::string& file_dir, int& istep)
+H_TDDFT_pw::H_TDDFT_pw(const ModulePW::PW_Basis* rho_basis_in,
+ const UnitCell* ucell_in,
+ const std::shared_ptr& field_manager)
+ : ucell_(ucell_in), field_manager_(field_manager)
{
- std::stringstream ssc;
- ssc << file_dir << "Restart_td.txt";
- std::ifstream file(ssc.str().c_str());
+ this->dynamic_mode = false;
+ this->fixed_mode = true;
+ this->rho_basis_ = rho_basis_in;
- if (!file)
+ if (!field_manager_)
{
- ModuleBase::WARNING_QUIT("H_TDDFT_pw::current_step_info", "No Restart_td.txt!");
+ ModuleBase::WARNING_QUIT("H_TDDFT_pw", "RT-TDDFT field manager is not initialized.");
}
+ sync_compatibility_state(*field_manager_);
+}
- file >> istep;
- file >> At[0] >> At[1] >> At[2];
- file >> At_laststep[0] >> At_laststep[1] >> At_laststep[2];
- At_laststep = -At_laststep;
- file.close();
+void H_TDDFT_pw::sync_compatibility_state(const TDFieldManager& manager)
+{
+ stype = manager.gauge();
+ At = manager.vector_potential();
+ At_laststep = manager.vector_potential_laststep();
+ Et = manager.electric_field();
+ const ModuleBase::Vector3& total_field = manager.total_electric_field();
+ global_vext_time = {total_field[0], total_field[1], total_field[2]};
}
void H_TDDFT_pw::cal_fixed_v(double* vl_pseudo)
{
ModuleBase::TITLE("H_TDDFT_pw", "cal_fixed_v");
-
- // skip if not length gauge
- if (stype != 0)
+ if (field_manager_->gauge() != 0)
{
return;
}
- // time evolve
- H_TDDFT_pw::istep++;
- H_TDDFT_pw::istep_int = istep;
- global_vext_time = {0.0, 0.0, 0.0};
-
- // judgement to skip vext
- if (!PARAM.inp.td_vext || istep > tend || istep < tstart)
+ // Advance exactly once per rebuilt fixed potential. The potential then
+ // consumes the same per-occurrence samples exposed to field output.
+ field_manager_->advance_length_gauge();
+ sync_compatibility_state(*field_manager_);
+ if (!field_manager_->active())
{
return;
}
ModuleBase::timer::start("H_TDDFT_pw", "cal_fixed_v");
-
- int count = 0;
- gauss_count = 0;
- trape_count = 0;
- trigo_count = 0;
- heavi_count = 0;
-
-
-
- for (auto direc: PARAM.inp.td_vext_dire)
+ const std::vector& fields = field_manager_->fields();
+ const std::vector& field_values = field_manager_->field_values();
+ for (std::size_t field_index = 0; field_index < fields.size(); ++field_index)
{
std::vector vext_space(this->rho_basis_->nrxx, 0.0);
- double vext_time = cal_v_time(ttype[count], true);
-
- global_vext_time[direc - 1] += vext_time;
-
- if (PARAM.inp.out_efield && GlobalV::MY_RANK == 0)
- {
- std::stringstream as;
- as << PARAM.globalv.global_out_dir << "efield_" << count << ".txt";
- std::ofstream ofs(as.str().c_str(), std::ofstream::app);
- ofs << H_TDDFT_pw::istep * dt * ModuleBase::AU_to_FS << "\t"
- << vext_time * ModuleBase::Ry_to_eV / ModuleBase::BOHR_TO_A << std::endl;
- ofs.close();
- }
+ const double field_value = field_values[field_index];
- cal_v_space(vext_space, direc);
- for (size_t ir = 0; ir < this->rho_basis_->nrxx; ++ir)
+ cal_v_space_length(vext_space, fields[field_index].direction() + 1);
+ for (std::size_t ir = 0; ir < static_cast(this->rho_basis_->nrxx); ++ir)
{
- vl_pseudo[ir] += vext_space[ir] * vext_time;
+ vl_pseudo[ir] += vext_space[ir] * field_value;
}
- count++;
}
-
- ModuleBase::timer::end("H_TDDFT_pw", "cal_fixed_v");
- return;
-}
-
-void H_TDDFT_pw::cal_v_space(std::vector& vext_space, int direc)
-{
- ModuleBase::TITLE("H_TDDFT_pw", "cal_v_space");
- ModuleBase::timer::start("H_TDDFT_pw", "cal_v_space");
-
- switch (stype)
+ if (PARAM.inp.out_efield && GlobalV::MY_RANK == 0)
{
- case 0:
- cal_v_space_length(vext_space, direc);
- break;
- default:
- std::cout << "space_domain_type of electric field is wrong" << std::endl;
- break;
+ ModuleIO::write_td_field_values(*field_manager_, PARAM.globalv.global_out_dir);
}
-
- ModuleBase::timer::end("H_TDDFT_pw", "cal_v_space");
- return;
+ ModuleBase::timer::end("H_TDDFT_pw", "cal_fixed_v");
}
-void H_TDDFT_pw::cal_v_space_length(std::vector& vext_space, int direc)
+void H_TDDFT_pw::cal_v_space_length(std::vector& vext_space, const int direction)
{
ModuleBase::TITLE("H_TDDFT_pw", "cal_v_space_length");
ModuleBase::timer::start("H_TDDFT_pw", "cal_v_space_length");
for (int ir = 0; ir < this->rho_basis_->nrxx; ++ir)
{
- int i = ir / (this->rho_basis_->ny * this->rho_basis_->nplane);
- int j = ir / this->rho_basis_->nplane - i * this->rho_basis_->ny;
- int k = ir % this->rho_basis_->nplane + this->rho_basis_->startz_current;
- double x = (double)i / this->rho_basis_->nx;
- double y = (double)j / this->rho_basis_->ny;
- double z = (double)k / this->rho_basis_->nz;
+ const int i = ir / (this->rho_basis_->ny * this->rho_basis_->nplane);
+ const int j = ir / this->rho_basis_->nplane - i * this->rho_basis_->ny;
+ const int k = ir % this->rho_basis_->nplane + this->rho_basis_->startz_current;
+ const double x = static_cast(i) / this->rho_basis_->nx;
+ const double y = static_cast(j) / this->rho_basis_->ny;
+ const double z = static_cast(k) / this->rho_basis_->nz;
- switch (direc)
+ if (direction == 1)
{
- case 1:
vext_space[ir] = cal_v_space_length_potential(x) * this->ucell_->latvec.e11
+ cal_v_space_length_potential(y) * this->ucell_->latvec.e21
+ cal_v_space_length_potential(z) * this->ucell_->latvec.e31;
- break;
-
- case 2:
+ }
+ else if (direction == 2)
+ {
vext_space[ir] = cal_v_space_length_potential(x) * this->ucell_->latvec.e12
+ cal_v_space_length_potential(y) * this->ucell_->latvec.e22
+ cal_v_space_length_potential(z) * this->ucell_->latvec.e32;
- break;
-
- case 3:
+ }
+ else
+ {
vext_space[ir] = cal_v_space_length_potential(x) * this->ucell_->latvec.e13
+ cal_v_space_length_potential(y) * this->ucell_->latvec.e23
+ cal_v_space_length_potential(z) * this->ucell_->latvec.e33;
- break;
-
- default:
- std::cout << "direction of electric field is wrong" << std::endl;
- break;
}
}
ModuleBase::timer::end("H_TDDFT_pw", "cal_v_space_length");
- return;
}
-double H_TDDFT_pw::cal_v_space_length_potential(double i)
+double H_TDDFT_pw::cal_v_space_length_potential(const double coordinate) const
{
- double vext_space = 0.0;
- if (i < lcut1)
+ const double lower_cut = field_manager_->length_cut1();
+ const double upper_cut = field_manager_->length_cut2();
+ if (coordinate < lower_cut)
{
- vext_space = -((i - lcut1) * (lcut2 - lcut1) / (lcut1 + 1.0 - lcut2) - lcut1) * this->ucell_->lat0;
+ return -((coordinate - lower_cut) * (upper_cut - lower_cut) / (lower_cut + 1.0 - upper_cut) - lower_cut) * this->ucell_->lat0;
}
- else if (i >= lcut1 && i < lcut2)
+ if (coordinate < upper_cut)
{
- vext_space = i * this->ucell_->lat0;
+ return coordinate * this->ucell_->lat0;
}
- else if (i >= lcut2)
- {
- vext_space = -((i - lcut2) * (lcut2 - lcut1) / (lcut1 + 1.0 - lcut2) - lcut2) * this->ucell_->lat0;
- }
- return vext_space;
-}
-
-int H_TDDFT_pw::check_ncut(int t_type)
-{
- int ncut = 0;
- switch (t_type)
- {
- case 0:
- ncut = *(gauss_ncut.begin() + gauss_count);
- break;
-
- case 1:
- ncut = *(trape_ncut.begin() + trape_count);
- break;
-
- case 2:
- ncut = *(trigo_ncut.begin() + trigo_count);
- break;
-
- case 3:
- ncut = 2;
- break;
-
- default:
- std::cout << "time_domain_type of electric field is wrong" << std::endl;
- break;
- }
- return ncut;
-}
-
-void H_TDDFT_pw::update_At()
-{
- // time evolve
- H_TDDFT_pw::istep++;
- // midpoint rule should be used both in Hamiltonian and here.
- At = At + At_laststep / 2.0;
- At_laststep.set(0.0, 0.0, 0.0);
- Et.set(0.0, 0.0, 0.0);
- global_vext_time = { 0.0, 0.0, 0.0 };
-
- // judgement to skip vext
- if (!PARAM.inp.td_vext || istep > tend || istep < tstart)
- {
- return;
- }
-
- ModuleBase::timer::start("H_TDDFT_pw", "update_At");
-
- int count = 0;
- gauss_count = 0;
- trape_count = 0;
- trigo_count = 0;
- heavi_count = 0;
- // parameters for integral
- int ncut = 1;
- bool last = false;
- double out = 0.0;
-
- for (auto direc: PARAM.inp.td_vext_dire)
- {
- last = false;
- // cut the integral space and initialize relevant parameters
- ncut = check_ncut(ttype[count]);
- istep_int = istep * ncut;
- dt_int = dt / double(ncut);
-
- // store vext_time for each time point, include the first and last point
- std::vector vext_time(ncut + 1, 0.0); // Use std::vector to manage memory
- for (int i = 0; i <= ncut; i++)
- {
- // if this is the last point, type_count++
- if (i == ncut)
- {
- last = true;
- }
- vext_time[i] = cal_v_time(ttype[count], last);
- istep_int++;
- }
- // Call the Simpson's rule integration using std::vector data
- ModuleBase::Integral::Simpson_Integral(ncut + 1, vext_time.data(), dt_int, out);
-
- // update At value for its direction
- switch (stype)
- {
- case 1:
- At_laststep[direc - 1] -= out;
- break;
- case 2:
- At_laststep[direc - 1] -= out;
- Et[direc - 1] += vext_time[0];
- break;
- default:
- std::cout << "space_domain_type of electric field is wrong" << std::endl;
- break;
- }
-
- // output Efield
- if (PARAM.inp.out_efield && GlobalV::MY_RANK == 0)
- {
- std::stringstream as;
- as << PARAM.globalv.global_out_dir << "efield_" << count << ".txt";
- std::ofstream ofs(as.str().c_str(), std::ofstream::app);
- ofs << H_TDDFT_pw::istep * dt * ModuleBase::AU_to_FS << "\t"
- << vext_time[0] * ModuleBase::Ry_to_eV / ModuleBase::BOHR_TO_A << std::endl;
- ofs.close();
- }
- // total count++
- count++;
- }
- At = At + At_laststep / 2.0;
- if(stype==2)global_vext_time = { Et[0],Et[1],Et[2] };
-
- ModuleBase::timer::end("H_TDDFT_pw", "update_At");
- return;
-}
-
-double H_TDDFT_pw::cal_v_time(int t_type, const bool last)
-{
- double vext_time = 0.0;
-
- switch (t_type)
- {
- case 0:
- vext_time = cal_v_time_Gauss(last);
- break;
-
- case 1:
- vext_time = cal_v_time_trapezoid(last);
- break;
-
- case 2:
- vext_time = cal_v_time_trigonometric(last);
- break;
-
- case 3:
- vext_time = cal_v_time_heaviside(last);
- break;
-
- default:
- std::cout << "time_domain_type of electric field is wrong" << std::endl;
- break;
- }
- return vext_time;
-}
-
-double H_TDDFT_pw::cal_v_time_Gauss(const bool last)
-{
- double vext_time = 0.0;
- double t0 = *(gauss_t0.begin() + gauss_count);
- double omega = *(gauss_omega.begin() + gauss_count);
- double sigma = *(gauss_sigma.begin() + gauss_count);
- double phase = *(gauss_phase.begin() + gauss_count);
- double amp = *(gauss_amp.begin() + gauss_count);
- double ncut = *(gauss_ncut.begin() + gauss_count);
-
- double gauss_t = (istep_int - t0 * ncut) * dt_int;
- vext_time = cos(omega * gauss_t + phase) * exp(-gauss_t * gauss_t * 0.5 / (sigma * sigma)) * amp;
- if (last)
- {
- gauss_count++;
- }
-
- return vext_time;
-}
-
-double H_TDDFT_pw::cal_v_time_trapezoid(const bool last)
-{
- double vext_time = 0.0;
- double t1 = *(trape_t1.begin() + trape_count);
- double t2 = *(trape_t2.begin() + trape_count);
- double t3 = *(trape_t3.begin() + trape_count);
- double omega = *(trape_omega.begin() + trape_count);
- double phase = *(trape_phase.begin() + trape_count);
- double amp = *(trape_amp.begin() + trape_count);
- double ncut = *(trape_ncut.begin() + trape_count);
-
- if (istep < t1)
- {
- vext_time = istep_int / ncut / t1;
- }
- else if (istep < t2)
- {
- vext_time = 1.0;
- }
- else if (istep < t3)
- {
- vext_time = (t3 - istep_int / ncut) / (t3 - t2);
- }
-
- vext_time = vext_time * amp * cos(omega * istep_int * dt_int + phase);
- if (last)
- {
- trape_count++;
- }
-
- return vext_time;
-}
-
-double H_TDDFT_pw::cal_v_time_trigonometric(const bool last)
-{
- double vext_time = 0.0;
- double omega1 = *(trigo_omega1.begin() + trigo_count);
- double phase1 = *(trigo_phase1.begin() + trigo_count);
- double omega2 = *(trigo_omega2.begin() + trigo_count);
- double phase2 = *(trigo_phase2.begin() + trigo_count);
- double amp = *(trigo_amp.begin() + trigo_count);
-
- const double timenow = istep_int * dt_int;
-
- vext_time = amp * cos(omega1 * timenow + phase1) * sin(omega2 * timenow + phase2) * sin(omega2 * timenow + phase2);
- if (last)
- {
- trigo_count++;
- }
-
- return vext_time;
-}
-
-double H_TDDFT_pw::cal_v_time_heaviside(const bool last)
-{
- double t0 = *(heavi_t0.begin() + heavi_count);
- double amp = *(heavi_amp.begin() + heavi_count);
- double vext_time = 0.0;
- if (istep < t0)
- {
- vext_time = amp;
- }
- else if (istep >= t0)
- {
- vext_time = 0.0;
- }
- if (last)
- {
- heavi_count++;
- }
-
- return vext_time;
+ return -((coordinate - upper_cut) * (upper_cut - lower_cut) / (lower_cut + 1.0 - upper_cut) - upper_cut) * this->ucell_->lat0;
}
-void H_TDDFT_pw::compute_force(const UnitCell& cell, ModuleBase::matrix& fe)
+void H_TDDFT_pw::compute_force(const UnitCell& cell, ModuleBase::matrix& force)
{
- int iat = 0;
- for (int it = 0; it < cell.ntype; ++it)
+ int atom_index = 0;
+ for (int type = 0; type < cell.ntype; ++type)
{
- for (int ia = 0; ia < cell.atoms[it].na; ++ia)
+ for (int atom = 0; atom < cell.atoms[type].na; ++atom)
{
- for (int direc = 0; direc < 3; ++direc)
+ for (int direction = 0; direction < 3; ++direction)
{
- // No need to multiply ModuleBase::e2, since the unit of force is Ry/Bohr
- fe(iat, direc) = global_vext_time[direc] * cell.atoms[it].ncpp.zv;
+ force(atom_index, direction) = global_vext_time[direction] * cell.atoms[type].ncpp.zv;
}
- ++iat;
+ ++atom_index;
}
}
}
diff --git a/source/source_estate/module_pot/H_TDDFT_pw.h b/source/source_estate/module_pot/H_TDDFT_pw.h
index 38463b2a95..b609bcfc31 100644
--- a/source/source_estate/module_pot/H_TDDFT_pw.h
+++ b/source/source_estate/module_pot/H_TDDFT_pw.h
@@ -2,147 +2,82 @@
#define H_TDDFT_PW_H
#include "pot_base.h"
-#include "source_io/module_parameter/parameter.h"
+#include "source_base/vector3.h"
+#include
#include
namespace elecstate
{
+class TDFieldManager;
+
+/**
+ * @brief Length-gauge RT-TDDFT potential backed by TDFieldManager.
+ *
+ * The class consumes the manager's current field samples to construct the
+ * periodic real-space potential. Static members are retained only as mirrors
+ * for legacy propagation, current, force, and restart interfaces.
+ */
class H_TDDFT_pw : public PotBase
{
public:
- H_TDDFT_pw(const ModulePW::PW_Basis* rho_basis_in, const UnitCell* ucell_in) : ucell_(ucell_in)
+ /**
+ * @brief Construct the time-dependent potential component.
+ *
+ * @param rho_basis_in Real-space grid on which the potential is evaluated.
+ * @param ucell_in Unit cell defining Cartesian coordinates and lattice size.
+ * @param field_manager Shared source of RT-TDDFT field state.
+ */
+ H_TDDFT_pw(const ModulePW::PW_Basis* rho_basis_in, const UnitCell* ucell_in, const std::shared_ptr& field_manager);
+
+ /** @brief Destroy the time-dependent potential component. */
+ ~H_TDDFT_pw()
{
- this->dynamic_mode = false;
- this->fixed_mode = true;
-
- this->rho_basis_ = rho_basis_in;
-
- // If it is the first time to create an H_TDDFT_pw instance and is restart calculation,
- // initialize istep using current_step_info
- if (!is_initialized && PARAM.inp.mdp.md_restart)
- {
- int restart_istep = -1;
- std::string file_dir = PARAM.globalv.global_readin_dir;
- current_step_info(file_dir, restart_istep);
-
- if (restart_istep >= 0)
- {
- H_TDDFT_pw::istep = restart_istep - 1; // Update istep
- }
-
- is_initialized = true; // Mark as initialized, so that istep will not be initialized again
- }
}
- ~H_TDDFT_pw() {};
-
+ /**
+ * @brief Add the current length-gauge external potential to the fixed part.
+ *
+ * @param vl_pseudo Real-space fixed potential updated in place.
+ */
void cal_fixed_v(double* vl_pseudo) override;
/**
- * @brief Compute ionic force of electric field
+ * @brief Synchronize legacy static mirrors with the field manager state.
*
- * @param[in] cell Information of cell
- * @param[out] fe Force of electric field F = qE
+ * @param manager Active RT-TDDFT field manager.
*/
- static void compute_force(const UnitCell& cell, ModuleBase::matrix& fe);
-
- // parameters
- static int stype; // 0: length gauge; 1: velocity gauge; 2: hybrid gauge
-
- static std::vector ttype;
- // 0: Gaussian type function.
- // 1: Trapezoid type function.
- // 2: Trigonometric functions, sin^2.
- // 3: Heaviside step function.
-
- static int tstart;
- static int tend;
- static double dt;
- // cut dt for integral
- static double dt_int;
- static int istep_int;
+ static void sync_compatibility_state(const TDFieldManager& manager);
- // Space domain parameters
+ /**
+ * @brief Compute ionic force of electric field.
+ *
+ * @param[in] cell Information of cell.
+ * @param[out] fe Electric-field force, F = qE.
+ */
+ static void compute_force(const UnitCell& cell, ModuleBase::matrix& fe);
- // length gauge
- static double lcut1;
- static double lcut2;
+ /** @brief Legacy mirror of the spatial-gauge selector. */
+ static int stype;
- // velocity gauge, vector potential
+ /** @brief Legacy mirror of the midpoint vector potential. */
static ModuleBase::Vector3 At;
+
+ /** @brief Legacy mirror of the current vector-potential increment. */
static ModuleBase::Vector3 At_laststep;
- static ModuleBase::Vector3 Et;
- // Time domain parameters
-
- // Gauss
- static int gauss_count;
- static std::vector gauss_omega; // time(a.u.)^-1
- static std::vector gauss_phase;
- static std::vector gauss_sigma; // time(a.u.)
- static std::vector gauss_t0;
- static std::vector gauss_amp; // Ry/bohr
- // add for velocity gauge, recut dt into n pieces to make sure the integral is accurate enough
- // must be even, thus would get odd number of points for Simpson integral
- static std::vector gauss_ncut;
-
- // Trapezoid
- static int trape_count;
- static std::vector trape_omega; // time(a.u.)^-1
- static std::vector trape_phase;
- static std::vector trape_t1;
- static std::vector trape_t2;
- static std::vector trape_t3;
- static std::vector trape_amp; // Ry/bohr
- // add for velocity gauge, recut dt into n pieces to make sure the integral is accurate enough
- static std::vector trape_ncut;
-
- // Trigonometric
- static int trigo_count;
- static std::vector trigo_omega1; // time(a.u.)^-1
- static std::vector trigo_omega2; // time(a.u.)^-1
- static std::vector trigo_phase1;
- static std::vector trigo_phase2;
- static std::vector trigo_amp; // Ry/bohr
- // add for velocity gauge, recut dt into n pieces to make sure the integral is accurate enough
- static std::vector trigo_ncut;
-
- // Heaviside
- static int heavi_count;
- static std::vector heavi_t0;
- static std::vector heavi_amp; // Ry/bohr
-
- // update At for velocity gauge by intergral of E(t)dt
- static void update_At();
+ /** @brief Legacy mirror of the instantaneous hybrid-gauge field. */
+ static ModuleBase::Vector3 Et;
private:
- static int istep;
- static bool is_initialized; // static flag variable, used to ensure initialization only once
-
- static double amp;
static std::vector global_vext_time;
- const UnitCell* ucell_ = nullptr;
-
- // Obtain the current MD step information, used for restart calculation
- void current_step_info(const std::string& file_dir, int& istep);
+ void cal_v_space_length(std::vector& vext_space, int direction);
+ double cal_v_space_length_potential(double coordinate) const;
- // Potential of electric field in space domain: for length gauge only
- void cal_v_space(std::vector& vext_space, int direc);
- void cal_v_space_length(std::vector& vext_space, int direc);
- double cal_v_space_length_potential(double i);
-
- // Potential of electric field in time domain: Gaussian, trapezoid, trigonometric, Heaviside
- static double cal_v_time(int t_type, const bool last);
- static double cal_v_time_Gauss(const bool last);
- static double cal_v_time_trapezoid(const bool last);
- static double cal_v_time_trigonometric(const bool last);
- static double cal_v_time_heaviside(const bool last);
-
- // Get ncut number for At integral
- static int check_ncut(int t_type);
+ const UnitCell* ucell_ = nullptr;
+ std::shared_ptr field_manager_;
};
} // namespace elecstate
diff --git a/source/source_estate/module_pot/potential_new.cpp b/source/source_estate/module_pot/potential_new.cpp
index 70b35cdf00..150dfe893a 100644
--- a/source/source_estate/module_pot/potential_new.cpp
+++ b/source/source_estate/module_pot/potential_new.cpp
@@ -1,5 +1,6 @@
#include "potential_new.h"
+#include "pot_ml_exx.h"
#include "source_base/global_function.h"
#include "source_base/global_variable.h"
#include "source_base/memory_recorder.h"
@@ -8,7 +9,6 @@
#include "source_base/tool_title.h"
#include "source_hamilt/module_xc/xc_functional.h"
#include "source_io/module_parameter/parameter.h"
-#include "pot_ml_exx.h"
#include