numerics
Loading...
Searching...
No Matches
fields.cpp
Go to the documentation of this file.
1/// @file src/spatial/fields.cpp
2/// @brief Implementations for num::ScalarField3D, VectorField3D, FieldSolver, MagneticSolver.
3#include "spatial/fields.hpp"
4#include "spatial/stencil.hpp"
6#include <algorithm>
7#include <cmath>
8
9namespace num {
10
11// ============================================================
12// ScalarField3D
13// ============================================================
14
15ScalarField3D::ScalarField3D(int nx, int ny, int nz, float dx,
16 float ox, float oy, float oz)
17 : grid_(nx, ny, nz, static_cast<double>(dx))
18 , ox_(ox), oy_(oy), oz_(oz) {}
19
20float ScalarField3D::sample(float x, float y, float z) const {
21 const float gx = (x - ox_) / dx();
22 const float gy = (y - oy_) / dx();
23 const float gz = (z - oz_) / dx();
24
25 if (gx < 0 || gx >= nx()-1 || gy < 0 || gy >= ny()-1 || gz < 0 || gz >= nz()-1)
26 return 0.0f;
27
28 const int i0 = static_cast<int>(gx);
29 const int j0 = static_cast<int>(gy);
30 const int k0 = static_cast<int>(gz);
31 const float tx = gx - i0, ty = gy - j0, tz = gz - k0;
32
33 auto v = [&](int di, int dj, int dk) {
34 return static_cast<float>(grid_(i0+di, j0+dj, k0+dk));
35 };
36 return (1-tz)*((1-ty)*((1-tx)*v(0,0,0) + tx*v(1,0,0)) +
37 ty *((1-tx)*v(0,1,0) + tx*v(1,1,0))) +
38 tz *((1-ty)*((1-tx)*v(0,0,1) + tx*v(1,0,1)) +
39 ty *((1-tx)*v(0,1,1) + tx*v(1,1,1)));
40}
41
42// ============================================================
43// VectorField3D
44// ============================================================
45
46VectorField3D::VectorField3D(int nx, int ny, int nz, float dx,
47 float ox, float oy, float oz)
48 : x(nx, ny, nz, dx, ox, oy, oz)
49 , y(nx, ny, nz, dx, ox, oy, oz)
50 , z(nx, ny, nz, dx, ox, oy, oz) {}
51
52std::array<float,3> VectorField3D::sample(float px, float py, float pz) const {
53 return { x.sample(px,py,pz), y.sample(px,py,pz), z.sample(px,py,pz) };
54}
55
56void VectorField3D::scale(float s) {
57 auto sc = [&](Grid3D& g) {
58 auto v = g.to_vector();
59 num::scale(v, static_cast<real>(s));
60 g.from_vector(v);
61 };
62 sc(x.grid()); sc(y.grid()); sc(z.grid());
63}
64
65// ============================================================
66// FieldSolver
67// ============================================================
68
69SolverResult FieldSolver::solve_poisson(ScalarField3D& phi,
70 const ScalarField3D& source,
71 double tol, int max_iter) {
72 const Grid3D& g = phi.grid();
73 const int nx = g.nx(), ny = g.ny(), nz = g.nz();
74 const double inv_dx2 = 1.0 / (g.dx() * g.dx());
75 const int N = nx * ny * nz;
76
77 auto flat = [&](int i, int j, int k) -> idx {
78 return static_cast<idx>(k * ny * nx + j * nx + i);
79 };
80
81 Vector b(N, 0.0);
82 for (int k=1; k<nz-1; ++k)
83 for (int j=1; j<ny-1; ++j)
84 for (int i=1; i<nx-1; ++i)
85 b[flat(i,j,k)] = -source.grid()(i,j,k);
86
87 Vector xv = phi.grid().to_vector();
88
89 auto matvec = [&](const Vector& v, Vector& Av) {
90 neg_laplacian_3d(v, Av, nx, ny, nz, inv_dx2);
91 };
92 auto result = cg_matfree(matvec, b, xv, tol, static_cast<idx>(max_iter));
93 phi.grid().from_vector(xv);
94 return result;
95}
96
97VectorField3D FieldSolver::gradient(const ScalarField3D& phi) {
98 VectorField3D out(phi.nx(), phi.ny(), phi.nz(), phi.dx(),
99 phi.ox(), phi.oy(), phi.oz());
100 gradient_3d(phi.grid(), out.x.grid(), out.y.grid(), out.z.grid());
101 return out;
102}
103
104ScalarField3D FieldSolver::divergence(const VectorField3D& f) {
105 ScalarField3D out(f.x.nx(), f.x.ny(), f.x.nz(), f.x.dx(),
106 f.x.ox(), f.x.oy(), f.x.oz());
107 divergence_3d(f.x.grid(), f.y.grid(), f.z.grid(), out.grid());
108 return out;
109}
110
111VectorField3D FieldSolver::curl(const VectorField3D& A) {
112 VectorField3D B(A.x.nx(), A.x.ny(), A.x.nz(), A.x.dx(),
113 A.x.ox(), A.x.oy(), A.x.oz());
114 curl_3d(A.x.grid(), A.y.grid(), A.z.grid(), B.x.grid(), B.y.grid(), B.z.grid());
115 return B;
116}
117
118// ============================================================
119// MagneticSolver
120// ============================================================
121
122VectorField3D MagneticSolver::current_density(const ScalarField3D& sigma,
123 const ScalarField3D& phi) {
124 VectorField3D J = FieldSolver::gradient(phi);
125 const Grid3D& sg = sigma.grid();
126 const int nx = sg.nx(), ny = sg.ny(), nz = sg.nz();
127 for (int k = 0; k < nz; ++k)
128 for (int j = 0; j < ny; ++j)
129 for (int i = 0; i < nx; ++i) {
130 const double neg_s = -sg(i,j,k);
131 J.x.grid()(i,j,k) *= neg_s;
132 J.y.grid()(i,j,k) *= neg_s;
133 J.z.grid()(i,j,k) *= neg_s;
134 }
135 return J;
136}
137
138VectorField3D MagneticSolver::solve_magnetic_field(const VectorField3D& J,
139 double tol, int max_iter) {
140 const int nx = J.x.nx(), ny = J.x.ny(), nz = J.x.nz();
141 const float dx = J.x.dx(), ox = J.x.ox(), oy = J.x.oy(), oz = J.x.oz();
142
143 auto make_source = [&](const ScalarField3D& Jc) {
144 ScalarField3D src(nx, ny, nz, dx, ox, oy, oz);
145 const Grid3D& gJ = Jc.grid();
146 Grid3D& gs = src.grid();
147 for (int k=0;k<nz;++k)
148 for (int j=0;j<ny;++j)
149 for (int i=0;i<nx;++i)
150 gs(i,j,k) = -MU0 * gJ(i,j,k);
151 return src;
152 };
153
154 ScalarField3D Ax(nx, ny, nz, dx, ox, oy, oz);
155 ScalarField3D Ay(nx, ny, nz, dx, ox, oy, oz);
156 ScalarField3D Az(nx, ny, nz, dx, ox, oy, oz);
157
158 FieldSolver::solve_poisson(Ax, make_source(J.x), tol, max_iter);
159 FieldSolver::solve_poisson(Ay, make_source(J.y), tol, max_iter);
160 FieldSolver::solve_poisson(Az, make_source(J.z), tol, max_iter);
161
162 VectorField3D A(nx, ny, nz, dx, ox, oy, oz);
163 A.x = Ax; A.y = Ay; A.z = Az;
164 return FieldSolver::curl(A);
165}
166
167} // namespace num
int nx() const
Definition fields.hpp:32
ScalarField3D(int nx, int ny, int nz, float dx, float ox=0.0f, float oy=0.0f, float oz=0.0f)
Definition fields.cpp:14
double real
Definition types.hpp:10
constexpr real phi
Golden ratio.
Definition math.hpp:42
void curl_3d(const Grid3D &ax, const Grid3D &ay, const Grid3D &az, Grid3D &bx, Grid3D &by, Grid3D &bz)
Definition stencil.hpp:170
void neg_laplacian_3d(const Vector &x, Vector &y, int nx, int ny, int nz, double inv_dx2)
Definition stencil.hpp:109
constexpr T ipow(T x) noexcept
Compute x^N at compile time via repeated squaring.
std::size_t idx
Definition types.hpp:11
void matvec(const Matrix &A, const Vector &x, Vector &y, Backend b=default_backend)
y = A * x
Definition matrix.cpp:94
void scale(Vector &v, real alpha, Backend b=default_backend)
v *= alpha
Definition vector.cpp:27
void divergence_3d(const Grid3D &fx, const Grid3D &fy, const Grid3D &fz, Grid3D &out)
Definition stencil.hpp:151
BasicVector< real > Vector
Real-valued dense vector with full backend dispatch (CPU + GPU)
Definition vector.hpp:122
void gradient_3d(const Grid3D &phi, Grid3D &gx, Grid3D &gy, Grid3D &gz)
Definition stencil.hpp:132
SolverResult cg_matfree(MatVecFn matvec, const Vector &b, Vector &x, real tol=1e-6, idx max_iter=1000)
Matrix-free conjugate gradient for Ax = b where A is SPD.
Definition cg.cpp:66
num::VectorField3D VectorField3D
Definition field.hpp:17
num::ScalarField3D ScalarField3D
Definition field.hpp:16
Umbrella include for all linear solvers.
Forwarding shim — field types have moved to pde/fields.hpp.
Forwarding shim — stencil utilities have moved to pde/stencil.hpp.
ScalarField3D x
Definition fields.hpp:57