23constexpr double kPi = 3.141592653589793238462643383279502884;
30void fail(std::string *reason,
const char *message)
noexcept
32 if (reason) *reason = message;
41bool near(
double a,
double b,
double scale = 1.0) noexcept
43 return std::fabs(a - b) <= 1.0e-4 * std::max(1.0, scale);
50 std::string *reason)
noexcept
53 if (reason) reason->clear();
55 std::vector<const PotentialObject2D *> vertical;
56 std::vector<const PotentialObject2D *> horizontal;
59 if (!
object.enabled)
continue;
61 fail(reason,
"Quantum revival box expects four enabled positive Rectangle walls.");
64 if (
object.height >
object.width) vertical.push_back(&
object);
65 else if (
object.width >
object.height) horizontal.push_back(&
object);
67 fail(reason,
"Quantum revival box walls must be clearly vertical or horizontal.");
72 if (vertical.size() != 2u || horizontal.size() != 2u) {
73 fail(reason,
"Quantum revival box needs exactly two vertical and two horizontal walls.");
77 std::sort(vertical.begin(), vertical.end(),
79 return a->centerX < b->centerX;
81 std::sort(horizontal.begin(), horizontal.end(),
83 return a->centerY < b->centerY;
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;
98 if (!(width > 0.0) || !(height > 0.0)) {
99 fail(reason,
"Quantum revival box walls overlap or leave no finite interior.");
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.");
112 fail(reason,
"Opposite quantum-box walls must use equal thickness.");
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.");
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;
137 double hbar)
noexcept
139 if (!(boxLength > 0.0) || !(mass > 0.0) || !(hbar > 0.0) ||
140 !std::isfinite(boxLength) || !std::isfinite(mass) || !std::isfinite(hbar)) {
143 return 4.0 * mass * boxLength * boxLength / (kPi * hbar);
148 double hbar)
noexcept
150 return geometry.valid ? revivalTime(geometry.innerWidth, mass, hbar) : 0.0;
155 double hbar)
noexcept
157 return geometry.valid ? revivalTime(geometry.innerHeight, mass, hbar) : 0.0;
162 std::vector<float> result(field.
width(), 0.0f);
163 if (field.
empty())
return result;
165 const double dy =
static_cast<double>(field.
dy());
166 for (std::size_t x = 0u; x < field.
width(); ++x) {
168 for (std::size_t y = 0u; y < field.
height(); ++y) {
170 const double re = value.real();
171 const double im = value.imag();
172 sum += re * re + im * im;
174 result[x] =
static_cast<float>(sum * dy);
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) {
189 std::complex<double> overlap(0.0, 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);
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));
205 : maximumSamples_(maximumSamples > 0u ? maximumSamples : 1u)
230 throw std::invalid_argument(
"QuantumRevivalHistory2D maximumSamples must be > 0");
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_
std::size_t maximumSamples_
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.
ComplexField2D reference_
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.