Files
Jungfraujoch/common/ScanResult.h
T
leonarski_fandClaude Opus 5 26a82ddc72 spindle: the per-image severity travels the whole data path, and absence travels with it
The score was computed and then thrown away - carried on the per-image message but transported
nowhere - so the automation it exists for could not read it. It now flows like bkg_estimate at
every layer: CBOR (per-image key, END-block run mean and per-image array), HDF5 (per-image
/entry/MX/spindleBlindFraction in the data files, the array and spindleBlindFractionMean in the
master), read-back into a re-opened dataset, the scan result, the receiver plots, the REST plot
and scan_result schemas, and the viewer and frontend plot menus.

Absence is load-bearing and every transport keeps it distinguishable from a measured zero: the
CBOR key is simply missing, the HDF5 array holds NaN, and read-back turns NaN back into an
absent optional rather than a value. A pipeline that read 0 where the truth is "no value" would
take exactly the wrong action - a measured 0 says one sweep loses nothing, absence says nobody
could look, and the second must engage the recovery protocol while the first must not. The
round-trip tests pin all three states through CBOR and through a written-and-reopened file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EFEJG6WBQv8th4UJFNe53N
2026-09-04 10:59:05 +02:00

77 lines
2.6 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 <vector>
#include <optional>
#include <string>
#include "CrystalLattice.h"
#include "UnitCell.h"
struct ScanResultElem {
int64_t number = -1;
float collection_efficiency = 0.0;
std::optional<int64_t> x;
std::optional<int64_t> y;
std::optional<float> angle_deg;
std::optional<int64_t> pixel_sum;
std::optional<int64_t> indexed_lattice_count;
std::optional<int64_t> min_viable_pixel;
std::optional<int64_t> max_viable_pixel;
std::optional<int64_t> err_pixels;
std::optional<int64_t> sat_pixels;
std::optional<float> bkg;
std::optional<float> spindle_blind;
std::optional<int64_t> spot_count;
std::optional<int64_t> spot_count_low_res;
std::optional<int64_t> spot_count_indexed;
std::optional<int64_t> spot_count_ice;
std::optional<float> spot_count_ice_control;
std::optional<int64_t> indexing_solution;
std::optional<float> profile_radius;
std::optional<float> b_factor;
std::optional<float> res;
std::optional<UnitCell> uc;
std::optional<uint64_t> xfel_pulse_id;
std::optional<float> mosaicity;
std::optional<int64_t> niggli_class;
std::optional<int64_t> integrated_reflections;
std::optional<float> image_scale_factor;
std::optional<float> image_scale_cc;
std::optional<float> ice_ring_score;
};
struct ScanResult {
std::string file_prefix;
std::vector<ScanResultElem> images;
std::optional<CrystalLattice> rotation_lattice;
// Bravais lattice type of the global rotation-indexing solution (from RotationIndexer).
std::optional<gemmi::CrystalSystem> rotation_crystal_system;
std::optional<char> rotation_centering;
};
// Two-letter Bravais lattice symbol: crystal-system letter + centering, e.g. "tP", "oC", "cF", "hR".
inline std::string BravaisSymbol(gemmi::CrystalSystem system, char centering) {
char family;
switch (system) {
case gemmi::CrystalSystem::Triclinic: family = 'a'; break;
case gemmi::CrystalSystem::Monoclinic: family = 'm'; break;
case gemmi::CrystalSystem::Orthorhombic: family = 'o'; break;
case gemmi::CrystalSystem::Tetragonal: family = 't'; break;
case gemmi::CrystalSystem::Trigonal: family = 'h'; break;
case gemmi::CrystalSystem::Hexagonal: family = 'h'; break;
case gemmi::CrystalSystem::Cubic: family = 'c'; break;
default: family = 'a'; break;
}
return std::string{family} + centering;
}