diff --git a/image_analysis/scale_merge/RotationScaleMerge.h b/image_analysis/scale_merge/RotationScaleMerge.h index 79278560f..6b5a81216 100644 --- a/image_analysis/scale_merge/RotationScaleMerge.h +++ b/image_analysis/scale_merge/RotationScaleMerge.h @@ -121,8 +121,7 @@ public: // Whether Run() writes the per-frame G / CC / mosaicity back onto the outcomes (on by default). Off // for a merge that is not the run's answer - the P1 cross-check - so the per-image table and the - // unmerged MTZ describe the merge that was written, and so an engine merging beside another one - // does not write the outcomes they share. + // unmerged MTZ describe the merge that was written. void SetWriteBackPerFrameScale(bool on) { write_back_per_frame_scale = on; } // Override the high-resolution cut for the next Run() - used to gate the de-novo P1 search pass at diff --git a/image_analysis/scale_merge/RotationScaleMergeGPU.cu b/image_analysis/scale_merge/RotationScaleMergeGPU.cu index 66aeabacb..8a0e97f85 100644 --- a/image_analysis/scale_merge/RotationScaleMergeGPU.cu +++ b/image_analysis/scale_merge/RotationScaleMergeGPU.cu @@ -19,9 +19,8 @@ namespace { constexpr int MIN_REFLECTIONS = 20; // Every kernel and copy here is queued on the instance's own stream (Impl::stream), not on the - // legacy NULL stream: two merges made side by side - the run's and the one it makes ahead of time - - // and the image analysis of a probe pass beside them would otherwise wait for each other's work at - // every launch and every synchronisation. As in BeamCenterFFTGPU no buffer comes from the pool. A + // legacy NULL stream: the merge and the image analysis of a probe pass beside it would otherwise + // wait for each other's work at every launch and every synchronisation. As in BeamCenterFFTGPU no buffer comes from the pool. A // pooled buffer is freed with cudaFreeAsync on the thread's allocation stream, which is not // ordered after this one. Each entry point below waits for its own work before it returns, so no // free here has yet overtaken a read, but that holds only by that convention, and not at all for a diff --git a/rugnux/Rugnux.cpp b/rugnux/Rugnux.cpp index 94a9325af..aed1270d0 100644 --- a/rugnux/Rugnux.cpp +++ b/rugnux/Rugnux.cpp @@ -6674,28 +6674,6 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b const auto &rot_ss = experiment_.GetScalingSettings(); const bool is_rotation = experiment_.IsRotationIndexing(); // rotation indexing -> rotation scaling/merge std::optional rsm; - // How many times rsm has been ingested on this pass: a re-ingest follows a reindex or a cell - // change, after which a merge made from the first ingest is a merge of other indices. - int rsm_ingests = 0; - // Two P1 merges of this pass's integration made beside the rest of the tail, on an engine of - // their own: the all-observation arm of the space-group search (see there) and the P1 - // cross-check (see where it is written). Neither reads anything the search, the in-symmetry - // merge or the analyses decide, so neither has to wait for them. The engine is ingested together - // with rsm, before any merge writes per-frame values back onto the outcomes, so the two start - // from the same state, and it writes nothing back itself. Used only while rsm was ingested once - // (rsm_ingest); otherwise both merges are made on rsm, as before. - struct P1MergesAhead { - DiffractionExperiment x; - Logger log = Logger::Buffered(); // what the engine logs - Logger all_observations_log = Logger::Buffered(); // ...up to the all-observation merge - std::optional engine; - std::future ingested; - std::future all_observations; - std::future crosscheck; - bool crosscheck_made = false; - int rsm_ingest = 0; - }; - std::unique_ptr p1_ahead; std::optional prepass_postrefine_obs; // The rotation geometry post-refinement (see its call sites below for what it is for). const auto post_refine_geometry = [&] { @@ -6826,60 +6804,6 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Rotation scaling/merging (RotationScaleMerge) does not support " "wedge refinement"); - // The conditions of p1_crosscheck and of the all-observation arm below that are known here; - // the rest (a pass that turns out superseded, a search that finds no point group) only means - // a merge is made and not used. - const bool all_observations_ahead = !geometry_prepass && !experiment_.GetGemmiSpaceGroup().has_value() - && rot_ss.GetSearchMinZeta() > 0.0; - const bool crosscheck_ahead = !geometry_prepass && write_files && config_.write_merged - && config_.write_p1_crosscheck && result.consensus_cell - && (!experiment_.GetGemmiSpaceGroup().has_value() || indexer->GetPredictionCentring() == 'P'); - if ((all_observations_ahead || crosscheck_ahead) && config_.observation_dump_path.empty()) { - p1_ahead = std::make_unique(); - p1_ahead->x = experiment_; - p1_ahead->rsm_ingest = 1; - p1_ahead->crosscheck_made = crosscheck_ahead; - std::promise ingested; - std::promise all_observations; - p1_ahead->ingested = ingested.get_future(); - if (all_observations_ahead) - p1_ahead->all_observations = all_observations.get_future(); - p1_ahead->crosscheck = std::async(std::launch::async, - [&a = *p1_ahead, &outcomes = indexer->GetIntegrationOutcome(), - cell = result.consensus_cell, iter = static_cast(config_.scaling_iter), - nthreads = config_.nthreads, ingested = std::move(ingested), - all_observations = std::move(all_observations), all_observations_ahead, - crosscheck_ahead]() mutable -> RotationScaleMerge::Result { - try { - a.engine.emplace(a.x, outcomes, cell, iter, nthreads, a.log); - a.engine->SetWriteBackPerFrameScale(false); - a.engine->Ingest(); - } catch (...) { - ingested.set_exception(std::current_exception()); - throw; - } - ingested.set_value(); - // Ingested in the group rsm was, merged in P1 - as both merges on rsm are. - a.x.SpaceGroupNumber(1); - if (all_observations_ahead) { - try { - a.engine->SetSearchMinZeta(0.0); - auto merged = a.engine->Run(/*for_search=*/true, /*full_stats=*/true, - /*measure_cc_before_corrections=*/false); - a.all_observations_log = a.log; - a.log = Logger::Buffered(); - all_observations.set_value(std::move(merged)); - } catch (...) { - all_observations.set_exception(std::current_exception()); - throw; - } - } - if (!crosscheck_ahead) - return {}; - return a.engine->Run(/*for_search=*/false, /*full_stats=*/true, - /*measure_cc_before_corrections=*/false); - }); - } // A reference MTZ is allowed for rotation: it fixes the space group / cell (on the CLI) and // resolves the indexing ambiguity (below), but is NOT used to scale - the rotation merge stays // self-consistent. @@ -6887,9 +6811,6 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b static_cast(config_.scaling_iter), config_.nthreads, logger, config_.observation_dump_path); rsm->Ingest(); - ++rsm_ingests; - if (p1_ahead) - p1_ahead->ingested.get(); } // The geometry pre-pass reads the per-image reflections exactly twice more: they were just @@ -7224,14 +7145,9 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b // all-observation arm on both twin gates and promoted to R32 by the filtered one. So the // losing arm's refusal is logged and carried to the report below; the rule is unchanged. if (rsm && rsm->GetSearchMinZeta() > 0.0 && !sg_search.point_group_hm.empty()) { - std::optional ahead; - if (p1_ahead && p1_ahead->all_observations.valid() && p1_ahead->rsm_ingest == rsm_ingests) { - ahead = p1_ahead->all_observations.get(); - p1_ahead->all_observations_log.ReplayInto(logger); - } const double zeta = rsm->GetSearchMinZeta(); rsm->SetSearchMinZeta(0.0); - auto sm_all = scale_and_merge("P1, all observations", true, false, std::move(ahead)); + auto sm_all = scale_and_merge("P1, all observations", true); rsm->SetSearchMinZeta(zeta); merged_filtered_isa = sg_opts.merge_isa; // the filtered arm's, before it is replaced sg_opts.merge_isa = result.error_model_isa; // this arm's own error model @@ -7910,7 +7826,6 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b static_cast(config_.scaling_iter), config_.nthreads, logger, config_.observation_dump_path); rsm->Ingest(); - ++rsm_ingests; } const auto &uc = *result.consensus_cell; logger.Info("{} names a cell of {}x the volume of its reference setting: the " @@ -8106,7 +8021,6 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b result.consensus_cell, static_cast(config_.scaling_iter), config_.nthreads, logger, config_.observation_dump_path); rsm->Ingest(); - ++rsm_ingests; } } } @@ -8134,7 +8048,6 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b static_cast(config_.scaling_iter), config_.nthreads, logger, config_.observation_dump_path); rsm->Ingest(); - ++rsm_ingests; } } experiment_.SetSpaceGroup(sg); @@ -8468,7 +8381,6 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b static_cast(config_.scaling_iter), config_.nthreads, logger, config_.observation_dump_path); rsm->Ingest(); - ++rsm_ingests; phase("Re-merging in the reference's frame"); sm = scale_and_merge(moved->short_name(), false); const auto &uc = *result.consensus_cell; @@ -8964,8 +8876,6 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b && !geometry_prepass && !superseded && config_.write_p1_crosscheck && p1_integration_complete && is_rotation; std::optional p1_merged_early; - const bool p1_ahead_usable = p1_crosscheck && p1_ahead && p1_ahead->crosscheck_made - && p1_ahead->rsm_ingest == rsm_ingests; // Model validation runs BEFORE the reflection files are written, because it is what settles the // frame they are written in: the enantiomorph, which merged intensities cannot choose, and - @@ -9000,7 +8910,7 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b // P1 merge afterwards, through merge_to_written, as it did when it was made below. The // validation's log lines are held and printed as one block once it is done. ModelValidationResult validation; - if (p1_crosscheck && rsm && !p1_ahead_usable) { + if (p1_crosscheck && rsm) { Logger held = Logger::Buffered(); auto pending = std::async(std::launch::async, validate, std::ref(held)); experiment_.SpaceGroupNumber(1); @@ -9202,10 +9112,6 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b // Both the merge and the MTZ read the group from the experiment, so it is set for // the whole of it and restored after. experiment_.SpaceGroupNumber(1); - if (p1_ahead_usable) { - p1_merged_early = p1_ahead->crosscheck.get(); - p1_ahead->log.ReplayInto(logger); - } if (!p1_merged_early) rsm->SetWriteBackPerFrameScale(false); auto p1 = scale_and_merge("P1 cross-check", false, false, std::move(p1_merged_early));