16constexpr double pi() {
return 3.1415926535897932384626433832795029; }
20constexpr double hc() {
return 12398.4197386209; }
31constexpr double deg(
double angle) {
return 180.0 /
pi() * angle; }
32constexpr double rad(
double angle) {
return pi() / 180.0 * angle; }
34constexpr float sq(
float x) {
return x * x; }
35constexpr double sq(
double x) {
return x * x; }
41 return x - std::log(2) + std::log1p(std::exp(-2 * x));
44inline int iround(
double d) {
return static_cast<int>(std::round(
d)); }
47 double d = std::fabs(a - b);
50 return std::min(
d,
full -
d);
55 return std::min(std::max(v,
lo),
hi);
58template <
typename Real>
62 Vec3_() : x(0), y(0), z(0) {}
63 Vec3_(Real x_, Real y_, Real z_) : x(x_), y(y_), z(z_) {}
64 explicit Vec3_(std::array<int, 3> h) : x(h[0]), y(h[1]), z(h[2]) {}
71 default:
throw std::out_of_range(
"Vec3 index must be 0, 1 or 2.");
74 Real at(
int i)
const {
return const_cast<Vec3_*
>(
this)->at(i); }
76 Vec3_ operator-()
const {
return {-x, -y, -z}; }
77 Vec3_ operator-(
const Vec3_& o)
const {
return {x-o.x, y-o.y, z-o.z}; }
78 Vec3_ operator+(
const Vec3_& o)
const {
return {x+o.x, y+o.y, z+o.z}; }
79 Vec3_
operator*(Real d)
const {
return {x*d, y*d, z*d}; }
80 Vec3_ operator/(Real d)
const {
return *
this * (1.0/d); }
81 Vec3_& operator-=(
const Vec3_& o) { *
this = *
this - o;
return *
this; }
82 Vec3_& operator+=(
const Vec3_& o) { *
this = *
this + o;
return *
this; }
83 Vec3_&
operator*=(Real d) { *
this = *
this * d;
return *
this; }
84 Vec3_& operator/=(Real d) {
return operator*=(1.0/d); }
86 Vec3_ negated()
const {
return {-x, -y, -z}; }
87 Real dot(
const Vec3_& o)
const {
return x*o.x + y*o.y + z*o.z; }
88 Vec3_ cross(
const Vec3_& o)
const {
89 return {y*o.z - z*o.y, z*o.x - x*o.z, x*o.y - y*o.x};
91 Real length_sq()
const {
return x * x + y * y + z * z; }
92 Real length()
const {
return std::sqrt(length_sq()); }
93 Vec3_ changed_magnitude(Real m)
const {
return operator*(m / length()); }
94 Vec3_ normalized()
const {
return changed_magnitude(1.0); }
95 Real dist_sq(
const Vec3_& o)
const {
return (*
this - o).length_sq(); }
96 Real dist(
const Vec3_& o)
const {
return std::sqrt(dist_sq(o)); }
97 Real cos_angle(
const Vec3_& o)
const {
98 return dot(o) / std::sqrt(length_sq() * o.length_sq());
100 Real angle(
const Vec3_& o)
const {
101 return std::acos(
clamp(cos_angle(o), -1., 1.));
103 bool approx(
const Vec3_& o, Real epsilon)
const {
104 return std::fabs(x - o.x) <= epsilon &&
105 std::fabs(y - o.y) <= epsilon &&
106 std::fabs(z - o.z) <= epsilon;
108 bool has_nan()
const {
109 return std::isnan(x) || std::isnan(y) || std::isnan(z);
128 double a[3][3] = { {1.,0.,0.}, {0.,1.,0.}, {0.,0.,1.} };
138 double c1,
double c2,
double c3)
147 throw std::out_of_range(
"Mat33 row index must be 0, 1 or 2.");
148 return Vec3(a[
i][0], a[
i][1], a[
i][2]);
153 throw std::out_of_range(
"Mat33 column index must be 0, 1 or 2.");
154 return Vec3(a[0][
i], a[1][
i], a[2][
i]);
158 return Mat33(a[0][0] + b[0][0], a[0][1] + b[0][1], a[0][2] + b[0][2],
159 a[1][0] + b[1][0], a[1][1] + b[1][1], a[1][2] + b[1][2],
160 a[2][0] + b[2][0], a[2][1] + b[2][1], a[2][2] + b[2][2]);
163 return Mat33(a[0][0] - b[0][0], a[0][1] - b[0][1], a[0][2] - b[0][2],
164 a[1][0] - b[1][0], a[1][1] - b[1][1], a[1][2] - b[1][2],
165 a[2][0] - b[2][0], a[2][1] - b[2][1], a[2][2] - b[2][2]);
169 return {a[0][0] *
p.x + a[0][1] *
p.y + a[0][2] *
p.z,
170 a[1][0] *
p.x + a[1][1] *
p.y + a[1][2] *
p.z,
171 a[2][0] *
p.x + a[2][1] *
p.y + a[2][2] *
p.z};
174 return {a[0][0] *
p.x + a[1][0] *
p.y + a[2][0] *
p.z,
175 a[0][1] *
p.x + a[1][1] *
p.y + a[2][1] *
p.z,
176 a[0][2] *
p.x + a[1][2] *
p.y + a[2][2] *
p.z};
180 return Mat33(a[0][0] *
p.x, a[0][1] *
p.y, a[0][2] *
p.z,
181 a[1][0] *
p.x, a[1][1] *
p.y, a[1][2] *
p.z,
182 a[2][0] *
p.x, a[2][1] *
p.y, a[2][2] *
p.z);
186 for (
int i = 0;
i != 3; ++
i)
187 for (
int j = 0;
j != 3; ++
j)
188 r[
i][
j] = a[
i][0] * b[0][
j] + a[
i][1] * b[1][
j] + a[
i][2] * b[2][
j];
192 return Mat33(a[0][0], a[1][0], a[2][0],
193 a[0][1], a[1][1], a[2][1],
194 a[0][2], a[1][2], a[2][2]);
196 double trace()
const {
return a[0][0] + a[1][1] + a[2][2]; }
199 for (
int i = 0;
i < 3; ++
i)
200 for (
int j = 0;
j < 3; ++
j)
206 for (
int i = 0;
i < 3; ++
i)
207 for (
int j = 0;
j < 3; ++
j)
208 if (std::isnan(a[
i][
j]))
214 return a[0][0] * (a[1][1]*a[2][2] - a[2][1]*a[1][2]) +
215 a[0][1] * (a[1][2]*a[2][0] - a[2][2]*a[1][0]) +
216 a[0][2] * (a[1][0]*a[2][1] - a[2][0]*a[1][1]);
220 double inv_det = 1.0 / determinant();
221 inv[0][0] =
inv_det * (a[1][1] * a[2][2] - a[2][1] * a[1][2]);
222 inv[0][1] =
inv_det * (a[0][2] * a[2][1] - a[0][1] * a[2][2]);
223 inv[0][2] =
inv_det * (a[0][1] * a[1][2] - a[0][2] * a[1][1]);
224 inv[1][0] =
inv_det * (a[1][2] * a[2][0] - a[1][0] * a[2][2]);
225 inv[1][1] =
inv_det * (a[0][0] * a[2][2] - a[0][2] * a[2][0]);
226 inv[1][2] =
inv_det * (a[1][0] * a[0][2] - a[0][0] * a[1][2]);
227 inv[2][0] =
inv_det * (a[1][0] * a[2][1] - a[2][0] * a[1][1]);
228 inv[2][1] =
inv_det * (a[2][0] * a[0][1] - a[0][0] * a[2][1]);
229 inv[2][2] =
inv_det * (a[0][0] * a[1][1] - a[1][0] * a[0][1]);
233 return a[0][0] == 1 && a[0][1] == 0 && a[0][2] == 0 &&
234 a[1][0] == 0 && a[1][1] == 1 && a[1][2] == 0 &&
235 a[2][0] == 0 && a[2][1] == 0 && a[2][2] == 1;
239 return a[0][
i] * a[0][
j] + a[1][
i] * a[1][
j] + a[2][
i] * a[2][
j];
243 return a[1][0] == 0 && a[2][0] == 0 && a[2][1] == 0;
248 double a11 = 0, a12 = 0, a13 = 0;
249 double a22 = 0, a23 = 0;
253 if (
m.is_upper_triangular()) {
261 a11 = a12 = a13 = a22 = a23 = a33 =
NAN;
266 return {a11 *
p.x + a12 *
p.y + a13 *
p.z,
267 a22 *
p.y + a23 *
p.z,
274 T u11, u22, u33, u12, u13, u23;
278 std::array<T, 6>
elements_pdb()
const {
return {{u11, u22, u33, u12, u13, u23}}; }
279 std::array<T, 6>
elements_voigt()
const {
return {{u11, u22, u33, u23, u13, u12}}; }
282 return Mat33(u11, u12, u13, u12, u22, u23, u13, u23, u33);
287 T*
ptrs[9] = {&u11, &u12, &u13, &u12, &u22, &u23, &u13, &u23, &u33};
291 T trace()
const {
return u11 + u22 + u33; }
295 return u11 == 0 && u22 == 0 && u33 == 0 && u12 == 0 && u13 == 0 && u23 == 0;
299 u11 *= s; u22 *= s; u33 *= s; u12 *= s; u13 *= s; u23 *= s;
302 template<
typename Real>
304 return SMat33<Real>{u11*s, u22*s, u33*s, u12*s, u13*s, u23*s};
309 return {u11+
k, u22+
k, u33+
k, u12, u13, u23};
313 template<
typename VT>
315 return r.x *
r.x * u11 +
r.y *
r.y * u22 +
r.z *
r.z * u33 +
316 2 * (
r.x *
r.y * u12 +
r.x *
r.z * u13 +
r.y *
r.z * u23);
318 double r_u_r(
const std::array<int,3>&
h)
const {
320 return r_u_r(
Vec3(
h));
324 return {u11 *
p.x + u12 *
p.y + u13 *
p.z,
325 u12 *
p.x + u22 *
p.y + u23 *
p.z,
326 u13 *
p.x + u23 *
p.y + u33 *
p.z};
330 return {u11-
o.u11, u22-
o.u22, u33-
o.u33, u12-
o.u12, u13-
o.u13, u23-
o.u23};
333 return {u11+
o.u11, u22+
o.u22, u33+
o.u33, u12+
o.u12, u13+
o.u13, u23+
o.u23};
337 template<
typename Real=
double>
340 auto elem = [&](
int i,
int j) {
341 return static_cast<Real>(
342 m[
i][0] * (
m[
j][0] * u11 +
m[
j][1] * u12 +
m[
j][2] * u13) +
343 m[
i][1] * (
m[
j][0] * u12 +
m[
j][1] * u22 +
m[
j][2] * u23) +
344 m[
i][2] * (
m[
j][0] * u13 +
m[
j][1] * u23 +
m[
j][2] * u33));
347 elem(0, 1), elem(0, 2), elem(1, 2)};
351 return u11 * (u22*u33 - u23*u23) +
352 u12 * (u23*u13 - u33*u12) +
353 u13 * (u12*u23 - u13*u22);
368 return inverse_(determinant());
374 double p1 = u12*u12 + u13*u13 + u23*u23;
376 return {{u11, u22, u33}};
377 double q = (1./3.) * trace();
379 double p2 =
sq(b.u11) +
sq(b.u22) +
sq(b.u33) + 2 *
p1;
380 double p = std::sqrt((1./6.) *
p2);
381 double r = b.determinant() / ((1./3.) *
p2 *
p);
384 phi = (1./3.) *
pi();
386 phi = (1./3.) * std::acos(
r);
388 double eig3 =
q + 2 *
p * std::cos(
phi + 2./3.*
pi());
399 return {
minv,
minv.multiply(vec).negated()};
409 return mat.
is_identity() && vec.x == 0. && vec.y == 0. && vec.z == 0.;
414 return mat.
has_nan() || vec.has_nan();
422template<
typename Pos>
427 if (
p.x < minimum.x) minimum.x =
p.x;
428 if (
p.y < minimum.y) minimum.y =
p.y;
429 if (
p.z < minimum.z) minimum.z =
p.z;
430 if (
p.x > maximum.x) maximum.x =
p.x;
431 if (
p.y > maximum.y) maximum.y =
p.y;
432 if (
p.z > maximum.z) maximum.z =
p.z;
443typename std::enable_if<std::is_integral<T>::value,
bool>::type
444is_nan(T) {
return false; }
446typename std::enable_if<std::is_floating_point<T>::value,
bool>::type
447is_nan(T a) {
return std::isnan(a); }
450typename std::enable_if<std::is_integral<T>::value,
bool>::type
451is_same(T a, T b) {
return a == b; }
453typename std::enable_if<std::is_floating_point<T>::value,
bool>::type
454is_same(T a, T b) {
return std::isnan(b) ? std::isnan(a) : a == b; }
constexpr double deg(double angle)
constexpr double bohrradius()
constexpr T clamp(T v, T lo, T hi)
Vec3 rotate_about_axis(const Vec3 &v, const Vec3 &axis, double theta)
Rodrigues' rotation formula: rotate vector v about given axis of rotation (which must be a unit vecto...
constexpr double mott_bethe_const()
Vec3 operator*(double d, const Vec3 &v)
Op & operator*=(Op &a, const Op &b)
double angle_abs_diff(double a, double b, double full=360.0)
constexpr double rad(double angle)
constexpr float sq(float x)
double log_cosh(double x)
constexpr double u_to_b()
void extend(const Pos &p)
void add_margins(const Pos &p)
void add_margin(double m)
bool is_upper_triangular() const
Vec3 column_copy(int i) const
row_t & operator[](int i)
double determinant() const
Mat33 operator+(const Mat33 &b) const
Mat33 multiply(const Mat33 &b) const
Vec3 left_multiply(const Vec3 &p) const
Mat33(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3)
bool approx(const Mat33 &other, double epsilon) const
Mat33 multiply_by_diagonal(const Vec3 &p) const
const row_t & operator[](int i) const
Vec3 row_copy(int i) const
static Mat33 from_columns(const Vec3 &c1, const Vec3 &c2, const Vec3 &c3)
Vec3 multiply(const Vec3 &p) const
double column_dot(int i, int j) const
Mat33 operator-(const Mat33 &b) const
SMat33 operator+(const SMat33 &o) const
T & unchecked_ref(int i, int j)
std::array< T, 6 > elements_voigt() const
SMat33 operator-(const SMat33 &o) const
Vec3 multiply(const Vec3 &p) const
SMat33< Real > scaled(Real s) const
SMat33< Real > transformed_by(const Mat33 &m) const
std::array< double, 3 > calculate_eigenvalues() const
Based on https://en.wikipedia.org/wiki/Eigenvalue_algorithm To calculate both eigenvalues and eigenve...
double r_u_r(const std::array< int, 3 > &h) const
auto r_u_r(const Vec3_< VT > &r) const -> decltype(r.x+u11)
SMat33< T > added_kI(T k) const
std::array< T, 6 > elements_pdb() const
UpperTriangularMat33 & operator=(const Mat33 &m)
Vec3 multiply(const Vec3 &p) const
UpperTriangularMat33()=default