numerics
Loading...
Searching...
No Matches
field.cpp
Go to the documentation of this file.
1/// @file field.cpp
2/// @brief ElectricSolver and joule_heating implementations.
3#include "field.hpp"
4#include <algorithm>
5#include <unordered_map>
6
7namespace physics {
8
9// ============================================================
10// ElectricSolver
11// ============================================================
12
14 const ScalarField3D& sigma,
15 const std::vector<ElectrodeBC>& bcs,
16 double tol, int max_iter) {
17 const num::Grid3D& g = phi.grid();
18 const num::Grid3D& sg = sigma.grid();
19 const int nx = g.nx(), ny = g.ny(), nz = g.nz();
20 const int N = nx * ny * nz;
21 const double inv_dx2 = 1.0 / (g.dx() * g.dx());
22
23 auto flat = [&](int i, int j, int k) -> int {
24 return k * ny * nx + j * nx + i;
25 };
26
27 std::unordered_map<int, double> bc_map;
28 bc_map.reserve(bcs.size());
29 for (const auto& e : bcs)
30 bc_map[e.flat_idx] = static_cast<double>(e.voltage);
31
32 constexpr int DI[6] = { 1,-1, 0, 0, 0, 0};
33 constexpr int DJ[6] = { 0, 0, 1,-1, 0, 0};
34 constexpr int DK[6] = { 0, 0, 0, 0, 1,-1};
35
36 constexpr double penalty = 1e10;
37 num::Vector b(N, 0.0);
38
39 for (const auto& e : bcs) {
40 b[e.flat_idx] = penalty * static_cast<double>(e.voltage);
41 const int ei = e.flat_idx % nx;
42 const int ej = (e.flat_idx / nx) % ny;
43 const int ek = e.flat_idx / (nx * ny);
44 for (int d = 0; d < 6; ++d) {
45 int ni = ei + DI[d], nj = ej + DJ[d], nk = ek + DK[d];
46 if (ni < 0 || ni >= nx || nj < 0 || nj >= ny || nk < 0 || nk >= nz)
47 continue;
48 int nidx = flat(ni, nj, nk);
49 if (bc_map.count(nidx)) continue;
50 double sigma_face = 0.5 * (sg(ei,ej,ek) + sg(ni,nj,nk));
51 b[nidx] += sigma_face * inv_dx2 * static_cast<double>(e.voltage);
52 }
53 }
54
55 auto matvec = [&](const num::Vector& v, num::Vector& Av) {
56 for (int k = 0; k < nz; ++k)
57 for (int j = 0; j < ny; ++j)
58 for (int i = 0; i < nx; ++i) {
59 int id = flat(i, j, k);
60 if (bc_map.count(id)) { Av[id] = penalty * v[id]; continue; }
61 double Av_ijk = 0.0;
62 for (int d = 0; d < 6; ++d) {
63 int ni = std::max(0, std::min(i + DI[d], nx-1));
64 int nj = std::max(0, std::min(j + DJ[d], ny-1));
65 int nk = std::max(0, std::min(k + DK[d], nz-1));
66 int nidx = flat(ni, nj, nk);
67 double sigma_face = 0.5 * (sg(i,j,k) + sg(ni,nj,nk));
68 double v_nb = bc_map.count(nidx) ? 0.0 : v[nidx];
69 Av_ijk += sigma_face * inv_dx2 * (v[id] - v_nb);
70 }
71 Av[id] = Av_ijk;
72 }
73 };
74
75 num::Vector xv = phi.grid().to_vector();
76 auto result = num::cg_matfree(matvec, b, xv, tol,
77 static_cast<num::idx>(max_iter));
78 phi.grid().from_vector(xv);
79 return result;
80}
81
83 const ScalarField3D& phi) {
84 const num::Grid3D& g = phi.grid();
85 const num::Grid3D& sg = sigma.grid();
86 const int nx = g.nx(), ny = g.ny(), nz = g.nz();
87 const double inv2dx = 1.0 / (2.0 * g.dx());
88
89 ScalarField3D Q(nx, ny, nz, phi.dx(), phi.ox(), phi.oy(), phi.oz());
90 for (int k = 0; k < nz; ++k)
91 for (int j = 0; j < ny; ++j)
92 for (int i = 0; i < nx; ++i) {
93 int ip = std::min(i+1,nx-1), im = std::max(i-1,0);
94 int jp = std::min(j+1,ny-1), jm = std::max(j-1,0);
95 int kp = std::min(k+1,nz-1), km = std::max(k-1,0);
96 double dpdx = (g(ip,j,k) - g(im,j,k)) * inv2dx;
97 double dpdy = (g(i,jp,k) - g(i,jm,k)) * inv2dx;
98 double dpdz = (g(i,j,kp) - g(i,j,km)) * inv2dx;
99 Q.grid().set(i, j, k, sg(i,j,k) * (dpdx*dpdx + dpdy*dpdy + dpdz*dpdz));
100 }
101 return Q;
102}
103
104} // namespace physics
double dx() const
Definition grid3d.hpp:23
int ny() const
Definition grid3d.hpp:21
int nz() const
Definition grid3d.hpp:22
int nx() const
Definition grid3d.hpp:20
void set(int i, int j, int k, real v)
Definition grid3d.hpp:29
Grid3D & grid()
Definition fields.hpp:29
static num::SolverResult solve_potential(ScalarField3D &phi, const ScalarField3D &sigma, const std::vector< ElectrodeBC > &bcs, double tol=1e-6, int max_iter=500)
Definition field.cpp:13
static ScalarField3D joule_heating(const ScalarField3D &sigma, const ScalarField3D &phi)
Compute Joule heating power density Q = σ|∇φ|² [W/m³].
Definition field.cpp:82
EM-specific field types and solvers.
std::size_t idx
Definition types.hpp:11
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