Source code for tidy3d.components.base_sim.monitor
"""Abstract bases for classes that define how data is recorded from simulation."""
from __future__ import annotations
from abc import ABC, abstractmethod
import numpy as np
import pydantic.v1 as pd
from tidy3d.components.base import cached_property
from tidy3d.components.geometry.base import Box
from tidy3d.components.types import ArrayFloat1D, Axis, Numpy
from tidy3d.components.validators import _warn_unsupported_traced_argument
from tidy3d.components.viz import PlotParams, plot_params_monitor
[docs]
class AbstractMonitor(Box, ABC):
"""Abstract base class for steady-state monitors."""
name: str = pd.Field(
...,
title="Name",
description="Unique name for monitor.",
min_length=1,
)
_warn_traced_center = _warn_unsupported_traced_argument("center")
_warn_traced_size = _warn_unsupported_traced_argument("size")
@cached_property
def plot_params(self) -> PlotParams:
"""Default parameters for plotting a Monitor object."""
return plot_params_monitor
@cached_property
def geometry(self) -> Box:
""":class:`Box` representation of monitor.
Returns
-------
:class:`Box`
Representation of the monitor geometry as a :class:`Box`.
"""
return Box(center=self.center, size=self.size)
[docs]
@abstractmethod
def storage_size(self, num_cells: int, tmesh: ArrayFloat1D) -> int:
"""Size of monitor storage given the number of points after discretization.
Parameters
----------
num_cells : int
Number of grid cells within the monitor after discretization by a :class:`.Simulation`.
tmesh : Array
The discretized time mesh of a :class:`.Simulation`.
Returns
-------
int
Number of bytes to be stored in monitor.
"""
[docs]
def downsample(self, arr: Numpy, axis: Axis) -> Numpy:
"""Downsample a 1D array making sure to keep the first and last entries, based on the
spatial interval defined for the ``axis``.
Parameters
----------
arr : Numpy
A 1D array of arbitrary type.
axis : Axis
Axis for which to select the interval_space defined for the monitor.
Returns
-------
Numpy
Downsampled array.
"""
size = len(arr)
interval = self.interval_space[axis]
# There should always be at least 3 indices for "surface" monitors. Also, if the
# size along this dim is already smaller than the interval, then don't downsample.
if size < 4 or (size - 1) <= interval:
return arr
# make sure the last index is always included
inds = np.arange(0, size, interval)
if inds[-1] != size - 1:
inds = np.append(inds, size - 1)
return arr[inds]
[docs]
def downsampled_num_cells(self, num_cells: tuple[int, int, int]) -> tuple[int, int, int]:
"""Given a tuple of the number of cells spanned by the monitor along each dimension,
return the number of cells one would have after downsampling based on ``interval_space``.
"""
arrs = [np.arange(ncells) for ncells in num_cells]
return tuple((self.downsample(arr, axis=dim).size for dim, arr in enumerate(arrs)))