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
77 lines
2.6 KiB
C++
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;
|
|
}
|
|
|
|
|