// Copyright (2019-2022) Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-or-later #include #include "../writer/HDF5Objects.h" #include "../image_analysis/IndexerWrapper.h" #define make_unit_cell(a1,a2,a3,a4,a5,a6) UnitCell{.a = a1, .b = a2, .c = a3, .alpha = a4, .beta = a5, .gamma = a6} TEST_CASE("CrystalLattice") { CrystalLattice l(make_unit_cell(50,60,80, 90, 90, 90)); REQUIRE(l.Vec0().Length() == Approx(50)); REQUIRE(l.Vec1().Length() == Approx(60)); REQUIRE(l.Vec2().Length() == Approx(80)); REQUIRE(angle_deg(l.Vec0(), l.Vec2()) == 90); REQUIRE(angle_deg(l.Vec0(), l.Vec1()) == 90); REQUIRE(angle_deg(l.Vec1(), l.Vec2()) == 90); l = CrystalLattice(make_unit_cell(30, 40, 70, 90, 95, 90)); REQUIRE(l.Vec0().Length() == Approx(30)); REQUIRE(l.Vec1().Length() == Approx(40)); REQUIRE(l.Vec2().Length() == Approx(70)); REQUIRE(angle_deg(l.Vec0(), l.Vec2()) == 95); REQUIRE(angle_deg(l.Vec0(), l.Vec1()) == 90); REQUIRE(angle_deg(l.Vec1(), l.Vec2()) == 90); l = CrystalLattice(make_unit_cell(45, 45, 70, 90, 90, 120)); REQUIRE(l.Vec0().Length() == Approx(45)); REQUIRE(l.Vec1().Length() == Approx(45)); REQUIRE(l.Vec2().Length() == Approx(70)); REQUIRE(angle_deg(l.Vec0(), l.Vec2()) == Approx(90)); REQUIRE(angle_deg(l.Vec0(), l.Vec1()) == Approx(120)); REQUIRE(angle_deg(l.Vec1(), l.Vec2()) == Approx(90)); } TEST_CASE("CrystalLattice_ReciprocalLattice") { CrystalLattice l(make_unit_cell(50,60,80, 78, 80, 120)); CrystalLattice rl = l.ReciprocalLattice(); REQUIRE(l.Vec0() * rl.Vec0() == Approx(1.0)); REQUIRE(l.Vec0() * rl.Vec1() < 1e-5); REQUIRE(l.Vec0() * rl.Vec2() < 1e-5); REQUIRE(l.Vec1() * rl.Vec0() < 1e-5); REQUIRE(l.Vec1() * rl.Vec1() == Approx(1.0)); REQUIRE(l.Vec1() * rl.Vec2() < 1e-5); REQUIRE(l.Vec2() * rl.Vec0() < 1e-5); REQUIRE(l.Vec2() * rl.Vec1() < 1e-5); REQUIRE(l.Vec2() * rl.Vec2() == Approx(1.0)); } TEST_CASE("CrystalLattice_EigenMatrix") { CrystalLattice l1(make_unit_cell(50,60,80, 78, 80, 120)); auto m = l1.GetEigenMatrix(); CrystalLattice l2(m); REQUIRE(l2.Vec0().x == Approx(l1.Vec0().x)); REQUIRE(l2.Vec1().y == Approx(l1.Vec1().y)); REQUIRE(l2.Vec2().x == Approx(l1.Vec2().x)); } inline double round_err(double x) { return std::abs(x - std::round(x)); } TEST_CASE("FastFeedbackIndexer","[Indexing]") { std::vector hkl; for (int i = 1; i < 7; i++) for (int j = 1; j<6; j++) for (int k = 1; k < 4; k++) hkl.emplace_back(i,j,k); std::vector cells; cells.emplace_back(make_unit_cell(30,40,50,90,90,90)); cells.emplace_back(make_unit_cell(80,80,90,90,90,120)); cells.emplace_back(make_unit_cell(40,45,80,90,82.5,90)); for (auto &c: cells) { CrystalLattice l(c); CrystalLattice recip_l = l.ReciprocalLattice(); std::vector recip; recip.reserve(hkl.size()); for (const auto &i: hkl) recip.emplace_back(i.x * recip_l.Vec0() + i.y * recip_l.Vec1() + i.z * recip_l.Vec2()); IndexerWrapper wrapper; wrapper.Setup(c); auto ret = wrapper.Run(recip); REQUIRE(!ret.empty()); //auto uc = ret[0].GetUnitCell(); //REQUIRE(c.a == Approx(uc.a)); //REQUIRE(c.b == Approx(uc.b)); //REQUIRE(c.c == Approx(uc.c)); REQUIRE(ret[0].indexed_spots_count == recip.size()); double err[3] = {0.0, 0.0, 0.0}; for (const auto &iter: recip) { err[0] += round_err(ret[0].l.Vec0() * iter); err[1] += round_err(ret[0].l.Vec1() * iter); err[2] += round_err(ret[0].l.Vec2() * iter); } REQUIRE (err[0] < 0.001 * recip.size()); REQUIRE (err[1] < 0.001 * recip.size()); REQUIRE (err[2] < 0.001 * recip.size()); } }