Structure

Reference for Structure, which binds one geometry to one material with stable IDs, UVs and a phase screen, and for MaterialAssignment.

Structure and MaterialAssignment live in witwin.core.structure and are exported from witwin.core. Before 0.4.0, Structure lived in witwin.core.material; imports from witwin.core did not change.

from witwin.core import MaterialAssignment, Structure

Structure#

class Structure(
    geometry: GeometrySpec,
    material: MaterialSpec,
    name: str | None = None,
    priority: int = 0,
    enabled: bool = True,
    tags=(),
    metadata: Mapping[str, Any] | None = None,
    *,
    structure_id: StructureId | int | None = None,
    material_id: MaterialId | int | None = None,
    assignment_id: AssignmentId | int | None = None,
    surface_id: SurfaceId | int | None = None,
    primitive_ids=(),
    phase_screen: PhaseScreen | None = None,
    uv: torch.Tensor | None = None,
    face_uv: torch.Tensor | None = None,
)

One geometry bound to one material, with the IDs solvers use. Immutable (frozen dataclass).

geometryGeometrySpecrequired

Any object with kind and to_mesh(). Raises TypeError otherwise.

materialMaterialSpecrequired

Any object with name, capabilities(), evaluate_static() and evaluate_at_frequency(). Raises TypeError otherwise.

namestr | Nonedefault None

A label. Converted to str.

priorityintdefault 0

Stored for solvers, for example to resolve overlaps. Core does not use it.

enabledbooldefault True

Stored for solvers and tools. Core does not use it; a disabled structure is still part of the scene.

tagsIterable[str]default ()

Labels, stored as a tuple of strings.

metadataMapping[str, Any] | Nonedefault None

Free-form data, stored as a read-only mapping.

structure_idStructureId | int | Nonedefault None

None allocates a new ID; an integer reserves it. Must be at least 0.

material_idMaterialId | int | Nonedefault None

None takes material.material_id when the material has one (every PhysicalMaterial does), else allocates a new ID.

assignment_idAssignmentId | int | Nonedefault None

None allocates; an integer reserves.

surface_idSurfaceId | int | Nonedefault None

None allocates; an integer reserves.

primitive_idsIterable[int] | Nonedefault ()

Explicit IDs for the structure's primitives (for example triangles). Empty or None means "derive them", see primitive_id.

phase_screenPhaseScreen | Nonedefault None

A height map for this structure's surface. Raises TypeError for another type.

uvtorch.Tensor | Nonedefault None

Texture coordinates, shape (T, 2), floating point. Requires face_uv.

face_uvtorch.Tensor | Nonedefault None

UV indices per face, shape (F, 3), int32 or int64, one row per mesh face. Requires uv and a geometry with a faces tensor (a Mesh). UV and mesh tensors must share a device.

Raises ValueError when only one of uv and face_uv is given or their shapes are wrong, and TypeError for wrong dtypes or a geometry without mesh faces.

Attributes#

All constructor arguments are attributes with the same names. tags is a tuple, metadata a read-only mapping, and each *_id holds the resolved ID. primitive_ids is None when none were given.

Structure.primitive_id#

primitive_id(local_index: int) -> PrimitiveId

Returns the stable ID of the primitive at local_index. With explicit primitive_ids it returns primitive_ids[local_index] (raises IndexError past the end). Otherwise it returns (structure_id << 32) | local_index. Raises ValueError for a negative index or one that does not fit in 32 bits.

import torch
 
from witwin.core import Mesh, PhysicalMaterial, Structure
 
quad = Mesh(
    torch.tensor([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0]]),
    torch.tensor([[0, 1, 2], [0, 2, 3]]),
    fill_mode="surface",
)
tile = Structure(
    quad,
    PhysicalMaterial(eps_r=4.0),
    structure_id=3,
    uv=torch.tensor([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]),
    face_uv=torch.tensor([[0, 1, 2], [0, 2, 3]]),
)
print(tile.primitive_id(1))  # 12884901889 == (3 << 32) | 1

Note

GeometryBase.with_material(material, **kwargs) was meant as a shortcut for Structure(geometry, material, **kwargs). In 0.4.0 it raises ImportError. Call Structure(...) directly.

MaterialAssignment#

@dataclass(frozen=True)
class MaterialAssignment:
    assignment_id: AssignmentId
    surface_id: SurfaceId
    material_id: MaterialId
    material: MaterialSpec
    phase_screen: PhaseScreen | None = None

Which material, and which phase screen, covers which surface. Scene.assignments returns one per structure. Raises TypeError when material is not a MaterialSpec or phase_screen is not a PhaseScreen.