Skip to content

Commit

Permalink
make ComponentModeler.batch_data property, simplify internals, deprec…
Browse files Browse the repository at this point in the history
…ate passing path_dir to methods
  • Loading branch information
tylerflex committed Aug 30, 2024
1 parent bd84833 commit fc5a233
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 71 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added plotting functionality to voltage and current path integrals in the `microwave` plugin.
- Added convenience functions `from_terminal_positions` and `from_circular_path` to simplify setup of `VoltageIntegralAxisAligned` and `CustomCurrentIntegral2D`, respectively.
- Added `axial_ratio` to `DirectivityData.axial_ratio` for the `DirectivityMonitor`, defined as the ratio of the major axis to the minor axis of the polarization ellipse.
`ComponentModeler.batch_data` convenience property to access the `BatchData` corresponding to the component modeler run.

### Changed
- Priority is given to `snapping_points` in `GridSpec` when close to structure boundaries, which reduces the chance of them being skipped.
- Gradients for autograd are computed server-side by default. They can be computed locally (requiring more data download) by passing `local_gradient=True` to the `web.run()` and related functions.
- Passing `path_dir` to `ComponentModeler` methods is deprecated in favor of setting `ComponentModeler.path_dir` and will result in an error if the two don't match.

### Fixed
- Significant speedup for field projection computations.
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
)
from tidy3d.web.api.container import Batch

from ..utils import run_emulated
from ...utils import run_emulated

# Waveguide height
wg_height = 0.22
Expand Down Expand Up @@ -191,22 +191,15 @@ def make_component_modeler(**kwargs):


def run_component_modeler(monkeypatch, modeler: ComponentModeler):
# values = dict(
# simulation=modeler.simulation,
# ports=modeler.ports,
# freqs=modeler.freqs,
# run_only=modeler.run_only,
# element_mappings=modeler.element_mappings,
# )
sim_dict = modeler.sim_dict
batch_data = {task_name: run_emulated(sim) for task_name, sim in sim_dict.items()}
monkeypatch.setattr(ComponentModeler, "_run_sims", lambda self, path_dir: batch_data)
s_matrix = modeler.run(path_dir=modeler.path_dir)
monkeypatch.setattr(ComponentModeler, "batch_data", property(lambda self: batch_data))
s_matrix = modeler._construct_smatrix()
return s_matrix


def test_validate_no_sources(tmp_path):
modeler = make_component_modeler(path_dir=str(tmp_path))
def test_validate_no_sources():
modeler = make_component_modeler()
source = td.PointDipole(
source_time=td.GaussianPulse(freq0=2e14, fwidth=1e14), polarization="Ex"
)
Expand All @@ -215,21 +208,21 @@ def test_validate_no_sources(tmp_path):
_ = modeler.copy(update=dict(simulation=sim_w_source))


def test_element_mappings_none(tmp_path):
modeler = make_component_modeler(path_dir=str(tmp_path))
def test_element_mappings_none():
modeler = make_component_modeler()
modeler = modeler.updated_copy(ports=[], element_mappings=())
_ = modeler.matrix_indices_run_sim


def test_no_port(tmp_path):
modeler = make_component_modeler(path_dir=str(tmp_path))
def test_no_port():
modeler = make_component_modeler()
_ = modeler.ports
with pytest.raises(Tidy3dKeyError):
modeler.get_port_by_name(port_name="NOT_A_PORT")


def test_ports_too_close_boundary(tmp_path):
modeler = make_component_modeler(path_dir=str(tmp_path))
def test_ports_too_close_boundary():
modeler = make_component_modeler()
grid_boundaries = modeler.simulation.grid.boundaries.to_list[0]
way_outside = grid_boundaries[0] - 1000
xmin = grid_boundaries[1]
Expand All @@ -252,30 +245,30 @@ def test_validate_batch_supplied(tmp_path):
)


def test_plot_sim(tmp_path):
modeler = make_component_modeler(path_dir=str(tmp_path))
def test_plot_sim():
modeler = make_component_modeler()
modeler.plot_sim(z=0)
plt.close()


def test_plot_sim_eps(tmp_path):
modeler = make_component_modeler(path_dir=str(tmp_path))
def test_plot_sim_eps():
modeler = make_component_modeler()
modeler.plot_sim_eps(z=0)
plt.close()


def test_make_component_modeler(tmp_path):
_ = make_component_modeler(path_dir=str(tmp_path))
def test_make_component_modeler():
_ = make_component_modeler()


def test_run(monkeypatch, tmp_path):
modeler = make_component_modeler(path_dir=str(tmp_path))
monkeypatch.setattr(ComponentModeler, "run", lambda self, path_dir: None)
modeler.run(path_dir=str(tmp_path))
def test_run(monkeypatch):
modeler = make_component_modeler()
monkeypatch.setattr(ComponentModeler, "run", lambda self, path_dir=None: None)
modeler.run()


def test_run_component_modeler(monkeypatch, tmp_path):
modeler = make_component_modeler(path_dir=str(tmp_path))
def test_run_component_modeler(monkeypatch):
modeler = make_component_modeler()
s_matrix = run_component_modeler(monkeypatch, modeler)

for port_in in modeler.ports:
Expand Down Expand Up @@ -338,17 +331,17 @@ def _test_mappings(element_mappings, s_matrix):
), "mapping not applied correctly."


def test_run_component_modeler_mappings(monkeypatch, tmp_path):
def test_run_component_modeler_mappings(monkeypatch):
element_mappings = (
((("left_bot", 0), ("right_bot", 0)), (("left_top", 0), ("right_top", 0)), -1j),
((("left_bot", 0), ("right_top", 0)), (("left_top", 0), ("right_bot", 0)), +1),
)
modeler = make_component_modeler(element_mappings=element_mappings, path_dir=str(tmp_path))
modeler = make_component_modeler(element_mappings=element_mappings)
s_matrix = run_component_modeler(monkeypatch, modeler)
_test_mappings(element_mappings, s_matrix)


def test_mapping_exclusion(monkeypatch, tmp_path):
def test_mapping_exclusion(monkeypatch):
"""Make sure that source indices are skipped if totally covered by element mapping."""

_ = make_coupler()
Expand All @@ -369,7 +362,7 @@ def test_mapping_exclusion(monkeypatch, tmp_path):
mapping = ((("right_bot", 1), ("right_bot", 1)), (EXCLUDE_INDEX, EXCLUDE_INDEX), +1)
element_mappings.append(mapping)

modeler = make_component_modeler(element_mappings=element_mappings, path_dir=str(tmp_path))
modeler = make_component_modeler(element_mappings=element_mappings)

run_sim_indices = modeler.matrix_indices_run_sim
assert EXCLUDE_INDEX not in run_sim_indices, "mapping didnt exclude row properly"
Expand All @@ -379,7 +372,7 @@ def test_mapping_exclusion(monkeypatch, tmp_path):


def test_batch_filename(tmp_path):
modeler = make_component_modeler(path_dir=str(tmp_path))
modeler = make_component_modeler()
path = modeler._batch_path
assert path

Expand All @@ -388,8 +381,8 @@ def test_import_smatrix_smatrix():
from tidy3d.plugins.smatrix.smatrix import ComponentModeler, Port # noqa: F401


def test_to_from_file_batch(monkeypatch, tmp_path):
modeler = make_component_modeler(path_dir=str(tmp_path))
def test_to_from_file_batch(tmp_path, monkeypatch):
modeler = make_component_modeler()
_ = run_component_modeler(monkeypatch, modeler)

batch = td.web.Batch(simulations=dict())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,22 @@
)
from tidy3d.plugins.smatrix.ports.base_lumped import AbstractLumpedPort

from ..utils import run_emulated
from ...utils import run_emulated
from .terminal_component_modeler_def import make_coaxial_component_modeler, make_component_modeler


def run_component_modeler(monkeypatch, modeler: TerminalComponentModeler):
sim_dict = modeler.sim_dict
batch_data = {task_name: run_emulated(sim) for task_name, sim in sim_dict.items()}
monkeypatch.setattr(TerminalComponentModeler, "_run_sims", lambda self, path_dir: batch_data)
# for the random data, the power wave matrix might be singular, leading to an error
# during inversion, so monkeypatch the inv method so that it operates on a random matrix
monkeypatch.setattr(
AbstractComponentModeler, "inv", lambda matrix: np.random.rand(*matrix.shape) + 1e-4
)
# Need to do something similar when computing F
monkeypatch.setattr(AbstractComponentModeler, "batch_data", property(lambda self: batch_data))
monkeypatch.setattr(TerminalComponentModeler, "batch_data", property(lambda self: batch_data))
monkeypatch.setattr(AbstractComponentModeler, "inv", lambda matrix: np.eye(len(modeler.ports)))
monkeypatch.setattr(
TerminalComponentModeler,
"_compute_F",
lambda matrix: 1.0 / (2.0 * np.sqrt(np.abs(matrix) + 1e-4)),
)
s_matrix = modeler.run(path_dir=modeler.path_dir)
s_matrix = modeler._construct_smatrix()
return s_matrix


Expand Down
42 changes: 20 additions & 22 deletions tidy3d/plugins/smatrix/component_modelers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from ....components.types import FreqArray
from ....constants import HERTZ
from ....exceptions import SetupError, Tidy3dKeyError
from ....log import log
from ....web.api.container import Batch, BatchData
from ..ports.coaxial_lumped import CoaxialLumpedPort
from ..ports.modal import Port
Expand Down Expand Up @@ -172,22 +171,23 @@ def batch(self) -> Batch:
@cached_property
def batch_path(self) -> str:
"""Path to the batch saved to file."""
return self.batch._batch_path(path_dir=self.path_dir)

return self.batch._batch_path(path_dir=DEFAULT_DATA_DIR)
@cached_property
def batch_data(self) -> BatchData:
"""Path to the batch saved to file."""
return self.batch.run(path_dir=self.path_dir)

def get_path_dir(self, path_dir: str) -> None:
"""Check whether the supplied 'path_dir' matches the internal field value."""

if path_dir not in (DEFAULT_DATA_DIR, self.path_dir):
log.warning(
f"'ComponentModeler' method was supplied a 'path_dir' of '{path_dir}' "
f"when its internal 'path_dir' field was set to '{self.path_dir}'. "
"The passed value will be deprecated in later versions. "
"Please set the internal 'path_dir' field to the desired value and "
"remove the 'path_dir' from the method argument. "
f"Using supplied '{path_dir}'."
if path_dir != self.path_dir:
raise ValueError(
f"'path_dir' of '{path_dir}' passed, but 'ComponentModeler.path_dir' is "
f"{self.path_dir}. Moving forward, only the 'ComponentModeler.path_dir' will be "
"used internally, please update your scripts accordingly to avoid passing this "
"value to methods. "
)
return path_dir

return self.path_dir

Expand All @@ -198,10 +198,9 @@ def _batch_path(self) -> str:

def _run_sims(self, path_dir: str = DEFAULT_DATA_DIR) -> BatchData:
"""Run :class:`Simulations` for each port and return the batch after saving."""
batch = self.batch

batch_data = batch.run(path_dir=path_dir)
batch.to_file(self._batch_path)
_ = self.get_path_dir(path_dir)
self.batch.to_file(self._batch_path)
batch_data = self.batch_data
return batch_data

def get_port_by_name(self, port_name: str) -> Port:
Expand All @@ -217,16 +216,15 @@ def _construct_smatrix(self, batch_data: BatchData) -> DataArray:

def run(self, path_dir: str = DEFAULT_DATA_DIR) -> DataArray:
"""Solves for the scattering matrix of the system."""
path_dir = self.get_path_dir(path_dir)
batch_data = self._run_sims(path_dir=path_dir)
return self._construct_smatrix(batch_data=batch_data)
_ = self.get_path_dir(path_dir)
# batch_data = self._run_sims(path_dir=path_dir)
return self._construct_smatrix()

def load(self, path_dir: str = DEFAULT_DATA_DIR) -> DataArray:
"""Load a scattering matrix from saved :class:`BatchData` object."""
path_dir = self.get_path_dir(path_dir)

batch_data = BatchData.load(path_dir=path_dir)
return self._construct_smatrix(batch_data=batch_data)
_ = self.get_path_dir(path_dir)
# batch_data = self.batch_data
return self._construct_smatrix()

@staticmethod
def inv(matrix: DataArray):
Expand Down
5 changes: 3 additions & 2 deletions tidy3d/plugins/smatrix/component_modelers/modal.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from ....components.types import Ax, Complex
from ....components.viz import add_ax_if_none, equal_aspect
from ....exceptions import SetupError
from ....web.api.container import BatchData
from ..ports.modal import ModalPortDataArray, Port
from .base import FWIDTH_FRAC, AbstractComponentModeler

Expand Down Expand Up @@ -256,9 +255,11 @@ def get_max_mode_indices(matrix_elements: Tuple[str, int]) -> int:

return max_mode_index_out, max_mode_index_in

def _construct_smatrix(self, batch_data: BatchData) -> ModalPortDataArray:
def _construct_smatrix(self) -> ModalPortDataArray:
"""Post process `BatchData` to generate scattering matrix."""

batch_data = self.batch_data

max_mode_index_out, max_mode_index_in = self.max_mode_index
num_modes_out = max_mode_index_out + 1
num_modes_in = max_mode_index_in + 1
Expand Down
4 changes: 3 additions & 1 deletion tidy3d/plugins/smatrix/component_modelers/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,11 @@ def _source_time(self):
freq0=freq0, fwidth=fwidth, remove_dc_component=self.remove_dc_component
)

def _construct_smatrix(self, batch_data: BatchData) -> TerminalPortDataArray:
def _construct_smatrix(self) -> TerminalPortDataArray:
"""Post process ``BatchData`` to generate scattering matrix."""

batch_data = self.batch_data

port_names = [port.name for port in self.ports]

values = np.zeros(
Expand Down

0 comments on commit fc5a233

Please sign in to comment.