Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tests/test_IO.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def test_simulation_preserve_types():
FieldTimeMonitor(size=(1, 1, 1), start=1e-12, interval=3, name="fieldtime"),
FluxMonitor(size=(1, 0, 1), freqs=[1, 2, 3], name="flux"),
FluxTimeMonitor(size=(1, 0, 1), start=1e-12, interval=3, name="fluxtime"),
ModeMonitor(size=(1, 0, 1), freqs=[1, 2, 3], modes=[Mode(mode_index=1)], name="mode"),
ModeMonitor(size=(1, 0, 1), freqs=[1, 2], mode_spec=ModeSpec(num_modes=3), name="mode"),
],
)

Expand Down
14 changes: 5 additions & 9 deletions tests/test_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,12 +329,8 @@ def test_epsilon_eval():

def test_modes():

m = Mode(mode_index=0)
m = Mode(mode_index=0, num_modes=1)

# not enough modes
with pytest.raises(SetupError) as e:
m = Mode(mode_index=1, num_modes=1)
m = ModeSpec(num_modes=2)
m = ModeSpec(num_modes=1, target_neff=1.0)


""" names """
Expand Down Expand Up @@ -483,7 +479,7 @@ def test_source_times():

def test_FieldSource():
g = GaussianPulse(freq0=1, fwidth=0.1)
mode = Mode(mode_index=0)
mode_spec = ModeSpec(num_modes=2)

# test we can make planewave
s = PlaneWave(size=(0, 1, 1), source_time=g, pol_angle=np.pi / 2, direction="+")
Expand All @@ -492,15 +488,15 @@ def test_FieldSource():
s = GaussianBeam(size=(0, 1, 1), source_time=g, pol_angle=np.pi / 2, direction="+")

# test we can make mode source
s = ModeSource(size=(0, 1, 1), direction="+", source_time=g, mode=mode)
s = ModeSource(size=(0, 1, 1), direction="+", source_time=g, mode_spec=mode_spec, mode_index=0)

# test that non-planar geometry crashes plane wave and gaussian beam
with pytest.raises(ValidationError) as e_info:
s = PlaneWave(size=(1, 1, 1), source_time=g, pol_angle=np.pi / 2, direction="+")
with pytest.raises(ValidationError) as e_info:
s = GaussianBeam(size=(1, 1, 1), source_time=g, pol_angle=np.pi / 2, direction="+")
with pytest.raises(ValidationError) as e_info:
s = ModeSource(size=(1, 1, 1), direction="+", source_time=g, mode=mode)
s = ModeSource(size=(1, 1, 1), source_time=g, mode_spec=mode_spec)


""" monitors """
Expand Down
2 changes: 1 addition & 1 deletion tests/test_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def test_mode_solver():
simulation = td.Simulation(size=(2, 2, 2), grid_size=(0.1, 0.1, 0.1), structures=[waveguide])
plane = td.Box(center=(0, 0, 0), size=(0, 1, 1))
ms = ModeSolver(simulation=simulation, plane=plane, freq=td.constants.C_0 / 1.5)
modes = ms.solve(mode=td.Mode(mode_index=1))
modes = ms.solve(mode_spec=td.ModeSpec(num_modes=2))


def test_coeffs():
Expand Down
16 changes: 11 additions & 5 deletions tests/test_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
import pytest

import tidy3d as td
from tidy3d.log import DataError
import tidy3d.web as web
from tidy3d.web.auth import get_credentials
from tidy3d.web.auth import get_credentials, encode_password

from .utils import SIM_CONVERT as sim_original
from .utils import clear_tmp
Expand Down Expand Up @@ -35,7 +36,7 @@ def test_get_email_passwd_auth_key_ok(self, set_authentication_config):
os.environ["TIDY3D_USER"] = "mytestuser"
os.environ["TIDY3D_PASS"] = "mytestpass"
get_credentials()
set_authentication_config.assert_called_with("mytestuser", "mytestpass")
set_authentication_config.assert_called_with("mytestuser", encode_password("mytestpass"))


@clear_tmp
Expand Down Expand Up @@ -109,9 +110,6 @@ def test_source_norm():
sim_data_raw = web.run(
simulation=sim_original, task_name="test_webapi", path=PATH_SIM_DATA, normalize_index=None
)
sim_data_norm = web.run(
simulation=sim_original, task_name="test_webapi", path=PATH_SIM_DATA, normalize_index=1
)


""" Jobs """
Expand Down Expand Up @@ -181,6 +179,14 @@ def _test_job_7_delete():
assert task_info.status in ("deleted", "deleting")


def test_job_source_norm():
"""test complete run"""
job = web.Job(simulation=sim_original, task_name="test_job", callback_url=CALLBACK_URL)
sim_data_norm = job.run(path=PATH_SIM_DATA, normalize_index=0)
with pytest.raises(DataError):
sim_data_norm = web.load(task_id=job.task_id, simulation=sim_original, normalize_index=1)


""" Batches """


Expand Down
2 changes: 1 addition & 1 deletion tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def prepend_tmp(path):
size=(1, 1, 0),
center=(0, 0, 0),
freqs=[1.90, 2.01, 2.2],
modes=[Mode(mode_index=1)],
mode_spec=ModeSpec(num_modes=3),
name="mode",
),
],
Expand Down
2 changes: 1 addition & 1 deletion tidy3d/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from .components import Structure

# modes
from .components import Mode
from .components import ModeSpec

# sources
from .components import GaussianPulse, ContinuousWave
Expand Down
2 changes: 1 addition & 1 deletion tidy3d/components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from .structure import Structure

# mode
from .mode import Mode
from .mode import ModeSpec

# source
from .source import GaussianPulse, ContinuousWave
Expand Down
4 changes: 1 addition & 3 deletions tidy3d/components/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from .types import Numpy, Direction, Array, numpy_encoding, Literal, Ax
from .base import Tidy3dBaseModel
from .simulation import Simulation
from .mode import Mode
from .mode import ModeSpec
from .viz import add_ax_if_none
from ..log import DataError

Expand Down Expand Up @@ -605,7 +605,6 @@ class ModeData(PlanarData, FreqData):
-------

>>> f = np.linspace(2e14, 3e14, 1001)
>>> modes = [Mode(mode_index=0), Mode(mode_index=1)]
>>> values = (1+1j) * np.random.random((1, 2, len(f)))
>>> data = ModeData(values=values, direction=['+'], mode_index=np.arange(1, 3), f=f)
"""
Expand All @@ -618,7 +617,6 @@ class ModeData(PlanarData, FreqData):

_dims = ("direction", "mode_index", "f")

@abstractmethod
def normalize(self, source_freq_amps: Array[complex]) -> None:
"""normalize the values by the amplitude of the source."""
self.values /= 1j * source_freq_amps # pylint: disable=no-member
Expand Down
29 changes: 6 additions & 23 deletions tidy3d/components/mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,18 @@

from .base import Tidy3dBaseModel
from .types import Symmetry
from ..log import SetupError


class Mode(Tidy3dBaseModel):
class ModeSpec(Tidy3dBaseModel):
"""Stores specifications for the mode solver to find an electromagntic mode.
Note, the planar axes are found by popping the propagation axis from {x,y,z}.
For example, if propagation axis is y, the planar axes are ordered {x,z}.

Parameters
----------
mode_index : int
Return the mode solver output at ``mode_index``.
Must be >= 0.
num_modes : int = None
Number of modes returned by mode solver before selecting mode at ``mode_index``.
Must be > ``mode_index`` to accomodate ``mode_index``-th mode.

num_modes : int = 1
Number of modes returned by mode solver.
target_neff : float = None
Guess for effective index of mode.
Must be > 0.
Expand All @@ -33,23 +29,10 @@ class Mode(Tidy3dBaseModel):

Example
-------
>>> mode = Mode(mode_index=1, num_modes=3, target_neff=1.5, symmetries=(1,-1))
>>> mode_spec = ModeSpec(num_modes=3, target_neff=1.5, symmetries=(1,-1))
"""

mode_index: pd.NonNegativeInt
num_modes: pd.PositiveInt = None
num_modes: pd.PositiveInt = 1
target_neff: pd.PositiveFloat = None
symmetries: Tuple[Symmetry, Symmetry] = (0, 0)
num_pml: Tuple[pd.NonNegativeInt, pd.NonNegativeInt] = (0, 0)

@pd.validator("num_modes", always=True)
def check_num_modes(cls, val, values):
"""Make sure num_modes is > mode_index or None"""
if val is not None:
mode_index = values.get("mode_index")
if not val > mode_index:
raise SetupError(
"`num_modes` must be greater than `mode_index`"
f"given {val} and {mode_index}, respectively"
)
return val
8 changes: 4 additions & 4 deletions tidy3d/components/monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from .types import Literal, Ax, Direction, FieldType, EMField, Array
from .geometry import Box
from .validators import assert_plane, validate_name_str
from .mode import Mode
from .mode import ModeSpec
from .viz import add_ax_if_none, MonitorParams
from ..log import SetupError, ValidationError

Expand Down Expand Up @@ -262,16 +262,16 @@ class ModeMonitor(PlanarMonitor, FreqMonitor):

Example
-------
>>> modes = [Mode(mode_index=0), Mode(mode_index=1)]
>>> mode_spec = ModeSpec(num_modes=3)
>>> monitor = ModeMonitor(
... size=(2,2,0),
... freqs=[200e12, 210e12],
... modes=modes,
... mode_spec=mode_spec,
... name='mode_monitor')
"""

direction: List[Direction] = ["+", "-"]
modes: List[Mode]
mode_spec: ModeSpec
type: Literal["ModeMonitor"] = "ModeMonitor"
data_type: Literal["ModeData"] = "ModeData"

Expand Down
37 changes: 23 additions & 14 deletions tidy3d/components/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from .types import Direction, Polarization, Ax, FreqBound, Array, Literal
from .validators import assert_plane, validate_name_str
from .geometry import Box
from .mode import Mode
from .mode import ModeSpec
from .viz import add_ax_if_none, SourceParams
from ..constants import inf # pylint:disable=unused-import

Expand Down Expand Up @@ -337,22 +337,32 @@ class ModeSource(FieldSource):
source_time : :class:`GaussianPulse` or :class:`ContinuousWave`
Specification of time-dependence of source.
direction : str
Specifies propagation in the positive or negative direction of the normal axis. Must be in
``{'+', '-'}``.
mode : :class:`Mode`
Specification of the mode being injected by source.
Specifies propagation in the positive or negative direction of the normal axis.
Must be in ``{'+', '-'}``.
mode_spec :class:`ModeSpec`
Specification for the mode solver to find the mode injected by the source.
mode_index : int
Index of the mode to inject in the collection of modes returned by the solver. If larger
than ``mode_spec.num_modes``, ``num_modes`` in the solver will be set to ``mode_index + 1``.
Must be >= 0.
name : str = None
Optional name for source.

Example
-------
>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)
>>> mode = Mode(mode_index=1, num_modes=3)
>>> mode_source = ModeSource(size=(10,10,0), source_time=pulse, mode=mode, direction='-')
>>> mode_spec = ModeSpec(target_neff=2.)
>>> mode_source = ModeSource(
... size=(10,10,0),
... source_time=pulse,
... mode_spec=mode_spec,
... mode_index=1,
... direction='-')
"""

type: Literal["ModeSource"] = "ModeSource"
mode: Mode
mode_spec: ModeSpec = ModeSpec()
mode_index: pydantic.NonNegativeInt = 0


class PlaneWave(FieldSource):
Expand All @@ -377,8 +387,8 @@ class PlaneWave(FieldSource):
- ``Ex`` polarization for propagation along ``y``.
- ``Ex`` polarization for propagation along ``z``.
direction : str
Specifies propagation in the positive or negative direction of the normal axis. Must be in
``{'+', '-'}``.
Specifies propagation in the positive or negative direction of the normal axis.
Must be in ``{'+', '-'}``.
name : str = None
Optional name for source.

Expand Down Expand Up @@ -408,14 +418,13 @@ class GaussianBeam(FieldSource):
source_time : :class:`GaussianPulse` or :class:`ContinuousWave`
Specification of time-dependence of source.
direction : str
Specifies propagation in the positive or negative direction of the normal axis. Must be in
``{'+', '-'}``.
Specifies propagation in the positive or negative direction of the normal axis.
Must be in ``{'+', '-'}``.
waist_radius: float = 1.0
Radius of the beam at the waist (um).
Must be positive.
waist_distance: float = 0.0
Distance (um) from the beam waist along the propagation direction.
Must be non-negative.
angle_theta : float, optional
Polar angle from the normal axis (rad).
angle_phi : float, optional
Expand Down Expand Up @@ -443,7 +452,7 @@ class GaussianBeam(FieldSource):
"""

waist_radius: pydantic.PositiveFloat = 1.0
waist_distance: pydantic.NonNegativeFloat = 0.0
waist_distance: float = 0.0
angle_theta: float = 0.0
angle_phi: float = 0.0
pol_angle: float = 0.0
Expand Down
11 changes: 5 additions & 6 deletions tidy3d/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,8 @@ def old_json_sources(sim: Simulation) -> List[Dict]:
"amplitude": source.source_time.amplitude,
}
elif isinstance(source, ModeSource):
mode_ind = source.mode.mode_index
num_modes = source.mode.num_modes if source.mode.num_modes else mode_ind + 1
mode_ind = source.mode_index
num_modes = max(source.mode_spec.num_modes, mode_ind + 1)
direction = "forward" if source.direction == "+" else "backward"
src = {
"name": name,
Expand All @@ -260,7 +260,7 @@ def old_json_sources(sim: Simulation) -> List[Dict]:
"direction": direction,
"amplitude": source.source_time.amplitude,
"mode_ind": mode_ind,
"target_neff": source.mode.target_neff,
"target_neff": source.mode_spec.target_neff,
"Nmodes": num_modes,
}
elif isinstance(source, PlaneWave):
Expand Down Expand Up @@ -386,12 +386,11 @@ def old_json_monitors(sim: Simulation) -> Dict:
}
)
elif isinstance(monitor, ModeMonitor):
num_modes = max([m.mode_index for m in monitor.modes]) + 1
mnt.update(
{
"type": "ModeMonitor",
"Nmodes": num_modes,
"target_neff": None,
"Nmodes": monitor.mode_spec.num_modes,
"target_neff": monitor.mode_spec.target_neff,
"store": ["mode_amps"],
}
)
Expand Down
Loading