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 double m_omega{0.0};
259
260public:
261 //! Returns true if the operator is frequency-dependent (requires updateFrequency() calls).
262 bool freqDependantQ() const { return m_freqDependantQ; }
263
264 //! Returns the current frequency set by the last updateFrequency() call.
265 //! Zero for frequency-independent operators.
266 double omega() const { return m_omega; }
267
268public:
269 //! Returns true if <a|h|b> = 0 by rank/parity selection rules.
270 bool isZero(int ka, int kb) const;
271 //! Overload taking DiracSpinors; forwards to isZero(ka, kb).
272 bool isZero(const DiracSpinor &Fa, const DiracSpinor &Fb) const;
273
274 //! Returns true if the matrix element is non-zero by angular momentum and parity selection rules (arguments are 2j and pi as integers).
275 bool selectrion_rule(int twoJA, int piA, int twoJB, int piB) const {
276 if (twoJA == twoJB && twoJA == 0.0)
277 return false;
278
279 if (Angular::triangle(twoJA, twoJB, 2 * m_rank) == 0)
280 return false;
281
282 return (m_parity == Parity::even) == (piA == piB);
283 }
284
285 //! @brief Updates the operator for a new frequency omega.
286 /*!
287 @details
288 Must be overridden by any frequency-dependent operator (i.e., where
289 freqDependantQ() returns true). Called before computing matrix elements
290 whenever the frequency changes.
291
292 The base class implementation aborts -- if a frequency-dependent operator
293 is constructed but this function is not overridden, it will abort at
294 runtime when called.
295
296 @param omega Frequency in atomic units.
297
298 @warning Must be implemented in any derived class that sets freq_dep=true.
299 Calling this on a non-frequency-dependent operator is a logic error.
300
301 @note Derived implementations must set @p m_omega = omega so that omega()
302 reflects the current frequency (e.g., for use by the TDHF solver when
303 constructing the \f$ t_- \f$ operator at negated frequency).
304 */
305 virtual void updateFrequency(const double) {
306 std::cout << "Must reimplement updateFrequency()\n";
307 std::cout << this->name() << "\n";
308 std::abort();
309 };
310
311 /*!
312 Updates the rank of operator (rarely used). Generally also updates parity
313
314 @details
315 Use with caution.
316 @warning Will usually have to call updateFrequency() after this!
317 Updating rank often breaks frequency-dependence of radial functions
318 (e.g., spherical Bessel functions)
319 */
320 virtual void updateRank(int) {
321 std::cout << "Must reimplement updateRank() is needed\n";
322 std::cout << this->name() << "\n";
323 std::abort();
324 }
325
326 //! Returns a const ref to the stored vector v
327 const std::vector<double> &getv() const { return m_vec; }
328
329 //! Returns the "overall" constant c
330 double getc() const { return m_constant; }
331
332 //! returns true if operator is imaginary (has imag MEs)
333 bool imaginaryQ() const { return (m_Realness == Realness::imaginary); }
334
335 //! Rank k of operator
336 int rank() const { return m_rank; }
337
338 //! returns parity, as integer (+1 or -1)
339 int parity() const { return (m_parity == Parity::even) ? 1 : -1; }
340
341 //! returns relative sign between <a||x||b> and <b||x||a>
342 int symm_sign(const DiracSpinor &Fa, const DiracSpinor &Fb) const {
343 const auto sra_i = imaginaryQ() ? -1 : 1;
344 const auto sra = Angular::neg1pow_2(Fa.twoj() - Fb.twoj());
345 return sra_i * sra;
346 }
347
348 //! Returns "name" of operator (e.g., 'E1')
349 virtual std::string name() const { return "Operator"; };
350 //! Returns units of operator as a string (usually au, may be MHz, etc.)
351 virtual std::string units() const { return "au"; };
352
353public:
354 // These are needed for radial integrals
355 // Usually just constants, but can also be functions of kappa
356
357 /*!
358 @brief Angular coefficient C_ff for the f_a*f_b term of the radial integral.
359
360 @details
361 The default radial integral is structured as:
362
363 \f[
364 R_{ab} = c\int_0^\infty v(r)\left(
365 C_{ff}\,f_a f_b + C_{fg}\,f_a g_b +
366 C_{gf}\,g_a f_b + C_{gg}\,g_a g_b
367 \right)\,{\rm d}r
368 \f]
369
370 These coefficients are often constants, but may depend on
371 \f$ \kappa_a, \kappa_b \f$ for operators with angular-momentum-dependent
372 coupling between large and small components (e.g., spin-dependent
373 operators). Override in derived classes as needed.
374
375 @param kappa_a kappa \f$ \kappa_a \f$ for left-hand-side (bra)
376 @param kappa_b kappa \f$ \kappa_b \f$ for right-hand-side (ket)
377
378 @note Only relevant when using the default radial_rhs()/radialIntegral().
379 If those are overridden, these are not called.
380 */
381 virtual double angularCff(int kappa_a, int kappa_b) const {
382 (void)kappa_a, (void)kappa_b;
383 return 1.0;
384 }
385 //! Angular coefficient C_gg for the g_a*g_b term of the radial integral.
386 virtual double angularCgg(int, int) const { return 1.0; }
387 //! Angular coefficient C_fg for the f_a*g_b term of the radial integral.
388 virtual double angularCfg(int, int) const { return 0.0; }
389 //! Angular coefficient C_gf for the g_a*f_b term of the radial integral.
390 virtual double angularCgf(int, int) const { return 0.0; }
391
392 /*!
393 @brief Dispatches to angularCff/fg/gf/gg based on component indices x, y.
394 @details
395 Convenience dispatcher: x and y index the spinor component (0 = large/f,
396 1 = small/g) of the bra and ket respectively, and returns the
397 corresponding angular coefficient C_xy(ka, kb).
398
399 See @ref angularCff()
400
401 | x | y | returns |
402 |---|---|----------------|
403 | 0 | 0 | angularCff() |
404 | 0 | 1 | angularCfg() |
405 | 1 | 0 | angularCgf() |
406 | 1 | 1 | angularCgg() |
407
408 @param x Bra component index: 0=f (large), 1=g (small).
409 @param y Ket component index: 0=f (large), 1=g (small).
410 @param kappa_a kappa \f$ \kappa_a \f$ for left-hand-side (bra)
411 @param kappa_b kappa \f$ \kappa_b \f$ for right-hand-side (ket)
412
413 @note Only relevant when using the default radial_rhs()/radialIntegral().
414 If those are overridden, these are not called.
415 */
416 double angularCxy(uint8_t x, uint8_t y, int kappa_a, int kappa_b) const {
417 assert((x <= 1 && y <= 1) && "x and y must be 0 or 1 in angularCxy");
418 return x == 0 ? (y == 0 ? angularCff(kappa_a, kappa_b) :
419 angularCfg(kappa_a, kappa_b)) :
420 (y == 0 ? angularCgf(kappa_a, kappa_b) :
421 angularCgg(kappa_a, kappa_b));
422 }
423
424public:
425 /*!
426 @brief Angular factor A_ab linking the radial integral to the RME.
427
428 @details
429 All derived operators must implement this. It gives the purely angular
430 part of the reduced matrix element:
431
432 \f[
433 \langle a \| \hat{h} \| b \rangle \equiv A_{ab} \cdot R_{ab}
434 \f]
435
436 where \f$ R_{ab} \f$ is returned by radialIntegral(). For most operators,
437 \f$ A_{ab} \f$ is a product of Clebsch-Gordan / 3j coefficients and
438 depends only on \f$ \kappa_a, \kappa_b \f$
439 (and the rank \f$ k \f$ and parity \f$ \pi \f$ of the operator).
440
441 @note This is a pure virtual function -- every derived operator must
442 provide an implementation.
443 */
444 virtual double angularF(const int, const int) const = 0;
445
446 /*!
447 @brief Creates a polymorphic copy of the operator at its current state,
448 or nullptr if cloning is not supported by the derived class.
449 @details
450 Frequency-dependent operators must override this so the TDHF solver
451 can construct an independent \f$ t_- = t_+^\dagger(-\omega) \f$ operator.
452
453 Most operators can implement this as a one-liner using the copy constructor:
454 \code
455 return std::make_unique<DerivedClass>(*this);
456 \endcode
457 This works whenever the copy constructor correctly preserves all state,
458 including m_vec, m_constant, and m_omega.
459
460 @return Owning pointer to a copy, or nullptr if cloning is unsupported.
461 @note The base class returns nullptr. Operators whose copy constructor is
462 deleted or otherwise unavailable cannot use this pattern and must either
463 implement a manual clone or leave the default nullptr.
464 */
465 virtual std::unique_ptr<TensorOperator> clone() const { return nullptr; }
466
467 //! @brief Computes the right-hand spinor dF_b for the radial integral.
468 /*!
469 @details
470 Returns \f$ \delta F_b \f$ such that the radial integral satisfies:
471
472 \f[
473 R_{ab} = F_a \cdot \delta F_b
474 = \int_0^\infty \left(f_a\,\delta f_b + g_a\,\delta g_b\right)\,{\rm d}r
475 \f]
476
477 The default implementation constructs \f$ \delta F_b \f$ using the stored
478 radial function \f$ v(r) \f$ and the angular coefficients:
479
480 \f[
481 \delta F_b(r) = c\,v(r)
482 \begin{pmatrix}
483 C_{ff}\,f_b(r) + C_{fg}\,g_b(r) \\
484 C_{gf}\,f_b(r) + C_{gg}\,g_b(r)
485 \end{pmatrix}
486 \f]
487
488 This is used by reduced_rhs() to build \f$ \langle a \| \hat{h} \| b \rangle \f$
489 as a spinor-valued quantity, enabling perturbation theory and TDHF.
490 Override this for operators whose radial structure cannot be expressed in
491 this standard form.
492
493 @param kappa_a Relativistic quantum number \f$ \kappa_a \f$ of the bra state
494 (needed to evaluate the angular coefficients).
495 @param Fb Ket DiracSpinor \f$ F_b \f$ .
496
497 @return DiracSpinor \f$ \delta F_b \f$ .
498
499 @warning If this is overridden, radialIntegral() should also be overridden
500 consistently (and vice versa), so that reducedME() and reduced_rhs() remain
501 consistent.
502 */
503 virtual DiracSpinor radial_rhs(const int kappa_a,
504 const DiracSpinor &Fb) const;
505
506 //! @brief Radial integral R_ab, defined by RME = angularF(a,b) * radialIntegral(a,b).
507 /*!
508 @details
509 Returns the radial part \f$ R_{ab} \f$ of the reduced matrix element:
510
511 \f[
512 \langle a \| \hat{h} \| b \rangle = A_{ab} \cdot R_{ab}
513 \f]
514
515 where \f$ A_{ab} \f$ is angularF().
516
517 The default implementation evaluates \f$ R_{ab} = F_a \cdot \delta F_b \f$ ,
518 using the default radial structure:
519
520 \f[
521 R_{ab} = c\int_0^\infty v(r)\left(
522 C_{ff}\,f_a f_b + C_{fg}\,f_a g_b +
523 C_{gf}\,g_a f_b + C_{gg}\,g_a g_b
524 \right)\,{\rm d}r
525 \f]
526
527 Override this for operators that do not fit this standard form. If
528 radial_rhs() is also overridden, both must remain mutually consistent.
529
530 @warning If radial_rhs() is overridden but radialIntegral() is not (or
531 vice versa), reducedME() and reduced_rhs() will give inconsistent results.
532 */
533 virtual double radialIntegral(const DiracSpinor &Fa,
534 const DiracSpinor &Fb) const;
535
536 /*!
537 @brief 3j-symbol factor linking the full ME to the RME.
538 @details
539 \f[ (-1)^{j_a - m_a} \begin{pmatrix} j_a & k & j_b \\ -m_a & q & m_b \end{pmatrix} \f]
540 such that \f$\langle a | \hat{h} | b \rangle = {\rm rme3js} \times \langle a \| \hat{h} \| b \rangle\f$.
541 All arguments are twice the actual value (2*j, 2*m, 2*q).
542 */
543 double rme3js(int twoja, int twojb, int two_mb = 1, int two_q = 0) const;
544
545 //! Overload of rme3js taking DiracSpinors.
546 double rme3js(const DiracSpinor &Fa, const DiracSpinor &Fb, int two_mb = 1,
547 int two_q = 0) const {
548 return rme3js(Fa.twoj(), Fb.twoj(), two_mb, two_q);
549 }
550
551 //! Returns angularF(ka,kb) * radial_rhs(ka,Fb); spinor-valued RME action on Fb, used in perturbation theory/TDHF.
552 DiracSpinor reduced_rhs(const int ka, const DiracSpinor &Fb) const;
553
554 //! As reduced_rhs but for the conjugate direction; Fb * reduced_lhs(ka, Fb) = <b||h||a>.
555 DiracSpinor reduced_lhs(const int ka, const DiracSpinor &Fb) const;
556
557 //! Returns the reduced matrix element <a||h||b> = A_ab * R_ab.
558 double reducedME(const DiracSpinor &Fa, const DiracSpinor &Fb) const;
559
560 //! Returns "full" matrix element, for optional (ma, mb, q) [taken as int 2*].
561 //! If not specified, returns z-component (q=0), with ma=mb=min(ja,jb)
562 double fullME(const DiracSpinor &Fa, const DiracSpinor &Fb,
563 std::optional<int> two_ma = std::nullopt,
564 std::optional<int> two_mb = std::nullopt,
565 std::optional<int> two_q = std::nullopt) const;
566
567 //! Returns the factor to convert a reduced ME to a different form (Reduced, Stretched, or HFConstant); see MatrixElementType.
568 double matel_factor(MatrixElementType type, int twoJa, int twoJb) const;
569
570 //! Overload of matel_factor taking DiracSpinors.
572 const DiracSpinor &Fb) const {
573 return matel_factor(type, Fa.twoj(), Fb.twoj());
574 }
575};
576
577//============================================================================
578//============================================================================
579/*!
580 @brief Rank-0 (scalar) tensor operator; derives from TensorOperator with k=0.
581 @details
582 Convenience base for scalar operators. angularF() returns \f$ \sqrt{2|\kappa|} \f$
583 when \f$ |\kappa_a|=|\kappa_b| \f$ , and zero otherwise. The four C_xy coefficients
584 default to (1,0,0,1) (diagonal ff+gg), but can be set via in_g for operators
585 with large/small component mixing (e.g., PNC operators).
586*/
588public:
589 //! General scalar operator constructor. in_g = {C_ff, C_fg, C_gf, C_gg}.
590 ScalarOperator(Parity pi, double in_coef,
591 const std::vector<double> &in_v = {},
592 const std::array<int, 4> &in_g = {1, 0, 0, 1},
593 Realness rori = Realness::real)
594 : TensorOperator(0, pi, in_coef, in_v, rori),
595 c_ff(in_g[0]),
596 c_fg(in_g[1]),
597 c_gf(in_g[2]),
598 c_gg(in_g[3]) {}
599
600public:
601 virtual double angularF(const int ka, const int kb) const override {
602 // For scalar operators, <a||h||b> = RadInt / 3js
603 // 3js:= 1/(Sqrt[2j+1]) ... depends on m???
604 // |k| = j+1/2
605 return (std::abs(ka) == std::abs(kb)) ? std::sqrt(2.0 * std::abs(ka)) : 0.0;
606 }
607
608private:
609 const double c_ff, c_fg, c_gf, c_gg;
610
611protected:
612 double virtual angularCff(int, int) const override { return c_ff; }
613 double virtual angularCgg(int, int) const override { return c_gg; }
614 double virtual angularCfg(int, int) const override { return c_fg; }
615 double virtual angularCgf(int, int) const override { return c_gf; }
616};
617
618//------------------------------------------------------------------------------
619//! Speacial operator: 0
620class NullOperator final : public ScalarOperator {
621public:
622 NullOperator() : ScalarOperator(Parity::even, 0, {}) {}
623
624protected:
625 double angularCff(int, int) const override final { return 0.0; }
626 double angularCgg(int, int) const override final { return 0.0; }
627 double angularCfg(int, int) const override final { return 0.0; }
628 double angularCgf(int, int) const override final { return 0.0; }
629};
630
631//******************************************************************************
632// Helper functions: Useful for several operators
633//******************************************************************************
634
635//! Pab function: Int[ (fa*gb + pm*ga*fb) * t(r) , dr]. pm = +/-1 (usually)
636/*! @details
637Note: does not know selection rules, so only evaluate if non-zero
638*/
639double Pab(double pm, const std::vector<double> &t, const DiracSpinor &Fa,
640 const DiracSpinor &Fb);
641
642//! Rab function: Int[ (fa*fb + pm*ga*gb) * t(r) , dr]. pm = +/-1 (usually)
643/*! @details
644Note: does not know selection rules, so only evaluate if non-zero
645*/
646double Rab(double pm, const std::vector<double> &t, const DiracSpinor &Fa,
647 const DiracSpinor &Fb);
648
649//! Pab_rhs function: dF_ab += A * t(r) * (g, pm*f) , pm=+/-1 (usually).
650//! NOTE: uses +=, so can combine. Ensure empty to begin.
651/*! @details
652Note: does not know selection rules, so only evaluate if non-zero.
653Should have Fa*Pab_rhs = A * Pab.
654*/
655void Pab_rhs(double pm, const std::vector<double> &t, DiracSpinor *dF,
656 const DiracSpinor &Fb, double A = 1.0);
657
658//! Rab_rhs function: dF_ab += A * t(r) * (f, pm*g) , pm=+/-1 (usually).
659//! NOTE: uses +=, so can combine. Ensure empty to begin.
660/*! @details
661Note: does not know selection rules, so only evaluate if non-zero.
662Should have Fa*Rab_rhs = A * Rab.
663*/
664void Rab_rhs(double pm, const std::vector<double> &t, DiracSpinor *dF,
665 const DiracSpinor &Fb, double A = 1.0);
666
667//! Vab function: Int[ (fa*gb ) * t(r) , dr].
668double Vab(const std::vector<double> &t, const DiracSpinor &Fa,
669 const DiracSpinor &Fb);
670//! Wab function: Int[ (ga*fb ) * t(r) , dr].
671double Wab(const std::vector<double> &t, const DiracSpinor &Fa,
672 const DiracSpinor &Fb);
673
674//! Gab function: Int[ (ga*gb ) * t(r) , dr].
675double Gab(const std::vector<double> &t, const DiracSpinor &Fa,
676 const DiracSpinor &Fb);
677
678//! Gab_rhs function: dF += a * t(r) * (0, g_b). NOTE: uses +=, so can combine.
679void Gab_rhs(const std::vector<double> &t, DiracSpinor *dF,
680 const DiracSpinor &Fb, double a);
681
682// Same - for constant t(r)=c
683
684//! Pab[1] function: Int[ (fa*gb + pm*ga*fb) , dr]. pm = +/-1 (usually)
685double Pab(double pm, const DiracSpinor &Fa, const DiracSpinor &Fb);
686
687//! Rab[1] function: Int[ (fa*fb + pm*ga*gb) , dr] = Int[ (pm-1)*ga*gb) , dr].
688//! NOTE: assumes NOT diagonal, using orthogonality condition.
689double Rab(double pm, const DiracSpinor &Fa, const DiracSpinor &Fb);
690
691//! Pab_rhs[1] function: dF_ab += A * (g, pm*f) , pm=+/-1 (usually).
692void Pab_rhs(double pm, DiracSpinor *dF, const DiracSpinor &Fb, double A = 1.0);
693
694//! Rab_rhs[1] function: dF_ab += A * (f, pm*g) = dF_ab += A * (0, (pm-1)*g).
695//! NOTE: assumes NOT diagonal, using orthogonality condition.
696void Rab_rhs(double pm, DiracSpinor *dF, const DiracSpinor &Fb, double A = 1.0);
697
698//! Gab = Int[ ga*gb , dr] - (just relativistic correction part of integral)
699double Gab(const DiracSpinor &Fa, const DiracSpinor &Fb);
700
701//! Gab_rhs(r) += a*g_b(r). Note: uses += so may be sumulative
702void Gab_rhs(DiracSpinor *dF, const DiracSpinor &Fb, double a);
703
704} // namespace DiracOperator
Speacial operator: 0.
Definition TensorOperator.hpp:620
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:626
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:625
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:627
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:628
Rank-0 (scalar) tensor operator; derives from TensorOperator with k=0.
Definition TensorOperator.hpp:587
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:590
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:615
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:614
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:613
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:601
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:612
General tensor operator (virtual base class); all single-particle (one-body) tenosor operators derive...
Definition TensorOperator.hpp:198
double omega() const
Returns the current frequency set by the last updateFrequency() call. Zero for frequency-independent ...
Definition TensorOperator.hpp:266
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:390
bool freqDependantQ() const
Returns true if the operator is frequency-dependent (requires updateFrequency() calls).
Definition TensorOperator.hpp:262
virtual std::unique_ptr< TensorOperator > clone() const
Creates a polymorphic copy of the operator at its current state, or nullptr if cloning is not support...
Definition TensorOperator.hpp:465
int symm_sign(const DiracSpinor &Fa, const DiracSpinor &Fb) const
returns relative sign between <a||x||b> and <b||x||a>
Definition TensorOperator.hpp:342
bool imaginaryQ() const
returns true if operator is imaginary (has imag MEs)
Definition TensorOperator.hpp:333
virtual std::string units() const
Returns units of operator as a string (usually au, may be MHz, etc.)
Definition TensorOperator.hpp:351
int parity() const
returns parity, as integer (+1 or -1)
Definition TensorOperator.hpp:339
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:546
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:388
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:349
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:330
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:386
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:275
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:416
double matel_factor(MatrixElementType type, const DiracSpinor &Fa, const DiracSpinor &Fb) const
Overload of matel_factor taking DiracSpinors.
Definition TensorOperator.hpp:571
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:320
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:381
int rank() const
Rank k of operator.
Definition TensorOperator.hpp:336
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:305
const std::vector< double > & getv() const
Returns a const ref to the stored vector v.
Definition TensorOperator.hpp:327
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