gsim 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gsim-0.2.0/src/gsim.egg-info → gsim-0.3.0}/PKG-INFO +4 -2
- {gsim-0.2.0 → gsim-0.3.0}/README.md +1 -1
- {gsim-0.2.0 → gsim-0.3.0}/pyproject.toml +3 -14
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/__init__.py +1 -1
- gsim-0.3.0/src/gsim/common/materials.py +191 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/polygon.py +23 -6
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/stack/extractor.py +17 -4
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/meep/mode_solver.py +3 -1
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/meep/models/results.py +2 -2
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/meep/simulation.py +59 -4
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/meep/viz.py +5 -35
- {gsim-0.2.0 → gsim-0.3.0/src/gsim.egg-info}/PKG-INFO +4 -2
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim.egg-info/SOURCES.txt +1 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim.egg-info/requires.txt +1 -0
- {gsim-0.2.0 → gsim-0.3.0}/LICENSE +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/setup.cfg +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/__init__.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/cross_section.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/geometry.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/geometry_model.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/layered_component.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/polygon_utils.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/stack/__init__.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/stack/_layer_utils.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/stack/materials.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/stack/overlays.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/stack/visualization.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/types.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/viz/__init__.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/viz/_colors.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/viz/_mesh_helpers.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/viz/render2d.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/viz/render2d_interactive.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/viz/render3d.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/viz/render3d_open3d.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/common/viz/render3d_pyvista.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/gcloud.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/hashing.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/meep/__init__.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/meep/materials.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/meep/models/__init__.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/meep/models/api.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/meep/models/config.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/meep/overlay.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/meep/ports.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/meep/results.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/meep/script.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/__init__.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/base.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/boundarymode.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/driven.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/eigenmode.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/electrostatic.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/field_viz.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/fields.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/materials.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/mesh/__init__.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/mesh/auto_size.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/mesh/config_generator.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/mesh/generator.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/mesh/geometry.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/mesh/gmsh_utils.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/mesh/groups.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/mesh/validation.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/models/__init__.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/models/cross_section.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/models/geometry.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/models/mesh.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/models/numerical.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/models/pec.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/models/ports.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/models/problems.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/models/results.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/models/stack.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/ports/__init__.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/ports/config.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/results.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/palace/runtime.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim/viz.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim.egg-info/dependency_links.txt +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/src/gsim.egg-info/top_level.txt +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/tests/test_gcloud_cache.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/tests/test_gcloud_start.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/tests/test_gsim.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/tests/test_hashing.py +0 -0
- {gsim-0.2.0 → gsim-0.3.0}/tests/test_viz_mesh.py +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gsim
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Electromagnetic simulation for photonics and electronics, powered by GDSFactory.
|
|
4
5
|
Author-email: GDSFactory <contact@gdsfactory.com>
|
|
5
6
|
License: Apache-2.0
|
|
6
7
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
@@ -15,6 +16,7 @@ Requires-Dist: gmsh
|
|
|
15
16
|
Requires-Dist: meshio>=5.0.0
|
|
16
17
|
Requires-Dist: nbformat>=4.2.0
|
|
17
18
|
Requires-Dist: nest_asyncio2
|
|
19
|
+
Requires-Dist: pdk-schema==0.0.2
|
|
18
20
|
Requires-Dist: plotly
|
|
19
21
|
Requires-Dist: pyvista>=0.43.0
|
|
20
22
|
Requires-Dist: trame
|
|
@@ -22,7 +24,7 @@ Requires-Dist: trame-vtk
|
|
|
22
24
|
Requires-Dist: trame-vuetify
|
|
23
25
|
Dynamic: license-file
|
|
24
26
|
|
|
25
|
-
# gsim 0.
|
|
27
|
+
# gsim 0.3.0
|
|
26
28
|
|
|
27
29
|
> Electromagnetic simulation for photonics and electronics, powered by [GDSFactory+](https://gdsfactory.com)
|
|
28
30
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "gsim"
|
|
3
|
-
version = "0.
|
|
4
|
-
description = ""
|
|
3
|
+
version = "0.3.0"
|
|
4
|
+
description = "Electromagnetic simulation for photonics and electronics, powered by GDSFactory."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = "~=3.12.0"
|
|
7
7
|
license = { text = "Apache-2.0" }
|
|
@@ -18,6 +18,7 @@ dependencies = [
|
|
|
18
18
|
"meshio>=5.0.0",
|
|
19
19
|
"nbformat>=4.2.0",
|
|
20
20
|
"nest_asyncio2",
|
|
21
|
+
"pdk-schema==0.0.2",
|
|
21
22
|
"plotly",
|
|
22
23
|
"pyvista>=0.43.0",
|
|
23
24
|
"trame",
|
|
@@ -69,18 +70,6 @@ test = [
|
|
|
69
70
|
requires = ["build", "setuptools>=61", "uv", "wheel"]
|
|
70
71
|
build-backend = "setuptools.build_meta"
|
|
71
72
|
|
|
72
|
-
[[tool.bver.file]]
|
|
73
|
-
src = "README.md"
|
|
74
|
-
|
|
75
|
-
[[tool.bver.file]]
|
|
76
|
-
src = "pyproject.toml"
|
|
77
|
-
|
|
78
|
-
[[tool.bver.file]]
|
|
79
|
-
src = "src/gsim/__init__.py"
|
|
80
|
-
|
|
81
|
-
[tool.bver.git]
|
|
82
|
-
commit-template = "Release {new-version}"
|
|
83
|
-
|
|
84
73
|
[tool.codespell]
|
|
85
74
|
ignore-words-list = "doubleclick,euclidian,te"
|
|
86
75
|
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""Built-in optical material cards."""
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
|
|
5
|
+
import gdsfactory as gf
|
|
6
|
+
from pdk_schema import (
|
|
7
|
+
Band,
|
|
8
|
+
Coord,
|
|
9
|
+
Index,
|
|
10
|
+
MaterialCard,
|
|
11
|
+
Provenance,
|
|
12
|
+
Regime,
|
|
13
|
+
Sellmeier,
|
|
14
|
+
SellmeierTerm,
|
|
15
|
+
TableData,
|
|
16
|
+
TabulatedValue,
|
|
17
|
+
Validity,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
_LI_293K_DATA = (
|
|
21
|
+
(1.20, 3.5167),
|
|
22
|
+
(1.22, 3.5133),
|
|
23
|
+
(1.24, 3.5102),
|
|
24
|
+
(1.26, 3.5072),
|
|
25
|
+
(1.28, 3.5043),
|
|
26
|
+
(1.30, 3.5016),
|
|
27
|
+
(1.32, 3.4990),
|
|
28
|
+
(1.34, 3.4965),
|
|
29
|
+
(1.36, 3.4941),
|
|
30
|
+
(1.38, 3.4918),
|
|
31
|
+
(1.40, 3.4896),
|
|
32
|
+
(1.45, 3.4845),
|
|
33
|
+
(1.50, 3.4799),
|
|
34
|
+
(1.55, 3.4757),
|
|
35
|
+
(1.60, 3.4719),
|
|
36
|
+
(1.65, 3.4684),
|
|
37
|
+
(1.70, 3.4653),
|
|
38
|
+
(1.80, 3.4597),
|
|
39
|
+
(1.90, 3.4550),
|
|
40
|
+
(2.00, 3.4510),
|
|
41
|
+
(2.25, 3.4431),
|
|
42
|
+
(2.50, 3.4375),
|
|
43
|
+
(2.75, 3.4334),
|
|
44
|
+
(3.00, 3.4302),
|
|
45
|
+
(4.00, 3.4229),
|
|
46
|
+
(5.00, 3.4195),
|
|
47
|
+
(6.00, 3.4177),
|
|
48
|
+
(7.00, 3.4165),
|
|
49
|
+
(8.00, 3.4158),
|
|
50
|
+
(9.00, 3.4153),
|
|
51
|
+
(10.0, 3.4150),
|
|
52
|
+
(11.0, 3.4147),
|
|
53
|
+
(12.0, 3.4145),
|
|
54
|
+
(13.0, 3.4144),
|
|
55
|
+
(14.0, 3.4142),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _validity(minimum_um: float, maximum_um: float) -> Validity:
|
|
60
|
+
"""Return a strict wavelength validity range in micrometers."""
|
|
61
|
+
return Validity(
|
|
62
|
+
at=None,
|
|
63
|
+
over={
|
|
64
|
+
"wavelength": Band(
|
|
65
|
+
min=minimum_um,
|
|
66
|
+
max=maximum_um,
|
|
67
|
+
unit="um",
|
|
68
|
+
label=None,
|
|
69
|
+
)
|
|
70
|
+
},
|
|
71
|
+
on_out_of_range="raise",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _provenance(label: str) -> Provenance:
|
|
76
|
+
"""Return the minimum required literature provenance."""
|
|
77
|
+
return Provenance(
|
|
78
|
+
source="literature",
|
|
79
|
+
label=label,
|
|
80
|
+
maturity="empirical",
|
|
81
|
+
citations=[],
|
|
82
|
+
comment=None,
|
|
83
|
+
url=None,
|
|
84
|
+
data_url=None,
|
|
85
|
+
info={},
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _card(
|
|
90
|
+
name: str,
|
|
91
|
+
permittivity: Index | Sellmeier,
|
|
92
|
+
temperature_ref: float,
|
|
93
|
+
) -> MaterialCard:
|
|
94
|
+
"""Build an optical material card."""
|
|
95
|
+
return MaterialCard(
|
|
96
|
+
name=name,
|
|
97
|
+
optical=Regime(
|
|
98
|
+
temperature_ref=temperature_ref,
|
|
99
|
+
provenance=_provenance(name),
|
|
100
|
+
permittivity=permittivity,
|
|
101
|
+
conductivity=None,
|
|
102
|
+
permeability=None,
|
|
103
|
+
perturbations=[],
|
|
104
|
+
info={},
|
|
105
|
+
),
|
|
106
|
+
rf=None,
|
|
107
|
+
info={},
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
_SI_SALZBERG = _card(
|
|
112
|
+
name="Si-Salzberg",
|
|
113
|
+
temperature_ref=299.15,
|
|
114
|
+
permittivity=Sellmeier(
|
|
115
|
+
validity=_validity(1.357, 11.04),
|
|
116
|
+
variation=None,
|
|
117
|
+
conductivity=None,
|
|
118
|
+
terms=(
|
|
119
|
+
SellmeierTerm(b=10.6684293, c_um=0.301516485),
|
|
120
|
+
SellmeierTerm(b=0.0030434748, c_um=1.13475115),
|
|
121
|
+
SellmeierTerm(b=1.54133408, c_um=1104.0),
|
|
122
|
+
),
|
|
123
|
+
offset=0.0,
|
|
124
|
+
),
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
_SI_LI_293K = _card(
|
|
128
|
+
name="Si-Li-293K",
|
|
129
|
+
temperature_ref=293.0,
|
|
130
|
+
permittivity=Index(
|
|
131
|
+
validity=_validity(1.2, 14.0),
|
|
132
|
+
variation=None,
|
|
133
|
+
conductivity=None,
|
|
134
|
+
n=TabulatedValue(
|
|
135
|
+
unit="",
|
|
136
|
+
data=TableData(
|
|
137
|
+
dims=("wavelength",),
|
|
138
|
+
coords={
|
|
139
|
+
"wavelength": Coord(
|
|
140
|
+
values=[row[0] for row in _LI_293K_DATA],
|
|
141
|
+
unit="um",
|
|
142
|
+
)
|
|
143
|
+
},
|
|
144
|
+
values=[row[1] for row in _LI_293K_DATA],
|
|
145
|
+
attrs={},
|
|
146
|
+
interp="linear",
|
|
147
|
+
),
|
|
148
|
+
),
|
|
149
|
+
k=None,
|
|
150
|
+
),
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
_SIO2_MALITSON = _card(
|
|
154
|
+
name="SiO2-Malitson",
|
|
155
|
+
temperature_ref=293.0,
|
|
156
|
+
permittivity=Sellmeier(
|
|
157
|
+
validity=_validity(0.21, 6.7),
|
|
158
|
+
variation=None,
|
|
159
|
+
conductivity=None,
|
|
160
|
+
terms=(
|
|
161
|
+
SellmeierTerm(b=0.6961663, c_um=0.0684043),
|
|
162
|
+
SellmeierTerm(b=0.4079426, c_um=0.1162414),
|
|
163
|
+
SellmeierTerm(b=0.8974794, c_um=9.896161),
|
|
164
|
+
),
|
|
165
|
+
offset=0.0,
|
|
166
|
+
),
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
GSIM_MATERIAL_CARDS: dict[str, MaterialCard] = {
|
|
170
|
+
"Si": _SI_SALZBERG.model_copy(update={"name": "Si"}),
|
|
171
|
+
"Si-Salzberg": _SI_SALZBERG,
|
|
172
|
+
"Si-Li-293K": _SI_LI_293K,
|
|
173
|
+
"SiO2": _SIO2_MALITSON.model_copy(update={"name": "SiO2"}),
|
|
174
|
+
"SiO2-Malitson": _SIO2_MALITSON,
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def get_material_card(
|
|
179
|
+
material_name: str,
|
|
180
|
+
project_material_cards: Mapping[str, MaterialCard] | None = None,
|
|
181
|
+
) -> MaterialCard:
|
|
182
|
+
"""Return an active-PDK card when present, otherwise a built-in card."""
|
|
183
|
+
if project_material_cards is None:
|
|
184
|
+
active_pdk = gf.get_active_pdk()
|
|
185
|
+
project_material_cards = getattr(active_pdk, "material_cards", None)
|
|
186
|
+
if project_material_cards and material_name in project_material_cards:
|
|
187
|
+
return project_material_cards[material_name]
|
|
188
|
+
return GSIM_MATERIAL_CARDS[material_name]
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
__all__ = ["GSIM_MATERIAL_CARDS", "get_material_card"]
|
|
@@ -55,7 +55,26 @@ def fuse_polygons(
|
|
|
55
55
|
Returns:
|
|
56
56
|
Merged Shapely Polygon or MultiPolygon
|
|
57
57
|
"""
|
|
58
|
-
|
|
58
|
+
source_layer = getattr(layer, "layer", layer)
|
|
59
|
+
derived_layer = getattr(layer, "derived_layer", None)
|
|
60
|
+
|
|
61
|
+
# Simulation export materializes derived layers onto their GDS targets.
|
|
62
|
+
# Prefer those polygons when present: re-evaluating the source Boolean
|
|
63
|
+
# expression loses LayerLevel.background semantics (notably full-height
|
|
64
|
+
# grating teeth). Fall back to evaluating the source expression for the
|
|
65
|
+
# ordinary, unmaterialized visualization path.
|
|
66
|
+
layer_region = None
|
|
67
|
+
if derived_layer is not None:
|
|
68
|
+
target = tuple(derived_layer.layer)
|
|
69
|
+
layer_index = component.kcl.layer(*target)
|
|
70
|
+
target_region = component.kdb_cell.begin_shapes_rec(layer_index)
|
|
71
|
+
if not target_region.at_end():
|
|
72
|
+
from kfactory import kdb
|
|
73
|
+
|
|
74
|
+
layer_region = kdb.Region(target_region)
|
|
75
|
+
|
|
76
|
+
if layer_region is None:
|
|
77
|
+
layer_region = source_layer.get_shapes(component)
|
|
59
78
|
|
|
60
79
|
shapely_polygons = []
|
|
61
80
|
for klayout_polygon in layer_region.each_merged():
|
|
@@ -100,15 +119,13 @@ def cleanup_component(
|
|
|
100
119
|
Returns:
|
|
101
120
|
Dict mapping layer name to merged Shapely polygon
|
|
102
121
|
"""
|
|
103
|
-
layer_stack_dict = layer_stack.to_dict()
|
|
104
|
-
|
|
105
122
|
return {
|
|
106
123
|
layername: fuse_polygons(
|
|
107
124
|
component,
|
|
108
|
-
layer
|
|
125
|
+
layer,
|
|
109
126
|
round_tol=round_tol,
|
|
110
127
|
simplify_tol=simplify_tol,
|
|
111
128
|
)
|
|
112
|
-
for layername, layer in
|
|
113
|
-
if layer
|
|
129
|
+
for layername, layer in layer_stack.layers.items()
|
|
130
|
+
if layer.layer is not None
|
|
114
131
|
}
|
|
@@ -491,6 +491,13 @@ def extract_layer_stack(
|
|
|
491
491
|
if not _is_dielectric_material(material):
|
|
492
492
|
continue
|
|
493
493
|
if not _looks_like_passivation(layer_name, material):
|
|
494
|
+
if material.strip().lower() in {
|
|
495
|
+
"si",
|
|
496
|
+
"silicon",
|
|
497
|
+
"ge",
|
|
498
|
+
"germanium",
|
|
499
|
+
}:
|
|
500
|
+
continue
|
|
494
501
|
bulk_material = material
|
|
495
502
|
break
|
|
496
503
|
|
|
@@ -502,13 +509,19 @@ def extract_layer_stack(
|
|
|
502
509
|
|
|
503
510
|
if bulk_material is None and sorted_dielectric_layers:
|
|
504
511
|
for _zmin, _zmax, material, _layer_name in sorted_dielectric_layers:
|
|
505
|
-
|
|
512
|
+
# Silicon/Ge layers can be classified as dielectrics for geometry
|
|
513
|
+
# purposes, but they are not a suitable blanket cladding. If a
|
|
514
|
+
# PDK has no oxide-like layer, use the explicit SiO2 fallback
|
|
515
|
+
# below rather than turning the synthetic BOX/cladding into Si.
|
|
516
|
+
if _is_dielectric_material(material) and material.strip().lower() not in {
|
|
517
|
+
"si",
|
|
518
|
+
"silicon",
|
|
519
|
+
"ge",
|
|
520
|
+
"germanium",
|
|
521
|
+
}:
|
|
506
522
|
bulk_material = material
|
|
507
523
|
break
|
|
508
524
|
|
|
509
|
-
if bulk_material is None and sorted_dielectric_layers:
|
|
510
|
-
bulk_material = sorted_dielectric_layers[0][2]
|
|
511
|
-
|
|
512
525
|
if bulk_material is None:
|
|
513
526
|
# Rare fallback when a PDK stack defines no dielectric layers.
|
|
514
527
|
bulk_material = "SiO2"
|
|
@@ -1270,7 +1270,7 @@ def refractive_index_profile(
|
|
|
1270
1270
|
if layer.material == "air":
|
|
1271
1271
|
continue
|
|
1272
1272
|
gds_layer = getattr(layer, "gds_layer", None)
|
|
1273
|
-
if gds_layer
|
|
1273
|
+
if not isinstance(gds_layer, tuple):
|
|
1274
1274
|
continue
|
|
1275
1275
|
intervals = interval_func(component, layer, cut_coord)
|
|
1276
1276
|
if not intervals and not _layer_has_any_polygon(component, layer):
|
|
@@ -1292,6 +1292,8 @@ def refractive_index_profile(
|
|
|
1292
1292
|
if eps <= 0:
|
|
1293
1293
|
continue
|
|
1294
1294
|
gds_layer = getattr(layer, "gds_layer", None)
|
|
1295
|
+
if not isinstance(gds_layer, tuple):
|
|
1296
|
+
continue
|
|
1295
1297
|
h_mask = layer_h_masks.get(gds_layer)
|
|
1296
1298
|
if h_mask is None:
|
|
1297
1299
|
continue
|
|
@@ -475,9 +475,9 @@ class ModeResult(BaseModel):
|
|
|
475
475
|
raise ValueError(
|
|
476
476
|
"Ambiguous geometry: both x_grid and y_grid are populated."
|
|
477
477
|
)
|
|
478
|
-
if
|
|
478
|
+
if self.y_grid is not None:
|
|
479
479
|
return self.y_grid, "y (µm)"
|
|
480
|
-
if
|
|
480
|
+
if self.x_grid is not None:
|
|
481
481
|
return self.x_grid, "x (µm)"
|
|
482
482
|
raise ValueError(
|
|
483
483
|
"No horizontal grid available. Set x_grid or y_grid on ModeResult."
|
|
@@ -553,7 +553,52 @@ class Simulation(BaseModel):
|
|
|
553
553
|
if mz_high < needed:
|
|
554
554
|
self.domain.margin_z = (mz_low, needed)
|
|
555
555
|
|
|
556
|
-
def
|
|
556
|
+
def _component_with_derived_layers(self, component: Any) -> Any:
|
|
557
|
+
"""Return *component* augmented with any active-PDK derived layers.
|
|
558
|
+
|
|
559
|
+
GDS stores source mask layers, whereas a gdsfactory ``LayerStack`` may
|
|
560
|
+
describe physical layers using boolean expressions and ``derived_layer``
|
|
561
|
+
targets. MEEP needs both: the evaluated layers for the physical stack
|
|
562
|
+
and the original layers for stack entries that are not derived.
|
|
563
|
+
"""
|
|
564
|
+
import gdsfactory as gf
|
|
565
|
+
|
|
566
|
+
pdk_layer_stack = gf.get_active_pdk().layer_stack
|
|
567
|
+
if pdk_layer_stack is None:
|
|
568
|
+
return component.copy()
|
|
569
|
+
if not any(
|
|
570
|
+
level.derived_layer is not None for level in pdk_layer_stack.layers.values()
|
|
571
|
+
):
|
|
572
|
+
return component.copy()
|
|
573
|
+
|
|
574
|
+
derived = pdk_layer_stack.get_component_with_derived_layers(component)
|
|
575
|
+
# ``get_component_with_derived_layers`` evaluates each layer's
|
|
576
|
+
# Boolean expression but does not apply gdsfactory's ``background``
|
|
577
|
+
# semantics. Recreate those physical layers from the component bbox
|
|
578
|
+
# and the declared etch exclusions, matching ``Component.to_3d()``.
|
|
579
|
+
# This keeps the hierarchy intact; no flattening is required.
|
|
580
|
+
from kfactory import kdb
|
|
581
|
+
|
|
582
|
+
for level in pdk_layer_stack.layers.values():
|
|
583
|
+
if not getattr(level, "background", False) or level.derived_layer is None:
|
|
584
|
+
continue
|
|
585
|
+
|
|
586
|
+
target_layer = gf.get_layer_tuple(level.derived_layer.layer)
|
|
587
|
+
background = kdb.Region(component.kdb_cell.bbox())
|
|
588
|
+
for excluded_layer in getattr(level, "background_exclude_layers", ()):
|
|
589
|
+
layer_index = component.kcl.layer(*tuple(excluded_layer))
|
|
590
|
+
background -= kdb.Region(
|
|
591
|
+
component.kdb_cell.begin_shapes_rec(layer_index)
|
|
592
|
+
)
|
|
593
|
+
derived.remove_layers([target_layer])
|
|
594
|
+
derived.add_polygon(background, layer=target_layer)
|
|
595
|
+
|
|
596
|
+
derived.add_ref(component)
|
|
597
|
+
return derived
|
|
598
|
+
|
|
599
|
+
def _resolve_z_ref_extent(
|
|
600
|
+
self, component: Any | None = None
|
|
601
|
+
) -> tuple[float, float, str, float | None, bool]:
|
|
557
602
|
"""Resolve ``domain.z_ref`` to a vertical reference window.
|
|
558
603
|
|
|
559
604
|
Single source of truth for both the fiber-margin expansion and the
|
|
@@ -588,7 +633,8 @@ class Simulation(BaseModel):
|
|
|
588
633
|
|
|
589
634
|
if z_ref is None:
|
|
590
635
|
layer, n = _find_highest_n_layer_in_component(
|
|
591
|
-
self.geometry.component,
|
|
636
|
+
component if component is not None else self.geometry.component,
|
|
637
|
+
stack,
|
|
592
638
|
)
|
|
593
639
|
if layer is None:
|
|
594
640
|
extent = self._stack_material_extent()
|
|
@@ -1139,11 +1185,21 @@ class Simulation(BaseModel):
|
|
|
1139
1185
|
if self.geometry.component is None:
|
|
1140
1186
|
raise ValueError("No geometry set.")
|
|
1141
1187
|
|
|
1188
|
+
# Materialize derived PDK layers before inspecting or exporting the
|
|
1189
|
+
# geometry. A number of PDKs define the physical core as a boolean
|
|
1190
|
+
# expression of fabrication-mask layers; those derived polygons are
|
|
1191
|
+
# not present in an imported GDS until the layer stack evaluates them.
|
|
1192
|
+
original_component = self._component_with_derived_layers(
|
|
1193
|
+
self.geometry.component
|
|
1194
|
+
)
|
|
1195
|
+
|
|
1142
1196
|
# Apply z-crop for 3D and XZ 2D (both use the vertical dimension).
|
|
1143
1197
|
# XY 2D collapses z entirely so cropping is meaningless. The crop
|
|
1144
1198
|
# window comes from domain.z_ref (default: the drawn photonic core).
|
|
1145
1199
|
if (is_3d or plane == "xz") and not self._z_cropped:
|
|
1146
|
-
ref_zmin, ref_zmax, ref_name, ref_n, is_auto = self._resolve_z_ref_extent(
|
|
1200
|
+
ref_zmin, ref_zmax, ref_name, ref_n, is_auto = self._resolve_z_ref_extent(
|
|
1201
|
+
component=original_component
|
|
1202
|
+
)
|
|
1147
1203
|
# When a fiber source is configured in XZ mode, expand the
|
|
1148
1204
|
# above (high) side of margin_z so the cropped stack still
|
|
1149
1205
|
# contains the beam plane (and PML headroom) — from the ref top.
|
|
@@ -1152,7 +1208,6 @@ class Simulation(BaseModel):
|
|
|
1152
1208
|
|
|
1153
1209
|
import gdsfactory as gf
|
|
1154
1210
|
|
|
1155
|
-
original_component = self.geometry.component.copy()
|
|
1156
1211
|
stack = self.geometry.stack
|
|
1157
1212
|
|
|
1158
1213
|
# Resolve the XZ cut Y-coordinate ('auto'/None -> bbox center).
|
|
@@ -254,9 +254,8 @@ def build_cross_section_rectangles(
|
|
|
254
254
|
directly so cross-section geometry for custom material stacks
|
|
255
255
|
(e.g. TFLN) is rendered correctly.
|
|
256
256
|
|
|
257
|
-
Layers that have no GDS polygons
|
|
258
|
-
|
|
259
|
-
implicit from adjacent layers.
|
|
257
|
+
Layers that have no GDS polygons are skipped, since their boundaries are
|
|
258
|
+
already implicit from adjacent layers.
|
|
260
259
|
|
|
261
260
|
Args:
|
|
262
261
|
component: gdsfactory Component with GDS polygons.
|
|
@@ -275,23 +274,6 @@ def build_cross_section_rectangles(
|
|
|
275
274
|
if not stack.layers:
|
|
276
275
|
return []
|
|
277
276
|
|
|
278
|
-
def _has_any_polygon(layer: object) -> bool:
|
|
279
|
-
gds = getattr(layer, "gds_layer", None)
|
|
280
|
-
if gds is None:
|
|
281
|
-
return False
|
|
282
|
-
try:
|
|
283
|
-
polys = component.get_polygons_points(layers=(gds,), merge=True)
|
|
284
|
-
except Exception:
|
|
285
|
-
return False
|
|
286
|
-
else:
|
|
287
|
-
if not isinstance(polys, dict):
|
|
288
|
-
return False
|
|
289
|
-
for v in polys.values():
|
|
290
|
-
items = v if isinstance(v, list) else [v]
|
|
291
|
-
if len(items) > 0:
|
|
292
|
-
return True
|
|
293
|
-
return False
|
|
294
|
-
|
|
295
277
|
if slice_axis == "y":
|
|
296
278
|
cut_line = LineString([(-1e6, slice_coord), (1e6, slice_coord)])
|
|
297
279
|
elif slice_axis == "x":
|
|
@@ -327,21 +309,9 @@ def build_cross_section_rectangles(
|
|
|
327
309
|
poly_items.extend(items)
|
|
328
310
|
|
|
329
311
|
if not poly_items:
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
{
|
|
334
|
-
"h_min": -float("inf"),
|
|
335
|
-
"h_max": float("inf"),
|
|
336
|
-
"z_min": layer.zmin,
|
|
337
|
-
"z_max": layer.zmax,
|
|
338
|
-
"layer_name": layer.name,
|
|
339
|
-
"material": layer.material,
|
|
340
|
-
"sidewall_angle": float(
|
|
341
|
-
getattr(layer, "sidewall_angle", 0.0) or 0.0
|
|
342
|
-
),
|
|
343
|
-
}
|
|
344
|
-
)
|
|
312
|
+
# The component does not draw this stack layer. Do not turn it
|
|
313
|
+
# into an infinite slab: the runner likewise emits no geometry
|
|
314
|
+
# for a layer with no GDS polygons.
|
|
345
315
|
continue
|
|
346
316
|
|
|
347
317
|
for poly in poly_items:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gsim
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Electromagnetic simulation for photonics and electronics, powered by GDSFactory.
|
|
4
5
|
Author-email: GDSFactory <contact@gdsfactory.com>
|
|
5
6
|
License: Apache-2.0
|
|
6
7
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
@@ -15,6 +16,7 @@ Requires-Dist: gmsh
|
|
|
15
16
|
Requires-Dist: meshio>=5.0.0
|
|
16
17
|
Requires-Dist: nbformat>=4.2.0
|
|
17
18
|
Requires-Dist: nest_asyncio2
|
|
19
|
+
Requires-Dist: pdk-schema==0.0.2
|
|
18
20
|
Requires-Dist: plotly
|
|
19
21
|
Requires-Dist: pyvista>=0.43.0
|
|
20
22
|
Requires-Dist: trame
|
|
@@ -22,7 +24,7 @@ Requires-Dist: trame-vtk
|
|
|
22
24
|
Requires-Dist: trame-vuetify
|
|
23
25
|
Dynamic: license-file
|
|
24
26
|
|
|
25
|
-
# gsim 0.
|
|
27
|
+
# gsim 0.3.0
|
|
26
28
|
|
|
27
29
|
> Electromagnetic simulation for photonics and electronics, powered by [GDSFactory+](https://gdsfactory.com)
|
|
28
30
|
|
|
@@ -15,6 +15,7 @@ src/gsim/common/cross_section.py
|
|
|
15
15
|
src/gsim/common/geometry.py
|
|
16
16
|
src/gsim/common/geometry_model.py
|
|
17
17
|
src/gsim/common/layered_component.py
|
|
18
|
+
src/gsim/common/materials.py
|
|
18
19
|
src/gsim/common/polygon.py
|
|
19
20
|
src/gsim/common/polygon_utils.py
|
|
20
21
|
src/gsim/common/types.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|