integration: add --reciprocal-profile dial (global reciprocal-space width)
Build Packages / Unit tests (push) Successful in 59m53s
Build Packages / build:windows:nocuda (push) Successful in 18m24s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m30s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 14m33s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 14m54s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 14m20s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 15m2s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m29s
Build Packages / build:rpm (rocky8) (push) Successful in 14m37s
Build Packages / build:rpm (rocky9) (push) Successful in 12m44s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m10s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m21s
Build Packages / DIALS test (push) Successful in 12m22s
Build Packages / XDS test (durin plugin) (push) Successful in 7m34s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m41s
Build Packages / XDS test (neggia plugin) (push) Successful in 7m52s
Build Packages / Generate python client (push) Successful in 24s
Build Packages / Build documentation (push) Successful in 1m0s
Build Packages / Create release (push) Skipped
Build Packages / build:windows:cuda (push) Successful in 16m53s
Build Packages / Unit tests (push) Successful in 59m53s
Build Packages / build:windows:nocuda (push) Successful in 18m24s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m30s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 14m33s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 14m54s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 14m20s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 15m2s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m29s
Build Packages / build:rpm (rocky8) (push) Successful in 14m37s
Build Packages / build:rpm (rocky9) (push) Successful in 12m44s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m10s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m21s
Build Packages / DIALS test (push) Successful in 12m22s
Build Packages / XDS test (durin plugin) (push) Successful in 7m34s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m41s
Build Packages / XDS test (neggia plugin) (push) Successful in 7m52s
Build Packages / Generate python client (push) Successful in 24s
Build Packages / Build documentation (push) Successful in 1m0s
Build Packages / Create release (push) Skipped
Build Packages / build:windows:cuda (push) Successful in 16m53s
The per-shell profile width is learned in pixels, so it varies ~4x with resolution (mostly the geometric projection of a near-constant reciprocal-space relrod) and must be binned per shell -> it starves at high resolution / on sparse data. The new --reciprocal-profile flag instead learns ONE global width in reciprocal space, sigma2_q,tan = A + B|q| + C|q|^2: the Jacobian g_tan=cos(2theta) removes the geometric projection, and C|q|^2 is the crystal mosaicity relrod (variance ~(eta|q|)^2). Applied per reflection as sigma2_tan,px = (A + B|q| + C|q|^2)/g_tan^2 (B,C clamped >=0; quadratic->linear->constant fallback). Off by default. On the sharp HEWL test crystal (mosaicity 0.091deg, so C fits to ~0 and it reduces to the validated linear form) it is metric-neutral: ISa 16.2->16.3, anomalous 0.92x unchanged, CCref band 90.0->89.9, CC1/2 a touch lower (per-shell isn't starved at 23k spots/shell, and a global fit is less flexible). So: simpler + more transferable at a small CC1/2 cost, ISa/anomalous held. Its payoff is on MOSAIC crystals (large C|q|^2), where per-shell starves on the wide weak high-res spots and 6 shells are too coarse; both lyso test crystals are sharp, so it ships as a dial to try on mosaic data elsewhere. A separate radial relrod fit was tried and dropped (no gain). See NEXTGEN_INTEGRATOR.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -72,6 +72,7 @@ void print_usage() {
|
||||
std::cout << " --bandwidth <num> Relative X-ray bandwidth FWHM (e.g. 0.01 for 1% DMM); default from file or 0" << std::endl;
|
||||
std::cout << " --integration-radius <r> Signal-box radius r1, or r1,r2,r3 (px). One value => r2=r1+2, r3=r1+4" << std::endl;
|
||||
std::cout << " --integrator <txt> Spot integrator boxsum|gaussian|empirical (default: gaussian profile-fit; boxsum is the classical fallback)" << std::endl;
|
||||
std::cout << " --reciprocal-profile Learn one global reciprocal-space profile width (A+B|q|+C|q|^2) instead of per-shell; helps mosaic/sparse data" << std::endl;
|
||||
}
|
||||
|
||||
enum {
|
||||
@@ -97,7 +98,8 @@ enum {
|
||||
OPT_SCALE_FULLS,
|
||||
OPT_CAPTURE_UNCERTAINTY,
|
||||
OPT_MOSAICITY,
|
||||
OPT_SMOOTH_G
|
||||
OPT_SMOOTH_G,
|
||||
OPT_RECIPROCAL_PROFILE
|
||||
};
|
||||
|
||||
static option long_options[] = {
|
||||
@@ -142,6 +144,7 @@ static option long_options[] = {
|
||||
{"bandwidth", required_argument, nullptr, OPT_BANDWIDTH},
|
||||
{"integration-radius", required_argument, nullptr, OPT_INTEGRATION_RADIUS},
|
||||
{"integrator", required_argument, nullptr, OPT_INTEGRATOR},
|
||||
{"reciprocal-profile", no_argument, nullptr, OPT_RECIPROCAL_PROFILE},
|
||||
{"reject-outliers", required_argument, nullptr, OPT_REJECT_OUTLIERS},
|
||||
{"reject-delta-cchalf", required_argument, nullptr, OPT_REJECT_DELTA_CCHALF},
|
||||
{nullptr, 0, nullptr, 0}
|
||||
@@ -314,6 +317,7 @@ int main(int argc, char **argv) {
|
||||
std::optional<float> d_min_scale_merge;
|
||||
std::optional<std::string> integration_radius_arg; // "r1" or "r1,r2,r3"
|
||||
std::optional<IntegratorMode> integrator_mode; // --integrator boxsum|gaussian|empirical
|
||||
bool reciprocal_profile = false; // --reciprocal-profile
|
||||
std::optional<double> outlier_reject_nsigma; // merge per-observation outlier rejection
|
||||
std::optional<double> delta_cchalf_nsigma; // per-crystal CC1/2-delta rejection
|
||||
|
||||
@@ -535,6 +539,9 @@ int main(int argc, char **argv) {
|
||||
else if (strcmp(optarg, "empirical") == 0) integrator_mode = IntegratorMode::ProfileEmpirical;
|
||||
else { logger.Error("--integrator expects boxsum|gaussian|empirical"); return 1; }
|
||||
break;
|
||||
case OPT_RECIPROCAL_PROFILE:
|
||||
reciprocal_profile = true;
|
||||
break;
|
||||
case OPT_REJECT_OUTLIERS:
|
||||
outlier_reject_nsigma = std::stod(optarg);
|
||||
break;
|
||||
@@ -773,6 +780,13 @@ int main(int argc, char **argv) {
|
||||
: "profile (empirical)");
|
||||
}
|
||||
|
||||
if (reciprocal_profile) {
|
||||
BraggIntegrationSettings bis = experiment.GetBraggIntegrationSettings();
|
||||
bis.ReciprocalProfile(true);
|
||||
experiment.ImportBraggIntegrationSettings(bis);
|
||||
logger.Info("Reciprocal-space global profile width enabled (per-shell width replaced)");
|
||||
}
|
||||
|
||||
SpotFindingSettings spot_settings;
|
||||
spot_settings.enable = true;
|
||||
spot_settings.indexing = true;
|
||||
|
||||
Reference in New Issue
Block a user