38ea0ec237
On the LysozymeJet5 serial stills the default Gaussian profile-fit integrator (ProfileIntegrate2D) + reference scaling matched or beat whole-PixelRefine on every per-shell CC1/2 (overall 95.7% vs 91.9%), ISa (1.6 vs 1.2) and R-meas (98.5% vs 175%), with CCref a tie -- so PixelRefine has no remaining advantage. Reference-based per-image scaling is integrator-agnostic (IndexAndRefine::ReferenceIntensities builds a ScaleOnTheFly(experiment, reference) applied to any integrator's output), so the reference-dataset feature (CCref + reference scaling) is kept. Delete image_analysis/pixel_refinement/, GeomRefinementAlgorithmEnum:: PixelRefine and its gates, BraggIntegrationSettings::ProfileMultiplier (PixelRefine-only; R1 is shared and kept), and the -r pixelrefine / --profile-multiplier CLI. The inherited lessons (mean background, de-biased variance, tight-profile-loses / centroid floor, R-refinement futile) are folded into NEXTGEN_INTEGRATOR.md. NOTE: this transiently breaks the viewer build -- the committed viewer still references the removed enum and ProfileMultiplier. It is fixed in the next commit (the viewer feature work), held separate while the viewer UI is being tested. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
138 lines
5.1 KiB
C++
138 lines
5.1 KiB
C++
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include "JFJochProcessCommandLine.h"
|
|
#include "../common/DiffractionExperiment.h"
|
|
|
|
#include <sstream>
|
|
#include <vector>
|
|
|
|
namespace {
|
|
std::string quote_if_needed(const std::string &s) {
|
|
if (s.find_first_of(" \t\"'") == std::string::npos)
|
|
return s;
|
|
std::string out = "\"";
|
|
for (char c: s) {
|
|
if (c == '"' || c == '\\')
|
|
out += '\\';
|
|
out += c;
|
|
}
|
|
out += '"';
|
|
return out;
|
|
}
|
|
|
|
const char *indexing_alg_flag(IndexingAlgorithmEnum a) {
|
|
switch (a) {
|
|
case IndexingAlgorithmEnum::FFBIDX: return "ffbidx";
|
|
case IndexingAlgorithmEnum::FFT: return "fft";
|
|
case IndexingAlgorithmEnum::FFTW: return "fftw";
|
|
case IndexingAlgorithmEnum::None: return "none";
|
|
case IndexingAlgorithmEnum::Auto:
|
|
default: return "auto";
|
|
}
|
|
}
|
|
|
|
const char *refine_flag(GeomRefinementAlgorithmEnum r) {
|
|
switch (r) {
|
|
case GeomRefinementAlgorithmEnum::None: return "none";
|
|
case GeomRefinementAlgorithmEnum::OrientationOnly: return "orientation";
|
|
case GeomRefinementAlgorithmEnum::BeamCenter:
|
|
default: return "beam_and_lattice";
|
|
}
|
|
}
|
|
|
|
std::string num(double v) {
|
|
std::ostringstream o;
|
|
o << v;
|
|
return o.str();
|
|
}
|
|
}
|
|
|
|
std::string JFJochProcessCommandLine(const ProcessConfig &config,
|
|
const DiffractionExperiment &experiment,
|
|
const std::string &input_file) {
|
|
std::vector<std::string> args;
|
|
const bool azint = (config.mode == ProcessMode::AzimuthalIntegration);
|
|
args.emplace_back(azint ? "jfjoch_azint" : "jfjoch_process");
|
|
|
|
auto add = [&](const std::string &flag, const std::string &val) {
|
|
args.push_back(flag);
|
|
args.push_back(val);
|
|
};
|
|
|
|
if (!config.output_prefix.empty())
|
|
add("-o", config.output_prefix);
|
|
add("-N", std::to_string(config.nthreads));
|
|
if (config.start_image != 0)
|
|
add("-s", std::to_string(config.start_image));
|
|
if (config.end_image >= 0)
|
|
add("-e", std::to_string(config.end_image));
|
|
if (config.stride != 1)
|
|
add("-t", std::to_string(config.stride));
|
|
|
|
if (azint) {
|
|
const auto a = experiment.GetAzimuthalIntegrationSettings();
|
|
add("--min-q", num(a.GetLowQ_recipA()));
|
|
add("--max-q", num(a.GetHighQ_recipA()));
|
|
add("--q-spacing", num(a.GetQSpacing_recipA()));
|
|
add("--azimuthal-bins", std::to_string(a.GetAzimuthalBinCount()));
|
|
add("--polarization-correction", a.IsPolarizationCorrection() ? "on" : "off");
|
|
add("--solid-angle-correction", a.IsSolidAngleCorrection() ? "on" : "off");
|
|
} else {
|
|
const auto &sf = config.spot_finding;
|
|
add("--spot-sigma", num(sf.signal_to_noise_threshold));
|
|
add("--spot-threshold", std::to_string(sf.photon_count_threshold));
|
|
add("--spot-high-resolution", num(sf.high_resolution_limit));
|
|
add("--max-spots", std::to_string(experiment.GetMaxSpotCount()));
|
|
|
|
const auto idx = experiment.GetIndexingSettings();
|
|
add("-X", indexing_alg_flag(idx.GetAlgorithm()));
|
|
add("-r", refine_flag(idx.GetGeomRefinementAlgorithm()));
|
|
|
|
if (const auto sg = experiment.GetSpaceGroupNumber())
|
|
add("-S", std::to_string(*sg));
|
|
if (const auto uc = experiment.GetUnitCell()) {
|
|
std::ostringstream o;
|
|
o << uc->a << "," << uc->b << "," << uc->c << "," << uc->alpha << "," << uc->beta << "," << uc->gamma;
|
|
add("-C", o.str());
|
|
}
|
|
if (const auto bw = experiment.GetBandwidthFWHM())
|
|
add("--bandwidth", num(*bw));
|
|
|
|
const auto bragg = experiment.GetBraggIntegrationSettings();
|
|
std::ostringstream radii;
|
|
radii << bragg.GetR1() << "," << bragg.GetR2() << "," << bragg.GetR3();
|
|
add("--integration-radius", radii.str());
|
|
|
|
if (config.rotation_indexing) {
|
|
if (config.two_pass_rotation)
|
|
add("-R", std::to_string(config.rotation_indexing_image_count));
|
|
else
|
|
args.emplace_back("--single-pass-rotation");
|
|
if (!config.reuse_rotation_spots)
|
|
args.emplace_back("--redo-rotation-spots");
|
|
}
|
|
|
|
if (config.run_scaling) {
|
|
args.emplace_back("-M");
|
|
const auto sc = experiment.GetScalingSettings();
|
|
if (const auto pm = sc.GetPartialityModel())
|
|
add("-P", *pm == PartialityModel::Unity ? "unity" : *pm == PartialityModel::Rotation ? "rot" : "fixed");
|
|
if (!sc.GetMergeFriedel())
|
|
args.emplace_back("-A");
|
|
if (sc.GetRefineB())
|
|
args.emplace_back("-B");
|
|
}
|
|
}
|
|
|
|
args.push_back(input_file);
|
|
|
|
std::ostringstream cmd;
|
|
for (size_t i = 0; i < args.size(); i++) {
|
|
if (i)
|
|
cmd << ' ';
|
|
cmd << quote_if_needed(args[i]);
|
|
}
|
|
return cmd.str();
|
|
}
|