16 float ox,
float oy,
float oz)
18 , ox_(ox), oy_(oy), oz_(oz) {}
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();
25 if (gx < 0 || gx >= nx()-1 || gy < 0 || gy >= ny()-1 || gz < 0 || gz >= nz()-1)
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;
33 auto v = [&](
int di,
int dj,
int dk) {
34 return static_cast<float>(grid_(i0+di, j0+dj, k0+dk));
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)));
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) {}
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) };
56void VectorField3D::scale(
float s) {
57 auto sc = [&](Grid3D& g) {
58 auto v = g.to_vector();
62 sc(x.grid()); sc(y.grid()); sc(z.grid());
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;
77 auto flat = [&](
int i,
int j,
int k) -> idx {
78 return static_cast<idx>(k * ny * nx + j * nx + i);
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);
92 auto result =
cg_matfree(matvec, b, xv, tol,
static_cast<idx>(max_iter));
93 phi.grid().from_vector(xv);
97VectorField3D FieldSolver::gradient(
const ScalarField3D& phi) {
100 gradient_3d(
phi.grid(), out.x.grid(), out.y.grid(), out.z.grid());
104ScalarField3D FieldSolver::divergence(
const VectorField3D& f) {
106 f.x.ox(), f.x.oy(), f.x.oz());
107 divergence_3d(f.x.grid(), f.y.grid(), f.z.grid(), out.grid());
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());
122VectorField3D MagneticSolver::current_density(
const ScalarField3D& sigma,
123 const ScalarField3D& 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;
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();
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);
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);
163 A.x = Ax; A.y = Ay; A.z = Az;
164 return FieldSolver::curl(A);
ScalarField3D(int nx, int ny, int nz, float dx, float ox=0.0f, float oy=0.0f, float oz=0.0f)
constexpr real phi
Golden ratio.
void curl_3d(const Grid3D &ax, const Grid3D &ay, const Grid3D &az, Grid3D &bx, Grid3D &by, Grid3D &bz)
void neg_laplacian_3d(const Vector &x, Vector &y, int nx, int ny, int nz, double inv_dx2)
constexpr T ipow(T x) noexcept
Compute x^N at compile time via repeated squaring.
void matvec(const Matrix &A, const Vector &x, Vector &y, Backend b=default_backend)
y = A * x
void scale(Vector &v, real alpha, Backend b=default_backend)
v *= alpha
void divergence_3d(const Grid3D &fx, const Grid3D &fy, const Grid3D &fz, Grid3D &out)
BasicVector< real > Vector
Real-valued dense vector with full backend dispatch (CPU + GPU)
void gradient_3d(const Grid3D &phi, Grid3D &gx, Grid3D &gy, Grid3D &gz)
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.
num::VectorField3D VectorField3D
num::ScalarField3D ScalarField3D
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.