Source code for tidy3d.components.heat.data.monitor_data

"""Monitor level data, store the DataArrays associated with a single heat monitor."""
from __future__ import annotations
from typing import Union, Tuple, Optional

from abc import ABC

import pydantic.v1 as pd

from ..monitor import TemperatureMonitor, HeatMonitorType
from ...base import skip_if_fields_missing
from ...base_sim.data.monitor_data import AbstractMonitorData
from ...data.data_array import SpatialDataArray
from ...data.dataset import TriangularGridDataset, TetrahedralGridDataset
from ...types import ScalarSymmetry, Coordinate, annotate_type
from ....constants import KELVIN

from ....log import log


class HeatMonitorData(AbstractMonitorData, ABC):
    """Abstract base class of objects that store data pertaining to a single :class:`HeatMonitor`."""

    monitor: HeatMonitorType = pd.Field(
        ...,
        title="Monitor",
        description="Monitor associated with the data.",
    )

    symmetry: Tuple[ScalarSymmetry, ScalarSymmetry, ScalarSymmetry] = pd.Field(
        (0, 0, 0),
        title="Symmetry",
        description="Symmetry of the original simulation in x, y, and z.",
    )

    symmetry_center: Coordinate = pd.Field(
        (0, 0, 0),
        title="Symmetry Center",
        description="Symmetry center of the original simulation in x, y, and z.",
    )

    @property
    def symmetry_expanded_copy(self) -> HeatMonitorData:
        """Return copy of self with symmetry applied."""
        return self.copy()


[docs] class TemperatureData(HeatMonitorData): """Data associated with a :class:`TemperatureMonitor`: spatial temperature field. Example ------- >>> from tidy3d import TemperatureMonitor, SpatialDataArray >>> import numpy as np >>> temp_data = SpatialDataArray( ... np.ones((2, 3, 4)), coords={"x": [0, 1], "y": [0, 1, 2], "z": [0, 1, 2, 3]} ... ) >>> temp_mnt = TemperatureMonitor(size=(1, 2, 3), name="temperature") >>> temp_mnt_data = TemperatureData( ... monitor=temp_mnt, temperature=temp_data, symmetry=(0, 1, 0), symmetry_center=(0, 0, 0) ... ) >>> temp_mnt_data_expanded = temp_mnt_data.symmetry_expanded_copy """ monitor: TemperatureMonitor = pd.Field( ..., title="Monitor", description="Temperature monitor associated with the data." ) temperature: Optional[ Union[SpatialDataArray, annotate_type(Union[TriangularGridDataset, TetrahedralGridDataset])] ] = pd.Field( ..., title="Temperature", description="Spatial temperature field.", units=KELVIN, )
[docs] @pd.validator("temperature", always=True) @skip_if_fields_missing(["monitor"]) def warn_no_data(cls, val, values): """Warn if no data provided.""" mnt = values.get("monitor") if val is None: log.warning( f"No data is available for monitor '{mnt.name}'. This is typically caused by " "monitor not intersecting any solid medium." ) return val
@property def symmetry_expanded_copy(self) -> TemperatureData: """Return copy of self with symmetry applied.""" if self.temperature is None: return self.updated_copy(symmetry=(0, 0, 0)) if all(sym == 0 for sym in self.symmetry): return self.copy() new_temp = self.temperature for dim in range(3): # do not expand monitor with zero size along symmetry direction # this is done because 2d unstructured data does not support this if self.symmetry[dim] == 1 and self.monitor.size[dim] != 0: new_temp = new_temp.reflect(axis=dim, center=self.symmetry_center[dim]) return self.updated_copy(temperature=new_temp, symmetry=(0, 0, 0))
HeatMonitorDataType = Union[TemperatureData]