Skip to content

Commit 348a931

Browse files
committed
pydantic v2 shenanigans
add somefiles replacing v1 more replacements copy methods and ordering of basemodel update get_submodels_by_hash basemodel done (except for docs) basemodel and modespec done slowly but surely.. progress next batch going going getting started on medium more refactoring new structure for medium.py
1 parent 8bb90ff commit 348a931

113 files changed

Lines changed: 1882 additions & 1906 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

poetry.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ documentation = "https://docs.flexcompute.com/projects/tidy3d/en/latest/"
2323

2424
[tool.poetry.dependencies]
2525
python = ">=3.9,<3.14"
26+
typing-extensions = { version = "*", python = "<3.11" }
2627
pyroots = ">=0.5.0"
2728
xarray = ">=2023.08"
2829
importlib-metadata = ">=6.0.0"

run.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env -S poetry run python
2+
# ruff: noqa: F401
3+
4+
# from tidy3d.components.base import Tidy3dBaseModel
5+
import numpy as np
6+
7+
from tidy3d.components.base import Tidy3dBaseModel
8+
9+
10+
class Test(Tidy3dBaseModel):
11+
a: np.ndarray
12+
x: str = "test"
13+
14+
15+
m = Test(a=np.zeros(1))
16+
print(m.model_dump())

tidy3d/compat.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@
55
except ImportError:
66
from xarray.core import alignment
77

8-
__all__ = ["alignment"]
8+
try:
9+
from typing import Self # Python >= 3.11
10+
except ImportError: # Python <3.11
11+
from typing_extensions import Self
12+
13+
__all__ = ["alignment", "Self"]

tidy3d/components/apodization.py

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
"""Defines specification for apodization."""
22

3+
from typing import Optional
4+
35
import numpy as np
4-
import pydantic.v1 as pd
6+
from pydantic import Field, NonNegativeFloat, PositiveFloat, model_validator
57

8+
from ..compat import Self
69
from ..constants import SECOND
710
from ..exceptions import SetupError
8-
from .base import Tidy3dBaseModel, skip_if_fields_missing
11+
from .base import Tidy3dBaseModel
912
from .types import ArrayFloat1D, Ax
1013
from .viz import add_ax_if_none
1114

@@ -24,45 +27,40 @@ class ApodizationSpec(Tidy3dBaseModel):
2427
2528
"""
2629

27-
start: pd.NonNegativeFloat = pd.Field(
30+
start: Optional[NonNegativeFloat] = Field(
2831
None,
2932
title="Start Interval",
3033
description="Defines the time at which the start apodization ends.",
3134
units=SECOND,
3235
)
3336

34-
end: pd.NonNegativeFloat = pd.Field(
37+
end: Optional[NonNegativeFloat] = Field(
3538
None,
3639
title="End Interval",
3740
description="Defines the time at which the end apodization begins.",
3841
units=SECOND,
3942
)
4043

41-
width: pd.PositiveFloat = pd.Field(
44+
width: Optional[PositiveFloat] = Field(
4245
None,
4346
title="Apodization Width",
4447
description="Characteristic decay length of the apodization function, i.e., the width of the ramping up of the scaling function from 0 to 1.",
4548
units=SECOND,
4649
)
4750

48-
@pd.validator("end", always=True, allow_reuse=True)
49-
@skip_if_fields_missing(["start"])
50-
def end_greater_than_start(cls, val, values):
51+
@model_validator(mode="after")
52+
def end_greater_than_start(self) -> Self:
5153
"""Ensure end is greater than or equal to start."""
52-
start = values.get("start")
53-
if val is not None and start is not None and val < start:
54+
if self.end is not None and self.start is not None and self.end < self.start:
5455
raise SetupError("End apodization begins before start apodization ends.")
55-
return val
56+
return self
5657

57-
@pd.validator("width", always=True, allow_reuse=True)
58-
@skip_if_fields_missing(["start", "end"])
59-
def width_provided(cls, val, values):
58+
@model_validator(mode="after")
59+
def width_provided(self) -> Self:
6060
"""Check that width is provided if either start or end apodization is requested."""
61-
start = values.get("start")
62-
end = values.get("end")
63-
if (start is not None or end is not None) and val is None:
61+
if (self.start is not None or self.end is not None) and self.val is None:
6462
raise SetupError("Apodization width must be set.")
65-
return val
63+
return self
6664

6765
@add_ax_if_none
6866
def plot(self, times: ArrayFloat1D, ax: Ax = None) -> Ax:

tidy3d/components/autograd/boxes.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# NOTE: we do not subclass ArrayBox since that would break autograd's internal checks
33

44
import importlib
5-
from typing import Any, Callable, Dict, List, Tuple
5+
from typing import Any, Callable
66

77
import autograd.numpy as anp
88
from autograd.extend import VJPNode, defjvp, register_notrace
@@ -33,9 +33,9 @@ def from_arraybox(cls, box: ArrayBox) -> TidyArrayBox:
3333
def __array_function__(
3434
self: Any,
3535
func: Callable,
36-
types: List[Any],
37-
args: Tuple[Any, ...],
38-
kwargs: Dict[str, Any],
36+
types: list[Any],
37+
args: tuple[Any, ...],
38+
kwargs: dict[str, Any],
3939
) -> Any:
4040
"""
4141
Handle the dispatch of NumPy functions to autograd's numpy implementation.
@@ -46,11 +46,11 @@ def __array_function__(
4646
The instance of the class.
4747
func : Callable
4848
The NumPy function being called.
49-
types : List[Any]
49+
types : list[Any]
5050
The types of the arguments that implement __array_function__.
51-
args : Tuple[Any, ...]
51+
args : tuple[Any, ...]
5252
The positional arguments to the function.
53-
kwargs : Dict[str, Any]
53+
kwargs : dict[str, Any]
5454
The keyword arguments to the function.
5555
5656
Returns
@@ -102,7 +102,7 @@ def __array_ufunc__(
102102
ufunc: Callable,
103103
method: str,
104104
*inputs: Any,
105-
**kwargs: Dict[str, Any],
105+
**kwargs: dict[str, Any],
106106
) -> Any:
107107
"""
108108
Handle the dispatch of NumPy ufuncs to autograd's numpy implementation.
@@ -117,7 +117,7 @@ def __array_ufunc__(
117117
The method of the ufunc being called.
118118
inputs : Any
119119
The input arguments to the ufunc.
120-
kwargs : Dict[str, Any]
120+
kwargs : dict[str, Any]
121121
The keyword arguments to the ufunc.
122122
123123
Returns

tidy3d/components/autograd/derivative_utils.py

Lines changed: 27 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
# utilities for autograd derivative passing
2-
from __future__ import annotations
2+
3+
from typing import Optional
34

45
import numpy as np
5-
import pydantic.v1 as pd
66
import xarray as xr
7+
from pydantic import Field
78

9+
from ...compat import Self
810
from ...constants import LARGE_NUMBER
911
from ..base import Tidy3dBaseModel
1012
from ..data.data_array import ScalarFieldDataArray, SpatialDataArray
@@ -43,32 +45,27 @@ class DerivativeSurfaceMesh(Tidy3dBaseModel):
4345
4446
"""
4547

46-
centers: ArrayLike = pd.Field(
47-
...,
48+
centers: ArrayLike = Field(
4849
title="Centers",
4950
description="(N, 3) array storing the centers of each surface element.",
5051
)
5152

52-
areas: ArrayLike = pd.Field(
53-
...,
53+
areas: ArrayLike = Field(
5454
title="Area Elements",
5555
description="(N,) array storing the first perpendicular vectors of each surface element.",
5656
)
5757

58-
normals: ArrayLike = pd.Field(
59-
...,
58+
normals: ArrayLike = Field(
6059
title="Normals",
6160
description="(N, 3) array storing the normal vectors of each surface element.",
6261
)
6362

64-
perps1: ArrayLike = pd.Field(
65-
...,
63+
perps1: ArrayLike = Field(
6664
title="Perpendiculars 1",
6765
description="(N, 3) array storing the first perpendicular vectors of each surface element.",
6866
)
6967

70-
perps2: ArrayLike = pd.Field(
71-
...,
68+
perps2: ArrayLike = Field(
7269
title="Perpendiculars 1",
7370
description="(N, 3) array storing the first perpendicular vectors of each surface element.",
7471
)
@@ -77,122 +74,110 @@ class DerivativeSurfaceMesh(Tidy3dBaseModel):
7774
class DerivativeInfo(Tidy3dBaseModel):
7875
"""Stores derivative information passed to the ``.compute_derivatives`` methods."""
7976

80-
paths: list[PathType] = pd.Field(
81-
...,
77+
paths: list[PathType] = Field(
8278
title="Paths to Traced Fields",
8379
description="List of paths to the traced fields that need derivatives calculated.",
8480
)
8581

86-
E_der_map: FieldData = pd.Field(
87-
...,
82+
E_der_map: FieldData = Field(
8883
title="Electric Field Gradient Map",
8984
description='Dataset where the field components ``("Ex", "Ey", "Ez")`` store the '
9085
"multiplication of the forward and adjoint electric fields. The tangential components "
9186
"of this dataset is used when computing adjoint gradients for shifting boundaries. "
9287
"All components are used when computing volume-based gradients.",
9388
)
9489

95-
D_der_map: FieldData = pd.Field(
96-
...,
90+
D_der_map: FieldData = Field(
9791
title="Displacement Field Gradient Map",
9892
description='Dataset where the field components ``("Ex", "Ey", "Ez")`` store the '
9993
"multiplication of the forward and adjoint displacement fields. The normal component "
10094
"of this dataset is used when computing adjoint gradients for shifting boundaries.",
10195
)
10296

103-
E_fwd: FieldData = pd.Field(
104-
...,
97+
E_fwd: FieldData = Field(
10598
title="Forward Electric Fields",
10699
description='Dataset where the field components ``("Ex", "Ey", "Ez")`` represent the '
107100
"forward electric fields used for computing gradients for a given structure.",
108101
)
109102

110-
E_adj: FieldData = pd.Field(
111-
...,
103+
E_adj: FieldData = Field(
112104
title="Adjoint Electric Fields",
113105
description='Dataset where the field components ``("Ex", "Ey", "Ez")`` represent the '
114106
"adjoint electric fields used for computing gradients for a given structure.",
115107
)
116108

117-
D_fwd: FieldData = pd.Field(
118-
...,
109+
D_fwd: FieldData = Field(
119110
title="Forward Displacement Fields",
120111
description='Dataset where the field components ``("Ex", "Ey", "Ez")`` represent the '
121112
"forward displacement fields used for computing gradients for a given structure.",
122113
)
123114

124-
D_adj: FieldData = pd.Field(
125-
...,
115+
D_adj: FieldData = Field(
126116
title="Adjoint Displacement Fields",
127117
description='Dataset where the field components ``("Ex", "Ey", "Ez")`` represent the '
128118
"adjoint displacement fields used for computing gradients for a given structure.",
129119
)
130120

131-
eps_data: PermittivityData = pd.Field(
132-
...,
121+
eps_data: PermittivityData = Field(
133122
title="Permittivity Dataset",
134123
description="Dataset of relative permittivity values along all three dimensions. "
135124
"Used for automatically computing permittivity inside or outside of a simple geometry.",
136125
)
137126

138-
eps_in: tidycomplex = pd.Field(
127+
eps_in: tidycomplex = Field(
139128
title="Permittivity Inside",
140129
description="Permittivity inside of the ``Structure``. "
141130
"Typically computed from ``Structure.medium.eps_model``."
142131
"Used when it can not be computed from ``eps_data`` or when ``eps_approx==True``.",
143132
)
144133

145-
eps_out: tidycomplex = pd.Field(
146-
...,
134+
eps_out: tidycomplex = Field(
147135
title="Permittivity Outside",
148136
description="Permittivity outside of the ``Structure``. "
149137
"Typically computed from ``Simulation.medium.eps_model``."
150138
"Used when it can not be computed from ``eps_data`` or when ``eps_approx==True``.",
151139
)
152140

153-
eps_background: tidycomplex = pd.Field(
141+
eps_background: tidycomplex = Field(
154142
None,
155143
title="Permittivity in Background",
156144
description="Permittivity outside of the ``Structure`` as manually specified by. "
157145
"``Structure.background_medium``. ",
158146
)
159147

160-
bounds: Bound = pd.Field(
161-
...,
148+
bounds: Bound = Field(
162149
title="Geometry Bounds",
163150
description="Bounds corresponding to the structure, used in ``Medium`` calculations.",
164151
)
165152

166-
bounds_intersect: Bound = pd.Field(
167-
...,
153+
bounds_intersect: Bound = Field(
168154
title="Geometry and Simulation Intersections Bounds",
169155
description="Bounds corresponding to the minimum intersection between the "
170156
"structure and the simulation it is contained in.",
171157
)
172158

173-
frequency: float = pd.Field(
174-
...,
159+
frequency: float = Field(
175160
title="Frequency of adjoint simulation",
176161
description="Frequency at which the adjoint gradient is computed.",
177162
)
178163

179-
eps_no_structure: SpatialDataArray = pd.Field(
164+
eps_no_structure: Optional[SpatialDataArray] = Field(
180165
None,
181166
title="Permittivity Without Structure",
182167
description="The permittivity of the original simulation without the structure that is "
183168
"being differentiated with respect to. Used to approximate permittivity outside of the "
184169
"structure for shape optimization.",
185170
)
186171

187-
eps_inf_structure: SpatialDataArray = pd.Field(
172+
eps_inf_structure: Optional[SpatialDataArray] = Field(
188173
None,
189174
title="Permittivity With Infinite Structure",
190175
description="The permittivity of the original simulation where the structure being "
191176
" differentiated with respect to is inifinitely large. Used to approximate permittivity "
192177
"inside of the structure for shape optimization.",
193178
)
194179

195-
eps_approx: bool = pd.Field(
180+
eps_approx: bool = Field(
196181
False,
197182
title="Use Permittivity Approximation",
198183
description="If ``True``, approximates outside permittivity using ``Simulation.medium``"
@@ -201,7 +186,7 @@ class DerivativeInfo(Tidy3dBaseModel):
201186
"evaluate the inside and outside relative permittivity for each geometry.",
202187
)
203188

204-
def updated_paths(self, paths: list[PathType]) -> DerivativeInfo:
189+
def updated_paths(self, paths: list[PathType]) -> Self:
205190
"""Update this ``DerivativeInfo`` with new set of paths."""
206191
return self.updated_copy(paths=paths)
207192

0 commit comments

Comments
 (0)