41 a = (a + 1) % n + n - 1;
51 return n == 1 || n == -1;
61 n = std::max(
int(std::floor(
exact)), 1);
66 int sign = n >
exact ? -1 : 1;
81 std::array<int, 3>
m = {{0, 0, 0}};
84 gops =
sg->operations();
90 for (
int i = 1;
i < 3; ++
i)
91 for (
int j = 0;
j <
i; ++
j)
103 for (
int i = 0;
i < 3; ++
i) {
119 std::array<int, 3>
apply(
int u,
int v,
int w)
const {
120 std::array<int, 3>
t;
122 for (
int i = 0;
i != 3; ++
i)
132 for (
int i = 0;
i != 3; ++
i)
134 fail(
"Grid not compatible with the space group " +
sg->xhm());
135 for (
int i = 1;
i != 3; ++
i)
136 for (
int j = 0;
j !=
i; ++
j)
138 fail(
"Grid must have the same size in symmetry-related directions");
142inline double lerp_(
double a,
double b,
double t) {
143 return a + (b - a) * t;
146std::complex<T> lerp_(std::complex<T> a, std::complex<T> b,
double t) {
147 return a + (b - a) * (
T) t;
156 return -0.5 * (a * u * ((u-2)*u + 1) - b * ((3*u - 5) * u*u + 2) +
157 u * (c * ((3*u - 4) * u - 1) -
d * (u-1) * u));
162 return a * (-1.5*u*u + 2*u - 0.5) + c * (-4.5*u*u + 4*u + 0.5)
163 + u * (4.5*b*u - 5*b + 1.5*
d*u -
d);
177 return {u * (1.0 /
nu), v * (1.0 /
nv), w * (1.0 /
nw)};
189 fail(
"grid can use symmetries only if it is setup in the XYZ order");
194 Op op =
so.add_centering(
co);
200 for (
int i = 0;
i != 3; ++
i)
201 for (
int j = 0;
j != 3; ++
j)
211 return size_t(w *
nv + v) *
nu + u;
213 size_t index_q(
size_t u,
size_t v,
size_t w)
const {
214 return (w *
nv + v) *
nu + u;
222 if (u >=
nu) u -=
nu;
else if (u < 0) u +=
nu;
223 if (v >=
nv) v -=
nv;
else if (v < 0) v +=
nv;
224 if (w >=
nw) w -=
nw;
else if (w < 0) w +=
nw;
230 return this->
index_q(u >= 0 ? u : u +
nu,
232 w >= 0 ? w : w +
nw);
249 fail(
"grid is empty");
264 int u = (
int)
d1.rem;
265 int v = (
int)
d2.rem;
266 int w = (
int)
d2.quot;
268 return {u, v, w, &
data.at(idx)};
273 std::fill(
data.begin(),
data.end(), value);
276 using Tsum =
typename std::conditional<std::is_integral<T>::value,
277 std::ptrdiff_t,
T>::type;
311template<
typename T=
float>
345 fail(
"Grids work only with the standard orientation of crystal frame (SCALEn)");
368 double alpha,
double beta,
double gamma) {
411 fail(
"grid is not fully setup");
431 double f = std::floor(x);
444 assert(u >= 0 && v >= 0 && w >= 0);
447 for (
int i = 0;
i < 2; ++
i) {
448 int wi = (
i == 0 || w + 1 !=
nw ? w +
i : 0);
450 int v2 = v + 1 !=
nv ? v + 1 : 0;
452 int u_add = u + 1 !=
nu ? 1 : -u;
457 return (
T) lerp_(
avg[0],
avg[1], zd);
469 std::array<std::array<std::array<T,4>,4>,4>
copy;
470 copy_4x4x4(x, y, z,
copy);
473 for (
int i = 0;
i < 4; ++
i) {
474 for (
int j = 0;
j < 4; ++
j)
475 a[
j] =
cubic_interpolation(z, s(
i,
j,0), s(
i,
j,1), s(
i,
j,2), s(
i,
j,3));
488 std::array<std::array<std::array<T,4>,4>,4>
copy;
489 copy_4x4x4(x, y, z,
copy);
493 for (
int i = 0;
i < 4; ++
i)
494 for (
int j = 0;
j < 4; ++
j)
495 a[
i][
j] =
cubic_interpolation(z, s(
i,
j,0), s(
i,
j,1), s(
i,
j,2), s(
i,
j,3));
496 for (
int i = 0;
i < 4; ++
i)
498 std::array<double, 4>
ret;
501 for (
int i = 0;
i < 4; ++
i)
504 for (
int i = 0;
i < 4; ++
i)
505 for (
int j = 0;
j < 4; ++
j)
506 a[
i][
j] =
cubic_interpolation(y, s(
i,0,
j), s(
i,1,
j), s(
i,2,
j), s(
i,3,
j));
507 for (
int i = 0;
i < 4; ++
i)
514 return {
r[0],
r[1] *
nu,
r[2] *
nv,
r[3] *
nw};
517 void copy_4x4x4(
double& x,
double& y,
double& z,
518 std::array<std::array<std::array<T,4>,4>,4>&
copy)
const {
529 indices[2] = t + 2 == nt ? t + 1 : 0;
530 indices[3] = t + 2 == nt ? 0 : 1;
533 int u_indices[4], v_indices[4], w_indices[4];
534 prepare_indices(x,
nu, u_indices);
535 prepare_indices(y,
nv, v_indices);
536 prepare_indices(z,
nw, w_indices);
537 for (
int i = 0; i < 4; ++i)
538 for (
int j = 0; j < 4; ++j)
539 for (
int k = 0; k < 4; ++k)
540 copy[i][j][k] = this->
get_value_q(u_indices[i], v_indices[j], w_indices[k]);
550 throw std::invalid_argument(
"interpolation \"order\" must 0, 1 or 3");
559 fail(
"get_subarray() is for Grids in XYZ order");
561 for (
int w = 0; w <
shape[2]; w++) {
563 for (
int v = 0; v <
shape[1]; v++) {
585 fail(
"set_subarray() is for Grids in XYZ order");
587 for (
int w = 0; w <
shape[2]; w++) {
589 for (
int v = 0; v <
shape[1]; v++) {
608 template <
bool UsePbc>
614 fail(
"grid operation failed: radius bigger than half the unit cell?");
618 du = std::min(
du,
nu - 1);
619 dv = std::min(
dv,
nv - 1);
620 dw = std::min(
dw,
nw - 1);
625 template <
bool UsePbc,
typename Func>
650 auto wrap = [](
int&
q,
int nq) {
if (
UsePbc &&
q ==
nq)
q = 0; };
664 func(*
t, dist_sq,
delta, u, v, w);
680 template <
bool UsePbc,
typename Func>
688 template <
bool UsePbc,
typename Func>
696 [&](
T& ref,
double d2,
const Position&,
int,
int,
int) { func(ref,
d2); },
719 template<
typename Func>
724 template<
typename Func>
728 std::vector<size_t>
mates(
ops.size(), 0);
731 for (
int w = 0; w !=
nw; ++w)
732 for (
int v = 0; v !=
nv; ++v)
733 for (
int u = 0; u !=
nu; ++u, ++idx) {
737 for (
size_t k = 0;
k <
ops.size(); ++
k) {
738 std::array<int,3>
t =
ops[
k].apply(u, v, w);
744 fail(
"grid size is not compatible with space group");
745 value = func(value,
data[
k]);
759 symmetrize([](
T a,
T b) {
return (a < b || !(b == b)) ? a : b; });
762 symmetrize([](
T a,
T b) {
return (a > b || !(b == b)) ? a : b; });
765 symmetrize([](
T a,
T b) {
return (std::abs(a) > std::abs(b) || !(b == b)) ? a : b; });
798 for (
int w = 0; w !=
dest.nw; ++w)
799 for (
int v = 0; v !=
dest.nv; ++v)
800 for (
int u = 0; u !=
dest.nu; ++u, ++idx) {
809 if (a.data.size() != b.data.size() || a.nu != b.nu || a.nv != b.nv || a.nw != b.nw)
810 fail(
"calculate_correlation(): grids have different sizes");
812 for (
size_t i = 0;
i != a.data.size(); ++
i)
813 if (!std::isnan(a.data[
i]) && !std::isnan(b.data[
i]))
fail(), unreachable() and __declspec/__attribute__ macros
AxisOrder
Order of grid axis.
double cubic_interpolation_der(double u, double a, double b, double c, double d)
df/du (from Wolfram Alpha)
void interpolate_grid(Grid< T > &dest, const Grid< T > &src, const Transform &tr, int order=1)
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(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)
Statistics utilities: classes Covariance, Correlation, DataStats.
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
T trilinear_interpolation(const Fractional &fctr) const
T interpolate_value(const Fractional &f, int order=1) const
void set_value(int u, int v, int w, T x)
Point get_nearest_point(const Position &pos)
T trilinear_interpolation(double x, double y, double z) const
https://en.wikipedia.org/wiki/Trilinear_interpolation x,y,z are grid coordinates (x=1....
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
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 trilinear_interpolation(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 setup_from(const S &st, double approx_spacing=0)
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....
T interpolate_value(const Position &ctr, int order=1) const
void change_values(T old_value, T new_value)
Change all occurrences of old_value to 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)
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().
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
Crystallographic Symmetry. Space Groups. Coordinate Triplets.