From 8e2d656b487dc2df8e8c7969e4163178bd73aed8 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sun, 8 Nov 2026 21:49:24 +0100 Subject: [PATCH] Refinement: the final maps' missing reflections beside the map transforms MakeMaps filled FWT at the reflections the data do not have only after the three map transforms, and MissingReflections computed the atoms' Fcalc (CPU, anisotropic atoms included) and the solvent mask's Fmask one after the other. Neither reads the other: MissingReflections now runs beside the difference and 2mFo-DFc transforms and the anomalous map, and inside it Fcalc runs beside Fmask. Both are serial-heavy (a single-threaded FFTW transform each, the mask's flood fill), so the tail shortens to about the mask alone. Measured on one RTX 5080, -N 28, two runs each (Step 11 wall, s; with the twinned arm beside the untwinned one): thaumatin (anisotropic U chosen): 3.24 / 3.23 -> 3.04 / 3.08 lysozyme: 2.38 / 2.38 -> 2.25 / 2.28 cytochrome C (two arms): 4.53 / 4.58 -> 4.49 / 4.57 Every output (model, maps, MTZ, report, refinement log lines) is identical to the rc184-port binary on all three sets. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01HVeDQsU5a8AJUdJPgWevAK --- image_analysis/structure_refinement/Refinement.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/image_analysis/structure_refinement/Refinement.cpp b/image_analysis/structure_refinement/Refinement.cpp index 184e671ed..7e8034a1e 100644 --- a/image_analysis/structure_refinement/Refinement.cpp +++ b/image_analysis/structure_refinement/Refinement.cpp @@ -1201,9 +1201,11 @@ std::vector MissingReflections(Context &ctx, const gemmi::SMa std::unique_ptr engine = MakeRefinementEngineCPU(ctx.cell, *ctx.sg, ctx.d_min, missing, ctx.nthreads); engine->SetBlur(RefinementBlur(ctx.cell, *ctx.sg, ctx.d_min, ctx.b_floor)); engine->SetAniso(&ctx.aniso); + // the atoms and the solvent side by side: neither reads the other std::vector> fcalc, fmask; - engine->Fcalc(ctx.Model(), fcalc); + std::future atoms = std::async(std::launch::async, [&] { engine->Fcalc(ctx.Model(), fcalc); }); ctx.mask->Fmask(ctx.Model(), missing.hkl, fmask); + atoms.get(); std::vector> d_by_s; // (1/d^2, D) of the observed reflections, by resolution for (size_t m = 0; m < ctx.refl.Size(); m++) @@ -1298,7 +1300,11 @@ void MakeMaps(Context &ctx, const std::vector &merged, double fwt_data.v.push_back({ctx.refl.hkl[m], std::polar(static_cast(fwt), static_cast(phi))}); } result.maps = maps; - // The difference map and the 2mFo-DFc map beside the anomalous one below: none reads another. + // The reflections the data do not have, the difference map and the 2mFo-DFc map beside the anomalous one below: + // none reads another. + std::future> missing = std::async(std::launch::async, [&ctx, &b_aniso] { + return MissingReflections(ctx, b_aniso); + }); const std::array size = gemmi::get_size_for_hkl(diff, {{0, 0, 0}}, 3.0); std::future difference_map = std::async(std::launch::async, [&diff, &size, &result] { result.difference_map = std::make_shared>(MapFromFPhi(gemmi::get_f_phi_on_grid(diff, size, true))); @@ -1354,7 +1360,7 @@ void MakeMaps(Context &ctx, const std::vector &merged, double } // The filled reflections after the observed ones: FWT/PHWT and the model's FC/PHIC, every other column missing. const float nan = std::numeric_limits::quiet_NaN(); - for (const MissingReflection &r : MissingReflections(ctx, b_aniso)) { + for (const MissingReflection &r : missing.get()) { const double phi_deg = std::arg(r.f_model) * 180.0 / PI; const double k_aniso = std::exp(-0.25 * b_aniso.r_u_r(r.hkl)); const float row[] = {static_cast(r.hkl[0]), static_cast(r.hkl[1]), static_cast(r.hkl[2]), nan,