Gemmi C++ API
Loading...
Searching...
No Matches
blob.hpp
Go to the documentation of this file.
1// Copyright 2021 Global Phasing Ltd.
2//
3// Finding maxima or "blobs" in a Grid (map).
4// Similar to CCP4 PEAKMAX and COOT's "Unmodelled blobs".
5//
6// Implementation of the flood fill algorithm in find_blobs_by_flood_fill()
7// differs from from FloodFill in floodfill.hpp.
8// FloodFill uses more efficient scanline fill, but doesn't use symmetry.
9
10#ifndef GEMMI_BLOB_HPP_
11#define GEMMI_BLOB_HPP_
12
13#include "grid.hpp" // for Grid
14#include "asumask.hpp" // for get_asu_mask
15
16namespace gemmi {
17
18struct Blob {
19 double volume = 0.0;
20 double score = 0.0;
21 double peak_value = 0.0;
24 explicit operator bool() const { return volume != 0. ; }
25};
26
28 double cutoff;
29 double min_volume = 10.0;
30 double min_score = 15.0;
31 double min_peak = 0.0;
32};
33
34namespace impl {
35
36struct GridConstPoint {
37 int u, v, w;
38 float value;
39};
40
41inline Blob make_blob_of_points(const std::vector<GridConstPoint>& points,
42 const GridMeta& grid,
43 const BlobCriteria& criteria) {
44 Blob blob;
45 if (points.size() < 3)
46 return blob;
47 double volume_per_point = grid.unit_cell.volume / grid.point_count();
48 double volume = points.size() * volume_per_point;
49 if (volume < criteria.min_volume)
50 return blob;
51 double sum[3] = {0., 0., 0.};
52 const GridConstPoint* peak_point = &points[0];
53 blob.peak_value = points[0].value;
54 double score = 0.;
55 for (const GridConstPoint& point : points) {
56 score += point.value;
57 if (point.value > blob.peak_value) {
58 blob.peak_value = point.value;
59 peak_point = &point;
60 }
61 sum[0] += double(point.u) * point.value;
62 sum[1] += double(point.v) * point.value;
63 sum[2] += double(point.w) * point.value;
64 }
65 if (blob.peak_value < criteria.min_peak)
66 return blob;
67 blob.score = score * volume_per_point;
68 if (blob.score < criteria.min_score)
69 return blob;
70 gemmi::Fractional fract(sum[0] / (score * grid.nu),
71 sum[1] / (score * grid.nv),
72 sum[2] / (score * grid.nw));
73 blob.centroid = grid.unit_cell.orthogonalize(fract);
74 blob.peak_pos = grid.get_position(peak_point->u, peak_point->v, peak_point->w);
75 blob.volume = volume;
76 return blob;
77}
78
79} // namespace impl
80
81// with negate=true grid negatives of grid values are used
82inline std::vector<Blob> find_blobs_by_flood_fill(const gemmi::Grid<float>& grid,
84 bool negate=false) {
85 std::vector<Blob> blobs;
86 std::array<std::array<int, 3>, 6> moves = {{{{-1, 0, 0}}, {{1, 0, 0}},
87 {{0 ,-1, 0}}, {{0, 1, 0}},
88 {{0, 0, -1}}, {{0, 0, 1}}}};
89 // the mask will be used as follows:
90 // -1=in blob, 0=in asu, not in blob (so far), 1=in neither
91 std::vector<std::int8_t> mask = gemmi::get_asu_mask(grid);
92 std::vector<gemmi::GridOp> ops = grid.get_scaled_ops_except_id();
93 size_t idx = 0;
94 for (int w = 0; w != grid.nw; ++w)
95 for (int v = 0; v != grid.nv; ++v)
96 for (int u = 0; u != grid.nu; ++u, ++idx) {
97 assert(idx == grid.index_q(u, v, w));
98 if (mask[idx] != 0)
99 continue;
100 float value = grid.data[idx];
101 if (negate)
102 value = -value;
103 if (value < criteria.cutoff)
104 continue;
105 std::vector<impl::GridConstPoint> points;
106 points.push_back({u, v, w, value});
107 mask[idx] = -1;
108 for (size_t j = 0; j < points.size()/*increasing!*/; ++j)
109 for (const std::array<int, 3>& mv : moves) {
110 int nabe_u = points[j].u + mv[0];
111 int nabe_v = points[j].v + mv[1];
112 int nabe_w = points[j].w + mv[2];
113 size_t nabe_idx = grid.index_s(nabe_u, nabe_v, nabe_w);
114 if (mask[nabe_idx] == -1)
115 continue;
116 float nabe_value = grid.data[nabe_idx];
117 if (negate)
119 if (nabe_value > criteria.cutoff) {
120 if (mask[nabe_idx] != 0)
121 for (const gemmi::GridOp& op : ops) {
122 auto t = op.apply(nabe_u, nabe_v, nabe_w);
123 size_t mate_idx = grid.index_s(t[0], t[1], t[2]);
124 if (mask[mate_idx] == 0)
125 mask[mate_idx] = 1;
126 }
127 mask[nabe_idx] = -1;
128 points.push_back({nabe_u, nabe_v, nabe_w, nabe_value});
129 }
130 }
131 if (Blob blob = impl::make_blob_of_points(points, grid, criteria))
132 blobs.push_back(blob);
133 }
134 std::sort(blobs.begin(), blobs.end(),
135 [](const Blob& a, const Blob& b) { return a.score > b.score; });
136 return blobs;
137}
138
139} // namespace gemmi
140#endif
std::vector< Blob > find_blobs_by_flood_fill(const gemmi::Grid< float > &grid, const BlobCriteria &criteria, bool negate=false)
Definition blob.hpp:82
std::vector< V > get_asu_mask(const GridMeta &grid)
Definition asumask.hpp:255
double min_volume
Definition blob.hpp:29
gemmi::Position peak_pos
Definition blob.hpp:23
double score
Definition blob.hpp:20
double volume
Definition blob.hpp:19
gemmi::Position centroid
Definition blob.hpp:22
double peak_value
Definition blob.hpp:21
Fractional coordinates.
Definition unitcell.hpp:50
Coordinates in Angstroms - orthogonal (Cartesian) coordinates.
Definition unitcell.hpp:32