ampsci
High-precision calculations for one- and two-valence atomic systems
hfs.hpp
1#pragma once
2#include "DiracOperator/TensorOperator.hpp"
3#include "IO/InputBlock.hpp"
4#include "Physics/NuclearData.hpp"
5#include "Potentials/NuclearPotentials.hpp"
6#include "Wavefunction/Wavefunction.hpp"
7#include "fmt/color.hpp"
8#include "qip/Maths.hpp"
9#include <functional>
10
11namespace DiracOperator {
12
13//==============================================================================
14//! Auxiliary functions for hyperfine operators; F(r) [nuclear distribution] and similar
15//! @details See \ref DiracOperator::hfs for operator
16namespace Hyperfine {
17
18/*!
19 @brief Type for radial function F(r, r_Nuc) -- nuclear magnetisation/charge distribution
20 @details
21 - F(r,rN) contains only finite nuclear size correction, not HFS radial function.
22 - F(r,rN) -> 1 for r > rN
23 - r and rN always in atomic units
24
25 The full HFS radial operator is t^k(r) = F(r, r_N) / r^{k+1}, formed by
26 \ref tk_radial. F(r) itself is defined by the chosen nuclear model;
27 see \ref sphericalBall_F, \ref VolotkaSP_F, \ref uSP, \ref doublyOddSP_F,
28 \ref generic_F.
29*/
30using RadialFunction = std::function<double(double r, double r_Nuc)>;
31
32//==============================================================================
33/*!
34 @brief Forms the hyperfine radial operator: F(r, r_N) / r^{k+1}
35 @details
36 \f[
37 t^k_{\rm radial}[r_i] = \frac{F(r_i, r_N)}{r_i^{k+1}}
38 \f]
39
40 See \ref RadialFunction for the contract on F(r, r_N).
41 Angular factors and signs are handled elsewhere.
42
43 @param k Multipole rank (1 = M1, 2 = E2, ...)
44 @param rN Nuclear radius (a.u.); passed to @p hfs_F as r_N
45 @param r Radial grid points (a.u.)
46 @param hfs_F Nuclear magnetisation/charge distribution F(r, r_N);
47 see \ref RadialFunction and \ref sphericalBall_F
48 @return Radial values of t^k(r)
49*/
50std::vector<double> tk_radial(int k, double rN, const std::vector<double> &r,
51 const RadialFunction &hfs_F);
52
53//==============================================================================
54/*!
55 @brief Spherical ball model for F(r, r_N) [default]. Uniformly distributed point k-poles.
56 @details
57 Based on a simple multipole expansion, assuming the nucleus is composed of
58 uniformly distributed point k-poles. Note: not everyone defines this the same way.
59
60 \f[
61 F(r, r_N) =
62 \begin{cases}
63 (r/r_N)^{2k+1} & r < r_N \\
64 1 & r > r_N
65 \end{cases}
66 \f]
67*/
69
70//! Spherical shell F(r, r_N): 0 for r < r_N, 1 for r > r_N
72
73//! Pointlike F(r): F = 1 everywhere
75
76/*!
77 @brief Volotka single-particle nuclear model: F(r, rN)
78 @details
79 Calculates the Bohr-Weisskopf magnetisation distribution using the Volotka
80 single-particle model of Phys. Rev. Lett. 125, 063002 (2020).
81 Assumes radial nuclear density is a step function.
82 F goes to 1 as r_N -> 0. See \ref RadialFunction for F(r) contract.
83
84 @param mu Nuclear magnetic moment (in nuclear magnetons)
85 @param I_nuc Nuclear spin
86 @param l_pn Orbital angular momentum of valence nucleon
87 @param gl Orbital g-factor (1 = proton, 0 = neutron)
88 @param print Print model details
89
90 @return Radial function \f$ F_{\mathrm{BW}}(r, r_N) \f$
91*/
92RadialFunction VolotkaSP_F(double mu, double I_nuc, double l_pn, int gl,
93 bool print = true);
94
95/*!
96 @brief Elizarov single-particle magnetisation model [extended Volotka]
97 @details
98 Returns the radial magnetisation function F(r, r_N) for the model of
99 Elizarov, A. A. et al., Opt. Spectrosc. 100, 361 (2006).
100 Uses nuclear radial density u(r), with:
101
102 \f[
103 u(r) =
104 \begin{cases}
105 u_0 (R-r)^n & \text{u1(r)} \\
106 u_0 r^n & \text{u2(r)}
107 \end{cases}
108 \f]
109
110 n=0 should correspond to the Volotka model (see \ref VolotkaSP_F).
111 See \ref RadialFunction for F(r) contract.
112
113 @param mu Nuclear magnetic moment (in nuclear magnetons)
114 @param I_nuc Nuclear spin
115 @param l_pn Orbital angular momentum of valence nucleon
116 @param gl Orbital g-factor (1 = proton, 0 = neutron)
117 @param n Power; usually 0, 1, or 2. 0 => Volotka
118 @param R Nuclear radius
119 @param u_option Selects radial form: true for u1(r), false for u2(r)
120 @param print Print model details
121
122 @return Radial magnetisation function F(r, r_N)
123
124 @warning Normalisation is done by numerical integration; may be unstable.
125 Check that result returns to \ref VolotkaSP_F as n -> 0.
126*/
127RadialFunction uSP(double mu, double I_nuc, double l_pn, int gl, double n,
128 double R, bool u_option, bool print = true);
129
130//! Volotka single-particle model for doubly-odd nuclei
131/*! @details
132 From: [Phys. Rev. Lett. 125, 063002 (2020).](http://arxiv.org/abs/2001.01907)
133
134 Total magnetisation:
135 \f[
136 g F(r) = 0.5 \left[ g_1 F_1(r) + g_2 F_2(r)
137 + (g_1 F_1(r) - g_2 F_2(r)) K \right]
138 \f]
139
140 with
141
142 \f[
143 K = \frac{[ I_1(I_1+1) - I_2(I_2+1) ]}{[ I(I+1) ]}
144 \f]
145
146 Returns F(r) (i.e., divided by total g).
147
148 g2 is obtained from
149 g = 0.5 [ g1 + g2 + (g1 - g2) K ].
150
151 @note F1, F2 are the Volotka single-particle functions (see \ref VolotkaSP_F).
152
153 @param mut Total nuclear magnetic moment (in nuclear magnetons)
154 @param It Total nuclear spin
155 @param mu1 Magnetic moment of nucleon 1
156 @param I1 Spin of nucleon 1
157 @param l1 Orbital angular momentum of nucleon 1
158 @param gl1 Orbital g-factor of nucleon 1 (1 = proton, 0 = neutron)
159 @param I2 Spin of nucleon 2
160 @param l2 Orbital angular momentum of nucleon 2
161 @param print Print model details
162
163 @return Radial function F(r)
164*/
165RadialFunction doublyOddSP_F(double mut, double It, double mu1, double I1,
166 double l1, int gl1, double I2, double l2,
167 bool print = true);
168
169/*!
170 @brief Constructs F(r) from a numerical density rho(r) given on the radial grid.
171 @details
172 Computes the cumulative radial integral with rank-k weighting:
173
174 \f[
175 F(r) = N \int_0^r x^{2k} \rho(x)\, \d x, \qquad
176 N = \frac{1}{\int_0^\infty x^{2k} \rho(x)\, \d x}
177 \f]
178
179 so that \f$ F(r) \to 1 \f$ as \f$ r \to \infty \f$.
180
181 The x^{2k} weighting matches the radial scaling of the multipole operator of rank k
182 (consistent with \ref sphericalBall_F, where F ~ r^{2k+1} inside the nucleus).
183
184 The density @p rho need not be pre-normalised.
185 The returned function ignores its second argument (r_Nuc), since the
186 distribution is already encoded in @p rho. Assumes @p r is always a
187 grid point (no interpolation).
188
189 @param grid Radial grid on which @p rho is defined.
190 @param rho Nuclear density values on the grid points.
191 @param k Multipole rank (1 = M1, 2 = E2, ...)
192 @return Radial distribution function F(r, r_Nuc).
193*/
194RadialFunction generic_F(const Grid &grid, const std::vector<double> &rho,
195 int k);
196
197//------------------------------------------------------------------------------
198//! Converts reduced matrix element to A/B coeficients (takes k, 2J, 2J)
199double convert_RME_to_HFSconstant_2J(int k, int tja, int tjb);
200
201//! Converts reduced matrix element to A/B coeficients (takes k, kappa, kappa)
202double convert_RME_to_HFSconstant(int k, int ka, int kb);
203
204} // namespace Hyperfine
205
206//==============================================================================
207//==============================================================================
208//==============================================================================
209
210//! Generalised hyperfine-structure operator, including relevant nuclear moment
211/*! @details
212
213 Implements the nuclear multipole hyperfine operator of rank @p k using a
214 specified finite-nucleus radial model.
215
216 By default, includes the nuclear moment, and relevant factors.
217 Input parameter @p GQ is the g-factor (k=1) or nuclear moment (k>1),
218 in units of nuclear magnetons * barns^power.
219 If 'units' set to 'au', usually should set mu=I=Q=1 then to get raw t^k matrix elements.
220
221 That is, it calculates:
222
223 \f[
224 GQ * t^k
225 \f]
226
227 with:
228
229 \f[
230 t^k =
231 \frac{-1}{r^{k+1}}\,F(r)
232 \begin{cases}
233 C^k & \text{electric (even k)} \\
234 \sqrt{\frac{k+1}{k}}
235 \mathbf{\alpha}\!\cdot\!\mathbf{C}^{(0)}_k
236 & \text{magnetic (odd k)}
237 \end{cases}
238 \f]
239
240 where F(r) is nuclear k-pole distribution (=1 for pointlike).
241
242 Convert to hyperfine constant by taking stretched state, and multiply by:
243
244 \f[
245 M =
246 \begin{cases}
247 1/J & k = 1 \\
248 2 & k = 2 \\
249 -1 & k = 3 \\
250 1 & k \geq 4 \\
251 \end{cases}
252 \f]
253
254 This factor (including the steched 3j symbol) is returned by \ref Hyperfine::convert_RME_to_HFSconstant()
255
256 Units:
257 - Assumes nuclear moments in units of:
258 - magnetic moments: @f$\mu_N\, b^{(k-1)/2}@f$
259 - electric moments: @f$b^{k/2}@f$
260 - Matrix element are in MHz by default, otherwise in atomic units.
261
262 Here \f$ \mu_N \f$ is the nuclear magneton and \f$ b \f$ is the barn.
263
264 See, e.g., Xiao _et al._, [Phys. Rev. A 102, 022810 (2020).](http://arxiv.org/abs/2007.06798)
265
266 The radial part is constructed from \ref Hyperfine::tk_radial().
267
268 @note See @ref DiracOperator::Hyperfine for details
269*/
270class hfs final : public TensorOperator {
271 using RadialFunction = std::function<double(double, double)>;
272
273public:
274 //! @brief Constructs hyperfine operator of multipolarity k.
275 /*! @details
276 Initialises the hyperfine interaction operator.
277
278 @param in_k Tensor rank k (multipolarity) of the hyperfine interaction
279 (e.g., 1,2,3,... for M1, E2, M3,... etc.)
280 @param GQ Nuclear g-factor for k=1, general moment for k>1
281 @param rN_au Nuclear radius (a.u.), used for finite-size magnetisation models.
282 @param rgrid Radial grid used to define the radial functions.
283 @param hfs_F Radial magnetisation distribution function
284 (see @ref DiracOperator::Hyperfine).
285 @param MHzQ If true outputs in MHz units (assuming input g etc. in muN.barns); otherwise in raw atomic units (pure t^k matrix elements).
286
287 @see See also: \ref DiracOperator::Hyperfine
288 */
289 hfs(int in_k, double GQ, double rN_au, const Grid &rgrid,
290 const RadialFunction &hfs_F = Hyperfine::pointlike_F(), bool MHzQ = true)
291 : TensorOperator(in_k, Parity::even, GQ,
292 Hyperfine::tk_radial(in_k, rN_au, rgrid.r(), hfs_F)),
293 k(in_k),
294 magnetic(k % 2 != 0),
295 cfg(magnetic ? 1.0 : 0.0),
296 cff(magnetic ? 0.0 : 1.0),
297 mMHzQ(MHzQ) {
298
299 const auto power = magnetic ? (k - 1) / 2 : k / 2;
300
301 // Assumes nuclear moment in muN*b^(k-1)/2 for magnetic,
302 // and b^k/2 for electric
303 const auto unit_au =
304 magnetic ? PhysConst::muN_CGS * std::pow(PhysConst::barn_au, power) :
305 std::pow(PhysConst::barn_au, power);
306 m_unit = mMHzQ ? unit_au * PhysConst::Hartree_MHz : 1.0;
307 }
308
309 std::string name() const override final {
310 return "hfs" + std::to_string(k) + "";
311 }
312 std::string units() const override final { return mMHzQ ? "MHz" : "au"; }
313
314 double angularF(const int ka, const int kb) const override final {
315 return magnetic ? -double(ka + kb) / double(k) *
316 Angular::Ck_kk(k, ka, -kb) * m_unit :
317 -Angular::Ck_kk(k, ka, kb) * m_unit;
318 }
319
320 double angularCff(int, int) const override final { return cff; }
321 double angularCgg(int, int) const override final { return cff; }
322 double angularCfg(int, int) const override final { return cfg; }
323 double angularCgf(int, int) const override final { return cfg; }
324
325 static std::unique_ptr<TensorOperator> generate(const IO::InputBlock &input,
326 const Wavefunction &wf) {
327
328 input.check(
329 {{"", "Most following will be taken from the default nucleus if "
330 "not explicitely given"},
331 {"mu", "Magnetic moment in mu_N"},
332 {"Q", "Nuclear quadrupole moment, in barns. Also used as overall "
333 "constant for any higher-order moments [1.0]"},
334 {"k", "Multipolarity. 1=mag. dipole, 2=elec. quad, etc. [1]"},
335 {"rrms",
336 "nuclear (magnetic) rms radius, in Fermi (fm) (defult is charge rms)"},
337 {"units",
338 "Units for output (only for k=1,k=2). MHz or au. For MHz, "
339 "assumes nuclear moments g/Q are in mu_N*barns^p. For atomic "
340 "units, best to set g=Q=1 to get raw t^k matrix elements [MHz]"},
341 {"F", "F(r): Nuclear moment distribution: ball, point, shell, "
342 "SingleParticle, doublyOddSP, uSP, Fermi, or Gaussian [ball]"},
343 {"", "The following options are all for F(r) details. See "
344 "https://ampsci.dev for full details (search `hyperfine`)"},
345 {"printF", "Writes F(r) to a text file [false]"},
346 {"print", "Write F(r) info to screen [true]"},
347 {"", "The following are only for F=SingleParticle or doublyOddSP"},
348 {"I", "Nuclear spin. Taken from nucleus"},
349 {"parity", "Nulcear parity: +/-1"},
350 {"l", "l for unpaired nucleon (automatically derived from I and "
351 "parity; best to leave as default)"},
352 {"gl", "=1 for proton, =0 for neutron"},
353 {"", "The following are only used if F=doublyOddSP"},
354 {"mu1", "mag moment of 'first' unpaired nucleon"},
355 {"gl1", "gl of 'first' unpaired nucleon"},
356 {"l1", "l of 'first' unpaired nucleon"},
357 {"l2", "l of 'second' unpaired nucleon"},
358 {"I1", "total spin (J) of 'first' unpaired nucleon"},
359 {"I2", "total spin (J) of 'second' unpaired nucleon"},
360 {"", "The following are only for u(r) function (F=uSP)"},
361 {"u", "u1 or u2 : u1(r) = (R-r)^n, u2(r) = r^n [u1]"},
362 {"n", "n that appears above. Should be between 0 and 2 [0]"},
363 {"", "The following are only for Fermi function (F=Fermi)"},
364 {"t",
365 "skin thickness (normally 2.3). note: c taken from wavefunction, or "
366 "from rrms above [2.3]"}});
367 if (input.has_option("help")) {
368 return nullptr;
369 }
370
371 const auto nuc = wf.nucleus();
372 const auto isotope = Nuclear::findIsotopeData(nuc.z(), nuc.a());
373
374 auto mu = input.get("mu", isotope.mu ? *isotope.mu : 1.0);
375 auto I_nuc = input.get("I", isotope.I_N ? *isotope.I_N : 1.0);
376 const auto print = input.get("print", true);
377 const auto k = input.get("k", 1);
378
379 const auto use_MHz =
380 qip::ci_compare(input.get<std::string>("units", "MHz"), "MHz");
381
382 if (k <= 0) {
383 fmt2::styled_print(fg(fmt::color::red), "\nError 246:\n");
384 std::cout << "In hyperfine: invalid K=" << k << "! meaningless results\n";
385 }
386 if (I_nuc <= 0 && k == 1) {
387 fmt2::styled_print(fg(fmt::color::orange), "\nWarning 253:\n");
388 std::cout << "In hyperfine: invalid I_nuc=" << I_nuc
389 << "! meaningless results\nSetting I=1\n";
390 I_nuc = 1;
391 }
392 if (mu == 0.0 && k == 1) {
393 fmt2::styled_print(fg(fmt::color::orange), "\nWarning 352:\n");
394 std::cout << "Setting mu=1\n";
395 mu = 1;
396 }
397
398 const auto g_or_Q =
399 (k == 1) ? (mu / I_nuc) :
400 (k == 2) ? input.get("Q", isotope.q ? *isotope.q : 1.0) :
401 input.get("Q", 1.0);
402
403 enum class DistroType {
404 point,
405 ball,
406 shell,
407 SingleParticle,
408 doublyOddSP,
409 uSP,
410 Fermi,
411 Gaussian,
412 Error
413 };
414
415 const std::string default_distribution = "ball";
416
417 // For compatability with old notation of 'F(r)' input option
418 const auto Fr_str =
419 input.has_option("F") ?
420 input.get<std::string>("F", default_distribution) :
421 input.has_option("nuc_mag") ?
422 input.get<std::string>("nuc_mag", default_distribution) :
423 input.get<std::string>("F(r)", default_distribution);
424
425 const auto distro_type =
426 (qip::ci_wc_compare(Fr_str, "point*") || qip::ci_compare(Fr_str, "1")) ?
427 DistroType::point :
428 qip::ci_compare(Fr_str, "ball") ? DistroType::ball :
429 qip::ci_compare(Fr_str, "shell") ? DistroType::shell :
430 qip::ci_wc_compare(Fr_str, "Single*") ? DistroType::SingleParticle :
431 qip::ci_wc_compare(Fr_str, "doublyOdd*") ? DistroType::doublyOddSP :
432 (qip::ci_compare(Fr_str, "spu") || qip::ci_compare(Fr_str, "uSP")) ?
433 DistroType::uSP :
434 qip::ci_wc_compare(Fr_str, "Fermi*") ? DistroType::Fermi :
435 qip::ci_wc_compare(Fr_str, "Gauss*") ? DistroType::Gaussian :
436 DistroType::Error;
437 if (distro_type == DistroType::Error) {
438 fmt2::styled_print(fg(fmt::color::red), "\nError 271:\n");
439 std::cout << "\nIn hyperfine. Unkown F(r) - " << Fr_str << "\n";
440 std::cout << "Defaulting to pointlike!\n";
441 }
442
443 const auto r_rmsfm =
444 distro_type == DistroType::point ? 0.0 : input.get("rrms", nuc.r_rms());
445 const auto r_nucfm = std::sqrt(5.0 / 3) * r_rmsfm;
446 const auto r_nucau = r_nucfm / PhysConst::aB_fm;
447
448 if (print) {
449 std::cout << "\nHyperfine structure: " << wf.atom() << "\n";
450 std::cout << "K=" << k << " ("
451 << (k == 1 ? "magnetic dipole" :
452 k == 2 ? "electric quadrupole" :
453 k % 2 == 0 ? "electric multipole" :
454 "magnetic multipole")
455 << ")\n";
456 std::cout << "Using " << Fr_str << " nuclear distro for F(r)\n"
457 << "w/ r_N = " << r_nucfm << "fm = " << r_nucau
458 << "au (r_rms=" << r_rmsfm << "fm)\n";
459 std::cout << "Points inside nucleus: " << wf.grid().getIndex(r_nucau)
460 << "\n";
461 if (k == 1) {
462 std::cout << "mu = " << mu << ", I = " << I_nuc << ", g = " << g_or_Q
463 << "\n";
464 } else {
465 std::cout << "Q = " << g_or_Q << "\n";
466 }
467 }
468
469 // default is BALL:
470 auto Fr = Hyperfine::sphericalBall_F(k); // should never be used
471
472 if (distro_type == DistroType::ball) {
474
475 } else if (distro_type == DistroType::shell) {
477
478 } else if (distro_type == DistroType::SingleParticle) {
479 const auto pi = input.get("parity", isotope.parity ? *isotope.parity : 0);
480 const auto l_tmp = int(I_nuc + 0.5 + 0.0001);
481 auto l = ((l_tmp % 2 == 0) == (pi == 1)) ? l_tmp : l_tmp - 1;
482 l = input.get("l", l); // can override derived 'l' (not recommended)
483 const auto gl_default = wf.Znuc() % 2 == 0 ? 0 : 1; // unparied proton?
484 const auto gl = input.get<int>("gl", gl_default);
485 if (print) {
486 std::cout << "Single-Particle (Volotka formula) for unpaired";
487 if (gl == 1)
488 std::cout << " proton ";
489 else if (gl == 0)
490 std::cout << " neturon ";
491 else
492 std::cout << " gl=" << gl
493 << "??? program will run, but prob wrong!\n";
494 std::cout << "with l=" << l << " (pi=" << pi << ")\n";
495 }
496 Fr = Hyperfine::VolotkaSP_F(mu, I_nuc, l, gl, print);
497
498 } else if (distro_type == DistroType::uSP) {
499 const auto pi = input.get("parity", isotope.parity ? *isotope.parity : 0);
500 const auto u_func =
501 input.get("u", std::string{"u1"}); // u1=(R-r)^n, u2=r^n
502 const bool u_option = u_func == std::string{"u1"};
503 const auto n = input.get("n", 1.0); // u1=(R-r)^n, u2=r^n
504 const auto l_tmp = int(I_nuc + 0.5 + 0.0001);
505 auto l = ((l_tmp % 2 == 0) == (pi == 1)) ? l_tmp : l_tmp - 1;
506 l = input.get("l", l); // can override derived 'l' (not recommended)
507 const auto gl_default = wf.Znuc() % 2 == 0 ? 0 : 1; // unparied proton?
508 const auto gl = input.get<int>("gl", gl_default);
509 if (print) {
510 std::cout << "Single-Particle (Volotka formula) with u(r) for unpaired";
511 if (gl == 1)
512 std::cout << " proton ";
513 else if (gl == 0)
514 std::cout << " neturon ";
515 else
516 std::cout << " gl=" << gl
517 << "??? program will run, but prob wrong!\n";
518 std::cout << "with l=" << l << " (pi=" << pi << ")\n";
519 }
520 if (print) {
521 std::cout << "u(r) = " << u_func << ": "
522 << (u_option ? "(R-r)^n" : "r^n") << ", n=" << n << "\n";
523 }
524 Fr = Hyperfine::uSP(mu, I_nuc, l, gl, n, r_nucau, u_option, print);
525
526 } else if (distro_type == DistroType::doublyOddSP) {
527 const auto mu1 = input.get<double>("mu1", 1.0);
528 const auto gl1 = input.get<int>("gl1", -1); // 1 or 0 (p or n)
529 if (gl1 != 0 && gl1 != 1) {
530 fmt2::styled_print(fg(fmt::color::red), "\nError 324:\n");
531 std::cout << "In " << input.name() << " " << Fr_str
532 << "; have gl1=" << gl1 << " but need 1 or 0\n";
533 return std::make_unique<NullOperator>(NullOperator());
534 }
535 const auto l1 = input.get<double>("l1", -1.0);
536 const auto l2 = input.get<double>("l2", -1.0);
537 const auto I1 = input.get<double>("I1", -1.0);
538 const auto I2 = input.get<double>("I2", -1.0);
539
540 Fr = Hyperfine::doublyOddSP_F(mu, I_nuc, mu1, I1, l1, gl1, I2, l2, print);
541
542 } else if (distro_type == DistroType::Fermi) {
543 const auto t_fm = input.get("t", nuc.t());
544 const auto c_fm = Nuclear::c_hdr_formula_rrms_t(r_rmsfm, t_fm);
545 if (print)
546 std::cout << "Fermi distro: c=" << c_fm << " fm, t=" << t_fm << " fm\n";
547 const auto rho =
548 Nuclear::fermiNuclearDensity_tcN(t_fm, c_fm, 1.0, wf.grid());
549 Fr = Hyperfine::generic_F(wf.grid(), rho, k);
550
551 } else if (distro_type == DistroType::Gaussian) {
552 const auto rN_au = r_rmsfm / PhysConst::aB_fm;
553 if (print)
554 std::cout << "Gaussian distro: r_rms=" << r_rmsfm << " fm\n";
555 std::vector<double> rho;
556 rho.reserve(wf.grid().num_points());
557 for (const auto ri : wf.grid().r()) {
558 rho.push_back(std::exp(-1.5 * ri * ri / (rN_au * rN_au)));
559 }
560 Fr = Hyperfine::generic_F(wf.grid(), rho, k);
561 } else if (distro_type == DistroType::Error) {
562 std::cout << "Using pointlike F(r):\n";
564 }
565
566 // Optionally print F(r) function to file
567 if (input.get<bool>("printF", false)) {
568 std::ofstream of(wf.identity() + "_" + Fr_str + ".txt");
569 of << "r/fm F(r)\n";
570 for (auto r : wf.grid()) {
571 of << r * PhysConst::aB_fm << " "
572 << Fr(r * PhysConst::aB_fm, r_nucau * PhysConst::aB_fm) << "\n";
573 }
574 }
575
576 return std::make_unique<hfs>(k, g_or_Q, r_nucau, wf.grid(), Fr, use_MHz);
577 }
578
579private:
580 int k;
581 bool magnetic;
582 double cfg;
583 double cff;
584 bool mMHzQ;
585 double m_unit{1.0};
586};
587
588} // namespace DiracOperator
General tensor operator (virtual base class); all single-particle (one-body) tenosor operators derive...
Definition TensorOperator.hpp:198
Generalised hyperfine-structure operator, including relevant nuclear moment.
Definition hfs.hpp:270
double angularCgg(int, int) const override final
Angular coefficient C_gg for the g_a*g_b term of the radial integral.
Definition hfs.hpp:321
double angularCgf(int, int) const override final
Angular coefficient C_gf for the g_a*f_b term of the radial integral.
Definition hfs.hpp:323
double angularCfg(int, int) const override final
Angular coefficient C_fg for the f_a*g_b term of the radial integral.
Definition hfs.hpp:322
std::string units() const override final
Returns units of operator as a string (usually au, may be MHz, etc.)
Definition hfs.hpp:312
std::string name() const override final
Returns "name" of operator (e.g., 'E1')
Definition hfs.hpp:309
hfs(int in_k, double GQ, double rN_au, const Grid &rgrid, const RadialFunction &hfs_F=Hyperfine::pointlike_F(), bool MHzQ=true)
Constructs hyperfine operator of multipolarity k.
Definition hfs.hpp:289
double angularF(const int ka, const int kb) const override final
Angular factor A_ab linking the radial integral to the RME.
Definition hfs.hpp:314
double angularCff(int, int) const override final
Angular coefficient C_ff for the f_a*f_b term of the radial integral.
Definition hfs.hpp:320
Non-uniform radial grid with Jacobian, suitable for atomic structure calculations.
Definition Grid.hpp:85
auto num_points() const
Number of grid points.
Definition Grid.hpp:120
std::size_t getIndex(double x, bool require_nearest=false) const
Returns the grid index closest to x. If require_nearest is false, returns the index of the largest gr...
Definition Grid.cpp:76
Holds a named list of key=value options and nested InputBlocks.
Definition InputBlock.hpp:154
bool check(std::initializer_list< std::string > blocks, const std::vector< std::pair< std::string, std::string > > &list, bool print=false) const
Validates options and sub-blocks against an allowed list.
Definition InputBlock.hpp:649
std::string_view name() const
Returns the name of this block.
Definition InputBlock.hpp:210
bool has_option(std::string_view key) const
Returns true if key is present in this block's option list, even if unset.
Definition InputBlock.hpp:247
T get(std::string_view key, T default_value) const
Returns the value of key, or default_value if not found.
Definition InputBlock.hpp:471
Stores Wavefunction (set of valence orbitals, grid, HF etc.)
Definition Wavefunction.hpp:37
const Grid & grid() const
Returns a const reference to the radial grid.
Definition Wavefunction.hpp:82
int Znuc() const
Nuclear charge, Z.
Definition Wavefunction.hpp:99
std::string identity() const
Atomic symbol, including core ionisation degree and run_label.
Definition Wavefunction.cpp:690
std::string atom() const
String of atom info (e.g., "Cs, Z=55, A=133")
Definition Wavefunction.hpp:190
const Nuclear::Nucleus & nucleus() const
Returns Nuclear::nucleus object (contains nuc. parameters)
Definition Wavefunction.hpp:97
double Ck_kk(int k, int ka, int kb)
Reduced relativistic angular ME: <ka||C^k||kb>. Takes kappa values.
Definition Wigner369j.hpp:486
double convert_RME_to_HFSconstant_2J(int k, int tja, int tjb)
Converts reduced matrix element to A/B coeficients (takes k, 2J, 2J)
Definition hfs.cpp:206
RadialFunction doublyOddSP_F(double mut, double It, double mu1, double I1, double l1, int gl1, double I2, double l2, bool print)
Volotka single-particle model for doubly-odd nuclei.
Definition hfs.cpp:150
std::vector< double > tk_radial(int k, double rN, const std::vector< double > &r, const RadialFunction &hfs_F)
Forms the hyperfine radial operator: F(r, r_N) / r^{k+1}.
Definition hfs.cpp:14
double convert_RME_to_HFSconstant(int k, int ka, int kb)
Converts reduced matrix element to A/B coeficients (takes k, kappa, kappa)
Definition hfs.cpp:240
RadialFunction pointlike_F()
Pointlike F(r): F = 1 everywhere.
Definition hfs.cpp:38
RadialFunction sphericalBall_F(int k)
Spherical ball model for F(r, r_N) [default]. Uniformly distributed point k-poles.
Definition hfs.cpp:26
RadialFunction sphericalShell_F()
Spherical shell F(r, r_N): 0 for r < r_N, 1 for r > r_N.
Definition hfs.cpp:33
RadialFunction generic_F(const Grid &grid, const std::vector< double > &rho, int k)
Constructs F(r) from a numerical density rho(r) given on the radial grid.
Definition hfs.cpp:168
RadialFunction uSP(double mu, double I_nuc, double l_pn, int gl, double n, double R, bool u_option, bool print)
Elizarov single-particle magnetisation model [extended Volotka].
Definition hfs.cpp:81
std::function< double(double r, double r_Nuc)> RadialFunction
Type for radial function F(r, r_Nuc) – nuclear magnetisation/charge distribution.
Definition hfs.hpp:30
RadialFunction VolotkaSP_F(double mu, double I_nuc, double l_pn, int gl, bool print)
Volotka single-particle nuclear model: F(r, rN)
Definition hfs.cpp:44
Dirac operators: TensorOperator base class and derived implementations for single-particle (one-body)...
Definition GenerateOperator.cpp:6
Parity
Parity of operator.
Definition TensorOperator.hpp:57
double c_hdr_formula_rrms_t(double rrms, double t)
Calculates c from rrms and t.
Definition NuclearData.cpp:73
Isotope findIsotopeData(int z, int a)
Looks up + returns an isotope from the list. If not in list, partially blank.
Definition NuclearData.cpp:6
std::vector< double > fermiNuclearDensity_tcN(double t, double c, double Z_norm, const Grid &grid)
Fermi charge distribution, rho(r) - normalised to Z_norm.
Definition NuclearPotentials.cpp:319
constexpr double muN_CGS
Nulcear magneton (in Gaussian CGS-derived atomic units):
Definition PhysConst_constants.hpp:101
General-purpose utility library.
Definition Array.hpp:23
bool ci_wc_compare(std::string_view s1, std::string_view s2)
Case-insensitive version of wildcard_compare.
Definition String.hpp:155
bool ci_compare(std::string_view s1, std::string_view s2)
Case-insensitive string comparison; equivalent to tolower(s1) == tolower(s2).
Definition String.hpp:143