Build Packages / Create release (push) Successful in 16s
Build Packages / build:rugnux:aarch64 (cross) (push) Successful in 8m27s
Build Packages / build:rugnux-tgz (x86_64) (push) Successful in 9m15s
Build Packages / build:viewer-tgz:cpu (push) Successful in 10m11s
Build Packages / build:viewer-tgz:cuda (push) Successful in 12m6s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 15m44s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 16m1s
Build Packages / build:windows:nocuda (push) Successful in 17m29s
Build Packages / build:windows:cuda (push) Successful in 19m58s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 24m7s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 19m8s
Build Packages / build:rugnux:windows (push) Successful in 10m58s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 20m46s
Build Packages / Generate python client (push) Successful in 53s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 20m13s
Build Packages / Build documentation (push) Successful in 1m36s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 19m57s
Build Packages / build:rpm (rocky8) (push) Successful in 18m7s
Build Packages / build:rpm (rocky9) (push) Successful in 18m54s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 19m32s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 17m30s
Build Packages / Unit tests (push) Successful in 1h39m2s
* Fixed `jfjoch_broker` cancelling every data collection with a CUDA "out of memory" error after long operation: GPU memory no longer leaks with each collection. * Rugnux scales a rotation sweep until the per-frame scales settle instead of for a fixed three rounds, and says so when they did not - merged intensities, and the space group, resolution cut and frame rejection read off them, change accordingly; `--scaling-iterations` is now the cap on that loop (default 100). * Rugnux places every frame of a marCCD, SMV or miniCBF series at the spindle angle its own header states, so a series with missing frames, or with angles written modulo 360, is no longer read at the wrong geometry or refused. * Every rotation run writes two diagnostic files beside its reflections: `<prefix>_detector.jpg`, the detector projection with the pixel mask and the detected beam-stop shadow drawn on it, and `<prefix>_plot.txt`, one row per image. Reviewed-on: #82 Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
64 lines
2.8 KiB
C++
64 lines
2.8 KiB
C++
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#pragma once
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "JFJochReader.h"
|
|
#include "MarCCD.h"
|
|
|
|
// Reads a rotation sweep straight from a directory of marCCD files - what Rayonix MX-series and mar
|
|
// Mosaic detectors write, and what a decade of deposited CCD data is archived as - with no
|
|
// conversion step.
|
|
//
|
|
// The same shape as JFJochCBFReader: the sweep's geometry comes from the first file's header, the
|
|
// rotation angle of each image from its own, and images are decoded on demand so any number of
|
|
// workers can read at once. A raw marCCD file carries no analysis results, so there are no spots
|
|
// and no reflections here either.
|
|
//
|
|
// The one thing a CCD needs that a pixel detector does not: its pixels are unsigned 16-bit with no
|
|
// negative marker for untrusted ones, so the mask is what the header calls saturated and nothing
|
|
// else. A CCD's point spread and read-out noise are left to the analysis, which measures the
|
|
// background from the image rather than assuming a detector.
|
|
class JFJochMarCCDReader : public JFJochReader {
|
|
std::vector<std::string> files_;
|
|
std::shared_ptr<JFJochReaderDataset> dataset_;
|
|
marccd::Header header0_;
|
|
|
|
bool LoadImage_i(std::shared_ptr<JFJochReaderDataset> &dataset,
|
|
DataMessage &message,
|
|
std::vector<uint8_t> &buffer,
|
|
int64_t image_number,
|
|
bool update_dataset) override;
|
|
|
|
// Decodes one image into the caller's byte buffer and returns the image that points at it. The
|
|
// stored 16-bit strip is read through scratch, which the caller keeps between frames.
|
|
template <class Buffer>
|
|
CompressedImage DecodeInto(int64_t image_number, Buffer &buffer, std::vector<uint8_t> &scratch) const;
|
|
|
|
public:
|
|
~JFJochMarCCDReader() override = default;
|
|
|
|
// True if the path names something this reader can open: a marCCD file, or a directory holding
|
|
// at least one. Cheap - it reads a few kB at most.
|
|
static bool CanRead(const std::string &path);
|
|
|
|
// path is a directory of marCCD frames, or one frame inside the sweep to take the whole sweep
|
|
// from.
|
|
void ReadFiles(const std::string &path);
|
|
|
|
[[nodiscard]] uint64_t GetNumberOfImages() const override;
|
|
void Close() override;
|
|
|
|
|
|
// Whether the sweep really has an image at this point. A deposited series can be missing frames,
|
|
// and they are kept as gaps so that every image keeps the spindle angle its own header states;
|
|
// ReadRawImage hands such a slot back as "nothing to read".
|
|
[[nodiscard]] bool HasImage(int64_t image_number) const;
|
|
|
|
bool ReadRawImage(int64_t image_number, JFJochReaderRawImage &image) override;
|
|
[[nodiscard]] std::vector<SpotToSave> ReadSpots(int64_t image) const override;
|
|
};
|