5#ifndef GEMMI_UNITCELL_HPP_
6#define GEMMI_UNITCELL_HPP_
61 return {x - std::floor(x), y - std::floor(y), z - std::floor(z)};
64 return {x - std::round(x), y - std::round(y), z - std::round(z)};
67 return {std::round(x), std::round(y), std::round(z)};
70 if (x > 0.5) x -= 1.0;
else if (x < -0.5) x += 1.0;
71 if (y > 0.5) y -= 1.0;
else if (y < -0.5) y += 1.0;
72 if (z > 0.5) z -= 1.0;
else if (z < -0.5) z += 1.0;
91 std::string s = std::to_string(
sym_idx + 1);
98 s +=
char(
'5' +
shift);
100 for (
int i = 0;
i < 3; ++
i) {
133 return std::size_t((hkl[0] * 1024 + hkl[1]) * 1024 + hkl[2]);
138 double a = 1.0,
b = 1.0,
c = 1.0;
150 return a ==
o.a &&
b ==
o.b &&
c ==
o.c &&
156 auto eq = [&](
double x,
double y) {
return std::fabs(x - y) <
epsilon; };
191 auto siml = [&](
double x,
double y) {
return std::fabs(x - y) <
rel * std::max(x, y); };
192 auto sima = [&](
double x,
double y) {
return std::fabs(x - y) <
deg; };
206 fail(
"Impossible angle - N*180deg.");
284 if (
frac.
mat[0][0] == 1.0 && (f.
mat[0][0] == 0.0 || f.
mat[0][0] > 1.0))
305 set(
p.a,
p.b,
p.c,
p.alpha,
p.beta,
p.gamma);
311 set(
va.length(),
vb.length(),
vc.length(),
339 std::array<double,6> other = {{
340 m.column_dot(0,0),
m.column_dot(1,1),
m.column_dot(2,2),
341 m.column_dot(1,2),
m.column_dot(0,2),
m.column_dot(0,1)
343 for (
int i = 0;
i < 6; ++
i)
365 set_cell_images_from_groupops(
sg->operations());
373 assert(cs_count == (
short) images.size());
379 for (
int i = 0;
i < cs_count; ++
i)
380 images.push_back(images[
i].combine(f));
385 std::vector<FTransform> ncs;
386 for (
size_t n = cs_count; n < images.size(); n += cs_count + 1)
387 ncs.push_back(images[n]);
413 r.minimum = orthogonalize(f.minimum);
414 r.maximum = orthogonalize(f.maximum);
415 if (alpha != 90. || beta == 90. || gamma == 90.) {
416 r.extend(orthogonalize({f.minimum.x, f.minimum.y, f.maximum.z}));
417 r.extend(orthogonalize({f.minimum.x, f.maximum.y, f.maximum.z}));
418 r.extend(orthogonalize({f.minimum.x, f.maximum.y, f.minimum.z}));
419 r.extend(orthogonalize({f.maximum.x, f.maximum.y, f.minimum.z}));
420 r.extend(orthogonalize({f.maximum.x, f.minimum.y, f.minimum.z}));
421 r.extend(orthogonalize({f.maximum.x, f.minimum.y, f.maximum.z}));
435 return orthogonalize_difference(
diff).length_sq();
438 return distance_sq(fractionalize(
pos1), fractionalize(
pos2));
442 return is_crystal() ? volume / (1 + images.size()) :
NAN;
449 for (
int j = 0;
j < 3; ++
j)
459 for (
int j = 0;
j < 3; ++
j)
471 image.dist_sq = ref.dist_sq(pos);
478 image.pbc_shift[0] == 0 &&
image.pbc_shift[1] == 0 &&
image.pbc_shift[2] == 0)
480 for (
int n = 0; n !=
static_cast<int>(images.size()); ++n)
482 image.sym_idx = n + 1;
497 int image_idx=0)
const {
501 apply_transform(
fpos, image_idx,
false);
506 int image_idx=0)
const {
507 return find_nearest_pbc_image(fractionalize(ref), fractionalize(pos), image_idx);
512 std::vector<NearestImage>
results;
514 int sh[3] = {
im.pbc_shift[0],
im.pbc_shift[1],
im.pbc_shift[2]};
515 for (
im.pbc_shift[0] =
sh[0]-1;
im.pbc_shift[0] <=
sh[0]+1; ++
im.pbc_shift[0])
516 for (
im.pbc_shift[1] =
sh[1]-1;
im.pbc_shift[1] <=
sh[1]+1; ++
im.pbc_shift[1])
517 for (
im.pbc_shift[2] =
sh[2]-1;
im.pbc_shift[2] <=
sh[2]+1; ++
im.pbc_shift[2]) {
519 im.dist_sq = orthogonalize_difference(
fpos -
fref +
shift).length_sq();
520 if (
im.dist_sq <=
sq(dist))
529 return orthogonalize_difference((
fpos -
fref).wrap_to_zero()) + ref;
533 int image_idx,
bool inverse=
false)
const {
535 apply_transform(
fpos, image_idx, inverse);
536 return orthogonalize_in_pbc(ref,
fpos);
541 apply_transform(
fpos,
im.sym_idx,
false);
558 return is_special_position(fractionalize(pos),
max_dist);
574 return calculate_1_d2_double(hkl[0], hkl[1], hkl[2]);
580 return 1.0 / std::sqrt(calculate_1_d2(hkl));
585 return 0.25 * calculate_1_d2(hkl);
591 return {a*a, b*b, c*c, a*orth.mat[0][1], a*orth.mat[0][2], b*c*cos_alpha()};
595 return {ar*ar, br*br, cr*cr, ar*br*cos_gammar, ar*cr*cos_betar, br*cr*cos_alphar};
600 auto acosd = [](
double x) {
return deg(std::acos(x)); };
606 return {{
int(a / dmin),
int(b / dmin),
int(c / dmin)}};
610 if (centring_type ==
'P')
613 return orth.mat.multiply(
c2p);
fail(), unreachable() and __declspec/__attribute__ macros
Math utilities. 3D linear algebra.
constexpr double deg(double angle)
Op::Rot centred_to_primitive(char centring_type)
std::array< int, 3 > Miller
A synonym for convenient passing of hkl.
Mat33 rot_as_mat33(const Op::Rot &rot)
Vec3 operator*(double d, const Vec3 &v)
constexpr double rad(double angle)
constexpr float sq(float x)
void fail(const std::string &msg)
Vec3 tran_as_vec3(const Op &op)
Fractional wrap_to_unit() const
void move_toward_zero_by_one()
Fractional(const Vec3 &v)
Fractional operator-(const Fractional &o) const
Fractional operator+(const Fractional &o) const
Fractional wrap_to_zero() const
std::vector< Op > sym_ops
Vec3 column_copy(int i) const
bool approx(const Mat33 &other, double epsilon) const
Vec3 multiply(const Vec3 &p) const
std::size_t operator()(const Miller &hkl) const noexcept
Non-crystallographic symmetry operation (such as in the MTRIXn record)
Position apply(const Position &p) const
Result of find_nearest_image.
std::string symmetry_code(bool underscore) const
Returns a string such as 1555 or 1_555.
std::array< std::array< int, 3 >, 3 > Rot
static constexpr Op identity()
Coordinates in Angstroms - orthogonal (Cartesian) coordinates.
Position operator*(double d) const
Position operator/(double d) const
Position & operator+=(const Position &o)
Position operator-(const Position &o) const
Position & operator*=(double d)
Position operator+(const Position &o) const
Position operator-() const
Position & operator-=(const Position &o)
Position & operator/=(double d)
std::array< T, 6 > elements_voigt() const
UnitCellParameters(const double(&par)[6])
bool operator==(const UnitCellParameters &o) const
UnitCellParameters()=default
UnitCellParameters(const std::array< double, 6 > &par)
bool approx(const UnitCellParameters &o, double epsilon) const
bool operator!=(const UnitCellParameters &o) const
double calculate_d(const Miller &hkl) const
Calculate d-spacing.
double distance_sq(const Fractional &pos1, const Fractional &pos2) const
NearestImage find_nearest_image(const Position &ref, const Position &pos, Asu asu) const
UnitCell changed_basis_backward(const Op &op, bool set_images)
void set_from_array(const std::array< double, 6 > &v)
std::vector< FTransform > get_ncs_transforms() const
UnitCell reciprocal() const
Returns reciprocal unit cell.
UnitCell(const std::array< double, 6 > &v)
double calculate_u_eq(const SMat33< double > &ani) const
The equivalent isotropic displacement factor.
Position find_nearest_pbc_position(const Position &ref, const Position &pos, int image_idx, bool inverse=false) const
void calculate_properties()
SMat33< double > metric_tensor() const
https://dictionary.iucr.org/Metric_tensor
double ar
reciprocal parameters a*, b*, c*, alpha*, beta*, gamma*
Fractional fractionalize(const Position &o) const
bool is_compatible_with_spacegroup(const SpaceGroup *sg, double eps=1e-3) const
Fractional fract_image(const NearestImage &im, Fractional fpos)
NearestImage find_nearest_pbc_image(const Position &ref, const Position &pos, int image_idx=0) const
double calculate_stol_sq(const Miller &hkl) const
Calculate (sin(theta)/lambda)^2 = d*^2/4.
void set_matrices_from_fract(const Transform &f)
bool is_compatible_with_groupops(const GroupOps &gops, double eps=1e-3) const
double distance_sq(const Position &pos1, const Position &pos2) const
Transform op_as_transform(const Op &op) const
Mat33 calculate_matrix_B() const
B matrix following convention from Busing & Levy (1967), not from cctbx.
void set(double a_, double b_, double c_, double alpha_, double beta_, double gamma_)
UnitCell(double a_, double b_, double c_, double alpha_, double beta_, double gamma_)
Miller get_hkl_limits(double dmin) const
void apply_transform(Fractional &fpos, int image_idx, bool inverse) const
void set_from_vectors(const Vec3 &va, const Vec3 &vb, const Vec3 &vc)
Mat33 primitive_orth_matrix(char centring_type) const
Position orthogonalize(const Fractional &f) const
double volume_per_image() const
void add_ncs_images_to_cs_images(const std::vector< NcsOp > &ncs)
double calculate_1_d2_double(double h, double k, double l) const
Calculate 1/d^2 for specified hkl reflection.
void set_cell_images_from_groupops(const GroupOps &group_ops)
bool search_pbc_images(Fractional &&diff, NearestImage &image) const
UnitCell changed_basis_forward(const Op &op, bool set_images)
double calculate_1_d2(const Miller &hkl) const
std::vector< FTransform > images
Position orthogonalize_difference(const Fractional &delta) const
orthogonalize_difference(a-b) == orthogonalize(a) - orthogonalize(b)
void set_cell_images_from_spacegroup(const SpaceGroup *sg)
int is_special_position(const Position &pos, double max_dist=0.8) const
int is_special_position(const Fractional &fpos, double max_dist) const
Counts nearby symmetry mates (0 = none, 3 = 4-fold axis, etc).
void set_from_parameters(const UnitCellParameters &p)
NearestImage find_nearest_pbc_image(const Fractional &fref, Fractional fpos, int image_idx=0) const
SMat33< double > reciprocal_metric_tensor() const
bool is_similar(const UnitCell &o, double rel, double deg) const
Box< Position > orthogonalize_box(const Box< Fractional > &f) const
Returns box containing fractional box (a cuboid in fractional coordinates can be a parallelepiped in ...
std::vector< NearestImage > find_nearest_pbc_images(const Fractional &fref, double dist, const Fractional &fpos, int image_idx) const
Fractional fractionalize_difference(const Position &delta) const
the inverse of orthogonalize_difference
Transform orthogonalize_transform(const FTransform &ftr) const
Position orthogonalize_in_pbc(const Position &ref, const Fractional &fpos) const
Crystallographic Symmetry. Space Groups. Coordinate Triplets.