Skip to content

Scattering spec

spec

The problem specification: one description, solved by any backend.

Units: lengths and wavelengths in nanometres (vacuum wavelength). Conventions: exp(-iomegat); cross sections in nm^2; efficiencies are normalised by the geometric cross section of the volume-equivalent sphere, pi * r_eq^2, so they are comparable across methods and shapes.

SCHEMA_VERSION module-attribute

SCHEMA_VERSION = '0.1'

Shape module-attribute

Shape = Annotated[Union[Sphere, Spheroid, Cylinder, LayeredSphere], Field(discriminator='kind')]

Sphere

Bases: _Model

kind class-attribute instance-attribute

kind: Literal['sphere'] = 'sphere'

radius_nm class-attribute instance-attribute

radius_nm: float = Field(gt=0)

volume

volume() -> float

bounding_half_extent

bounding_half_extent() -> ndarray

contains

contains(p: ndarray) -> ndarray

Spheroid

Bases: _Model

Spheroid with symmetry axis along z.

kind class-attribute instance-attribute

kind: Literal['spheroid'] = 'spheroid'

semi_axis_xy_nm class-attribute instance-attribute

semi_axis_xy_nm: float = Field(gt=0)

semi_axis_z_nm class-attribute instance-attribute

semi_axis_z_nm: float = Field(gt=0)

volume

volume() -> float

bounding_half_extent

bounding_half_extent() -> ndarray

contains

contains(p: ndarray) -> ndarray

Cylinder

Bases: _Model

Flat-ended cylinder with axis along z.

kind class-attribute instance-attribute

kind: Literal['cylinder'] = 'cylinder'

radius_nm class-attribute instance-attribute

radius_nm: float = Field(gt=0)

length_nm class-attribute instance-attribute

length_nm: float = Field(gt=0)

volume

volume() -> float

bounding_half_extent

bounding_half_extent() -> ndarray

contains

contains(p: ndarray) -> ndarray

Shell

Bases: _Model

thickness_nm class-attribute instance-attribute

thickness_nm: float = Field(gt=0)

material instance-attribute

material: Material

LayeredSphere

Bases: _Model

Core-shell / multilayer sphere. The particle's material is the core; shells are listed from the inside out.

kind class-attribute instance-attribute

kind: Literal['layered_sphere'] = 'layered_sphere'

core_radius_nm class-attribute instance-attribute

core_radius_nm: float = Field(gt=0)

shells class-attribute instance-attribute

shells: list[Shell] = Field(min_length=1)

radii_nm property

radii_nm: list[float]

radius_nm property

radius_nm: float

volume

volume() -> float

bounding_half_extent

bounding_half_extent() -> ndarray

contains

contains(p: ndarray) -> ndarray

region

region(p: ndarray) -> ndarray

-1 outside, 0 in the core, i in shell i.

Particle

Bases: _Model

shape instance-attribute

shape: Shape

material class-attribute instance-attribute

material: Material = Field(description='Particle material (the core for layered spheres).')

position_nm class-attribute instance-attribute

position_nm: tuple[float, float, float] = (0.0, 0.0, 0.0)

region_materials

region_materials() -> list

Materials indexed by region: [core/body, shell 1, shell 2, ...].

region

region(p: ndarray) -> ndarray

Region index per point in the particle frame (-1 = outside).

Substrate

Bases: _Model

Semi-infinite half-space z < interface_z_nm with the given material.

material instance-attribute

material: Material

interface_z_nm class-attribute instance-attribute

interface_z_nm: float = 0.0

PlaneWave

Bases: _Model

kind class-attribute instance-attribute

kind: Literal['plane_wave'] = 'plane_wave'

direction class-attribute instance-attribute

direction: tuple[float, float, float] = Field((0.0, 0.0, 1.0), description='Propagation direction.')

polarization class-attribute instance-attribute

polarization: tuple[float, float, float] = Field((1.0, 0.0, 0.0), description='Real E-field direction.')

unit_vectors

unit_vectors() -> tuple[ndarray, ndarray]

WavelengthRange

Bases: _Model

start_nm class-attribute instance-attribute

start_nm: float = Field(gt=0)

stop_nm class-attribute instance-attribute

stop_nm: float = Field(gt=0)

num class-attribute instance-attribute

num: int = Field(ge=1)

values

values() -> ndarray

NearFieldRequest

Bases: _Model

Total electric field on a square plane through the scene.

plane class-attribute instance-attribute

plane: Literal['xy', 'xz', 'yz'] = 'xz'

offset_nm class-attribute instance-attribute

offset_nm: float = Field(0.0, description='Position of the plane along its normal.')

half_width_nm class-attribute instance-attribute

half_width_nm: float = Field(gt=0)

points class-attribute instance-attribute

points: int = Field(101, ge=2, description='Samples per axis.')

wavelengths_nm class-attribute instance-attribute

wavelengths_nm: list[float] = Field(min_length=1, description='Vacuum wavelengths to sample.')

FarFieldRequest

Bases: _Model

Differential scattering cross section dC_sca/dOmega on a theta x phi grid.

theta is measured from the incident direction; phi is the azimuth around it, measured from the incident polarization (phi=0 is the E-plane, 90 the H-plane).

theta_deg class-attribute instance-attribute

theta_deg: list[float] = Field(min_length=1)

phi_deg class-attribute instance-attribute

phi_deg: list[float] = Field([0.0, 90.0], min_length=1)

wavelengths_nm class-attribute instance-attribute

wavelengths_nm: list[float] = Field(min_length=1)

Outputs

Bases: _Model

cross_sections class-attribute instance-attribute

cross_sections: bool = True

near_field class-attribute instance-attribute

near_field: NearFieldRequest | None = None

far_field class-attribute instance-attribute

far_field: FarFieldRequest | None = None

Simulation

Bases: _Model

A complete scattering problem. Serialisable to/from JSON.

kind class-attribute instance-attribute

kind: Literal['scattering'] = 'scattering'

schema_version class-attribute instance-attribute

schema_version: Literal['0.1'] = SCHEMA_VERSION

particles class-attribute instance-attribute

particles: list[Particle] = Field(min_length=1)

medium_index class-attribute instance-attribute

medium_index: float = Field(1.0, gt=0, description='Real refractive index of the host medium.')

illumination class-attribute instance-attribute

illumination: PlaneWave = PlaneWave()

wavelengths class-attribute instance-attribute

wavelengths: list[float] | WavelengthRange = Field(description='Vacuum wavelengths in nm.')

substrate class-attribute instance-attribute

substrate: Substrate | None = Field(None, description='Optional half-space below the particles.')

orientation_average class-attribute instance-attribute

orientation_average: bool = Field(False, description='Average cross sections over all particle orientations.')

outputs class-attribute instance-attribute

outputs: Outputs = Outputs()

options class-attribute instance-attribute

options: dict[str, dict[str, Any]] = Field(default_factory=dict, description="Solver options keyed by method or backend name, e.g. {'dda': {'dipoles_per_diameter': 20}}.")

options_for

options_for(backend_name: str, method: str) -> dict[str, Any]

Method-level options overlaid with backend-specific ones.

wavelength_array

wavelength_array() -> ndarray

equivalent_radius_nm

equivalent_radius_nm() -> float

to_json

to_json(**kw) -> str

from_json classmethod

from_json(text: str) -> 'Simulation'

load classmethod

load(path: str | Path) -> 'Simulation'

json_schema

json_schema() -> dict

JSON Schema of :class:Simulation, for agents and validators.

dumps_schema

dumps_schema() -> str