diff --git a/docs/CPU_DATA_ANALYSIS_REFINEMENT.md b/docs/CPU_DATA_ANALYSIS_REFINEMENT.md index 830f3aec5..b136b6ed0 100644 --- a/docs/CPU_DATA_ANALYSIS_REFINEMENT.md +++ b/docs/CPU_DATA_ANALYSIS_REFINEMENT.md @@ -356,7 +356,8 @@ The refined model's map coefficients, `_refined_maps.mtz`, are $2mF_o - $\sigma_A$ of §14.4, so the maps carry the weights the target was minimised with; $m$ is $I_1(X)/I_0(X)$, $X = 2F_oD|F_\mathrm{model}|/\Sigma$, for an acentric reflection and $\tanh(X/2)$ for a centric one. Where the merge kept the Bijvoet pairs, the anomalous difference map is made on the refined -model's phases too, and read by the blob finder below. +model's phases too, written in the same file as `ANOM`/`PHANOM` (as in `_maps.mtz`; missing where a +reflection has no Bijvoet pair), and read by the blob finder below. ### 15.9 Unexplained density: blobs diff --git a/docs/RUGNUX_MODEL_AND_REFERENCE.md b/docs/RUGNUX_MODEL_AND_REFERENCE.md index cde751bfe..c67389d9b 100644 --- a/docs/RUGNUX_MODEL_AND_REFERENCE.md +++ b/docs/RUGNUX_MODEL_AND_REFERENCE.md @@ -440,7 +440,7 @@ the data, a weak shell says nothing about them, and nothing acts on it. |---|---|---| | `.mtz` / `.cif` / `.hkl` | The answer: the data's space group, with only the class-(b) labels from the model | Refinement, deposition, everything by default | | `_model.cif` / `.pdb`, `_maps.mtz` | The model as placed, in the frame of `.mtz`, and its map coefficients (Coot/PyMOL open them as maps) | Starting refinement (REFMAC5, phenix.refine), PanDDA, Coot | -| `_refined_model.cif`/`.pdb`, `_refined_maps.mtz`, `_blobs.json` | The placed model refined by rugnux, its map coefficients, and the unexplained blobs of its difference map | A first look at the refined density and at what the model leaves unexplained; continuing refinement | +| `_refined_model.cif`/`.pdb`, `_refined_maps.mtz`, `_blobs.json` | The placed model refined by rugnux, its map coefficients (with the anomalous difference map's, `ANOM`/`PHANOM`, where the merge kept the Bijvoet pairs, as in `_maps.mtz`), and the unexplained blobs of its difference map | A first look at the refined density and at what the model leaves unexplained; continuing refinement | | `_twin_.mtz` / `.cif` | The same data merged in a subgroup with a twin law — written from the data, model or not | Twin refinement, where you suspect the higher group absorbed a twin law | | `_mr.mtz` / `.cif`, `_mr_model.pdb` / `.cif`, `_mr_*` maps | The merge in the space group the model chose (`MODEL_CHOICE_SPACE_GROUP=`), and the model placed there | Refinement *if* you accept the model's choice; compare R-free against the answer's | diff --git a/image_analysis/structure_refinement/Refinement.cpp b/image_analysis/structure_refinement/Refinement.cpp index 4c31dc9b4..e2449d33a 100644 --- a/image_analysis/structure_refinement/Refinement.cpp +++ b/image_analysis/structure_refinement/Refinement.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -1252,12 +1253,25 @@ void MakeMaps(Context &ctx, const std::vector &merged, double gemmi::AsuData> anom; anom.unit_cell_ = ctx.cell; anom.spacegroup_ = ctx.sg; + // Its coefficients in the maps file too (ANOM/PHANOM, as model validation writes them), missing (NaN) where + // the reflection has no Bijvoet pair. + const float nan = std::numeric_limits::quiet_NaN(); + MtzTable::Column anom_col{"ANOM", 'F', 1, {}}, phanom_col{"PHANOM", 'P', 1, {}}; for (size_t m = 0; m < ctx.refl.Size(); m++) { const auto it = danom.find(ctx.refl.hkl[m]); - if (it != danom.end()) - anom.v.push_back({ctx.refl.hkl[m], it->second * std::polar(1.0f, static_cast(std::arg(fmodel[m]) - PI / 2))}); + if (it == danom.end()) { + anom_col.values.push_back(nan); + phanom_col.values.push_back(nan); + continue; + } + const std::complex c = it->second * std::polar(1.0f, static_cast(std::arg(fmodel[m]) - PI / 2)); + anom.v.push_back({ctx.refl.hkl[m], c}); + anom_col.values.push_back(std::abs(c)); + phanom_col.values.push_back(MtzPhase(std::arg(c) * 180.0 / PI)); } if (!anom.v.empty()) { + mtz.columns.push_back(std::move(anom_col)); + mtz.columns.push_back(std::move(phanom_col)); result.anomalous_map = std::make_shared>( MapFromFPhi(gemmi::get_f_phi_on_grid(anom, gemmi::get_size_for_hkl(anom, {{0, 0, 0}}, 3.0), true))); result.anomalous_map_rms = gemmi::calculate_data_statistics(result.anomalous_map->data).rms;