Quantum Phenomena Explorer 7.9.8
Interactive quantum-phenomena Explorer Tutor — source documentation
Loading...
Searching...
No Matches
landauzener2d.cpp
Go to the documentation of this file.
1/**
2 * @file landauzener2d.cpp
3 * @brief Implements the landauzener2d physics/numerical component used by QPE experiments.
4 * @ingroup qpe_quantum
5 *
6 * Source: @c core/quantum/landauzener2d.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 "landauzener2d.h"
13
18
19#include <algorithm>
20#include <cmath>
21
22namespace qpe {
23namespace {
24
25const double Pi = 3.1415926535897932384626433832795;
26
27/**
28 * @brief Performs valid pair.
29 * @param spectrum The spectrum value used by the operation.
30 * @param stateA The state a value used by the operation.
31 * @param stateB The state b value used by the operation.
32 */
33bool validPair(const BoundStateSpectrum1D &spectrum, int stateA, int stateB) noexcept
34{
35 return spectrum.valid && stateA >= 0 && stateB >= 0 && stateA != stateB &&
36 stateA < static_cast<int>(spectrum.states.size()) &&
37 stateB < static_cast<int>(spectrum.states.size()) &&
38 spectrum.states[static_cast<std::size_t>(stateA)].amplitude.size() == spectrum.x.size() &&
39 spectrum.states[static_cast<std::size_t>(stateB)].amplitude.size() == spectrum.x.size();
40}
41
42/**
43 * @brief Performs matrix element x.
44 * @param spectrum The spectrum value used by the operation.
45 * @param stateA The state a value used by the operation.
46 * @param stateB The state b value used by the operation.
47 */
48double matrixElementX(const BoundStateSpectrum1D &spectrum,
49 int stateA,
50 int stateB) noexcept
51{
52 if (!validPair(spectrum, stateA, stateB) || !(spectrum.dx > 0.0)) {
53 return 0.0;
54 }
55 const BoundState1D &a = spectrum.states[static_cast<std::size_t>(stateA)];
56 const BoundState1D &b = spectrum.states[static_cast<std::size_t>(stateB)];
57 double sum = 0.0;
58 for (std::size_t i = 0u; i < spectrum.x.size(); ++i) {
59 sum += static_cast<double>(a.amplitude[i]) * spectrum.x[i] *
60 static_cast<double>(b.amplitude[i]) * spectrum.dx;
61 }
62 return sum;
63}
64
65/**
66 * @brief Performs project stationary pair.
67 * @param field Field data to read or modify.
68 * @param spectrum The spectrum value used by the operation.
69 * @param stateA The state a value used by the operation.
70 * @param stateB The state b value used by the operation.
71 * @param ca The ca value used by the operation.
72 * @param cb The cb value used by the operation.
73 */
75 const BoundStateSpectrum1D &spectrum,
76 int stateA,
77 int stateB,
78 std::complex<double> &ca,
79 std::complex<double> &cb) noexcept
80{
81 if (!validPair(spectrum, stateA, stateB) || field.empty() ||
82 field.width() != spectrum.x.size()) {
83 return false;
84 }
85 const double yMeasure = static_cast<double>(field.height()) * static_cast<double>(field.dy());
86 if (!(yMeasure > 0.0)) {
87 return false;
88 }
89 const BoundState1D &a = spectrum.states[static_cast<std::size_t>(stateA)];
90 const BoundState1D &b = spectrum.states[static_cast<std::size_t>(stateB)];
91 const double yScale = 1.0 / std::sqrt(yMeasure);
92 const double cellArea = static_cast<double>(field.dx()) * static_cast<double>(field.dy());
93 ca = std::complex<double>(0.0, 0.0);
94 cb = std::complex<double>(0.0, 0.0);
95 for (std::size_t y = 0u; y < field.height(); ++y) {
96 for (std::size_t x = 0u; x < field.width(); ++x) {
97 const ComplexField2D::Value value = field(x, y);
98 const std::complex<double> psi(static_cast<double>(value.real()),
99 static_cast<double>(value.imag()));
100 ca += static_cast<double>(a.amplitude[x]) * yScale * psi * cellArea;
101 cb += static_cast<double>(b.amplitude[x]) * yScale * psi * cellArea;
102 }
103 }
104 return true;
105}
106
107} // namespace
108
110 const BoundStateSpectrum1D &zeroBiasSpectrum,
111 const LinearPotentialSweep2DConfig &sweep,
112 int stateA,
113 int stateB,
114 double hbar) noexcept
115{
116 LandauZenerTheory2D result;
117 if (!validPair(zeroBiasSpectrum, stateA, stateB) || !(hbar > 0.0) ||
118 !sweep.enabled || sweep.parameter != TimePotentialParameter2D::LinearSlopeX ||
119 !std::isfinite(sweep.startValue) || !std::isfinite(sweep.endValue) ||
120 !std::isfinite(sweep.startTime) || !std::isfinite(sweep.duration) ||
121 !(sweep.duration > 0.0) || sweep.startTime < 0.0 ||
122 sweep.startValue == sweep.endValue) {
123 return result;
124 }
125
126 result.stateA = stateA;
127 result.stateB = stateB;
128 result.energyA = zeroBiasSpectrum.states[static_cast<std::size_t>(stateA)].energy;
129 result.energyB = zeroBiasSpectrum.states[static_cast<std::size_t>(stateB)].energy;
130 result.minimumGap = std::abs(result.energyB - result.energyA);
131 result.couplingMatrixElementX = matrixElementX(zeroBiasSpectrum, stateA, stateB);
132 result.parameterSweepRate = (sweep.endValue - sweep.startValue) / sweep.duration;
133 result.diabaticDetuningRate =
134 2.0 * std::abs(result.couplingMatrixElementX * result.parameterSweepRate);
135 if (!(result.minimumGap > 1.0e-12) ||
136 !(std::abs(result.couplingMatrixElementX) > 1.0e-12) ||
137 !(result.diabaticDetuningRate > 1.0e-15)) {
138 return result;
139 }
140
141 const double u = -sweep.startValue / (sweep.endValue - sweep.startValue);
142 if (!(u >= 0.0 && u <= 1.0)) {
143 return result; // this recipe does not cross zero bias
144 }
145 result.crossingTime = sweep.startTime + u * sweep.duration;
146
147 const double exponent = Pi * result.minimumGap * result.minimumGap /
148 (2.0 * hbar * result.diabaticDetuningRate);
149 result.diabaticProbability = std::exp(-std::max(0.0, exponent));
150 result.diabaticProbability = std::max(0.0, std::min(1.0, result.diabaticProbability));
153 zeroBiasSpectrum, stateA, stateB, nullptr);
154 result.leftSign = std::cos(result.leftPhaseRadians) >= 0.0 ? 1.0 : -1.0;
155 result.valid = true;
156 return result;
157}
158
160 const ComplexField2D &field,
161 const BoundStateSpectrum1D &zeroBiasSpectrum,
162 const LandauZenerTheory2D &theory,
163 double currentBias)
164{
166 if (!theory.valid || !std::isfinite(currentBias)) {
167 return result;
168 }
169
170 std::complex<double> ca;
171 std::complex<double> cb;
172 if (!projectStationaryPair(field, zeroBiasSpectrum,
173 theory.stateA, theory.stateB, ca, cb)) {
174 return result;
175 }
176 result.amplitudeA = ca;
177 result.amplitudeB = cb;
178 result.capturedPopulation = std::norm(ca) + std::norm(cb);
179
180 const double invSqrt2 = 1.0 / std::sqrt(2.0);
181 const std::complex<double> cLeft =
182 (ca + theory.leftSign * cb) * invSqrt2;
183 const std::complex<double> cRight =
184 (ca - theory.leftSign * cb) * invSqrt2;
185 result.leftPopulation = std::norm(cLeft);
186 result.rightPopulation = std::norm(cRight);
187
188 // Instantaneous effective Hamiltonian in the zero-bias stationary basis:
189 // [ E1, F*x12 ; F*x12, E2 ].
190 const double a = theory.energyA;
191 const double d = theory.energyB;
192 const double g = currentBias * theory.couplingMatrixElementX;
193 const double mean = 0.5 * (a + d);
194 const double halfDifference = 0.5 * (a - d);
195 const double radius = std::sqrt(halfDifference * halfDifference + g * g);
196 result.lowerEnergy = mean - radius;
197 result.upperEnergy = mean + radius;
198
199 double v1 = 1.0;
200 double v2 = 0.0;
201 if (std::abs(g) > 1.0e-14) {
202 v1 = g;
203 v2 = result.lowerEnergy - a;
204 const double n = std::sqrt(v1 * v1 + v2 * v2);
205 if (n > 0.0) {
206 v1 /= n;
207 v2 /= n;
208 }
209 } else if (d < a) {
210 v1 = 0.0;
211 v2 = 1.0;
212 }
213
214 const std::complex<double> cLower = v1 * ca + v2 * cb;
215 const std::complex<double> cUpper = -v2 * ca + v1 * cb;
216 result.lowerAdiabaticPopulation = std::norm(cLower);
217 result.upperAdiabaticPopulation = std::norm(cUpper);
218 result.valid = true;
219 return result;
220}
221
222} // namespace qpe
Declares the boundstates1d physics/numerical component used by QPE experiments.
static double preferredLeftPhase(const BoundStateSpectrum1D &spectrum, int stateA, int stateB, double *leftProbability=nullptr)
Performs preferred left phase.
Owning Cartesian grid of complex scalar samples.
std::complex< float > Value
static LandauZenerProjection2D project(const ComplexField2D &field, const BoundStateSpectrum1D &zeroBiasSpectrum, const LandauZenerTheory2D &theory, double currentBias)
Performs project.
static LandauZenerTheory2D analyze(const BoundStateSpectrum1D &zeroBiasSpectrum, const LinearPotentialSweep2DConfig &sweep, int stateA=0, int stateB=1, double hbar=1.0) noexcept
Performs analyze.
Declares the coherenttunneling2d physics/numerical component used by QPE experiments.
Declares the complex scalar field container representing two-dimensional wave functions.
Declares the landauzener2d physics/numerical component used by QPE experiments.
bool projectStationaryPair(const ComplexField2D &field, const BoundStateSpectrum1D &spectrum, int stateA, int stateB, std::complex< double > &ca, std::complex< double > &cb) noexcept
Performs project stationary pair.
double matrixElementX(const BoundStateSpectrum1D &spectrum, int stateA, int stateB) noexcept
Performs matrix element x.
Data structure used by the Bound State1D component.
std::vector< float > amplitude
Data structure used by the Bound State Spectrum1D component.
Data structure used by the Landau Zener Projection2D component.
std::complex< double > amplitudeA
std::complex< double > amplitudeB
Data structure used by the Landau Zener Theory2D component.
Configuration values for Linear Potential Sweep2D Config.
Declares the timedependentpotential2d physics/numerical component used by QPE experiments.