SIRIUS 7.5.0
Electronic structure library and applications
r3.hpp
Go to the documentation of this file.
1// Copyright (c) 2013-2017 Anton Kozhevnikov, Thomas Schulthess
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
5// the following conditions are met:
6//
7// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
8// following disclaimer.
9// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
10// and the following disclaimer in the documentation and/or other materials provided with the distribution.
11//
12// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
13// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
15// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
16// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
18// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
20/** \file r3.hpp
21 *
22 * \brief Simple classes and functions to work with vectors and matrices of the R^3 space.
23 */
24
25#ifndef __R3_HPP__
26#define __R3_HPP__
27
28#include <cassert>
29#include <cmath>
30#include <array>
31#include <vector>
32#include <ostream>
33#include <initializer_list>
34#include <stdexcept>
35#include <sstream>
36
37namespace sirius {
38
39/// Work with 3D vectors and matrices.
40namespace r3 {
41
42/// Simple implementation of 3d vector.
43template <typename T>
44class vector : public std::array<T, 3>
45{
46 public:
47 /// Create zero vector
49 {
50 (*this) = {0, 0, 0};
51 }
52
53 /// Create arbitrary vector.
54 vector(T x, T y, T z)
55 {
56 (*this) = {x, y, z};
57 }
58
59 /// Create from std::initializer_list.
60 vector(std::initializer_list<T> v__)
61 {
62 assert(v__.size() == 3);
63 for (int x : {0, 1, 2}) {
64 (*this)[x] = v__.begin()[x];
65 }
66 }
67
68 vector& operator=(std::initializer_list<T> v__)
69 {
70 assert(v__.size() == 3);
71 for (int x : {0, 1, 2}) {
72 (*this)[x] = v__.begin()[x];
73 }
74 return *this;
75 }
76
77 /// Create from std::vector.
78 vector(std::vector<T> const& v__)
79 {
80 assert(v__.size() == 3);
81 for (int x : {0, 1, 2}) {
82 (*this)[x] = v__[x];
83 }
84 }
85
86 vector& operator=(std::vector<T> const& v__)
87 {
88 assert(v__.size() == 3);
89 for (int x : {0, 1, 2}) {
90 (*this)[x] = v__[x];
91 }
92 return *this;
93 }
94
95 /// Create from raw pointer.
96 vector(T const* ptr__)
97 {
98 for (int x : {0, 1, 2}) {
99 (*this)[x] = ptr__[x];
100 }
101 }
102
103 /// Create from array.
104 vector(std::array<T, 3> v__)
105 {
106 for (int x : {0, 1, 2}) {
107 (*this)[x] = v__[x];
108 }
109 }
110
111 /// Copy constructor.
112 vector(vector<T> const& vec__)
113 {
114 for (int x : {0, 1, 2}) {
115 (*this)[x] = vec__[x];
116 }
117 }
118
119 /// Return L1 norm of the vector.
120 inline T l1norm() const
121 {
122 return std::abs((*this)[0]) + std::abs((*this)[1]) + std::abs((*this)[2]);
123 }
124
125 /// Return vector length (L2 norm).
126 inline double length() const
127 {
128 return std::sqrt(this->length2());
129 }
130
131 /// Return square length of the vector.
132 inline double length2() const
133 {
134 return static_cast<double>(std::pow((*this)[0], 2) + std::pow((*this)[1], 2) + std::pow((*this)[2], 2));
135 }
136
137 inline vector<T>& operator+=(vector<T> const& b)
138 {
139 for (int x : {0, 1, 2}) {
140 (*this)[x] += b[x];
141 }
142 return *this;
143 }
144
145 inline vector<T>& operator-=(vector<T> const& b)
146 {
147 for (int x : {0, 1, 2}) {
148 (*this)[x] -= b[x];
149 }
150 return *this;
151 }
152
153};
154
155template <typename T, typename U>
156inline vector<decltype(T{} + U{})>
157operator+(vector<T> const& a, vector<U> const& b)
158{
159 vector<decltype(T{} + U{})> c;
160 for (int x : {0, 1, 2}) {
161 c[x] = a[x] + b[x];
162 }
163 return c;
164}
165
166template <typename T, typename U>
167inline vector<decltype(T{} - U{})>
168operator-(vector<T> const& a, vector<U> const& b)
169{
170 vector<decltype(T{} - U{})> c;
171 for (int x : {0, 1, 2}) {
172 c[x] = a[x] - b[x];
173 }
174 return c;
175}
176
177template <typename T, typename U>
178inline std::enable_if_t<std::is_scalar<U>::value, vector<decltype(T{} * U{})>>
179operator*(vector<T> const& vec, U p)
180{
181 vector<decltype(T{} * U{})> a;
182 for (int x : {0, 1, 2}) {
183 a[x] = vec[x] * p;
184 }
185 return a;
186}
187
188template <typename T, typename U>
189inline std::enable_if_t<std::is_scalar<U>::value, vector<decltype(T{} * U{})>>
190operator*(U p, vector<T> const& vec)
191{
192 return vec * p;
193}
194
195template <typename T, typename U>
196inline std::enable_if_t<std::is_scalar<U>::value, vector<decltype(T{} * U{})>>
197operator/(vector<T> const& vec, U p)
198{
199 vector<decltype(T{} * U{})> a;
200 for (int x : {0, 1, 2}) {
201 a[x] = vec[x] / p;
202 }
203 return a;
204}
205
206template <typename T, typename U>
207inline auto dot(vector<T> const a, vector<U> const b) -> decltype(T{} * U{})
208{
209 return (a[0] * b[0] + a[1] * b[1] + a[2] * b[2]);
210}
211
212template <typename T>
213inline auto cross(vector<T> const a, vector<T> const b)
214{
215 vector<T> res;
216 res[0] = a[1] * b[2] - a[2] * b[1];
217 res[1] = a[2] * b[0] - a[0] * b[2];
218 res[2] = a[0] * b[1] - a[1] * b[0];
219 return res;
220}
221
222template <typename T>
223std::ostream& operator<<(std::ostream& out, r3::vector<T> const& v)
224{
225 out << "{" << v[0] << ", " << v[1] << ", " << v[2] << "}";
226 return out;
227}
228
229/// Handling of a 3x3 matrix of numerical data types.
230template <typename T>
232{
233 private:
234 /// Store matrix \f$ M_{ij} \f$ as <tt>mtrx[i][j]</tt>.
235 T mtrx_[3][3];
236
237 public:
238 template <typename U>
239 friend class matrix;
240
241 /// Construct a zero matrix.
243 {
244 this->zero();
245 }
246
247 /// Construct matrix form plain 3x3 array.
248 matrix(T mtrx__[3][3])
249 {
250 for (int i = 0; i < 3; i++) {
251 for (int j = 0; j < 3; j++) {
252 mtrx_[i][j] = mtrx__[i][j];
253 }
254 }
255 }
256
257 /// Construct matrix from std::vector.
258 matrix(std::vector<std::vector<T>> src__)
259 {
260 for (int i = 0; i < 3; i++) {
261 for (int j = 0; j < 3; j++) {
262 mtrx_[i][j] = src__[i][j];
263 }
264 }
265 }
266
267 matrix(std::array<std::array<T, 3>, 3> src__)
268 {
269 for (int i = 0; i < 3; i++) {
270 for (int j = 0; j < 3; j++) {
271 mtrx_[i][j] = src__[i][j];
272 }
273 }
274 }
275
276 /// Copy constructor.
277 template <typename U>
278 matrix(matrix<U> const& src__)
279 {
280 for (int i = 0; i < 3; i++) {
281 for (int j = 0; j < 3; j++) {
282 mtrx_[i][j] = src__.mtrx_[i][j];
283 }
284 }
285 }
286
287 /// Construct matrix form std::initializer_list.
288 matrix(std::initializer_list<std::initializer_list<T>> mtrx__)
289 {
290 for (int i : {0, 1, 2}) {
291 for (int j : {0, 1, 2}) {
292 mtrx_[i][j] = mtrx__.begin()[i].begin()[j];
293 }
294 }
295 }
296
297 /// Assignment operator.
299 {
300 if (this != &rhs) {
301 for (int i = 0; i < 3; i++) {
302 for (int j = 0; j < 3; j++) {
303 this->mtrx_[i][j] = rhs.mtrx_[i][j];
304 }
305 }
306 }
307 return *this;
308 }
309
310 inline T& operator()(const int i, const int j)
311 {
312 return mtrx_[i][j];
313 }
314
315 inline T const& operator()(const int i, const int j) const
316 {
317 return mtrx_[i][j];
318 }
319
320 /// Sum of two matrices.
321 template <typename U>
322 inline auto operator+(matrix<U> const& b) const
323 {
324 matrix<decltype(T{} + U{})> a;
325 for (int i = 0; i < 3; i++) {
326 for (int j = 0; j < 3; j++) {
327 a(i, j) = (*this)(i, j) + b(i, j);
328 }
329 }
330 return a;
331 }
332
333 /// += operator
334 template <typename U>
335 inline auto& operator+=(matrix<U> const& b)
336 {
337 for (int i = 0; i < 3; i++) {
338 for (int j = 0; j < 3; j++) {
339 (*this)(i, j) += b(i, j);
340 }
341 }
342 return *this;
343 }
344
345 /// Multiply matrix by a scalar number.
346 template <typename U>
347 inline auto& operator*=(U p)
348 {
349 for (int i = 0; i < 3; i++) {
350 for (int j = 0; j < 3; j++) {
351 (*this)(i, j) *= p;
352 }
353 }
354 return *this;
355 }
356
357 /// Return determinant of a matrix.
358 inline T det() const
359 {
360 return (mtrx_[0][2] * (mtrx_[1][0] * mtrx_[2][1] - mtrx_[1][1] * mtrx_[2][0]) +
361 mtrx_[0][1] * (mtrx_[1][2] * mtrx_[2][0] - mtrx_[1][0] * mtrx_[2][2]) +
362 mtrx_[0][0] * (mtrx_[1][1] * mtrx_[2][2] - mtrx_[1][2] * mtrx_[2][1]));
363 }
364
365 inline void zero()
366 {
367 std::fill(&mtrx_[0][0], &mtrx_[0][0] + 9, 0);
368 }
369};
370
371/// Multiply matrix by a scalar number.
372template <typename T, typename U>
373inline std::enable_if_t<std::is_scalar<U>::value, matrix<decltype(T{} * U{})>> operator*(matrix<T> const& a__, U p__)
374{
375 matrix<decltype(T{} * U{})> c;
376 for (int i = 0; i < 3; i++) {
377 for (int j = 0; j < 3; j++) {
378 c(i, j) = a__(i, j) * p__;
379 }
380 }
381 return c;
382}
383
384template <typename T, typename U>
385inline std::enable_if_t<std::is_scalar<U>::value, matrix<decltype(T{} * U{})>> operator*(U p__, matrix<T> const& a__)
386{
387 return a__ * p__;
388}
389
390inline bool operator==(matrix<int> const& a__, matrix<int> const& b__)
391{
392 for (int i = 0; i < 3; i++) {
393 for (int j = 0; j < 3; j++) {
394 if (a__(i, j) != b__(i, j)) {
395 return false;
396 }
397 }
398 }
399 return true;
400}
401
402/// Multiply two matrices.
403template <typename T, typename U>
404inline auto dot(matrix<T> const& a__, matrix<U> const& b__)
405{
406 matrix<decltype(T{} * U{})> c;
407 for (int i = 0; i < 3; i++) {
408 for (int j = 0; j < 3; j++) {
409 for (int k = 0; k < 3; k++) {
410 c(i, j) += a__(i, k) * b__(k, j);
411 }
412 }
413 }
414 return c;
415}
416
417/// Matrix-vector multiplication.
418template <typename T, typename U>
419inline auto dot(matrix<T> const& m__, vector<U> const& b__)
420{
421 vector<decltype(T{} * U{})> a;
422 for (int i = 0; i < 3; i++) {
423 for (int j = 0; j < 3; j++) {
424 a[i] += m__(i, j) * b__[j];
425 }
426 }
427 return a;
428}
429
430/// Vector-matrix multiplication.
431template <typename T, typename U>
432inline auto dot(vector<U> const& b__, matrix<T> const& m__)
433{
434 vector<decltype(T{} * U{})> a;
435 for (int i = 0; i < 3; i++) {
436 for (int j = 0; j < 3; j++) {
437 a[i] += b__[j] * m__(j, i);
438 }
439 }
440 return a;
441}
442
443/// Return transpose of the matrix.
444template <typename T>
445inline auto transpose(matrix<T> src)
446{
447 matrix<T> mtrx;
448 for (int i = 0; i < 3; i++) {
449 for (int j = 0; j < 3; j++) {
450 mtrx(i, j) = src(j, i);
451 }
452 }
453 return mtrx;
454}
455
456template <typename T>
457inline auto inverse_aux(matrix<T> src)
458{
459 matrix<T> mtrx;
460
461 mtrx(0, 0) = (src(1, 1) * src(2, 2) - src(1, 2) * src(2, 1));
462 mtrx(0, 1) = (src(0, 2) * src(2, 1) - src(0, 1) * src(2, 2));
463 mtrx(0, 2) = (src(0, 1) * src(1, 2) - src(0, 2) * src(1, 1));
464 mtrx(1, 0) = (src(1, 2) * src(2, 0) - src(1, 0) * src(2, 2));
465 mtrx(1, 1) = (src(0, 0) * src(2, 2) - src(0, 2) * src(2, 0));
466 mtrx(1, 2) = (src(0, 2) * src(1, 0) - src(0, 0) * src(1, 2));
467 mtrx(2, 0) = (src(1, 0) * src(2, 1) - src(1, 1) * src(2, 0));
468 mtrx(2, 1) = (src(0, 1) * src(2, 0) - src(0, 0) * src(2, 1));
469 mtrx(2, 2) = (src(0, 0) * src(1, 1) - src(0, 1) * src(1, 0));
470
471 return mtrx;
472}
473
474/// Return inverse of the integer matrix
475inline auto inverse(matrix<int> src)
476{
477 int t1 = src.det();
478 if (std::abs(t1) != 1) {
479 throw std::runtime_error("integer matrix can't be inverted");
480 }
481 return inverse_aux(src) * t1;
482}
483
484/// Return inverse of the matrix.
485template <typename T>
486inline auto inverse(matrix<T> src)
487{
488 T t1 = src.det();
489
490 if (std::abs(t1) < 1e-10) {
491 throw std::runtime_error("matrix is degenerate");
492 }
493
494 return inverse_aux(src) * (1.0 / t1);
495}
496
497template <typename T>
498inline std::ostream& operator<<(std::ostream& out, matrix<T> const& v)
499{
500 out << "{";
501 for (int i = 0; i < 3; i++) {
502 out << "{";
503 for (int j = 0; j < 3; j++) {
504 out << v(i, j);
505 if (j != 2) {
506 out << ", ";
507 }
508 }
509 out << "}";
510 if (i != 2) {
511 out << ",";
512 } else {
513 out << "}";
514 }
515 }
516 return out;
517}
518
519/// Reduce the coordinates to the first unit cell.
520/** Split the input vector in lattice coordinates to the sum r0 + T, where T is the lattice translation
521 * vector (three integers) and r0 is the vector within the first unit cell with coordinates in [0, 1) range. */
522inline auto
524{
525 const double eps{1e-9};
526
527 std::pair<vector<double>, vector<int>> v;
528
529 v.first = coord__;
530 for (int i = 0; i < 3; i++) {
531 v.second[i] = (int)floor(v.first[i]);
532 v.first[i] -= v.second[i];
533 if (v.first[i] < -eps || v.first[i] > 1.0 + eps) {
534 std::stringstream s;
535 s << "wrong fractional coordinates" << std::endl
536 << v.first[0] << " " << v.first[1] << " " << v.first[2];
537 throw std::runtime_error(s.str());
538 }
539 if (v.first[i] < 0) {
540 v.first[i] = 0;
541 }
542 if (v.first[i] >= (1 - eps)) {
543 v.first[i] = 0;
544 v.second[i] += 1;
545 }
546 if (v.first[i] < 0 || v.first[i] >= 1) {
547 std::stringstream s;
548 s << "wrong fractional coordinates" << std::endl
549 << v.first[0] << " " << v.first[1] << " " << v.first[2];
550 throw std::runtime_error(s.str());
551 }
552 }
553 for (int x : {0, 1, 2}) {
554 if (std::abs(coord__[x] - (v.first[x] + v.second[x])) > eps) {
555 std::stringstream s;
556 s << "wrong coordinate reduction" << std::endl
557 << " original coord: " << coord__ << std::endl
558 << " reduced coord: " << v.first << std::endl
559 << " T: " << v.second;
560 throw std::runtime_error(s.str());
561 }
562 }
563 return v;
564}
565
566/// Find supercell that circumscribes the sphere with a given radius.
567/** Search for the translation limits (N1, N2, N3) such that the resulting supercell with the lattice
568 * vectors a1 * N1, a2 * N2, a3 * N3 fully contains the sphere with a given radius. This is done
569 * by equating the expressions for the volume of the supercell:
570 * Volume = |(A1 x A2) * A3| = N1 * N2 * N3 * |(a1 x a2) * a3|
571 * Volume = h * S = 2 * R * |a_i x a_j| * N_i * N_j */
572inline auto find_translations(double radius__, matrix<double> const& lattice_vectors__)
573{
574 vector<double> a0(lattice_vectors__(0, 0), lattice_vectors__(1, 0), lattice_vectors__(2, 0));
575 vector<double> a1(lattice_vectors__(0, 1), lattice_vectors__(1, 1), lattice_vectors__(2, 1));
576 vector<double> a2(lattice_vectors__(0, 2), lattice_vectors__(1, 2), lattice_vectors__(2, 2));
577
578 double det = std::abs(lattice_vectors__.det());
579
580 vector<int> limits;
581
582 limits[0] = static_cast<int>(2 * radius__ * cross(a1, a2).length() / det) + 1;
583 limits[1] = static_cast<int>(2 * radius__ * cross(a0, a2).length() / det) + 1;
584 limits[2] = static_cast<int>(2 * radius__ * cross(a0, a1).length() / det) + 1;
585
586 return limits;
587}
588
589/// Transform Cartesian coordinates [x,y,z] to spherical coordinates [r,theta,phi]
591{
593
594 const double eps{1e-12};
595
596 const double twopi = 6.2831853071795864769;
597
598 vs[0] = vc.length();
599
600 if (vs[0] <= eps) {
601 vs[1] = 0.0;
602 vs[2] = 0.0;
603 } else {
604 vs[1] = std::acos(vc[2] / vs[0]); // theta = cos^{-1}(z/r)
605
606 if (std::abs(vc[0]) > eps || std::abs(vc[1]) > eps) {
607 vs[2] = std::atan2(vc[1], vc[0]); // phi = tan^{-1}(y/x)
608 if (vs[2] < 0.0) {
609 vs[2] += twopi;
610 }
611 } else {
612 vs[2] = 0.0;
613 }
614 }
615
616 return vs;
617}
618
619} // namespace r3
620
621} // namespace sirius
622
623#endif // __R3_HPP__
Handling of a 3x3 matrix of numerical data types.
Definition: r3.hpp:232
matrix< T > & operator=(matrix< T > const &rhs)
Assignment operator.
Definition: r3.hpp:298
auto & operator*=(U p)
Multiply matrix by a scalar number.
Definition: r3.hpp:347
T det() const
Return determinant of a matrix.
Definition: r3.hpp:358
auto operator+(matrix< U > const &b) const
Sum of two matrices.
Definition: r3.hpp:322
matrix(matrix< U > const &src__)
Copy constructor.
Definition: r3.hpp:278
T mtrx_[3][3]
Store matrix as mtrx[i][j].
Definition: r3.hpp:235
matrix(std::initializer_list< std::initializer_list< T > > mtrx__)
Construct matrix form std::initializer_list.
Definition: r3.hpp:288
auto & operator+=(matrix< U > const &b)
+= operator
Definition: r3.hpp:335
matrix()
Construct a zero matrix.
Definition: r3.hpp:242
matrix(std::vector< std::vector< T > > src__)
Construct matrix from std::vector.
Definition: r3.hpp:258
matrix(T mtrx__[3][3])
Construct matrix form plain 3x3 array.
Definition: r3.hpp:248
Simple implementation of 3d vector.
Definition: r3.hpp:45
T l1norm() const
Return L1 norm of the vector.
Definition: r3.hpp:120
vector()
Create zero vector.
Definition: r3.hpp:48
vector(std::initializer_list< T > v__)
Create from std::initializer_list.
Definition: r3.hpp:60
double length() const
Return vector length (L2 norm).
Definition: r3.hpp:126
vector(std::array< T, 3 > v__)
Create from array.
Definition: r3.hpp:104
vector(vector< T > const &vec__)
Copy constructor.
Definition: r3.hpp:112
vector(T x, T y, T z)
Create arbitrary vector.
Definition: r3.hpp:54
double length2() const
Return square length of the vector.
Definition: r3.hpp:132
vector(std::vector< T > const &v__)
Create from std::vector.
Definition: r3.hpp:78
vector(T const *ptr__)
Create from raw pointer.
Definition: r3.hpp:96
void zero(T *ptr__, size_t n__)
Zero the device memory.
Definition: acc.hpp:397
auto dot(vector< U > const &b__, matrix< T > const &m__)
Vector-matrix multiplication.
Definition: r3.hpp:432
auto transpose(matrix< T > src)
Return transpose of the matrix.
Definition: r3.hpp:445
auto find_translations(double radius__, matrix< double > const &lattice_vectors__)
Find supercell that circumscribes the sphere with a given radius.
Definition: r3.hpp:572
auto inverse(matrix< int > src)
Return inverse of the integer matrix.
Definition: r3.hpp:475
auto spherical_coordinates(vector< double > vc)
Transform Cartesian coordinates [x,y,z] to spherical coordinates [r,theta,phi].
Definition: r3.hpp:590
auto reduce_coordinates(vector< double > coord__)
Reduce the coordinates to the first unit cell.
Definition: r3.hpp:523
Namespace of the SIRIUS library.
Definition: sirius.f90:5
const double twopi
Definition: constants.hpp:45