The world model
How a Core Scene is built from structures, materials and antenna endpoints, what a snapshot is, and what Core leaves to the solvers.
Core describes the world; solvers simulate it. A Core Scene is a logical description: shapes, what they are made of, where the antennas are and how things move. It holds no solver state, no GPU buffers and no results. Each solver reads the scene and compiles it into its own runtime resources.
The parts of a scene#
| Part | Class | What it holds |
|---|---|---|
| Scene | Scene | A tuple of structures, a tuple of endpoints, a read-only metadata mapping and four version counters. |
| Structure | Structure | One geometry, one material, a name, tags, metadata and stable IDs. Optional UV coordinates and a phase screen. |
| Geometry | Box, Sphere, ..., Mesh, or any GeometrySpec | Shape and pose. Can produce a triangle mesh and, for the built-in classes, a signed distance. |
| Material | PhysicalMaterial, or any MaterialSpec | Electromagnetic and surface parameters. Can report its permittivity at a frequency. |
| Endpoint | AntennaState, ReceiverGrid | A transmitter or receiver: position, orientation, polarization, array layout, pattern and power. |
Scene
├── structures: (Structure, ...)
│ ├── geometry -> Box | Sphere | ... | Mesh
│ └── material -> PhysicalMaterial
└── endpoints: (AntennaState | ReceiverGrid, ...)A scene with no structures is valid, and so is a scene with no endpoints. Which parts a solver needs is up to the solver.
Snapshots#
Solvers do not read a Scene directly while they run. They read a SceneSnapshot: the world at one time time_s, with each structure wrapped in a StructureState and each endpoint in an EndpointState.
scene.snapshot(time_s)returns a static snapshot. No structure or endpoint moves.DynamicScene(scene, ...).at(time_s)returns a snapshot in which some structures carry aRigidMotionor aDeformationState, and some endpoints carry aRigidMotion.
Core records motion; it does not apply it. A snapshot keeps the authored geometry untouched and attaches the motion next to it. The solver composes the two, in this order:
- A deformation replaces the authored local mesh vertices (
DeformationState.vertices) or adds offsets to them (DeformationState.offsets). - The authored geometry transform (scale, rotation, position) is applied.
RigidMotion.rotationis composed on the left of the authored rotation, andRigidMotion.translation(world frame) is added last.
Endpoint motion follows the same rule, after the antenna's own orientation. See Animate a scene.
Immutable containers, live tensors#
Scene, Structure, PhysicalMaterial, AntennaState and the other contracts are frozen dataclasses. You cannot assign to their fields. To change a scene, you build a new one, usually with the with_* methods (with_structure_geometry, with_material, with_endpoints, ...). See Update a scene.
The tensors inside are not frozen. Core stores the exact tensor objects you pass, so an optimizer can update them in place and every scene that refers to them sees the new values. The scene's version counters notice such in-place changes. See Tensors and gradients and Identity and versions.
Contracts, not base classes#
Structure accepts any object that satisfies two runtime-checkable protocols:
GeometrySpec: has akindstring and ato_mesh(segments=16)method.MaterialSpec: has aname, and the methodscapabilities(),evaluate_static()andevaluate_at_frequency(frequency).
So a solver or a Plugin can add its own geometry or material type without subclassing a Core class. Radar's SMPL body and Maxwell's PolySlab are geometry types defined this way, outside Core. See Write your own geometry or material.
What Core does not do#
- It does not trace rays, solve fields or store results. That is the job of Maxwell, Radar and Channel.
- It does not compile scenes into GPU resources or cache them. Each solver owns its compiled scene, native resources and caches, keyed on Core's IDs and versions.
- It reads one file format, Wavefront OBJ (
Mesh.from_obj), and has no scene file format of its own.