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