grid scan: one cell is a crystal when that cell is decisive, and the list can be capped
The minimum patch size was a flat floor, so a crystal that covers one or two grid points was thrown away however strong its diffraction. It is now a floor OR a piece of evidence: a patch is reported when it has min_blob_cells cells, or when its best cell reaches decisive_protein_score. One condition, and both halves are parameters. The bar is the patch PEAK, not the patch mean. A two-cell patch with one strong cell and one marginal one is the case this exists for, and the mean averages exactly that evidence away. Over the 67 labelled rasters the two populations do not overlap: no water raster reaches a peak of 0.15 and no ice raster reaches 0.50, while the weakest protein raster peaks at 0.67 - so 0.6, the middle of that gap, is the default. The peak is reported beside the mean, in the table and in the JSON, so an admission can be checked against the number that decided it. max_crystals caps the returned list after the sort, best first; 0, the default, is all of them, because a crystal that was found and then dropped is information the caller cannot get back. The four parameters now travel as one GridScanAnalysisParameters, which is the shape the GridScanAnalysisSettings class in common/ is to take: when it lands it replaces this struct in the signature and nothing else changes. On the corpus this reaches 17/17 protein loops (it was 16/17 - the miss was a crystal covering two grid points of a 4x4 raster) with water still 0/4 and ice still 0/3. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EFEJG6WBQv8th4UJFNe53N
This commit is contained in:
1 parent
1f54b3a971
commit
cdb60c2916
10 files changed
+234
-59
No files matched your search
@@ -50,8 +50,11 @@ TEST_CASE("AnalyzeGridScan finds nothing in an empty scan", "[AnalyzeGridScan]")
|
||||
CHECK(result.crystals.empty());
|
||||
}
|
||||
|
||||
SECTION("a two-cell patch is below the minimum blob size") {
|
||||
auto scan = MakeScan(6, 6, {{2, 2}, {3, 2}}, 0.9f);
|
||||
SECTION("a two-cell patch is below the minimum blob size and its score is not decisive") {
|
||||
// Above the admission threshold, so the cells are in a patch at all, but under the score at
|
||||
// which one cell would be evidence enough on its own. RasterReportTest covers the other
|
||||
// side of that rule - a patch this small kept because its best cell IS decisive.
|
||||
auto scan = MakeScan(6, 6, {{2, 2}, {3, 2}}, 0.55f);
|
||||
auto result = AnalyzeGridScan(scan, grid, 5.0f, 5.0f);
|
||||
CHECK(result.crystals.empty());
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user