23constexpr double kPi = 3.141592653589793238462643383279502884;
30void fail(std::string *reason,
const char *message)
noexcept
32 if (reason) *reason = message;
42 return !a.empty() && !b.empty() &&
43 a.width() == b.width() && a.height() == b.height() &&
44 std::fabs(
static_cast<double>(a.dx()) -
static_cast<double>(b.dx())) <= 1.0e-9 &&
45 std::fabs(
static_cast<double>(a.dy()) -
static_cast<double>(b.dy())) <= 1.0e-9;
58 double halfWidth)
noexcept
60 if (!(totalWeight > 0.0))
return 0.0;
63 if (!(area > 0.0) || !(bandArea > 0.0))
return 0.0;
64 const double geometricFraction = std::min(1.0, bandArea / area);
65 if (!(geometricFraction > 0.0))
return 0.0;
66 return (bandWeight / totalWeight) / geometricFraction;
72 std::string *reason)
noexcept
74 if (reason) reason->clear();
75 if (!(config.orbitBandHalfWidth > 0.0) || !std::isfinite(config.orbitBandHalfWidth) ||
76 config.orbitBandHalfWidth > 20.0) {
77 fail(reason,
"Scar orbit-band half-width must be finite and positive.");
80 if (!(config.referenceEnergy >= 0.0) || !std::isfinite(config.referenceEnergy) ||
81 config.referenceEnergy > 10000.0) {
82 fail(reason,
"Scar reference energy must be finite and non-negative.");
90 std::string *reason)
noexcept
93 if (reason) reason->clear();
97 if (!
object.enabled)
continue;
99 fail(reason,
"Quantum Scar analysis expects one Stadium Exterior potential object.");
102 if (stadium !=
nullptr) {
103 fail(reason,
"Quantum Scar analysis expects exactly one Stadium Exterior object.");
109 if (!stadium || stadium->
value <= 0.0f || stadium->
width <= 0.0f || stadium->
radius <= 0.0f) {
110 fail(reason,
"Stadium Exterior must have positive wall height, straight length and radius.");
114 geometry.
valid =
true;
115 geometry.centerX = stadium->
centerX;
116 geometry.centerY = stadium->
centerY;
117 geometry.straightLength = stadium->
width;
118 geometry.radius = stadium->
radius;
119 geometry.wallPotential = stadium->
value;
127 if (!geometry.valid || !(geometry.straightLength > 0.0) || !(geometry.radius > 0.0)) {
130 const double lx = x - geometry.centerX;
131 const double ly = y - geometry.centerY;
132 const double halfStraight = 0.5 * geometry.straightLength;
133 if (std::fabs(lx) <= halfStraight)
return std::fabs(ly) <= geometry.radius;
134 const double capX = lx > 0.0 ? halfStraight : -halfStraight;
135 const double dx = lx - capX;
136 return dx * dx + ly * ly <= geometry.radius * geometry.radius;
141 if (!geometry.valid || !(geometry.straightLength > 0.0) || !(geometry.radius > 0.0))
return 0.0;
142 return 2.0 * geometry.radius * geometry.straightLength +
143 kPi * geometry.radius * geometry.radius;
147 double halfWidth)
noexcept
149 if (!geometry.valid || !(halfWidth > 0.0) || !(geometry.radius > 0.0))
return 0.0;
150 const double w = std::min(geometry.radius, halfWidth);
151 const double r = geometry.radius;
152 const double central = 2.0 * w * geometry.straightLength;
153 const double root = std::sqrt(std::max(0.0, r * r - w * w));
156 const double caps = 2.0 * (w * root + r * r * std::asin(std::min(1.0, w / r)));
157 return std::min(accessibleArea(geometry), central + caps);
162 if (!geometry.valid)
return 0.0;
163 const double oneWay = geometry.straightLength + 2.0 * geometry.radius;
168 double speed)
noexcept
170 if (!(speed > 0.0))
return 0.0;
171 return axialOrbitRoundTripLength(geometry) / speed;
177 if (!sameGrid(reference, field))
return 0.0;
178 const double cellArea =
static_cast<double>(field.dx()) *
static_cast<double>(field.dy());
179 std::complex<double> overlap(0.0, 0.0);
180 for (std::size_t i = 0; i < field.size(); ++i) {
181 const std::complex<double> a(reference.data()[i].real(), reference.data()[i].imag());
182 const std::complex<double> b(field.data()[i].real(), field.data()[i].imag());
183 overlap += std::conj(a) * b * cellArea;
185 return std::norm(overlap);
190 double halfWidth)
noexcept
192 if (field.empty() || !geometry.valid || !(halfWidth > 0.0))
return 0.0;
195 const double cellArea =
static_cast<double>(field.dx()) *
static_cast<double>(field.dy());
196 for (std::size_t y = 0; y < field.height(); ++y) {
198 for (std::size_t x = 0; x < field.width(); ++x) {
200 if (!inside(geometry, px, py))
continue;
201 const double rho =
static_cast<double>(std::norm(field(x, y))) * cellArea;
203 if (std::fabs(py - geometry.centerY) <= halfWidth) band += rho;
206 return enhancementFromWeights(band, total, geometry, halfWidth);
210 : maximumSamples_(std::max<std::size_t>(1u, maximumSamples))
236 double referenceEnergy,
276 if (elapsed > 0.0 && std::isfinite(elapsed)) weight = elapsed;
282 const std::complex<double> phase(std::cos(phaseAngle), std::sin(phaseAngle));
283 const std::size_t n = field.
size();
284 for (std::size_t i = 0; i < n; ++i) {
285 const std::complex<double> psi(field.
data()[i].real(), field.
data()[i].imag());
286 const double rho = std::norm(psi);
294 double filteredMax = 0.0;
295 for (std::size_t i = 0; i < n; ++i) {
298 filteredMax = std::max(filteredMax, v);
300 const double invFilteredMax = filteredMax > 0.0 ? 1.0 / filteredMax : 0.0;
301 for (std::size_t i = 0; i < n; ++i) {
308 sample.instantaneousOrbitEnhancement =
Owning Cartesian grid of complex scalar samples.
std::size_t size() const noexcept
Returns the total number of complex 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.
Value * data() noexcept
Returns mutable contiguous row-major sample storage.
std::size_t width() const noexcept
Returns the number of samples along X.
static double yCoordinate(const ComplexField2D &field, std::size_t y) noexcept
Performs y coordinate.
static double xCoordinate(const ComplexField2D &field, std::size_t x) noexcept
Performs x coordinate.
Implements the Potential Scene2D component.
std::vector< std::complex< double > > spectralAccumulator_
bool append(double time, const ComplexField2D &field)
Carries out append.
std::size_t accumulatedFrames_
double filteredEnhancement() const noexcept
Carries out filtered enhancement.
std::vector< float > meanDensity_
bool hasAccumulationTime_
double referenceEnergy() const noexcept
Carries out reference energy.
std::vector< float > filteredDensity_
double lastAccumulationTime_
QuantumScarConfig2D config_
ComplexField2D reference_
std::vector< double > meanDensitySum_
std::size_t maximumSamples_
std::vector< QuantumScarSample2D > samples_
std::size_t maximumSamples() const noexcept
Carries out maximum samples.
QuantumScarGeometry2D geometry_
const QuantumScarGeometry2D & geometry() const noexcept
Carries out geometry.
void clear() noexcept
Clears stored state and returns the component to its empty/default state.
const QuantumScarConfig2D & config() const noexcept
Returns config.
void setMaximumSamples(std::size_t maximumSamples)
Sets maximum samples.
double hbar() const noexcept
Carries out hbar.
bool configure(const ComplexField2D &reference, const QuantumScarGeometry2D &geometry, const QuantumScarConfig2D &config, double referenceEnergy, double hbar=1.0)
Returns configure.
QuantumScarHistory2D(std::size_t maximumSamples=1600u)
Constructs a Quantum Scar History 2D instance.
void trimToLimit()
Carries out trim to limit.
static double orbitEnhancement(const ComplexField2D &field, const QuantumScarGeometry2D &geometry, double halfWidth) noexcept
Performs orbit enhancement.
static double axialOrbitPeriod(const QuantumScarGeometry2D &geometry, double speed) noexcept
Performs axial orbit period.
static double orbitBandArea(const QuantumScarGeometry2D &geometry, double halfWidth) noexcept
Performs orbit band area.
static double accessibleArea(const QuantumScarGeometry2D &geometry) noexcept
Performs accessible area.
static double fidelity(const ComplexField2D &reference, const ComplexField2D &field) noexcept
Performs fidelity.
static double axialOrbitRoundTripLength(const QuantumScarGeometry2D &geometry) noexcept
Performs axial orbit round trip length.
static bool inside(const QuantumScarGeometry2D &geometry, double x, double y) noexcept
Performs inside.
static bool identify(const PotentialScene2D &scene, QuantumScarGeometry2D &geometry, std::string *reason=nullptr) noexcept
Returns identify.
static bool validateConfig(const QuantumScarConfig2D &config, std::string *reason=nullptr) noexcept
Validates config.
Declares the gaussianpacket2d physics/numerical component used by QPE experiments.
double enhancementFromWeights(double bandWeight, double totalWeight, const QuantumScarGeometry2D &geometry, double halfWidth) noexcept
Performs enhancement from weights.
Declares the quantumscar2d physics/numerical component used by QPE experiments.
Data structure used by the Potential Object2D component.
bool valid() const noexcept
Performs valid.
Data structure used by the Quantum Scar Config2D component.
double orbitBandHalfWidth
Data structure used by the Quantum Scar Geometry2D component.
Data structure used by the Quantum Scar Sample2D component.