Choose images_per_file from the acquisition when it is not given
The value means three different things at once. It is the unit of writer parallelism - whole files go round-robin to the writers, (image_number / images_per_file) % socket.size() in ZMQStream2Pusher::SendImage and TCPStreamPusher - it multiplies writer memory linearly, since every data-file plugin reserves per file, and it decides whether a legacy master is readable at all, because dxtbx follows only the first data file of one. That last point is what makes a flat default wrong. Measured with DIALS on a 2500-image rotation sweep written as legacy: split into five files it reports 2500 images and then raises IndexError beyond image 499, so it half-works silently; in one file all 2500 read. AutoPROC does not read VDS, so legacy has to stay the default, which leaves the file count as the only lever. So make it optional and resolve it from the acquisition. A rotation sweep of at most 20000 images goes into one data file - rotation datasets are small enough, and one writer keeps up with them. A grid scan splits on whole fast-axis rows, so a file is a meaningful piece of the grid. Stills and serial keep 1000, where the image count far exceeds it and the parallelism and the bounded writer memory are what matter. An explicit value is always taken literally. GetImagesPerFile is the single place this is resolved, and it must always return a fixed non-zero number, because everything downstream - receiver, pusher, puller, writer - requires one. That was already true of the old 0 = "one file" spelling; 0 is now gone from the API and omitting the field says the same thing better. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1113,19 +1113,43 @@ std::vector<uint16_t> DiffractionExperiment::ExportROIMap() const {
|
||||
return roi_mask.GetROIMap(GetDiffractionGeometry(), GetXPixelsNumConv(), GetYPixelsNumConv());
|
||||
}
|
||||
|
||||
DiffractionExperiment &DiffractionExperiment::ImagesPerFile(int64_t input) {
|
||||
DiffractionExperiment &DiffractionExperiment::ImagesPerFile(const std::optional<int64_t> &input) {
|
||||
dataset.ImagesPerFile(input);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Images per file is optional in the settings, because at setup time the acquisition it should suit
|
||||
// is not necessarily known yet. Everything downstream of here - receiver, pusher, puller, writer -
|
||||
// requires a fixed, non-zero number, so this is the one place that resolves it and it must always
|
||||
// return one.
|
||||
int64_t DiffractionExperiment::GetImagesPerFile() const {
|
||||
auto tmp = dataset.GetImagesPerFile();
|
||||
// A single self-contained file holds the whole run whatever the setting says.
|
||||
if (file_writer.GetFileFormat() == FileWriterFormat::NXmxIntegrated)
|
||||
return std::max<int64_t>(GetImageNum(), 1);
|
||||
|
||||
if (tmp == 0
|
||||
|| file_writer.GetFileFormat() == FileWriterFormat::NXmxIntegrated)
|
||||
return GetImageNum();
|
||||
else
|
||||
return tmp;
|
||||
if (const auto requested = dataset.GetImagesPerFile())
|
||||
return requested.value(); // taken literally
|
||||
|
||||
const int64_t image_num = GetImageNum();
|
||||
|
||||
// Rotation: keep the sweep in one data file. A legacy master splits over several files is read
|
||||
// by some programs as only its first one, and a rotation dataset is small enough that the file
|
||||
// is not a problem - past the limit the writer parallelism is worth more, one file going to one
|
||||
// writer (see ZMQStream2Pusher::SendImage).
|
||||
const auto goniometer = GetGoniometer();
|
||||
if (goniometer.has_value() && (goniometer->GetIncrement_deg() != 0.0f)
|
||||
&& (image_num > 0) && (image_num <= ROTATION_SINGLE_FILE_IMAGE_LIMIT))
|
||||
return image_num;
|
||||
|
||||
// Grid scan: split on whole rows of the fast axis, so a file is a meaningful piece of the grid
|
||||
// rather than an arbitrary cut across it.
|
||||
if (const auto grid_scan = GetGridScan()) {
|
||||
const int64_t n_fast = grid_scan->GetNFast();
|
||||
if (n_fast > 0)
|
||||
return ((DEFAULT_IMAGES_PER_FILE + n_fast - 1) / n_fast) * n_fast;
|
||||
}
|
||||
|
||||
return DEFAULT_IMAGES_PER_FILE; // stills, serial
|
||||
}
|
||||
|
||||
int64_t DiffractionExperiment::GetImageBufferLocationSize() const {
|
||||
|
||||
Reference in New Issue
Block a user