Files
Jungfraujoch/viewer/widgets/JFJochViewerSettingsDock.h
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

166 lines
8.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
#pragma once
#include <QWidget>
#include <memory>
#include "../../common/DiffractionExperiment.h"
#include "../../common/IndexingSettings.h"
#include "../../common/AzimuthalIntegrationSettings.h"
#include "../../common/BraggIntegrationSettings.h"
#include "../../common/ScalingSettings.h"
#include "../../image_analysis/spot_finding/SpotFindingSettings.h"
#include "../../reader/JFJochReaderDataset.h"
#include "../../reader/JFJochReaderImage.h"
#include "../../rugnux/Rugnux.h" // ProcessMode
#include "../ReferenceMtzInfo.h"
#include "PowderCalibrationWidget.h" // CalibrationSelection
class QStackedWidget;
class QCheckBox;
class QComboBox;
class QLabel;
class QLineEdit;
class QPushButton;
class QRadioButton;
class SliderPlusBox;
class NumberLineEdit;
// The single, always-visible settings panel: an MX / AzInt / Calib toggle picks the page, and the panel
// is the one place all processing settings live (there is no separate window, so no synchronisation).
// "Analyze image" / "Analyze dataset" sit on top; the page choice decides what a dataset run does.
// Edits feed straight back into the running analysis via the worker.
class JFJochViewerSettingsDock : public QWidget {
Q_OBJECT
public:
JFJochViewerSettingsDock(const SpotFindingSettings &spot, const IndexingSettings &indexing,
const AzimuthalIntegrationSettings &azint, const BraggIntegrationSettings &bragg,
const ScalingSettings &scaling, QWidget *parent = nullptr);
public slots:
void datasetLoaded(std::shared_ptr<const JFJochReaderDataset> dataset);
void loadImage(std::shared_ptr<const JFJochReaderImage> image);
void referenceLoaded(ReferenceMtzInfo info); // worker reports a (un)loaded reference MTZ
// Dataset re-processing reads a stored HDF5 file, so it is unavailable on a live HTTP stream:
// grey out "Analyze dataset" while connected rather than failing with a dialog afterwards.
void setHttpConnection(bool connected, QString addr);
signals:
void spotFindingChanged(const SpotFindingSettings &spot, const IndexingSettings &indexing, int64_t max_spots);
void azintChanged(const AzimuthalIntegrationSettings &settings);
void braggChanged(BraggIntegrationSettings settings);
void scalingChanged(ScalingSettings settings);
void experimentChanged(const DiffractionExperiment &experiment);
void findBeamCenter(QVector<float> ring_q, bool guess, bool refine_tilt);
void ringsFromCalibration(QVector<float> rings);
void referenceSelected(QString path, QString column); // user picked a reference MTZ / SF-mmCIF / column
void modelSelected(QString path); // user picked (or cleared) the atomic model for validation
void reanalyzeImage(bool armed); // "Analyze image" toggle
// "Analyze dataset". The mode is the selected page; the calibrant selection is only read for
// ProcessMode::Calibration and is carried along so the job needs no second copy of the controls.
void analyzeDataset(ProcessMode mode, CalibrationSelection calibration);
private:
SpotFindingSettings spot_;
IndexingSettings indexing_;
AzimuthalIntegrationSettings azint_;
BraggIntegrationSettings bragg_;
ScalingSettings scaling_;
DiffractionExperiment experiment_;
bool have_experiment_ = false; // geometry edits only take effect once a dataset is loaded
int64_t max_spots_ = 1000;
// Min-pix is kept as the pair the UI shows - the fixed value AND whether to choose it per image -
// because spot_.min_pix_per_spot can only hold one of the two (unset = per image). SyncMinPix()
// turns the pair into that field, and per-image only ever applies to stills.
bool adaptive_min_pix_ = false;
int64_t min_pix_value_ = 2;
ProcessMode mode_ = ProcessMode::FullAnalysis; // the selected page, and what "Analyze dataset" runs
// "Analyze dataset" hero button, disabled while a live HTTP source is connected.
QPushButton *analyzeDatasetBtn_ = nullptr;
// Indexing-algorithm combo + the description line under it (kept so the Auto resolution refreshes).
QComboBox *algo_ = nullptr;
QLabel *algoDesc_ = nullptr;
// Geometry fields (shared by both MX and AzInt, since both need the same geometry)
NumberLineEdit *energy_ = nullptr;
NumberLineEdit *distance_ = nullptr;
NumberLineEdit *beamX_ = nullptr;
NumberLineEdit *beamY_ = nullptr;
NumberLineEdit *rot1_ = nullptr; // detector tilt (PONI rot1), deg
NumberLineEdit *rot2_ = nullptr; // detector tilt (PONI rot2), deg
// Polarization factor, also shared: it corrects the azimuthal profile and the Bragg intensities
// alike. Unchecked = no polarization correction (the experiment's factor is unset).
QCheckBox *polarizationOn_ = nullptr;
NumberLineEdit *polarization_ = nullptr;
// How the sample moves between images — the three cases a dataset can be, exactly as a file
// stores them (a rotation axis, a grid scan, or neither). The choice sets or clears the
// experiment's goniometer / grid scan, and ApplyProcessingMode() turns it into the
// indexing/scaling mode. Each group keeps its values while another mode is selected.
QRadioButton *modeStill_ = nullptr;
QRadioButton *modeRotation_ = nullptr;
QRadioButton *modeGrid_ = nullptr;
QLineEdit *axisName_ = nullptr;
NumberLineEdit *axisX_ = nullptr, *axisY_ = nullptr, *axisZ_ = nullptr;
NumberLineEdit *rotStart_ = nullptr, *rotIncrement_ = nullptr;
// Not editable here, but part of the file's goniometer — kept so rebuilding the axis from the
// fields does not drop them.
std::optional<Coord> gonioHelicalStep_;
std::optional<float> gonioScreeningWedge_;
// Grid scan. Only the fast-axis point count is a free parameter: the number of slow rows follows
// from the image count (GridScanSettings::ImageNum), which is why there is no second count field
// and why gridSummary_ spells out the grid the settings actually make.
NumberLineEdit *gridNFast_ = nullptr;
NumberLineEdit *gridStepX_ = nullptr, *gridStepY_ = nullptr;
QCheckBox *gridVertical_ = nullptr, *gridSnake_ = nullptr;
QLabel *gridSummary_ = nullptr;
// Crystal fields
QCheckBox *cellKnown_ = nullptr;
NumberLineEdit *cellA_ = nullptr, *cellB_ = nullptr, *cellC_ = nullptr;
NumberLineEdit *cellAlpha_ = nullptr, *cellBeta_ = nullptr, *cellGamma_ = nullptr;
NumberLineEdit *spaceGroup_ = nullptr;
QLabel *spaceGroupName_ = nullptr; // resolved Hermann–Mauguin symbol
// Reference dataset (MTZ) for scaling / CCref. The chosen file is remembered so a
// column change re-loads the same file; the worker owns the reflections, this just drives it.
QPushButton *refButton_ = nullptr;
QComboBox *refColumn_ = nullptr;
QLabel *refSummary_ = nullptr;
QLabel *refWarning_ = nullptr;
QString refPath_;
QPushButton *modelButton_ = nullptr;
QPushButton *modelClear_ = nullptr;
QLabel *modelLabel_ = nullptr;
QString modelPath_;
PowderCalibrationWidget *powder_ = nullptr;
// Azimuthal integration: one section, shared by the AzInt and Calib pages (a calibration by rings
// integrates the run in azimuthal sectors), so it sits outside the page stack and is hidden on MX.
QWidget *azintSection_ = nullptr;
QWidget *BuildGeometrySection();
QWidget *BuildMXPage();
QWidget *BuildGoniometerSection();
QWidget *BuildBraggSection();
QWidget *BuildScalingSection();
QWidget *BuildReferenceSection();
QWidget *BuildAzIntSection();
QWidget *BuildCalibrationPage();
void SyncMinPix();
void EmitSpotFinding();
void EmitExperiment();
void ApplyProcessingMode(); // sample-motion mode -> indexing + scaling rotation/stills mode
void UpdateAlgorithmDescription();
void RefreshGeometryFields();
void UpdateSpaceGroupName();
void EnableRotationFields(bool on);
void EnableGridFields(bool on);
void UpdateGridSummary();
[[nodiscard]] std::optional<GoniometerAxis> GoniometerFromFields() const;
[[nodiscard]] std::optional<GridScanSettings> GridScanFromFields() const;
};