rugnux: --mode raster reads a stored grid scan and reports the crystals in it
The offline entry point for a raster. It scores every image of a stored grid scan - spot finding for the per-cell resolution, no indexing, because a raster answers where the crystal is and not what its lattice is - hands the per-image protein and ice scores to AnalyzeGridScan, and writes what came back as two files beside the usual output: <prefix>_raster_report.txt in the idiom of the results report, and <prefix>_raster.json with the same content typed, so a battery can aggregate a sweep without scraping prose. --beam-size states the beam at the sample, defaulting to the file's incident_beam_size. It matters more than it looks: the reported crystal sizes are measured and still contain the beam, and taking an anisotropic beam back out is a subtraction of two covariance matrices, so a beam given as square when it is not rotates the reported crystal axis. --raster-protein-threshold and --raster-min-cells expose the two constants AnalyzeGridScan held at file scope, so a sweep can vary them without a rebuild; they are now defaulted parameters with the old values, and every existing call is unchanged. The observer feeding the analysis reads the file's own image number (DataMessage::original_number), not the loop's ordinal, so -s/-e/--stride cannot silently shift the grid mapping. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EFEJG6WBQv8th4UJFNe53N
This commit is contained in:
@@ -10,21 +10,15 @@
|
||||
#include "AnalyzeGridScan.h"
|
||||
|
||||
namespace {
|
||||
// A cell counts as protein above this. The per-image score saturates, so this only has to
|
||||
// separate "something diffracted here" from "nothing did".
|
||||
constexpr float PROTEIN_SCORE_THRESHOLD = 0.5f;
|
||||
|
||||
// Two cells can be the two ends of a single hit lying on a cell boundary; three is the
|
||||
// smallest patch that is a shape rather than a coincidence.
|
||||
constexpr int64_t MIN_BLOB_CELLS = 3;
|
||||
|
||||
constexpr float NO_VALUE = -1.0f;
|
||||
}
|
||||
|
||||
GridScanResult AnalyzeGridScan(const ScanResult &scan,
|
||||
const GridScanSettings &grid,
|
||||
float beam_size_x_um,
|
||||
float beam_size_y_um) {
|
||||
float beam_size_y_um,
|
||||
float protein_score_threshold,
|
||||
int64_t min_blob_cells) {
|
||||
const int64_t nx = grid.GetGridSizeX_step();
|
||||
const int64_t ny = grid.GetGridSizeY_step();
|
||||
const float step_x = fabsf(grid.GetGridStepX_um());
|
||||
@@ -49,9 +43,9 @@ GridScanResult AnalyzeGridScan(const ScanResult &scan,
|
||||
|
||||
std::vector<uint8_t> above(nx * ny);
|
||||
for (int64_t i = 0; i < nx * ny; i++)
|
||||
above[i] = (protein[i] > PROTEIN_SCORE_THRESHOLD) ? 1 : 0;
|
||||
above[i] = (protein[i] > protein_score_threshold) ? 1 : 0;
|
||||
|
||||
const std::vector<int32_t> label = LabelConnectedComponents(above, nx, ny, MIN_BLOB_CELLS);
|
||||
const std::vector<int32_t> label = LabelConnectedComponents(above, nx, ny, min_blob_cells);
|
||||
const int32_t n_label = label.empty() ? 0 : *std::max_element(label.begin(), label.end());
|
||||
|
||||
GridScanResult result;
|
||||
@@ -65,7 +59,7 @@ GridScanResult AnalyzeGridScan(const ScanResult &scan,
|
||||
cell.push_back(i);
|
||||
}
|
||||
if (cell.empty())
|
||||
continue; // label fell below MIN_BLOB_CELLS and was erased
|
||||
continue; // label fell below min_blob_cells and was erased
|
||||
|
||||
const auto n = static_cast<float>(cell.size());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user