ampsci
High-precision calculations for one- and two-valence atomic systems
TensorOperator.hpp
1#pragma once
2#include "Angular/Wigner369j.hpp"
3#include "Maths/Grid.hpp"
4#include "Maths/NumCalc_quadIntegrate.hpp"
5#include "Maths/SphericalBessel.hpp"
6#include "Physics/PhysConst_constants.hpp"
7#include "Potentials/NuclearPotentials.hpp"
8#include "Wavefunction/DiracSpinor.hpp"
9#include "qip/Vector.hpp"
10#include <cmath>
11#include <memory>
12#include <string>
13#include <vector>
14
15/*!
16 @brief Dirac operators: TensorOperator base class and derived implementations for single-particle (one-body) spherical tensor operators.
17
18 @details
19 This namespace contains the TensorOperator base class and all derived
20 operator classes. Operators act on DiracSpinor objects and compute reduced
21 matrix elements (RMEs) of the form:
22
23 \f[
24 \langle a \| \hat{h} \| b \rangle = A_{ab} \cdot R_{ab}
25 \f]
26
27 where \f$ A_{ab} \f$ is a purely angular factor and \f$ R_{ab} \f$ is a radial
28 integral. New operators are implemented by deriving from TensorOperator (or
29 ScalarOperator for rank-0 operators) and overriding the relevant virtual
30 functions; see TensorOperator for details.
31
32 Operators are typically constructed via @ref generate(), which takes a name
33 string and an InputBlock; see GenerateOperator.hpp for the full list of
34 available operators.
35
36 See @ref TensorOperator class documentation for main descriptions.
37 All usable tensor operators dervive from that virtual class.
38
39 From the command line, use
40 ```shell
41 ampsci -o
42 ```
43 to get a list of available operators.
44 For a specific operator 'OperatorName', use:
45 ```shell
46 ampsci -o OperatorName
47 ```
48 to see available run-time options for that operator.
49 These options are passed to @ref generate().
50
51 @note New operator classes must be registered in the @ref operator_list in
52 GenerateOperator.hpp to be accessible at runtime.
53*/
54namespace DiracOperator {
55
56//! Parity of operator
57enum class Parity { even, odd, Error };
58
59/*!
60 @brief Specifies whether an operator's matrix elements are real or imaginary.
61 @details
62 Operators must have purely real or purely imaginary reduced matrix elements.
63 For imaginary operators, the imaginary part is computed and stored; the real
64 part is identically zero. This distinction affects the Hermitian symmetry
65 relation \f$ \langle b \| \hat{h} \| a \rangle = \pm \langle a \| \hat{h} \| b \rangle^* \f$
66 and the sign of \f$ \langle b \| \hat{h} \| a \rangle \f$ relative to
67 \f$ \langle a \| \hat{h} \| b \rangle \f$ .
68*/
69enum class Realness { real, imaginary, Error };
70
71//! Type of matrix element returned
72/*! @details
73 Specifies which form of matrix element is used or returned.
74
75 @value Reduced : Reduced matrix element
76 @value Stretched : Matrix element for stretched states (m = j)
77 @value HFConstant : Hyperfine (A,B,C...) constant
78
79 For off-diagonal, j:=min(ja,jb)
80*/
81enum class MatrixElementType { Reduced, Stretched, HFConstant, Error };
82
83//! Convert string to Parity
84Parity parse_Parity(const std::string &s);
85
86//! Convert Parity to string
87std::string parse_Parity(Parity p);
88
89//! Convert string to Realness
90Realness parse_Realness(const std::string &s);
91
92//! Convert Realness to string
93std::string parse_Realness(Realness r);
94
95//! Convert string to MatrixElementType
96MatrixElementType parse_MatrixElementType(const std::string &s);
97
98//! Convert MatrixElementType to string
100
101//==============================================================================
102/*!
103 @brief General tensor operator (virtual base class);
104 all single-particle (one-body) tenosor operators derive from this.
105
106 @details
107
108 Represents a single-particle (one-body) tensor operator
109 \f$ \hat{h} \f$ of rank-\f$ k \f$ and parity \f$ \pi \f$,
110 thats acts on Dirac spinors.
111 The core quantity is the _reduced matrix element_ (RME):
112
113 \f[
114 \langle a \| \hat{h} \| b \rangle \equiv A_{ab} \cdot R_{ab}
115 \f]
116
117 where \f$ A_{ab} \f$ is the angular factor (see angularF()) and \f$ R_{ab} \f$
118 is the radial integral (see radialIntegral()).
119
120 The default radial integral is:
121
122 \f[
123 R_{ab} = c \int_0^\infty v(r)\left(
124 C_{ff}\,f_a f_b + C_{fg}\,f_a g_b +
125 C_{gf}\,g_a f_b + C_{gg}\,g_a g_b
126 \right)\,{\rm d}r
127 \f]
128
129 where \f$ c \f$ is an overall multiplicative constant (1 by default),
130 \f$ v(r) \f$ is an optional radial function (stored in m_vec),
131 and the \f$ C_{xy} \f$ are angular coefficients returned by @ref angularCff() etc.
132
133 - Operators must be spherical tensor operators of defined rank and parity
134 - Operators must have pure real, or pure imaginary matrix elements
135 - If matrix elements are imaginary, class returns the imaginary part
136 - For operators with imaginary matrix elements, the @ref Realness member variable (m_Realness) must be set to Realness::imaginary via the virtual base class constructor @ref TensorOperator() (impacts symmetry)
137 - (For brevity, we may refer to operators whose matrix elements are imaginary as 'imaginary operators'. This is sometimes confusing.)
138
139 ## Implementing a derived operator
140
141 TensorOperator is a virtual base class and cannot be constructed directly.
142
143 @note All derived operators must implement angularF()
144
145 Beyond that, there are two levels of customisation:
146
147 ### Standard case -- override angular factors only:
148
149 Implement angularF() (required), and optionally
150 @ref angularCff(), angularCgg(), angularCfg(), angularCgf().
151 The radial integral is then handled
152 automatically by the default @ref radial_rhs() and @ref radialIntegral().
153 The \f$ v(r) \f$ radial function, and overall constant \f$ c \f$ are set
154 within the constructor @ref TensorOperator::TensorOperator(), which should
155 be called by any deriving class.
156 Then, the default radial integral as above will be used.
157
158 ### Non-standard case -- override the radial functions:
159
160 If the radial integral cannot be expressed in the above standard/default form
161 (e.g., it involves derivatives, non-local terms, or more complicated radial structure),
162 you shuold override radial_rhs() **and** radialIntegral() directly.
163 In that case both should be consistent with each other:
164
165 - radial_rhs(ka, Fb) returns the spinor \f$ \delta F_b \f$ such that
166
167 \f[ F_a \cdot \delta F_b = R_{ab} \f]
168
169 - radialIntegral(Fa, Fb) returns \f$ R_{ab} \f$ directly
170 - Generally, this should be directly checked with a unit test
171
172 @note
173 - If radialIntegral() is overridden then radial_rhs() _must_ be overridden
174 (and vice versa), or results will be inconsistent.
175 It's OK (but inefficient) to define radialIntegral(a,b) = a*radial_rhs(b).
176 But that is not the default.
177
178 @warning
179 - Frequency-dependent operators: if the operator depends on the
180 transition frequency, or energy/momentum transfer,
181 (e.g., dynamic multipole operators), pass
182 freq_dep=true to the constructor and override updateFrequency(). This
183 function must be called with the current frequency before computing
184 any matrix elements. Failing to override it will abort at runtime.
185
186 @note
187 - You may not construct a TensorOperator directly. Construct one of the
188 derived classes; see [Operators/include.hpp](Operators/include.hpp) for the list.
189
190 --
191
192 @note
193 - To expose a new operator at runtime (e.g., via `ampsci -o`), add it to
194 the @ref operator_list in GenerateOperator.hpp and provide a corresponding
195 `generate_XYZ()` factory function.
196*/
198protected:
199 /*!
200 @brief Constructs a specific tensor operator. Called by derived classes.
201 @details
202 Initialises the basic properties of a tensor operator.
203
204 @param rank_k Tensor rank k of the operator.
205 @param pi Parity of the operator (Parity::even or Parity::odd).
206 @param constant Multiplicative constant c, included in the radial integral.
207 @param vec Overall v=f(r) radial function, as std::vector.
208 May be impty, in which case it is not used (equivilant to vector of 1)
209 @param RorI Specifies whether the matrix element is real or imaginary
210 (Realness::real or Realness::imaginary).
211 @param freq_dep Indicates whether the operator depends on frequency
212 (e.g., dynamic external fields).
213
214 @note TensorOperator is a virtual base class and may not be constructed
215 directly. It is intended to be initialised by derived operator classes.
216 */
217 TensorOperator(int rank_k, Parity pi, double constant = 1.0,
218 const std::vector<double> &vec = {},
219 Realness RorI = Realness::real, bool freq_dep = false)
220 : m_rank(rank_k),
221 m_parity(pi),
222 m_Realness(RorI),
223 m_freqDependantQ(freq_dep),
224 m_constant(constant),
225 m_vec(vec) {};
226
227public:
228 //! Used to pass generic parameters to update() function
229 /*! @details
230 Override in derived class, then use as:
231
232 auto const* params = dynamic_cast<const Params*>(&p);
233
234 Rarely used.
235 */
236 struct Params {
237 virtual ~Params() = default;
238 };
239
240public:
241 virtual ~TensorOperator() = default;
242 TensorOperator(const TensorOperator &) = default;
243 TensorOperator &operator=(const TensorOperator &) = default;
244 TensorOperator(TensorOperator &&) = default;
245 TensorOperator &operator=(TensorOperator &&) = default;
246
247protected:
248 int m_rank;
249 Parity m_parity;
250 Realness m_Realness;
251 bool m_freqDependantQ{false};
252
253protected:
254 // these may be updated for frequency-dependant operators
255 double m_constant; // included in radial integral
256 std::vector<double> m_vec;
257
258public:
259 //! Returns true if the operator is frequency-dependent (requires updateFrequency() calls).
260 bool freqDependantQ() const { return m_freqDependantQ; }
261
262public:
263 //! Returns true if <a|h|b> = 0 by rank/parity selection rules.
264 bool isZero(int ka, int kb) const;
265 //! Overload taking DiracSpinors; forwards to isZero(ka, kb).
266 bool isZero(const DiracSpinor &Fa, const DiracSpinor &Fb) const;
267
268 //! Returns true if the matrix element is non-zero by angular momentum and parity selection rules (arguments are 2j and pi as integers).
269 bool selectrion_rule(int twoJA, int piA, int twoJB, int piB) const {
270 if (twoJA == twoJB && twoJA == 0.0)
271 return false;
272
273 if (Angular::triangle(twoJA, twoJB, 2 * m_rank) == 0)
274 return false;
275
276 return (m_parity == Parity::even) == (piA == piB);
277 }
278
279 //! @brief Updates the operator for a new frequency omega.
280 /*!
281 @details
282 Must be overridden by any frequency-dependent operator (i.e., where
283 freqDependantQ() returns true). Called before computing matrix elements
284 whenever the frequency changes.
285
286 The base class implementation aborts -- if a frequency-dependent operator
287 is constructed but this function is not overridden, it will abort at
288 runtime when called.
289
290 @param omega Frequency in atomic units.
291
292 @warning Must be implemented in any derived class that sets freq_dep=true.
293 Calling this on a non-frequency-dependent operator is a logic error.
294 */
295 virtual void updateFrequency(const double) {
296 std::cout << "Must reimplement updateFrequency()\n";
297 std::cout << this->name() << "\n";
298 std::abort();
299 };
300
301 /*!
302 Updates the rank of operator (rarely used). Generally also updates parity
303
304 @details
305 Use with caution.
306 @warning Will usually have to call updateFrequency() after this!
307 Updating rank often breaks frequency-dependence of radial functions
308 (e.g., spherical Bessel functions)
309 */
310 virtual void updateRank(int) {
311 std::cout << "Must reimplement updateRank() is needed\n";
312 std::cout << this->name() << "\n";
313 std::abort();
314 }
315
316 //! Returns a const ref to the stored vector v
317 const std::vector<double> &getv() const { return m_vec; }
318
319 //! Returns the "overall" constant c
320 double getc() const { return m_constant; }
321
322 //! returns true if operator is imaginary (has imag MEs)
323 bool imaginaryQ() const { return (m_Realness == Realness::imaginary); }
324
325 //! Rank k of operator
326 int rank() const { return m_rank; }
327
328 //! returns parity, as integer (+1 or -1)
329 int parity() const { return (m_parity == Parity::even) ? 1 : -1; }
330
331 //! returns relative sign between <a||x||b> and <b||x||a>
332 int symm_sign(const DiracSpinor &Fa, const DiracSpinor &Fb) const {
333 const auto sra_i = imaginaryQ() ? -1 : 1;
334 const auto sra = Angular::neg1pow_2(Fa.twoj() - Fb.twoj());
335 return sra_i * sra;
336 }
337
338 //! Returns "name" of operator (e.g., 'E1')
339 virtual std::string name() const { return "Operator"; };
340 //! Returns units of operator as a string (usually au, may be MHz, etc.)
341 virtual std::string units() const { return "au"; };
342
343public:
344 // These are needed for radial integrals
345 // Usually just constants, but can also be functions of kappa
346
347 /*!
348 @brief Angular coefficient C_ff for the f_a*f_b term of the radial integral.
349
350 @details
351 The default radial integral is structured as:
352
353 \f[
354 R_{ab} = c\int_0^\infty v(r)\left(
355 C_{ff}\,f_a f_b + C_{fg}\,f_a g_b +
356 C_{gf}\,g_a f_b + C_{gg}\,g_a g_b
357 \right)\,{\rm d}r
358 \f]
359
360 These coefficients are often constants, but may depend on
361 \f$ \kappa_a, \kappa_b \f$ for operators with angular-momentum-dependent
362 coupling between large and small components (e.g., spin-dependent
363 operators). Override in derived classes as needed.
364
365 @param kappa_a kappa \f$ \kappa_a \f$ for left-hand-side (bra)
366 @param kappa_b kappa \f$ \kappa_b \f$ for right-hand-side (ket)
367
368 @note Only relevant when using the default radial_rhs()/radialIntegral().
369 If those are overridden, these are not called.
370 */
371 virtual double angularCff(int kappa_a, int kappa_b) const {
372 (void)kappa_a, (void)kappa_b;
373 return 1.0;
374 }
375 //! Angular coefficient C_gg for the g_a*g_b term of the radial integral.
376 virtual double angularCgg(int, int) const { return 1.0; }
377 //! Angular coefficient C_fg for the f_a*g_b term of the radial integral.
378 virtual double angularCfg(int, int) const { return 0.0; }
379 //! Angular coefficient C_gf for the g_a*f_b term of the radial integral.
380 virtual double angularCgf(int, int) const { return 0.0; }
381
382 /*!
383 @brief Dispatches to angularCff/fg/gf/gg based on component indices x, y.
384 @details
385 Convenience dispatcher: x and y index the spinor component (0 = large/f,
386 1 = small/g) of the bra and ket respectively, and returns the
387 corresponding angular coefficient C_xy(ka, kb).
388
389 See @ref angularCff()
390
391 | x | y | returns |
392 |---|---|----------------|
393 | 0 | 0 | angularCff() |
394 | 0 | 1 | angularCfg() |
395 | 1 | 0 | angularCgf() |
396 | 1 | 1 | angularCgg() |
397
398 @param x Bra component index: 0=f (large), 1=g (small).
399 @param y Ket component index: 0=f (large), 1=g (small).
400 @param kappa_a kappa \f$ \kappa_a \f$ for left-hand-side (bra)
401 @param kappa_b kappa \f$ \kappa_b \f$ for right-hand-side (ket)
402
403 @note Only relevant when using the default radial_rhs()/radialIntegral().
404 If those are overridden, these are not called.
405 */
406 double angularCxy(uint8_t x, uint8_t y, int kappa_a, int kappa_b) const {
407 assert((x <= 1 && y <= 1) && "x and y must be 0 or 1 in angularCxy");
408 return x == 0 ? (y == 0 ? angularCff(kappa_a, kappa_b) :
409 angularCfg(kappa_a, kappa_b)) :
410 (y == 0 ? angularCgf(kappa_a, kappa_b) :
411 angularCgg(kappa_a, kappa_b));
412 }
413
414public:
415 /*!
416 @brief Angular factor A_ab linking the radial integral to the RME.
417
418 @details
419 All derived operators must implement this. It gives the purely angular
420 part of the reduced matrix element:
421
422 \f[
423 \langle a \| \hat{h} \| b \rangle \equiv A_{ab} \cdot R_{ab}
424 \f]
425
426 where \f$ R_{ab} \f$ is returned by radialIntegral(). For most operators,
427 \f$ A_{ab} \f$ is a product of Clebsch-Gordan / 3j coefficients and
428 depends only on \f$ \kappa_a, \kappa_b \f$
429 (and the rank \f$ k \f$ and parity \f$ \pi \f$ of the operator).
430
431 @note This is a pure virtual function -- every derived operator must
432 provide an implementation.
433 */
434 virtual double angularF(const int, const int) const = 0;
435
436 //! Returns a polymorphic copy of the operator at its current state,
437 //! or nullptr if cloning is not supported by the derived class.
438 virtual std::unique_ptr<TensorOperator> clone() const { return nullptr; }
439
440 //! @brief Computes the right-hand spinor dF_b for the radial integral.
441 /*!
442 @details
443 Returns \f$ \delta F_b \f$ such that the radial integral satisfies:
444
445 \f[
446 R_{ab} = F_a \cdot \delta F_b
447 = \int_0^\infty \left(f_a\,\delta f_b + g_a\,\delta g_b\right)\,{\rm d}r
448 \f]
449
450 The default implementation constructs \f$ \delta F_b \f$ using the stored
451 radial function \f$ v(r) \f$ and the angular coefficients:
452
453 \f[
454 \delta F_b(r) = c\,v(r)
455 \begin{pmatrix}
456 C_{ff}\,f_b(r) + C_{fg}\,g_b(r) \\
457 C_{gf}\,f_b(r) + C_{gg}\,g_b(r)
458 \end{pmatrix}
459 \f]
460
461 This is used by reduced_rhs() to build \f$ \langle a \| \hat{h} \| b \rangle \f$
462 as a spinor-valued quantity, enabling perturbation theory and TDHF.
463 Override this for operators whose radial structure cannot be expressed in
464 this standard form.
465
466 @param kappa_a Relativistic quantum number \f$ \kappa_a \f$ of the bra state
467 (needed to evaluate the angular coefficients).
468 @param Fb Ket DiracSpinor \f$ F_b \f$ .
469
470 @return DiracSpinor \f$ \delta F_b \f$ .
471
472 @warning If this is overridden, radialIntegral() should also be overridden
473 consistently (and vice versa), so that reducedME() and reduced_rhs() remain
474 consistent.
475 */
476 virtual DiracSpinor radial_rhs(const int kappa_a,
477 const DiracSpinor &Fb) const;
478
479 //! @brief Radial integral R_ab, defined by RME = angularF(a,b) * radialIntegral(a,b).
480 /*!
481 @details
482 Returns the radial part \f$ R_{ab} \f$ of the reduced matrix element:
483
484 \f[
485 \langle a \| \hat{h} \| b \rangle = A_{ab} \cdot R_{ab}
486 \f]
487
488 where \f$ A_{ab} \f$ is angularF().
489
490 The default implementation evaluates \f$ R_{ab} = F_a \cdot \delta F_b \f$ ,
491 using the default radial structure:
492
493 \f[
494 R_{ab} = c\int_0^\infty v(r)\left(
495 C_{ff}\,f_a f_b + C_{fg}\,f_a g_b +
496 C_{gf}\,g_a f_b + C_{gg}\,g_a g_b
497 \right)\,{\rm d}r
498 \f]
499
500 Override this for operators that do not fit this standard form. If
501 radial_rhs() is also overridden, both must remain mutually consistent.
502
503 @warning If radial_rhs() is overridden but radialIntegral() is not (or
504 vice versa), reducedME() and reduced_rhs() will give inconsistent results.
505 */
506 virtual double radialIntegral(const DiracSpinor &Fa,
507 const DiracSpinor &Fb) const;
508
509 /*!
510 @brief 3j-symbol factor linking the full ME to the RME.
511 @details
512 \f[ (-1)^{j_a - m_a} \begin{pmatrix} j_a & k & j_b \\ -m_a & q & m_b \end{pmatrix} \f]
513 such that \f$\langle a | \hat{h} | b \rangle = {\rm rme3js} \times \langle a \| \hat{h} \| b \rangle\f$.
514 All arguments are twice the actual value (2*j, 2*m, 2*q).
515 */
516 double rme3js(int twoja, int twojb, int two_mb = 1, int two_q = 0) const;
517
518 //! Overload of rme3js taking DiracSpinors.
519 double rme3js(const DiracSpinor &Fa, const DiracSpinor &Fb, int two_mb = 1,
520 int two_q = 0) const {
521 return rme3js(Fa.twoj(), Fb.twoj(), two_mb, two_q);
522 }
523
524 //! Returns angularF(ka,kb) * radial_rhs(ka,Fb); spinor-valued RME action on Fb, used in perturbation theory/TDHF.
525 DiracSpinor reduced_rhs(const int ka, const DiracSpinor &Fb) const;
526
527 //! As reduced_rhs but for the conjugate direction; Fb * reduced_lhs(ka, Fb) = <b||h||a>.
528 DiracSpinor reduced_lhs(const int ka, const DiracSpinor &Fb) const;
529
530 //! Returns the reduced matrix element <a||h||b> = A_ab * R_ab.
531 double reducedME(const DiracSpinor &Fa, const DiracSpinor &Fb) const;
532
533 //! Returns "full" matrix element, for optional (ma, mb, q) [taken as int 2*].
534 //! If not specified, returns z-component (q=0), with ma=mb=min(ja,jb)
535 double fullME(const DiracSpinor &Fa, const DiracSpinor &Fb,
536 std::optional<int> two_ma = std::nullopt,
537 std::optional<int> two_mb = std::nullopt,
538 std::optional<int> two_q = std::nullopt) const;
539
540 //! Returns the factor to convert a reduced ME to a different form (Reduced, Stretched, or HFConstant); see MatrixElementType.
541 double matel_factor(MatrixElementType type, int twoJa, int twoJb) const;
542
543 //! Overload of matel_factor taking DiracSpinors.
545 const DiracSpinor &Fb) const {
546 return matel_factor(type, Fa.twoj(), Fb.twoj());
547 }
548};
549
550//============================================================================
551//============================================================================
552/*!
553 @brief Rank-0 (scalar) tensor operator; derives from TensorOperator with k=0.
554 @details
555 Convenience base for scalar operators. angularF() returns \f$ \sqrt{2|\kappa|} \f$
556 when \f$ |\kappa_a|=|\kappa_b| \f$ , and zero otherwise. The four C_xy coefficients
557 default to (1,0,0,1) (diagonal ff+gg), but can be set via in_g for operators
558 with large/small component mixing (e.g., PNC operators).
559*/
561public:
562 //! General scalar operator constructor. in_g = {C_ff, C_fg, C_gf, C_gg}.
563 ScalarOperator(Parity pi, double in_coef,
564 const std::vector<double> &in_v = {},
565 const std::array<int, 4> &in_g = {1, 0, 0, 1},
566 Realness rori = Realness::real)
567 : TensorOperator(0, pi, in_coef, in_v, rori),
568 c_ff(in_g[0]),
569 c_fg(in_g[1]),
570 c_gf(in_g[2]),
571 c_gg(in_g[3]) {}
572
573 //! Convenience constructor: even-parity, real, diagonal (C_ff=C_gg=1, C_fg=C_gf=0) scalar operator.
574 ScalarOperator(const std::vector<double> &in_v = {}, double in_coef = 1.0)
575 : TensorOperator(0, Parity::even, in_coef, in_v),
576 c_ff(1.0),
577 c_fg(0.0),
578 c_gf(0.0),
579 c_gg(1.0) {}
580
581public:
582 virtual double angularF(const int ka, const int kb) const override {
583 // For scalar operators, <a||h||b> = RadInt / 3js
584 // 3js:= 1/(Sqrt[2j+1]) ... depends on m???
585 // |k| = j+1/2
586 return (std::abs(ka) == std::abs(kb)) ? std::sqrt(2.0 * std::abs(ka)) : 0.0;
587 }
588
589private:
590 const double c_ff, c_fg, c_gf, c_gg;
591
592protected:
593 double virtual angularCff(int, int) const override { return c_ff; }
594 double virtual angularCgg(int, int) const override { return c_gg; }
595 double virtual angularCfg(int, int) const override { return c_fg; }
596 double virtual angularCgf(int, int) const override { return c_gf; }
597};
598
599//------------------------------------------------------------------------------
600//! Speacial operator: 0
601class NullOperator final : public ScalarOperator {
602public:
603 NullOperator() : ScalarOperator(Parity::even, 0, {}) {}
604
605protected:
606 double angularCff(int, int) const override final { return 0.0; }
607 double angularCgg(int, int) const override final { return 0.0; }
608 double angularCfg(int, int) const override final { return 0.0; }
609 double angularCgf(int, int) const override final { return 0.0; }
610};
611
612//******************************************************************************
613// Helper functions: Useful for several operators
614//******************************************************************************
615
616//! Pab function: Int[ (fa*gb + pm*ga*fb) * t(r) , dr]. pm = +/-1 (usually)
617/*! @details
618Note: does not know selection rules, so only evaluate if non-zero
619*/
620double Pab(double pm, const std::vector<double> &t, const DiracSpinor &Fa,
621 const DiracSpinor &Fb);
622
623//! Rab function: Int[ (fa*fb + pm*ga*gb) * t(r) , dr]. pm = +/-1 (usually)
624/*! @details
625Note: does not know selection rules, so only evaluate if non-zero
626*/
627double Rab(double pm, const std::vector<double> &t, const DiracSpinor &Fa,
628 const DiracSpinor &Fb);
629
630//! Pab_rhs function: dF_ab += A * t(r) * (g, pm*f) , pm=+/-1 (usually).
631//! NOTE: uses +=, so can combine. Ensure empty to begin.
632/*! @details
633Note: does not know selection rules, so only evaluate if non-zero.
634Should have Fa*Pab_rhs = A * Pab.
635*/
636void Pab_rhs(double pm, const std::vector<double> &t, DiracSpinor *dF,
637 const DiracSpinor &Fb, double A = 1.0);
638
639//! Rab_rhs function: dF_ab += A * t(r) * (f, pm*g) , pm=+/-1 (usually).
640//! NOTE: uses +=, so can combine. Ensure empty to begin.
641/*! @details
642Note: does not know selection rules, so only evaluate if non-zero.
643Should have Fa*Rab_rhs = A * Rab.
644*/
645void Rab_rhs(double pm, const std::vector<double> &t, DiracSpinor *dF,
646 const DiracSpinor &Fb, double A = 1.0);
647
648//! Vab function: Int[ (fa*gb ) * t(r) , dr].
649double Vab(const std::vector<double> &t, const DiracSpinor &Fa,
650 const DiracSpinor &Fb);
651//! Wab function: Int[ (ga*fb ) * t(r) , dr].
652double Wab(const std::vector<double> &t, const DiracSpinor &Fa,
653 const DiracSpinor &Fb);
654
655//! Gab function: Int[ (ga*gb ) * t(r) , dr].
656double Gab(const std::vector<double> &t, const DiracSpinor &Fa,
657 const DiracSpinor &Fb);
658
659//! Gab_rhs function: dF += a * t(r) * (0, g_b). NOTE: uses +=, so can combine.
660void Gab_rhs(const std::vector<double> &t, DiracSpinor *dF,
661 const DiracSpinor &Fb, double a);
662
663// Same - for constant t(r)=c
664
665//! Pab[1] function: Int[ (fa*gb + pm*ga*fb) , dr]. pm = +/-1 (usually)
666double Pab(double pm, const DiracSpinor &Fa, const DiracSpinor &Fb);
667
668//! Rab[1] function: Int[ (fa*fb + pm*ga*gb) , dr] = Int[ (pm-1)*ga*gb) , dr].
669//! NOTE: assumes NOT diagonal, using orthogonality condition.
670double Rab(double pm, const DiracSpinor &Fa, const DiracSpinor &Fb);
671
672//! Pab_rhs[1] function: dF_ab += A * (g, pm*f) , pm=+/-1 (usually).
673void Pab_rhs(double pm, DiracSpinor *dF, const DiracSpinor &Fb, double A = 1.0);
674
675//! Rab_rhs[1] function: dF_ab += A * (f, pm*g) = dF_ab += A * (0, (pm-1)*g).
676//! NOTE: assumes NOT diagonal, using orthogonality condition.
677void Rab_rhs(double pm, DiracSpinor *dF, const DiracSpinor &Fb, double A = 1.0);
678
679//! Gab = Int[ ga*gb , dr] - (just relativistic correction part of integral)
680double Gab(const DiracSpinor &Fa, const DiracSpinor &Fb);
681
682//! Gab_rhs(r) += a*g_b(r). Note: uses += so may be sumulative
683void Gab_rhs(DiracSpinor *dF, const DiracSpinor &Fb, double a);
684
685} // namespace DiracOperator
Speacial operator: 0.
Definition TensorOperator.hpp:601
double angularCgg(int, int) const override final
Angular coefficient C_gg for the g_a*g_b term of the radial integral.
Definition TensorOperator.hpp:607
double angularCff(int, int) const override final
Angular coefficient C_ff for the f_a*f_b term of the radial integral.
Definition TensorOperator.hpp:606
double angularCfg(int, int) const override final
Angular coefficient C_fg for the f_a*g_b term of the radial integral.
Definition TensorOperator.hpp:608
double angularCgf(int, int) const override final
Angular coefficient C_gf for the g_a*f_b term of the radial integral.
Definition TensorOperator.hpp:609
Rank-0 (scalar) tensor operator; derives from TensorOperator with k=0.
Definition TensorOperator.hpp:560
ScalarOperator(Parity pi, double in_coef, const std::vector< double > &in_v={}, const std::array< int, 4 > &in_g={1, 0, 0, 1}, Realness rori=Realness::real)
General scalar operator constructor. in_g = {C_ff, C_fg, C_gf, C_gg}.
Definition TensorOperator.hpp:563
virtual double angularCgf(int, int) const override
Angular coefficient C_gf for the g_a*f_b term of the radial integral.
Definition TensorOperator.hpp:596
ScalarOperator(const std::vector< double > &in_v={}, double in_coef=1.0)
Convenience constructor: even-parity, real, diagonal (C_ff=C_gg=1, C_fg=C_gf=0) scalar operator.
Definition TensorOperator.hpp:574
virtual double angularCfg(int, int) const override
Angular coefficient C_fg for the f_a*g_b term of the radial integral.
Definition TensorOperator.hpp:595
virtual double angularCgg(int, int) const override
Angular coefficient C_gg for the g_a*g_b term of the radial integral.
Definition TensorOperator.hpp:594
virtual double angularF(const int ka, const int kb) const override
Angular factor A_ab linking the radial integral to the RME.
Definition TensorOperator.hpp:582
virtual double angularCff(int, int) const override
Angular coefficient C_ff for the f_a*f_b term of the radial integral.
Definition TensorOperator.hpp:593
General tensor operator (virtual base class); all single-particle (one-body) tenosor operators derive...
Definition TensorOperator.hpp:197
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,...
Definition TensorOperator.cpp:67
virtual double angularCgf(int, int) const
Angular coefficient C_gf for the g_a*f_b term of the radial integral.
Definition TensorOperator.hpp:380
bool freqDependantQ() const
Returns true if the operator is frequency-dependent (requires updateFrequency() calls).
Definition TensorOperator.hpp:260
virtual std::unique_ptr< TensorOperator > clone() const
Returns a polymorphic copy of the operator at its current state, or nullptr if cloning is not support...
Definition TensorOperator.hpp:438
int symm_sign(const DiracSpinor &Fa, const DiracSpinor &Fb) const
returns relative sign between <a||x||b> and <b||x||a>
Definition TensorOperator.hpp:332
bool imaginaryQ() const
returns true if operator is imaginary (has imag MEs)
Definition TensorOperator.hpp:323
virtual std::string units() const
Returns units of operator as a string (usually au, may be MHz, etc.)
Definition TensorOperator.hpp:341
int parity() const
returns parity, as integer (+1 or -1)
Definition TensorOperator.hpp:329
double rme3js(const DiracSpinor &Fa, const DiracSpinor &Fb, int two_mb=1, int two_q=0) const
Overload of rme3js taking DiracSpinors.
Definition TensorOperator.hpp:519
virtual double angularF(const int, const int) const =0
Angular factor A_ab linking the radial integral to the RME.
virtual double angularCfg(int, int) const
Angular coefficient C_fg for the f_a*g_b term of the radial integral.
Definition TensorOperator.hpp:378
double matel_factor(MatrixElementType type, int twoJa, int twoJb) const
Returns the factor to convert a reduced ME to a different form (Reduced, Stretched,...
Definition TensorOperator.cpp:84
virtual std::string name() const
Returns "name" of operator (e.g., 'E1')
Definition TensorOperator.hpp:339
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.
Definition TensorOperator.hpp:217
double getc() const
Returns the "overall" constant c.
Definition TensorOperator.hpp:320
double reducedME(const DiracSpinor &Fa, const DiracSpinor &Fb) const
Returns the reduced matrix element <a||h||b> = A_ab * R_ab.
Definition TensorOperator.cpp:62
virtual double angularCgg(int, int) const
Angular coefficient C_gg for the g_a*g_b term of the radial integral.
Definition TensorOperator.hpp:376
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 (argume...
Definition TensorOperator.hpp:269
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>.
Definition TensorOperator.cpp:55
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.
Definition TensorOperator.hpp:406
double matel_factor(MatrixElementType type, const DiracSpinor &Fa, const DiracSpinor &Fb) const
Overload of matel_factor taking DiracSpinors.
Definition TensorOperator.hpp:544
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.
Definition TensorOperator.cpp:40
bool isZero(int ka, int kb) const
Returns true if <a|h|b> = 0 by rank/parity selection rules.
Definition TensorOperator.cpp:18
virtual DiracSpinor radial_rhs(const int kappa_a, const DiracSpinor &Fb) const
Computes the right-hand spinor dF_b for the radial integral.
Definition TensorOperator.cpp:104
virtual void updateRank(int)
Definition TensorOperator.hpp:310
virtual double radialIntegral(const DiracSpinor &Fa, const DiracSpinor &Fb) const
Radial integral R_ab, defined by RME = angularF(a,b) * radialIntegral(a,b).
Definition TensorOperator.cpp:143
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.
Definition TensorOperator.hpp:371
int rank() const
Rank k of operator.
Definition TensorOperator.hpp:326
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 the...
Definition TensorOperator.cpp:50
virtual void updateFrequency(const double)
Updates the operator for a new frequency omega.
Definition TensorOperator.hpp:295
const std::vector< double > & getv() const
Returns a const ref to the stored vector v.
Definition TensorOperator.hpp:317
Stores radial Dirac spinor: F_nk = (f, g)
Definition DiracSpinor.hpp:42
constexpr int neg1pow_2(int two_a)
Evaluates (-1)^{two_a/2} (for integer a; two_a is even)
Definition Wigner369j.hpp:239
constexpr int triangle(int j1, int j2, int J)
Returns 1 if triangle rule is satisfied. nb: works with j OR twoj!
Definition Wigner369j.hpp:249
Dirac operators: TensorOperator base class and derived implementations for single-particle (one-body)...
Definition GenerateOperator.cpp:3
void Pab_rhs(double pm, const std::vector< double > &t, DiracSpinor *dF, const DiracSpinor &Fb, double a)
Pab_rhs function: dF_ab += A * t(r) * (g, pm*f) , pm=+/-1 (usually). NOTE: uses +=,...
Definition TensorOperator.cpp:223
double Vab(const std::vector< double > &t, const DiracSpinor &Fa, const DiracSpinor &Fb)
Vab function: Int[ (fa*gb ) * t(r) , dr].
Definition TensorOperator.cpp:242
double Gab(const std::vector< double > &t, const DiracSpinor &Fa, const DiracSpinor &Fb)
Gab function: Int[ (ga*gb ) * t(r) , dr].
Definition TensorOperator.cpp:261
double Rab(double pm, const std::vector< double > &t, const DiracSpinor &Fa, const DiracSpinor &Fb)
Rab function: Int[ (fa*fb + pm*ga*gb) * t(r) , dr]. pm = +/-1 (usually)
Definition TensorOperator.cpp:211
double Wab(const std::vector< double > &t, const DiracSpinor &Fa, const DiracSpinor &Fb)
Wab function: Int[ (ga*fb ) * t(r) , dr].
Definition TensorOperator.cpp:252
Realness parse_Realness(const std::string &s)
Convert string to Realness.
Definition TensorOperator.cpp:385
MatrixElementType
Type of matrix element returned.
Definition TensorOperator.hpp:81
void Rab_rhs(double pm, const std::vector< double > &t, DiracSpinor *dF, const DiracSpinor &Fb, double a)
Rab_rhs function: dF_ab += A * t(r) * (f, pm*g) , pm=+/-1 (usually). NOTE: uses +=,...
Definition TensorOperator.cpp:233
Parity
Parity of operator.
Definition TensorOperator.hpp:57
Parity parse_Parity(const std::string &s)
Convert string to Parity.
Definition TensorOperator.cpp:362
void Gab_rhs(const std::vector< double > &t, DiracSpinor *dF, const DiracSpinor &Fb, double a)
Gab_rhs function: dF += a * t(r) * (0, g_b). NOTE: uses +=, so can combine.
Definition TensorOperator.cpp:270
Realness
Specifies whether an operator's matrix elements are real or imaginary.
Definition TensorOperator.hpp:69
double Pab(double pm, const std::vector< double > &t, const DiracSpinor &Fa, const DiracSpinor &Fb)
Pab function: Int[ (fa*gb + pm*ga*fb) * t(r) , dr]. pm = +/-1 (usually)
Definition TensorOperator.cpp:197
MatrixElementType parse_MatrixElementType(const std::string &s)
Convert string to MatrixElementType.
Definition TensorOperator.cpp:408
Used to pass generic parameters to update() function.
Definition TensorOperator.hpp:236