Quantum Phenomena Explorer 7.9.8
Interactive quantum-phenomena Explorer Tutor — source documentation
Loading...
Searching...
No Matches
quantumkleinanglescan2d.cpp
Go to the documentation of this file.
1/**
2 * @file quantumkleinanglescan2d.cpp
3 * @brief Implements the quantumkleinanglescan2d physics/numerical component used by QPE experiments.
4 * @ingroup qpe_quantum
5 *
6 * Source: @c core/quantum/quantumkleinanglescan2d.cpp. This file is part of Quantum Phenomena Explorer (QPE),
7 * maintained by Officina Turini. See LICENSE_IT.txt / LICENSE.txt for the
8 * QPE freeware source-available terms and THIRD_PARTY_NOTICES.txt for
9 * third-party components.
10 */
11
13
14#include <algorithm>
15#include <array>
16#include <cmath>
17#include <complex>
18
19namespace qpe {
20namespace {
21
22constexpr double kPi = 3.141592653589793238462643383279502884;
23using C = std::complex<double>;
24using Vec2 = std::array<C, 2>;
25using Matrix4 = std::array<std::array<C, 4>, 4>;
26using Vector4 = std::array<C, 4>;
27
28/**
29 * @brief Performs finite.
30 * @param x X coordinate/value.
31 */
32bool finite(double x) noexcept { return std::isfinite(x); }
33
34/**
35 * @brief Performs eigen spinor.
36 * @param px The px value used by the operation.
37 * @param py The py value used by the operation.
38 * @param relativeEnergy The relative energy value used by the operation.
39 * @param lightSpeed The light speed value used by the operation.
40 * @param restEnergy The rest energy value used by the operation.
41 */
42Vec2 eigenSpinor(const C &px, double py, double relativeEnergy,
43 double lightSpeed, double restEnergy) noexcept
44{
45 const C denom(relativeEnergy + restEnergy, 0.0);
46 if (std::abs(denom) > 1.0e-12) {
47 return Vec2{{C(1.0, 0.0), lightSpeed * (px + C(0.0, py)) / denom}};
48 }
49
50 const C alternate(relativeEnergy - restEnergy, 0.0);
51 if (std::abs(alternate) > 1.0e-12) {
52 return Vec2{{lightSpeed * (px - C(0.0, py)) / alternate, C(1.0, 0.0)}};
53 }
54 return Vec2{{C(1.0, 0.0), C(0.0, 0.0)}};
55}
56
57/**
58 * @brief Performs solve4x4.
59 * @param a The a value used by the operation.
60 * @param b The b value used by the operation.
61 * @param x X coordinate/value.
62 */
63bool solve4x4(Matrix4 a, Vector4 b, Vector4 &x) noexcept
64{
65 for (int col = 0; col < 4; ++col) {
66 int pivot = col;
67 double best = std::abs(a[static_cast<std::size_t>(col)][static_cast<std::size_t>(col)]);
68 for (int row = col + 1; row < 4; ++row) {
69 const double candidate = std::abs(a[static_cast<std::size_t>(row)][static_cast<std::size_t>(col)]);
70 if (candidate > best) {
71 best = candidate;
72 pivot = row;
73 }
74 }
75 if (!(best > 1.0e-14) || !finite(best)) return false;
76 if (pivot != col) {
77 std::swap(a[static_cast<std::size_t>(pivot)], a[static_cast<std::size_t>(col)]);
78 std::swap(b[static_cast<std::size_t>(pivot)], b[static_cast<std::size_t>(col)]);
79 }
80
81 const C diag = a[static_cast<std::size_t>(col)][static_cast<std::size_t>(col)];
82 for (int j = col; j < 4; ++j)
83 a[static_cast<std::size_t>(col)][static_cast<std::size_t>(j)] /= diag;
84 b[static_cast<std::size_t>(col)] /= diag;
85
86 for (int row = 0; row < 4; ++row) {
87 if (row == col) continue;
88 const C f = a[static_cast<std::size_t>(row)][static_cast<std::size_t>(col)];
89 if (std::abs(f) == 0.0) continue;
90 for (int j = col; j < 4; ++j)
91 a[static_cast<std::size_t>(row)][static_cast<std::size_t>(j)] -=
92 f * a[static_cast<std::size_t>(col)][static_cast<std::size_t>(j)];
93 b[static_cast<std::size_t>(row)] -= f * b[static_cast<std::size_t>(col)];
94 }
95 }
96 x = b;
97 return true;
98}
99
100/**
101 * @brief Performs rotated config.
102 * @param base The base value used by the operation.
103 * @param angleDegrees The angle degrees value used by the operation.
104 */
106 double angleDegrees) noexcept
107{
110 const double theta = angleDegrees * kPi / 180.0;
111 c.momentumX = p * std::cos(theta);
112 c.momentumY = p * std::sin(theta);
113 return c;
114}
115
116} // namespace
117
119 const QuantumKleinTunneling2DConfig &baseConfig, double angleDegrees, double hbar) noexcept
120{
122 out.angleDegrees = angleDegrees;
123
124 if (!QuantumKleinTunneling2D::validateConfig(baseConfig, nullptr) ||
125 !finite(angleDegrees) || angleDegrees < 0.0 || angleDegrees >= 89.9 ||
126 !finite(hbar) || hbar <= 0.0) {
127 return out;
128 }
129
130 const QuantumKleinTunneling2DConfig c = rotatedConfig(baseConfig, angleDegrees);
134
136 const double theta = angleDegrees * kPi / 180.0;
137 const double px = p * std::cos(theta);
138 const double py = p * std::sin(theta);
139 if (!(px > 1.0e-10)) return out;
140
141 const double cc = c.lightSpeed;
142 const double rest = c.restMass * cc * cc;
143 const double e = QuantumKleinTunneling2D::incidentEnergy(c);
144 const double er = e - c.barrierHeight;
145 const C qx = std::sqrt(C(out.interiorLongitudinalMomentumSquared, 0.0));
146
147 const Vec2 incident = eigenSpinor(C(px, 0.0), py, e, cc, rest);
148 const Vec2 reflected = eigenSpinor(C(-px, 0.0), py, e, cc, rest);
149 const Vec2 barrierForward = eigenSpinor(qx, py, er, cc, rest);
150 const Vec2 barrierBackward = eigenSpinor(-qx, py, er, cc, rest);
151 const Vec2 transmitted = incident;
152
153 const C phaseBarrierForward = std::exp(C(0.0, 1.0) * qx * c.barrierWidth / hbar);
154 const C phaseBarrierBackward = std::exp(C(0.0, -1.0) * qx * c.barrierWidth / hbar);
155 const C phaseTransmitted = std::exp(C(0.0, px * c.barrierWidth / hbar));
156
157 Matrix4 a{};
158 Vector4 b{};
159 for (int component = 0; component < 2; ++component) {
160 const std::size_t k = static_cast<std::size_t>(component);
161 a[k][0] = reflected[k];
162 a[k][1] = -barrierForward[k];
163 a[k][2] = -barrierBackward[k];
164 a[k][3] = C(0.0, 0.0);
165 b[k] = -incident[k];
166
167 a[k + 2u][0] = C(0.0, 0.0);
168 a[k + 2u][1] = barrierForward[k] * phaseBarrierForward;
169 a[k + 2u][2] = barrierBackward[k] * phaseBarrierBackward;
170 a[k + 2u][3] = -transmitted[k] * phaseTransmitted;
171 b[k + 2u] = C(0.0, 0.0);
172 }
173
174 Vector4 solution{};
175 if (!solve4x4(a, b, solution)) return out;
176
177 const double r = std::norm(solution[0]);
178 const double t = std::norm(solution[3]);
179 if (!finite(r) || !finite(t)) return out;
180
181 // Left and right asymptotic media are identical, so the Dirac flux ratio
182 // reduces to |amplitude|^2 for the reflected/transmitted coefficients.
183 out.reflection = std::max(0.0, std::min(1.0, r));
184 out.transmission = std::max(0.0, std::min(1.0, t));
185 out.valid = true;
186 return out;
187}
188
190 const QuantumKleinTunneling2DConfig &baseConfig,
191 double minimumAngleDegrees, double maximumAngleDegrees,
192 int samples, double hbar) noexcept
193{
195 if (!QuantumKleinTunneling2D::validateConfig(baseConfig, nullptr) ||
196 !finite(minimumAngleDegrees) || !finite(maximumAngleDegrees) ||
197 minimumAngleDegrees < 0.0 || maximumAngleDegrees <= minimumAngleDegrees ||
198 maximumAngleDegrees >= 89.9 || samples < 2 || samples > 721 ||
199 !finite(hbar) || hbar <= 0.0) {
200 return out;
201 }
202
203 out.hbar = hbar;
206 out.barrierHeight = baseConfig.barrierHeight;
207 out.barrierWidth = baseConfig.barrierWidth;
208 out.minimumAngleDegrees = minimumAngleDegrees;
209 out.maximumAngleDegrees = maximumAngleDegrees;
210 out.points.reserve(static_cast<std::size_t>(samples));
211
212 bool allValid = true;
213 for (int i = 0; i < samples; ++i) {
214 const double f = static_cast<double>(i) / static_cast<double>(samples - 1);
215 const double angle = minimumAngleDegrees + f * (maximumAngleDegrees - minimumAngleDegrees);
216 const QuantumKleinAnglePoint2D point = evaluate(baseConfig, angle, hbar);
217 allValid = allValid && point.valid;
218 out.points.push_back(point);
219 }
220 out.valid = allValid && out.points.size() == static_cast<std::size_t>(samples);
221 return out;
222}
223
224} // namespace qpe
static QuantumKleinAngleScan2DResult scan(const QuantumKleinTunneling2DConfig &baseConfig, double minimumAngleDegrees=0.0, double maximumAngleDegrees=70.0, int samples=71, double hbar=1.0) noexcept
Performs scan.
static QuantumKleinAnglePoint2D evaluate(const QuantumKleinTunneling2DConfig &baseConfig, double angleDegrees, double hbar=1.0) noexcept
Performs evaluate.
static double incidentEnergy(const QuantumKleinTunneling2DConfig &config) noexcept
Performs incident energy.
static double interiorLongitudinalMomentumSquared(const QuantumKleinTunneling2DConfig &config) noexcept
Performs interior longitudinal momentum squared.
static double incidentMomentumMagnitude(const QuantumKleinTunneling2DConfig &config) noexcept
Performs incident momentum magnitude.
static bool validateConfig(const QuantumKleinTunneling2DConfig &config, std::string *reason=nullptr) noexcept
Validates config.
static QuantumKleinBarrierRegime2D classifyBarrierRegime(const QuantumKleinTunneling2DConfig &config) noexcept
Performs classify barrier regime.
bool solve4x4(Matrix4 a, Vector4 b, Vector4 &x) noexcept
Performs solve4x4.
QuantumKleinTunneling2DConfig rotatedConfig(const QuantumKleinTunneling2DConfig &base, double angleDegrees) noexcept
Performs rotated config.
Vec2 eigenSpinor(const C &px, double py, double relativeEnergy, double lightSpeed, double restEnergy) noexcept
Performs eigen spinor.
Declares the quantumkleinanglescan2d physics/numerical component used by QPE experiments.
Data structure used by the Quantum Klein Angle Point2D component.
QuantumKleinBarrierRegime2D regime
Data record containing Quantum Klein Angle Scan2D Result.
std::vector< QuantumKleinAnglePoint2D > points
Configuration values for Quantum Klein Tunneling2D Config.