numerics 0.1.0
Loading...
Searching...
No Matches
3D Field Types and Solvers

include/pde/fields.hpp and src/pde/fields.cpp provide general-purpose 3D scalar and vector field types together with PDE field solvers for Poisson, gradient, divergence, and curl. The old path include/spatial/fields.hpp is a forwarding shim and continues to work.

These classes previously lived in apps/em_demo/field.hpp/cpp as physics:: types. Moving them into num:: makes them available to any 3D app without copy-pasting.


Types

ScalarField3D

public:
ScalarField3D(int nx, int ny, int nz, float dx,
float ox=0, float oy=0, float oz=0);
const num::Grid3D& grid() const;
int nx(), ny(), nz();
float dx(), ox(), oy(), oz();
void set(int i, int j, int k, double v);
void fill(double v);
/// Trilinear interpolation at world position (x,y,z).
/// Returns 0 outside the grid domain.
float sample(float x, float y, float z) const;
};
void set(int i, int j, int k, double v)
Definition fields.hpp:64
float oy() const
Definition fields.hpp:57
float ox() const
Definition fields.hpp:54
int nx() const
Definition fields.hpp:42
float dx() const
Definition fields.hpp:51
float sample(float x, float y, float z) const
Definition fields.cpp:18
int ny() const
Definition fields.hpp:45
Grid3D & grid()
Definition fields.hpp:35
float oz() const
Definition fields.hpp:60
int nz() const
Definition fields.hpp:48
void fill(double v)
Definition fields.hpp:67

Wraps a num::Grid3D with a world-space origin (ox, oy, oz). sample() converts world coordinates to grid coordinates and performs trilinear interpolation across the 8 surrounding nodes.


VectorField3D

ScalarField3D x, y, z; // all on the same grid
VectorField3D(int nx, int ny, int nz, float dx,
float ox=0, float oy=0, float oz=0);
std::array<float,3> sample(float px, float py, float pz) const;
void scale(float s);
};
std::array< float, 3 > sample(float px, float py, float pz) const
Trilinear-interpolated field vector at world position.
Definition fields.cpp:48
ScalarField3D z
x, y, z components on the same grid layout
Definition fields.hpp:92
ScalarField3D x
Definition fields.hpp:92
void scale(float s)
Multiply all components by scalar s.
Definition fields.cpp:52
ScalarField3D y
Definition fields.hpp:92

Three co-located components. sample() returns {x.sample(p), y.sample(p), z.sample(p)} via trilinear interpolation.


FieldSolver

Static PDE utilities. All methods operate on ScalarField3D / VectorField3D in-place or return new field objects.

public:
/// Solve Lapphi = source (phi=0 Dirichlet on all boundaries).
static SolverResult solve_poisson(ScalarField3D& phi,
const ScalarField3D& source,
double tol = 1e-6, int max_iter = 500);
/// gradphi via central differences (one-sided at boundaries).
static VectorField3D gradient(const ScalarField3D& phi);
/// grad*f via central differences.
static ScalarField3D divergence(const VectorField3D& f);
/// gradxA via central differences (one-sided at boundaries).
static VectorField3D curl(const VectorField3D& A);
};
static VectorField3D gradient(const ScalarField3D &phi)
Definition fields.cpp:165
static SolverResult solve_poisson(ScalarField3D &phi, const ScalarField3D &source, double tol=1e-6, int max_iter=500)
Definition fields.cpp:65
static VectorField3D curl(const VectorField3D &A)
Definition fields.cpp:179
static ScalarField3D divergence(const VectorField3D &f)
Compute div(f) via central finite differences.
Definition fields.cpp:172
constexpr real phi
Golden ratio.
Definition math.hpp:44
constexpr real e
Definition math.hpp:43

solve_poisson internally calls num::neg_laplacian_3d (see Stencil Higher-Order Functions) and num::cg_matfree. The SPD operator (-Lap) with identity rows on the boundary means the Dirichlet system is SPD -> CG converges.


MagneticSolver

public:
static constexpr double MU0 = 1.2566370614e-6; // mu_0 [H/m]
/// J = -sigmagradphi [A/m^2]
static VectorField3D current_density(const ScalarField3D& sigma,
const ScalarField3D& phi);
/// Solve for B given J.
/// Solves LapA = -mu_0J (Coulomb gauge, Dirichlet) then returns B = gradxA.
static VectorField3D solve_magnetic_field(const VectorField3D& J,
double tol = 1e-6, int max_iter = 500);
};
static VectorField3D solve_magnetic_field(const VectorField3D &J, double tol=1e-6, int max_iter=500)
Definition fields.cpp:205
static VectorField3D current_density(const ScalarField3D &sigma, const ScalarField3D &phi)
Compute current density J = -sigma*grad(phi) [A/m^2].
Definition fields.cpp:189
static constexpr double MU0
mu_0 [H/m]
Definition fields.hpp:156

solve_magnetic_field runs three independent solve_poisson calls (one per component of A) then applies curl.


Typical Workflow

// Electric field from charge distribution
num::ScalarField3D phi(32,32,32, 0.05f);
num::ScalarField3D rho(32,32,32, 0.05f);
rho.set(16,16,16, charge_density);
E.scale(-1.0f); // E = -gradphi
// Per-particle force
for (auto& p : particles) {
auto [ex, ey, ez] = E.sample(p.x, p.y, p.z);
p.ax += charge * ex / p.mass;
}
// Magnetic field from DC current
num::ScalarField3D sigma(nx, ny, nz, dx);
num::ScalarField3D Vphi(nx, ny, nz, dx);
// ... fill sigma, solve ElectricSolver::solve_potential(Vphi, sigma, bcs) ...

Where Each Type Is Used

Type / Method App Purpose
ScalarField3D, VectorField3D EM demo Potential phi, conductivity sigma, E and B fields
FieldSolver::solve_poisson EM demo Lapphi = rho for electrostatic potential
FieldSolver::gradient EM demo E = -gradphi, J component from gradient
FieldSolver::curl EM demo B = gradxA
MagneticSolver::current_density EM demo J = -sigmagradphi
MagneticSolver::solve_magnetic_field EM demo Vector Poisson + curl for B

The EM-specific ElectricSolver (variable-conductivity div(sigmagradphi)=0 with electrode BCs and Joule heating) remains in apps/em_demo/field.hpp.