24constexpr double kPi = 3.141592653589793238462643383279502884;
25constexpr double kTwoPi = 2.0 * kPi;
31bool finite(
double v)
noexcept {
return std::isfinite(v); }
39double fftWaveNumber(std::size_t index, std::size_t count,
double spacing)
noexcept
41 const long long n = (index <= count / 2u)
42 ?
static_cast<long long>(index)
43 :
static_cast<long long>(index) -
static_cast<long long>(count);
44 return kTwoPi *
static_cast<double>(n) /
45 (
static_cast<double>(count) * spacing);
54double coordinate(std::size_t index, std::size_t count,
double spacing)
noexcept
56 return (
static_cast<double>(index) - 0.5 *
static_cast<double>(count)) * spacing;
61 const double f = x /
static_cast<double>(field.dx()) +
62 0.5 *
static_cast<double>(field.width());
63 long long i =
static_cast<long long>(std::llround(f));
65 if (i >
static_cast<long long>(field.width()) - 2)
66 i =
static_cast<long long>(field.width()) - 2;
67 return static_cast<std::size_t
>(i);
73 std::string *reason)
noexcept
75 const bool ok = finite(c.detectorX) && finite(c.slowWaveNumber) &&
76 finite(c.fastWaveNumber) && finite(c.momentumSigma) &&
77 finite(c.fastAmplitudeRatio) && finite(c.relativePhaseDegrees) &&
78 finite(c.initialCenterX) && finite(c.transverseSigma) &&
79 finite(c.analysisEndTime) &&
80 c.slowWaveNumber > 0.0 && c.slowWaveNumber <= 8.0 &&
81 c.fastWaveNumber > c.slowWaveNumber && c.fastWaveNumber <= 12.0 &&
82 c.momentumSigma >= 0.03 && c.momentumSigma <= 3.0 &&
83 c.fastAmplitudeRatio > 0.0 && c.fastAmplitudeRatio <= 2.0 &&
84 c.transverseSigma >= 0.2 && c.transverseSigma <= 12.0 &&
85 c.analysisEndTime >= 0.1 && c.analysisEndTime <= 100.0 &&
86 std::abs(c.detectorX) <= 1000.0 &&
87 std::abs(c.initialCenterX) <= 1000.0;
89 *reason =
"QuantumBackflow2D: invalid configuration";
100 if (reason && reason->empty()) *reason =
"QuantumBackflow2D: invalid field or hbar";
107 const double lx =
static_cast<double>(field.
width()) *
static_cast<double>(field.
dx());
108 const double ly =
static_cast<double>(field.
height()) *
static_cast<double>(field.
dy());
110 const double y0IndexCoordinates = 0.5 * ly;
112 const std::complex<double> relative(std::cos(phase), std::sin(phase));
115 const double invTwoKySigma2 = 0.5 / (transverseKsigma * transverseKsigma);
117 for (std::size_t y = 0; y < field.
height(); ++y) {
118 const double ky = fftWaveNumber(y, field.
height(),
static_cast<double>(field.
dy()));
119 const double gy = std::exp(-ky * ky * invTwoKySigma2);
120 const std::complex<double> shiftY = std::exp(std::complex<double>(0.0, -ky * y0IndexCoordinates));
121 for (std::size_t x = 0; x < field.
width(); ++x) {
122 const double kx = fftWaveNumber(x, field.
width(),
static_cast<double>(field.
dx()));
123 if (kx <= 0.0)
continue;
127 const double g1 = std::exp(-d1 * d1 * invTwoSigma2);
128 const double g2 = std::exp(-d2 * d2 * invTwoSigma2);
130 const std::complex<double> shiftX = std::exp(std::complex<double>(0.0, -kx * x0IndexCoordinates));
131 const std::complex<double> a = ax * gy * shiftX * shiftY;
139 if (reason) *reason =
"QuantumBackflow2D: state normalization failed";
151 double positive = 0.0;
153 for (std::size_t y = 0; y < field.height(); ++y) {
154 for (std::size_t x = 0; x < field.width(); ++x) {
155 const double w = std::norm(spectrum(x, y));
157 if (fftWaveNumber(x, field.width(),
static_cast<double>(field.dx())) > 0.0)
161 return total > 0.0 ? positive / total : 0.0;
171 double time)
noexcept
175 if (field.empty() || !finite(mass) || mass <= 0.0 || !finite(hbar) || hbar <= 0.0)
178 const std::size_t ix = nearestColumn(field, c.detectorX);
179 const double dx =
static_cast<double>(field.dx());
180 const double dy =
static_cast<double>(field.dy());
181 const double currentScale = hbar / mass;
185 double current = 0.0;
186 for (std::size_t y = 0; y < field.height(); ++y) {
187 for (std::size_t x = 0; x < field.width(); ++x) {
188 const double p = std::norm(field(x, y)) * dx * dy;
189 if (coordinate(x, field.width(), dx) < c.detectorX) left += p;
192 const std::complex<double> psi(field(ix, y).real(), field(ix, y).imag());
193 const std::complex<double> plus(field(ix + 1u, y).real(), field(ix + 1u, y).imag());
194 const std::complex<double> minus(field(ix - 1u, y).real(), field(ix - 1u, y).imag());
195 const std::complex<double> dpsi = (plus - minus) / (2.0 * dx);
196 current += currentScale * std::imag(std::conj(psi) * dpsi) * dy;
223 !finite(mass) || mass <= 0.0 || !finite(hbar) || hbar <= 0.0)
239 const double dt = std::max(0.0, s.
time - p.
time);
Owning Cartesian grid of complex scalar samples.
bool empty() const noexcept
Returns whether the field contains no samples.
float dx() const noexcept
Returns the X grid spacing.
std::size_t height() const noexcept
Returns the number of samples along Y.
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
float dy() const noexcept
Returns the Y grid spacing.
std::size_t width() const noexcept
Returns the number of samples along X.
static bool supportsSize(std::size_t width, std::size_t height) noexcept
Returns whether both grid dimensions are supported by the radix-2 backend.
static void forward(ComplexField2D &field)
Convenience wrapper for an in-place forward transform.
static void inverse(ComplexField2D &field)
Convenience wrapper for an in-place normalized inverse transform.
static bool prepareState(ComplexField2D &field, const QuantumBackflow2DConfig &config, double hbar, std::string *reason=nullptr)
Prepares state.
static bool validateConfig(const QuantumBackflow2DConfig &config, std::string *reason=nullptr) noexcept
Validates config.
static double positiveMomentumFraction(const ComplexField2D &field) noexcept
Performs positive momentum fraction.
static QuantumBackflowSample2D measure(const ComplexField2D &field, const QuantumBackflow2DConfig &config, double mass, double hbar, double time) noexcept
Performs measure.
double positiveMomentumFraction_
const QuantumBackflow2DConfig & config() const noexcept
Returns config.
std::vector< QuantumBackflowSample2D > samples_
void append(double time, const ComplexField2D &field)
Carries out append.
std::size_t maximumSamples_
void clear()
Clears stored state and returns the component to its empty/default state.
bool configure(const ComplexField2D &field, const QuantumBackflow2DConfig &config, double mass, double hbar)
Returns configure.
QuantumBackflow2DConfig config_
void trim()
Carries out trim.
double maximumBackwardFlux_
Declares the two-dimensional FFT utility used by spectral quantum propagators and diagnostics.
std::size_t nearestColumn(const ComplexField2D &field, double x) noexcept
Declares the quantumbackflow2d physics/numerical component used by QPE experiments.
Configuration values for Quantum Backflow2D Config.
double relativePhaseDegrees
double fastAmplitudeRatio
Data structure used by the Quantum Backflow Sample2D component.
double cumulativeBackwardFlux