Tail: the cell e.s.d.s and the unmerged MTZ table beside the refinement; the refined difference and anomalous maps side by side
The cell e.s.d.s and the unmerged MTZ read only the integrated observations and the group, both final once the model has been read, and the refinement reads neither: both now start before the refinement instead of after it. In MakeMaps the difference map is made on its own thread while the anomalous map is made. Outputs identical (MTZ data, CIF/HKL/INS, refined model, maps, blobs, report minus provenance) on the thaumatin and cytochrome C live runs. Live path without the unmerged MTZ (as the broker runs it), step Refinement: thaumatin 2.76 -> 2.40 s, cytochrome C 1.99 -> 1.93 s. With the unmerged MTZ (CLI), Refinement + Writing files: 3.21 -> 2.67 s and 3.33 -> 2.80 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015CeEGgpKdfkCTJb3YNMJcu
This commit is contained in:
1 parent
067f3a7d7b
commit
7c49fefb54
2 files changed
+39
-24
No files matched your search
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <cmath>
|
||||
@@ -856,9 +857,12 @@ void MakeMaps(Context &ctx, const std::vector<MergedReflection> &merged, double
|
||||
diff.v.push_back({ctx.refl.hkl[m], std::polar(static_cast<float>(delfwt), static_cast<float>(phi))});
|
||||
}
|
||||
result.maps = maps;
|
||||
const std::array<int, 3> size = gemmi::get_size_for_hkl(diff, {{0, 0, 0}}, 3.0);
|
||||
result.difference_map = std::make_shared<gemmi::Grid<float>>(MapFromFPhi(gemmi::get_f_phi_on_grid<float>(diff, size, true)));
|
||||
result.difference_map_rms = gemmi::calculate_data_statistics(result.difference_map->data).rms;
|
||||
// The difference map beside the anomalous one below: neither reads the other.
|
||||
std::future<void> difference_map = std::async(std::launch::async, [&diff, &result] {
|
||||
const std::array<int, 3> size = gemmi::get_size_for_hkl(diff, {{0, 0, 0}}, 3.0);
|
||||
result.difference_map = std::make_shared<gemmi::Grid<float>>(MapFromFPhi(gemmi::get_f_phi_on_grid<float>(diff, size, true)));
|
||||
result.difference_map_rms = gemmi::calculate_data_statistics(result.difference_map->data).rms;
|
||||
});
|
||||
|
||||
// The anomalous difference map: F(+) - F(-) on the model's phase turned back by 90 degrees, read on the +
|
||||
// rows of an anomalous merge only (as model validation reads it).
|
||||
@@ -890,6 +894,7 @@ void MakeMaps(Context &ctx, const std::vector<MergedReflection> &merged, double
|
||||
result.anomalous_map_rms = gemmi::calculate_data_statistics(result.anomalous_map->data).rms;
|
||||
}
|
||||
}
|
||||
difference_map.get();
|
||||
}
|
||||
|
||||
// The engine for the model as it is now: on the GPU where it is wanted and takes the case within its budget,
|
||||
|
||||
+31
-21
@@ -4754,6 +4754,35 @@ bool Rugnux::ScaleMergeAndSymmetry(PipelineLocals &p) {
|
||||
}
|
||||
result.model_prior = std::move(mr);
|
||||
}
|
||||
|
||||
// The cell's e.s.d.s (CellEsd.h), from the same integrated observations and at the same point as the
|
||||
// unmerged MTZ below: the indexing and the group are final here, once the model has been read. Rotation
|
||||
// only - a stills run keeps no per-image reflections to the end, and its crystals' cells differ by more than
|
||||
// any one is measured to. Made beside the refinement, which reads neither.
|
||||
std::future<std::optional<CellEsd>> cell_esd;
|
||||
if (is_rotation && !geometry_prepass && !superseded && result.consensus_cell)
|
||||
cell_esd = std::async(std::launch::async, [&outcomes = indexer->GetIntegrationOutcome(),
|
||||
sg = experiment_.GetSpaceGroupOrP1(),
|
||||
wavelength = experiment_.GetWavelength_A(),
|
||||
nthreads = config_.nthreads, &logger = logger] {
|
||||
TimingMark mark(logger, "cell e.s.d.");
|
||||
return EstimateCellEsd(GatherCellObservations(outcomes, nthreads), sg, wavelength);
|
||||
});
|
||||
|
||||
// The unmerged MTZ (kept with the other outputs, see there) is built from here on, beside the
|
||||
// refinement and the reflection files: the indexing and the group it is written in are final once the
|
||||
// model has been read, and nothing after this changes the integrated observations it reads. It gets its
|
||||
// own copy of the experiment.
|
||||
if (full && write_output && !geometry_prepass && !superseded && result.consensus_cell
|
||||
&& config_.export_unmerged) {
|
||||
unmerged_mtz = std::async(std::launch::async,
|
||||
[&outcomes = indexer->GetIntegrationOutcome(),
|
||||
cell = *result.consensus_cell, x = experiment_,
|
||||
&provenance = config_.provenance, nthreads = config_.nthreads] {
|
||||
return UnmergedMtzTable(outcomes, cell, x, true, provenance, nthreads);
|
||||
});
|
||||
}
|
||||
|
||||
if (model_run) {
|
||||
result.model_placement = placed_by_rigid_body ? "RIGID_BODY"
|
||||
: result.model_prior && result.model_prior->chosen >= 0 ? "MR" : "NOT_PLACED";
|
||||
@@ -4833,13 +4862,8 @@ bool Rugnux::ScaleMergeAndSymmetry(PipelineLocals &p) {
|
||||
}
|
||||
}
|
||||
|
||||
// The cell's e.s.d.s (CellEsd.h), from the same integrated observations and at the same point as the
|
||||
// unmerged MTZ below: the indexing and the group are final here. Rotation only - a stills run keeps no
|
||||
// per-image reflections to the end, and its crystals' cells differ by more than any one is measured to.
|
||||
if (is_rotation && !geometry_prepass && !superseded && result.consensus_cell) {
|
||||
TimingMark mark(logger, "cell e.s.d.");
|
||||
const auto obs = GatherCellObservations(indexer->GetIntegrationOutcome(), config_.nthreads);
|
||||
result.cell_esd = EstimateCellEsd(obs, experiment_.GetSpaceGroupOrP1(), experiment_.GetWavelength_A());
|
||||
if (cell_esd.valid()) {
|
||||
result.cell_esd = cell_esd.get();
|
||||
if (result.cell_esd) {
|
||||
const CellEsd &e = *result.cell_esd;
|
||||
logger.Info("Cell e.s.d.s from {} observations of {} reflections: {:.5f} {:.5f} {:.5f} {:.4f} {:.4f} {:.4f}"
|
||||
@@ -4850,20 +4874,6 @@ bool Rugnux::ScaleMergeAndSymmetry(PipelineLocals &p) {
|
||||
}
|
||||
}
|
||||
|
||||
// The unmerged MTZ (kept with the other outputs, see there) is built from here on, beside the
|
||||
// reflection files: the indexing and the group it is written in are final once the model has been
|
||||
// read, and nothing after this changes the integrated observations it reads. It gets its own copy of
|
||||
// the experiment.
|
||||
if (full && write_output && !geometry_prepass && !superseded && result.consensus_cell
|
||||
&& config_.export_unmerged) {
|
||||
unmerged_mtz = std::async(std::launch::async,
|
||||
[&outcomes = indexer->GetIntegrationOutcome(),
|
||||
cell = *result.consensus_cell, x = experiment_,
|
||||
&provenance = config_.provenance, nthreads = config_.nthreads] {
|
||||
return UnmergedMtzTable(outcomes, cell, x, true, provenance, nthreads);
|
||||
});
|
||||
}
|
||||
|
||||
// Not on the geometry pre-pass, and not on a pass that is going to be re-run. Pass 1 exists to
|
||||
// choose the space group and post-refine the geometry; the pass after it remakes these outputs
|
||||
// seconds later at the refined geometry, and that is the answer anyone reads. The quality guard is
|
||||
|
||||
Reference in new issue
Block a user