v1.0.0-rc.127 (#34)
All checks were successful
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 10m51s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 8m0s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 9m6s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 10m7s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 9m47s
Build Packages / Generate python client (push) Successful in 29s
Build Packages / Build documentation (push) Successful in 43s
Build Packages / Create release (push) Has been skipped
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 10m46s
Build Packages / build:rpm (rocky8) (push) Successful in 9m33s
Build Packages / Unit tests (push) Has been skipped
Build Packages / build:rpm (ubuntu2204) (push) Successful in 8m47s
Build Packages / build:rpm (rocky9) (push) Successful in 9m55s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 9m4s

This is an UNSTABLE release. The release has significant modifications and bug fixes, if things go wrong, it is better to revert to 1.0.0-rc.124.

* jfjoch_broker: Default EIGER readout time is 20 microseconds
* jfjoch_broker: Multiple improvements regarding performance
* jfjoch_broker: Image buffer allows to track frames in preparation and sending
* jfjoch_broker: Dedicated thread for ZeroMQ transmission to better utilize the image buffer
* jfjoch_broker: Experimental implementation of transmission with raw TCP/IP sockets
* jfjoch_writer: Fixes regarding properly closing files in long data collections
* jfjoch_process: Scale & merge has been significantly improved, but it is not yet integrated into mainstream code

Reviewed-on: #34
This commit was merged in pull request #34.
This commit is contained in:
2026-03-02 15:57:12 +01:00
parent 32b681e591
commit f3e0a15d26
205 changed files with 2685 additions and 1046 deletions

View File

@@ -39,10 +39,10 @@ void print_usage(Logger &logger) {
logger.Info(" -F Use FFT indexing algorithm (default: Auto)");
logger.Info(" -x No least-square beam center refinement");
logger.Info(" -d<num> High resolution limit for spot finding (default: 1.5)");
logger.Info(" -D<num> High resolution limit for scaling/merging (default: 0.0; no limit)");
logger.Info(" -S<num> Space group number");
logger.Info(" -M Scale and merge (refine mosaicity) and write scaled.hkl + image.dat");
logger.Info(" -L Use log-scaling residual");
logger.Info(" -m<txt> Mosaicity refinement none|fixed|image (default: image)");
logger.Info(" -P<txt> Partiality refinement fixed|rot|unity (default: fixed)");
logger.Info(" -A Anomalous mode (don't merge Friedel pairs)");
}
@@ -67,11 +67,10 @@ int main(int argc, char **argv) {
bool anomalous_mode = false;
std::optional<int> space_group_number;
bool log_residual = false;
enum class MosaicityRefinementMode { None, Fixed, Image };
MosaicityRefinementMode mosaicity_refinement_mode = MosaicityRefinementMode::Image;
ScaleMergeOptions::PartialityModel partiality_model = ScaleMergeOptions::PartialityModel::Fixed;
float d_high = 1.5;
float d_min_spot_finding = 1.5;
std::optional<float> d_min_scale_merge;
if (argc == 1) {
print_usage(logger);
@@ -79,7 +78,7 @@ int main(int argc, char **argv) {
}
int opt;
while ((opt = getopt(argc, argv, "o:N:s:e:vR::Fxd:S:MLm:A")) != -1) {
while ((opt = getopt(argc, argv, "o:N:s:e:vR::Fxd:S:MP:AD:")) != -1) {
switch (opt) {
case 'o':
output_prefix = optarg;
@@ -96,6 +95,9 @@ int main(int argc, char **argv) {
case 'v':
verbose = true;
break;
case 'd':
d_min_spot_finding = atof(optarg);
break;
case 'R':
rotation_indexing = true;
if (optarg) rotation_indexing_range = atof(optarg);
@@ -106,8 +108,9 @@ int main(int argc, char **argv) {
case 'x':
refine_beam_center = false;
break;
case 'd':
d_high = atof(optarg);
case 'D':
d_min_scale_merge = atof(optarg);
logger.Info("High resolution limit for scaling/merging set to {:.2f} A", d_min_spot_finding);
break;
case 'S':
space_group_number = atoi(optarg);
@@ -115,21 +118,20 @@ int main(int argc, char **argv) {
case 'M':
run_scaling = true;
break;
case 'L':
log_residual = true;
break;
case 'A':
anomalous_mode = true;
break;
case 'm':
if (strcmp(optarg, "none") == 0)
mosaicity_refinement_mode = MosaicityRefinementMode::None;
case 'P':
if (strcmp(optarg, "unity") == 0)
partiality_model = ScaleMergeOptions::PartialityModel::Unity;
else if (strcmp(optarg, "fixed") == 0)
mosaicity_refinement_mode = MosaicityRefinementMode::Fixed;
else if (strcmp(optarg, "image") == 0)
mosaicity_refinement_mode = MosaicityRefinementMode::Image;
partiality_model = ScaleMergeOptions::PartialityModel::Fixed;
else if (strcmp(optarg, "rot") == 0)
partiality_model = ScaleMergeOptions::PartialityModel::Rotation;
else if (strcmp(optarg, "still") == 0)
partiality_model = ScaleMergeOptions::PartialityModel::Still;
else {
logger.Error("Invalid mosaicity refinement mode: {}", optarg);
logger.Error("Invalid partiality mode: {}", optarg);
print_usage(logger);
exit(EXIT_FAILURE);
}
@@ -206,7 +208,9 @@ int main(int argc, char **argv) {
SpotFindingSettings spot_settings;
spot_settings.enable = true;
spot_settings.indexing = true;
spot_settings.high_resolution_limit = d_high;
spot_settings.high_resolution_limit = d_min_spot_finding;
if (d_min_scale_merge > 0)
spot_settings.high_resolution_limit = d_min_spot_finding;
// Initialize Analysis Components
PixelMask pixel_mask = dataset->pixel_mask;
@@ -420,25 +424,12 @@ int main(int argc, char **argv) {
logger.Info("Running scaling (mosaicity refinement) ...");
ScaleMergeOptions scale_opts;
scale_opts.refine_mosaicity = true;
scale_opts.partiality_model = partiality_model;
scale_opts.max_num_iterations = 500;
scale_opts.max_solver_time_s = 240.0; // generous cutoff for now
scale_opts.log_scaling_residual = log_residual;
scale_opts.merge_friedel = !anomalous_mode;
scale_opts.d_min_limit_A = d_min_scale_merge.value_or(0.0);
switch (mosaicity_refinement_mode) {
case MosaicityRefinementMode::None:
scale_opts.refine_mosaicity = false;
break;
case MosaicityRefinementMode::Fixed:
scale_opts.refine_mosaicity = true;
scale_opts.per_image_mosaicity = false;
break;
case MosaicityRefinementMode::Image:
scale_opts.refine_mosaicity = true;
scale_opts.per_image_mosaicity = true;
break;
}
if (space_group)
scale_opts.space_group = *space_group;
else
@@ -450,12 +441,10 @@ int main(int argc, char **argv) {
double scale_time = std::chrono::duration<double>(scale_end - scale_start).count();
if (scale_result) {
end_msg.scale_factor = scale_result->image_scale_g;
// ... existing code ...
logger.Info("Scaling completed in {:.2f} s ({} unique reflections, {} images)",
scale_time,
scale_result->merged.size(),
scale_result->image_ids.size());
logger.Info("Scaling completed in {:.2f} s ({} unique reflections)",
scale_time, scale_result->merged.size());
// Print resolution-shell statistics table
{
@@ -498,13 +487,10 @@ int main(int argc, char **argv) {
logger.Error("Cannot open {} for writing", img_path);
} else {
img_file << "# image_id mosaicity_deg K\n";
for (size_t i = 0; i < scale_result->image_ids.size(); ++i) {
img_file << scale_result->image_ids[i] << " "
<< scale_result->mosaicity_deg[i] << " "
<< scale_result->image_scale_g[i] << "\n";
for (size_t i = 0; i < scale_result->mosaicity_deg.size(); ++i) {
img_file << i << " " << scale_result->mosaicity_deg[i] << " " << scale_result->image_scale_g[i] << "\n";
}
img_file.close();
logger.Info("Wrote {} image records to {}", scale_result->image_ids.size(), img_path);
}
}