Quantum Phenomena Explorer 7.9.8
Interactive quantum-phenomena Explorer Tutor — source documentation
Loading...
Searching...
No Matches
quantumkickedrotorplotwidget.cpp
Go to the documentation of this file.
1/**
2 * @file quantumkickedrotorplotwidget.cpp
3 * @brief Implements the quantumkickedrotorplotwidget visualization component used by QPE.
4 * @ingroup qpe_graphics
5 *
6 * Source: @c graphics/renderer/quantumkickedrotorplotwidget.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 <QPainter>
17#include <QPainterPath>
18#include <QPaintEvent>
19#include <QPen>
20#include <QString>
21
22#include <algorithm>
23#include <cmath>
24
25namespace {
26
27/**
28 * @brief Performs heat color.
29 * @param value Value to assign or evaluate.
30 */
31QColor heatColor(double value)
32{
33 value = std::max(0.0, std::min(1.0, value));
34 if (value < 0.25) {
35 const double u = value / 0.25;
36 return QColor(8, static_cast<int>(25 + 80 * u), static_cast<int>(45 + 150 * u));
37 }
38 if (value < 0.55) {
39 const double u = (value - 0.25) / 0.30;
40 return QColor(static_cast<int>(15 + 30 * u), static_cast<int>(105 + 120 * u), 210);
41 }
42 if (value < 0.80) {
43 const double u = (value - 0.55) / 0.25;
44 return QColor(static_cast<int>(45 + 205 * u), static_cast<int>(225 - 40 * u), static_cast<int>(210 - 150 * u));
45 }
46 const double u = (value - 0.80) / 0.20;
47 return QColor(250, static_cast<int>(185 + 70 * u), static_cast<int>(60 + 195 * u));
48}
49
50} // namespace
51
53 : QWidget(parent)
54{
55 setAutoFillBackground(false);
56}
57
59{
60 history_ = &history;
61 update();
62}
63
65{
66 history_ = nullptr;
67 update();
68}
69
71{
72 return QSize(620, 410);
73}
74
76{
77 Q_UNUSED(event);
78 QPainter p(this);
79 p.setRenderHint(QPainter::Antialiasing, true);
80 p.setRenderHint(QPainter::TextAntialiasing, true);
81 p.fillRect(rect(), QColor(13, 17, 23));
82 p.setPen(QColor(210, 220, 230));
83
84 const int marginL = 58;
85 const int marginR = 18;
86 const int top = 28;
87 const int gap = 40;
88 const int bottom = 30;
89 const int carpetH = std::max(120, (height() - top - bottom - gap) * 3 / 5);
90 const int spreadH = std::max(90, height() - top - bottom - gap - carpetH);
91 const QRect carpetRect(marginL, top, std::max(40, width() - marginL - marginR), carpetH);
92 const QRect spreadRect(marginL, top + carpetH + gap,
93 std::max(40, width() - marginL - marginR), spreadH);
94
95 p.drawText(QRect(8, 3, width() - 16, 20), Qt::AlignCenter,
96 QStringLiteral("Quantum kicked rotor: diffusion in momentum, then dynamical localization"));
97
98 if (!history_ || !history_->configured() || history_->empty()) {
99 p.drawText(rect(), Qt::AlignCenter,
100 QStringLiteral("Run the Quantum Kicked Rotor preset"));
101 return;
102 }
103
104 const std::vector<qpe::QuantumKickedRotorSample2D> &samples = history_->samples();
105 p.setPen(QColor(72, 84, 96));
106 p.drawRect(carpetRect);
107 p.drawRect(spreadRect);
108 p.setPen(QColor(210, 220, 230));
109 p.drawText(QRect(carpetRect.left(), carpetRect.top() - 20, carpetRect.width(), 18),
110 Qt::AlignLeft,
111 QStringLiteral("Stroboscopic momentum carpet P(n) after each kick"));
112 p.drawText(QRect(spreadRect.left(), spreadRect.top() - 20, spreadRect.width(), 18),
113 Qt::AlignLeft,
114 QStringLiteral("Momentum diffusion: <n^2> quantum vs classical standard map"));
115
116 std::size_t modeCount = 0u;
117 double maxProbability = 0.0;
118 for (const qpe::QuantumKickedRotorSample2D &s : samples) {
119 modeCount = std::max(modeCount, s.modeProbability.size());
120 for (float v : s.modeProbability) maxProbability = std::max(maxProbability, static_cast<double>(v));
121 }
122 maxProbability = std::max(maxProbability, 1.0e-12);
123
124 if (modeCount > 0u) {
125 const double rowH = static_cast<double>(carpetRect.height()) / static_cast<double>(samples.size());
126 const double cellW = static_cast<double>(carpetRect.width()) / static_cast<double>(modeCount);
127 for (std::size_t row = 0u; row < samples.size(); ++row) {
128 const qpe::QuantumKickedRotorSample2D &s = samples[row];
129 for (std::size_t col = 0u; col < s.modeProbability.size(); ++col) {
130 const double normalized = std::sqrt(static_cast<double>(s.modeProbability[col]) / maxProbability);
131 const QRectF cell(carpetRect.left() + static_cast<double>(col) * cellW,
132 carpetRect.top() + static_cast<double>(row) * rowH,
133 std::max(1.0, cellW + 0.5),
134 std::max(1.0, rowH + 0.5));
135 p.fillRect(cell, heatColor(normalized));
136 }
137 }
138
139 const qpe::QuantumKickedRotorSample2D &latest = samples.back();
140 const double nMin = latest.modeMin;
141 const double nMax = latest.modeMin + latest.modeStep * static_cast<double>(modeCount - 1u);
142 p.setPen(QColor(210, 220, 230));
143 p.drawText(QRect(carpetRect.left(), carpetRect.bottom() + 3, carpetRect.width(), 20),
144 Qt::AlignLeft,
145 QStringLiteral("n=%1").arg(nMin, 0, 'f', 0));
146 p.drawText(QRect(carpetRect.left(), carpetRect.bottom() + 3, carpetRect.width(), 20),
147 Qt::AlignCenter, QStringLiteral("momentum mode n"));
148 p.drawText(QRect(carpetRect.left(), carpetRect.bottom() + 3, carpetRect.width(), 20),
149 Qt::AlignRight,
150 QStringLiteral("n=%1").arg(nMax, 0, 'f', 0));
151 p.drawText(QRect(4, carpetRect.top(), 50, carpetRect.height()),
152 Qt::AlignRight | Qt::AlignTop,
153 QStringLiteral("kick 0"));
154 p.drawText(QRect(4, carpetRect.top(), 50, carpetRect.height()),
155 Qt::AlignRight | Qt::AlignBottom,
156 QStringLiteral("kick %1").arg(static_cast<qulonglong>(latest.kickCount)));
157 }
158
159 const std::size_t maxKick = std::max<std::size_t>(1u, samples.back().kickCount);
160 double yMax = 1.0;
161 for (const qpe::QuantumKickedRotorSample2D &s : samples) {
162 yMax = std::max(yMax, std::max(s.meanModeSquared, s.classicalMeanModeSquared));
163 }
164 auto mapKick = [&](std::size_t kick) {
165 return spreadRect.left() + static_cast<double>(kick) /
166 static_cast<double>(maxKick) * spreadRect.width();
167 };
168 auto mapY = [&](double value) {
169 return spreadRect.bottom() - value / yMax * spreadRect.height();
170 };
171
172 auto drawSeries = [&](bool classical) {
173 QPainterPath path;
174 bool started = false;
175 for (const qpe::QuantumKickedRotorSample2D &s : samples) {
176 const double value = classical ? s.classicalMeanModeSquared : s.meanModeSquared;
177 const QPointF point(mapKick(s.kickCount), mapY(value));
178 if (!started) { path.moveTo(point); started = true; }
179 else path.lineTo(point);
180 }
181 p.setPen(QPen(classical ? QColor(245, 166, 70) : QColor(80, 220, 235),
182 classical ? 1.6 : 2.2,
183 classical ? Qt::DashLine : Qt::SolidLine));
184 p.drawPath(path);
185 };
186 drawSeries(false);
187 drawSeries(true);
188
189 p.setPen(QColor(80, 220, 235));
190 p.drawText(spreadRect.adjusted(8, 6, -8, -6), Qt::AlignTop | Qt::AlignLeft,
191 QStringLiteral("quantum <n^2>"));
192 p.setPen(QColor(245, 166, 70));
193 p.drawText(spreadRect.adjusted(8, 6, -8, -6), Qt::AlignTop | Qt::AlignRight,
194 QStringLiteral("classical diffusion"));
195 p.setPen(QColor(210, 220, 230));
196 p.drawText(QRect(4, spreadRect.top(), 50, spreadRect.height()),
197 Qt::AlignRight | Qt::AlignTop,
198 QString::number(yMax, 'f', 0));
199 p.drawText(QRect(spreadRect.left(), spreadRect.bottom() + 4, spreadRect.width(), 20),
200 Qt::AlignCenter,
201 QStringLiteral("number of kicks"));
202}
QuantumKickedRotorPlotWidget(QWidget *parent=nullptr)
Performs quantum kicked rotor plot widget.
void setData(const qpe::QuantumKickedRotorHistory2D &history)
Sets data.
void paintEvent(QPaintEvent *event) override
Paints event.
const qpe::QuantumKickedRotorHistory2D * history_
QSize minimumSizeHint() const override
Performs minimum size hint.
Implements the Quantum Kicked Rotor History2D component.
bool empty() const noexcept
Performs empty.
bool configured() const noexcept
Returns configured.
const std::vector< QuantumKickedRotorSample2D > & samples() const noexcept
Samples s.
Declares the quantumkickedrotor2d physics/numerical component used by QPE experiments.
Declares the quantumkickedrotorplotwidget visualization component used by QPE.
Data structure used by the Quantum Kicked Rotor Sample2D component.