LatticeSearch: Make the code a bit more versatile
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 12m28s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 12m35s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 12m47s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 12m57s
Build Packages / Generate python client (push) Successful in 18s
Build Packages / Create release (push) Has been skipped
Build Packages / build:rpm (rocky8) (push) Successful in 13m12s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 13m12s
Build Packages / Build documentation (push) Successful in 37s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 13m48s
Build Packages / build:rpm (rocky9) (push) Successful in 13m51s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 6m38s
Build Packages / Unit tests (push) Successful in 51m56s

This commit is contained in:
2025-12-03 12:06:41 +01:00
parent 885537ec22
commit d196e198e7
2 changed files with 563 additions and 144 deletions
+552 -144
View File
@@ -5,6 +5,496 @@
#include <gemmi/cellred.hpp>
#include <cmath>
#include <optional>
#include "../../common/JFJochException.h"
const std::map<int, NiggliClassDefinition> kNiggliClassDefinitions = {
{
1, {
gemmi::Mat33{
1, -1, 1,
1, 1, -1,
-1, 1, 1
},
gemmi::CrystalSystem::Cubic,
'F'
}
},
{
2, {
gemmi::Mat33{
1, -1, 0,
-1, 0, 1,
-1, -1, -1
},
gemmi::CrystalSystem::Trigonal,
'R'
}
},
{
3, {
gemmi::Mat33{
1, 0, 0,
0, 1, 0,
0, 0, 1
},
gemmi::CrystalSystem::Cubic,
'P'
}
},
{
5, {
gemmi::Mat33{
1, 0, 1,
1, 1, 0,
0, 1, 1
},
gemmi::CrystalSystem::Cubic,
'I'
}
},
{
4, {
gemmi::Mat33{
1, -1, 0,
-1, 0, 1,
-1, -1, -1
},
gemmi::CrystalSystem::Trigonal,
'R'
}
},
{
6, {
gemmi::Mat33{
0, 1, 1,
1, 0, 1,
1, 1, 0
},
gemmi::CrystalSystem::Tetragonal,
'I'
}
},
{
7, {
gemmi::Mat33{
1, 0, 1,
1, 1, 0,
0, 1, 1
},
gemmi::CrystalSystem::Tetragonal,
'I'
}
},
{
8, {
gemmi::Mat33{
-1, -1, 0,
-1, 0, -1,
0, -1, -1
},
gemmi::CrystalSystem::Orthorhombic,
'I'
}
},
{
9, {
gemmi::Mat33{
1, 0, 0,
-1, 1, 0,
-1, -1, -3
},
gemmi::CrystalSystem::Trigonal,
'R'
}
},
{
10, {
gemmi::Mat33{
1, 1, 0,
1, -1, 0,
0, 0, -1
},
gemmi::CrystalSystem::Monoclinic,
'C'
}
},
{
11, {
gemmi::Mat33{
1, 0, 0,
0, 1, 0,
0, 0, 1
},
gemmi::CrystalSystem::Tetragonal,
'P'
}
},
{
12, {
gemmi::Mat33{
1, 0, 0,
0, 1, 0,
0, 0, 1
},
gemmi::CrystalSystem::Hexagonal,
'P'
}
},
{
13, {
gemmi::Mat33{
1, 1, 0,
-1, 1, 0,
0, 0, 1
},
gemmi::CrystalSystem::Orthorhombic,
'C'
}
},
{
15, {
gemmi::Mat33{
1, 0, 0,
0, 1, 0,
1, 1, 2
},
gemmi::CrystalSystem::Tetragonal,
'I'
}
},
{
16, {
gemmi::Mat33{
-1, -1, 0,
1, -1, 0,
1, 1, 2
},
gemmi::CrystalSystem::Orthorhombic,
'F'
}
},
{
14, {
gemmi::Mat33{
1, 1, 0,
-1, 1, 0,
0, 0, 1
},
gemmi::CrystalSystem::Monoclinic,
'C'
}
},
{
17, {
gemmi::Mat33{
1, -1, 0,
1, 1, 0,
-1, 0, -1
},
gemmi::CrystalSystem::Monoclinic,
'C'
}
},
{
18, {
gemmi::Mat33{
0, -1, 1,
1, -1, -1,
1, 0, 0
},
gemmi::CrystalSystem::Tetragonal,
'I'
}
},
{
19, {
gemmi::Mat33{
-1, 0, 0,
0, -1, 1,
-1, 1, 1
},
gemmi::CrystalSystem::Orthorhombic,
'I'
}
},
{
20, {
gemmi::Mat33{
0, 1, 1,
0, 1, -1,
-1, 0, 0
},
gemmi::CrystalSystem::Monoclinic,
'C'
}
},
{
21, {
gemmi::Mat33{
0, 1, 0,
0, 0, 1,
1, 0, 0
},
gemmi::CrystalSystem::Tetragonal,
'P'
}
},
{
22, {
gemmi::Mat33{
0, 1, 0,
0, 0, 1,
1, 0, 0
},
gemmi::CrystalSystem::Hexagonal,
'P'
}
},
{
23, {
gemmi::Mat33{
0, 1, 1,
0, -1, 1,
1, 0, 0
},
gemmi::CrystalSystem::Orthorhombic,
'C'
}
},
{
24, {
gemmi::Mat33{
1, 2, 1,
0, -1, 1,
1, 0, 0
},
gemmi::CrystalSystem::Trigonal,
'R'
}
},
{
25, {
gemmi::Mat33{
0, 1, 1,
0, -1, 1,
1, 0, 0
},
gemmi::CrystalSystem::Monoclinic,
'C'
}
},
{
26, {
gemmi::Mat33{
1, 0, 0,
-1, 2, 0,
-1, 0, 2
},
gemmi::CrystalSystem::Orthorhombic,
'F'
}
},
{
27, {
gemmi::Mat33{
-1, 2, 0,
-1, 0, 0,
0, -1, 1
},
gemmi::CrystalSystem::Monoclinic,
'C'
}
},
{
28, {
gemmi::Mat33{
-1, 0, 0,
-1, 0, 2,
0, 1, 0
},
gemmi::CrystalSystem::Monoclinic,
'C'
}
},
{
29, {
gemmi::Mat33{
1, 0, 0,
1, -2, 0,
0, 0, -1
},
gemmi::CrystalSystem::Monoclinic,
'C'
}
},
{
30, {
gemmi::Mat33{
0, 1, 0,
0, 1, -2,
-1, 0, 0
},
gemmi::CrystalSystem::Monoclinic,
'C'
}
},
{
31, {
gemmi::Mat33{
1, 0, 0,
0, 1, 0,
0, 0, 1
},
gemmi::CrystalSystem::Triclinic,
'P'
}
},
{
32, {
gemmi::Mat33{
1, 0, 0,
0, 1, 0,
0, 0, 1
},
gemmi::CrystalSystem::Orthorhombic,
'P'
}
},
{
40, {
gemmi::Mat33{
0, -1, 0,
-1, 0, 0,
0, 0, -1
},
gemmi::CrystalSystem::Orthorhombic,
'C'
}
},
{
35, {
gemmi::Mat33{
0, -1, 0,
-1, 0, 0,
0, 0, -1
},
gemmi::CrystalSystem::Monoclinic,
'P'
}
},
{
36, {
gemmi::Mat33{
1, 0, 0,
-1, 0, -2,
0, 1, 0
},
gemmi::CrystalSystem::Orthorhombic,
'C'
}
},
{
33, {
gemmi::Mat33{
1, 0, 0,
0, 1, 0,
0, 0, 1
},
gemmi::CrystalSystem::Monoclinic,
'P'
}
},
{
38, {
gemmi::Mat33{
-1, 0, 0,
1, 2, 0,
0, 0, -1
},
gemmi::CrystalSystem::Orthorhombic,
'C'
}
},
{
34, {
gemmi::Mat33{
-1, 0, 0,
0, 0, -1,
0, -1, 0
},
gemmi::CrystalSystem::Monoclinic,
'P'
}
},
{
42, {
gemmi::Mat33{
-1, 0, 0,
0, -1, 0,
1, 1, 2
},
gemmi::CrystalSystem::Orthorhombic,
'I'
}
},
{
41, {
gemmi::Mat33{
0, -1, -2,
0, -1, 0,
-1, 0, 0
},
gemmi::CrystalSystem::Monoclinic,
'C'
}
},
{
37, {
gemmi::Mat33{
1, 0, 2,
1, 0, 0,
0, 1, 0
},
gemmi::CrystalSystem::Monoclinic,
'C'
}
},
{
39, {
gemmi::Mat33{
-1, -2, 0,
-1, 0, 0,
0, 0, -1
},
gemmi::CrystalSystem::Monoclinic,
'C'
}
},
{
43, {
gemmi::Mat33{
-1, 0, 0,
-1, -1, -2,
0, -1, 0
},
gemmi::CrystalSystem::Monoclinic,
'I'
}
},
{
44, {
gemmi::Mat33{
1, 0, 0,
0, 1, 0,
0, 0, 1
},
gemmi::CrystalSystem::Triclinic,
'P'
}
},
};
struct NiggliClass {
int number;
@@ -16,9 +506,6 @@ struct NiggliClass {
double cond_F;
bool cond_DEF;
bool cond_2DF;
gemmi::Mat33 reindex;
gemmi::CrystalSystem system;
char centering;
};
LatticeSearchResult LatticeSearch(const CrystalLattice &L, double dist_tolerance, double angle_tolerance) {
@@ -41,269 +528,186 @@ LatticeSearchResult LatticeSearch(const CrystalLattice &L, double dist_tolerance
std::vector<NiggliClass> niggli_classes = {
{
1, 1,
true, true, A / 2, A / 2, A / 2, false, false,
gemmi::Mat33{1, -1, 1, 1, 1, -1, -1, 1, 1},
gemmi::CrystalSystem::Cubic, 'F'
true, true, A / 2, A / 2, A / 2, false, false
},
{
2, 1,
true, true, D, D, D, false, false,
{1, -1, 0, -1, 0, 1, -1, -1, -1},
gemmi::CrystalSystem::Trigonal, 'R'
true, true, D, D, D, false, false
},
{
3, 2,
true, true, 0, 0, 0, false, false,
gemmi::Mat33{1, 0, 0, 0, 1, 0, 0, 0, 1},
gemmi::CrystalSystem::Cubic, 'P'
true, true, 0, 0, 0, false, false
},
{
5, 2,
true, true, -A / 3, -A / 3, -A / 3, false, false,
gemmi::Mat33{1, 0, 1, 1, 1, 0, 0, 1, 1},
gemmi::CrystalSystem::Cubic, 'I'
true, true, -A / 3, -A / 3, -A / 3, false, false
},
{
4, 2,
true, true, D, D, D, false, false,
{1, -1, 0, -1, 0, 1, -1, -1, -1},
gemmi::CrystalSystem::Trigonal, 'R'
true, true, D, D, D, false, false
},
{
6, 2,
true, true, D, D, F, true, false,
{0, 1, 1, 1, 0, 1, 1, 1, 0},
gemmi::CrystalSystem::Tetragonal, 'I'
true, true, D, D, F, true, false
},
{
7, 2,
true, true, D, E, E, true, false,
{1, 0, 1, 1, 1, 0, 0, 1, 1},
gemmi::CrystalSystem::Tetragonal, 'I'
true, true, D, E, E, true, false
},
{
8, 2,
true, true, D, E, F, true, false,
{-1, -1, 0, -1, 0, -1, 0, -1, -1},
gemmi::CrystalSystem::Orthorhombic, 'I'
true, true, D, E, F, true, false
},
{
9, 1,
true, false, A / 2, A / 2, A / 2, false, false,
{1, 0, 0, -1, 1, 0, -1, -1, -3},
gemmi::CrystalSystem::Trigonal, 'R'
true, false, A / 2, A / 2, A / 2, false, false
},
{
10, 1,
true, false, D, D, F, false, false,
{1, 1, 0, 1, -1, 0, 0, 0, -1},
gemmi::CrystalSystem::Monoclinic, 'C'
true, false, D, D, F, false, false
},
{
11, 2,
true, false, 0, 0, 0, false, false,
{1, 0, 0, 0, 1, 0, 0, 0, 1},
gemmi::CrystalSystem::Tetragonal, 'P'
true, false, 0, 0, 0, false, false
},
{
12, 2,
true, false, 0, 0, -A / 2, false, false,
{1, 0, 0, 0, 1, 0, 0, 0, 1},
gemmi::CrystalSystem::Hexagonal, 'P'
true, false, 0, 0, -A / 2, false, false
},
{
13, 2,
true, false, 0, 0, F, false, false,
{1, 1, 0, -1, 1, 0, 0, 0, 1},
gemmi::CrystalSystem::Orthorhombic, 'C'
true, false, 0, 0, F, false, false
},
{
15, 2,
true, false, -A / 2, -A / 2, 0, false, false,
{1, 0, 0, 0, 1, 0, 1, 1, 2},
gemmi::CrystalSystem::Tetragonal, 'I'
true, false, -A / 2, -A / 2, 0, false, false
},
{
16, 2,
true, false, D, D, F, true, false,
{-1, -1, 0, 1, -1, 0, 1, 1, 2},
gemmi::CrystalSystem::Orthorhombic, 'F'
true, false, D, D, F, true, false
},
{
14, 2,
true, false, D, D, F, false, false,
{1, 1, 0, -1, 1, 0, 0, 0, 1},
gemmi::CrystalSystem::Monoclinic, 'C'
true, false, D, D, F, false, false
},
{
17, 2,
true, false, D, E, F, true, false,
{1, -1, 0, 1, 1, 0, -1, 0, -1},
gemmi::CrystalSystem::Monoclinic, 'C'
true, false, D, E, F, true, false
},
{
18, 1,
false, true, A / 4, A / 2, A / 2, false, false,
{0, -1, 1, 1, -1, -1, 1, 0, 0},
gemmi::CrystalSystem::Tetragonal, 'I'
false, true, A / 4, A / 2, A / 2, false, false
},
{
19, 1,
false, true, D, A / 2, A / 2, false, false,
{-1, 0, 0, 0, -1, 1, -1, 1, 1},
gemmi::CrystalSystem::Orthorhombic, 'I'
false, true, D, A / 2, A / 2, false, false
},
{
20, 1,
false, true, D, E, E, false, false,
{0, 1, 1, 0, 1, -1, -1, 0, 0},
gemmi::CrystalSystem::Monoclinic, 'C'
false, true, D, E, E, false, false
},
{
21, 2,
false, true, 0, 0, 0, false, false,
{0, 1, 0, 0, 0, 1, 1, 0, 0},
gemmi::CrystalSystem::Tetragonal, 'P'
false, true, 0, 0, 0, false, false
},
{
22, 2,
false, true, -B / 2, 0, 0, false, false,
{0, 1, 0, 0, 0, 1, 1, 0, 0},
gemmi::CrystalSystem::Hexagonal, 'P'
false, true, -B / 2, 0, 0, false, false
},
{
23, 2,
false, true, D, 0, 0, false, false,
{0, 1, 1, 0, -1, 1, 1, 0, 0},
gemmi::CrystalSystem::Orthorhombic, 'C'
false, true, D, 0, 0, false, false
},
{
24, 2,
false, true, D, -A / 3, -A / 3, true, false,
{1, 2, 1, 0, -1, 1, 1, 0, 0},
gemmi::CrystalSystem::Trigonal, 'R'
false, true, D, -A / 3, -A / 3, true, false
},
{
25, 2,
false, true, D, E, E, false, false,
{0, 1, 1, 0, -1, 1, 1, 0, 0},
gemmi::CrystalSystem::Monoclinic, 'C'
false, true, D, E, E, false, false
},
{
26, 1,
false, false, A / 4, A / 2, A / 2, false, false,
{1, 0, 0, -1, 2, 0, -1, 0, 2},
gemmi::CrystalSystem::Orthorhombic, 'F'
false, false, A / 4, A / 2, A / 2, false, false
},
{
27, 1,
false, false, D, A / 2, A / 2, false, false,
{-1, 2, 0, -1, 0, 0, 0, -1, 1},
gemmi::CrystalSystem::Monoclinic, 'C'
false, false, D, A / 2, A / 2, false, false
},
{
28, 1,
false, false, D, A / 2, 2 * D, false, false,
{-1, 0, 0, -1, 0, 2, 0, 1, 0},
gemmi::CrystalSystem::Monoclinic, 'C'
false, false, D, A / 2, 2 * D, false, false
},
{
29, 1,
false, false, D, 2 * D, A / 2, false, false,
{1, 0, 0, 1, -2, 0, 0, 0, -1},
gemmi::CrystalSystem::Monoclinic, 'C'
false, false, D, 2 * D, A / 2, false, false
},
{
30, 1,
false, false, B / 2, E, 2 * E, false, false,
{0, 1, 0, 0, 1, -2, -1, 0, 0},
gemmi::CrystalSystem::Monoclinic, 'C'
false, false, B / 2, E, 2 * E, false, false
},
{
31, 1,
false, false, D, E, F, false, false,
{1, 0, 0, 0, 1, 0, 0, 0, 1},
gemmi::CrystalSystem::Triclinic, 'P'
false, false, D, E, F, false, false
},
{
32, 2,
false, false, 0, 0, 0, false, false,
{1, 0, 0, 0, 1, 0, 0, 0, 1},
gemmi::CrystalSystem::Orthorhombic, 'P'
false, false, 0, 0, 0, false, false
},
{
40, 2,
false, false, -B / 2, 0, 0, false, false,
{0, -1, 0, -1, 0, 0, 0, 0, -1},
gemmi::CrystalSystem::Orthorhombic, 'C'
false, false, -B / 2, 0, 0, false, false
},
{
35, 2,
false, false, D, 0, 0, false, false,
{0, -1, 0, -1, 0, 0, 0, 0, -1},
gemmi::CrystalSystem::Monoclinic, 'P'
false, false, D, 0, 0, false, false
},
{
36, 2,
false, false, 0, -A / 2, 0, false, false,
{1, 0, 0, -1, 0, -2, 0, 1, 0},
gemmi::CrystalSystem::Orthorhombic, 'C'
false, false, 0, -A / 2, 0, false, false
},
{
33, 2,
false, false, 0, E, 0, false, false,
{1, 0, 0, 0, 1, 0, 0, 0, 1},
gemmi::CrystalSystem::Monoclinic, 'P'
false, false, 0, E, 0, false, false
},
{
38, 2,
false, false, 0, 0, -A / 2, false, false,
{-1, 0, 0, 1, 2, 0, 0, 0, -1},
gemmi::CrystalSystem::Orthorhombic, 'C'
false, false, 0, 0, -A / 2, false, false
},
{
34, 2,
false, false, 0, 0, F, false, false,
{-1, 0, 0, 0, 0, -1, 0, -1, 0},
gemmi::CrystalSystem::Monoclinic, 'P'
false, false, 0, 0, F, false, false
},
{
42, 2,
false, false, -B / 2, -A / 2, 0, false, false,
{-1, 0, 0, 0, -1, 0, 1, 1, 2},
gemmi::CrystalSystem::Orthorhombic, 'I'
false, false, -B / 2, -A / 2, 0, false, false
},
{
41, 2,
false, false, -B / 2, E, 0, false, false,
{0, -1, -2, 0, -1, 0, -1, 0, 0},
gemmi::CrystalSystem::Monoclinic, 'C'
false, false, -B / 2, E, 0, false, false
},
{
37, 2,
false, false, D, -A / 2, 0, false, false,
{1, 0, 2, 1, 0, 0, 0, 1, 0},
gemmi::CrystalSystem::Monoclinic, 'C'
false, false, D, -A / 2, 0, false, false
},
{
39, 2,
false, false, D, 0, -A / 2, false, false,
{-1, -2, 0, -1, 0, 0, 0, 0, -1},
gemmi::CrystalSystem::Monoclinic, 'C'
false, false, D, 0, -A / 2, false, false
},
{
44, 2,
false, false, D, E, F, false, false,
{1, 0, 0, 0, 1, 0, 0, 0, 1},
gemmi::CrystalSystem::Triclinic, 'P'
false, false, D, E, F, false, false
}
};
const auto uc_reduced = L_niggli.GetUnitCell();
std::optional<int> first_niggli_class;
std::vector<int> possible_classes = {};
for (const auto &c: niggli_classes) {
if (c.type == 1 && uc_reduced.beta >= 90 - angle_tolerance )
continue;
@@ -333,21 +737,25 @@ LatticeSearchResult LatticeSearch(const CrystalLattice &L, double dist_tolerance
ok = false;
if (ok) {
return LatticeSearchResult{
.niggli_class = c.number,
.primitive_reduced = L,
.conventional = L_niggli.Multiply(c.reindex),
.system = c.system,
.centering = c.centering,
};
if (!first_niggli_class.has_value())
first_niggli_class = c.number;
possible_classes.push_back(c.number);
}
}
int first_niggli_class_val = first_niggli_class.value_or(44);
auto it = kNiggliClassDefinitions.find(first_niggli_class_val);
if (it == kNiggliClassDefinitions.end())
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds,
"Wrong niggli class number " + std::to_string(first_niggli_class_val));
return LatticeSearchResult{
.niggli_class = 44,
.primitive_reduced = L,
.conventional = L,
.system = gemmi::CrystalSystem::Triclinic,
.centering = 'P',
.niggli_class = first_niggli_class_val,
.possible_niggli_classes = possible_classes,
.primitive_reduced = L_niggli,
.conventional = L_niggli.Multiply(it->second.reindex),
.system = it->second.system,
.centering = it->second.centering,
};
}
@@ -4,6 +4,7 @@
#ifndef JFJOCH_LATTICESEARCH_H
#define JFJOCH_LATTICESEARCH_H
#include <map>
#include "../../common/CrystalLattice.h"
#include "../../common/UnitCell.h"
#include "../../common/Coord.h"
@@ -12,12 +13,22 @@
struct LatticeSearchResult {
int niggli_class = 44;
std::vector<int> possible_niggli_classes;
CrystalLattice primitive_reduced;
CrystalLattice conventional;
gemmi::CrystalSystem system = gemmi::CrystalSystem::Triclinic;
char centering = 'P'; // 'P','A','B','C','I','F','R'
};
struct NiggliClassDefinition {
gemmi::Mat33 reindex;
gemmi::CrystalSystem system;
char centering;
};
LatticeSearchResult LatticeSearch(const CrystalLattice& L, double dist_tolerance = 0.03, double angle_tolerance_deg = 3);
// Global lookup: niggli class -> definition
extern const std::map<int, NiggliClassDefinition> kNiggliClassDefinitions;
#endif //JFJOCH_LATTICESEARCH_H