Quantum Phenomena Explorer 7.9.8
Interactive quantum-phenomena Explorer Tutor — source documentation
Loading...
Searching...
No Matches
probabilitycurrent2d_tests.cpp
Go to the documentation of this file.
1/**
2 * @file probabilitycurrent2d_tests.cpp
3 * @brief Implements regression and invariant tests for probabilitycurrent2d tests.
4 * @ingroup qpe_tests
5 *
6 * Source: @c tests/probabilitycurrent2d_tests.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
15
16#include <cmath>
17#include <exception>
18
19namespace qpe {
20namespace tests {
21
22/**
23 * @brief Runs probability current2 d tests.
24 * @param error Output diagnostic text on failure.
25 */
26bool runProbabilityCurrent2DTests(std::string &error)
27{
28 error.clear();
29
30 try {
31 // A real constant field has zero phase gradient and therefore J=0.
32 ComplexField2D constantField(32, 24, 0.1f, 0.1f);
33 constantField.fill(ComplexField2D::Value(1.0f, 0.0f));
34 const ProbabilityCurrentField2D zeroCurrent =
35 ProbabilityCurrent2D::compute(constantField, 1.0f, 1.0f);
36 if (zeroCurrent.maxMagnitude > 1.0e-6f ||
37 std::abs(zeroCurrent.integratedX) > 1.0e-8 ||
38 std::abs(zeroCurrent.integratedY) > 1.0e-8) {
39 error = "real constant field must have zero probability current";
40 return false;
41 }
42
43 // Plane wave exp(i k x): the centred finite difference gives
44 // Jx = |psi|^2 (hbar/m) sin(k dx)/dx in the interior.
45 const std::size_t width = 96;
46 const std::size_t height = 48;
47 const float dx = 0.05f;
48 const float dy = 0.05f;
49 const double k = 1.4;
50 ComplexField2D plane(width, height, dx, dy);
51 for (std::size_t y = 0; y < height; ++y) {
52 for (std::size_t x = 0; x < width; ++x) {
53 const double phase = k * static_cast<double>(x) * dx;
54 plane(x, y) = ComplexField2D::Value(
55 static_cast<float>(std::cos(phase)),
56 static_cast<float>(std::sin(phase)));
57 }
58 }
59 plane.normalize();
60
61 const float hbar = 1.0f;
62 const float mass = 2.0f;
63 const ProbabilityCurrentField2D current =
64 ProbabilityCurrent2D::compute(plane, hbar, mass);
65
66 const std::size_t cx = width / 2;
67 const std::size_t cy = height / 2;
68 const std::size_t ci = cy * width + cx;
69 const double probability = std::norm(std::complex<double>(
70 static_cast<double>(plane(cx, cy).real()),
71 static_cast<double>(plane(cx, cy).imag())));
72 const double expected = probability *
73 (static_cast<double>(hbar) / static_cast<double>(mass)) *
74 std::sin(k * dx) / dx;
75
76 if (std::abs(static_cast<double>(current.jx[ci]) - expected) > 2.0e-5) {
77 error = "plane-wave Jx does not match the finite-difference reference";
78 return false;
79 }
80 if (std::abs(current.jy[ci]) > 1.0e-6f) {
81 error = "plane wave along X must have Jy approximately zero";
82 return false;
83 }
84 if (!(current.maxMagnitude > 0.0f) || !(current.integratedX > 0.0)) {
85 error = "positive-k plane wave must carry positive integrated X current";
86 return false;
87 }
88
89 // The gauge-covariant expression must reduce to the ordinary current
90 // when every Peierls link is the identity.
91 U1GaugeField2D identityGauge(width, height, dx, dy);
92 const ProbabilityCurrentField2D gaugeCurrent =
93 ProbabilityCurrent2D::computeGaugeCovariant(plane, identityGauge, hbar, mass);
94 if (std::abs(static_cast<double>(gaugeCurrent.jx[ci]) -
95 static_cast<double>(current.jx[ci])) > 2.0e-7 ||
96 std::abs(static_cast<double>(gaugeCurrent.jy[ci]) -
97 static_cast<double>(current.jy[ci])) > 2.0e-7 ||
98 std::abs(gaugeCurrent.integratedX - current.integratedX) > 2.0e-7 ||
99 std::abs(gaugeCurrent.integratedY - current.integratedY) > 2.0e-7) {
100 error = "identity-gauge current must match the ordinary current";
101 return false;
102 }
103
104
105 // Local U(1) gauge transformation: psi -> exp(i chi) psi and
106 // U_ij -> exp(i chi_i) U_ij exp(-i chi_j). The physical current
107 // must remain unchanged.
108 ComplexField2D transformed = plane;
109 U1GaugeField2D transformedGauge(width, height, dx, dy);
110 const double ax = 0.17;
111 const double ay = -0.11;
112 for (std::size_t y = 0; y < height; ++y) {
113 for (std::size_t x = 0; x < width; ++x) {
114 const double chi = ax * static_cast<double>(x) + ay * static_cast<double>(y);
115 const std::complex<float> phase(static_cast<float>(std::cos(chi)),
116 static_cast<float>(std::sin(chi)));
117 transformed(x, y) *= phase;
118 if (x + 1u < width) {
119 const double dchi = chi - (ax * static_cast<double>(x + 1u) + ay * static_cast<double>(y));
120 transformedGauge.setLinkX(x, y, U1GaugeField2D::Link(
121 static_cast<float>(std::cos(dchi)), static_cast<float>(std::sin(dchi))));
122 }
123 if (y + 1u < height) {
124 const double dchi = chi - (ax * static_cast<double>(x) + ay * static_cast<double>(y + 1u));
125 transformedGauge.setLinkY(x, y, U1GaugeField2D::Link(
126 static_cast<float>(std::cos(dchi)), static_cast<float>(std::sin(dchi))));
127 }
128 }
129 }
130 const ProbabilityCurrentField2D invariantCurrent =
131 ProbabilityCurrent2D::computeGaugeCovariant(transformed, transformedGauge, hbar, mass);
132 if (std::abs(static_cast<double>(invariantCurrent.jx[ci]) -
133 static_cast<double>(current.jx[ci])) > 3.0e-6 ||
134 std::abs(static_cast<double>(invariantCurrent.jy[ci]) -
135 static_cast<double>(current.jy[ci])) > 3.0e-6 ||
136 std::abs(invariantCurrent.integratedX - current.integratedX) > 3.0e-6 ||
137 std::abs(invariantCurrent.integratedY - current.integratedY) > 3.0e-6) {
138 error = "gauge-covariant probability current is not U(1) invariant";
139 return false;
140 }
141 } catch (const std::exception &e) {
142 error = e.what();
143 return false;
144 }
145
146 return true;
147}
148
149} // namespace tests
150} // namespace qpe
Owning Cartesian grid of complex scalar samples.
void fill(const Value &value)
Assigns one complex value to every grid sample.
bool normalize() noexcept
Scales the field to unit discrete probability norm.
std::complex< float > Value
static ProbabilityCurrentField2D compute(const ComplexField2D &field, float hbar, float mass)
Performs compute.
static ProbabilityCurrentField2D computeGaugeCovariant(const ComplexField2D &field, const U1GaugeField2D &gauge, float hbar, float mass)
Computes gauge covariant.
Discrete U(1) gauge connection for gauge-covariant Schrodinger experiments.
void setLinkY(std::size_t x, std::size_t y, Link value) noexcept
Assigns the +Y link at a lattice site.
void setLinkX(std::size_t x, std::size_t y, Link value) noexcept
Assigns the +X link at a lattice site.
std::complex< float > Link
bool runProbabilityCurrent2DTests(std::string &error)
Runs probability current2 d tests.
Declares the probabilitycurrent2d physics/numerical component used by QPE experiments.
Declares regression and invariant tests for probabilitycurrent2d tests.
Sampled two-dimensional probability-current field and integrated diagnostics.