ampsci
High-precision calculations for one- and two-valence atomic systems
DiracOperator::TensorOperatorabstract

ok

General tensor operator (virtual base class); all single-particle (one-body) tenosor operators derive from this.

Represents a single-particle (one-body) tensor operator \( \hat{h} \) of rank- \( k \) and parity \( \pi \), thats acts on Dirac spinors. The core quantity is the reduced matrix element (RME):

\[ \langle a \| \hat{h} \| b \rangle \equiv A_{ab} \cdot R_{ab} \]

where \( A_{ab} \) is the angular factor (see angularF()) and \( R_{ab} \) is the radial integral (see radialIntegral()).

The default radial integral is:

\[ R_{ab} = c \int_0^\infty v(r)\left( C_{ff}\,f_a f_b + C_{fg}\,f_a g_b + C_{gf}\,g_a f_b + C_{gg}\,g_a g_b \right)\,{\rm d}r \]

where \( c \) is an overall multiplicative constant (1 by default), \( v(r) \) is an optional radial function (stored in m_vec), and the \( C_{xy} \) are angular coefficients returned by angularCff() etc.

  • Operators must be spherical tensor operators of defined rank and parity
  • Operators must have pure real, or pure imaginary matrix elements
  • If matrix elements are imaginary, class returns the imaginary part
  • For operators with imaginary matrix elements, the Realness member variable (m_Realness) must be set to Realness::imaginary via the virtual base class constructor TensorOperator() (impacts symmetry)
  • (For brevity, we may refer to operators whose matrix elements are imaginary as 'imaginary operators'. This is sometimes confusing.)

Implementing a derived operator

TensorOperator is a virtual base class and cannot be constructed directly.

Note
All derived operators must implement angularF()

Beyond that, there are two levels of customisation:

Standard case – override angular factors only:

Implement angularF() (required), and optionally angularCff(), angularCgg(), angularCfg(), angularCgf(). The radial integral is then handled automatically by the default radial_rhs() and radialIntegral(). The \( v(r) \) radial function, and overall constant \( c \) are set within the constructor TensorOperator::TensorOperator(), which should be called by any deriving class. Then, the default radial integral as above will be used.

Non-standard case – override the radial functions:

If the radial integral cannot be expressed in the above standard/default form (e.g., it involves derivatives, non-local terms, or more complicated radial structure), you shuold override radial_rhs() and radialIntegral() directly. In that case both should be consistent with each other:

  • radial_rhs(ka, Fb) returns the spinor \( \delta F_b \) such that

    \[ F_a \cdot \delta F_b = R_{ab} \]

  • radialIntegral(Fa, Fb) returns \( R_{ab} \) directly
  • Generally, this should be directly checked with a unit test
Note
  • If radialIntegral() is overridden then radial_rhs() must be overridden (and vice versa), or results will be inconsistent. It's OK (but inefficient) to define radialIntegral(a,b) = a*radial_rhs(b). But that is not the default.
Warning
  • Frequency-dependent operators: if the operator depends on the transition frequency, or energy/momentum transfer, (e.g., dynamic multipole operators), pass freq_dep=true to the constructor and override updateFrequency(). This function must be called with the current frequency before computing any matrix elements. Failing to override it will abort at runtime.
Note
  • You may not construct a TensorOperator directly. Construct one of the derived classes; see Operators/include.hpp for the list.

Note
  • To expose a new operator at runtime (e.g., via ampsci -o), add it to the operator_list in GenerateOperator.hpp and provide a corresponding generate_XYZ() factory function.

#include <TensorOperator.hpp>

+ Inheritance diagram for DiracOperator::TensorOperator:

Classes

struct  Params
 Used to pass generic parameters to update() function. More...
 

Public Member Functions

 TensorOperator (const TensorOperator &)=default
 
TensorOperatoroperator= (const TensorOperator &)=default
 
 TensorOperator (TensorOperator &&)=default
 
TensorOperatoroperator= (TensorOperator &&)=default
 
bool freqDependantQ () const
 Returns true if the operator is frequency-dependent (requires updateFrequency() calls).
 
bool isZero (int ka, int kb) const
 Returns true if <a|h|b> = 0 by rank/parity selection rules.
 
bool isZero (const DiracSpinor &Fa, const DiracSpinor &Fb) const
 Overload taking DiracSpinors; forwards to isZero(ka, kb).
 
bool selectrion_rule (int twoJA, int piA, int twoJB, int piB) const
 Returns true if the matrix element is non-zero by angular momentum and parity selection rules (arguments are 2j and pi as integers).
 
virtual void updateFrequency (const double)
 Updates the operator for a new frequency omega.
 
virtual void updateRank (int)
 
const std::vector< double > & getv () const
 Returns a const ref to the stored vector v.
 
double getc () const
 Returns the "overall" constant c.
 
bool imaginaryQ () const
 returns true if operator is imaginary (has imag MEs)
 
int rank () const
 Rank k of operator.
 
int parity () const
 returns parity, as integer (+1 or -1)
 
int symm_sign (const DiracSpinor &Fa, const DiracSpinor &Fb) const
 returns relative sign between <a||x||b> and <b||x||a>
 
virtual std::string name () const
 Returns "name" of operator (e.g., 'E1')
 
virtual std::string units () const
 Returns units of operator as a string (usually au, may be MHz, etc.)
 
virtual double angularCff (int kappa_a, int kappa_b) const
 Angular coefficient C_ff for the f_a*f_b term of the radial integral.
 
virtual double angularCgg (int, int) const
 Angular coefficient C_gg for the g_a*g_b term of the radial integral.
 
virtual double angularCfg (int, int) const
 Angular coefficient C_fg for the f_a*g_b term of the radial integral.
 
virtual double angularCgf (int, int) const
 Angular coefficient C_gf for the g_a*f_b term of the radial integral.
 
double angularCxy (uint8_t x, uint8_t y, int kappa_a, int kappa_b) const
 Dispatches to angularCff/fg/gf/gg based on component indices x, y.
 
virtual double angularF (const int, const int) const =0
 Angular factor A_ab linking the radial integral to the RME.
 
virtual std::unique_ptr< TensorOperatorclone () const
 Returns a polymorphic copy of the operator at its current state, or nullptr if cloning is not supported by the derived class.
 
virtual DiracSpinor radial_rhs (const int kappa_a, const DiracSpinor &Fb) const
 Computes the right-hand spinor dF_b for the radial integral.
 
virtual double radialIntegral (const DiracSpinor &Fa, const DiracSpinor &Fb) const
 Radial integral R_ab, defined by RME = angularF(a,b) * radialIntegral(a,b).
 
double rme3js (int twoja, int twojb, int two_mb=1, int two_q=0) const
 3j-symbol factor linking the full ME to the RME.
 
double rme3js (const DiracSpinor &Fa, const DiracSpinor &Fb, int two_mb=1, int two_q=0) const
 Overload of rme3js taking DiracSpinors.
 
DiracSpinor reduced_rhs (const int ka, const DiracSpinor &Fb) const
 Returns angularF(ka,kb) * radial_rhs(ka,Fb); spinor-valued RME action on Fb, used in perturbation theory/TDHF.
 
DiracSpinor reduced_lhs (const int ka, const DiracSpinor &Fb) const
 As reduced_rhs but for the conjugate direction; Fb * reduced_lhs(ka, Fb) = <b||h||a>.
 
double reducedME (const DiracSpinor &Fa, const DiracSpinor &Fb) const
 Returns the reduced matrix element <a||h||b> = A_ab * R_ab.
 
double fullME (const DiracSpinor &Fa, const DiracSpinor &Fb, std::optional< int > two_ma=std::nullopt, std::optional< int > two_mb=std::nullopt, std::optional< int > two_q=std::nullopt) const
 Returns "full" matrix element, for optional (ma, mb, q) [taken as int 2*]. If not specified, returns z-component (q=0), with ma=mb=min(ja,jb)
 
double matel_factor (MatrixElementType type, int twoJa, int twoJb) const
 Returns the factor to convert a reduced ME to a different form (Reduced, Stretched, or HFConstant); see MatrixElementType.
 
double matel_factor (MatrixElementType type, const DiracSpinor &Fa, const DiracSpinor &Fb) const
 Overload of matel_factor taking DiracSpinors.
 

Protected Member Functions

 TensorOperator (int rank_k, Parity pi, double constant=1.0, const std::vector< double > &vec={}, Realness RorI=Realness::real, bool freq_dep=false)
 Constructs a specific tensor operator. Called by derived classes.
 

Protected Attributes

int m_rank
 
Parity m_parity
 
Realness m_Realness
 
bool m_freqDependantQ {false}
 
double m_constant
 
std::vector< double > m_vec
 

Constructor & Destructor Documentation

◆ TensorOperator()

DiracOperator::TensorOperator::TensorOperator ( int  rank_k,
Parity  pi,
double  constant = 1.0,
const std::vector< double > &  vec = {},
Realness  RorI = Realness::real,
bool  freq_dep = false 
)
inlineprotected

Constructs a specific tensor operator. Called by derived classes.

Initialises the basic properties of a tensor operator.

Parameters
rank_kTensor rank k of the operator.
piParity of the operator (Parity::even or Parity::odd).
constantMultiplicative constant c, included in the radial integral.
vecOverall v=f(r) radial function, as std::vector. May be impty, in which case it is not used (equivilant to vector of 1)
RorISpecifies whether the matrix element is real or imaginary (Realness::real or Realness::imaginary).
freq_depIndicates whether the operator depends on frequency (e.g., dynamic external fields).
Note
TensorOperator is a virtual base class and may not be constructed directly. It is intended to be initialised by derived operator classes.

Member Function Documentation

◆ freqDependantQ()

bool DiracOperator::TensorOperator::freqDependantQ ( ) const
inline

Returns true if the operator is frequency-dependent (requires updateFrequency() calls).

◆ isZero() [1/2]

bool DiracOperator::TensorOperator::isZero ( int  ka,
int  kb 
) const

Returns true if <a|h|b> = 0 by rank/parity selection rules.

◆ isZero() [2/2]

bool DiracOperator::TensorOperator::isZero ( const DiracSpinor Fa,
const DiracSpinor Fb 
) const

Overload taking DiracSpinors; forwards to isZero(ka, kb).

◆ selectrion_rule()

bool DiracOperator::TensorOperator::selectrion_rule ( int  twoJA,
int  piA,
int  twoJB,
int  piB 
) const
inline

Returns true if the matrix element is non-zero by angular momentum and parity selection rules (arguments are 2j and pi as integers).

◆ updateFrequency()

virtual void DiracOperator::TensorOperator::updateFrequency ( const double  )
inlinevirtual

Updates the operator for a new frequency omega.

Must be overridden by any frequency-dependent operator (i.e., where freqDependantQ() returns true). Called before computing matrix elements whenever the frequency changes.

The base class implementation aborts – if a frequency-dependent operator is constructed but this function is not overridden, it will abort at runtime when called.

Parameters
omegaFrequency in atomic units.
Warning
Must be implemented in any derived class that sets freq_dep=true. Calling this on a non-frequency-dependent operator is a logic error.

Reimplemented in DiracOperator::VEk_Len, DiracOperator::VEk, DiracOperator::VLk, DiracOperator::VMk, DiracOperator::Phik, DiracOperator::Sk, DiracOperator::AEk, DiracOperator::ALk, DiracOperator::AMk, DiracOperator::Phi5k, DiracOperator::S5k, DiracOperator::VMk_lowq, DiracOperator::Phik_lowq, DiracOperator::Sk_lowq, DiracOperator::AEk_lowq, DiracOperator::ALk_lowq, DiracOperator::AMk_lowq, DiracOperator::Phi5k_lowq, DiracOperator::S5k_lowq, DiracOperator::M1, DiracOperator::VEk_lowq, and DiracOperator::VLk_lowq.

◆ updateRank()

virtual void DiracOperator::TensorOperator::updateRank ( int  )
inlinevirtual

Updates the rank of operator (rarely used). Generally also updates parity

Use with caution.

Warning
Will usually have to call updateFrequency() after this! Updating rank often breaks frequency-dependence of radial functions (e.g., spherical Bessel functions)

Reimplemented in DiracOperator::EM_multipole.

◆ getv()

const std::vector< double > & DiracOperator::TensorOperator::getv ( ) const
inline

Returns a const ref to the stored vector v.

◆ getc()

double DiracOperator::TensorOperator::getc ( ) const
inline

Returns the "overall" constant c.

◆ imaginaryQ()

bool DiracOperator::TensorOperator::imaginaryQ ( ) const
inline

returns true if operator is imaginary (has imag MEs)

◆ rank()

int DiracOperator::TensorOperator::rank ( ) const
inline

Rank k of operator.

◆ parity()

int DiracOperator::TensorOperator::parity ( ) const
inline

returns parity, as integer (+1 or -1)

◆ symm_sign()

int DiracOperator::TensorOperator::symm_sign ( const DiracSpinor Fa,
const DiracSpinor Fb 
) const
inline

returns relative sign between <a||x||b> and <b||x||a>

◆ name()

◆ units()

◆ angularCff()

virtual double DiracOperator::TensorOperator::angularCff ( int  kappa_a,
int  kappa_b 
) const
inlinevirtual

Angular coefficient C_ff for the f_a*f_b term of the radial integral.

The default radial integral is structured as:

\[ R_{ab} = c\int_0^\infty v(r)\left( C_{ff}\,f_a f_b + C_{fg}\,f_a g_b + C_{gf}\,g_a f_b + C_{gg}\,g_a g_b \right)\,{\rm d}r \]

These coefficients are often constants, but may depend on \( \kappa_a, \kappa_b \) for operators with angular-momentum-dependent coupling between large and small components (e.g., spin-dependent operators). Override in derived classes as needed.

Parameters
kappa_akappa \( \kappa_a \) for left-hand-side (bra)
kappa_bkappa \( \kappa_b \) for right-hand-side (ket)
Note
Only relevant when using the default radial_rhs()/radialIntegral(). If those are overridden, these are not called.

Reimplemented in DiracOperator::VertexQED, DiracOperator::MLVP, DiracOperator::jL, DiracOperator::ig0g5jL, DiracOperator::ScalarOperator, DiracOperator::E1v, DiracOperator::VEk_lowq, DiracOperator::VMk_lowq, DiracOperator::VLk_lowq, DiracOperator::hfs, DiracOperator::g0jL, DiracOperator::ig5jL, DiracOperator::M1, DiracOperator::p, and DiracOperator::NullOperator.

◆ angularCgg()

virtual double DiracOperator::TensorOperator::angularCgg ( int  ,
int   
) const
inlinevirtual

◆ angularCfg()

virtual double DiracOperator::TensorOperator::angularCfg ( int  ,
int   
) const
inlinevirtual

◆ angularCgf()

virtual double DiracOperator::TensorOperator::angularCgf ( int  ,
int   
) const
inlinevirtual

◆ angularCxy()

double DiracOperator::TensorOperator::angularCxy ( uint8_t  x,
uint8_t  y,
int  kappa_a,
int  kappa_b 
) const
inline

Dispatches to angularCff/fg/gf/gg based on component indices x, y.

Convenience dispatcher: x and y index the spinor component (0 = large/f, 1 = small/g) of the bra and ket respectively, and returns the corresponding angular coefficient C_xy(ka, kb).

See angularCff()

x y returns
0 0 angularCff()
0 1 angularCfg()
1 0 angularCgf()
1 1 angularCgg()
Parameters
xBra component index: 0=f (large), 1=g (small).
yKet component index: 0=f (large), 1=g (small).
kappa_akappa \( \kappa_a \) for left-hand-side (bra)
kappa_bkappa \( \kappa_b \) for right-hand-side (ket)
Note
Only relevant when using the default radial_rhs()/radialIntegral(). If those are overridden, these are not called.

◆ angularF()

virtual double DiracOperator::TensorOperator::angularF ( const int  ,
const int   
) const
pure virtual

Angular factor A_ab linking the radial integral to the RME.

All derived operators must implement this. It gives the purely angular part of the reduced matrix element:

\[ \langle a \| \hat{h} \| b \rangle \equiv A_{ab} \cdot R_{ab} \]

where \( R_{ab} \) is returned by radialIntegral(). For most operators, \( A_{ab} \) is a product of Clebsch-Gordan / 3j coefficients and depends only on \( \kappa_a, \kappa_b \) (and the rank \( k \) and parity \( \pi \) of the operator).

Note
This is a pure virtual function – every derived operator must provide an implementation.

Implemented in DiracOperator::EM_multipole, DiracOperator::jL, DiracOperator::ig0g5jL, DiracOperator::ScalarOperator, DiracOperator::Ek, DiracOperator::E1v, DiracOperator::VMk_lowq, DiracOperator::hfs, DiracOperator::ig5jL, DiracOperator::j, DiracOperator::l, DiracOperator::s, DiracOperator::M1, DiracOperator::p, DiracOperator::VertexQED, DiracOperator::MLVP, and DiracOperator::M1nr.

◆ clone()

virtual std::unique_ptr< TensorOperator > DiracOperator::TensorOperator::clone ( ) const
inlinevirtual

Returns a polymorphic copy of the operator at its current state, or nullptr if cloning is not supported by the derived class.

Reimplemented in DiracOperator::EM_multipole.

◆ radial_rhs()

DiracSpinor DiracOperator::TensorOperator::radial_rhs ( const int  kappa_a,
const DiracSpinor Fb 
) const
virtual

Computes the right-hand spinor dF_b for the radial integral.

Returns \( \delta F_b \) such that the radial integral satisfies:

\[ R_{ab} = F_a \cdot \delta F_b = \int_0^\infty \left(f_a\,\delta f_b + g_a\,\delta g_b\right)\,{\rm d}r \]

The default implementation constructs \( \delta F_b \) using the stored radial function \( v(r) \) and the angular coefficients:

\[ \delta F_b(r) = c\,v(r) \begin{pmatrix} C_{ff}\,f_b(r) + C_{fg}\,g_b(r) \\ C_{gf}\,f_b(r) + C_{gg}\,g_b(r) \end{pmatrix} \]

This is used by reduced_rhs() to build \( \langle a \| \hat{h} \| b \rangle \) as a spinor-valued quantity, enabling perturbation theory and TDHF. Override this for operators whose radial structure cannot be expressed in this standard form.

Parameters
kappa_aRelativistic quantum number \( \kappa_a \) of the bra state (needed to evaluate the angular coefficients).
FbKet DiracSpinor \( F_b \) .
Returns
DiracSpinor \( \delta F_b \) .
Warning
If this is overridden, radialIntegral() should also be overridden consistently (and vice versa), so that reducedME() and reduced_rhs() remain consistent.

Reimplemented in DiracOperator::jL, DiracOperator::VEk_Len, DiracOperator::VEk, DiracOperator::VLk, DiracOperator::VMk, DiracOperator::Phik, DiracOperator::Sk, DiracOperator::AEk, DiracOperator::ALk, DiracOperator::AMk, DiracOperator::Phi5k, DiracOperator::S5k, DiracOperator::Phik_lowq, DiracOperator::Sk_lowq, DiracOperator::AEk_lowq, DiracOperator::ALk_lowq, DiracOperator::AMk_lowq, DiracOperator::Phi5k_lowq, DiracOperator::S5k_lowq, DiracOperator::M1nr, DiracOperator::p, and DiracOperator::Vrad.

◆ radialIntegral()

double DiracOperator::TensorOperator::radialIntegral ( const DiracSpinor Fa,
const DiracSpinor Fb 
) const
virtual

Radial integral R_ab, defined by RME = angularF(a,b) * radialIntegral(a,b).

Returns the radial part \( R_{ab} \) of the reduced matrix element:

\[ \langle a \| \hat{h} \| b \rangle = A_{ab} \cdot R_{ab} \]

where \( A_{ab} \) is angularF().

The default implementation evaluates \( R_{ab} = F_a \cdot \delta F_b \) , using the default radial structure:

\[ R_{ab} = c\int_0^\infty v(r)\left( C_{ff}\,f_a f_b + C_{fg}\,f_a g_b + C_{gf}\,g_a f_b + C_{gg}\,g_a g_b \right)\,{\rm d}r \]

Override this for operators that do not fit this standard form. If radial_rhs() is also overridden, both must remain mutually consistent.

Warning
If radial_rhs() is overridden but radialIntegral() is not (or vice versa), reducedME() and reduced_rhs() will give inconsistent results.

Reimplemented in DiracOperator::VEk_Len, DiracOperator::VEk, DiracOperator::VLk, DiracOperator::VMk, DiracOperator::Phik, DiracOperator::Sk, DiracOperator::AEk, DiracOperator::ALk, DiracOperator::AMk, DiracOperator::Phi5k, DiracOperator::S5k, DiracOperator::Phik_lowq, DiracOperator::Sk_lowq, DiracOperator::AEk_lowq, DiracOperator::ALk_lowq, DiracOperator::AMk_lowq, DiracOperator::Phi5k_lowq, DiracOperator::S5k_lowq, DiracOperator::jL, DiracOperator::M1nr, DiracOperator::p, and DiracOperator::Vrad.

◆ rme3js() [1/2]

double DiracOperator::TensorOperator::rme3js ( int  twoja,
int  twojb,
int  two_mb = 1,
int  two_q = 0 
) const

3j-symbol factor linking the full ME to the RME.

\[ (-1)^{j_a - m_a} \begin{pmatrix} j_a & k & j_b \\ -m_a & q & m_b \end{pmatrix} \]

such that \(\langle a | \hat{h} | b \rangle = {\rm rme3js} \times \langle a \| \hat{h} \| b \rangle\). All arguments are twice the actual value (2*j, 2*m, 2*q).

◆ rme3js() [2/2]

double DiracOperator::TensorOperator::rme3js ( const DiracSpinor Fa,
const DiracSpinor Fb,
int  two_mb = 1,
int  two_q = 0 
) const
inline

Overload of rme3js taking DiracSpinors.

◆ reduced_rhs()

DiracSpinor DiracOperator::TensorOperator::reduced_rhs ( const int  ka,
const DiracSpinor Fb 
) const

Returns angularF(ka,kb) * radial_rhs(ka,Fb); spinor-valued RME action on Fb, used in perturbation theory/TDHF.

◆ reduced_lhs()

DiracSpinor DiracOperator::TensorOperator::reduced_lhs ( const int  ka,
const DiracSpinor Fb 
) const

As reduced_rhs but for the conjugate direction; Fb * reduced_lhs(ka, Fb) = <b||h||a>.

◆ reducedME()

double DiracOperator::TensorOperator::reducedME ( const DiracSpinor Fa,
const DiracSpinor Fb 
) const

Returns the reduced matrix element <a||h||b> = A_ab * R_ab.

◆ fullME()

double DiracOperator::TensorOperator::fullME ( const DiracSpinor Fa,
const DiracSpinor Fb,
std::optional< int >  two_ma = std::nullopt,
std::optional< int >  two_mb = std::nullopt,
std::optional< int >  two_q = std::nullopt 
) const

Returns "full" matrix element, for optional (ma, mb, q) [taken as int 2*]. If not specified, returns z-component (q=0), with ma=mb=min(ja,jb)

◆ matel_factor() [1/2]

double DiracOperator::TensorOperator::matel_factor ( MatrixElementType  type,
int  twoJa,
int  twoJb 
) const

Returns the factor to convert a reduced ME to a different form (Reduced, Stretched, or HFConstant); see MatrixElementType.

◆ matel_factor() [2/2]

double DiracOperator::TensorOperator::matel_factor ( MatrixElementType  type,
const DiracSpinor Fa,
const DiracSpinor Fb 
) const
inline

Overload of matel_factor taking DiracSpinors.


The documentation for this class was generated from the following files: