grid scan: a raster reaches the spot engine, and the crystal cap says none rather than zero
Two defects the merge created and one the API carried. Rugnux gated the per-image spot engine on AnalysisModeIsMX, so AnalysisMode::Grid fell through to the azimuthal-integration-only path: a raster ran, scored nothing, and reported no crystals. The gate now asks the stages table whether the mode does spot finding, which is the actual question - three modes need that engine for three different reasons, and a fourth would otherwise have to be remembered here too. max_crystals was a required integer defaulting to 10, with 0 meaning "all". Zero reads as "report no crystals", the opposite of what it did. It is now optional, and absent means no cap; a crystal found and then dropped is information the caller cannot get back. grow_score_threshold was missing from the schema entirely. Measured over the labelled corpus after these fixes: 34 of 34 confirmed-protein rasters yield a crystal, 0 of 8 water, 0 of 6 ice, 19 of 19 heldout. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EFEJG6WBQv8th4UJFNe53N
This commit is contained in:
@@ -72,7 +72,8 @@ TEST_CASE("RasterReport_Render", "[Diagnostics]") {
|
||||
CHECK(report.find("GROW_SCORE_THRESHOLD= 0.35\n") != std::string::npos);
|
||||
CHECK(report.find("MIN_BLOB_CELLS= 3\n") != std::string::npos);
|
||||
CHECK(report.find("DECISIVE_PROTEIN_SCORE= 0.60\n") != std::string::npos);
|
||||
CHECK(report.find("MAX_CRYSTALS= 0\n") != std::string::npos);
|
||||
// Unset means no cap; "0" would read as "report no crystals".
|
||||
CHECK(report.find("MAX_CRYSTALS= none\n") != std::string::npos);
|
||||
CHECK(report.find("CRYSTAL_COUNT= 1\n") != std::string::npos);
|
||||
CHECK(report.find("END OF REPORT") != std::string::npos);
|
||||
}
|
||||
@@ -196,7 +197,7 @@ TEST_CASE("RasterReport_ThreeCrystalsAndTheCap", "[Diagnostics]") {
|
||||
CHECK(all.crystals[2].score == Catch::Approx(0.75).margin(1e-5));
|
||||
|
||||
// The cap keeps the strongest, not the first found: the 0.85 patch is the last one in grid order.
|
||||
settings.analysis.max_crystals = 2;
|
||||
settings.analysis.MaxCrystals(2);
|
||||
const GridScanResult capped = AnalyzeGridScan(scan, grid, settings.beam_size_x_um,
|
||||
settings.beam_size_y_um, settings.analysis);
|
||||
REQUIRE(capped.crystals.size() == 2);
|
||||
@@ -225,7 +226,7 @@ TEST_CASE("RasterReport_OneDecisiveCellIsACrystal", "[Diagnostics]") {
|
||||
|
||||
// Raise the bar past the one cell that passed and nothing is left; a patch that meets the cell
|
||||
// minimum is unaffected by the bar, which is what makes this an OR and not a second gate.
|
||||
settings.analysis.decisive_protein_score = 0.99f;
|
||||
settings.analysis.DecisiveSingleCellScore(0.99f);
|
||||
CHECK(AnalyzeGridScan(scan, grid, settings.beam_size_x_um, settings.beam_size_y_um,
|
||||
settings.analysis).crystals.empty());
|
||||
|
||||
@@ -250,7 +251,7 @@ TEST_CASE("RasterReport_HysteresisHealsASplit", "[Diagnostics]") {
|
||||
CHECK(healed.crystals[0].n_images == 7); // the bridging cell is part of the crystal
|
||||
|
||||
// Growing no further than the seed level is the behaviour hysteresis replaced, and it splits.
|
||||
settings.analysis.grow_score_threshold = settings.analysis.protein_score_threshold;
|
||||
settings.analysis.GrowScoreThreshold(settings.analysis.GetProteinScoreThreshold());
|
||||
const GridScanResult split = AnalyzeGridScan(scan, grid, settings.beam_size_x_um,
|
||||
settings.beam_size_y_um, settings.analysis);
|
||||
CHECK(split.crystals.size() == 2);
|
||||
@@ -266,7 +267,7 @@ TEST_CASE("RasterReport_GrowthCannotStartOnItsOwn", "[Diagnostics]") {
|
||||
CHECK(AnalyzeGridScan(scan, grid, settings.beam_size_x_um, settings.beam_size_y_um,
|
||||
settings.analysis).crystals.empty());
|
||||
|
||||
settings.analysis.grow_score_threshold = 0.05f;
|
||||
settings.analysis.GrowScoreThreshold(0.05f);
|
||||
CHECK(AnalyzeGridScan(scan, grid, settings.beam_size_x_um, settings.beam_size_y_um,
|
||||
settings.analysis).crystals.empty());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user