From c37711196d09d3a4c9a4fab151945ee78c46cb9a Mon Sep 17 00:00:00 2001 From: Yannick Augenstein Date: Fri, 11 Apr 2025 11:18:07 +0200 Subject: [PATCH] fix: lazy import scipy and matplotlib --- tidy3d/components/dispersion_fitter.py | 17 ++++++++++++++++- tidy3d/components/medium.py | 6 +++++- tidy3d/components/mode/mode_solver.py | 9 +++++++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/tidy3d/components/dispersion_fitter.py b/tidy3d/components/dispersion_fitter.py index 07fecf866e..15aa6adf4e 100644 --- a/tidy3d/components/dispersion_fitter.py +++ b/tidy3d/components/dispersion_fitter.py @@ -5,7 +5,6 @@ from typing import Optional, Tuple import numpy as np -import scipy from pydantic.v1 import Field, NonNegativeFloat, PositiveFloat, PositiveInt, validator from rich.progress import Progress @@ -493,6 +492,11 @@ def real_weighted_matrix(self, matrix: ArrayComplex2D) -> ArrayFloat2D: def iterate_poles(self) -> FastFitterData: """Perform a single iteration of the pole-updating procedure.""" + try: + import scipy + except ImportError: + raise ImportError("scipy is required to fit the dispersion.") + def compute_zeros(residues: ArrayComplex1D, d_tilde: float) -> ArrayComplex1D: """Compute the zeros from the residues.""" size = len(self.real_poles) + 2 * len(self.complex_poles) @@ -593,6 +597,12 @@ def compute_zeros(residues: ArrayComplex1D, d_tilde: float) -> ArrayComplex1D: def fit_residues(self) -> FastFitterData: """Fit residues.""" + + try: + import scipy + except ImportError: + raise ImportError("scipy is required to fit the dispersion.") + # build the matrices if self.optimize_eps_inf: poly_len = 1 @@ -650,6 +660,11 @@ def iterate_fit(self) -> FastFitterData: def iterate_passivity(self, passivity_omega: ArrayFloat1D) -> Tuple[FastFitterData, int]: """Iterate passivity enforcement algorithm.""" + try: + import scipy + except ImportError: + raise ImportError("scipy is required to fit the dispersion.") + size = len(self.real_poles) + 2 * len(self.complex_poles) constraint_matrix = np.imag(self.pole_matrix_omega(passivity_omega)) diff --git a/tidy3d/components/medium.py b/tidy3d/components/medium.py index 9639695b14..f3489558fb 100644 --- a/tidy3d/components/medium.py +++ b/tidy3d/components/medium.py @@ -15,7 +15,6 @@ import numpy as npo import pydantic.v1 as pd import xarray as xr -from scipy import signal from tidy3d.components.material.tcad.heat import ThermalSpecType @@ -3482,6 +3481,11 @@ def _real_partial_fraction_decomposition( """ + try: + from scipy import signal + except ImportError: + raise ImportError("scipy is required to use this method.") + if a.ndim != 1 or np.any(np.iscomplex(a)): raise ValidationError( "Numerator coefficients must be a one-dimensional array of real numbers." diff --git a/tidy3d/components/mode/mode_solver.py b/tidy3d/components/mode/mode_solver.py index 1c1a5a6e7b..997c79c247 100644 --- a/tidy3d/components/mode/mode_solver.py +++ b/tidy3d/components/mode/mode_solver.py @@ -11,8 +11,6 @@ import numpy as np import pydantic.v1 as pydantic import xarray as xr -from matplotlib.collections import PatchCollection -from matplotlib.patches import Rectangle from ...constants import C_0 from ...exceptions import SetupError, ValidationError @@ -2315,6 +2313,13 @@ def _plot_pml( cls, simulation: Simulation, plane: Box, mode_spec: ModeSpec, ax: Ax = None ) -> Ax: """Plot the mode plane absorbing boundaries.""" + + try: + from matplotlib.collections import PatchCollection + from matplotlib.patches import Rectangle + except ImportError: + raise ImportError("matplotlib is required to plot the mode plane absorbing boundaries.") + # Get the mode plane normal axis, center, and limits. _, h_lim, v_lim, _ = cls._center_and_lims(simulation=simulation, plane=plane)