Files
Jungfraujoch/viewer/windows/JFJochCalibrationResultWindow.cpp
T
leonarski_f 84228bf8be
Build Packages / Create release (push) Successful in 24s
Build Packages / build:viewer:macos-arm64:nocuda (push) Successful in 3m29s
Build Packages / build:rugnux:macos-arm64:nocuda (push) Successful in 2m43s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 8m27s
Build Packages / build:rugnux:linux-x86_64:cuda (push) Successful in 9m53s
Build Packages / build:viewer:linux-x86_64:nocuda (push) Successful in 9m58s
Build Packages / build:viewer:linux-x86_64:cuda (push) Successful in 11m22s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 13m39s
Build Packages / build:viewer:windows-x86_64:nocuda (push) Successful in 18m37s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 16m32s
Build Packages / build:viewer:windows-x86_64:cuda (push) Successful in 24m11s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 25m30s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 19m3s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 20m23s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 19m41s
Build Packages / Generate python client (push) Successful in 50s
Build Packages / Build documentation (push) Successful in 1m16s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 21m0s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 18m38s
Build Packages / build:rugnux:windows-x86_64:cuda (push) Successful in 14m33s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 17m55s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 20m50s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 18m38s
Build Packages / Unit tests (push) Successful in 1h46m14s
v1.0.0-rc.173 (#83)
* jfjoch_broker: Optional per-dataset authentication - statistics, images and plots can require a bearer token, which jfjoch_viewer supports.
* jfjoch_viewer: Dark mode and a theme-matched colour scheme, a magnifier panel, and simpler contrast and background controls.
* Rugnux: Multiple performance improvements on GPU and CPU (CPU-only processing up to 40% faster, faster image decoding on ARM), with unchanged results.
* Rugnux: `--model` rigid-body refinement runs on the GPU, and the model-validation check is faster and more reliable.
* Rugnux: Improved scaling and merging - error model, outlier rejection, absorption correction and French-Wilson amplitudes now agree more closely with XDS and ctruncate.
* Rugnux: Improved integration - radial background on powder and ice rings, crowded rotation data keep their reflections, and CPU-only builds integrate large unit cells as GPU builds do.
* Rugnux: More robust detector geometry - measured beam centre, X-ray bandwidth and goniometer rate, and geometry refinement accepted only on significant evidence.
* Rugnux: Merged files are written in the standard setting, or in the setting of a reference MTZ, structure-factor mmCIF or model, with its free-R flags.
* Rugnux: Richer report - ice and powder rings, further lattices, superstructure candidates and mosaicity, with warnings worded as prompts to check.
* Rugnux: Clear error messages when a data set needs more GPU or host memory than is available.

Reviewed-on: #83
Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
2026-09-29 15:57:32 +02:00

107 lines
5.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include "JFJochCalibrationResultWindow.h"
#include "../ViewerTheme.h"
#include <QFrame>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QTableWidget>
#include <QVBoxLayout>
#include "../../common/JFJochMath.h" // PI
namespace {
constexpr double RAD_TO_DEG = 180.0 / PI;
// A big-number "card" for the hero row, as in the merge-statistics window.
QWidget *MakeCard(const QString &value, const QString &caption, QWidget *parent) {
auto *card = new QFrame(parent);
card->setFrameShape(QFrame::StyledPanel);
auto *l = new QVBoxLayout(card);
l->setContentsMargins(12, 8, 12, 8);
l->setSpacing(0);
auto *v = new QLabel(value, card);
QFont f = v->font();
f.setPointSizeF(f.pointSizeF() * 2.2);
f.setBold(true);
v->setFont(f);
SetThemedStyleSheet(v, [] { return "color: " + AccentTextColor().name() + ";"; });
v->setAlignment(Qt::AlignCenter);
auto *c = new QLabel(caption, card);
c->setStyleSheet("color: gray;");
c->setAlignment(Qt::AlignCenter);
l->addWidget(v);
l->addWidget(c);
return card;
}
}
JFJochCalibrationResultWindow::JFJochCalibrationResultWindow(const QString &title,
const CalibrationResult &calibration,
const DiffractionGeometry &header,
const QString &poni_path,
QWidget *parent)
: QWidget(parent, Qt::Window) {
setWindowTitle("Detector calibration — " + title);
setAttribute(Qt::WA_DeleteOnClose);
resize(640, 380);
const DiffractionGeometry &g = calibration.geometry;
const double pxl_mm = g.GetPixelSize_mm();
auto *layout = new QVBoxLayout(this);
auto *hero = new QHBoxLayout();
hero->addWidget(MakeCard(QString::number(calibration.rms_radial_pxl, 'f', 2), "Radial rms [px]", this));
hero->addWidget(MakeCard(QString::number(calibration.beam_sigma_pxl, 'f', 3), "Beam σ [px]", this));
hero->addWidget(MakeCard(QString::number(calibration.ring_points), "Ring points", this));
layout->addLayout(hero);
auto *table = new QTableWidget(7, 4, this);
table->setHorizontalHeaderLabels({"Quantity", "Fitted", "From header", "Change"});
table->setEditTriggers(QAbstractItemView::NoEditTriggers);
table->verticalHeader()->setVisible(false);
table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
// The PONI is the point of normal incidence, which is what the .poni file stores; the direct beam
// is where the beam actually lands, which is what every other program calls the beam centre. They
// part company by distance*tan(rot) as soon as the detector is tilted, so show both.
const auto [beam_x, beam_y] = g.GetDirectBeam_pxl();
const auto [header_beam_x, header_beam_y] = header.GetDirectBeam_pxl();
const struct { QString name; double fitted; double header; int digits; } rows[] = {
{"PONI x [px]", g.GetBeamX_pxl(), header.GetBeamX_pxl(), 3},
{"PONI y [px]", g.GetBeamY_pxl(), header.GetBeamY_pxl(), 3},
{"Rot1 [°]", g.GetPoniRot1_rad() * RAD_TO_DEG, header.GetPoniRot1_rad() * RAD_TO_DEG, 4},
{"Rot2 [°]", g.GetPoniRot2_rad() * RAD_TO_DEG, header.GetPoniRot2_rad() * RAD_TO_DEG, 4},
{"Distance [mm]", g.GetDetectorDistance_mm(), header.GetDetectorDistance_mm(), 4},
{"Direct beam x [px]", beam_x, header_beam_x, 3},
{"Direct beam y [px]", beam_y, header_beam_y, 3},
};
for (int i = 0; i < 7; i++) {
const double change = rows[i].fitted - rows[i].header;
table->setItem(i, 0, new QTableWidgetItem(rows[i].name));
table->setItem(i, 1, new QTableWidgetItem(QString::number(rows[i].fitted, 'f', rows[i].digits)));
table->setItem(i, 2, new QTableWidgetItem(QString::number(rows[i].header, 'f', rows[i].digits)));
table->setItem(i, 3, new QTableWidgetItem(
QStringLiteral("%1%2").arg(change >= 0 ? "+" : "").arg(change, 0, 'f', rows[i].digits)));
}
layout->addWidget(table);
auto *note = new QLabel(this);
note->setWordWrap(true);
note->setStyleSheet("color: gray;");
// In mm these are what the .poni file carries, so they are measured pyFAI's way - from the edge of
// the sensor, which puts the centre of pixel i at (i + 0.5) * pixel size - not from the centre of
// the first pixel as the [px] rows above (docs/DETECTOR_GEOMETRY.md).
note->setText(QStringLiteral("PONI x = %1 mm, PONI y = %2 mm.%3")
.arg((g.GetBeamX_pxl() + 0.5) * pxl_mm, 0, 'f', 4)
.arg((g.GetBeamY_pxl() + 0.5) * pxl_mm, 0, 'f', 4)
.arg(poni_path.isEmpty() ? QString() : " Written to " + poni_path));
layout->addWidget(note);
}