Source code for skyscapes.disk.composite

"""CompositeDisk: sum of multiple ``AbstractDisk`` components.

Mirrors how ``skyscapes.scene.System`` composes multiple ``Planet`` objects
via a tuple: a ``CompositeDisk`` holds a tuple of disk components and
renders their summed ``surface_brightness`` on a shared grid.

All components must share the same ``spatial_extent()`` so the per-component
rendered arrays can be added directly without resampling. Mismatched
geometries are rejected at construction.
"""

from __future__ import annotations

from jaxtyping import Array

from .._repr import indent
from .base import AbstractDisk


[docs] class CompositeDisk(AbstractDisk): """Sum of multiple disk components rendered on a shared grid. Attributes: components: Tuple of ``AbstractDisk`` instances. At least one component is required. All components must report the same ``spatial_extent()`` so their rendered ``(ny, nx)`` arrays sum elementwise. """ components: tuple[AbstractDisk, ...]
[docs] def __check_init__(self): """Reject empty composites and mismatched component extents.""" if len(self.components) == 0: raise ValueError("CompositeDisk requires at least one component.") ref_extent = self.components[0].spatial_extent() for i, c in enumerate(self.components[1:], start=1): ext = c.spatial_extent() if ext != ref_extent: raise ValueError( f"CompositeDisk component {i} has spatial_extent={ext}, " f"which does not match component 0's {ref_extent}. All " f"components must share the same grid for direct summation." )
[docs] def surface_brightness( self, wavelength_nm: Array, time_jd: Array, incl_deg: Array, pa_deg: Array, ) -> Array: """Return the per-pixel sum of all component contrast maps.""" contrib = self.components[0].surface_brightness( wavelength_nm, time_jd, incl_deg, pa_deg ) for c in self.components[1:]: contrib = contrib + c.surface_brightness( wavelength_nm, time_jd, incl_deg, pa_deg ) return contrib
[docs] def spatial_extent(self) -> tuple[float, float]: """Return the shared ``(width_arcsec, height_arcsec)``.""" return self.components[0].spatial_extent()
[docs] def __repr__(self) -> str: """Nested summary listing each component disk.""" lines = [f"CompositeDisk(n_components={len(self.components)})"] for i, c in enumerate(self.components): lines.append(indent(f"[{i}] {c!r}")) return "\n".join(lines)