differt.em.GeometricFieldSolver#
- class GeometricFieldSolver(tx_polarization='V', rx_polarization='V', radio_materials=None, tx_wavefront_radii=0.0, interaction_matrices=None)[source]#
Bases:
AbstractFieldSolverComputes fields for
TracedPaths.This solver combines a transmitter excitation, one 2x2 dyadic transition (Jones) matrix per interaction along each path, and a receiver projection, following Geometrical Optics (GO) and the Uniform Theory of Diffraction (UTD), see
differt.em.To support an additional
InteractionType, subclass this solver, override the matching*_matrixmethod (e.g.,diffraction_matrix), and add the corresponding member tosupported_interaction_types. Both steps are required: the latter is what letstransition_matricesstayjax.jit-compatible, as it decides, from a plain Python (i.e., non-traced) set, which of the*_matrixmethods to call, rather than branching on the (traced) contents ofTracedPaths.interaction_types.Solver-specific configuration (
tx_polarization,rx_polarization,radio_materials,tx_wavefront_radii) lives on the solver instance itself, as plain attributes – mirroringAbstractPathSolverand its subclasses (e.g.,ExhaustivePathTracer) – rather than being passed as keyword arguments at call time; every*_matrixmethod,transition_matrices,compute_fields, andspreading_factortherefore only take(paths, mesh, frequency)(the per-call data), reading their configuration fromself.Examples
from differt.em import ( GeometricFieldSolver, InteractionType, compute_received_fields, ) class MyFieldSolver(GeometricFieldSolver): supported_interaction_types = frozenset({ InteractionType.REFLECTION, InteractionType.DIFFRACTION, }) def diffraction_matrix( self, paths, mesh, frequency ): ... # your implementation, using 'self.radio_materials' etc. fields = compute_received_fields( paths, mesh, frequency, solver=MyFieldSolver() )
Note
Unlike Sionna RT, which only supports a point source (equivalently, a wavefront that is already spherical, with a radius of curvature equal to the geometric distance traveled), this solver supports a non-planar incident wavefront at the transmitter, via the
tx_wavefront_radiiattribute, used internally bycompute_fields,transition_matrices,diffraction_matrix, andspreading_factor(all overridable). It accepts either a single value, for an isotropic (spherical) wavefront, a(rho_s, rho_p)tuple, for a general astigmatic wavefront with unequal principal radii along the s- and p-planes, orNone, for a planar wavefront: a chain of flat-mirror reflections and/or transmissions leaves both principal radii unchanged (only the total path length, plus each ofrho_s/rho_p, matters, regardless of order), since neither interaction does anything but fold the ray direction (for a flat mirror) or leave it unchanged (for a thin transmitting slab).An astigmatic
tx_wavefront_radiicombined with at most one diffraction interaction anywhere along the path is not currently supported (and raises at runtime, viaequinox.error_if): computing the diffraction point’s edge-fixed radius of curvature would require tracking the wavefront’s principal-axis orientation along the path, not just its two radii. For a single isotropic radius (or a planar wavefront), the existing behavior is unchanged: the UTD distance parameter and the post-diffraction (cylindrical) spreading factor both use the cumulative path length up to the diffraction point, plustx_wavefront_radii. This also only tracks the wavefront up to the first diffraction: a path with a diffraction bounce followed by further interactions would, in general, need to track the diffracted wavefront’s curvature onward, since diffraction turns even an initially-spherical wavefront astigmatic;L_ialready accepts the general astigmatic case (rho_1_i,rho_2_i,rho_e_i) for whoever wants to extenddiffraction_matrixthat far. Sionna RT has no equivalent feature to compare against;tx_wavefront_radii’s correctness instead rests on the geometric argument above (also checked against the equivalent of physically moving the transmitter back bytx_wavefront_radii, see the test suite).When
tx_polarizationis set to anAbstractAntennainstance, its ownAbstractAntenna.wavefront_radiiis used instead oftx_wavefront_radii.Attributes
Optional mapping of custom interaction matrix functions.
The mapping of material properties.
The receiver antenna polarization or pattern.
The interaction types handled by
transition_matrices.The transmitter antenna polarization or pattern.
The radius (or radii) of curvature of the incident wavefront at the transmitter.
Methods
compute_fields(paths, mesh, frequency, *[, ...])Compute the received complex fields for each path.
diffraction_matrix(paths, mesh, frequency)Compute the per-bounce diffraction transition matrix, for every bounce.
reflection_matrix(paths, mesh, frequency)Compute the per-bounce reflection transition matrix, for every bounce.
ris_matrix(paths, mesh, frequency)Compute the per-bounce RIS (Reconfigurable Intelligent Surface) transition matrix.
scattering_matrix(paths, mesh, frequency)Compute the per-bounce diffuse scattering transition matrix, for every bounce.
spreading_factor(paths[, mesh, wavefront_radii])Compute the wavefront spreading factor for each path.
transition_matrices(paths, mesh, frequency)Compute one transition matrix per bounce, dispatching on the bounce's interaction type.
transmission_matrix(paths, mesh, frequency)Compute the per-bounce transmission transition matrix, for every bounce.
Detailed documentation
- compute_fields(paths, mesh, frequency, *, wavefront_radii=None)[source]#
Compute the received complex fields for each path.
Reads
tx_polarization,rx_polarization,radio_materials, andtx_wavefront_radiifromself– seeGeometricFieldSolver.- Parameters:
paths (
TracedPaths) – The paths.mesh (
Mesh) – The triangle mesh of the scene.frequency (
Float[ArrayLike, "*#batch"]) –The operating frequency (or frequencies) in Hz.
Can be an array broadcastable against
paths’ batch dimensions, e.g., to assign a different frequency to different transmitters.wavefront_radii (
Float[ArrayLike, "*#batch"]|tuple[Float[ArrayLike, "*#batch"],Float[ArrayLike, "*#batch"]] |WavefrontState|None) – Optional custom wavefront radii orWavefrontStateto use instead of resolving fromself.
- Return type:
- Returns:
The received complex fields.
- diffraction_matrix(paths, mesh, frequency)[source]#
Compute the per-bounce diffraction transition matrix, for every bounce.
Implements the Uniform Theory of Diffraction (UTD), via
diffraction_coefficients, for a wedge formed by two adjacent mesh faces. The convention for aDIFFRACTIONbounce is thatTracedPaths.objectsholds a flat half-edge index3 * triangle_index + local_edge_index(local_edge_indexbeing 0, 1, or 2), matching Sionna RT’s own wedge addressing andMesh.wedge_angles’s(num_triangles, 3)shape — unlikeREFLECTION/TRANSMISSION, which index a plain triangle. This (rather thanMesh.diffraction_edges, which deduplicates shared edges via a non-jax.jit-compatibleunique) keeps this methodjax.jit-compatible.The wedge-face reflection coefficients (used for the shadow- and reflection-boundary terms) use the same finite-thickness slab model as
reflection_matrix, matching Sionna RT’s dielectric-wedge diffraction model.The transmitter’s non-planar wavefront (
tx_wavefront_radii, or the value returned byAbstractAntenna.wavefront_radiiwhentx_polarizationis anAbstractAntenna) only affects aDIFFRACTIONbounce that is the first interaction along a path; see the note inGeometricFieldSolver.None(a planar wavefront, the \(\rho_0 \to \infty\) limit) uses the well-known plane-wave-incidence distance parameter formula, rather than evaluating the general one at \(\rho_0 \to \infty\) (which would give a 0/0 division); an astigmatic(rho_s, rho_p)tuple (or aWavefrontState) is instead handled via curvature transport throughpropagate_wavefront– seespreading_factor.- Parameters:
paths (
TracedPaths) – The paths.mesh (
Mesh) – The triangle mesh of the scene.frequency (
Float[ArrayLike, "*#batch"]) – The operating frequency (or frequencies) in Hz.
- Return type:
- Returns:
One transition matrix per bounce.
- Raises:
ValueError – If the mesh does not contain face materials.
-
interaction_matrices:
Mapping[InteractionType|int,Any] |None= None# Optional mapping of custom interaction matrix functions.
Keyed by
InteractionType(or integer). Overrides or extends the built-in interaction matrix methods (such asreflection_matrix,diffraction_matrix,scattering_matrix,transmission_matrix,ris_matrix) without subclassing.
- reflection_matrix(paths, mesh, frequency)[source]#
Compute the per-bounce reflection transition matrix, for every bounce.
The reflection coefficients are obtained from
reflection_coefficients(or the thin-slab variant thereof, when the material has a finite thickness), then expressed in the local (theta, phi) spherical basis of the incoming and outgoing ray segments.- Parameters:
paths (
TracedPaths) – The paths.mesh (
Mesh) – The triangle mesh of the scene.frequency (
Float[ArrayLike, "*#batch"]) – The operating frequency (or frequencies) in Hz.
- Return type:
- Returns:
One transition matrix per bounce.
- ris_matrix(paths, mesh, frequency)[source]#
Compute the per-bounce RIS (Reconfigurable Intelligent Surface) transition matrix.
Warning
Not implemented yet. Subclasses can override this method to provide custom RIS physics.
- Parameters:
paths (
TracedPaths) – The paths.mesh (
Mesh) – The triangle mesh of the scene.frequency (
Float[ArrayLike, "*#batch"]) – The operating frequency (or frequencies) in Hz.
- Raises:
NotImplementedError – Unconditionally, as RIS modeling is reserved for future implementation.
- Return type:
-
rx_polarization:
Any= 'V'# The receiver antenna polarization or pattern. See
tx_polarization.
- scattering_matrix(paths, mesh, frequency)[source]#
Compute the per-bounce diffuse scattering transition matrix, for every bounce.
Implements a Lambertian rough-surface scattering model, following Degli-Esposti’s directive model (as also used by Sionna RT’s
RadioMaterial), adapted to DiffeRT’s exact/deterministic path model:Warning
Sionna RT’s scattering model is defined in terms of a Monte Carlo ray-tube solid angle \(\Omega\), which has no equivalent for a single, deterministic point-to-point path. This method instead uses the solid angle subtended by the scattering triangle, as seen from the next path vertex, \(\mathrm{d}A / s^2\), as a geometrically-motivated substitute (\(\mathrm{d}A\) being the triangle’s area and \(s\) the distance to the next vertex). This is a physically-motivated but distinct adaptation: because Sionna RT’s model is stochastic, this method should not be expected to numerically match its output for a single path, only in a statistical (many-samples) sense.
Given the specular reflection coefficients \(r_s, r_p\) (
reflection_matrix, ignoring the scattering-coefficient energy reduction) and the incident and scattered directions \(\hat{k}_i, \hat{k}_o\), the per-polarization scattered amplitude is:\[a_{s,p} = S \sqrt{f_s(\hat{k}_i, \hat{k}_o, \hat{n}) \frac{\mathrm{d}A}{s^2}} \, |r_{s,p}|,\]where \(S\) is
Material.scattering_coefficientand \(f_s\) is the material’sMaterial.scattering_pattern(normalized so that its integral over the hemisphere is 1), which defaults toLambertianPattern, \(f_s(\hat{k}_i, \hat{k}_o, \hat{n}) = \max(\hat{n}\cdot\hat{k}_o, 0) / \pi\). A custom (e.g., directive) pattern can be set per-material by subclassingAbstractScatteringPattern. A final rotation mixes the s and p channels according toMaterial.xpd_coefficient.- Parameters:
paths (
TracedPaths) – The paths.mesh (
Mesh) – The triangle mesh of the scene.frequency (
Float[ArrayLike, "*#batch"]) – The operating frequency (or frequencies) in Hz.
- Return type:
- Returns:
One transition matrix per bounce.
- spreading_factor(paths, mesh=None, *, wavefront_radii=None)[source]#
Compute the wavefront spreading factor for each path.
Reads
tx_wavefront_radii(or the value returned byAbstractAntenna.wavefront_radiiwhentx_polarizationis anAbstractAntenna) fromself, or useswavefront_radiiif provided explicitly.For a path with no diffraction interaction, this is the general astigmatic-ray-tube spreading factor, \(1/\sqrt{(\rho_s+L)(\rho_p+L)}\), where \(L\) is the total path length and \(\rho_s\), \(\rho_p\) are the wavefront’s two principal radii of curvature at the transmitter (plus
tx_wavefront_radii, for a non-planar source); this is exact for any chain of flat-mirror reflections and/or transmissions, regardless of how many interactions the path has, since neither changes a wavefront’s principal radii (only a flat mirror’s image-method folds the ray direction). Iftx_wavefront_radiiisNone(a planar wavefront), this is instead exactly1(a plane wave does not spread at all).For a path containing a diffraction interaction, the wavefront becomes cylindrical past the diffraction point, and the spreading factor becomes \(1/\sqrt{\rho^i s(\rho^i+s)}\), where \(\rho^i\) is the incident wavefront’s radius of curvature at the diffraction point (the cumulative path length before it, plus
tx_wavefront_radiiif it is the first interaction) and \(s\) is the path length after it, matching Sionna RT’s model whentx_wavefront_radiiis left at its default of0. For a planar wavefront, this is instead \(1/\sqrt{s}\), the classic cylindrical-spreading law for an edge illuminated by a plane wave (\(\rho^i \to \infty\) independently of \(s\), unlike the amplitude, which would incorrectly vanish if this limit were taken naively). For general astigmatic wavefronts, the spreading factor is evaluated using Kouyoumjian-Pathak / McNamara curvature transport viapropagate_wavefront.- Parameters:
paths (
TracedPaths) – The paths.mesh (
Mesh|None) – The scene triangle mesh, required when evaluating general astigmatic wavefronts combined with diffraction.wavefront_radii (
Float[ArrayLike, "*#batch"]|tuple[Float[ArrayLike, "*#batch"],Float[ArrayLike, "*#batch"]] |WavefrontState|None) – Optional custom wavefront configuration to overrideself.
- Return type:
- Returns:
The spreading factor for each path.
-
supported_interaction_types:
ClassVar[frozenset[InteractionType]] = frozenset({InteractionType.REFLECTION, InteractionType.DIFFRACTION, InteractionType.SCATTERING, InteractionType.TRANSMISSION})# The interaction types handled by
transition_matrices.Subclasses adding support for a new interaction type must add the corresponding member here, in addition to overriding the matching
*_matrixmethod.
- transition_matrices(paths, mesh, frequency)[source]#
Compute one transition matrix per bounce, dispatching on the bounce’s interaction type.
Only interaction types listed in
supported_interaction_typesare ever dispatched to (a plain Python, non-traced, check), so overriding one of the*_matrixmethods without adding the type here has no effect. Any bounce whose interaction type is not covered raises at runtime (works underjax.jittoo).- Parameters:
paths (
TracedPaths) – The paths.mesh (
Mesh) – The triangle mesh of the scene.frequency (
Float[ArrayLike, "*#batch"]) – The operating frequency (or frequencies) in Hz.
- Return type:
- Returns:
One transition matrix per bounce.
- transmission_matrix(paths, mesh, frequency)[source]#
Compute the per-bounce transmission transition matrix, for every bounce.
This is a thin-surface transmission model: the transmitting object is treated as a single dielectric slab whose thickness is read from
Material.thickness(accounting for multiple internal reflections in closed form, per ITU-R P.2040-3 eq. 43b/44), evaluated at the incidence angle and combined coherently. This matches Sionna RT’sRadioMaterial/ITURadioMaterialtransmission model, and, as in Sionna RT, the ray direction is not bent by refraction (the wall is assumed thin enough that the geometric deflection is negligible); only the field amplitude/phase are affected.This is a deliberate simplification, not an architectural constraint: a volumetric transmission model, where the effective thickness is instead derived from where a ray enters and exits a solid object’s geometry (rather than from a fixed per-material property), can be added later as a sibling implementation, by overriding this method in a subclass.
- Parameters:
paths (
TracedPaths) – The paths.mesh (
Mesh) – The triangle mesh of the scene.frequency (
Float[ArrayLike, "*#batch"]) – The operating frequency (or frequencies) in Hz.
- Return type:
- Returns:
One transition matrix per bounce.
-
tx_polarization:
Any= 'V'# The transmitter antenna polarization or pattern.
Either
"V","H", a Jones vector, or anAbstractAntenna(that provides.fields(...)and.wavefront_radii(...)).To model different antennas across a scene, pass a single antenna instance whose array fields carry their own batch dimension, broadcastable against the paths’ batch dimensions – either one antenna model shared by every transmitter, or one antenna model per transmitter (
AbstractAntennais aequinox.Module, so this works out of the box).When this is an
AbstractAntennainstance, itsAbstractAntenna.wavefront_radiiis used instead oftx_wavefront_radii(which only serves as a fallback for a plain polarization string/vector, since those carry no wavefront-curvature information of their own); itsfrequencyis also used bycompute_received_fieldswhen nofrequencyis passed explicitly.
-
tx_wavefront_radii:
Float[ArrayLike, "*#batch"]|tuple[Float[ArrayLike, "*#batch"],Float[ArrayLike, "*#batch"]] |WavefrontState|None= 0.0# The radius (or radii) of curvature of the incident wavefront at the transmitter.
For a non-planar (near-field) source. This is a distance, and
0andNoneare its two opposite limits, not two ways of saying the same thing:0(the default) is the near-distance limit, an ideal point source located exactly at the transmitter, matching Sionna RT’s implicit assumption;Noneis the far-distance limit (\(\rho_0 \to \infty\)), an ideal plane wave, e.g., a source far enough away that its curvature is negligible – seeAbstractFarFieldAntenna. Either of those, a single finite value (spherical wavefront), or a(rho_s, rho_p)tuple (astigmatic wavefront, with unequal principal radii along the s- and p-planes) may be passed. Ignored whentx_polarizationis anAbstractAntennainstance – seetx_polarization.