Files
Jungfraujoch/common/CrystalLattice.cpp
2025-09-08 20:28:59 +02:00

173 lines
4.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include <cmath>
#include "CrystalLattice.h"
#include "JFJochException.h"
#include "gemmi/symmetry.hpp"
#include "gemmi/unitcell.hpp"
#define DEG_TO_RAD static_cast<float>(M_PI/180.0)
CrystalLattice::CrystalLattice(const UnitCell &cell) {
vec[0] = {cell.a, 0, 0};
vec[1] = {cell.b * cosf(cell.gamma * DEG_TO_RAD), cell.b * sinf(cell.gamma * DEG_TO_RAD), 0};
float cx = cell.c * cosf(cell.beta * DEG_TO_RAD);
float cy = cell.c
* (cosf(cell.alpha * DEG_TO_RAD) - cosf(cell.beta * DEG_TO_RAD) * cosf(cell.gamma * DEG_TO_RAD))
/ sinf(cell.gamma * DEG_TO_RAD);
vec[2] = {cx, cy, sqrtf(cell.c*cell.c-cx*cx-cy*cy)};
Sort();
FixHandeness();
}
CrystalLattice::CrystalLattice(const Coord &a, const Coord &b, const Coord &c) {
vec[0] = a;
vec[1] = b;
vec[2] = c;
Sort();
FixHandeness();
}
const Coord &CrystalLattice::Vec0() const {
return vec[0];
}
const Coord &CrystalLattice::Vec1() const {
return vec[1];
}
const Coord &CrystalLattice::Vec2() const {
return vec[2];
}
UnitCell CrystalLattice::GetUnitCell() const {
UnitCell cell{};
cell.a = vec[0].Length();
cell.b = vec[1].Length();
cell.c = vec[2].Length();
cell.alpha = angle_deg(vec[1], vec[2]);
cell.beta = angle_deg(vec[0], vec[2]);
cell.gamma = angle_deg(vec[0], vec[1]);
return cell;
}
std::vector<float> CrystalLattice::GetVector() const {
std::vector<float> output(9);
for (int i = 0; i < 3; i++) {
output[3 * i + 0] = vec[i].x;
output[3 * i + 1] = vec[i].y;
output[3 * i + 2] = vec[i].z;
}
return output;
}
float CrystalLattice::CalcVolume() const {
// Calculate the cell volume
// V = a · (b × c)
Coord cross_product = vec[1] % vec[2];
return vec[0] * cross_product;
}
void CrystalLattice::Sort() {
if (vec[0].Length() > vec[1].Length())
std::swap(vec[0], vec[1]);
if (vec[1].Length() > vec[2].Length())
std::swap(vec[1], vec[2]);
if (vec[0].Length() > vec[1].Length())
std::swap(vec[0], vec[1]);
}
void CrystalLattice::FixHandeness() {
if (CalcVolume() < 0)
vec[2] *= -1;
}
Coord CrystalLattice::Astar() const {
return (vec[1] % vec[2]) * (1.0f / CalcVolume());
}
Coord CrystalLattice::Bstar() const {
return (vec[2] % vec[0]) * (1.0f / CalcVolume());
}
Coord CrystalLattice::Cstar() const {
return (vec[0] % vec[1]) * (1.0f / CalcVolume());
}
CrystalLattice::CrystalLattice(float a, float b, float c, float alpha, float beta, float gamma)
: CrystalLattice(UnitCell{.a = a, .b = b, .c = c, .alpha = alpha, .beta = beta, .gamma = gamma}) {}
CrystalLattice::CrystalLattice(const std::vector<float> &input) {
if (input.size() != 9)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,"Wrong size of crystal lattice vector");
for (int i = 0; i < 3; i++) {
vec[i].x = input[3 * i + 0];
vec[i].y = input[3 * i + 1];
vec[i].z = input[3 * i + 2];
}
}
void CrystalLattice::ReorderABEqual() {
double la = vec[0].Length();
double lb = vec[1].Length();
double lc = vec[2].Length();
double dab = std::abs(la - lb);
double dbc = std::abs(lb - lc);
double dac = std::abs(la - lc);
Coord a = vec[0];
Coord b = vec[1];
Coord c = vec[2];
if (dbc < dab && dbc < dac) {
// b≈c → [b, c, a]
vec[0] = b;
vec[1] = c;
vec[2] = a;
} else if (dac < dab && dac < dbc) {
// a≈c → [a, c, b]
vec[0] = a;
vec[1] = c;
vec[2] = b;
} // else a≈b → keep [a, b, c]
FixHandeness();
}
CrystalLattice CrystalLattice::FromPrimitive(char centering) const {
if (centering == 'P')
return *this;
CrystalLattice l;
auto c2p = gemmi::rot_as_mat33(gemmi::centred_to_primitive(centering));
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
l.vec[i][j] = c2p[i][0] * vec[0][j] + c2p[i][1] * vec[1][j] + c2p[i][2] * vec[2][j];
}
}
l.FixHandeness();
return l;
}
CrystalLattice CrystalLattice::ToPrimitive(char centering) const {
if (centering == 'P')
return *this;
CrystalLattice l;
auto c2p = gemmi::rot_as_mat33(gemmi::centred_to_primitive(centering)).inverse();
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
l.vec[i][j] = c2p[i][0] * vec[0][j] + c2p[i][1] * vec[1][j] + c2p[i][2] * vec[2][j];
}
}
l.FixHandeness();
return l;
}