174 lines
6.7 KiB
C++
174 lines
6.7 KiB
C++
// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include <catch2/catch_all.hpp>
|
|
#include "../common/CrystalLattice.h"
|
|
|
|
TEST_CASE("CrystalLattice") {
|
|
CrystalLattice l(50,60,80, 90, 90, 90);
|
|
REQUIRE(l.Vec0().Length() == Catch::Approx(50));
|
|
REQUIRE(l.Vec1().Length() == Catch::Approx(60));
|
|
REQUIRE(l.Vec2().Length() == Catch::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);
|
|
|
|
auto uc0 = l.GetUnitCell();
|
|
REQUIRE(uc0.a == Catch::Approx(50));
|
|
REQUIRE(uc0.b == Catch::Approx(60));
|
|
REQUIRE(uc0.c == Catch::Approx(80));
|
|
REQUIRE(uc0.alpha == Catch::Approx(90));
|
|
REQUIRE(uc0.beta == Catch::Approx(90));
|
|
REQUIRE(uc0.gamma == Catch::Approx(90));
|
|
|
|
l = CrystalLattice(30, 40, 70, 90, 95, 90);
|
|
REQUIRE(l.Vec0().Length() == Catch::Approx(30));
|
|
REQUIRE(l.Vec1().Length() == Catch::Approx(40));
|
|
REQUIRE(l.Vec2().Length() == Catch::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);
|
|
|
|
auto uc1 = l.GetUnitCell();
|
|
REQUIRE(uc1.a == Catch::Approx(30));
|
|
REQUIRE(uc1.b == Catch::Approx(40));
|
|
REQUIRE(uc1.c == Catch::Approx(70));
|
|
REQUIRE(uc1.alpha == Catch::Approx(90));
|
|
REQUIRE(uc1.beta == Catch::Approx(95));
|
|
REQUIRE(uc1.gamma == Catch::Approx(90));
|
|
|
|
l = CrystalLattice(45, 45, 70, 90, 90, 120);
|
|
REQUIRE(l.Vec0().Length() == Catch::Approx(45));
|
|
REQUIRE(l.Vec1().Length() == Catch::Approx(45));
|
|
REQUIRE(l.Vec2().Length() == Catch::Approx(70));
|
|
REQUIRE(angle_deg(l.Vec0(), l.Vec2()) == Catch::Approx(90));
|
|
REQUIRE(angle_deg(l.Vec0(), l.Vec1()) == Catch::Approx(120));
|
|
REQUIRE(angle_deg(l.Vec1(), l.Vec2()) == Catch::Approx(90));
|
|
|
|
auto uc2 = l.GetUnitCell();
|
|
REQUIRE(uc2.a == Catch::Approx(45));
|
|
REQUIRE(uc2.b == Catch::Approx(45));
|
|
REQUIRE(uc2.c == Catch::Approx(70));
|
|
REQUIRE(uc2.alpha == Catch::Approx(90));
|
|
REQUIRE(uc2.beta == Catch::Approx(90));
|
|
REQUIRE(uc2.gamma == Catch::Approx(120));
|
|
}
|
|
|
|
TEST_CASE("CrystalLattice_Sort") {
|
|
CrystalLattice l(80,60,50, 120, 90, 90);
|
|
l.Sort();
|
|
REQUIRE(l.Vec0().Length() == Catch::Approx(50));
|
|
REQUIRE(l.Vec1().Length() == Catch::Approx(60));
|
|
REQUIRE(l.Vec2().Length() == Catch::Approx(80));
|
|
REQUIRE(angle_deg(l.Vec0(), l.Vec2()) == Catch::Approx(90));
|
|
REQUIRE(angle_deg(l.Vec0(), l.Vec1()) == Catch::Approx(120));
|
|
REQUIRE(angle_deg(l.Vec1(), l.Vec2()) == Catch::Approx(90));
|
|
}
|
|
|
|
TEST_CASE("CrystalLattice_ReorderMonoclinic") {
|
|
std::vector<CrystalLattice> latt = {
|
|
{85,70,60, 85, 90, 90},
|
|
{60,70,85, 90, 90, 85},
|
|
{60,85,70, 90, 85, 90},
|
|
{70,60,85, 90, 90, 85}
|
|
};
|
|
for (const auto &l_in :latt) {
|
|
CrystalLattice l = l_in;
|
|
l.ReorderMonoclinic();
|
|
|
|
CHECK(l.Vec0().Length() == Catch::Approx(60));
|
|
CHECK(l.Vec1().Length() == Catch::Approx(85));
|
|
CHECK(l.Vec2().Length() == Catch::Approx(70));
|
|
CHECK(l.GetUnitCell().beta == Catch::Approx(95.0));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("CrystalLattice_ReorderTetragonal") {
|
|
CrystalLattice l(40,60,60, 90, 90, 90);
|
|
l.ReorderABEqual();
|
|
REQUIRE(l.Vec0().Length() == Catch::Approx(60));
|
|
REQUIRE(l.Vec1().Length() == Catch::Approx(60));
|
|
REQUIRE(l.Vec2().Length() == Catch::Approx(40));
|
|
}
|
|
|
|
TEST_CASE("CrystalLattice_ReorderTetragonal_ForHexagonal") {
|
|
CrystalLattice l(40,60,60, 120, 90, 90);
|
|
l.ReorderABEqual();
|
|
REQUIRE(l.Vec0().Length() == Catch::Approx(60));
|
|
REQUIRE(l.Vec1().Length() == Catch::Approx(60));
|
|
REQUIRE(l.Vec2().Length() == Catch::Approx(40));
|
|
}
|
|
|
|
TEST_CASE("CrystalLattice_Handedness") {
|
|
CrystalLattice l(Coord(1,0,0), Coord(0,1,0), Coord(0,0,-1));
|
|
REQUIRE(l.Vec0().x == Catch::Approx(1));
|
|
REQUIRE(l.Vec1().y == Catch::Approx(1));
|
|
REQUIRE(l.Vec2().z == Catch::Approx(1));
|
|
}
|
|
|
|
TEST_CASE("CrystalLattice_Volume") {
|
|
CrystalLattice l(50, 60, 80, 90, 90, 90);
|
|
REQUIRE(l.CalcVolume() == 50 * 60 * 80);
|
|
|
|
CrystalLattice l2(50,60,80, 90, 120, 90);
|
|
float sin120 = std::sqrt(3) / 2;
|
|
REQUIRE(l2.CalcVolume() == Catch::Approx(50 * 60 * 80 * sin120));
|
|
}
|
|
|
|
TEST_CASE("CrystalLattice_Recip") {
|
|
CrystalLattice l(50,60,80, 90, 90, 90);
|
|
REQUIRE(l.Astar().Length() == Catch::Approx(1/50.0));
|
|
REQUIRE(l.Astar().x == Catch::Approx(1/50.0));
|
|
REQUIRE(l.Bstar().Length() == Catch::Approx(1/60.0));
|
|
REQUIRE(l.Bstar().y == Catch::Approx(1/60.0));
|
|
REQUIRE(l.Cstar().Length() == Catch::Approx(1/80.0));
|
|
REQUIRE(l.Cstar().z == Catch::Approx(1/80.0));
|
|
}
|
|
|
|
TEST_CASE("CrystalLattice_ToPrimitive") {
|
|
// Conventional cubic (take as I-conventional basis): a=b=c=50, orthogonal
|
|
CrystalLattice conv(50, 50, 50, 90, 90, 90);
|
|
const float Vconv = conv.CalcVolume();
|
|
REQUIRE(Vconv == Catch::Approx(50.f * 50.f * 50.f).margin(1e-4f));
|
|
|
|
CrystalLattice prim = conv.ToPrimitive('I');
|
|
|
|
// Volume halves (index 2)
|
|
CHECK(prim.CalcVolume() == Catch::Approx(Vconv * 0.5f).margin(1e-4f));
|
|
|
|
// bcc primitive lengths and angles
|
|
auto uc_p = prim.GetUnitCell();
|
|
const float a0 = 50.f;
|
|
const float expected_len = a0 * std::sqrt(3.f) * 0.5f; // a*sqrt(3)/2
|
|
const float expected_angle = 109.4712206f; // arccos(-1/3) in degrees
|
|
|
|
CHECK(uc_p.a == Catch::Approx(expected_len).margin(1e-3f));
|
|
CHECK(uc_p.b == Catch::Approx(expected_len).margin(1e-3f));
|
|
CHECK(uc_p.c == Catch::Approx(expected_len).margin(1e-3f));
|
|
CHECK(uc_p.alpha == Catch::Approx(expected_angle).margin(1e-3f));
|
|
CHECK(uc_p.beta == Catch::Approx(expected_angle).margin(1e-3f));
|
|
CHECK(uc_p.gamma == Catch::Approx(expected_angle).margin(1e-3f));
|
|
}
|
|
|
|
TEST_CASE("CrystalLattice_FromPrimitive") {
|
|
// Conventional cubic (take as I-conventional basis): a=b=c=50, orthogonal
|
|
const float a0 = 50.f;
|
|
const float expected_len = a0 * std::sqrt(3.f) * 0.5f; // a*sqrt(3)/2
|
|
const float expected_angle = 109.4712206f; // arccos(-1/3) in degrees
|
|
|
|
CrystalLattice conv(expected_len, expected_len, expected_len,
|
|
expected_angle, expected_angle, expected_angle);
|
|
|
|
auto prim = conv.FromPrimitive('I');
|
|
auto uc_c = prim.GetUnitCell();
|
|
|
|
// Back to conventional cube with original volume
|
|
CHECK(prim.CalcVolume() == Catch::Approx(a0 * a0 * a0).margin(1e-4f));
|
|
CHECK(uc_c.a == Catch::Approx(a0).margin(1e-3f));
|
|
CHECK(uc_c.b == Catch::Approx(a0).margin(1e-3f));
|
|
CHECK(uc_c.c == Catch::Approx(a0).margin(1e-3f));
|
|
CHECK(uc_c.alpha == Catch::Approx(90.f).margin(1e-3f));
|
|
CHECK(uc_c.beta == Catch::Approx(90.f).margin(1e-3f));
|
|
CHECK(uc_c.gamma == Catch::Approx(90.f).margin(1e-3f));
|
|
}
|