|
2 | 2 |
|
3 | 3 | from __future__ import annotations
|
4 | 4 |
|
5 |
| -import os |
6 | 5 | from typing import Optional, Union
|
7 | 6 |
|
8 | 7 | import numpy as np
|
|
22 | 21 | from tidy3d.constants import C_0, OHM
|
23 | 22 | from tidy3d.exceptions import SetupError, Tidy3dError, Tidy3dKeyError, ValidationError
|
24 | 23 | from tidy3d.log import log
|
25 |
| -from tidy3d.plugins.smatrix.component_modelers.base import DEFAULT_DATA_DIR |
26 | 24 | from tidy3d.plugins.smatrix.data.terminal import PortDataArray, TerminalPortDataArray
|
27 | 25 | from tidy3d.plugins.smatrix.ports.base_lumped import AbstractLumpedPort
|
28 | 26 | from tidy3d.plugins.smatrix.ports.coaxial_lumped import CoaxialLumpedPort
|
@@ -327,41 +325,6 @@ def _source_time(self):
|
327 | 325 | fmin=min(self.freqs), fmax=max(self.freqs), remove_dc_component=self.remove_dc_component
|
328 | 326 | )
|
329 | 327 |
|
330 |
| - def _construct_smatrix(self) -> TerminalPortDataArray: |
331 |
| - """Post process :class:`.BatchData` to generate scattering matrix.""" |
332 |
| - return self._internal_construct_smatrix(batch_data=self.batch_data) |
333 |
| - |
334 |
| - def _internal_construct_smatrix(self, batch_data) -> TerminalPortDataArray: |
335 |
| - """Post process :class:`.BatchData` to generate scattering matrix, for internal use only.""" |
336 |
| - |
337 |
| - port_names = [port.name for port in self.ports] |
338 |
| - |
339 |
| - values = np.zeros( |
340 |
| - (len(self.freqs), len(port_names), len(port_names)), |
341 |
| - dtype=complex, |
342 |
| - ) |
343 |
| - coords = { |
344 |
| - "f": np.array(self.freqs), |
345 |
| - "port_out": port_names, |
346 |
| - "port_in": port_names, |
347 |
| - } |
348 |
| - a_matrix = TerminalPortDataArray(values, coords=coords) |
349 |
| - b_matrix = a_matrix.copy(deep=True) |
350 |
| - |
351 |
| - # Tabulate the reference impedances at each port and frequency |
352 |
| - port_impedances = self._port_reference_impedances(batch_data=batch_data) |
353 |
| - |
354 |
| - # loop through source ports |
355 |
| - for port_in in self.ports: |
356 |
| - sim_data = batch_data[self._task_name(port=port_in)] |
357 |
| - a, b = self.compute_power_wave_amplitudes_at_each_port(port_impedances, sim_data) |
358 |
| - indexer = {"f": a.f, "port_in": port_in.name, "port_out": a.port} |
359 |
| - a_matrix.loc[indexer] = a |
360 |
| - b_matrix.loc[indexer] = b |
361 |
| - |
362 |
| - s_matrix = self.ab_to_s(a_matrix, b_matrix) |
363 |
| - return s_matrix |
364 |
| - |
365 | 328 | @pd.validator("simulation")
|
366 | 329 | def _validate_3d_simulation(cls, val):
|
367 | 330 | """Error if :class:`.Simulation` is not a 3D simulation"""
|
@@ -453,60 +416,40 @@ def get_radiation_monitor_by_name(self, monitor_name: str) -> DirectivityMonitor
|
453 | 416 | return monitor
|
454 | 417 | raise Tidy3dKeyError(f"No radiation monitor named '{monitor_name}'.")
|
455 | 418 |
|
456 |
| - def run(self, path_dir: str = DEFAULT_DATA_DIR) -> TerminalComponentModelerData: |
457 |
| - """Solves for the scattering matrix of the system.""" |
458 |
| - _ = self.get_path_dir(path_dir) |
459 |
| - _ = self._upload_terminal_modeler() |
460 |
| - _ = self._construct_smatrix() |
461 |
| - |
462 |
| - @cached_property |
463 |
| - def _terminal_modeler_path(self) -> str: |
464 |
| - """Where we store the for this :class:`TerminalComponentModeler` instance after the run.""" |
465 |
| - return os.path.join(self.path_dir, "tcp_" + str(hash(self)) + ".hdf5") |
| 419 | + # Backwards compatible methods |
| 420 | + @staticmethod |
| 421 | + def compute_port_VI( |
| 422 | + port_out: TerminalPortType, sim_data: SimulationData |
| 423 | + ) -> tuple[FreqDataArray, FreqDataArray]: |
| 424 | + return compute_port_VI(port_out=port_out, sim_data=sim_data) |
466 | 425 |
|
467 |
| - def _upload_terminal_modeler(self): |
468 |
| - # TODO properly refactor, plugins data types should not have web methods. |
469 |
| - from tidy3d.web.api.container import Job |
470 |
| - |
471 |
| - # first try loading the terminal_component_modeler from file, if it exists |
472 |
| - terminal_modeler_path = self._terminal_modeler_path |
473 |
| - |
474 |
| - if os.path.exists(terminal_modeler_path): |
475 |
| - return Job.from_file(fname=terminal_modeler_path) |
476 |
| - |
477 |
| - return Job( |
478 |
| - simulation=self, |
479 |
| - task_name=self.name, |
480 |
| - folder_name=self.folder_name, |
481 |
| - callback_url=self.callback_url, |
482 |
| - verbose=self.verbose, |
483 |
| - solver_version=self.solver_version, |
484 |
| - simulation_type="microwave", |
| 426 | + def compute_power_wave_amplitudes_at_each_port( |
| 427 | + self, port_reference_impedances: PortDataArray, sim_data: SimulationData |
| 428 | + ) -> tuple[PortDataArray, PortDataArray]: |
| 429 | + return TerminalComponentModelerData().compute_power_wave_amplitudes_at_each_port( |
| 430 | + port_reference_impedances=port_reference_impedances, sim_data=sim_data |
485 | 431 | )
|
486 | 432 |
|
| 433 | + def _construct_smatrix(self) -> TerminalPortDataArray: |
| 434 | + pass |
| 435 | + |
| 436 | + def _internal_construct_smatrix(self, batch_data: BatchData) -> TerminalPortDataArray: |
| 437 | + pass |
| 438 | + |
487 | 439 | @cached_property
|
488 | 440 | def batch(self):
|
489 | 441 | """:class:`.Batch` associated with this component modeler."""
|
490 |
| - # TODO properly refactor, plugins data types should not have web methods. |
491 |
| - from tidy3d.web.api.container import Batch |
492 |
| - |
493 |
| - if self.batch_cached is not None: |
494 |
| - return self.batch_cached |
| 442 | + from tidy3d.plugins.smatrix.web import batch |
495 | 443 |
|
496 |
| - # first try loading the batch from file, if it exists |
497 |
| - batch_path = self._batch_path |
| 444 | + return batch(self) |
498 | 445 |
|
499 |
| - if os.path.exists(batch_path): |
500 |
| - return Batch.from_file(fname=batch_path) |
| 446 | + @cached_property |
| 447 | + def batch_path(self) -> str: |
| 448 | + """Path to the batch saved to file.""" |
501 | 449 |
|
502 |
| - return Batch( |
503 |
| - simulations=self.sim_dict, |
504 |
| - folder_name=self.folder_name, |
505 |
| - callback_url=self.callback_url, |
506 |
| - verbose=self.verbose, |
507 |
| - solver_version=self.solver_version, |
508 |
| - simulation_type="microwave", |
509 |
| - ) |
| 450 | + @cached_property |
| 451 | + def batch_data(self): |
| 452 | + """The :class:`.BatchData` associated with the simulations run for this component modeler.""" |
510 | 453 |
|
511 | 454 |
|
512 | 455 | class SMatrixData:
|
@@ -741,10 +684,74 @@ def compute_power_wave_amplitudes_at_each_port(
|
741 | 684 | V_numpy = np.where(negative_real_Z, -V_numpy, V_numpy)
|
742 | 685 | Z_numpy = np.where(negative_real_Z, -Z_numpy, Z_numpy)
|
743 | 686 |
|
744 |
| - F_numpy = TerminalComponentModeler._compute_F(Z_numpy) |
| 687 | + F_numpy = _compute_F(Z_numpy) |
745 | 688 |
|
746 | 689 | # Equation 4.67 - Pozar - Microwave Engineering 4ed
|
747 | 690 | a.values = F_numpy * (V_numpy + Z_numpy * I_numpy)
|
748 | 691 | b.values = F_numpy * (V_numpy - np.conj(Z_numpy) * I_numpy)
|
749 | 692 |
|
750 | 693 | return a, b
|
| 694 | + |
| 695 | + |
| 696 | +def _construct_smatrix(batch_data) -> TerminalPortDataArray: |
| 697 | + """Post process :class:`.BatchData` to generate scattering matrix.""" |
| 698 | + return _internal_construct_smatrix(batch_data=batch_data) |
| 699 | + |
| 700 | + |
| 701 | +def _internal_construct_smatrix(simulation: TerminalComponentModeler) -> TerminalPortDataArray: |
| 702 | + """Post process :class:`.BatchData` to generate scattering matrix, for internal use only.""" |
| 703 | + |
| 704 | + port_names = [port.name for port in simulation.ports] |
| 705 | + |
| 706 | + values = np.zeros( |
| 707 | + (len(simulation.freqs), len(port_names), len(port_names)), |
| 708 | + dtype=complex, |
| 709 | + ) |
| 710 | + coords = { |
| 711 | + "f": np.array(simulation.freqs), |
| 712 | + "port_out": port_names, |
| 713 | + "port_in": port_names, |
| 714 | + } |
| 715 | + a_matrix = TerminalPortDataArray(values, coords=coords) |
| 716 | + b_matrix = a_matrix.copy(deep=True) |
| 717 | + |
| 718 | + # Tabulate the reference impedances at each port and frequency |
| 719 | + port_impedances = simulation._port_reference_impedances(batch_data=batch_data) |
| 720 | + |
| 721 | + # loop through source ports |
| 722 | + for port_in in simulation.ports: |
| 723 | + sim_data = batch_data[simulation._task_name(port=port_in)] |
| 724 | + a, b = compute_power_wave_amplitudes_at_each_port(port_impedances, sim_data) |
| 725 | + indexer = {"f": a.f, "port_in": port_in.name, "port_out": a.port} |
| 726 | + a_matrix.loc[indexer] = a |
| 727 | + b_matrix.loc[indexer] = b |
| 728 | + |
| 729 | + s_matrix = ab_to_s(a_matrix, b_matrix) |
| 730 | + return s_matrix |
| 731 | + |
| 732 | + |
| 733 | +# @cached_property |
| 734 | +# def _terminal_modeler_path(self) -> str: |
| 735 | +# """Where we store the for this :class:`TerminalComponentModeler` instance after the run.""" |
| 736 | +# return os.path.join(self.path_dir, "tcp_" + str(hash(self)) + ".hdf5") |
| 737 | +# |
| 738 | +# |
| 739 | +# def _upload_terminal_modeler(self): |
| 740 | +# # TODO properly refactor, plugins data types should not have web methods. |
| 741 | +# from tidy3d.web.api.container import Job |
| 742 | +# |
| 743 | +# # first try loading the terminal_component_modeler from file, if it exists |
| 744 | +# terminal_modeler_path = self._terminal_modeler_path |
| 745 | +# |
| 746 | +# if os.path.exists(terminal_modeler_path): |
| 747 | +# return Job.from_file(fname=terminal_modeler_path) |
| 748 | +# |
| 749 | +# return Job( |
| 750 | +# simulation=self, |
| 751 | +# task_name=self.name, |
| 752 | +# folder_name=self.folder_name, |
| 753 | +# callback_url=self.callback_url, |
| 754 | +# verbose=self.verbose, |
| 755 | +# solver_version=self.solver_version, |
| 756 | +# simulation_type="microwave", |
| 757 | +# ) |
0 commit comments