Quantum Phenomena Explorer 7.9.8
Interactive quantum-phenomena Explorer Tutor — source documentation
Loading...
Searching...
No Matches
experimentdocument2d_tests.cpp
Go to the documentation of this file.
1/**
2 * @file experimentdocument2d_tests.cpp
3 * @brief Implements regression and invariant tests for experimentdocument2d tests.
4 * @ingroup qpe_tests
5 *
6 * Source: @c tests/experimentdocument2d_tests.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 <QJsonArray>
17#include <QJsonObject>
18#include <QTemporaryDir>
19
20#include <cmath>
21
22namespace qpe {
23namespace tests {
24
25/**
26 * @brief Runs experiment document2 d tests.
27 * @param errorMessage The error message value used by the operation.
28 */
29bool runExperimentDocument2DTests(std::string &errorMessage)
30{
31 errorMessage.clear();
32
34 source.name = QStringLiteral("Round trip test");
35 source.sourcePreset = QStringLiteral("Quantum Tunneling (E < V0)");
36 source.controls.insert(QStringLiteral("universeWidthSpinBox"), 61.44);
37 source.controls.insert(QStringLiteral("geometryComboBox"), 3);
38 source.controls.insert(QStringLiteral("currentOverlayCheckBox"), true);
39
40 PotentialObject2D barrier;
42 barrier.value = 4.5f;
43 barrier.centerX = -0.5f;
44 barrier.centerY = 0.0f;
45 barrier.length = 20.0f;
46 barrier.thickness = 0.64f;
47 const std::uint64_t barrierId = source.potentialScene.add(barrier);
48 source.potentialSceneActive = true;
49 source.initialPreparationMode = 2;
50 source.boundStateA = 0;
51 source.boundStateB = 2;
52 source.boundRelativePhaseDegrees = 45.0;
53 source.collapseResolution = 0.72;
54 source.quench.enabled = true;
55 source.quench.targetObjectId = barrierId;
57 source.quench.quenchTime = 1.25;
58 source.quench.beforeValue = 4.5;
59 source.quench.afterValue = 2.25;
60
61 PotentialObject2D second = barrier;
62 second.centerX = 1.0f;
63 const std::uint64_t secondId = source.potentialScene.add(second);
64
65 source.periodicDrive.enabled = true;
66 source.periodicDrive.targetObjectId = secondId;
68 source.periodicDrive.meanValue = 1.0;
69 source.periodicDrive.amplitude = 0.7;
71 source.periodicDrive.phaseDegrees = 30.0;
72
73 PotentialObject2D gaussian;
75 gaussian.value = -3.5f;
76 gaussian.centerX = 2.0f;
77 gaussian.sigmaX = 1.25f;
78 gaussian.sigmaY = 2.5f;
79 const std::uint64_t gaussianId = source.potentialScene.add(gaussian);
80
81 PotentialObject2D linearBias;
83 linearBias.slopeX = 0.35f;
84 const std::uint64_t biasId = source.potentialScene.add(linearBias);
85 source.linearSweep.enabled = true;
86 source.linearSweep.targetObjectId = biasId;
88 source.linearSweep.startValue = 0.35;
89 source.linearSweep.endValue = -0.35;
90 source.linearSweep.startTime = 0.5;
91 source.linearSweep.duration = 4.0;
92 source.linearSweep.returnEnabled = true;
93 source.linearSweep.holdDuration = 4.0;
94 source.linearSweep.returnDuration = 4.0;
95
96 source.ramseySequence.enabled = true;
97 source.ramseySequence.targetObjectId = biasId;
99 source.ramseySequence.meanValue = 0.0;
100 source.ramseySequence.amplitude = 0.10;
101 source.ramseySequence.angularFrequency = 0.305536;
104 source.ramseySequence.startTime = 0.25;
105 source.ramseySequence.pulseDuration = 14.35;
107 source.ramseySequence.echoEnabled = true;
108 source.ramseySequence.echoPulseDuration = 25.75;
110 source.ramseyEnsemble.enabled = true;
111 source.ramseyEnsemble.detuningStdDev = 0.06;
112 source.ramseyEnsemble.memberCount = 41;
113 source.talbotInitialState.period = 5.12;
114 source.talbotInitialState.toothSigma = 0.45;
115 source.talbotInitialState.offsetX = 0.32;
116 source.talbotInitialState.centerY = -8.0;
117 source.talbotInitialState.sigmaY = 1.5;
118 source.talbotInitialState.momentumY = 1.2;
122 source.vortexInitialState.coreX = 1.0;
123 source.vortexInitialState.coreY = 0.0;
124 source.vortexInitialState.charge = 1;
125 source.andersonInitialState.centerX = 0.0;
126 source.andersonInitialState.cleanLaneY = 4.0;
128 source.andersonInitialState.sigma = 0.35;
130 source.kickedRotor.enabled = true;
131 source.kickedRotor.firstKickTime = 0.20;
132 source.kickedRotor.kickPeriod = 1.0;
133 source.kickedRotor.phaseStrength = 6.0;
134 source.kickedRotorInitialState.yCenter = 0.0;
135 source.kickedRotorInitialState.ySigma = 1.5;
137 source.quantumZeno.enabled = true;
138 source.quantumZeno.firstMeasurementTime = 0.40;
139 source.quantumZeno.measurementPeriod = 0.10;
140 source.quantumZeno.laneSplitY = 0.0;
141 source.quantumZeno.survivalBoundaryX = 0.40;
142 source.quantumZeno.edgeWidth = 0.32;
143 source.quantumZenoInitialState.centerX = -5.5;
146 source.quantumZenoInitialState.sigma = 0.80;
149 source.quantumScar.enabled = true;
150 source.quantumScar.orbitBandHalfWidth = 0.80;
151 source.quantumScar.referenceEnergy = 9.50;
152
153 const QJsonObject json = ExperimentDocument2DJson::toJson(source);
154
155 ExperimentDocument2D restored;
156 QString qtError;
157 if (!ExperimentDocument2DJson::fromJson(json, restored, qtError)) {
158 errorMessage = std::string("round trip parse failed: ") + qtError.toStdString();
159 return false;
160 }
161
163 restored.name != source.name ||
164 restored.sourcePreset != source.sourcePreset ||
165 restored.controls.value(QStringLiteral("geometryComboBox")).toInt() != 3 ||
166 !restored.controls.value(QStringLiteral("currentOverlayCheckBox")).toBool() ||
167 !restored.potentialSceneActive ||
168 restored.potentialScene.size() != 4 ||
169 !restored.potentialScene.find(barrierId) ||
170 !restored.potentialScene.find(secondId) ||
171 !restored.potentialScene.find(gaussianId) ||
172 !restored.potentialScene.find(biasId) ||
173 std::abs(restored.potentialScene.find(gaussianId)->sigmaY - 2.5f) > 1.0e-6f ||
174 restored.initialPreparationMode != 2 || restored.boundStateA != 0 ||
175 restored.boundStateB != 2 ||
176 std::abs(restored.boundRelativePhaseDegrees - 45.0) > 1.0e-12 ||
177 std::abs(restored.collapseResolution - 0.72) > 1.0e-12 ||
178 !restored.quench.enabled || restored.quench.targetObjectId != barrierId ||
180 std::abs(restored.quench.quenchTime - 1.25) > 1.0e-12 ||
181 std::abs(restored.quench.afterValue - 2.25) > 1.0e-12 ||
182 !restored.periodicDrive.enabled || restored.periodicDrive.targetObjectId != secondId ||
184 std::abs(restored.periodicDrive.amplitude - 0.7) > 1.0e-12 ||
185 std::abs(restored.periodicDrive.angularFrequency - 0.5) > 1.0e-12 ||
186 std::abs(restored.periodicDrive.phaseDegrees - 30.0) > 1.0e-12 ||
187 !restored.linearSweep.enabled || restored.linearSweep.targetObjectId != biasId ||
189 std::abs(restored.linearSweep.startValue - 0.35) > 1.0e-12 ||
190 std::abs(restored.linearSweep.endValue + 0.35) > 1.0e-12 ||
191 std::abs(restored.linearSweep.startTime - 0.5) > 1.0e-12 ||
192 std::abs(restored.linearSweep.duration - 4.0) > 1.0e-12 ||
193 !restored.linearSweep.returnEnabled ||
194 std::abs(restored.linearSweep.holdDuration - 4.0) > 1.0e-12 ||
195 std::abs(restored.linearSweep.returnDuration - 4.0) > 1.0e-12 ||
196 !restored.ramseySequence.enabled || restored.ramseySequence.targetObjectId != biasId ||
198 std::abs(restored.ramseySequence.amplitude - 0.10) > 1.0e-12 ||
199 std::abs(restored.ramseySequence.angularFrequency - 0.305536) > 1.0e-12 ||
200 std::abs(restored.ramseySequence.startTime - 0.25) > 1.0e-12 ||
201 std::abs(restored.ramseySequence.pulseDuration - 14.35) > 1.0e-12 ||
202 std::abs(restored.ramseySequence.freeEvolutionDuration - 5.5) > 1.0e-12 ||
203 !restored.ramseySequence.echoEnabled ||
204 std::abs(restored.ramseySequence.echoPulseDuration - 25.75) > 1.0e-12 ||
205 std::abs(restored.ramseySequence.echoPulsePhaseDegrees - 90.0) > 1.0e-12 ||
206 !restored.ramseyEnsemble.enabled ||
207 std::abs(restored.ramseyEnsemble.detuningStdDev - 0.06) > 1.0e-12 ||
208 restored.ramseyEnsemble.memberCount != 41 ||
209 std::abs(restored.talbotInitialState.period - 5.12) > 1.0e-12 ||
210 std::abs(restored.talbotInitialState.toothSigma - 0.45) > 1.0e-12 ||
211 std::abs(restored.talbotInitialState.offsetX - 0.32) > 1.0e-12 ||
212 std::abs(restored.talbotInitialState.centerY + 8.0) > 1.0e-12 ||
213 std::abs(restored.talbotInitialState.sigmaY - 1.5) > 1.0e-12 ||
214 std::abs(restored.talbotInitialState.momentumY - 1.2) > 1.0e-12 ||
215 std::abs(restored.vortexInitialState.envelopeSigma - 1.0) > 1.0e-12 ||
216 std::abs(restored.vortexInitialState.coreX - 1.0) > 1.0e-12 ||
217 std::abs(restored.vortexInitialState.coreY) > 1.0e-12 ||
218 restored.vortexInitialState.charge != 1 ||
219 !restored.kickedRotor.enabled ||
220 std::abs(restored.kickedRotor.firstKickTime - 0.20) > 1.0e-12 ||
221 std::abs(restored.kickedRotor.kickPeriod - 1.0) > 1.0e-12 ||
222 std::abs(restored.kickedRotor.phaseStrength - 6.0) > 1.0e-12 ||
223 std::abs(restored.kickedRotorInitialState.ySigma - 1.5) > 1.0e-12 ||
225 !restored.quantumZeno.enabled ||
226 std::abs(restored.quantumZeno.firstMeasurementTime - 0.40) > 1.0e-12 ||
227 std::abs(restored.quantumZeno.measurementPeriod - 0.10) > 1.0e-12 ||
228 std::abs(restored.quantumZeno.survivalBoundaryX - 0.40) > 1.0e-12 ||
229 std::abs(restored.quantumZeno.edgeWidth - 0.32) > 1.0e-12 ||
230 std::abs(restored.quantumZenoInitialState.controlLaneY - 4.8) > 1.0e-12 ||
231 std::abs(restored.quantumZenoInitialState.watchedLaneY + 4.8) > 1.0e-12 ||
232 std::abs(restored.quantumZenoInitialState.sigma - 0.80) > 1.0e-12 ||
233 std::abs(restored.quantumZenoInitialState.momentumX - 1.50) > 1.0e-12 ||
234 !restored.quantumScar.enabled ||
235 std::abs(restored.quantumScar.orbitBandHalfWidth - 0.80) > 1.0e-12 ||
236 std::abs(restored.quantumScar.referenceEnergy - 9.50) > 1.0e-12) {
237 errorMessage = "round trip values differ";
238 return false;
239 }
240
241 QTemporaryDir temporaryDirectory;
242 if (!temporaryDirectory.isValid()) {
243 errorMessage = "cannot create temporary directory";
244 return false;
245 }
246
247 const QString fileName = temporaryDirectory.filePath(QStringLiteral("experiment.qpe.json"));
248 if (!ExperimentDocument2DJson::saveFile(fileName, source, qtError)) {
249 errorMessage = std::string("file save failed: ") + qtError.toStdString();
250 return false;
251 }
252
253 ExperimentDocument2D fileRestored;
254 if (!ExperimentDocument2DJson::loadFile(fileName, fileRestored, qtError)) {
255 errorMessage = std::string("file load failed: ") + qtError.toStdString();
256 return false;
257 }
258 if (fileRestored.controls.value(QStringLiteral("universeWidthSpinBox")).toDouble() != 61.44 ||
259 fileRestored.sourcePreset != source.sourcePreset ||
260 fileRestored.potentialScene.size() != 4 ||
261 fileRestored.initialPreparationMode != 2 ||
262 std::abs(fileRestored.collapseResolution - 0.72) > 1.0e-12 ||
263 !fileRestored.quench.enabled || fileRestored.quench.targetObjectId != barrierId ||
264 !fileRestored.periodicDrive.enabled || fileRestored.periodicDrive.targetObjectId != secondId ||
265 !fileRestored.linearSweep.enabled || fileRestored.linearSweep.targetObjectId != biasId ||
266 !fileRestored.ramseySequence.enabled || fileRestored.ramseySequence.targetObjectId != biasId ||
267 !fileRestored.ramseyEnsemble.enabled || fileRestored.ramseyEnsemble.memberCount != 41 ||
268 std::abs(fileRestored.talbotInitialState.period - 5.12) > 1.0e-12 ||
269 std::abs(fileRestored.vortexInitialState.coreX - 1.0) > 1.0e-12 ||
270 fileRestored.vortexInitialState.charge != 1 ||
271 !fileRestored.kickedRotor.enabled ||
272 std::abs(fileRestored.kickedRotor.phaseStrength - 6.0) > 1.0e-12 ||
273 std::abs(fileRestored.kickedRotorInitialState.ySigma - 1.5) > 1.0e-12 ||
274 !fileRestored.quantumZeno.enabled ||
275 std::abs(fileRestored.quantumZeno.measurementPeriod - 0.10) > 1.0e-12 ||
276 std::abs(fileRestored.quantumZenoInitialState.sigma - 0.80) > 1.0e-12 ||
277 !fileRestored.quantumScar.enabled ||
278 std::abs(fileRestored.quantumScar.referenceEnergy - 9.50) > 1.0e-12) {
279 errorMessage = "file round trip values differ";
280 return false;
281 }
282
283 ExperimentDocument2D talbotSource = source;
284 talbotSource.initialPreparationMode = 3;
285 talbotSource.name = QStringLiteral("Talbot persistence test");
286 const QJsonObject talbotJson = ExperimentDocument2DJson::toJson(talbotSource);
287 ExperimentDocument2D talbotRestored;
288 if (!ExperimentDocument2DJson::fromJson(talbotJson, talbotRestored, qtError) ||
289 talbotRestored.initialPreparationMode != 3 ||
290 std::abs(talbotRestored.talbotInitialState.period - 5.12) > 1.0e-12 ||
291 std::abs(talbotRestored.talbotInitialState.toothSigma - 0.45) > 1.0e-12 ||
292 std::abs(talbotRestored.talbotInitialState.momentumY - 1.2) > 1.0e-12) {
293 errorMessage = std::string("schema 13 Talbot preparation round trip failed: ") + qtError.toStdString();
294 return false;
295 }
296
297 ExperimentDocument2D vortexSource = source;
298 vortexSource.initialPreparationMode = 4;
299 vortexSource.name = QStringLiteral("Vortex persistence test");
300 const QJsonObject vortexJson = ExperimentDocument2DJson::toJson(vortexSource);
301 ExperimentDocument2D vortexRestored;
302 if (!ExperimentDocument2DJson::fromJson(vortexJson, vortexRestored, qtError) ||
303 vortexRestored.initialPreparationMode != 4 ||
304 std::abs(vortexRestored.vortexInitialState.envelopeSigma - 1.0) > 1.0e-12 ||
305 std::abs(vortexRestored.vortexInitialState.coreX - 1.0) > 1.0e-12 ||
306 vortexRestored.vortexInitialState.charge != 1) {
307 errorMessage = std::string("schema 14 Vortex preparation round trip failed: ") + qtError.toStdString();
308 return false;
309 }
310
311
312 ExperimentDocument2D andersonSource = source;
313 andersonSource.initialPreparationMode = 5;
314 andersonSource.name = QStringLiteral("Anderson persistence test");
315 const QJsonObject andersonJson = ExperimentDocument2DJson::toJson(andersonSource);
316 ExperimentDocument2D andersonRestored;
317 if (!ExperimentDocument2DJson::fromJson(andersonJson, andersonRestored, qtError) ||
318 andersonRestored.initialPreparationMode != 5 ||
319 std::abs(andersonRestored.andersonInitialState.cleanLaneY - 4.0) > 1.0e-12 ||
320 std::abs(andersonRestored.andersonInitialState.disorderLaneY + 4.0) > 1.0e-12 ||
321 std::abs(andersonRestored.andersonInitialState.sigma - 0.35) > 1.0e-12) {
322 errorMessage = std::string("schema 15 Anderson preparation round trip failed: ") + qtError.toStdString();
323 return false;
324 }
325
326 ExperimentDocument2D kickedRotorSource = source;
327 kickedRotorSource.initialPreparationMode = 6;
328 kickedRotorSource.name = QStringLiteral("Kicked Rotor persistence test");
329 const QJsonObject kickedRotorJson = ExperimentDocument2DJson::toJson(kickedRotorSource);
330 ExperimentDocument2D kickedRotorRestored;
331 if (!ExperimentDocument2DJson::fromJson(kickedRotorJson, kickedRotorRestored, qtError) ||
332 kickedRotorRestored.initialPreparationMode != 6 ||
333 !kickedRotorRestored.kickedRotor.enabled ||
334 std::abs(kickedRotorRestored.kickedRotor.firstKickTime - 0.20) > 1.0e-12 ||
335 std::abs(kickedRotorRestored.kickedRotor.kickPeriod - 1.0) > 1.0e-12 ||
336 std::abs(kickedRotorRestored.kickedRotor.phaseStrength - 6.0) > 1.0e-12 ||
337 std::abs(kickedRotorRestored.kickedRotorInitialState.ySigma - 1.5) > 1.0e-12 ||
338 kickedRotorRestored.kickedRotorInitialState.initialMomentumMode != 0) {
339 errorMessage = std::string("schema 16 Kicked Rotor preparation round trip failed: ") + qtError.toStdString();
340 return false;
341 }
342
343 ExperimentDocument2D zenoSource = source;
344 zenoSource.initialPreparationMode = 7;
345 zenoSource.name = QStringLiteral("Quantum Zeno persistence test");
346 const QJsonObject zenoJson = ExperimentDocument2DJson::toJson(zenoSource);
347 ExperimentDocument2D zenoRestored;
348 if (!ExperimentDocument2DJson::fromJson(zenoJson, zenoRestored, qtError) ||
349 zenoRestored.initialPreparationMode != 7 ||
350 !zenoRestored.quantumZeno.enabled ||
351 std::abs(zenoRestored.quantumZeno.firstMeasurementTime - 0.40) > 1.0e-12 ||
352 std::abs(zenoRestored.quantumZeno.measurementPeriod - 0.10) > 1.0e-12 ||
353 std::abs(zenoRestored.quantumZeno.survivalBoundaryX - 0.40) > 1.0e-12 ||
354 std::abs(zenoRestored.quantumZeno.edgeWidth - 0.32) > 1.0e-12 ||
355 std::abs(zenoRestored.quantumZenoInitialState.controlLaneY - 4.8) > 1.0e-12 ||
356 std::abs(zenoRestored.quantumZenoInitialState.watchedLaneY + 4.8) > 1.0e-12 ||
357 std::abs(zenoRestored.quantumZenoInitialState.sigma - 0.80) > 1.0e-12 ||
358 std::abs(zenoRestored.quantumZenoInitialState.momentumX - 1.50) > 1.0e-12) {
359 errorMessage = std::string("schema 17 Quantum Zeno preparation round trip failed: ") + qtError.toStdString();
360 return false;
361 }
362
363 ExperimentDocument2D scarSource = source;
364 scarSource.name = QStringLiteral("Quantum Scars persistence test");
365 const QJsonObject scarJson = ExperimentDocument2DJson::toJson(scarSource);
366 ExperimentDocument2D scarRestored;
367 if (!ExperimentDocument2DJson::fromJson(scarJson, scarRestored, qtError) ||
368 !scarRestored.quantumScar.enabled ||
369 std::abs(scarRestored.quantumScar.orbitBandHalfWidth - 0.80) > 1.0e-12 ||
370 std::abs(scarRestored.quantumScar.referenceEnergy - 9.50) > 1.0e-12) {
371 errorMessage = std::string("schema 18 Quantum Scars round trip failed: ") + qtError.toStdString();
372 return false;
373 }
374
375 ExperimentDocument2D berrySource;
376 berrySource.name = QStringLiteral("Berry Phase persistence test");
377 berrySource.sourcePreset = QStringLiteral("Berry Phase / Geometric Phase");
378 berrySource.controls.insert(QStringLiteral("universeWidthSpinBox"), 40.96);
379 berrySource.initialPreparationMode = 8;
380 berrySource.potentialSceneActive = true;
381 PotentialObject2D berryTrap;
383 berryTrap.curvatureX = 1.0f;
384 berryTrap.curvatureY = 1.0f;
385 berrySource.potentialScene.add(berryTrap);
386 berrySource.quantumBerry.enabled = true;
387 berrySource.quantumBerry.anisotropy = 0.35;
388 berrySource.quantumBerry.startTime = 0.5;
389 berrySource.quantumBerry.duration = 240.0;
390 berrySource.quantumBerry.winding = -1;
391 const QJsonObject berryJson = ExperimentDocument2DJson::toJson(berrySource);
392 ExperimentDocument2D berryRestored;
393 if (!ExperimentDocument2DJson::fromJson(berryJson, berryRestored, qtError) ||
394 berryRestored.initialPreparationMode != 8 || !berryRestored.quantumBerry.enabled ||
395 std::abs(berryRestored.quantumBerry.anisotropy - 0.35) > 1.0e-12 ||
396 std::abs(berryRestored.quantumBerry.startTime - 0.5) > 1.0e-12 ||
397 std::abs(berryRestored.quantumBerry.duration - 240.0) > 1.0e-12 ||
398 berryRestored.quantumBerry.winding != -1) {
399 errorMessage = std::string("schema 19 Berry Phase round trip failed: ") + qtError.toStdString();
400 return false;
401 }
402
403 ExperimentDocument2D loschmidtSource;
404 loschmidtSource.name = QStringLiteral("Loschmidt Echo persistence test");
405 loschmidtSource.sourcePreset = QStringLiteral("Loschmidt Echo / Quantum Time Reversal");
406 loschmidtSource.controls.insert(QStringLiteral("universeWidthSpinBox"), 40.96);
407 loschmidtSource.quantumLoschmidt.enabled = true;
408 loschmidtSource.quantumLoschmidt.reversalTime = 4.25;
409 loschmidtSource.quantumLoschmidt.momentumErrorX = 0.12;
410 loschmidtSource.quantumLoschmidt.momentumErrorY = -0.07;
411 const QJsonObject loschmidtJson = ExperimentDocument2DJson::toJson(loschmidtSource);
412 ExperimentDocument2D loschmidtRestored;
413 if (!ExperimentDocument2DJson::fromJson(loschmidtJson, loschmidtRestored, qtError) ||
414 !loschmidtRestored.quantumLoschmidt.enabled ||
415 std::abs(loschmidtRestored.quantumLoschmidt.reversalTime - 4.25) > 1.0e-12 ||
416 std::abs(loschmidtRestored.quantumLoschmidt.momentumErrorX - 0.12) > 1.0e-12 ||
417 std::abs(loschmidtRestored.quantumLoschmidt.momentumErrorY + 0.07) > 1.0e-12) {
418 errorMessage = std::string("schema 20 Loschmidt Echo round trip failed: ") + qtError.toStdString();
419 return false;
420 }
421
422 ExperimentDocument2D moshinskySource;
423 moshinskySource.name = QStringLiteral("Moshinsky Shutter persistence test");
424 moshinskySource.sourcePreset = QStringLiteral("Moshinsky Shutter / Diffraction in Time");
425 moshinskySource.controls.insert(QStringLiteral("universeWidthSpinBox"), 40.96);
426 moshinskySource.initialPreparationMode = 9;
427 moshinskySource.potentialSceneActive = true;
428 PotentialObject2D moshinskyShutter;
429 moshinskyShutter.type = PotentialObjectType2D::Barrier;
430 moshinskyShutter.value = 120.0f;
431 moshinskyShutter.centerX = 0.0f;
432 moshinskyShutter.centerY = 0.0f;
433 moshinskyShutter.length = 19.0f;
434 moshinskyShutter.thickness = 0.32f;
435 const std::uint64_t moshinskyShutterId = moshinskySource.potentialScene.add(moshinskyShutter);
436 moshinskySource.moshinskyInitialState.enabled = true;
437 moshinskySource.moshinskyInitialState.shutterX = 0.0;
438 moshinskySource.moshinskyInitialState.envelopeCenterX = -8.0;
439 moshinskySource.moshinskyInitialState.envelopeSigmaX = 8.0;
440 moshinskySource.moshinskyInitialState.centerY = 0.0;
441 moshinskySource.moshinskyInitialState.transverseSigmaY = 3.2;
442 moshinskySource.moshinskyInitialState.momentumX = 3.0;
443 moshinskySource.moshinskyInitialState.edgeWidth = 0.18;
444 moshinskySource.quantumMoshinsky.enabled = true;
445 moshinskySource.quantumMoshinsky.shutterObjectId = moshinskyShutterId;
446 moshinskySource.quantumMoshinsky.openTime = 0.25;
447 moshinskySource.quantumMoshinsky.detectorX = 3.5;
448 moshinskySource.quantumMoshinsky.analysisEndTime = 7.0;
449 const QJsonObject moshinskyJson = ExperimentDocument2DJson::toJson(moshinskySource);
450 ExperimentDocument2D moshinskyRestored;
451 if (!ExperimentDocument2DJson::fromJson(moshinskyJson, moshinskyRestored, qtError) ||
452 moshinskyRestored.initialPreparationMode != 9 ||
453 !moshinskyRestored.moshinskyInitialState.enabled ||
454 !moshinskyRestored.quantumMoshinsky.enabled ||
455 std::abs(moshinskyRestored.moshinskyInitialState.envelopeCenterX + 8.0) > 1.0e-12 ||
456 std::abs(moshinskyRestored.moshinskyInitialState.edgeWidth - 0.18) > 1.0e-12 ||
457 std::abs(moshinskyRestored.quantumMoshinsky.openTime - 0.25) > 1.0e-12 ||
458 std::abs(moshinskyRestored.quantumMoshinsky.detectorX - 3.5) > 1.0e-12 ||
459 std::abs(moshinskyRestored.quantumMoshinsky.analysisEndTime - 7.0) > 1.0e-12 ||
460 moshinskyRestored.quantumMoshinsky.shutterObjectId != moshinskyShutterId) {
461 errorMessage = std::string("schema 21 Moshinsky Shutter round trip failed: ") + qtError.toStdString();
462 return false;
463 }
464
465 ExperimentDocument2D kapitzaSource;
466 kapitzaSource.name = QStringLiteral("Kapitza-Dirac persistence test");
467 kapitzaSource.sourcePreset = QStringLiteral("Kapitza-Dirac Diffraction / Optical Standing Wave");
468 kapitzaSource.controls.insert(QStringLiteral("universeWidthSpinBox"), 40.96);
469 kapitzaSource.initialPreparationMode = 10;
470 kapitzaSource.kapitzaDiracInitialState.centerY = -6.25;
471 kapitzaSource.kapitzaDiracInitialState.sigmaX = 4.75;
472 kapitzaSource.kapitzaDiracInitialState.sigmaY = 1.15;
473 kapitzaSource.kapitzaDiracInitialState.momentumY = 1.25;
474 kapitzaSource.quantumKapitzaDirac.enabled = true;
475 kapitzaSource.quantumKapitzaDirac.latticePeriod = 4.096;
476 kapitzaSource.quantumKapitzaDirac.latticeDepth = 15.5;
477 kapitzaSource.quantumKapitzaDirac.latticePhaseDegrees = 22.5;
478 kapitzaSource.quantumKapitzaDirac.pulseStartTime = 0.1;
479 kapitzaSource.quantumKapitzaDirac.pulseDuration = 0.28;
480 kapitzaSource.quantumKapitzaDirac.analysisEndTime = 4.5;
481 kapitzaSource.quantumKapitzaDirac.maximumOrder = 5;
482 const QJsonObject kapitzaJson = ExperimentDocument2DJson::toJson(kapitzaSource);
483 ExperimentDocument2D kapitzaRestored;
484 if (!ExperimentDocument2DJson::fromJson(kapitzaJson, kapitzaRestored, qtError) ||
485 kapitzaRestored.initialPreparationMode != 10 ||
486 !kapitzaRestored.quantumKapitzaDirac.enabled ||
487 std::abs(kapitzaRestored.kapitzaDiracInitialState.centerY + 6.25) > 1.0e-12 ||
488 std::abs(kapitzaRestored.kapitzaDiracInitialState.sigmaX - 4.75) > 1.0e-12 ||
489 std::abs(kapitzaRestored.quantumKapitzaDirac.latticeDepth - 15.5) > 1.0e-12 ||
490 std::abs(kapitzaRestored.quantumKapitzaDirac.latticePhaseDegrees - 22.5) > 1.0e-12 ||
491 std::abs(kapitzaRestored.quantumKapitzaDirac.pulseDuration - 0.28) > 1.0e-12 ||
492 kapitzaRestored.quantumKapitzaDirac.maximumOrder != 5) {
493 errorMessage = std::string("schema 22 Kapitza-Dirac round trip failed: ") + qtError.toStdString();
494 return false;
495 }
496
497 ExperimentDocument2D aharonovSource;
498 aharonovSource.name = QStringLiteral("Aharonov-Bohm persistence test");
499 aharonovSource.sourcePreset = QStringLiteral("Aharonov-Bohm Effect / Magnetic Flux");
500 aharonovSource.controls.insert(QStringLiteral("universeWidthSpinBox"), 40.96);
501 aharonovSource.initialPreparationMode = 11;
502 aharonovSource.quantumAharonovBohm.enabled = true;
503 aharonovSource.quantumAharonovBohm.solenoidX = 0.3;
504 aharonovSource.quantumAharonovBohm.solenoidY = -0.2;
505 aharonovSource.quantumAharonovBohm.solenoidRadius = 1.4;
506 aharonovSource.quantumAharonovBohm.fluxQuanta = 0.75;
507 aharonovSource.quantumAharonovBohm.barrierHeight = 150.0;
508 aharonovSource.quantumAharonovBohm.detectorX = 6.5;
509 aharonovSource.quantumAharonovBohm.analysisEndTime = 5.5;
510 const QJsonObject aharonovJson = ExperimentDocument2DJson::toJson(aharonovSource);
511 ExperimentDocument2D aharonovRestored;
512 if (!ExperimentDocument2DJson::fromJson(aharonovJson, aharonovRestored, qtError) ||
513 aharonovRestored.initialPreparationMode != 11 ||
514 !aharonovRestored.quantumAharonovBohm.enabled ||
515 std::abs(aharonovRestored.quantumAharonovBohm.solenoidX - 0.3) > 1.0e-12 ||
516 std::abs(aharonovRestored.quantumAharonovBohm.solenoidY + 0.2) > 1.0e-12 ||
517 std::abs(aharonovRestored.quantumAharonovBohm.solenoidRadius - 1.4) > 1.0e-12 ||
518 std::abs(aharonovRestored.quantumAharonovBohm.fluxQuanta - 0.75) > 1.0e-12 ||
519 std::abs(aharonovRestored.quantumAharonovBohm.barrierHeight - 150.0) > 1.0e-12 ||
520 std::abs(aharonovRestored.quantumAharonovBohm.detectorX - 6.5) > 1.0e-12 ||
521 std::abs(aharonovRestored.quantumAharonovBohm.analysisEndTime - 5.5) > 1.0e-12) {
522 errorMessage = std::string("schema 23 Aharonov-Bohm round trip failed: ") + qtError.toStdString();
523 return false;
524 }
525
526 ExperimentDocument2D landauSource;
527 landauSource.name = QStringLiteral("Landau persistence test");
528 landauSource.sourcePreset = QStringLiteral("Landau Levels / Cyclotron Dynamics");
529 landauSource.controls.insert(QStringLiteral("landauFieldSpinBox"), 0.72);
530 landauSource.initialPreparationMode = 12;
531 landauSource.quantumLandau.enabled = true;
532 landauSource.quantumLandau.fieldStrength = -0.72;
533 landauSource.quantumLandau.preparationMode = 1;
534 landauSource.quantumLandau.landauIndex = 3;
535 landauSource.quantumLandau.orbitRadius = 6.25;
536 landauSource.quantumLandau.analysisEndTime = 18.5;
537 const QJsonObject landauJson = ExperimentDocument2DJson::toJson(landauSource);
538 ExperimentDocument2D landauRestored;
539 if (!ExperimentDocument2DJson::fromJson(landauJson, landauRestored, qtError) ||
540 landauRestored.initialPreparationMode != 12 || !landauRestored.quantumLandau.enabled ||
541 std::abs(landauRestored.quantumLandau.fieldStrength + 0.72) > 1.0e-12 ||
542 landauRestored.quantumLandau.preparationMode != 1 ||
543 landauRestored.quantumLandau.landauIndex != 3 ||
544 std::abs(landauRestored.quantumLandau.orbitRadius - 6.25) > 1.0e-12 ||
545 std::abs(landauRestored.quantumLandau.analysisEndTime - 18.5) > 1.0e-12) {
546 errorMessage = std::string("schema 24 Landau round trip failed: ") + qtError.toStdString();
547 return false;
548 }
549
550 ExperimentDocument2D hallSource;
551 hallSource.name = QStringLiteral("Quantum Hall edge persistence test");
552 hallSource.sourcePreset = QStringLiteral("Quantum Hall Edge State / Chiral Skipping Orbit");
553 hallSource.controls.insert(QStringLiteral("hallEdgeFieldSpinBox"), -0.63);
554 hallSource.initialPreparationMode = 13;
555 hallSource.quantumHallEdge.enabled = true;
556 hallSource.quantumHallEdge.fieldStrength = -0.63;
557 hallSource.quantumHallEdge.edgeY = -7.5;
558 hallSource.quantumHallEdge.wallHeight = 175.0;
559 hallSource.quantumHallEdge.launchY = -4.7;
560 hallSource.quantumHallEdge.orbitRadius = 5.1;
561 hallSource.quantumHallEdge.packetSigma = 0.95;
562 hallSource.quantumHallEdge.edgeBand = 4.6;
563 hallSource.quantumHallEdge.analysisEndTime = 9.25;
564 const QJsonObject hallJson = ExperimentDocument2DJson::toJson(hallSource);
565 ExperimentDocument2D hallRestored;
566 if (!ExperimentDocument2DJson::fromJson(hallJson, hallRestored, qtError) ||
567 hallRestored.initialPreparationMode != 13 || !hallRestored.quantumHallEdge.enabled ||
568 std::abs(hallRestored.quantumHallEdge.fieldStrength + 0.63) > 1.0e-12 ||
569 std::abs(hallRestored.quantumHallEdge.edgeY + 7.5) > 1.0e-12 ||
570 std::abs(hallRestored.quantumHallEdge.wallHeight - 175.0) > 1.0e-12 ||
571 std::abs(hallRestored.quantumHallEdge.launchY + 4.7) > 1.0e-12 ||
572 std::abs(hallRestored.quantumHallEdge.orbitRadius - 5.1) > 1.0e-12 ||
573 std::abs(hallRestored.quantumHallEdge.packetSigma - 0.95) > 1.0e-12 ||
574 std::abs(hallRestored.quantumHallEdge.edgeBand - 4.6) > 1.0e-12 ||
575 std::abs(hallRestored.quantumHallEdge.analysisEndTime - 9.25) > 1.0e-12) {
576 errorMessage = std::string("schema 25 Quantum Hall edge round trip failed: ") + qtError.toStdString();
577 return false;
578 }
579
580 ExperimentDocument2D backflowSource;
581 backflowSource.name = QStringLiteral("Quantum backflow persistence test");
582 backflowSource.sourcePreset = QStringLiteral("Quantum Backflow / Positive Momentum, Negative Current");
583 backflowSource.controls.insert(QStringLiteral("universeWidthSpinBox"), 40.96);
584 backflowSource.initialPreparationMode = 14;
585 backflowSource.quantumBackflow.enabled = true;
586 backflowSource.quantumBackflow.detectorX = 1.25;
587 backflowSource.quantumBackflow.slowWaveNumber = 0.42;
588 backflowSource.quantumBackflow.fastWaveNumber = 1.55;
589 backflowSource.quantumBackflow.momentumSigma = 0.28;
590 backflowSource.quantumBackflow.fastAmplitudeRatio = 0.61;
591 backflowSource.quantumBackflow.relativePhaseDegrees = 155.0;
592 backflowSource.quantumBackflow.initialCenterX = -2.4;
593 backflowSource.quantumBackflow.transverseSigma = 3.1;
594 backflowSource.quantumBackflow.analysisEndTime = 5.75;
595 const QJsonObject backflowJson = ExperimentDocument2DJson::toJson(backflowSource);
596 ExperimentDocument2D backflowRestored;
597 if (!ExperimentDocument2DJson::fromJson(backflowJson, backflowRestored, qtError) ||
598 backflowRestored.initialPreparationMode != 14 || !backflowRestored.quantumBackflow.enabled ||
599 std::abs(backflowRestored.quantumBackflow.detectorX - 1.25) > 1.0e-12 ||
600 std::abs(backflowRestored.quantumBackflow.slowWaveNumber - 0.42) > 1.0e-12 ||
601 std::abs(backflowRestored.quantumBackflow.fastWaveNumber - 1.55) > 1.0e-12 ||
602 std::abs(backflowRestored.quantumBackflow.momentumSigma - 0.28) > 1.0e-12 ||
603 std::abs(backflowRestored.quantumBackflow.fastAmplitudeRatio - 0.61) > 1.0e-12 ||
604 std::abs(backflowRestored.quantumBackflow.relativePhaseDegrees - 155.0) > 1.0e-12 ||
605 std::abs(backflowRestored.quantumBackflow.initialCenterX + 2.4) > 1.0e-12 ||
606 std::abs(backflowRestored.quantumBackflow.transverseSigma - 3.1) > 1.0e-12 ||
607 std::abs(backflowRestored.quantumBackflow.analysisEndTime - 5.75) > 1.0e-12) {
608 errorMessage = std::string("schema 26 Quantum backflow round trip failed: ") + qtError.toStdString();
609 return false;
610 }
611
612 ExperimentDocument2D zitterSource;
613 zitterSource.name = QStringLiteral("Zitterbewegung persistence test");
614 zitterSource.sourcePreset = QStringLiteral("Zitterbewegung / Free Dirac Wave Packet");
615 zitterSource.controls.insert(QStringLiteral("universeWidthSpinBox"), 40.96);
616 zitterSource.initialPreparationMode = 15;
617 zitterSource.quantumZitterbewegung.enabled = true;
618 zitterSource.quantumZitterbewegung.lightSpeed = 1.25;
619 zitterSource.quantumZitterbewegung.restMass = 0.44;
620 zitterSource.quantumZitterbewegung.centerX = -5.25;
621 zitterSource.quantumZitterbewegung.centerY = 0.75;
622 zitterSource.quantumZitterbewegung.sigma = 3.2;
623 zitterSource.quantumZitterbewegung.momentumX = 0.62;
624 zitterSource.quantumZitterbewegung.momentumY = -0.14;
625 zitterSource.quantumZitterbewegung.preparationMode = 1;
626 zitterSource.quantumZitterbewegung.analysisEndTime = 14.5;
627 const QJsonObject zitterJson = ExperimentDocument2DJson::toJson(zitterSource);
628 ExperimentDocument2D zitterRestored;
629 if (!ExperimentDocument2DJson::fromJson(zitterJson, zitterRestored, qtError) ||
630 zitterRestored.initialPreparationMode != 15 || !zitterRestored.quantumZitterbewegung.enabled ||
631 std::abs(zitterRestored.quantumZitterbewegung.lightSpeed - 1.25) > 1.0e-12 ||
632 std::abs(zitterRestored.quantumZitterbewegung.restMass - 0.44) > 1.0e-12 ||
633 std::abs(zitterRestored.quantumZitterbewegung.centerX + 5.25) > 1.0e-12 ||
634 std::abs(zitterRestored.quantumZitterbewegung.centerY - 0.75) > 1.0e-12 ||
635 std::abs(zitterRestored.quantumZitterbewegung.sigma - 3.2) > 1.0e-12 ||
636 std::abs(zitterRestored.quantumZitterbewegung.momentumX - 0.62) > 1.0e-12 ||
637 std::abs(zitterRestored.quantumZitterbewegung.momentumY + 0.14) > 1.0e-12 ||
638 zitterRestored.quantumZitterbewegung.preparationMode != 1 ||
639 std::abs(zitterRestored.quantumZitterbewegung.analysisEndTime - 14.5) > 1.0e-12) {
640 errorMessage = std::string("schema 27 Zitterbewegung round trip failed: ") + qtError.toStdString();
641 return false;
642 }
643
644 ExperimentDocument2D kleinSource;
645 kleinSource.name = QStringLiteral("Klein tunneling persistence test");
646 kleinSource.sourcePreset = QStringLiteral("Klein Tunneling / Supercritical Dirac Barrier");
647 kleinSource.initialPreparationMode = 16;
648 kleinSource.controls.insert(QStringLiteral("boundaryModeComboBox"), 1);
649 kleinSource.quantumKleinTunneling.enabled = true;
650 kleinSource.quantumKleinTunneling.lightSpeed = 1.15;
651 kleinSource.quantumKleinTunneling.restMass = 0.08;
652 kleinSource.quantumKleinTunneling.centerX = -9.5;
653 kleinSource.quantumKleinTunneling.centerY = 0.6;
654 kleinSource.quantumKleinTunneling.sigma = 2.4;
655 kleinSource.quantumKleinTunneling.momentumX = 1.6;
656 kleinSource.quantumKleinTunneling.momentumY = 0.25;
657 kleinSource.quantumKleinTunneling.barrierCenterX = 0.4;
658 kleinSource.quantumKleinTunneling.barrierWidth = 2.8;
659 kleinSource.quantumKleinTunneling.barrierHeight = 3.5;
660 kleinSource.quantumKleinTunneling.detectorX = 6.4;
661 kleinSource.quantumKleinTunneling.analysisEndTime = 17.0;
662 const QJsonObject kleinJson = ExperimentDocument2DJson::toJson(kleinSource);
663 ExperimentDocument2D kleinRestored;
664 if (!ExperimentDocument2DJson::fromJson(kleinJson, kleinRestored, qtError) ||
665 kleinRestored.initialPreparationMode != 16 ||
666 kleinRestored.controls.value(QStringLiteral("boundaryModeComboBox")).toInt() != 1 ||
667 !kleinRestored.quantumKleinTunneling.enabled ||
668 std::abs(kleinRestored.quantumKleinTunneling.lightSpeed - 1.15) > 1.0e-12 ||
669 std::abs(kleinRestored.quantumKleinTunneling.restMass - 0.08) > 1.0e-12 ||
670 std::abs(kleinRestored.quantumKleinTunneling.centerX + 9.5) > 1.0e-12 ||
671 std::abs(kleinRestored.quantumKleinTunneling.centerY - 0.6) > 1.0e-12 ||
672 std::abs(kleinRestored.quantumKleinTunneling.sigma - 2.4) > 1.0e-12 ||
673 std::abs(kleinRestored.quantumKleinTunneling.momentumX - 1.6) > 1.0e-12 ||
674 std::abs(kleinRestored.quantumKleinTunneling.momentumY - 0.25) > 1.0e-12 ||
675 std::abs(kleinRestored.quantumKleinTunneling.barrierCenterX - 0.4) > 1.0e-12 ||
676 std::abs(kleinRestored.quantumKleinTunneling.barrierWidth - 2.8) > 1.0e-12 ||
677 std::abs(kleinRestored.quantumKleinTunneling.barrierHeight - 3.5) > 1.0e-12 ||
678 std::abs(kleinRestored.quantumKleinTunneling.detectorX - 6.4) > 1.0e-12 ||
679 std::abs(kleinRestored.quantumKleinTunneling.analysisEndTime - 17.0) > 1.0e-12) {
680 errorMessage = std::string("schema 28 Klein tunneling round trip failed: ") + qtError.toStdString();
681 return false;
682 }
683
684 // Backward compatibility: schema 27 had Zitterbewegung but no Klein-tunneling object.
685 QJsonObject schema27 = zitterJson;
686 schema27.insert(QStringLiteral("schemaVersion"), 27);
687 schema27.remove(QStringLiteral("quantumKleinTunneling"));
688 ExperimentDocument2D schema27Restored;
689 if (!ExperimentDocument2DJson::fromJson(schema27, schema27Restored, qtError) ||
690 !schema27Restored.quantumZitterbewegung.enabled ||
691 schema27Restored.quantumKleinTunneling.enabled ||
693 errorMessage = std::string("schema 27 compatibility failed: ") + qtError.toStdString();
694 return false;
695 }
696
697 // Backward compatibility: schema 26 had quantum backflow but no Dirac spinor object.
698 QJsonObject schema26 = backflowJson;
699 schema26.insert(QStringLiteral("schemaVersion"), 26);
700 schema26.remove(QStringLiteral("quantumZitterbewegung"));
701 ExperimentDocument2D schema26Restored;
702 if (!ExperimentDocument2DJson::fromJson(schema26, schema26Restored, qtError) ||
703 !schema26Restored.quantumBackflow.enabled || schema26Restored.quantumZitterbewegung.enabled ||
705 errorMessage = std::string("schema 26 compatibility failed: ") + qtError.toStdString();
706 return false;
707 }
708
709 // Backward compatibility: schema 25 had Hall edge but no quantum-backflow object.
710 QJsonObject schema25 = hallJson;
711 schema25.insert(QStringLiteral("schemaVersion"), 25);
712 schema25.remove(QStringLiteral("quantumBackflow"));
713 ExperimentDocument2D schema25Restored;
714 if (!ExperimentDocument2DJson::fromJson(schema25, schema25Restored, qtError) ||
715 !schema25Restored.quantumHallEdge.enabled || schema25Restored.quantumBackflow.enabled ||
717 errorMessage = std::string("schema 25 compatibility failed: ") + qtError.toStdString();
718 return false;
719 }
720
721 // Backward compatibility: schema 24 had uniform-field Landau dynamics but no Hall edge object.
722 QJsonObject schema24 = landauJson;
723 schema24.insert(QStringLiteral("schemaVersion"), 24);
724 schema24.remove(QStringLiteral("quantumHallEdge"));
725 ExperimentDocument2D schema24Restored;
726 if (!ExperimentDocument2DJson::fromJson(schema24, schema24Restored, qtError) ||
727 !schema24Restored.quantumLandau.enabled || schema24Restored.quantumHallEdge.enabled ||
729 errorMessage = std::string("schema 24 compatibility failed: ") + qtError.toStdString();
730 return false;
731 }
732
733 // Backward compatibility: schema 23 had Aharonov-Bohm but no uniform-field Landau object.
734 QJsonObject schema23 = aharonovJson;
735 schema23.insert(QStringLiteral("schemaVersion"), 23);
736 schema23.remove(QStringLiteral("quantumLandau"));
737 ExperimentDocument2D schema23Restored;
738 if (!ExperimentDocument2DJson::fromJson(schema23, schema23Restored, qtError) ||
739 !schema23Restored.quantumAharonovBohm.enabled || schema23Restored.quantumLandau.enabled ||
741 errorMessage = std::string("schema 23 compatibility failed: ") + qtError.toStdString();
742 return false;
743 }
744
745 // Backward compatibility: schema 22 had Kapitza-Dirac but no Aharonov-Bohm gauge field.
746 QJsonObject schema22 = kapitzaJson;
747 schema22.insert(QStringLiteral("schemaVersion"), 22);
748 schema22.remove(QStringLiteral("quantumAharonovBohm"));
749 ExperimentDocument2D schema22Restored;
750 if (!ExperimentDocument2DJson::fromJson(schema22, schema22Restored, qtError) ||
751 !schema22Restored.quantumKapitzaDirac.enabled ||
752 schema22Restored.quantumAharonovBohm.enabled ||
754 errorMessage = std::string("schema 22 compatibility failed: ") + qtError.toStdString();
755 return false;
756 }
757
758 // Backward compatibility: schema 21 had Moshinsky Shutter but no Kapitza-Dirac pulse.
759 QJsonObject schema21 = moshinskyJson;
760 schema21.insert(QStringLiteral("schemaVersion"), 21);
761 schema21.remove(QStringLiteral("kapitzaDiracInitialState"));
762 schema21.remove(QStringLiteral("quantumKapitzaDirac"));
763 ExperimentDocument2D schema21Restored;
764 if (!ExperimentDocument2DJson::fromJson(schema21, schema21Restored, qtError) ||
765 !schema21Restored.quantumMoshinsky.enabled ||
766 schema21Restored.quantumKapitzaDirac.enabled ||
768 errorMessage = std::string("schema 21 compatibility failed: ") + qtError.toStdString();
769 return false;
770 }
771
772 // Backward compatibility: schema 20 had Loschmidt Echo but no Moshinsky shutter.
773 QJsonObject schema20 = loschmidtJson;
774 schema20.insert(QStringLiteral("schemaVersion"), 20);
775 schema20.remove(QStringLiteral("moshinskyInitialState"));
776 schema20.remove(QStringLiteral("quantumMoshinsky"));
777 ExperimentDocument2D schema20Restored;
778 if (!ExperimentDocument2DJson::fromJson(schema20, schema20Restored, qtError) ||
779 !schema20Restored.quantumLoschmidt.enabled ||
780 schema20Restored.quantumMoshinsky.enabled ||
781 schema20Restored.moshinskyInitialState.enabled ||
783 errorMessage = std::string("schema 20 compatibility failed: ") + qtError.toStdString();
784 return false;
785 }
786
787 // Backward compatibility: schema 19 had Berry Phase but no Loschmidt Echo.
788 QJsonObject schema19 = berryJson;
789 schema19.insert(QStringLiteral("schemaVersion"), 19);
790 schema19.remove(QStringLiteral("quantumLoschmidt"));
791 ExperimentDocument2D schema19Restored;
792 if (!ExperimentDocument2DJson::fromJson(schema19, schema19Restored, qtError) ||
793 !schema19Restored.quantumBerry.enabled ||
794 schema19Restored.quantumLoschmidt.enabled ||
795 std::abs(schema19Restored.quantumLoschmidt.reversalTime - 4.0) > 1.0e-12 ||
797 errorMessage = std::string("schema 19 compatibility failed: ") + qtError.toStdString();
798 return false;
799 }
800
801 // Backward compatibility: schema 18 had Quantum Scars but no Berry loop.
802 QJsonObject schema18 = json;
803 schema18.insert(QStringLiteral("schemaVersion"), 18);
804 schema18.remove(QStringLiteral("quantumBerry"));
805 ExperimentDocument2D schema18Restored;
806 if (!ExperimentDocument2DJson::fromJson(schema18, schema18Restored, qtError) ||
807 schema18Restored.initialPreparationMode != 2 ||
808 schema18Restored.quantumBerry.enabled ||
809 std::abs(schema18Restored.quantumBerry.anisotropy - 0.35) > 1.0e-12 ||
810 std::abs(schema18Restored.quantumBerry.duration - 240.0) > 1.0e-12 ||
811 schema18Restored.quantumBerry.winding != 1 ||
813 errorMessage = std::string("schema 18 compatibility failed: ") + qtError.toStdString();
814 return false;
815 }
816
817 // Backward compatibility: schema 17 had Quantum Zeno but no Quantum
818 // Scars spectral-analysis configuration.
819 QJsonObject schema17 = json;
820 schema17.insert(QStringLiteral("schemaVersion"), 17);
821 schema17.remove(QStringLiteral("quantumScar"));
822 ExperimentDocument2D schema17Restored;
823 if (!ExperimentDocument2DJson::fromJson(schema17, schema17Restored, qtError) ||
824 schema17Restored.initialPreparationMode != 2 ||
825 schema17Restored.quantumScar.enabled ||
826 std::abs(schema17Restored.quantumScar.orbitBandHalfWidth - 0.75) > 1.0e-12 ||
827 std::abs(schema17Restored.quantumScar.referenceEnergy) > 1.0e-12 ||
829 errorMessage = std::string("schema 17 compatibility failed: ") + qtError.toStdString();
830 return false;
831 }
832
833 // Backward compatibility: schema 16 had kicked-rotor preparation but no
834 // Quantum Zeno configuration or dual-lane initial-state object.
835 QJsonObject schema16 = json;
836 schema16.insert(QStringLiteral("schemaVersion"), 16);
837 schema16.remove(QStringLiteral("quantumZeno"));
838 schema16.remove(QStringLiteral("quantumZenoInitialState"));
839 ExperimentDocument2D schema16Restored;
840 if (!ExperimentDocument2DJson::fromJson(schema16, schema16Restored, qtError) ||
841 schema16Restored.initialPreparationMode != 2 ||
842 schema16Restored.quantumZeno.enabled ||
843 std::abs(schema16Restored.quantumZeno.measurementPeriod - 0.10) > 1.0e-12 ||
844 std::abs(schema16Restored.quantumZenoInitialState.sigma - 0.80) > 1.0e-12 ||
846 errorMessage = std::string("schema 16 compatibility failed: ") + qtError.toStdString();
847 return false;
848 }
849
850 // Backward compatibility: schema 15 had Anderson preparation but no
851 // kicked-rotor configuration or kicked-rotor initial-state object.
852 QJsonObject schema15 = json;
853 schema15.insert(QStringLiteral("schemaVersion"), 15);
854 schema15.remove(QStringLiteral("kickedRotor"));
855 schema15.remove(QStringLiteral("kickedRotorInitialState"));
856 ExperimentDocument2D schema15Restored;
857 if (!ExperimentDocument2DJson::fromJson(schema15, schema15Restored, qtError) ||
858 schema15Restored.initialPreparationMode != 2 ||
859 schema15Restored.kickedRotor.enabled ||
860 std::abs(schema15Restored.kickedRotor.kickPeriod - 1.0) > 1.0e-12 ||
861 std::abs(schema15Restored.kickedRotorInitialState.ySigma - 1.5) > 1.0e-12 ||
863 errorMessage = std::string("schema 15 compatibility failed: ") + qtError.toStdString();
864 return false;
865 }
866
867 // Backward compatibility: schema 14 had vortex preparation but no Anderson object.
868 QJsonObject schema14 = json;
869 schema14.insert(QStringLiteral("schemaVersion"), 14);
870 schema14.remove(QStringLiteral("andersonInitialState"));
871 ExperimentDocument2D schema14Restored;
872 if (!ExperimentDocument2DJson::fromJson(schema14, schema14Restored, qtError) ||
873 schema14Restored.initialPreparationMode != 2 ||
874 std::abs(schema14Restored.andersonInitialState.sigma - 0.35) > 1.0e-12 ||
876 errorMessage = std::string("schema 14 compatibility failed: ") + qtError.toStdString();
877 return false;
878 }
879
880 // Backward compatibility: schema 13 had Talbot preparation but no vortex object.
881 QJsonObject schema13 = json;
882 schema13.insert(QStringLiteral("schemaVersion"), 13);
883 schema13.remove(QStringLiteral("vortexInitialState"));
884 ExperimentDocument2D schema13Restored;
885 if (!ExperimentDocument2DJson::fromJson(schema13, schema13Restored, qtError) ||
886 schema13Restored.initialPreparationMode != 2 ||
887 std::abs(schema13Restored.vortexInitialState.coreX - 1.0) > 1.0e-12 ||
889 errorMessage = std::string("schema 13 compatibility failed: ") + qtError.toStdString();
890 return false;
891 }
892
893 // Backward compatibility: schema 12 had the Ramsey ensemble but no Talbot initial-state object.
894 QJsonObject schema12 = json;
895 schema12.insert(QStringLiteral("schemaVersion"), 12);
896 schema12.remove(QStringLiteral("talbotInitialState"));
897 ExperimentDocument2D schema12Restored;
898 if (!ExperimentDocument2DJson::fromJson(schema12, schema12Restored, qtError) ||
899 schema12Restored.initialPreparationMode != 2 ||
900 std::abs(schema12Restored.talbotInitialState.period - 5.12) > 1.0e-12 ||
902 errorMessage = std::string("schema 12 compatibility failed: ") + qtError.toStdString();
903 return false;
904 }
905
906 // Backward compatibility: schema 11 had Hahn echo but no static-detuning ensemble.
907 QJsonObject schema11 = json;
908 schema11.insert(QStringLiteral("schemaVersion"), 11);
909 schema11.remove(QStringLiteral("ramseyEnsemble"));
910 ExperimentDocument2D schema11Restored;
911 if (!ExperimentDocument2DJson::fromJson(schema11, schema11Restored, qtError) ||
912 !schema11Restored.ramseySequence.enabled || !schema11Restored.ramseySequence.echoEnabled ||
913 schema11Restored.ramseyEnsemble.enabled ||
915 errorMessage = std::string("schema 11 compatibility failed: ") + qtError.toStdString();
916 return false;
917 }
918
919 // Backward compatibility: schema 10 had Ramsey but no Hahn-echo fields.
920 QJsonObject schema10 = json;
921 schema10.insert(QStringLiteral("schemaVersion"), 10);
922 QJsonObject ramsey10 = schema10.value(QStringLiteral("ramseySequence")).toObject();
923 ramsey10.remove(QStringLiteral("echoEnabled"));
924 ramsey10.remove(QStringLiteral("echoPulseDuration"));
925 ramsey10.remove(QStringLiteral("echoPulsePhaseDegrees"));
926 schema10.insert(QStringLiteral("ramseySequence"), ramsey10);
927 ExperimentDocument2D schema10Restored;
928 if (!ExperimentDocument2DJson::fromJson(schema10, schema10Restored, qtError) ||
929 !schema10Restored.ramseySequence.enabled || schema10Restored.ramseySequence.echoEnabled ||
930 schema10Restored.ramseyEnsemble.enabled ||
932 errorMessage = std::string("schema 10 compatibility failed: ") + qtError.toStdString();
933 return false;
934 }
935
936 // Backward compatibility: schema 9 had no Ramsey pulse sequence.
937 QJsonObject schema9 = json;
938 schema9.insert(QStringLiteral("schemaVersion"), 9);
939 schema9.remove(QStringLiteral("ramseySequence"));
940 ExperimentDocument2D schema9Restored;
941 if (!ExperimentDocument2DJson::fromJson(schema9, schema9Restored, qtError) ||
942 schema9Restored.ramseySequence.enabled || schema9Restored.ramseyEnsemble.enabled ||
944 errorMessage = std::string("schema 9 compatibility failed: ") + qtError.toStdString();
945 return false;
946 }
947
948 // Backward compatibility: schema 8 had the same linearSweep object but
949 // no return leg. Missing schema-9 fields must restore one-way semantics.
950 QJsonObject schema8 = json;
951 schema8.insert(QStringLiteral("schemaVersion"), 8);
952 QJsonObject sweep8 = schema8.value(QStringLiteral("linearSweep")).toObject();
953 sweep8.remove(QStringLiteral("returnEnabled"));
954 sweep8.remove(QStringLiteral("holdDuration"));
955 sweep8.remove(QStringLiteral("returnDuration"));
956 schema8.insert(QStringLiteral("linearSweep"), sweep8);
957 ExperimentDocument2D schema8Restored;
958 if (!ExperimentDocument2DJson::fromJson(schema8, schema8Restored, qtError) ||
959 !schema8Restored.linearSweep.enabled || schema8Restored.linearSweep.returnEnabled ||
961 errorMessage = std::string("schema 8 compatibility failed: ") + qtError.toStdString();
962 return false;
963 }
964
965 // Backward compatibility: schema 2 geometric objects did not contain the
966 // smooth-potential numeric fields introduced by schema 3.
967 QJsonObject schema2 = json;
968 schema2.insert(QStringLiteral("schemaVersion"), 2);
969 QJsonObject scene2 = schema2.value(QStringLiteral("potentialScene")).toObject();
970 QJsonArray objects2 = scene2.value(QStringLiteral("objects")).toArray();
971 while (objects2.size() > 2) objects2.removeLast();
972 for (int i = 0; i < objects2.size(); ++i) {
973 QJsonObject o = objects2.at(i).toObject();
974 o.remove(QStringLiteral("sigmaX"));
975 o.remove(QStringLiteral("sigmaY"));
976 o.remove(QStringLiteral("curvatureX"));
977 o.remove(QStringLiteral("curvatureY"));
978 o.remove(QStringLiteral("slopeX"));
979 o.remove(QStringLiteral("slopeY"));
980 o.remove(QStringLiteral("softening"));
981 objects2.replace(i, o);
982 }
983 scene2.insert(QStringLiteral("objects"), objects2);
984 schema2.insert(QStringLiteral("potentialScene"), scene2);
985 ExperimentDocument2D schema2Restored;
986 if (!ExperimentDocument2DJson::fromJson(schema2, schema2Restored, qtError) ||
987 schema2Restored.potentialScene.size() != 2 ||
988 schema2Restored.initialPreparationMode != 0 ||
989 std::abs(schema2Restored.collapseResolution - 0.65) > 1.0e-12 ||
990 schema2Restored.quench.enabled || schema2Restored.periodicDrive.enabled ||
991 schema2Restored.linearSweep.enabled || schema2Restored.ramseySequence.enabled ||
993 errorMessage = std::string("schema 2 compatibility failed: ") + qtError.toStdString();
994 return false;
995 }
996
997 // Backward compatibility: schema 1 had no potentialScene object. It must
998 // still load and be promoted to the current in-memory schema.
999 QJsonObject legacy = json;
1000 legacy.insert(QStringLiteral("schemaVersion"), 1);
1001 legacy.remove(QStringLiteral("potentialScene"));
1002 ExperimentDocument2D legacyRestored;
1003 if (!ExperimentDocument2DJson::fromJson(legacy, legacyRestored, qtError)) {
1004 errorMessage = std::string("schema 1 compatibility failed: ") + qtError.toStdString();
1005 return false;
1006 }
1007 if (legacyRestored.potentialSceneActive || !legacyRestored.potentialScene.empty() ||
1008 std::abs(legacyRestored.collapseResolution - 0.65) > 1.0e-12 ||
1009 legacyRestored.quench.enabled || legacyRestored.periodicDrive.enabled ||
1010 legacyRestored.linearSweep.enabled || legacyRestored.ramseySequence.enabled ||
1012 errorMessage = "schema 1 compatibility values differ";
1013 return false;
1014 }
1015
1016 QJsonObject incompatible = json;
1017 incompatible.insert(QStringLiteral("schemaVersion"), 999);
1018 if (ExperimentDocument2DJson::fromJson(incompatible, restored, qtError)) {
1019 errorMessage = "incompatible schema was accepted";
1020 return false;
1021 }
1022
1023 QJsonObject wrongFormat = json;
1024 wrongFormat.insert(QStringLiteral("format"), QStringLiteral("Other.Application"));
1025 if (ExperimentDocument2DJson::fromJson(wrongFormat, restored, qtError)) {
1026 errorMessage = "foreign document format was accepted";
1027 return false;
1028 }
1029
1030 return true;
1031}
1032
1033} // namespace tests
1034} // namespace qpe
static bool fromJson(const QJsonObject &json, ExperimentDocument2D &document, QString &errorMessage)
Performs from json.
static QJsonObject toJson(const ExperimentDocument2D &document)
Performs to json.
static bool saveFile(const QString &fileName, const ExperimentDocument2D &document, QString &errorMessage)
Saves file.
static bool loadFile(const QString &fileName, ExperimentDocument2D &document, QString &errorMessage)
Loads file.
std::uint64_t add(PotentialObject2D object)
Performs add.
std::size_t size() const noexcept
Returns size.
PotentialObject2D * find(std::uint64_t id) noexcept
Performs find.
bool empty() const noexcept
Performs empty.
Declares the schema-28 experiment persistence document and JSON conversion API.
Declares regression and invariant tests for experimentdocument2d tests.
bool runExperimentDocument2DTests(std::string &errorMessage)
Runs experiment document2 d tests.
Serializable experiment document used by QPE schema 28.
QuantumVortexInitialState2DConfig vortexInitialState
QMap< QString, QVariant > controls
QuantumTalbotInitialState2DConfig talbotInitialState
QuantumBackflow2DConfig quantumBackflow
QuantumLoschmidt2DConfig quantumLoschmidt
LinearPotentialSweep2DConfig linearSweep
QuantumLandau2DConfig quantumLandau
QuantumKickedRotor2DConfig kickedRotor
PeriodicPotentialDrive2DConfig periodicDrive
QuantumAharonovBohm2DConfig quantumAharonovBohm
static const int CurrentSchemaVersion
QuantumBerryLoop2DConfig quantumBerry
QuantumMoshinsky2DConfig quantumMoshinsky
RamseyEnsemble2DConfig ramseyEnsemble
QuantumKapitzaDiracInitialState2DConfig kapitzaDiracInitialState
QuantumZitterbewegung2DConfig quantumZitterbewegung
QuantumHallEdge2DConfig quantumHallEdge
QuantumMoshinskyInitialState2DConfig moshinskyInitialState
QuantumAndersonInitialState2DConfig andersonInitialState
QuantumKapitzaDirac2DConfig quantumKapitzaDirac
RamseyPulseSequence2DConfig ramseySequence
QuantumKleinTunneling2DConfig quantumKleinTunneling
QuantumZenoInitialState2DConfig quantumZenoInitialState
QuantumKickedRotorInitialState2DConfig kickedRotorInitialState
QuantumQuench2DConfig quench
Data structure used by the Potential Object2D component.
PotentialObjectType2D type
TimePotentialParameter2D parameter