42 a = (a + 1) % n + n - 1;
52 return n == 1 || n == -1;
62 n = std::max(
int(std::floor(
exact)), 1);
67 int sign = n >
exact ? -1 : 1;
82 std::array<int, 3>
m = {{0, 0, 0}};
85 gops =
sg->operations();
87 for (
int i = 0;
i != 3; ++
i) {
88 for (
int j = 0;
j <
i; ++
j)
100 for (
int i = 1;
i != 3; ++
i)
101 for (
int j = 0;
j !=
i; ++
j)
112 std::array<int, 3>
apply(
int u,
int v,
int w)
const {
113 std::array<int, 3>
t;
115 for (
int i = 0;
i != 3; ++
i)
125 for (
int i = 0;
i != 3; ++
i)
127 fail(
"Grid not compatible with the space group " +
sg->xhm());
128 for (
int i = 1;
i != 3; ++
i)
129 for (
int j = 0;
j !=
i; ++
j)
131 fail(
"Grid must have the same size in symmetry-related directions");
135inline double lerp_(
double a,
double b,
double t) {
136 return a + (b - a) * t;
139std::complex<T> lerp_(std::complex<T> a, std::complex<T> b,
double t) {
140 return a + (b - a) * (
T) t;
149 return -0.5 * (a * u * ((u-2)*u + 1) - b * ((3*u - 5) * u*u + 2) +
150 u * (c * ((3*u - 4) * u - 1) -
d * (u-1) * u));
155 return a * (-1.5*u*u + 2*u - 0.5) + c * (-4.5*u*u + 4*u + 0.5)
156 + u * (4.5*b*u - 5*b + 1.5*
d*u -
d);
170 return {u * (1.0 /
nu), v * (1.0 /
nv), w * (1.0 /
nw)};
182 fail(
"grid can use symmetries only if it is setup in the XYZ order");
187 Op op =
so.add_centering(
co);
193 for (
int i = 0;
i != 3; ++
i)
194 for (
int j = 0;
j != 3; ++
j)
204 return size_t(w *
nv + v) *
nu + u;
212 if (u >=
nu) u -=
nu;
else if (u < 0) u +=
nu;
213 if (v >=
nv) v -=
nv;
else if (v < 0) v +=
nv;
214 if (w >=
nw) w -=
nw;
else if (w < 0) w +=
nw;
220 return this->
index_q(u >= 0 ? u : u +
nu,
222 w >= 0 ? w : w +
nw);
239 fail(
"grid is empty");
254 int u = (
int)
d1.rem;
255 int v = (
int)
d2.rem;
256 int w = (
int)
d2.quot;
258 return {u, v, w, &
data.at(idx)};
263 std::fill(
data.begin(),
data.end(), value);
266 using Tsum =
typename std::conditional<std::is_integral<T>::value,
267 std::ptrdiff_t,
T>::type;
301template<
typename T=
float>
335 fail(
"Grids work only with the standard orientation of crystal frame (SCALEn)");
362 double alpha,
double beta,
double gamma) {
404 fail(
"grid is not fully setup");
424 double f = std::floor(x);
437 assert(u >= 0 && v >= 0 && w >= 0);
440 for (
int i = 0;
i < 2; ++
i) {
441 int wi = (
i == 0 || w + 1 !=
nw ? w +
i : 0);
443 int v2 = v + 1 !=
nv ? v + 1 : 0;
445 int u_add = u + 1 !=
nu ? 1 : -u;
450 return (
T) lerp_(
avg[0],
avg[1], zd);
462 std::array<std::array<std::array<T,4>,4>,4>
copy;
463 copy_4x4x4(x, y, z,
copy);
466 for (
int i = 0;
i < 4; ++
i) {
467 for (
int j = 0;
j < 4; ++
j)
468 a[
j] =
cubic_interpolation(z, s(
i,
j,0), s(
i,
j,1), s(
i,
j,2), s(
i,
j,3));
481 std::array<std::array<std::array<T,4>,4>,4>
copy;
482 copy_4x4x4(x, y, z,
copy);
486 for (
int i = 0;
i < 4; ++
i)
487 for (
int j = 0;
j < 4; ++
j)
488 a[
i][
j] =
cubic_interpolation(z, s(
i,
j,0), s(
i,
j,1), s(
i,
j,2), s(
i,
j,3));
489 for (
int i = 0;
i < 4; ++
i)
491 std::array<double, 4>
ret;
494 for (
int i = 0;
i < 4; ++
i)
497 for (
int i = 0;
i < 4; ++
i)
498 for (
int j = 0;
j < 4; ++
j)
499 a[
i][
j] =
cubic_interpolation(y, s(
i,0,
j), s(
i,1,
j), s(
i,2,
j), s(
i,3,
j));
500 for (
int i = 0;
i < 4; ++
i)
507 return {
r[0],
r[1] *
nu,
r[2] *
nv,
r[3] *
nw};
510 void copy_4x4x4(
double& x,
double& y,
double& z,
511 std::array<std::array<std::array<T,4>,4>,4>&
copy)
const {
522 indices[2] = t + 2 == nt ? t + 1 : 0;
523 indices[3] = t + 2 == nt ? 0 : 1;
526 int u_indices[4], v_indices[4], w_indices[4];
527 prepare_indices(x,
nu, u_indices);
528 prepare_indices(y,
nv, v_indices);
529 prepare_indices(z,
nw, w_indices);
530 for (
int i = 0; i < 4; ++i)
531 for (
int j = 0; j < 4; ++j)
532 for (
int k = 0; k < 4; ++k)
533 copy[i][j][k] = this->
get_value_q(u_indices[i], v_indices[j], w_indices[k]);
543 throw std::invalid_argument(
"interpolation \"order\" must 1, 2 or 3");
549 fail(
"get_subarray() is for Grids in XYZ order");
551 for (
int w = 0; w <
shape[2]; w++) {
553 for (
int v = 0; v <
shape[1]; v++) {
575 fail(
"set_subarray() is for Grids in XYZ order");
577 for (
int w = 0; w <
shape[2]; w++) {
579 for (
int v = 0; v <
shape[1]; v++) {
598 template <
bool UsePbc>
604 fail(
"grid operation failed: radius bigger than half the unit cell?");
608 du = std::min(
du,
nu - 1);
609 dv = std::min(
dv,
nv - 1);
610 dw = std::min(
dw,
nw - 1);
615 template <
bool UsePbc,
typename Func>
640 auto wrap = [](
int&
q,
int nq) {
if (
UsePbc &&
q ==
nq)
q = 0; };
654 func(*
t, dist_sq,
delta, u, v, w);
670 template <
bool UsePbc,
typename Func>
678 template <
bool UsePbc,
typename Func>
686 [&](
T& ref,
double d2,
const Position&,
int,
int,
int) { func(ref,
d2); },
708 template<
typename Func>
713 template<
typename Func>
717 std::vector<size_t>
mates(
ops.size(), 0);
720 for (
int w = 0; w !=
nw; ++w)
721 for (
int v = 0; v !=
nv; ++v)
722 for (
int u = 0; u !=
nu; ++u, ++idx) {
726 for (
size_t k = 0;
k <
ops.size(); ++
k) {
727 std::array<int,3>
t =
ops[
k].apply(u, v, w);
733 fail(
"grid size is not compatible with space group");
734 value = func(value,
data[
k]);
748 symmetrize([](
T a,
T b) {
return (a < b || !(b == b)) ? a : b; });
751 symmetrize([](
T a,
T b) {
return (a > b || !(b == b)) ? a : b; });
754 symmetrize([](
T a,
T b) {
return (std::abs(a) > std::abs(b) || !(b == b)) ? a : b; });
781 dest.check_not_empty();
783 for (
int w = 0; w <
dest.nw; ++w)
784 for (
int v = 0; v <
dest.nv; ++v)
785 for (
int u = 0; u <
dest.nu; ++u, ++idx) {
795 if (a.data.size() != b.data.size() || a.nu != b.nu || a.nv != b.nv || a.nw != b.nw)
796 fail(
"calculate_correlation(): grids have different sizes");
798 for (
size_t i = 0;
i != a.data.size(); ++
i)
799 if (!std::isnan(a.data[
i]) && !std::isnan(b.data[
i]))
AxisOrder
Order of grid axis.
double cubic_interpolation_der(double u, double a, double b, double c, double d)
df/du (from Wolfram Alpha)
bool has_small_factorization(int n)
double cubic_interpolation(double u, double a, double b, double c, double d)
Catmull–Rom spline interpolation.
int round_with_small_factorization(double exact, GridSizeRounding rounding)
DataStats calculate_data_statistics(const std::vector< T > &data)
constexpr float sq(float x)
std::array< int, 3 > good_grid_size(const std::array< double, 3 > &limit, GridSizeRounding rounding, const SpaceGroup *sg)
void check_grid_factors(const SpaceGroup *sg, std::array< int, 3 > size)
void fail(const std::string &msg)
Correlation calculate_correlation(const GridBase< T > &a, const GridBase< T > &b)
void add_point(double x, double y)
grid coordinates (modulo size) and a pointer to value
GridBase< T >::Point operator*()
iterator(GridBase &parent_, size_t index_)
bool operator!=(const iterator &o) const
bool operator==(const iterator &o) const
A common subset of Grid and ReciprocalGrid.
T get_value_q(int u, int v, int w) const
void check_not_empty() const
size_t point_to_index(const Point &p) const
typename std::conditional< std::is_integral< T >::value, std::ptrdiff_t, T >::type Tsum
void set_size_without_checking(int nu_, int nv_, int nw_)
Point index_to_point(size_t idx)
std::array< int, 3 > apply(int u, int v, int w) const
double min_spacing() const
void set_value(int u, int v, int w, T x)
Point get_nearest_point(const Position &pos)
void setup_from(const S &st, double approx_spacing)
void set_unit_cell(double a, double b, double c, double alpha, double beta, double gamma)
void set_size_from_spacing(double approx_spacing, GridSizeRounding rounding)
void symmetrize_sum()
multiplies grid points on special position
T interpolate(const Fractional &f, int order) const
size_t get_nearest_index(const Fractional &f)
typename GridBase< T >::Point Point
T get_value(int u, int v, int w) const
returns data[index_s(u, v, w)]
T interpolate_value(const Position &ctr) const
void symmetrize_using_ops(const std::vector< GridOp > &ops, Func func)
double spacing[3]
spacing between virtual planes, not between points
void copy_metadata_from(const GridMeta &g)
copy unit_cell, spacegroup, nu, nv, nw, axis_order and set spacing
void do_use_points_in_box(const Fractional &fctr, int du, int dv, int dw, Func &&func, double radius=INFINITY)
Point get_point(int u, int v, int w)
Point stores normalizes indices (not the original u,v,w).
void set_size_without_checking(int nu_, int nv_, int nw_)
void calculate_spacing()
set spacing and orth_n
static double grid_modulo(double x, int n, int *iptr)
void set_points_around(const Position &ctr, double radius, T value, bool use_pbc=true)
void get_subarray(T *dest, std::array< int, 3 > start, std::array< int, 3 > shape) const
Fractional point_to_fractional(const Point &p) const
Point stores normalized indices, so fractional coordinates are in [0,1).
void use_points_in_box(const Fractional &fctr, int du, int dv, int dw, Func &&func, bool fail_on_too_large_radius=true, double radius=INFINITY)
void normalize()
scale the data to get mean == 0 and rmsd == 1 (doesn't work for T=complex)
Point get_nearest_point(const Fractional &f)
std::array< double, 4 > tricubic_interpolation_der(const Fractional &fctr) const
Position point_to_position(const Point &p) const
UpperTriangularMat33 orth_n
unit_cell.orth.mat columns divided by nu, nv, nw
double tricubic_interpolation(const Position &ctr) const
std::array< double, 4 > tricubic_interpolation_der(double x, double y, double z) const
returns the same as above + derivatives df/dx, df/dy, df/dz
void symmetrize_abs_max()
void set_unit_cell(const UnitCell &cell)
void symmetrize(Func func)
Use.
double tricubic_interpolation(const Fractional &fctr) const
double tricubic_interpolation(double x, double y, double z) const
https://en.wikipedia.org/wiki/Tricubic_interpolation x,y,z are grid coordinates (x=1....
void change_values(T old_value, T new_value)
void set_size(int nu_, int nv_, int nw_)
void set_subarray(const T *src, std::array< int, 3 > start, std::array< int, 3 > shape)
void use_points_around(const Fractional &fctr, double radius, Func &&func, bool fail_on_too_large_radius=true)
void resample_to(Grid< T > &dest, int order) const
size_t index_s(int u, int v, int w) const
Returns index in data array for (u,v,w). Safe but slower than index_q().
T interpolate_value(double x, double y, double z) const
https://en.wikipedia.org/wiki/Trilinear_interpolation x,y,z are grid coordinates (x=1....
T interpolate_value(const Fractional &fctr) const
void check_size_for_points_in_box(int &du, int &dv, int &dw, bool fail_on_too_large_radius) const
void symmetrize_nondefault(T default_)
std::vector< Op > sym_ops
std::array< int, 3 > find_grid_factors() const
std::vector< Op::Tran > cen_ops
bool are_directions_symmetry_related(int u, int v) const
bool is_upper_triangular() const
Mat33 multiply_by_diagonal(const Vec3 &p) const
std::array< std::array< int, 3 >, 3 > Rot
std::array< int, 3 > Tran
static constexpr Op identity()
Coordinates in Angstroms - orthogonal (Cartesian) coordinates.
double ar
reciprocal parameters a*, b*, c*, alpha*, beta*, gamma*
Fractional fractionalize(const Position &o) const
void set(double a_, double b_, double c_, double alpha_, double beta_, double gamma_)
Position orthogonalize(const Fractional &f) const
Vec3 multiply(const Vec3 &p) const