Quantum Phenomena Explorer 7.9.8
Interactive quantum-phenomena Explorer Tutor — source documentation
Loading...
Searching...
No Matches
quantumberryphaseplotwidget.cpp
Go to the documentation of this file.
1/**
2 * @file quantumberryphaseplotwidget.cpp
3 * @brief Implements the quantumberryphaseplotwidget visualization component used by QPE.
4 * @ingroup qpe_graphics
5 *
6 * Source: @c graphics/renderer/quantumberryphaseplotwidget.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
14#include <QPaintEvent>
15#include <QPainter>
16#include <QPainterPath>
17
18#include <algorithm>
19#include <cmath>
20
21namespace {
22const double kPi = 3.1415926535897932384626433832795;
23
24/**
25 * @brief Performs frame.
26 * @param p The p value used by the operation.
27 * @param r The r value used by the operation.
28 */
29void frame(QPainter &p, const QRectF &r)
30{
31 p.setBrush(Qt::NoBrush);
32 p.setPen(QPen(QColor(70, 79, 91), 1.0));
33 p.drawRect(r);
34}
35}
36
38 : QWidget(parent)
39{
40 setMinimumHeight(390);
41 setAutoFillBackground(false);
42}
43
45{
46 history_ = &history;
47 update();
48}
49
51{
52 history_ = nullptr;
53 update();
54}
55
57{
58 return QSize(680, 410);
59}
60
62{
63 Q_UNUSED(event);
64 QPainter p(this);
65 p.setRenderHint(QPainter::Antialiasing, true);
66 p.setRenderHint(QPainter::TextAntialiasing, true);
67 p.fillRect(rect(), QColor(14, 17, 22));
68
69 const double marginL = 58.0;
70 const double marginR = 48.0;
71 const double top = 34.0;
72 const double gap = 42.0;
73 const double bottom = 42.0;
74 const double available = std::max(180.0, height() - top - gap - bottom);
75 const double upperH = available * 0.48;
76 const QRectF loopRect(marginL, top, std::max(100.0, width() - marginL - marginR), upperH);
77 const QRectF curveRect(marginL, loopRect.bottom() + gap, loopRect.width(), available - upperH);
78 frame(p, loopRect);
79 frame(p, curveRect);
80
81 p.setPen(QColor(226, 232, 240));
82 p.drawText(QRectF(loopRect.left(), 5.0, loopRect.width(), 22.0), Qt::AlignCenter,
83 QStringLiteral("Berry loop in parameter space (q1,q2) — degeneracy at the origin"));
84 p.drawText(QRectF(curveRect.left(), loopRect.bottom() + 10.0, curveRect.width(), 22.0), Qt::AlignCenter,
85 QStringLiteral("Return fidelity and geometric phase extracted from the full wavefunction"));
86
87 if (!history_ || !history_->configured() || history_->empty()) {
88 p.setPen(QColor(205, 214, 224));
89 p.drawText(loopRect, Qt::AlignCenter,
90 QStringLiteral("Load Berry Phase / Geometric Phase and run one cyclic deformation"));
91 p.drawText(curveRect, Qt::AlignCenter,
92 QStringLiteral("In the adiabatic limit the endpoint phase tends to ±180°"));
93 return;
94 }
95
96 const std::vector<qpe::QuantumBerrySample2D> &samples = history_->samples();
97 const double A = std::max(1.0e-9, history_->config().anisotropy);
98 const QPointF center(loopRect.center().x(), loopRect.center().y());
99 const double radius = 0.39 * std::min(loopRect.width(), loopRect.height());
100 const auto mapQ = [&](double q1, double q2) {
101 return QPointF(center.x() + radius * q1 / A,
102 center.y() - radius * q2 / A);
103 };
104
105 p.setPen(QPen(QColor(66, 73, 82), 1.0));
106 p.drawLine(QPointF(loopRect.left() + 12.0, center.y()), QPointF(loopRect.right() - 12.0, center.y()));
107 p.drawLine(QPointF(center.x(), loopRect.top() + 12.0), QPointF(center.x(), loopRect.bottom() - 12.0));
108 p.setPen(QPen(QColor(115, 126, 140), 1.2, Qt::DashLine));
109 p.drawEllipse(center, radius, radius);
110
111 QPainterPath path;
112 bool first = true;
113 for (const qpe::QuantumBerrySample2D &s : samples) {
114 const QPointF pt = mapQ(s.q1, s.q2);
115 if (first) { path.moveTo(pt); first = false; }
116 else path.lineTo(pt);
117 }
118 p.setPen(QPen(QColor(83, 214, 255), 2.2));
119 p.drawPath(path);
120
121 p.setPen(Qt::NoPen);
122 p.setBrush(QColor(255, 92, 105));
123 p.drawEllipse(center, 5.0, 5.0);
124 p.setPen(QColor(255, 134, 143));
125 p.drawText(QRectF(center.x() + 8.0, center.y() - 19.0, 190.0, 22.0), Qt::AlignLeft,
126 QStringLiteral("degeneracy q1=q2=0"));
127
128 const qpe::QuantumBerrySample2D &last = samples.back();
129 const QPointF current = mapQ(last.q1, last.q2);
130 // Make motion obvious even during the first few samples. The Berry loop
131 // is intentionally slow, so a larger live marker and a radial guide give
132 // immediate visual feedback that Analysis is receiving samples.
133 p.setPen(QPen(QColor(255, 214, 91), 1.3, Qt::DashLine));
134 p.drawLine(center, current);
135 p.setPen(Qt::NoPen);
136 p.setBrush(QColor(255, 214, 91));
137 p.drawEllipse(current, 8.0, 8.0);
138 p.setPen(QColor(215, 223, 232));
139 p.drawText(QRectF(loopRect.left() + 10.0, loopRect.bottom() - 27.0, 310.0, 20.0), Qt::AlignLeft,
140 QStringLiteral("physical principal axis rotates by θ/2"));
141 p.drawText(QRectF(loopRect.right() - 360.0, loopRect.bottom() - 27.0, 350.0, 20.0), Qt::AlignRight,
142 QStringLiteral("samples %1 t=%2 progress %3 %")
143 .arg(static_cast<qulonglong>(samples.size()))
144 .arg(last.time, 0, 'f', 2)
145 .arg(100.0 * last.progress, 0, 'f', 1));
146
147 const double t0 = samples.front().time;
148 const double t1 = samples.back().time;
149 const double span = std::max(1.0e-12, t1 - t0);
150 const auto mx = [&](double t) { return curveRect.left() + (t - t0) / span * curveRect.width(); };
151 const auto myF = [&](double f) {
152 return curveRect.bottom() - std::max(0.0, std::min(1.0, f)) * curveRect.height();
153 };
154 const auto myP = [&](double phase) {
155 const double degrees = phase * 180.0 / kPi;
156 return curveRect.center().y() - degrees / 180.0 * 0.5 * curveRect.height();
157 };
158
159 p.setPen(QPen(QColor(60, 67, 76), 1.0));
160 p.drawLine(QPointF(curveRect.left(), curveRect.center().y()), QPointF(curveRect.right(), curveRect.center().y()));
161 p.setPen(QPen(QColor(255, 190, 79), 1.0, Qt::DashLine));
162 p.drawLine(QPointF(curveRect.left(), curveRect.top()), QPointF(curveRect.right(), curveRect.top()));
163 p.drawLine(QPointF(curveRect.left(), curveRect.bottom()), QPointF(curveRect.right(), curveRect.bottom()));
164
165 QPainterPath fidelityPath;
166 QPainterPath phasePath;
167 bool firstF = true;
168 bool firstP = true;
169 for (const qpe::QuantumBerrySample2D &s : samples) {
170 const QPointF pf(mx(s.time), myF(s.returnFidelity));
171 if (firstF) { fidelityPath.moveTo(pf); firstF = false; }
172 else fidelityPath.lineTo(pf);
173 if (s.geometricPhaseValid) {
174 const QPointF pp(mx(s.time), myP(s.geometricPhase));
175 if (firstP) { phasePath.moveTo(pp); firstP = false; }
176 else phasePath.lineTo(pp);
177 } else {
178 firstP = true;
179 }
180 }
181 p.setPen(QPen(QColor(79, 220, 255), 2.0));
182 p.drawPath(fidelityPath);
183 if (samples.size() == 1u) {
184 p.setBrush(QColor(79, 220, 255));
185 p.drawEllipse(QPointF(mx(samples.front().time), myF(samples.front().returnFidelity)), 3.5, 3.5);
186 p.setBrush(Qt::NoBrush);
187 }
188 p.setPen(QPen(QColor(255, 190, 79), 2.0));
189 p.drawPath(phasePath);
190 if (samples.size() == 1u && samples.front().geometricPhaseValid) {
191 p.setBrush(QColor(255, 190, 79));
192 p.drawEllipse(QPointF(mx(samples.front().time), myP(samples.front().geometricPhase)), 3.5, 3.5);
193 p.setBrush(Qt::NoBrush);
194 }
195
196 p.setPen(QColor(79, 220, 255));
197 p.drawText(QRectF(curveRect.left() + 8.0, curveRect.top() + 5.0, 220.0, 20.0), Qt::AlignLeft,
198 QStringLiteral("cyan: return fidelity"));
199 p.setPen(QColor(255, 190, 79));
200 p.drawText(QRectF(curveRect.left() + 215.0, curveRect.top() + 5.0, 270.0, 20.0), Qt::AlignLeft,
201 QStringLiteral("gold: geometric phase (±180° scale)"));
202
203 p.setPen(QColor(202, 211, 221));
204 p.drawText(QRectF(4.0, curveRect.top() - 8.0, 48.0, 20.0), Qt::AlignRight, QStringLiteral("1"));
205 p.drawText(QRectF(4.0, curveRect.bottom() - 10.0, 48.0, 20.0), Qt::AlignRight, QStringLiteral("0"));
206 p.drawText(QRectF(curveRect.right() + 5.0, curveRect.top() - 8.0, 42.0, 20.0), Qt::AlignLeft, QStringLiteral("+180°"));
207 p.drawText(QRectF(curveRect.right() + 5.0, curveRect.center().y() - 10.0, 42.0, 20.0), Qt::AlignLeft, QStringLiteral("0°"));
208 p.drawText(QRectF(curveRect.right() + 5.0, curveRect.bottom() - 10.0, 42.0, 20.0), Qt::AlignLeft, QStringLiteral("-180°"));
209 p.drawText(QRectF(curveRect.left(), curveRect.bottom() + 5.0, 85.0, 20.0), Qt::AlignLeft,
210 QString::number(t0, 'f', 1));
211 p.drawText(QRectF(curveRect.right() - 85.0, curveRect.bottom() + 5.0, 85.0, 20.0), Qt::AlignRight,
212 QString::number(t1, 'f', 1));
213 p.drawText(QRectF(curveRect.left(), curveRect.bottom() + 4.0, curveRect.width(), 24.0), Qt::AlignCenter,
214 QStringLiteral("simulation time"));
215}
QSize minimumSizeHint() const override
Performs minimum size hint.
void paintEvent(QPaintEvent *event) override
Paints event.
void setData(const qpe::QuantumBerryHistory2D &history)
Sets data.
QuantumBerryPhasePlotWidget(QWidget *parent=nullptr)
Performs quantum berry phase plot widget.
const qpe::QuantumBerryHistory2D * history_
Implements the Quantum Berry History2D component.
const std::vector< QuantumBerrySample2D > & samples() const noexcept
Samples s.
const QuantumBerryLoop2DConfig & config() const noexcept
Returns config.
bool empty() const noexcept
Returns whether the object contains no data.
bool configured() const noexcept
Returns configured.
void frame(QPainter &p, const QRectF &r)
Performs frame.
Declares the quantumberryphaseplotwidget visualization component used by QPE.
Data structure used by the Quantum Berry Sample2D component.