Replace the dead PartialityModel with a force_still_processing flag
With ScaleOnTheFly now fixed-only and rotation routed through RotationScaleMerge, the PartialityModel enum carried no information (it was always Rotation for rotation processing, Fixed otherwise, and mirrored combine_3d). Drop it: - ScalingSettings: `partiality_mode` (PartialityModel) -> `force_still_processing` (bool); SetPartialityModel/GetPartialityModel -> ForceStillProcessing/GetForceStillProcessing. Remove the enum. - DiffractionExperiment: drop GetPartialityModel(); the rotation-vs-stills decision is now just GetCombine3D() (set by the tool = rotation && !force_still). The wedge getters no longer key off the model (dead since wedge refinement was removed). - jfjoch_process: `-P/--partiality fixed|rot3d` -> `--force-still-processing` (a rotation dataset scaled as independent stills). Auto-detect sets combine_3d for rotation data unless the flag is given. - jfjoch_scale: `-P fixed|rot3d` now toggles combine_3d directly (no PartialityModel). - jfjoch_viewer: the "process as stills" toggle sets ForceStillProcessing(!rotation_mode) - UI unchanged, just wired to the new field. PartialityModel was never in the OpenAPI, so no generated clients change. Rotation path behaviour is unchanged (lyso 16.4/99.6%/87.3%); --force-still-processing correctly routes to ScaleOnTheFly. CUDA + non-CUDA + viewer all build. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1696,30 +1696,10 @@ DiffractionExperiment &DiffractionExperiment::RunNumber(uint64_t input) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
PartialityModel DiffractionExperiment::GetPartialityModel() const {
|
||||
if (const auto model = scaling_settings.GetPartialityModel())
|
||||
return model.value();
|
||||
if (GetGoniometer().has_value())
|
||||
return PartialityModel::Rotation;
|
||||
return PartialityModel::Unity;
|
||||
}
|
||||
|
||||
std::optional<double> DiffractionExperiment::GetRotationWedgeForScaling() const {
|
||||
// Only makes sense for rotation partiality model
|
||||
// If ScalingSettings set one, it is takes priority
|
||||
// otherwise if this is really rotation scan, than actual rotation wedge is given
|
||||
// otherwise return std::nullopt
|
||||
if (GetPartialityModel() != PartialityModel::Rotation)
|
||||
return std::nullopt;
|
||||
if (scaling_settings.GetRotationWedgeForScaling().has_value())
|
||||
return scaling_settings.GetRotationWedgeForScaling();
|
||||
if (GetGoniometer().has_value())
|
||||
return GetGoniometer()->GetWedge_deg();
|
||||
return std::nullopt;
|
||||
return scaling_settings.GetRotationWedgeForScaling();
|
||||
}
|
||||
|
||||
bool DiffractionExperiment::GetRefineRotationWedgeInScaling() const {
|
||||
if (GetRotationWedgeForScaling().has_value())
|
||||
return scaling_settings.GetRefineWedge();
|
||||
return false;
|
||||
return scaling_settings.GetRotationWedgeForScaling().has_value() && scaling_settings.GetRefineWedge();
|
||||
}
|
||||
|
||||
@@ -417,7 +417,6 @@ public:
|
||||
|
||||
bool IsRotationIndexing() const;
|
||||
|
||||
PartialityModel GetPartialityModel() const;
|
||||
std::optional<double> GetRotationWedgeForScaling() const;
|
||||
bool GetRefineRotationWedgeInScaling() const;
|
||||
};
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
#include "ScalingSettings.h"
|
||||
|
||||
|
||||
ScalingSettings& ScalingSettings::SetPartialityModel(PartialityModel mode) {
|
||||
partiality_mode = mode;
|
||||
ScalingSettings& ScalingSettings::ForceStillProcessing(bool input) {
|
||||
force_still_processing = input;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -51,8 +51,8 @@ bool ScalingSettings::GetRefineWedge() const {
|
||||
return refine_wedge;
|
||||
}
|
||||
|
||||
std::optional<PartialityModel> ScalingSettings::GetPartialityModel() const {
|
||||
return partiality_mode;
|
||||
bool ScalingSettings::GetForceStillProcessing() const {
|
||||
return force_still_processing;
|
||||
}
|
||||
|
||||
std::optional<double> ScalingSettings::GetHighResolutionLimit_A() const {
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
#include <optional>
|
||||
#include "JFJochException.h"
|
||||
|
||||
enum class PartialityModel { Fixed, Rotation, Unity };
|
||||
enum class IntensityFormat { Text, mmCIF, MTZ};
|
||||
|
||||
class ScalingSettings {
|
||||
std::optional<PartialityModel> partiality_mode;
|
||||
// Force per-image stills scaling (ScaleOnTheFly, fixed partiality) even for a rotation dataset,
|
||||
// instead of the rotation self-scale + 3D combine + merge (RotationScaleMerge). Off by default.
|
||||
bool force_still_processing = false;
|
||||
|
||||
bool refine_b = false;
|
||||
double max_b = 200.0;
|
||||
@@ -30,9 +31,9 @@ class ScalingSettings {
|
||||
double min_cc_for_image = 0.0;
|
||||
double outlier_reject_nsigma = 0.0; // per-observation merge outlier rejection (XDS/DIALS-style); 0 = off, e.g. 6 enables
|
||||
|
||||
// The "-P rot3d" 3D combine: scale per-frame as Rotation, then weight-sum each reflection's
|
||||
// per-frame partials into one counting-limited full before merging (orthogonal to the partiality
|
||||
// model, which stays Rotation - see Combine3D).
|
||||
// Rotation processing (RotationScaleMerge): recompute partiality, weight-sum each reflection's
|
||||
// per-frame partials into one counting-limited full, scale the fulls and merge. Set by the tool for
|
||||
// rotation data unless force_still_processing.
|
||||
bool combine_3d = false;
|
||||
|
||||
// Scale fulls: after the rot3d combine, refit a per-frame scale on the combined fulls (XDS
|
||||
@@ -55,7 +56,7 @@ class ScalingSettings {
|
||||
|
||||
bool scaling_regularize = false;
|
||||
public:
|
||||
ScalingSettings& SetPartialityModel(PartialityModel mode);
|
||||
ScalingSettings& ForceStillProcessing(bool input);
|
||||
ScalingSettings& RefineB(bool input);
|
||||
ScalingSettings& RefineRotationWedge(bool input);
|
||||
ScalingSettings& RotationWedgeForScaling(std::optional<double> input);
|
||||
@@ -92,7 +93,7 @@ public:
|
||||
|
||||
[[nodiscard]] bool GetMergeFriedel() const;
|
||||
|
||||
[[nodiscard]] std::optional<PartialityModel> GetPartialityModel() const;
|
||||
[[nodiscard]] bool GetForceStillProcessing() const;
|
||||
[[nodiscard]] std::optional<double> GetHighResolutionLimit_A() const;
|
||||
|
||||
[[nodiscard]] double GetMinPartiality() const;
|
||||
|
||||
@@ -440,8 +440,7 @@ ProcessResult JFJochProcess::Run(JFJochProcessObserver *observer) {
|
||||
// (forced) mosaicity is handled by the recompute. It does NOT support external-reference scaling,
|
||||
// B-factor refinement, an absorption surface, or wedge refinement - reject those combinations.
|
||||
const auto &rot_ss = experiment_.GetScalingSettings();
|
||||
const bool is_rotation = rot_ss.GetCombine3D()
|
||||
&& experiment_.GetPartialityModel() == PartialityModel::Rotation;
|
||||
const bool is_rotation = rot_ss.GetCombine3D(); // set for rotation data unless force-still
|
||||
std::optional<RotationScaleMerge> rsm;
|
||||
if (is_rotation) {
|
||||
if (!config_.reference_data.empty() || rot_ss.GetRefineB() || rot_ss.GetAbsorptionIter() > 0
|
||||
|
||||
@@ -116,8 +116,8 @@ std::string JFJochProcessCommandLine(const ProcessConfig &config,
|
||||
if (config.run_scaling) {
|
||||
args.emplace_back("-M");
|
||||
const auto sc = experiment.GetScalingSettings();
|
||||
if (const auto pm = sc.GetPartialityModel())
|
||||
add("-P", *pm == PartialityModel::Rotation ? "rot3d" : "fixed");
|
||||
if (sc.GetForceStillProcessing())
|
||||
args.emplace_back("--force-still-processing");
|
||||
if (!sc.GetMergeFriedel())
|
||||
args.emplace_back("-A");
|
||||
if (sc.GetRefineB())
|
||||
|
||||
+12
-25
@@ -63,7 +63,7 @@ void print_usage() {
|
||||
std::cout << " --no-scale-fulls Disable the rot3d scale-fulls refit (it is on by default for rot3d)" << std::endl;
|
||||
std::cout << " --write-process-h5 Also write the (large) _process.h5 when merging (default: only .mtz/.cif when merging)" << std::endl;
|
||||
std::cout << " --smooth-g[=deg] rot3d: smooth per-frame scale G over a deg-degree rotation range (XDS DELPHI-like) before the combine (default: 5 for rot3d; 0 = off)" << std::endl;
|
||||
std::cout << " -P, --partiality <txt> Scaling/merge model fixed|rot3d (default: rot3d for rotation data, fixed for stills). rot3d = RotationScaleMerge (recompute partiality, 3D combine, scale-fulls, merge); fixed = per-image ScaleOnTheFly with the stored partiality" << std::endl;
|
||||
std::cout << " --force-still-processing Scale a rotation dataset as independent stills (per-image ScaleOnTheFly, fixed partiality) instead of the default RotationScaleMerge (recompute partiality, 3D combine, scale-fulls, merge)" << std::endl;
|
||||
std::cout << " -A, --anomalous Anomalous mode (don't merge Friedel pairs)" << std::endl;
|
||||
std::cout << " -B, --refine-bfactor Refine per image B-factor" << std::endl;
|
||||
std::cout << " --scaling-high-resolution <num> High resolution limit for spot finding (default: no limit)" << std::endl;
|
||||
@@ -117,6 +117,7 @@ enum {
|
||||
OPT_NO_SCALE_FULLS,
|
||||
OPT_WRITE_PROCESS_H5,
|
||||
OPT_PROCESS_AS_STILLS,
|
||||
OPT_FORCE_STILL_PROCESSING,
|
||||
OPT_AZIM_MIN_Q,
|
||||
OPT_AZIM_MAX_Q,
|
||||
OPT_AZIM_PHI_BINS
|
||||
@@ -135,7 +136,7 @@ static option long_options[] = {
|
||||
{"reference-column", required_argument, nullptr, OPT_REFERENCE_COLUMN},
|
||||
{"dump-observations", required_argument, nullptr, OPT_DUMP_OBSERVATIONS},
|
||||
{"space-group", required_argument, nullptr, 'S'},
|
||||
{"partiality", required_argument, nullptr, 'P'},
|
||||
{"force-still-processing", no_argument, nullptr, OPT_FORCE_STILL_PROCESSING},
|
||||
{"anomalous", no_argument, nullptr, 'A'},
|
||||
{"refine-bfactor", no_argument, nullptr, 'B'},
|
||||
{"scale-merge", no_argument, nullptr, 'M'},
|
||||
@@ -339,8 +340,7 @@ int main(int argc, char **argv) {
|
||||
GeomRefinementAlgorithmEnum refinement_algorithm = GeomRefinementAlgorithmEnum::BeamCenter;
|
||||
|
||||
std::optional<IntensityFormat> intensity_format; // --scaling-output override; default lives in ScalingSettings (mmCIF)
|
||||
PartialityModel partiality_model = PartialityModel::Fixed;
|
||||
bool partiality_explicit = false; // true once -P is given, so the rotation/stills default does not override it
|
||||
bool force_still_processing = false; // --force-still-processing: scale a rotation dataset as stills
|
||||
bool combine_3d = false; // -P rot3d: weight-sum per-frame partials into fulls before merging
|
||||
|
||||
float d_min_spot_finding = 1.5;
|
||||
@@ -357,7 +357,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
int opt;
|
||||
int option_index = 0;
|
||||
const char *short_opts = "vo:N:s:e:t:R::X:C:z:FABS:MP:r:q:";
|
||||
const char *short_opts = "vo:N:s:e:t:R::X:C:z:FABS:Mr:q:";
|
||||
|
||||
while ((opt = getopt_long(argc, argv, short_opts, long_options, &option_index)) != -1) {
|
||||
switch (opt) {
|
||||
@@ -501,19 +501,8 @@ int main(int argc, char **argv) {
|
||||
case 'S':
|
||||
space_group_number = atoi(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
if (strcmp(optarg, "fixed") == 0)
|
||||
partiality_model = PartialityModel::Fixed;
|
||||
else if (strcmp(optarg, "rot3d") == 0) {
|
||||
partiality_model = PartialityModel::Rotation;
|
||||
combine_3d = true;
|
||||
}
|
||||
else {
|
||||
logger.Error("Invalid partiality mode: {}", optarg);
|
||||
print_usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
partiality_explicit = true;
|
||||
case OPT_FORCE_STILL_PROCESSING:
|
||||
force_still_processing = true;
|
||||
break;
|
||||
case OPT_SPOT_SIGMA:
|
||||
sigma_spot_finding = atof(optarg);
|
||||
@@ -789,12 +778,10 @@ int main(int argc, char **argv) {
|
||||
"indexing). Use --process-as-stills to treat it as stills.");
|
||||
}
|
||||
|
||||
// Default partiality model: rot3d for rotation processing (Rotation partiality + 3D combine of the
|
||||
// per-frame partials into fulls), fixed for stills. An explicit -P always wins.
|
||||
if (!partiality_explicit && rotation_indexing) {
|
||||
partiality_model = PartialityModel::Rotation;
|
||||
combine_3d = true; // rot3d
|
||||
}
|
||||
// Rotation data goes through RotationScaleMerge (3D combine of the per-frame partials into fulls)
|
||||
// unless --force-still-processing asks for per-image stills scaling instead.
|
||||
if (rotation_indexing && !force_still_processing)
|
||||
combine_3d = true;
|
||||
|
||||
// Configure Indexing
|
||||
IndexingSettings indexing_settings;
|
||||
@@ -815,7 +802,7 @@ int main(int argc, char **argv) {
|
||||
const bool scale_fulls = scale_fulls_arg.value_or(combine_3d);
|
||||
|
||||
ScalingSettings scaling_settings;
|
||||
scaling_settings.SetPartialityModel(partiality_model);
|
||||
scaling_settings.ForceStillProcessing(force_still_processing);
|
||||
scaling_settings.Combine3D(combine_3d);
|
||||
scaling_settings.ScaleFulls(scale_fulls);
|
||||
scaling_settings.SmoothGDegrees(smooth_g_deg_arg.value_or(combine_3d ? SMOOTH_G_DEFAULT_DEG : 0.0));
|
||||
|
||||
@@ -107,7 +107,6 @@ int main(int argc, char **argv) {
|
||||
int64_t scaling_iter = 3;
|
||||
|
||||
std::optional<IntensityFormat> intensity_format; // --scaling-output override; default lives in ScalingSettings (mmCIF)
|
||||
PartialityModel partiality_model = PartialityModel::Fixed;
|
||||
bool combine_3d = false; // -P rot3d: weight-sum per-frame partials into fulls before merging
|
||||
|
||||
std::optional<float> d_min_scale_merge;
|
||||
@@ -149,13 +148,11 @@ int main(int argc, char **argv) {
|
||||
break;
|
||||
case 'P':
|
||||
if (strcmp(optarg, "fixed") == 0)
|
||||
partiality_model = PartialityModel::Fixed;
|
||||
else if (strcmp(optarg, "rot3d") == 0) {
|
||||
partiality_model = PartialityModel::Rotation;
|
||||
combine_3d = true;
|
||||
}
|
||||
combine_3d = false; // stills: per-image ScaleOnTheFly
|
||||
else if (strcmp(optarg, "rot3d") == 0)
|
||||
combine_3d = true; // rotation: RotationScaleMerge
|
||||
else {
|
||||
logger.Error("Invalid partiality mode: {}", optarg);
|
||||
logger.Error("Invalid scaling model (use fixed|rot3d): {}", optarg);
|
||||
print_usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -304,7 +301,6 @@ int main(int argc, char **argv) {
|
||||
experiment.NumTriggers(1);
|
||||
|
||||
ScalingSettings scaling_settings;
|
||||
scaling_settings.SetPartialityModel(partiality_model);
|
||||
scaling_settings.Combine3D(combine_3d);
|
||||
if (d_min_scale_merge)
|
||||
scaling_settings.HighResolutionLimit_A(d_min_scale_merge.value());
|
||||
@@ -337,7 +333,7 @@ int main(int argc, char **argv) {
|
||||
// Rotation (rot3d): the dedicated RotationScaleMerge does the whole self-scale -> 3D combine -> merge
|
||||
// (on the GPU when present). It does not support external-reference scaling, B-factor refinement or
|
||||
// wedge refinement. Everything else (stills, reference scaling) uses ScaleOnTheFly + MergeOnTheFly.
|
||||
const bool is_rotation = combine_3d && experiment.GetPartialityModel() == PartialityModel::Rotation;
|
||||
const bool is_rotation = combine_3d; // -P rot3d
|
||||
if (is_rotation) {
|
||||
if (!reference_data.empty() || experiment.GetScalingSettings().GetRefineB()
|
||||
|| experiment.GetRefineRotationWedgeInScaling()
|
||||
|
||||
@@ -585,7 +585,7 @@ void JFJochViewerSettingsDock::ApplyProcessingMode() {
|
||||
const bool rotation_data = experiment_.GetGoniometer().has_value();
|
||||
const bool rotation_mode = rotation_data && stills_ && !stills_->isChecked();
|
||||
indexing_.RotationIndexing(rotation_mode);
|
||||
scaling_.SetPartialityModel(rotation_mode ? PartialityModel::Rotation : PartialityModel::Fixed);
|
||||
scaling_.ForceStillProcessing(!rotation_mode);
|
||||
scaling_.Combine3D(rotation_mode);
|
||||
scaling_.ScaleFulls(rotation_mode);
|
||||
EmitSpotFinding(); // carries indexing_ (incl. RotationIndexing) to the worker
|
||||
|
||||
Reference in New Issue
Block a user