diff --git a/image_analysis/IndexAndRefine.cpp b/image_analysis/IndexAndRefine.cpp index 2ec7c4e0..c6455113 100644 --- a/image_analysis/IndexAndRefine.cpp +++ b/image_analysis/IndexAndRefine.cpp @@ -457,6 +457,13 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, // report that default onward: RotationScaleMerge averages the reported values in frame order to // recompute every partiality, and a placeholder entered there is read as a measurement. std::optional mos_measured; + // The width the PREDICTION window opens to, which is a different question from the width the + // partiality divides by. Prediction only decides membership, and a reflection just inside a + // generous window arrives with a partiality near zero and is weighted accordingly, so erring wide + // there is close to free (measured: a 28% wider window moves the merged statistics by under half a + // percent). The divisor is not free - it multiplies every partial - so it must stay on the width + // this frame actually measured. + std::optional mos_predict; if (experiment.GetGoniometer().has_value()) { // Full oscillation wedge of one frame; BraggPredictionRot halves it to the +/- half-wedge of the @@ -474,15 +481,10 @@ void IndexAndRefine::QuickPredictAndIntegrate(DataMessage &msg, // reflections and collapse the multiplicity. (A wider value only helps prediction cover the spot.) if (msg.number >= 0 && msg.number < static_cast(prediction_mosaicity_override_.size()) && std::isfinite(prediction_mosaicity_override_[msg.number]) - && prediction_mosaicity_override_[msg.number] > 0.0f) { - mos_measured = std::max(mos_measured.value_or(0.0f), prediction_mosaicity_override_[msg.number]); - mosaicity[msg.number] = *mos_measured; - } + && prediction_mosaicity_override_[msg.number] > 0.0f) + mos_predict = std::max(mos_measured.value_or(0.0f), prediction_mosaicity_override_[msg.number]); } - // The width the prediction window opens to. It is the measured sigma_M unless a fixed prediction - // mosaicity was asked for: the reported (and therefore integrated-against) sigma_M below is left - // alone either way, so the two uses of the number can be separated. - float mos_deg = mos_measured.value_or(0.1f); + float mos_deg = mos_predict.value_or(mos_measured.value_or(0.1f)); if (const auto forced_pred = experiment.GetBraggIntegrationSettings().GetForcedPredictionMosaicity_deg()) mos_deg = *forced_pred; diff --git a/rugnux/rugnux_cli.cpp b/rugnux/rugnux_cli.cpp index ac2b012a..253da9a6 100644 --- a/rugnux/rugnux_cli.cpp +++ b/rugnux/rugnux_cli.cpp @@ -149,7 +149,7 @@ void print_usage() { std::cout << " --capture-uncertainty rot3d: systematic sigma ~num*(1-captured_fraction)*I on under-captured fulls (default: 1.0 for rot3d, 0 otherwise)" << std::endl; std::cout << " --min-captured-fraction rot3d: drop a combined full whose rocking curve was captured below this fraction (edge-of-sweep truncated fulls) (default: 0.7 for rotation, 0 otherwise; 0 = off)" << std::endl; std::cout << " --mosaicity Diagnostic: fix the scaling mosaicity (deg) instead of the per-image seed" << std::endl; - std::cout << " --prediction-mosaicity Diagnostic: fix the rocking width the PREDICTION window opens to (deg), leaving the partiality on the per-image sigma_M. Prediction and partiality are one number by default, so a sigma_M that moves takes the integrated reflection population with it" << std::endl; + std::cout << " --prediction-mosaicity Diagnostic: fix the rocking width the PREDICTION window opens to (deg), leaving the partiality on the per-image sigma_M. Prediction and partiality are one number by default, so a sigma_M that moves takes the integrated reflection population with it" << std::endl; std::cout << " --reject-outliers Per-observation merge outlier rejection, N sigma from the per-reflection median (default: 6 for rot3d, XDS/DIALS-style; 0 = off)" << std::endl; std::cout << " --search-min-zeta De-novo space-group search only: also search a merge of just the observations whose Lorentz geometry |zeta| reaches this, and keep whichever search found MORE symmetry (default: 0.85 for rotation, 0 = single search). Reflections crossing the Ewald sphere near-tangentially are measured worst and can make a real symmetry operator look like a twin law" << std::endl; std::cout << " --min-image-cc Per-image CC limit in percent (default: no limit)" << std::endl;