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
97#include "stage/stage.h"
98#include "fzm_format.h"
99#include "backend/types.h"
100#include <array>
101#include <cstdint>
102#include <cstring>
103#include <stdexcept>
104#include <string>
105#include <unordered_map>
106#include <vector>
107
108namespace fz {
109
111struct RoiPeak {
112 uint32_t z;
113 uint16_t x;
114 uint16_t y;
115};
116static_assert(sizeof(RoiPeak) == 8, "RoiPeak must be 8 bytes to match the .roi format");
117
123template <typename TData>
124class ROIBinSplitStage : public Stage {
125public:
126 ROIBinSplitStage() = default;
127 ~ROIBinSplitStage() override = default;
128
129 // ── Configuration ───────────────────────────────────────────────────────
130
133 void setPeaksFile(const std::string& path);
134
136 void setPeaks(const std::vector<RoiPeak>& peaks);
137
139 void setRoiHalfWidth(uint32_t hw) { half_width_ = hw; }
140 uint32_t getRoiHalfWidth() const { return half_width_; }
141
144 void setBinFactor(uint32_t b) {
145 if (b == 0) throw std::runtime_error("ROIBinSplit: bin_factor must be >= 1");
146 bin_ = b;
147 }
148 uint32_t getBinFactor() const { return bin_; }
149
160 void setDims(const std::array<size_t, 3>& dims) override {
161 if (dims_from_header_ || dims[0] == 0) return;
162 dims_ = dims;
163 }
164 void setDims(size_t x, size_t y = 1, size_t z = 1) {
165 setDims(std::array<size_t, 3>{x, y, z});
166 }
167
168 size_t getNumPeaks() const { return peaks_.size(); }
169 size_t getBoxArea() const { return size_t(2 * half_width_ + 1) * (2 * half_width_ + 1); }
170 size_t getBgNx() const { return (dims_[0] + bin_ - 1) / bin_; }
171 size_t getBgNy() const { return (dims_[1] + bin_ - 1) / bin_; }
172 size_t getBgCount() const { return getBgNx() * getBgNy() * dims_[2]; }
173 size_t getRoiCount() const { return peaks_.size() * getBoxArea(); }
174
178 double getRoiOverlapFraction() const { return overlap_frac_; }
179
180 // ── Stage control ───────────────────────────────────────────────────────
181 void setInverse(bool inv) override { is_inverse_ = inv; }
182 bool isInverse() const override { return is_inverse_; }
183
186 bool isGraphCompatible() const override { return true; }
187
188 // ── Port model ──────────────────────────────────────────────────────────
189 size_t getNumInputs() const override { return is_inverse_ ? 3 : 1; }
190 size_t getNumOutputs() const override { return is_inverse_ ? 1 : 3; }
191
192 std::vector<std::string> getOutputNames() const override {
193 return is_inverse_ ? std::vector<std::string>{"output"}
194 : std::vector<std::string>{"roi", "bg", "peaks"};
195 }
196
197 std::string getName() const override { return "ROIBinSplit"; }
198
199 uint16_t getStageTypeId() const override {
200 return static_cast<uint16_t>(StageType::ROIBIN_SPLIT);
201 }
202
203 uint8_t getOutputDataType(size_t output_index) const override {
204 if (is_inverse_) return elemType();
205 switch (output_index) {
206 case 0: return elemType(); // roi
207 case 1: return elemType(); // bg
208 default: return static_cast<uint8_t>(DataType::UINT8); // peaks
209 }
210 }
211 uint8_t getInputDataType(size_t input_index) const override {
212 if (!is_inverse_) return elemType();
213 switch (input_index) {
214 case 0: return elemType();
215 case 1: return elemType();
216 default: return static_cast<uint8_t>(DataType::UINT8);
217 }
218 }
219
220 // ── Execution ───────────────────────────────────────────────────────────
222 fz::stream_t stream,
223 MemoryPool* pool,
224 const std::vector<void*>& inputs,
225 const std::vector<void*>& outputs,
226 const std::vector<size_t>& sizes
227 ) override;
228
231 void onFinalize(size_t estimated_inlen, MemoryPool* pool) override;
232
233 size_t estimateDeviceFootprintBytes(size_t /*inlen*/) const override {
234 return peaks_.size() * sizeof(RoiPeak);
235 }
236
237 // ── Size estimation ─────────────────────────────────────────────────────
238 std::vector<size_t> estimateOutputSizes(
239 const std::vector<size_t>& input_sizes
240 ) const override {
241 if (is_inverse_) {
242 return {dims_[0] * dims_[1] * dims_[2] * sizeof(TData)};
243 }
244 (void)input_sizes;
245 return {getRoiCount() * sizeof(TData),
246 getBgCount() * sizeof(TData),
247 peaks_.size() * sizeof(RoiPeak)};
248 }
249
250 std::unordered_map<std::string, size_t>
251 getActualOutputSizesByName() const override {
252 if (is_inverse_)
253 return {{"output", dims_[0] * dims_[1] * dims_[2] * sizeof(TData)}};
254 return {{"roi", getRoiCount() * sizeof(TData)},
255 {"bg", getBgCount() * sizeof(TData)},
256 {"peaks", peaks_.size() * sizeof(RoiPeak)}};
257 }
258
259 size_t getActualOutputSize(int index) const override {
260 if (is_inverse_) return (index == 0)
261 ? dims_[0] * dims_[1] * dims_[2] * sizeof(TData) : 0;
262 switch (index) {
263 case 0: return getRoiCount() * sizeof(TData);
264 case 1: return getBgCount() * sizeof(TData);
265 case 2: return peaks_.size() * sizeof(RoiPeak);
266 default: return 0;
267 }
268 }
269
270 std::vector<std::string> getRunNotes() const override;
271
272 // ── Serialization ───────────────────────────────────────────────────────
273 size_t serializeHeader(size_t, uint8_t* buf, size_t max_size) const override {
274 if (max_size < kHeaderSize) return 0;
275 size_t off = 0;
276 auto put32 = [&](uint32_t v) { std::memcpy(buf + off, &v, 4); off += 4; };
277 auto put16 = [&](uint16_t v) { std::memcpy(buf + off, &v, 2); off += 2; };
278 put32(static_cast<uint32_t>(dims_[0]));
279 put32(static_cast<uint32_t>(dims_[1]));
280 put32(static_cast<uint32_t>(dims_[2]));
281 put32(static_cast<uint32_t>(peaks_.size()));
282 put16(static_cast<uint16_t>(half_width_));
283 put16(static_cast<uint16_t>(bin_));
284 buf[off++] = elemType();
285 buf[off++] = 0; // reserved
286 return off;
287 }
288
289 void deserializeHeader(const uint8_t* buf, size_t size) override {
290 if (size < kHeaderSize) return;
291 size_t off = 0;
292 auto get32 = [&]() { uint32_t v; std::memcpy(&v, buf + off, 4); off += 4; return v; };
293 auto get16 = [&]() { uint16_t v; std::memcpy(&v, buf + off, 2); off += 2; return v; };
294 dims_[0] = get32(); dims_[1] = get32(); dims_[2] = get32();
295 dims_from_header_ = true;
296 const uint32_t npeaks = get32();
297 half_width_ = get16();
298 bin_ = get16();
299 // The peak *values* arrive on the `peaks` input port, not in this header;
300 // only the count is needed here so the sizes line up before execute().
301 peaks_.assign(npeaks, RoiPeak{0, 0, 0});
302 }
303
304 size_t getMaxHeaderSize(size_t) const override { return kHeaderSize; }
305
306 void saveState() override {
307 saved_dims_ = dims_; saved_hw_ = half_width_;
308 saved_bin_ = bin_; saved_npeaks_ = peaks_.size();
309 state_saved_ = true;
310 }
316 void restoreState() override {
317 if (!state_saved_) return;
318 dims_ = saved_dims_; half_width_ = saved_hw_; bin_ = saved_bin_;
319 if (peaks_.size() != saved_npeaks_) peaks_.resize(saved_npeaks_);
320 }
321
322private:
323 // 4 x uint32 (dims, npeaks) + 2 x uint16 (hw, bin) + dtype + reserved.
324 static constexpr size_t kHeaderSize = 22;
325
326 static constexpr uint8_t elemType() {
327 return static_cast<uint8_t>(sizeof(TData) == 4 ? DataType::FLOAT32
328 : DataType::FLOAT64);
329 }
330
332 void computeOverlapFraction();
333
334 bool is_inverse_ = false;
335 bool dims_from_header_ = false;
336 bool state_saved_ = false;
337 std::array<size_t, 3> dims_ = {0, 0, 1};
338 uint32_t half_width_ = 4;
339 uint32_t bin_ = 1;
340 double overlap_frac_ = 0.0;
341
342 std::vector<RoiPeak> peaks_;
343 RoiPeak* d_peaks_ = nullptr;
344
345 std::array<size_t, 3> saved_dims_ = {0, 0, 1};
346 uint32_t saved_hw_ = 4;
347 uint32_t saved_bin_ = 1;
348 size_t saved_npeaks_ = 0;
349};
350
351extern template class ROIBinSplitStage<float>;
352extern template class ROIBinSplitStage<double>;
353
354} // namespace fz
Definition mempool.h:82
Definition roibin_split_stage.h:124
size_t getActualOutputSize(int index) const override
Definition roibin_split_stage.h:259
std::vector< std::string > getOutputNames() const override
Definition roibin_split_stage.h:192
size_t serializeHeader(size_t, uint8_t *buf, size_t max_size) const override
Definition roibin_split_stage.h:273
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:316
std::unordered_map< std::string, size_t > getActualOutputSizesByName() const override
Definition roibin_split_stage.h:251
void setBinFactor(uint32_t b)
Definition roibin_split_stage.h:144
void setPeaks(const std::vector< RoiPeak > &peaks)
Supply peaks directly (used by tests).
void setInverse(bool inv) override
Definition roibin_split_stage.h:181
void setDims(const std::array< size_t, 3 > &dims) override
Definition roibin_split_stage.h:160
double getRoiOverlapFraction() const
Definition roibin_split_stage.h:178
uint8_t getInputDataType(size_t input_index) const override
Definition roibin_split_stage.h:211
bool isGraphCompatible() const override
Definition roibin_split_stage.h:186
std::vector< size_t > estimateOutputSizes(const std::vector< size_t > &input_sizes) const override
Definition roibin_split_stage.h:238
size_t getMaxHeaderSize(size_t) const override
Definition roibin_split_stage.h:304
uint16_t getStageTypeId() const override
Definition roibin_split_stage.h:199
std::vector< std::string > getRunNotes() const override
std::string getName() const override
Definition roibin_split_stage.h:197
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:139
uint8_t getOutputDataType(size_t output_index) const override
Definition roibin_split_stage.h:203
size_t estimateDeviceFootprintBytes(size_t) const override
Definition roibin_split_stage.h:233
void deserializeHeader(const uint8_t *buf, size_t size) override
Definition roibin_split_stage.h:289
void saveState() override
Definition roibin_split_stage.h:306
Definition stage.h:31
FZM binary file format definitions — structs, enums, and helpers.
Definition dag.h:24
@ 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:139
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:111
uint16_t x
fast-axis pixel coordinate
Definition roibin_split_stage.h:113
uint16_t y
slow-axis pixel coordinate
Definition roibin_split_stage.h:114
uint32_t z
frame index (slowest axis)
Definition roibin_split_stage.h:112
Backend-neutral GPU type aliases.