FZGPUModules 2.0
GPU-accelerated modular compression pipelines
Loading...
Searching...
No Matches
roibin_split_stage.h
Go to the documentation of this file.
1#pragma once
2
91#include "stage/stage.h"
92#include "fzm_format.h"
93#include "backend/types.h"
94#include <array>
95#include <cstdint>
96#include <cstring>
97#include <stdexcept>
98#include <string>
99#include <unordered_map>
100#include <vector>
101
102namespace fz {
103
105struct RoiPeak {
106 uint32_t z;
107 uint16_t x;
108 uint16_t y;
109};
110static_assert(sizeof(RoiPeak) == 8, "RoiPeak must be 8 bytes to match the .roi format");
111
117template <typename TData>
118class ROIBinSplitStage : public Stage {
119public:
120 ROIBinSplitStage() = default;
121 ~ROIBinSplitStage() override = default;
122
123 // ── Configuration ───────────────────────────────────────────────────────
124
127 void setPeaksFile(const std::string& path);
128
130 void setPeaks(const std::vector<RoiPeak>& peaks);
131
133 void setRoiHalfWidth(uint32_t hw) { half_width_ = hw; }
134 uint32_t getRoiHalfWidth() const { return half_width_; }
135
138 void setBinFactor(uint32_t b) {
139 if (b == 0) throw std::runtime_error("ROIBinSplit: bin_factor must be >= 1");
140 bin_ = b;
141 }
142 uint32_t getBinFactor() const { return bin_; }
143
154 void setDims(const std::array<size_t, 3>& dims) override {
155 if (dims_from_header_ || dims[0] == 0) return;
156 dims_ = dims;
157 }
158 void setDims(size_t x, size_t y = 1, size_t z = 1) {
159 setDims(std::array<size_t, 3>{x, y, z});
160 }
161
162 size_t getNumPeaks() const { return peaks_.size(); }
163 size_t getBoxArea() const { return size_t(2 * half_width_ + 1) * (2 * half_width_ + 1); }
164 size_t getBgNx() const { return (dims_[0] + bin_ - 1) / bin_; }
165 size_t getBgNy() const { return (dims_[1] + bin_ - 1) / bin_; }
166 size_t getBgCount() const { return getBgNx() * getBgNy() * dims_[2]; }
167 size_t getRoiCount() const { return peaks_.size() * getBoxArea(); }
168
172 double getRoiOverlapFraction() const { return overlap_frac_; }
173
174 // ── Stage control ───────────────────────────────────────────────────────
175 void setInverse(bool inv) override { is_inverse_ = inv; }
176 bool isInverse() const override { return is_inverse_; }
177
180 bool isGraphCompatible() const override { return true; }
181
182 // ── Port model ──────────────────────────────────────────────────────────
183 size_t getNumInputs() const override { return is_inverse_ ? 3 : 1; }
184 size_t getNumOutputs() const override { return is_inverse_ ? 1 : 3; }
185
186 std::vector<std::string> getOutputNames() const override {
187 return is_inverse_ ? std::vector<std::string>{"output"}
188 : std::vector<std::string>{"roi", "bg", "peaks"};
189 }
190
191 std::string getName() const override { return "ROIBinSplit"; }
192
193 uint16_t getStageTypeId() const override {
194 return static_cast<uint16_t>(StageType::ROIBIN_SPLIT);
195 }
196
197 uint8_t getOutputDataType(size_t output_index) const override {
198 if (is_inverse_) return elemType();
199 switch (output_index) {
200 case 0: return elemType(); // roi
201 case 1: return elemType(); // bg
202 default: return static_cast<uint8_t>(DataType::UINT8); // peaks
203 }
204 }
205 uint8_t getInputDataType(size_t input_index) const override {
206 if (!is_inverse_) return elemType();
207 switch (input_index) {
208 case 0: return elemType();
209 case 1: return elemType();
210 default: return static_cast<uint8_t>(DataType::UINT8);
211 }
212 }
213
214 // ── Execution ───────────────────────────────────────────────────────────
216 fz::stream_t stream,
217 MemoryPool* pool,
218 const std::vector<void*>& inputs,
219 const std::vector<void*>& outputs,
220 const std::vector<size_t>& sizes
221 ) override;
222
225 void onFinalize(size_t estimated_inlen, MemoryPool* pool) override;
226
227 size_t estimateDeviceFootprintBytes(size_t /*inlen*/) const override {
228 return peaks_.size() * sizeof(RoiPeak);
229 }
230
231 // ── Size estimation ─────────────────────────────────────────────────────
232 std::vector<size_t> estimateOutputSizes(
233 const std::vector<size_t>& input_sizes
234 ) const override {
235 if (is_inverse_) {
236 return {dims_[0] * dims_[1] * dims_[2] * sizeof(TData)};
237 }
238 (void)input_sizes;
239 return {getRoiCount() * sizeof(TData),
240 getBgCount() * sizeof(TData),
241 peaks_.size() * sizeof(RoiPeak)};
242 }
243
244 std::unordered_map<std::string, size_t>
245 getActualOutputSizesByName() const override {
246 if (is_inverse_)
247 return {{"output", dims_[0] * dims_[1] * dims_[2] * sizeof(TData)}};
248 return {{"roi", getRoiCount() * sizeof(TData)},
249 {"bg", getBgCount() * sizeof(TData)},
250 {"peaks", peaks_.size() * sizeof(RoiPeak)}};
251 }
252
253 size_t getActualOutputSize(int index) const override {
254 if (is_inverse_) return (index == 0)
255 ? dims_[0] * dims_[1] * dims_[2] * sizeof(TData) : 0;
256 switch (index) {
257 case 0: return getRoiCount() * sizeof(TData);
258 case 1: return getBgCount() * sizeof(TData);
259 case 2: return peaks_.size() * sizeof(RoiPeak);
260 default: return 0;
261 }
262 }
263
264 std::vector<std::string> getRunNotes() const override;
265
266 // ── Serialization ───────────────────────────────────────────────────────
267 size_t serializeHeader(size_t, uint8_t* buf, size_t max_size) const override {
268 if (max_size < kHeaderSize) return 0;
269 size_t off = 0;
270 auto put32 = [&](uint32_t v) { std::memcpy(buf + off, &v, 4); off += 4; };
271 auto put16 = [&](uint16_t v) { std::memcpy(buf + off, &v, 2); off += 2; };
272 put32(static_cast<uint32_t>(dims_[0]));
273 put32(static_cast<uint32_t>(dims_[1]));
274 put32(static_cast<uint32_t>(dims_[2]));
275 put32(static_cast<uint32_t>(peaks_.size()));
276 put16(static_cast<uint16_t>(half_width_));
277 put16(static_cast<uint16_t>(bin_));
278 buf[off++] = elemType();
279 buf[off++] = 0; // reserved
280 return off;
281 }
282
283 void deserializeHeader(const uint8_t* buf, size_t size) override {
284 if (size < kHeaderSize) return;
285 size_t off = 0;
286 auto get32 = [&]() { uint32_t v; std::memcpy(&v, buf + off, 4); off += 4; return v; };
287 auto get16 = [&]() { uint16_t v; std::memcpy(&v, buf + off, 2); off += 2; return v; };
288 dims_[0] = get32(); dims_[1] = get32(); dims_[2] = get32();
289 dims_from_header_ = true;
290 const uint32_t npeaks = get32();
291 half_width_ = get16();
292 bin_ = get16();
293 // The peak *values* arrive on the `peaks` input port, not in this header;
294 // only the count is needed here so the sizes line up before execute().
295 peaks_.assign(npeaks, RoiPeak{0, 0, 0});
296 }
297
298 size_t getMaxHeaderSize(size_t) const override { return kHeaderSize; }
299
300 void saveState() override {
301 saved_dims_ = dims_; saved_hw_ = half_width_;
302 saved_bin_ = bin_; saved_npeaks_ = peaks_.size();
303 state_saved_ = true;
304 }
310 void restoreState() override {
311 if (!state_saved_) return;
312 dims_ = saved_dims_; half_width_ = saved_hw_; bin_ = saved_bin_;
313 if (peaks_.size() != saved_npeaks_) peaks_.resize(saved_npeaks_);
314 }
315
316private:
317 // 4 x uint32 (dims, npeaks) + 2 x uint16 (hw, bin) + dtype + reserved.
318 static constexpr size_t kHeaderSize = 22;
319
320 static constexpr uint8_t elemType() {
321 return static_cast<uint8_t>(sizeof(TData) == 4 ? DataType::FLOAT32
322 : DataType::FLOAT64);
323 }
324
326 void computeOverlapFraction();
327
328 bool is_inverse_ = false;
329 bool dims_from_header_ = false;
330 bool state_saved_ = false;
331 std::array<size_t, 3> dims_ = {0, 0, 1};
332 uint32_t half_width_ = 4;
333 uint32_t bin_ = 1;
334 double overlap_frac_ = 0.0;
335
336 std::vector<RoiPeak> peaks_;
337 RoiPeak* d_peaks_ = nullptr;
338
339 std::array<size_t, 3> saved_dims_ = {0, 0, 1};
340 uint32_t saved_hw_ = 4;
341 uint32_t saved_bin_ = 1;
342 size_t saved_npeaks_ = 0;
343};
344
345extern template class ROIBinSplitStage<float>;
346extern template class ROIBinSplitStage<double>;
347
348} // namespace fz
Definition mempool.h:82
Definition roibin_split_stage.h:118
size_t getActualOutputSize(int index) const override
Definition roibin_split_stage.h:253
std::vector< std::string > getOutputNames() const override
Definition roibin_split_stage.h:186
size_t serializeHeader(size_t, uint8_t *buf, size_t max_size) const override
Definition roibin_split_stage.h:267
void onFinalize(size_t estimated_inlen, MemoryPool *pool) override
void execute(fz::stream_t stream, MemoryPool *pool, const std::vector< void * > &inputs, const std::vector< void * > &outputs, const std::vector< size_t > &sizes) override
void restoreState() override
Definition roibin_split_stage.h:310
std::unordered_map< std::string, size_t > getActualOutputSizesByName() const override
Definition roibin_split_stage.h:245
void setBinFactor(uint32_t b)
Definition roibin_split_stage.h:138
void setPeaks(const std::vector< RoiPeak > &peaks)
Supply peaks directly (used by tests).
void setInverse(bool inv) override
Definition roibin_split_stage.h:175
void setDims(const std::array< size_t, 3 > &dims) override
Definition roibin_split_stage.h:154
double getRoiOverlapFraction() const
Definition roibin_split_stage.h:172
uint8_t getInputDataType(size_t input_index) const override
Definition roibin_split_stage.h:205
bool isGraphCompatible() const override
Definition roibin_split_stage.h:180
std::vector< size_t > estimateOutputSizes(const std::vector< size_t > &input_sizes) const override
Definition roibin_split_stage.h:232
size_t getMaxHeaderSize(size_t) const override
Definition roibin_split_stage.h:298
uint16_t getStageTypeId() const override
Definition roibin_split_stage.h:193
std::vector< std::string > getRunNotes() const override
std::string getName() const override
Definition roibin_split_stage.h:191
void setPeaksFile(const std::string &path)
void setRoiHalfWidth(uint32_t hw)
ROI box half-width in pixels; the box is (2*hw+1)^2. Default 4 → 9x9.
Definition roibin_split_stage.h:133
uint8_t getOutputDataType(size_t output_index) const override
Definition roibin_split_stage.h:197
size_t estimateDeviceFootprintBytes(size_t) const override
Definition roibin_split_stage.h:227
void deserializeHeader(const uint8_t *buf, size_t size) override
Definition roibin_split_stage.h:283
void saveState() override
Definition roibin_split_stage.h:300
Definition stage.h:30
FZM binary file format definitions — structs, enums, and helpers.
Definition algorithms.h:48
@ ROIBIN_SPLIT
Region-of-interest / binned-background split (ROIBIN-style dual-error-bound branching)
DataType
Element data type identifiers used in buffer and stage descriptors.
Definition fzm_format.h:118
Base class interface for all compression stages.
One Bragg-peak record, matching the on-disk .roi layout exactly (8 bytes).
Definition roibin_split_stage.h:105
uint16_t x
fast-axis pixel coordinate
Definition roibin_split_stage.h:107
uint16_t y
slow-axis pixel coordinate
Definition roibin_split_stage.h:108
uint32_t z
frame index (slowest axis)
Definition roibin_split_stage.h:106
Backend-neutral GPU type aliases.