Quantum Phenomena Explorer 7.9.8
Interactive quantum-phenomena Explorer Tutor — source documentation
Loading...
Searching...
No Matches
timedependentpotential2d.cpp
Go to the documentation of this file.
1/**
2 * @file timedependentpotential2d.cpp
3 * @brief Implements the timedependentpotential2d physics/numerical component used by QPE experiments.
4 * @ingroup qpe_quantum
5 *
6 * Source: @c core/quantum/timedependentpotential2d.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
13
15
16#include <algorithm>
17#include <cmath>
18
19namespace qpe {
20namespace {
21
22/**
23 * @brief Performs finite.
24 * @param value Value to assign or evaluate.
25 */
26bool finite(double value) noexcept
27{
28 return std::isfinite(value);
29}
30
31const double Pi = 3.1415926535897932384626433832795;
32
33} // namespace
34
36 const QuantumQuench2DConfig &config) noexcept
37{
38 if (!config.enabled) {
39 return true;
40 }
41 if (config.targetObjectId == 0 || !finite(config.quenchTime) || config.quenchTime < 0.0 ||
42 !finite(config.beforeValue) || !finite(config.afterValue)) {
43 return false;
44 }
45 const PotentialObject2D *object = scene.find(config.targetObjectId);
46 if (!object) {
47 return false;
48 }
49 double ignored = 0.0;
50 return parameterValue(*object, config.parameter, ignored);
51}
52
54 const PotentialScene2D &scene,
55 const PeriodicPotentialDrive2DConfig &config) noexcept
56{
57 if (!config.enabled) {
58 return true;
59 }
60 if (config.targetObjectId == 0 || !finite(config.meanValue) ||
61 !finite(config.amplitude) || !finite(config.angularFrequency) ||
62 config.angularFrequency < 0.0 || !finite(config.phaseDegrees)) {
63 return false;
64 }
65 const PotentialObject2D *object = scene.find(config.targetObjectId);
66 if (!object) {
67 return false;
68 }
69 double ignored = 0.0;
70 return parameterValue(*object, config.parameter, ignored);
71}
72
74 const PotentialScene2D &scene,
75 const LinearPotentialSweep2DConfig &config) noexcept
76{
77 if (!config.enabled) {
78 return true;
79 }
80 if (config.targetObjectId == 0 || !finite(config.startValue) ||
81 !finite(config.endValue) || !finite(config.startTime) ||
82 !finite(config.duration) || !finite(config.holdDuration) ||
83 !finite(config.returnDuration) || config.startTime < 0.0 ||
84 !(config.duration > 0.0) || config.holdDuration < 0.0 ||
85 (config.returnEnabled && !(config.returnDuration > 0.0))) {
86 return false;
87 }
88 const PotentialObject2D *object = scene.find(config.targetObjectId);
89 if (!object) {
90 return false;
91 }
92 double ignored = 0.0;
93 return parameterValue(*object, config.parameter, ignored);
94}
95
97 const PotentialScene2D &scene,
98 const RamseyPulseSequence2DConfig &config) noexcept
99{
100 if (!config.enabled) {
101 return true;
102 }
103 if (config.targetObjectId == 0 || !finite(config.meanValue) ||
104 !finite(config.amplitude) || !finite(config.angularFrequency) ||
105 !(config.angularFrequency > 0.0) ||
106 !finite(config.firstPulsePhaseDegrees) ||
107 !finite(config.secondPulsePhaseDegrees) ||
108 !finite(config.startTime) || config.startTime < 0.0 ||
109 !finite(config.pulseDuration) || !(config.pulseDuration > 0.0) ||
110 !finite(config.freeEvolutionDuration) || config.freeEvolutionDuration < 0.0 ||
111 !finite(config.echoPulseDuration) ||
112 (config.echoEnabled && !(config.echoPulseDuration > 0.0)) ||
113 !finite(config.echoPulsePhaseDegrees)) {
114 return false;
115 }
116 const PotentialObject2D *object = scene.find(config.targetObjectId);
117 if (!object) {
118 return false;
119 }
120 double ignored = 0.0;
121 return parameterValue(*object, config.parameter, ignored);
122}
123
125 TimePotentialParameter2D parameter,
126 double value) noexcept
127{
128 if (!finite(value)) {
129 return false;
130 }
131 const float v = static_cast<float>(value);
132 switch (parameter) {
134 object.value = v;
135 return true;
137 object.centerX = v;
138 return true;
140 object.centerY = v;
141 return true;
143 if (object.type != PotentialObjectType2D::Harmonic) return false;
144 object.curvatureX = v;
145 return true;
147 if (object.type != PotentialObjectType2D::Harmonic) return false;
148 object.curvatureY = v;
149 return true;
151 if (object.type != PotentialObjectType2D::Harmonic) return false;
152 object.curvatureX = v;
153 object.curvatureY = v;
154 return true;
156 if (object.type != PotentialObjectType2D::Linear) return false;
157 object.slopeX = v;
158 return true;
160 if (object.type != PotentialObjectType2D::Linear) return false;
161 object.slopeY = v;
162 return true;
163 }
164 return false;
165}
166
168 TimePotentialParameter2D parameter,
169 double &value) noexcept
170{
171 switch (parameter) {
173 value = object.value;
174 return true;
176 value = object.centerX;
177 return true;
179 value = object.centerY;
180 return true;
182 if (object.type != PotentialObjectType2D::Harmonic) return false;
183 value = object.curvatureX;
184 return true;
186 if (object.type != PotentialObjectType2D::Harmonic) return false;
187 value = object.curvatureY;
188 return true;
190 if (object.type != PotentialObjectType2D::Harmonic) return false;
191 if (std::abs(static_cast<double>(object.curvatureX) - static_cast<double>(object.curvatureY)) > 1.0e-6) {
192 return false;
193 }
194 value = object.curvatureX;
195 return true;
197 if (object.type != PotentialObjectType2D::Linear) return false;
198 value = object.slopeX;
199 return true;
201 if (object.type != PotentialObjectType2D::Linear) return false;
202 value = object.slopeY;
203 return true;
204 }
205 return false;
206}
207
209 const PeriodicPotentialDrive2DConfig &config,
210 double time) noexcept
211{
212 if (!finite(time)) {
213 return config.meanValue;
214 }
215 const double phase = config.angularFrequency * time + config.phaseDegrees * Pi / 180.0;
216 return config.meanValue + config.amplitude * std::sin(phase);
217}
218
220 const LinearPotentialSweep2DConfig &config,
221 double time) noexcept
222{
223 if (!finite(time) || time <= config.startTime) {
224 return config.startValue;
225 }
226
227 const double outwardEnd = config.startTime + config.duration;
228 if (time < outwardEnd) {
229 const double u = (time - config.startTime) / config.duration;
230 return config.startValue + (config.endValue - config.startValue) * u;
231 }
232
233 if (!config.returnEnabled) {
234 return config.endValue;
235 }
236
237 const double holdEnd = outwardEnd + config.holdDuration;
238 if (time < holdEnd) {
239 return config.endValue;
240 }
241
242 const double returnEnd = holdEnd + config.returnDuration;
243 if (time >= returnEnd) {
244 return config.startValue;
245 }
246
247 const double u = (time - holdEnd) / config.returnDuration;
248 return config.endValue + (config.startValue - config.endValue) * u;
249}
250
252 const LinearPotentialSweep2DConfig &config) noexcept
253{
254 if (!config.returnEnabled) {
255 return config.duration;
256 }
257 return config.duration + config.holdDuration + config.returnDuration;
258}
259
261 const RamseyPulseSequence2DConfig &config) noexcept
262{
263 return 2.0 * config.pulseDuration + config.freeEvolutionDuration +
264 (config.echoEnabled ? config.echoPulseDuration : 0.0);
265}
266
268 const RamseyPulseSequence2DConfig &config,
269 double time,
270 double *localPulseTime) noexcept
271{
272 if (localPulseTime) *localPulseTime = 0.0;
273 if (!finite(time) || time < config.startTime) {
275 }
276 const double firstEnd = config.startTime + config.pulseDuration;
277 if (time < firstEnd) {
278 if (localPulseTime) *localPulseTime = time - config.startTime;
280 }
281
282 if (!config.echoEnabled) {
283 const double freeEnd = firstEnd + config.freeEvolutionDuration;
284 if (time < freeEnd) return RamseyPulseSegment2D::FreeEvolution;
285 const double secondEnd = freeEnd + config.pulseDuration;
286 if (time < secondEnd) {
287 if (localPulseTime) *localPulseTime = time - freeEnd;
289 }
291 }
292
293 const double halfFree = 0.5 * config.freeEvolutionDuration;
294 const double firstFreeEnd = firstEnd + halfFree;
295 if (time < firstFreeEnd) return RamseyPulseSegment2D::EchoFreeFirst;
296
297 const double echoEnd = firstFreeEnd + config.echoPulseDuration;
298 if (time < echoEnd) {
299 if (localPulseTime) *localPulseTime = time - firstFreeEnd;
301 }
302
303 const double secondFreeEnd = echoEnd + halfFree;
304 if (time < secondFreeEnd) return RamseyPulseSegment2D::EchoFreeSecond;
305
306 const double secondEnd = secondFreeEnd + config.pulseDuration;
307 if (time < secondEnd) {
308 if (localPulseTime) *localPulseTime = time - secondFreeEnd;
310 }
312}
313
315 const RamseyPulseSequence2DConfig &config,
316 double time) noexcept
317{
318 double localTime = 0.0;
319 const RamseyPulseSegment2D segment = ramseySegment(config, time, &localTime);
320 if (segment != RamseyPulseSegment2D::FirstPulse &&
323 return config.meanValue;
324 }
325
326 double phaseDegrees = config.firstPulsePhaseDegrees;
327 if (segment == RamseyPulseSegment2D::EchoPulse) {
328 phaseDegrees = config.echoPulsePhaseDegrees;
329 } else if (segment == RamseyPulseSegment2D::SecondPulse) {
330 phaseDegrees = config.secondPulsePhaseDegrees;
331 }
332 const double phase = config.angularFrequency * localTime + phaseDegrees * Pi / 180.0;
333 return config.meanValue + config.amplitude * std::sin(phase);
334}
335
337 const PotentialScene2D &baseScene,
338 const QuantumQuench2DConfig &config,
339 double time,
340 PotentialField2D &target)
341{
343 if (!validate(baseScene, config) || !config.enabled) {
344 baseScene.rasterize(target);
345 state.valid = !config.enabled;
346 state.currentValue = 0.0;
347 return state;
348 }
349
350 PotentialScene2D scene = baseScene;
351 PotentialObject2D *object = scene.find(config.targetObjectId);
352 if (!object) {
353 baseScene.rasterize(target);
354 return state;
355 }
356
357 state.fired = time >= config.quenchTime;
358 state.currentValue = state.fired ? config.afterValue : config.beforeValue;
359 if (!applyParameter(*object, config.parameter, state.currentValue) || !object->valid()) {
360 baseScene.rasterize(target);
361 return state;
362 }
363
364 scene.rasterize(target);
365 state.valid = true;
366 return state;
367}
368
370 const PotentialScene2D &baseScene,
371 const PeriodicPotentialDrive2DConfig &config,
372 double time,
373 PotentialField2D &target)
374{
376 if (!validatePeriodic(baseScene, config) || !config.enabled) {
377 baseScene.rasterize(target);
378 state.valid = !config.enabled;
379 state.currentValue = config.meanValue;
380 return state;
381 }
382
383 PotentialScene2D scene = baseScene;
384 PotentialObject2D *object = scene.find(config.targetObjectId);
385 if (!object) {
386 baseScene.rasterize(target);
387 return state;
388 }
389
390 state.phaseRadians = config.angularFrequency * time + config.phaseDegrees * Pi / 180.0;
391 state.currentValue = periodicValue(config, time);
392 if (!applyParameter(*object, config.parameter, state.currentValue) || !object->valid()) {
393 baseScene.rasterize(target);
394 return state;
395 }
396
397 scene.rasterize(target);
398 state.valid = true;
399 return state;
400}
401
403 const PotentialScene2D &baseScene,
404 const LinearPotentialSweep2DConfig &config,
405 double time,
406 PotentialField2D &target)
407{
409 if (!validateSweep(baseScene, config) || !config.enabled) {
410 baseScene.rasterize(target);
411 state.valid = !config.enabled;
412 state.currentValue = config.startValue;
413 return state;
414 }
415
416 PotentialScene2D scene = baseScene;
417 PotentialObject2D *object = scene.find(config.targetObjectId);
418 if (!object) {
419 baseScene.rasterize(target);
420 return state;
421 }
422
423 state.currentValue = sweepValue(config, time);
424 const double outwardEnd = config.startTime + config.duration;
425 const double holdEnd = outwardEnd + (config.returnEnabled ? config.holdDuration : 0.0);
426 const double endTime = config.startTime + sweepTotalDuration(config);
427 state.finished = time >= endTime;
428 state.holding = config.returnEnabled && time >= outwardEnd && time < holdEnd;
429 state.returning = config.returnEnabled && time >= holdEnd && time < endTime;
430 if (time <= config.startTime) {
431 state.progress = 0.0;
432 } else if (state.finished) {
433 state.progress = 1.0;
434 } else {
435 state.progress = (time - config.startTime) /
436 std::max(1.0e-12, sweepTotalDuration(config));
437 }
438
439 if (!applyParameter(*object, config.parameter, state.currentValue) || !object->valid()) {
440 baseScene.rasterize(target);
441 return state;
442 }
443
444 scene.rasterize(target);
445 state.valid = true;
446 return state;
447}
448
450 const PotentialScene2D &baseScene,
451 const RamseyPulseSequence2DConfig &config,
452 double time,
453 PotentialField2D &target)
454{
456 if (!validateRamsey(baseScene, config) || !config.enabled) {
457 baseScene.rasterize(target);
458 state.valid = !config.enabled;
459 state.currentValue = config.meanValue;
460 return state;
461 }
462
463 PotentialScene2D scene = baseScene;
464 PotentialObject2D *object = scene.find(config.targetObjectId);
465 if (!object) {
466 baseScene.rasterize(target);
467 return state;
468 }
469
470 state.segment = ramseySegment(config, time, &state.localPulseTime);
471 state.currentValue = ramseyValue(config, time);
472 const double total = ramseyTotalDuration(config);
473 if (time <= config.startTime) state.progress = 0.0;
474 else if (time >= config.startTime + total) state.progress = 1.0;
475 else state.progress = (time - config.startTime) / std::max(1.0e-12, total);
476
477 if (!applyParameter(*object, config.parameter, state.currentValue) || !object->valid()) {
478 baseScene.rasterize(target);
479 return state;
480 }
481
482 scene.rasterize(target);
483 state.valid = true;
484 return state;
485}
486
487} // namespace qpe
Implements the Potential Field2D component.
Implements the Potential Scene2D component.
void rasterize(PotentialField2D &target) const
Performs rasterize.
PotentialObject2D * find(std::uint64_t id) noexcept
Performs find.
static RamseyPulseSequence2DState rasterizeRamsey(const PotentialScene2D &baseScene, const RamseyPulseSequence2DConfig &config, double time, PotentialField2D &target)
Performs rasterize ramsey.
static bool parameterValue(const PotentialObject2D &object, TimePotentialParameter2D parameter, double &value) noexcept
Performs parameter value.
static bool validatePeriodic(const PotentialScene2D &scene, const PeriodicPotentialDrive2DConfig &config) noexcept
Validates periodic.
static bool validateSweep(const PotentialScene2D &scene, const LinearPotentialSweep2DConfig &config) noexcept
Validates sweep.
static double sweepValue(const LinearPotentialSweep2DConfig &config, double time) noexcept
Performs sweep value.
static bool validateRamsey(const PotentialScene2D &scene, const RamseyPulseSequence2DConfig &config) noexcept
Validates ramsey.
static RamseyPulseSegment2D ramseySegment(const RamseyPulseSequence2DConfig &config, double time, double *localPulseTime=nullptr) noexcept
Performs ramsey segment.
static bool applyParameter(PotentialObject2D &object, TimePotentialParameter2D parameter, double value) noexcept
Applies parameter.
static double ramseyValue(const RamseyPulseSequence2DConfig &config, double time) noexcept
Performs ramsey value.
static double ramseyTotalDuration(const RamseyPulseSequence2DConfig &config) noexcept
Performs ramsey total duration.
static PeriodicPotentialDrive2DState rasterizePeriodic(const PotentialScene2D &baseScene, const PeriodicPotentialDrive2DConfig &config, double time, PotentialField2D &target)
Performs rasterize periodic.
static double sweepTotalDuration(const LinearPotentialSweep2DConfig &config) noexcept
Performs sweep total duration.
static QuantumQuench2DState rasterize(const PotentialScene2D &baseScene, const QuantumQuench2DConfig &config, double time, PotentialField2D &target)
Performs rasterize.
static bool validate(const PotentialScene2D &scene, const QuantumQuench2DConfig &config) noexcept
Performs validate.
static double periodicValue(const PeriodicPotentialDrive2DConfig &config, double time) noexcept
Performs periodic value.
static LinearPotentialSweep2DState rasterizeSweep(const PotentialScene2D &baseScene, const LinearPotentialSweep2DConfig &config, double time, PotentialField2D &target)
Performs rasterize sweep.
TimePotentialParameter2D
Enumerates the supported Time Potential Parameter2D values.
RamseyPulseSegment2D
Enumerates the supported Ramsey Pulse Segment2D values.
Declares the potentialfield2d physics/numerical component used by QPE experiments.
Configuration values for Linear Potential Sweep2D Config.
Data record containing Linear Potential Sweep2D State.
Configuration values for Periodic Potential Drive2D Config.
Data record containing Periodic Potential Drive2D State.
Data structure used by the Potential Object2D component.
bool valid() const noexcept
Performs valid.
Configuration values for Quantum Quench2D Config.
TimePotentialParameter2D parameter
Data record containing Quantum Quench2D State.
Configuration values for Ramsey Pulse Sequence2D Config.
Data record containing Ramsey Pulse Sequence2D State.
Declares the timedependentpotential2d physics/numerical component used by QPE experiments.