Files
Jungfraujoch/common/DatasetSettings.h
T
leonarski_fandClaude Opus 5 26fc4b02b3 symmetry: carry the space group as the group, not as its number
The adopted space group travelled the pipeline as a bare int and was rebuilt
downstream with find_spacegroup_by_number, which returns the reference setting.
So every setting a number cannot name was destroyed one line after it was
determined: P 1 1 2 came back as P 1 2 1, I 1 1 2 as C 1 2 1, R 3:R as R 3:H.

DatasetSettings now holds the gemmi::SpaceGroup itself, DiffractionExperiment
exposes it as GetGemmiSpaceGroup() / GetSpaceGroupOrP1(), and everything that
used to take an int - HKLKeyGenerator (its int constructor is gone, so the
compiler finds the callers), the merge, the R-free flags, French-Wilson, the
reindexing ambiguity, the completeness enumeration, the MTZ and mmCIF exports,
the model validation - takes the group. -S keeps the setting the symbol names
rather than reducing it to a number.

The end message carries both spellings and a reader prefers the name, since
only the name keeps the setting while the number is what a reader written
before the name understands. It carries them over CBOR too: the determined
group was never serialised at all, so a group rugnux chose reached the master
file only when the same process wrote it, and an online writer fell back to
whatever the user had supplied at the start. Both keys are optional additions,
so an older reader skips them and a newer one reads an older sender.

On disk the master's /entry/sample/space_group carries the extended
Hermann-Mauguin name and is what the reader takes the group from, so a setting
survives a _process.h5 and the --mode scale that re-reads it; the number stays
beside it and is the fallback for files written before. Every one of the 230
reference settings the old writer could produce reads back as itself, so older
files are unaffected.

Stage A and Stage B of the search still enumerate reference settings only, so
this determines no group differently today - it is what the enumeration needs
before it can be widened.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EFEJG6WBQv8th4UJFNe53N
2026-08-31 07:16:43 +02:00

179 lines
7.1 KiB
C++

// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include <cstdint>
#include <string>
#include <optional>
#include "UnitCell.h"
#include "Coord.h"
#include "../compression/CompressionAlgorithmEnum.h"
#include "JFJochMessages.h"
#include "XrayFluorescenceSpectrum.h"
#include "gemmi/symmetry.hpp"
class DatasetSettings {
int64_t images_per_trigger;
int64_t ntrigger;
float beam_x_pxl;
float beam_y_pxl;
float detector_distance_mm;
float photon_energy_keV;
std::string file_prefix;
std::optional<int64_t> images_per_file;
CompressionAlgorithm compression;
std::string sample_name;
std::optional<UnitCell> unit_cell;
// The whole group, not its number: a number can only name the reference setting, so
// "P 1 1 2" and "R 3:R" are lost the moment a number is all that is kept.
std::optional<gemmi::SpaceGroup> space_group;
std::optional<float> total_flux;
std::optional<float> attenuator_transmission;
std::optional<float> ring_current_mA;
std::optional<GoniometerAxis> goniometer;
std::optional<GridScanSettings> grid_scan;
std::optional<float> sample_temperature_K;
nlohmann::json image_appendix;
nlohmann::json header_appendix;
float data_reduction_factor_serialmx;
std::optional<std::chrono::nanoseconds> image_time;
std::optional<uint64_t> run_number;
std::optional<std::string> run_name;
std::string group;
std::optional<int64_t> compression_poisson_factor;
std::optional<int64_t> pixel_value_low_threshold;
std::optional<int64_t> pixel_value_high_threshold;
std::optional<bool> save_calibration;
bool write_nxmx_hdf5_master;
std::optional<float> polarization_factor;
std::optional<float> bandwidth_fwhm; // relative X-ray bandwidth, FWHM of dlambda/lambda (e.g. 0.01 for 1%)
float poni_rot_1_rad;
float poni_rot_2_rad;
float poni_rot_3_rad;
bool spot_finding_enable;
int64_t max_spot_count;
bool detect_ice_rings; // Enable special handling of ice rings
XrayFluorescenceSpectrum fluorescence_spectrum;
std::optional<SmargonPosition> smargon_position;
public:
DatasetSettings();
DatasetSettings& ImagesPerTrigger(int64_t input);
DatasetSettings& NumTriggers(int64_t triggers);
DatasetSettings& PhotonEnergy_keV(float input);
DatasetSettings& BeamX_pxl(float input);
DatasetSettings& BeamY_pxl(float input);
DatasetSettings& DetectorDistance_mm(float input);
DatasetSettings& FilePrefix(std::string input);
DatasetSettings& FilePrefixTrusted(std::string input); // offline/local: no CheckPath guard (absolute allowed)
DatasetSettings& Compression(CompressionAlgorithm input);
DatasetSettings& SetUnitCell(const std::optional<UnitCell> &cell);
DatasetSettings& SpaceGroupNumber(std::optional<int64_t> input);
DatasetSettings& SetSpaceGroup(const std::optional<gemmi::SpaceGroup> &input);
DatasetSettings& SampleName(std::string input);
DatasetSettings& AttenuatorTransmission(const std::optional<float> &input);
DatasetSettings& TotalFlux(const std::optional<float> &input);
DatasetSettings& Goniometer(const std::optional<GoniometerAxis>& input);
DatasetSettings& GridScan(const std::optional<GridScanSettings>& input);
DatasetSettings& HeaderAppendix(const nlohmann::json& input);
DatasetSettings& ImageAppendix(const nlohmann::json& input);
DatasetSettings& ImagesPerFile(const std::optional<int64_t> &input);
DatasetSettings& RunNumber(const std::optional<uint64_t> &run_number);
DatasetSettings& RunName(const std::optional<std::string> &input);
DatasetSettings& ExperimentGroup(const std::string &group);
DatasetSettings& ImageTime(const std::optional<std::chrono::nanoseconds> &input);
DatasetSettings& LossyCompressionSerialMX(float input);
DatasetSettings& LossyCompressionPoisson(std::optional<int64_t> input);
DatasetSettings& WriteNXmxHDF5Master(bool input);
DatasetSettings& SaveCalibration(std::optional<bool> input);
DatasetSettings& PixelValueLowThreshold(const std::optional<int64_t> &input);
DatasetSettings& PixelValueHighThreshold(const std::optional<int64_t> &input);
DatasetSettings& PolarizationFactor(const std::optional<float> &input);
DatasetSettings& BandwidthFWHM(const std::optional<float> &input);
DatasetSettings& PoniRot1_rad(float input);
DatasetSettings& PoniRot2_rad(float input);
DatasetSettings& PoniRot3_rad(float input);
DatasetSettings& RingCurrent_mA(const std::optional<float> &input);
DatasetSettings& SampleTemperature_K(const std::optional<float> &input);
DatasetSettings& SpotFindingEnable(bool input);
DatasetSettings& MaxSpotCount(int64_t input);
DatasetSettings& DetectIceRings(bool input);
DatasetSettings& FluorescenceSpectrum(const XrayFluorescenceSpectrum& input);
DatasetSettings& Smargon(const std::optional<SmargonPosition>& input);
std::optional<float> GetAttenuatorTransmission() const;
std::optional<float> GetTotalFlux() const;
std::optional<GoniometerAxis> &Goniometer();
std::optional<GridScanSettings> &GridScan();
const std::optional<GoniometerAxis> &GetGoniometer() const;
const std::optional<GridScanSettings> &GetGridScan() const;
const nlohmann::json& GetHeaderAppendix() const;
const nlohmann::json& GetImageAppendix() const;
std::optional<UnitCell> GetUnitCell() const;
std::optional<int64_t> GetSpaceGroupNumber() const;
const std::optional<gemmi::SpaceGroup> &GetSpaceGroup() const;
std::string GetSampleName() const;
float GetPhotonEnergy_keV() const;
float GetBeamX_pxl() const;
float GetBeamY_pxl() const;
float GetDetectorDistance_mm() const;
Coord GetScatteringVector() const;
std::string GetFilePrefix() const;
CompressionAlgorithm GetCompressionAlgorithm() const;
int64_t GetNumTriggers() const;
int64_t GetImageNumPerTrigger() const;
std::optional<int64_t> GetImagesPerFile() const;
std::optional<uint64_t> GetRunNumber() const;
std::optional<std::string> GetRunName() const;
std::string GetExperimentGroup() const;
std::optional<std::chrono::nanoseconds> GetImageTime() const;
float GetLossyCompressionSerialMX() const;
std::optional<int64_t> GetLossyCompressionPoisson() const;
std::optional<int64_t> GetPixelValueLowThreshold() const;
std::optional<int64_t> GetPixelValueHighThreshold() const;
bool IsWriteNXmxHDF5Master() const;
std::optional<bool> IsSaveCalibration() const;
std::optional<float> GetPolarizationFactor() const;
std::optional<float> GetBandwidthFWHM() const;
float GetPoniRot1_rad() const;
float GetPoniRot2_rad() const;
float GetPoniRot3_rad() const;
std::optional<float> GetRingCurrent_mA() const;
std::optional<float> GetSampleTemperature_K() const;
bool IsSpotFindingEnabled() const;
int64_t GetMaxSpotCount() const;
bool IsDetectIceRings() const;
const XrayFluorescenceSpectrum &GetFluorescenceSpectrum() const;
std::optional<SmargonPosition> GetSmargonPosition() const;
};