pytessel 1.2.4__cp311-cp311-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pytessel might be problematic. Click here for more details.

pytessel/isosurface.h ADDED
@@ -0,0 +1,180 @@
1
+ /**************************************************************************
2
+ * *
3
+ * Author: Ivo Filot <ivo@ivofilot.nl> *
4
+ * *
5
+ * PyTessel is free software: *
6
+ * you can redistribute it and/or modify it under the terms of the *
7
+ * GNU General Public License as published by the Free Software *
8
+ * Foundation, either version 3 of the License, or (at your option) *
9
+ * any later version. *
10
+ * *
11
+ * PyTessel is distributed in the hope that it will be useful, *
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty *
13
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
14
+ * See the GNU General Public License for more details. *
15
+ * *
16
+ * You should have received a copy of the GNU General Public License *
17
+ * along with this program. If not, see http://www.gnu.org/licenses/. *
18
+ * *
19
+ **************************************************************************/
20
+
21
+ #pragma once
22
+
23
+ #include <vector>
24
+ #include <iostream>
25
+ #include <cmath>
26
+ #include <mutex>
27
+ #include <memory>
28
+
29
+ #include "edgetable.h"
30
+ #include "triangletable.h"
31
+ #include "scalar_field.h"
32
+
33
+ #define PRECISION_LIMIT 0.000000001
34
+
35
+ /*
36
+ * z
37
+ * |
38
+ * 4----5
39
+ * /| /|
40
+ * 7-|--6 |
41
+ * | 0--|-1--- y
42
+ * |/ |/
43
+ * 3----2
44
+ * /
45
+ * x
46
+ *
47
+ */
48
+
49
+ class Cube{
50
+ private:
51
+ unsigned int i,j,k; // starting position of the cube
52
+ float values[8]; // vector holding cube values
53
+ unsigned int cubidx; // cubeindex (whether there is an intersection)
54
+
55
+ public:
56
+ Cube();
57
+
58
+ Cube(unsigned int _i, unsigned int _j, unsigned int _k, const ScalarField &_vp);
59
+
60
+ void set_cube_index(float _isovalue);
61
+
62
+ unsigned int get_cube_index() const;
63
+
64
+ float get_value_from_vertex(unsigned int _p) const;
65
+ Vec3 get_position_from_vertex(unsigned int _p) const;
66
+ };
67
+
68
+ /*
69
+ * + 0
70
+ * /|\
71
+ * / | \
72
+ * / | \
73
+ * / | \
74
+ * / | \
75
+ * / | \
76
+ * +-------------+ 1
77
+ * 3 \ | /
78
+ * \ | /
79
+ * \ | /
80
+ * \ | /
81
+ * \ | /
82
+ * \|/
83
+ * + 2
84
+ */
85
+
86
+ class Tetrahedron{
87
+ private:
88
+ unsigned int i,j,k; //!< starting position of the cube
89
+ float values[4];
90
+ unsigned int tetidx; //!< cubeindex (whether there is an intersection)
91
+ Vec3 pos[4]; //!< coordinates of the gridpoints
92
+
93
+ public:
94
+ Tetrahedron(unsigned int _i, unsigned int _j, unsigned int _k, const ScalarField &_vp, unsigned int _pos);
95
+
96
+ void set_tetrahedron_index(float _isovalue);
97
+
98
+ unsigned int get_tetrahedron_index() const;
99
+
100
+ float get_value_from_vertex(unsigned int _p) const;
101
+
102
+ const Vec3& get_position_from_vertex(unsigned int _p) const;
103
+ };
104
+
105
+ class Triangle{
106
+ public:
107
+ Vec3 p1, p2, p3;
108
+
109
+ Triangle();
110
+
111
+ Triangle(const Vec3 &_p1, const Vec3 &_p2, const Vec3 &_p3);
112
+
113
+ void transform_to_real(const ScalarField &_vp);
114
+
115
+ float get_x(unsigned int i) const;
116
+
117
+ float get_y(unsigned int i) const;
118
+
119
+ float get_z(unsigned int i) const;
120
+ };
121
+
122
+ /**
123
+ * @brief generates an isosurface using either the marching cubes or the
124
+ * marching tetrahedra algorithm, input is a (tabulated) scalar
125
+ * field
126
+ */
127
+ class IsoSurface {
128
+ private:
129
+ std::vector<Cube> cube_table;
130
+ std::vector<Tetrahedron> tetrahedra_table;
131
+ std::vector<Triangle> triangles;
132
+ std::shared_ptr<ScalarField> vp_ptr; // pointer to ScalarField obj
133
+ unsigned int grid_dimensions[3];
134
+ float isovalue; // isovalue setting
135
+
136
+ public:
137
+ /**
138
+ * @brief default constructor
139
+ *
140
+ * @param _sf pointer to ScalarField object
141
+ */
142
+ IsoSurface(const std::shared_ptr<ScalarField>& _sf);
143
+
144
+ /**
145
+ * @brief generate isosurface using marching cubes algorithm
146
+ *
147
+ * @param[in] _isovalue The isovalue
148
+ */
149
+ void marching_cubes(float _isovalue);
150
+
151
+ /**
152
+ * @brief generate isosurface using marching tetrahedra algorithm
153
+ *
154
+ * @param[in] _isovalue The isovalue
155
+ */
156
+ void marching_tetrahedra(float _isovalue);
157
+
158
+ /**
159
+ * @brief Gets the triangles pointer.
160
+ *
161
+ * @return The triangles pointer.
162
+ */
163
+ const std::vector<Triangle>* get_triangles_ptr() const;
164
+
165
+ inline float get_isovalue() const {
166
+ return this->isovalue;
167
+ }
168
+
169
+ inline const std::shared_ptr<ScalarField>& get_scalar_field() const {
170
+ return this->vp_ptr;
171
+ }
172
+
173
+ private:
174
+ void sample_grid_with_cubes(float _isovalue);
175
+ void sample_grid_with_tetrahedra(float _isovalue);
176
+ void construct_triangles_from_cubes(float _isovalue);
177
+ void construct_triangles_from_tetrahedra(float _isovalue);
178
+ Vec3 interpolate_from_cubes(const Cube &_cub, unsigned int _p1, unsigned int _p2, float _isovalue);
179
+ Vec3 interpolate_from_tetrahedra(const Tetrahedron &_cub, unsigned int _p1, unsigned int _p2, float _isovalue);
180
+ };
@@ -0,0 +1,144 @@
1
+ /**************************************************************************
2
+ * *
3
+ * Author: Ivo Filot <ivo@ivofilot.nl> *
4
+ * *
5
+ * PyTessel is free software: *
6
+ * you can redistribute it and/or modify it under the terms of the *
7
+ * GNU General Public License as published by the Free Software *
8
+ * Foundation, either version 3 of the License, or (at your option) *
9
+ * any later version. *
10
+ * *
11
+ * PyTessel is distributed in the hope that it will be useful, *
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty *
13
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
14
+ * See the GNU General Public License for more details. *
15
+ * *
16
+ * You should have received a copy of the GNU General Public License *
17
+ * along with this program. If not, see http://www.gnu.org/licenses/. *
18
+ * *
19
+ **************************************************************************/
20
+
21
+ #include "isosurface_mesh.h"
22
+
23
+ /**
24
+ * @brief build isosurface mesh object
25
+ *
26
+ * @param[in] _sf pointer to scalar field
27
+ * @param[in] _is pointer to isosurface
28
+ */
29
+ IsoSurfaceMesh::IsoSurfaceMesh(const std::shared_ptr<const ScalarField>& _sf,
30
+ const std::shared_ptr<const IsoSurface>& _is) :
31
+ sf(_sf),
32
+ is(_is) {
33
+ }
34
+
35
+ /**
36
+ * @brief construct surface mesh
37
+ *
38
+ * @param[in] center whether to center structure
39
+ */
40
+ void IsoSurfaceMesh::construct_mesh(bool center_mesh) {
41
+ // grab center
42
+ this->center = this->sf->get_mat_unitcell() * Vec3(0.5, 0.5, 0.5);
43
+
44
+ for(unsigned int i=0; i<this->is->get_triangles_ptr()->size(); i++) {
45
+ // load all index vertices in a map; this operation needs to be done, else a SEGFAULT
46
+ // will be thrown further down the lines
47
+ this->get_index_vertex(is->get_triangles_ptr()->at(i).p1);
48
+ this->get_index_vertex(is->get_triangles_ptr()->at(i).p2);
49
+ this->get_index_vertex(is->get_triangles_ptr()->at(i).p3);
50
+ }
51
+
52
+ // build vertex vector from unordered map
53
+ this->vertices.resize(this->vertices_map.size());
54
+ for(auto it : this->vertices_map) {
55
+ this->vertices[it.second] = it.first;
56
+ }
57
+
58
+ double dev = 0.01;
59
+ this->normals.resize(this->vertices.size());
60
+
61
+ // calculate normal vectors
62
+ #pragma omp parallel for schedule(static)
63
+ for(unsigned int i=0; i<this->vertices.size(); i++) {
64
+ // get derivatives
65
+ double dx0 = sf->get_value_interp(this->vertices[i].x - dev, this->vertices[i].y, this->vertices[i].z);
66
+ double dx1 = sf->get_value_interp(this->vertices[i].x + dev, this->vertices[i].y, this->vertices[i].z);
67
+
68
+ double dy0 = sf->get_value_interp(this->vertices[i].x, this->vertices[i].y - dev, this->vertices[i].z);
69
+ double dy1 = sf->get_value_interp(this->vertices[i].x, this->vertices[i].y + dev, this->vertices[i].z);
70
+
71
+ double dz0 = sf->get_value_interp(this->vertices[i].x, this->vertices[i].y, this->vertices[i].z - dev);
72
+ double dz1 = sf->get_value_interp(this->vertices[i].x, this->vertices[i].y, this->vertices[i].z + dev);
73
+
74
+ Vec3 normal((dx1 - dx0) / (2.0 * dev),
75
+ (dy1 - dy0) / (2.0 * dev),
76
+ (dz1 - dz0) / (2.0 * dev));
77
+ normal = -1 * normal.normalized(); // the negative of the gradient is the correct normal
78
+
79
+ this->normals[i] = normal * sgn(sf->get_value_interp(this->vertices[i].x, this->vertices[i].y, this->vertices[i].z));
80
+ }
81
+
82
+ // build indices in right orientation based on face normal
83
+ for(unsigned int i=0; i<this->is->get_triangles_ptr()->size(); i++) {
84
+ // calculate face normal
85
+ unsigned int id1 = this->get_index_vertex(is->get_triangles_ptr()->at(i).p1);
86
+ unsigned int id2 = this->get_index_vertex(is->get_triangles_ptr()->at(i).p2);
87
+ unsigned int id3 = this->get_index_vertex(is->get_triangles_ptr()->at(i).p3);
88
+
89
+ // calculate the orientation of the face with respect to the normal
90
+ const Vec3 face_normal = (this->normals[id1] + this->normals[id2] + this->normals[id3]) / 3.0f;
91
+ const Vec3 orientation_face = ((this->vertices[id2] - this->vertices[id1]).cross(this->vertices[id3] - this->vertices[id1])).normalized();
92
+ const float orientation = face_normal.dot(orientation_face);
93
+
94
+ // if orientation is positive, the orientation is correct, if it is negative, the orientation is incorrect and two indices should be swapped
95
+ if(orientation > 0.0f) {
96
+ this->indices.push_back(id1);
97
+ this->indices.push_back(id2);
98
+ this->indices.push_back(id3);
99
+ } else {
100
+ this->indices.push_back(id2);
101
+ this->indices.push_back(id1);
102
+ this->indices.push_back(id3);
103
+ }
104
+ }
105
+
106
+ // center structure
107
+ if(center_mesh) {
108
+ Vec3 sum = this->sf->get_mat_unitcell() * Vec3(0.5f, 0.5f, 0.5f);
109
+
110
+ #pragma omp parallel for
111
+ for(unsigned int i=0; i<this->vertices.size(); i++) {
112
+ this->vertices[i] -= sum;
113
+ }
114
+ }
115
+ }
116
+
117
+ /**
118
+ * @brief get the index of a vertex from unordered map
119
+ *
120
+ * @param[in] v vertex coordinates
121
+ *
122
+ * @return the index
123
+ */
124
+ unsigned int IsoSurfaceMesh::get_index_vertex(const Vec3 v) {
125
+ auto got = this->vertices_map.find(v);
126
+ if(got != this->vertices_map.end()) {
127
+ return got->second;
128
+ } else {
129
+ this->vertices_map.emplace(v, this->vertices_map.size());
130
+ return this->get_index_vertex(v);
131
+ }
132
+ }
133
+
134
+ std::vector<float> IsoSurfaceMesh::get_vertices() const {
135
+ return std::vector<float>(&this->vertices[0].x, &this->vertices[0].x + this->vertices.size() * 3);
136
+ }
137
+
138
+ std::vector<float> IsoSurfaceMesh::get_normals() const {
139
+ return std::vector<float>(&this->normals[0].x, &this->normals[0].x + this->normals.size() * 3);
140
+ }
141
+
142
+ const std::vector<unsigned int>& IsoSurfaceMesh::get_indices() const {
143
+ return this->indices;
144
+ }
@@ -0,0 +1,104 @@
1
+ /**************************************************************************
2
+ * *
3
+ * Author: Ivo Filot <ivo@ivofilot.nl> *
4
+ * *
5
+ * PyTessel is free software: *
6
+ * you can redistribute it and/or modify it under the terms of the *
7
+ * GNU General Public License as published by the Free Software *
8
+ * Foundation, either version 3 of the License, or (at your option) *
9
+ * any later version. *
10
+ * *
11
+ * PyTessel is distributed in the hope that it will be useful, *
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty *
13
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
14
+ * See the GNU General Public License for more details. *
15
+ * *
16
+ * You should have received a copy of the GNU General Public License *
17
+ * along with this program. If not, see http://www.gnu.org/licenses/. *
18
+ * *
19
+ **************************************************************************/
20
+
21
+ #pragma once
22
+
23
+ #include <fstream>
24
+ #include <set>
25
+ #include <vector>
26
+ #include <unordered_map>
27
+ #include <memory>
28
+
29
+ #include "vec3.h"
30
+ #include "isosurface.h"
31
+
32
+ // add SGN function for Windows
33
+ template <typename T> float sgn(T val) {
34
+ return (T(0) < val) - (val < T(0));
35
+ }
36
+
37
+ /**
38
+ * @brief structure to put Vec3f in a map
39
+ */
40
+ struct KeyFuncs
41
+ {
42
+ size_t operator()(const Vec3& k)const
43
+ {
44
+ return std::hash<float>()(k.x) ^ std::hash<float>()(k.y) ^ std::hash<float>()(k.z);
45
+ }
46
+
47
+ bool operator()(const Vec3& a, const Vec3& b)const
48
+ {
49
+ return a.x == b.x && a.y == b.y && a.z == b.z;
50
+ }
51
+ };
52
+
53
+ /**
54
+ * @brief Class for iso surface mesh.
55
+ */
56
+ class IsoSurfaceMesh{
57
+ private:
58
+ std::unordered_map<Vec3, unsigned int, KeyFuncs, KeyFuncs> vertices_map;
59
+ std::vector<Vec3> vertices;
60
+ std::vector<Vec3> normals;
61
+ std::vector<unsigned int> indices;
62
+
63
+ std::shared_ptr<const ScalarField> sf;
64
+ std::shared_ptr<const IsoSurface> is;
65
+
66
+ Vec3 center;
67
+
68
+ public:
69
+ /**
70
+ * @brief build isosurface mesh object
71
+ *
72
+ * @param[in] _sf pointer to scalar field
73
+ * @param[in] _is pointer to isosurface
74
+ */
75
+ IsoSurfaceMesh(const std::shared_ptr<const ScalarField>& _sf,
76
+ const std::shared_ptr<const IsoSurface>& _is);
77
+
78
+ IsoSurfaceMesh(const std::vector<float>& vertices,
79
+ const std::vector<float>& normals,
80
+ const std::vector<unsigned int>& indices);
81
+
82
+ /**
83
+ * @brief construct surface mesh
84
+ *
85
+ * @param[in] center_mesh whether to center structure
86
+ */
87
+ void construct_mesh(bool center_mesh);
88
+
89
+ std::vector<float> get_vertices() const;
90
+
91
+ std::vector<float> get_normals() const;
92
+
93
+ const std::vector<unsigned int>& get_indices() const;
94
+
95
+ private:
96
+ /**
97
+ * @brief get the index of a vertex from unordered map
98
+ *
99
+ * @param[in] v vertex coordinates
100
+ *
101
+ * @return the index
102
+ */
103
+ unsigned int get_index_vertex(const Vec3 v);
104
+ };
Binary file
@@ -0,0 +1,239 @@
1
+ /**************************************************************************
2
+ * *
3
+ * Author: Ivo Filot <ivo@ivofilot.nl> *
4
+ * *
5
+ * PyTessel is free software: *
6
+ * you can redistribute it and/or modify it under the terms of the *
7
+ * GNU General Public License as published by the Free Software *
8
+ * Foundation, either version 3 of the License, or (at your option) *
9
+ * any later version. *
10
+ * *
11
+ * PyTessel is distributed in the hope that it will be useful, *
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty *
13
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
14
+ * See the GNU General Public License for more details. *
15
+ * *
16
+ * You should have received a copy of the GNU General Public License *
17
+ * along with this program. If not, see http://www.gnu.org/licenses/. *
18
+ * *
19
+ **************************************************************************/
20
+
21
+ #include "scalar_field.h"
22
+
23
+ /**
24
+ * @brief constructor
25
+ *
26
+ * @param[in] _filename url to filename
27
+ * @param[in] _flag_is_locpot whether this file is a locpot
28
+ */
29
+ ScalarField::ScalarField(const std::vector<float>& _grid,
30
+ const std::vector<unsigned int>& _dimensions,
31
+ const std::vector<float>& _unitcell) {
32
+
33
+ this->grid = _grid;
34
+ this->grid_dimensions = {_dimensions[0], _dimensions[1], _dimensions[2]};
35
+ for(unsigned int i=0; i<3; i++) {
36
+ for(unsigned int j=0; j<3; j++) {
37
+ this->unitcell[i][j] = _unitcell[i*3 + j];
38
+ }
39
+ }
40
+ this->inverse(this->unitcell, &this->unitcell_inverse);
41
+ }
42
+
43
+ /*
44
+ * float get_value_interp(x,y,z)
45
+ *
46
+ * Grabs a value from the 3D scalar field. Calculate the value
47
+ * by using a trilinear interpolation.
48
+ *
49
+ * The trilinear interpolation algorithm has been extracted from:
50
+ * http://paulbourke.net/miscellaneous/interpolation/
51
+ *
52
+ * Future algorithm can make use of a cubic interpolation.
53
+ *
54
+ */
55
+ float ScalarField::get_value_interp(float x, float y, float z) const {
56
+ if(!this->is_inside(x,y,z)) {
57
+ return 0.0f;
58
+ }
59
+
60
+ // cast the input to the nearest grid point
61
+ Vec3 r = this->realspace_to_grid(x,y,z);
62
+
63
+ // recast
64
+ if(r.x < 0.0) r.x += (float)this->grid_dimensions[0];
65
+ if(r.y < 0.0) r.y += (float)this->grid_dimensions[1];
66
+ if(r.z < 0.0) r.z += (float)this->grid_dimensions[2];
67
+
68
+ // calculate value using trilinear interpolation
69
+ float xd = remainderf(r.x, 1.0);
70
+ float yd = remainderf(r.y, 1.0);
71
+ float zd = remainderf(r.z, 1.0);
72
+
73
+ if(xd < 0) xd += 1.0;
74
+ if(yd < 0) yd += 1.0;
75
+ if(zd < 0) zd += 1.0;
76
+
77
+ float x0 = fmod(floor(r.x), this->grid_dimensions[0]);
78
+ float x1 = fmod(ceil(r.x), this->grid_dimensions[0]);
79
+ float y0 = fmod(floor(r.y), this->grid_dimensions[1]);
80
+ float y1 = fmod(ceil(r.y), this->grid_dimensions[1]);
81
+ float z0 = fmod(floor(r.z), this->grid_dimensions[2]);
82
+ float z1 = fmod(ceil(r.z), this->grid_dimensions[2]);
83
+
84
+ return
85
+ this->get_value(x0, y0, z0) * (1.0 - xd) * (1.0 - yd) * (1.0 - zd) +
86
+ this->get_value(x1, y0, z0) * xd * (1.0 - yd) * (1.0 - zd) +
87
+ this->get_value(x0, y1, z0) * (1.0 - xd) * yd * (1.0 - zd) +
88
+ this->get_value(x0, y0, z1) * (1.0 - xd) * (1.0 - yd) * zd +
89
+ this->get_value(x1, y0, z1) * xd * (1.0 - yd) * zd +
90
+ this->get_value(x0, y1, z1) * (1.0 - xd) * yd * zd +
91
+ this->get_value(x1, y1, z0) * xd * yd * (1.0 - zd) +
92
+ this->get_value(x1, y1, z1) * xd * yd * zd;
93
+ }
94
+
95
+ /**
96
+ * @brief test whether point is inside unit cell
97
+ *
98
+ * @param[in] x x position
99
+ * @param[in] y y position
100
+ * @param[in] z z position
101
+ *
102
+ * @return True if inside, False otherwise.
103
+ */
104
+ bool ScalarField::is_inside(float x, float y, float z) const {
105
+ // cast the input to the nearest grid point
106
+ Vec3 d = this->realspace_to_direct(x,y,z);
107
+
108
+ if(d.x < 0 || d.x > 1.0) {
109
+ return false;
110
+ }
111
+ if(d.y < 0 || d.y > 1.0) {
112
+ return false;
113
+ }
114
+ if(d.z < 0 || d.z > 1.0) {
115
+ return false;
116
+ }
117
+
118
+ return true;
119
+ }
120
+
121
+ /*
122
+ * float get_value(i,j,k)
123
+ *
124
+ * Grabs the value at a particular grid point.
125
+ *
126
+ * This is a convenience function for the get_value_interp() function
127
+ *
128
+ */
129
+ float ScalarField::get_value(unsigned int i, unsigned int j, unsigned int k) const {
130
+ unsigned int idx = k * this->grid_dimensions[0] * this->grid_dimensions[1] +
131
+ j * this->grid_dimensions[0] +
132
+ i;
133
+ return this->grid[idx];
134
+ }
135
+
136
+ /*
137
+ * Vec3 grid_to_realspace(i,j,k)
138
+ *
139
+ * Converts a grid point to a realspace vector. This function
140
+ * is not being used at the moment.
141
+ *
142
+ */
143
+ Vec3 ScalarField::grid_to_realspace(float i, float j, float k) const {
144
+ float dx = (float)i / (float)grid_dimensions[0];
145
+ float dy = (float)j / (float)grid_dimensions[1];
146
+ float dz = (float)k / (float)grid_dimensions[2];
147
+
148
+ Vec3 r;
149
+ r.x = this->unitcell[0][0] * dx + this->unitcell[1][0] * dy + this->unitcell[2][0] * dz;
150
+ r.y = this->unitcell[0][1] * dx + this->unitcell[1][1] * dy + this->unitcell[2][1] * dz;
151
+ r.z = this->unitcell[0][2] * dx + this->unitcell[1][2] * dy + this->unitcell[2][2] * dz;
152
+
153
+ return r;
154
+ }
155
+
156
+ Vec3 ScalarField::realspace_to_direct(float x, float y, float z) const {
157
+ Vec3 d;
158
+ d.x = this->unitcell_inverse[0][0] * x + this->unitcell_inverse[0][1] * y + this->unitcell_inverse[0][2] * z;
159
+ d.y = this->unitcell_inverse[1][0] * x + this->unitcell_inverse[1][1] * y + this->unitcell_inverse[1][2] * z;
160
+ d.z = this->unitcell_inverse[2][0] * x + this->unitcell_inverse[2][1] * y + this->unitcell_inverse[2][2] * z;
161
+
162
+ return d;
163
+ }
164
+
165
+ /*
166
+ * Vec3 realspace_to_grid(i,j,k)
167
+ *
168
+ * Convert 3d realspace vector to a position on the grid. Non-integer
169
+ * values (i.e. floating point) are given as the result.
170
+ *
171
+ * This is a convenience function for the get_value_interp() function
172
+ *
173
+ */
174
+ Vec3 ScalarField::realspace_to_grid(float i, float j, float k) const {
175
+ Vec3 g = this->realspace_to_direct(i, j, k);
176
+
177
+ g.x *= float(this->grid_dimensions[0]);
178
+ g.y *= float(this->grid_dimensions[1]);
179
+ g.z *= float(this->grid_dimensions[2]);
180
+
181
+ return g;
182
+ }
183
+
184
+ void ScalarField::copy_grid_dimensions(unsigned int _grid_dimensions[]) const {
185
+ for(unsigned int i=0; i<3; i++) {
186
+ _grid_dimensions[i] = this->grid_dimensions[i];
187
+ }
188
+ }
189
+
190
+ float ScalarField::get_max() const {
191
+ return *std::max_element(this->grid.begin(), this->grid.end());
192
+ }
193
+
194
+ float ScalarField::get_min() const {
195
+ return *std::min_element(this->grid.begin(), this->grid.end());
196
+ }
197
+
198
+ void ScalarField::inverse(const mat33& mat, mat33* invmat) {
199
+ // computes the inverse of a matrix m
200
+ float det = mat[0][0] * (mat[1][1] * mat[2][2] - mat[2][1] * mat[1][2]) -
201
+ mat[0][1] * (mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) +
202
+ mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]);
203
+
204
+ float invdet = 1.0 / det;
205
+
206
+ (*invmat)[0][0] = (mat[1][1] * mat[2][2] - mat[2][1] * mat[1][2]) * invdet;
207
+ (*invmat)[0][1] = (mat[0][2] * mat[2][1] - mat[0][1] * mat[2][2]) * invdet;
208
+ (*invmat)[0][2] = (mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1]) * invdet;
209
+ (*invmat)[1][0] = (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) * invdet;
210
+ (*invmat)[1][1] = (mat[0][0] * mat[2][2] - mat[0][2] * mat[2][0]) * invdet;
211
+ (*invmat)[1][2] = (mat[1][0] * mat[0][2] - mat[0][0] * mat[1][2]) * invdet;
212
+ (*invmat)[2][0] = (mat[1][0] * mat[2][1] - mat[2][0] * mat[1][1]) * invdet;
213
+ (*invmat)[2][1] = (mat[2][0] * mat[0][1] - mat[0][0] * mat[2][1]) * invdet;
214
+ (*invmat)[2][2] = (mat[0][0] * mat[1][1] - mat[1][0] * mat[0][1]) * invdet;
215
+ }
216
+
217
+ std::vector<float> ScalarField::get_unitcell_vf() const {
218
+ std::vector<float> ans(9,0.0);
219
+
220
+ for(unsigned int i=0; i<3; i++) {
221
+ for(unsigned int j=0; j<3; j++) {
222
+ ans[i*3 + j] = this->unitcell[i][j];
223
+ }
224
+ }
225
+
226
+ return ans;
227
+ }
228
+
229
+ std::vector<float> ScalarField::get_unitcell_inverse() const {
230
+ std::vector<float> ans(9,0.0);
231
+
232
+ for(unsigned int i=0; i<3; i++) {
233
+ for(unsigned int j=0; j<3; j++) {
234
+ ans[i*3 + j] = this->unitcell_inverse[i][j];
235
+ }
236
+ }
237
+
238
+ return ans;
239
+ }