v1.0.0-rc.131 (#39)
All checks were successful
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 11m20s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 10m46s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 11m27s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 12m32s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 10m57s
Build Packages / build:rpm (rocky8) (push) Successful in 11m54s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 13m9s
Build Packages / build:rpm (rocky9) (push) Successful in 12m37s
Build Packages / Generate python client (push) Successful in 24s
Build Packages / Create release (push) Has been skipped
Build Packages / Build documentation (push) Successful in 57s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 9m12s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 8m4s
Build Packages / Unit tests (push) Successful in 1h17m43s
All checks were successful
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 11m20s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 10m46s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 11m27s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 12m32s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 10m57s
Build Packages / build:rpm (rocky8) (push) Successful in 11m54s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 13m9s
Build Packages / build:rpm (rocky9) (push) Successful in 12m37s
Build Packages / Generate python client (push) Successful in 24s
Build Packages / Create release (push) Has been skipped
Build Packages / Build documentation (push) Successful in 57s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 9m12s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 8m4s
Build Packages / Unit tests (push) Successful in 1h17m43s
This is an UNSTABLE release. The release has significant modifications and bug fixes, if things go wrong, it is better to revert to 1.0.0-rc.124. * jfjoch_broker: Fix bug in saving JUNGFRAU calibration (pedestal/pedestalRMS) * jfjoch_viewer: Fix calibration (pedestal) images being open flipped * jfjoch_process: Add space group detection (EXPERIMENTAL) Reviewed-on: #39
This commit was merged in pull request #39.
This commit is contained in:
150
tests/SearchSpaceGroupTest.cpp
Normal file
150
tests/SearchSpaceGroupTest.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include "../image_analysis/scale_merge/SearchSpaceGroup.h"
|
||||
#include "gemmi/symmetry.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
struct HKL {
|
||||
int h = 0;
|
||||
int k = 0;
|
||||
int l = 0;
|
||||
|
||||
bool operator==(const HKL& o) const noexcept {
|
||||
return h == o.h && k == o.k && l == o.l;
|
||||
}
|
||||
};
|
||||
|
||||
struct HKLHash {
|
||||
size_t operator()(const HKL& x) const noexcept {
|
||||
auto mix = [](uint64_t v) {
|
||||
v ^= v >> 33;
|
||||
v *= 0xff51afd7ed558ccdULL;
|
||||
v ^= v >> 33;
|
||||
v *= 0xc4ceb9fe1a85ec53ULL;
|
||||
v ^= v >> 33;
|
||||
return v;
|
||||
};
|
||||
return static_cast<size_t>(
|
||||
mix(static_cast<uint64_t>(x.h)) ^
|
||||
(mix(static_cast<uint64_t>(x.k)) << 1) ^
|
||||
(mix(static_cast<uint64_t>(x.l)) << 2));
|
||||
}
|
||||
};
|
||||
|
||||
double CalcSyntheticD(int h, int k, int l) {
|
||||
const double q2 = static_cast<double>(h * h + k * k + l * l);
|
||||
return 40.0 / std::sqrt(q2 + 1.0);
|
||||
}
|
||||
|
||||
double SyntheticIntensityFromAsu(const gemmi::Op::Miller& asu) {
|
||||
uint64_t x = static_cast<uint64_t>((asu[0] + 31) * 73856093u) ^
|
||||
static_cast<uint64_t>((asu[1] + 37) * 19349663u) ^
|
||||
static_cast<uint64_t>((asu[2] + 41) * 83492791u);
|
||||
x ^= x >> 13;
|
||||
x *= 0x9e3779b97f4a7c15ULL;
|
||||
x ^= x >> 17;
|
||||
return 100.0 + static_cast<double>(x % 500);
|
||||
}
|
||||
|
||||
std::vector<MergedReflection> GenerateMergedReflectionsForSpaceGroup(
|
||||
const gemmi::SpaceGroup& sg,
|
||||
int hmax = 8) {
|
||||
|
||||
std::vector<MergedReflection> merged;
|
||||
std::unordered_set<HKL, HKLHash> added;
|
||||
|
||||
const gemmi::GroupOps gops = sg.operations();
|
||||
const gemmi::ReciprocalAsu rasu(&sg);
|
||||
|
||||
for (int h = -hmax; h <= hmax; ++h) {
|
||||
for (int k = -hmax; k <= hmax; ++k) {
|
||||
for (int l = -hmax; l <= hmax; ++l) {
|
||||
if (h == 0 && k == 0 && l == 0)
|
||||
continue;
|
||||
|
||||
bool absent = false;
|
||||
gemmi::Op::Miller hkl{{h, k, l}};
|
||||
if (gops.is_systematically_absent(hkl))
|
||||
absent = true;
|
||||
|
||||
const auto [asu, sign_plus] = rasu.to_asu_sign(hkl, gops);
|
||||
if (!sign_plus)
|
||||
continue;
|
||||
|
||||
const HKL key{h, k, l};
|
||||
if (added.find(key) != added.end())
|
||||
continue;
|
||||
added.insert(key);
|
||||
|
||||
merged.push_back(MergedReflection{
|
||||
.h = h,
|
||||
.k = k,
|
||||
.l = l,
|
||||
.I = absent ? 0.0 : SyntheticIntensityFromAsu(asu),
|
||||
.sigma = 1.0,
|
||||
.d = CalcSyntheticD(h, k, l)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("SearchSpaceGroup detects synthetic space groups") {
|
||||
struct Case {
|
||||
std::string input_name;
|
||||
std::string expected_short_name;
|
||||
};
|
||||
|
||||
const std::vector<Case> cases = {
|
||||
{"P 1", "P1"},
|
||||
{"P 1 2 1", "P2"},
|
||||
{"P 3 2 1", "P321"},
|
||||
{"P 4 2 2", "P422"},
|
||||
{"P 4 3 2", "P432"},
|
||||
{"P 43 21 2", "P43212"},
|
||||
{"P 6 2 2", "P622"},
|
||||
{"C 1 2 1", "C2"},
|
||||
{"C 2 2 2", "C222"},
|
||||
{"I 4 3 2", "I432"},
|
||||
{"I 21 21 21", "I212121"},
|
||||
{"I 2 1 3", "I213"},
|
||||
};
|
||||
|
||||
for (const auto& tc : cases) {
|
||||
DYNAMIC_SECTION(tc.expected_short_name) {
|
||||
const gemmi::SpaceGroup& sg = gemmi::get_spacegroup_by_name(tc.input_name);
|
||||
const auto merged = GenerateMergedReflectionsForSpaceGroup(sg);
|
||||
|
||||
SearchSpaceGroupOptions opt;
|
||||
opt.crystal_system.reset();
|
||||
opt.centering = '\0';
|
||||
opt.merge_friedel = true;
|
||||
opt.d_min_limit_A = 2.0;
|
||||
opt.min_operator_cc = 0.99;
|
||||
opt.min_pairs_per_operator = 20;
|
||||
opt.min_total_compared = 80;
|
||||
opt.test_systematic_absences = true;
|
||||
opt.absence_resolution_bins = 10;
|
||||
opt.min_absent_reflections_per_bin = 5;
|
||||
opt.min_allowed_reflections_per_bin = 10;
|
||||
opt.max_absent_to_allowed_i_over_sigma_ratio = 0.05;
|
||||
opt.max_absent_to_allowed_i_over_sigma_ratio_in_any_bin = 0.10;
|
||||
|
||||
const auto result = SearchSpaceGroup(merged, opt);
|
||||
|
||||
INFO(SearchSpaceGroupResultToText(result));
|
||||
REQUIRE(result.best_space_group.has_value());
|
||||
CHECK(result.best_space_group->short_name() == tc.expected_short_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user