v1.0.0-rc.179 (#90)
Build Packages / Create release (push) Successful in 8s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 5m11s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 10m32s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 18m26s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 22m11s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 23m32s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 25m36s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 27m28s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 28m10s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 28m10s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 29m24s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 21m45s
Build Packages / Generate python client (push) Successful in 31s
Build Packages / Build documentation (push) Successful in 1m21s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 24m2s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 29m25s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 30m27s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 27m12s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 32m20s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 33m36s
Build Packages / Unit tests (push) Successful in 2h7m18s
Build Packages / Validation Battery (push) Successful in 33m19s

* Rugnux: Stills processing needs only the unit cell and space group beyond what the file records - detector distance, beam centre, tilt, panel placement, saturation level, gain and polarisation plane are found from the images - and is up to twice as fast.
* Rugnux: Stills can be indexed without a GPU, with a CPU implementation of the fast-feedback indexer (macOS, computers without a GPU).
* Rugnux: Rotation and stills data are integrated in the detector's own units with one gain model, improving data from CCD detectors.
* Web frontend: The Rugnux live page shows the placed model with its electron density and anomalous difference map in a Mol* viewer.

Reviewed-on: #90
Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
This commit was merged in pull request #90.
This commit is contained in:
leonarski_f authored and leonarski_f committed 2026-10-24 14:52:29 +02:00
1 parent afbe844b20
commit b00c668e3a
394 files changed
+57778 -2178

No files matched your search

@@ -21,6 +21,7 @@
#include <string>
#include <utility>
#include <vector>
#include <limits>
#include <unordered_map>
#include <gemmi/assembly.hpp> // expand_ncs
@@ -1725,6 +1726,8 @@ ModelValidationResult Validate(const std::vector<MergedReflection> &merged,
// thrown away unread: they are not made at all.
const bool maps_superseded = schedule.maps_superseded && schedule.maps_superseded(result);
std::shared_ptr<ModelMaps> maps;
// The anomalous difference map's coefficients, where the merge kept the Bijvoet split: for the maps file too.
gemmi::AsuData<std::complex<float>> mapanom;
if (!maps_superseded) {
maps = std::make_shared<ModelMaps>();
@@ -1739,8 +1742,7 @@ ModelValidationResult Validate(const std::vector<MergedReflection> &merged,
// rather than leaving a list of coordinates for someone to look up.
// Following ANODE, Thorn & Sheldrick (2011) J. Appl. Cryst. 44, 1285-1287
std::future<void> anomalous_map = std::async(std::launch::async, [&] {
gemmi::AsuData<std::complex<float>> mapanom =
anomalous_coefficients(merged, data_space_group != nullptr ? data_space_group : sg,
mapanom = anomalous_coefficients(merged, data_space_group != nullptr ? data_space_group : sg,
result.indexing_op, fmodel);
result.anomalous_pairs = static_cast<int>(mapanom.v.size());
if (!mapanom.v.empty()) {
@@ -1809,6 +1811,11 @@ ModelValidationResult Validate(const std::vector<MergedReflection> &merged,
{"FREE", 'I'}};
for (const auto &[label, type] : columns)
mtz.columns.push_back({label, type, type == 'H' ? 0 : 1, {}});
// The anomalous difference map's coefficients (ANOM/PHANOM, as phenix.maps names them), on the reflections
// that have a Bijvoet pair; missing (NaN) on the others.
std::unordered_map<long, std::complex<float>> anom_by_hkl;
for (const auto &hv : mapanom.v)
anom_by_hkl[hkl_key(hv.hkl)] = hv.value;
for (size_t i = 0; i < terms.size(); i++) {
// [0, 360), the convention the MTZ 'P' columns carried before sigma_A weighting: std::arg
// returns (-180, 180] and a P column is not supposed to.
@@ -1825,6 +1832,18 @@ ModelValidationResult Validate(const std::vector<MergedReflection> &merged,
for (size_t c = 0; c < mtz.columns.size(); c++)
mtz.columns[c].values.push_back(row[c]);
}
if (!anom_by_hkl.empty()) {
MtzTable::Column anom{"ANOM", 'F', 1, {}}, phanom{"PHANOM", 'P', 1, {}};
for (const auto &t : terms) {
const auto it = anom_by_hkl.find(hkl_key(t.hkl));
const float nan = std::numeric_limits<float>::quiet_NaN();
const double phi = it == anom_by_hkl.end() ? 0.0 : std::arg(it->second) * 180.0 / PI;
anom.values.push_back(it == anom_by_hkl.end() ? nan : std::abs(it->second));
phanom.values.push_back(it == anom_by_hkl.end() ? nan : static_cast<float>(phi < 0 ? phi + 360.0 : phi));
}
mtz.columns.push_back(std::move(anom));
mtz.columns.push_back(std::move(phanom));
}
}
result.ok = true;