Quantum Phenomena Explorer 7.9.8
Interactive quantum-phenomena Explorer Tutor — source documentation
Loading...
Searching...
No Matches
quantumrevivals2d.cpp
Go to the documentation of this file.
1/**
2 * @file quantumrevivals2d.cpp
3 * @brief Implements the quantumrevivals2d physics/numerical component used by QPE experiments.
4 * @ingroup qpe_quantum
5 *
6 * Source: @c core/quantum/quantumrevivals2d.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
12#include "quantumrevivals2d.h"
13
14#include <algorithm>
15#include <cmath>
16#include <complex>
17#include <stdexcept>
18#include <vector>
19
20namespace qpe {
21namespace {
22
23constexpr double kPi = 3.141592653589793238462643383279502884;
24
25/**
26 * @brief Performs fail.
27 * @param reason The reason value used by the operation.
28 * @param message The message value used by the operation.
29 */
30void fail(std::string *reason, const char *message) noexcept
31{
32 if (reason) *reason = message;
33}
34
35/**
36 * @brief Performs near.
37 * @param a The a value used by the operation.
38 * @param b The b value used by the operation.
39 * @param scale The scale value used by the operation.
40 */
41bool near(double a, double b, double scale = 1.0) noexcept
42{
43 return std::fabs(a - b) <= 1.0e-4 * std::max(1.0, scale);
44}
45
46} // namespace
47
49 QuantumBoxGeometry2D &geometry,
50 std::string *reason) noexcept
51{
52 geometry = QuantumBoxGeometry2D();
53 if (reason) reason->clear();
54
55 std::vector<const PotentialObject2D *> vertical;
56 std::vector<const PotentialObject2D *> horizontal;
57
58 for (const PotentialObject2D &object : scene.objects()) {
59 if (!object.enabled) continue;
60 if (object.type != PotentialObjectType2D::Rectangle || !(object.value > 0.0f)) {
61 fail(reason, "Quantum revival box expects four enabled positive Rectangle walls.");
62 return false;
63 }
64 if (object.height > object.width) vertical.push_back(&object);
65 else if (object.width > object.height) horizontal.push_back(&object);
66 else {
67 fail(reason, "Quantum revival box walls must be clearly vertical or horizontal.");
68 return false;
69 }
70 }
71
72 if (vertical.size() != 2u || horizontal.size() != 2u) {
73 fail(reason, "Quantum revival box needs exactly two vertical and two horizontal walls.");
74 return false;
75 }
76
77 std::sort(vertical.begin(), vertical.end(),
78 [](const PotentialObject2D *a, const PotentialObject2D *b) {
79 return a->centerX < b->centerX;
80 });
81 std::sort(horizontal.begin(), horizontal.end(),
82 [](const PotentialObject2D *a, const PotentialObject2D *b) {
83 return a->centerY < b->centerY;
84 });
85
86 const PotentialObject2D &left = *vertical[0];
87 const PotentialObject2D &right = *vertical[1];
88 const PotentialObject2D &bottom = *horizontal[0];
89 const PotentialObject2D &top = *horizontal[1];
90
91 const double leftInner = static_cast<double>(left.centerX) + 0.5 * left.width;
92 const double rightInner = static_cast<double>(right.centerX) - 0.5 * right.width;
93 const double bottomInner = static_cast<double>(bottom.centerY) + 0.5 * bottom.height;
94 const double topInner = static_cast<double>(top.centerY) - 0.5 * top.height;
95 const double width = rightInner - leftInner;
96 const double height = topInner - bottomInner;
97
98 if (!(width > 0.0) || !(height > 0.0)) {
99 fail(reason, "Quantum revival box walls overlap or leave no finite interior.");
100 return false;
101 }
102
103 const double wallValue = left.value;
104 if (!near(right.value, wallValue, wallValue) ||
105 !near(bottom.value, wallValue, wallValue) ||
106 !near(top.value, wallValue, wallValue)) {
107 fail(reason, "Quantum revival box walls must use the same potential height.");
108 return false;
109 }
110 if (!near(left.width, right.width, left.width) ||
111 !near(bottom.height, top.height, bottom.height)) {
112 fail(reason, "Opposite quantum-box walls must use equal thickness.");
113 return false;
114 }
115
116 const double centerX = 0.5 * (leftInner + rightInner);
117 const double centerY = 0.5 * (bottomInner + topInner);
118 if (!near(left.centerY, centerY, height) || !near(right.centerY, centerY, height) ||
119 !near(bottom.centerX, centerX, width) || !near(top.centerX, centerX, width)) {
120 fail(reason, "Quantum revival box walls are not centred on one rectangular interior.");
121 return false;
122 }
123
124 geometry.valid = true;
125 geometry.centerX = centerX;
126 geometry.centerY = centerY;
127 geometry.innerWidth = width;
128 geometry.innerHeight = height;
129 geometry.wallThicknessX = left.width;
130 geometry.wallThicknessY = bottom.height;
131 geometry.wallPotential = wallValue;
132 return true;
133}
134
135double QuantumRevivals2D::revivalTime(double boxLength,
136 double mass,
137 double hbar) noexcept
138{
139 if (!(boxLength > 0.0) || !(mass > 0.0) || !(hbar > 0.0) ||
140 !std::isfinite(boxLength) || !std::isfinite(mass) || !std::isfinite(hbar)) {
141 return 0.0;
142 }
143 return 4.0 * mass * boxLength * boxLength / (kPi * hbar);
144}
145
147 double mass,
148 double hbar) noexcept
149{
150 return geometry.valid ? revivalTime(geometry.innerWidth, mass, hbar) : 0.0;
151}
152
154 double mass,
155 double hbar) noexcept
156{
157 return geometry.valid ? revivalTime(geometry.innerHeight, mass, hbar) : 0.0;
158}
159
161{
162 std::vector<float> result(field.width(), 0.0f);
163 if (field.empty()) return result;
164
165 const double dy = static_cast<double>(field.dy());
166 for (std::size_t x = 0u; x < field.width(); ++x) {
167 double sum = 0.0;
168 for (std::size_t y = 0u; y < field.height(); ++y) {
169 const ComplexField2D::Value value = field(x, y);
170 const double re = value.real();
171 const double im = value.imag();
172 sum += re * re + im * im;
173 }
174 result[x] = static_cast<float>(sum * dy);
175 }
176 return result;
177}
178
180 const ComplexField2D &field) noexcept
181{
182 if (reference.empty() || field.empty() ||
183 reference.width() != field.width() || reference.height() != field.height() ||
184 std::fabs(reference.dx() - field.dx()) > 1.0e-9f ||
185 std::fabs(reference.dy() - field.dy()) > 1.0e-9f) {
186 return 0.0;
187 }
188
189 std::complex<double> overlap(0.0, 0.0);
190 double normA = 0.0;
191 double normB = 0.0;
192 for (std::size_t i = 0u; i < field.size(); ++i) {
193 const std::complex<double> a(reference.data()[i].real(), reference.data()[i].imag());
194 const std::complex<double> b(field.data()[i].real(), field.data()[i].imag());
195 overlap += std::conj(a) * b;
196 normA += std::norm(a);
197 normB += std::norm(b);
198 }
199 if (!(normA > 0.0) || !(normB > 0.0)) return 0.0;
200 const double value = std::norm(overlap) / (normA * normB);
201 return std::max(0.0, std::min(1.0, value));
202}
203
205 : maximumSamples_(maximumSamples > 0u ? maximumSamples : 1u)
206{
207 samples_.reserve(std::min<std::size_t>(maximumSamples_, 1200u));
208}
209
211{
213 samples_.clear();
214}
215
217{
218 if (field.empty()) {
219 clear();
220 return false;
221 }
222 reference_ = field;
223 samples_.clear();
224 return true;
225}
226
227void QuantumRevivalHistory2D::setMaximumSamples(std::size_t maximumSamples)
228{
229 if (maximumSamples == 0u) {
230 throw std::invalid_argument("QuantumRevivalHistory2D maximumSamples must be > 0");
231 }
233 trimToLimit();
234}
235
236bool QuantumRevivalHistory2D::append(double time, const ComplexField2D &field)
237{
238 if (!hasReference() || field.empty() || field.width() != reference_.width() ||
239 field.height() != reference_.height()) {
240 return false;
241 }
242
244 sample.time = time;
245 sample.fidelity = QuantumRevivals2D::fidelity(reference_, field);
246 sample.marginalX = QuantumRevivals2D::marginalProbabilityX(field);
247 samples_.push_back(sample);
248 trimToLimit();
249 return true;
250}
251
253{
254 if (samples_.size() <= maximumSamples_) return;
255 const std::size_t removeCount = samples_.size() - maximumSamples_;
256 samples_.erase(samples_.begin(), samples_.begin() + static_cast<std::ptrdiff_t>(removeCount));
257}
258
259} // namespace qpe
Owning Cartesian grid of complex scalar samples.
bool empty() const noexcept
Returns whether the field contains no samples.
std::size_t height() const noexcept
Returns the number of samples along Y.
void clear() noexcept
Releases all samples and returns the field to the empty state.
std::complex< float > Value
float dy() const noexcept
Returns the Y grid spacing.
std::size_t width() const noexcept
Returns the number of samples along X.
Implements the Potential Scene2D component.
void setMaximumSamples(std::size_t maximumSamples)
Sets maximum samples.
bool captureReference(const ComplexField2D &field)
Carries out capture reference.
std::vector< QuantumRevivalSample2D > samples_
void clear() noexcept
Clears stored state and returns the component to its empty/default state.
bool append(double time, const ComplexField2D &field)
Carries out append.
std::size_t maximumSamples() const noexcept
Carries out maximum samples.
bool hasReference() const noexcept
Returns whether reference.
QuantumRevivalHistory2D(std::size_t maximumSamples=1200u)
Constructs a Quantum Revival History 2D instance.
void trimToLimit()
Carries out trim to limit.
static std::vector< float > marginalProbabilityX(const ComplexField2D &field)
Performs marginal probability x.
static double revivalTimeY(const QuantumBoxGeometry2D &geometry, double mass, double hbar=1.0) noexcept
Performs revival time y.
static double revivalTimeX(const QuantumBoxGeometry2D &geometry, double mass, double hbar=1.0) noexcept
Performs revival time x.
static bool identifyBox(const PotentialScene2D &scene, QuantumBoxGeometry2D &geometry, std::string *reason=nullptr) noexcept
Returns identify box.
static double revivalTime(double boxLength, double mass, double hbar=1.0) noexcept
Performs revival time.
static double fidelity(const ComplexField2D &reference, const ComplexField2D &field) noexcept
Performs fidelity.
Declares the quantumrevivals2d physics/numerical component used by QPE experiments.
Data structure used by the Potential Object2D component.
Data structure used by the Quantum Box Geometry2D component.
Data structure used by the Quantum Revival Sample2D component.