One kernel, many physics.
Heat conduction, mass diffusion, potential flow, groundwater seepage, and pollutant transport look like five different problems. To a finite-element solver they are one equation wearing five different labels — so physicsbase solves them with a single kernel.
There's a moment in every numerical-methods course where the professor solves the heat equation, then quietly notes that the exact same code solves diffusion, and electrostatics, and porous flow, if you just relabel the variables. It feels like a trick. It isn't — it's the deepest bit of leverage in computational physics, and we built physicsbase around it.
The one equation
Strip the labels off and every one of these steady problems is the same statement: a quantity u diffuses through a medium, driven by a source and possibly carried along by a flow.
Choosing what the symbols mean picks the physics. That's the whole idea:
| Physics | u is… | k is… |
|---|---|---|
| Heat conduction | temperature | thermal conductivity |
| Mass diffusion | concentration | diffusivity |
| Potential flow | velocity potential | 1 (∇u is the velocity) |
| Seepage / Darcy | hydraulic head | permeability |
| Electrostatics | voltage | permittivity |
Turn on the \(\mathbf{v}\cdot\nabla u\) term and it becomes convection-diffusion — a scalar being swept along by a flow field, the backbone of transport problems. Add a time derivative and it's the transient version, solved with a θ-method integrator.
What that buys an agent
One element library, one assembly path, one set of boundary conditions (prescribed value, flux, and convection), and every physics above comes for free. An agent doesn't learn five APIs — it learns one problem shape and changes the material label:
# heat: a bar with a hot end, cooling by convection at the other from femengine import FieldModel, FieldMaterial, solve_field m = FieldModel() m.add_nodes([[x] for x in 0, ...]) m.add_material("steel", FieldMaterial(k=45)) # conductivity m.set_value(0, 200) # fixed temperature m.add_convection([-1], h=15, u_inf=20) # Newton cooling T = solve_field(m).values # diffusion: identical call, k is now a diffusivity, u a concentration m.add_material("gel", FieldMaterial(k=1e-9))
What crosses the wire
Over the API it's the same story as everywhere else in physicsbase: the agent sends a JSON description of the field problem and reads a JSON answer. Here's a real one — a bar generating heat internally, held at 20 °C at both ends. The agent sends the geometry, the conductivity, the heat source, and the fixed temperatures:
"nodes": [[0],[0.25],[0.5],[0.75],[1.0]], "materials": { "steel": { "k": 45 } }, // W/m·K "elements": [ {"type":"field_line2","nodes":[0,1],"material":"steel"}, /* …3 more */ ], "element_sources": [ {"element":0,"Q":50000}, /* … */ ], // heat generation "values": [ {"node":0,"value":20}, {"node":4,"value":20} ] // held at 20°C
physicsbase returns the temperature at every node and the heat flux in every element — nothing to assemble, nothing to derive:
"values": [ 20.0, 124.17, 158.89, 124.17, 20.0 ], // °C — a parabola "fluxes": [ [-18750.0], [-6250.0], /* … */ ], // W/m² per element "summary": { "n_nodes": 5, "analysis": "field_steady" }
That peak of 158.89 °C is not approximate — it's \(20 + \dfrac{QL^2}{8k}\) to the digit, the exact textbook answer for a heated bar. Relabel k as a diffusivity and the identical exchange returns a concentration field; set it to 1 and the returned gradient is a velocity field. Same wire, same shapes, different physics.
Under the hood the conductivity matrix is assembled exactly like a stiffness matrix, the capacitance matrix exactly like a mass matrix — the structural machinery and the field machinery are siblings, which is why both are validated against the same kind of closed-form checks: a linear temperature profile down a bar, the parabolic profile under uniform heating, the boundary-layer solution of convection-diffusion.
The honest edge
This unification is powerful precisely because it's linear scalar transport. It gives you potential (inviscid) flow, which is a real and useful model, and it gives you scalar transport through a known velocity field. What it does not give you is full viscous fluid dynamics — the Navier-Stokes equations couple velocity and pressure nonlinearly and need their own machinery. We say so plainly in the docs rather than dressing potential flow up as CFD. One kernel covers an enormous amount of ground; it doesn't cover everything, and we'd rather tell you where the edge is.