wavesimpro 1.9.0__tar.gz → 1.10.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.
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/PKG-INFO +10 -3
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/README.md +9 -2
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/pyproject.toml +1 -1
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro/__init__.py +17 -1
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro/json_helper.py +486 -9
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro.egg-info/PKG-INFO +10 -3
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/setup.cfg +0 -0
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro/__main__.py +0 -0
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro/binary_utils.py +0 -0
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro/client.py +0 -0
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro/config.py +0 -0
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro/exceptions.py +0 -0
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro/execute.py +0 -0
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro/py.typed +0 -0
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro/setup.py +0 -0
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro/simulate.py +0 -0
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro/validate.py +0 -0
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro.egg-info/SOURCES.txt +0 -0
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro.egg-info/dependency_links.txt +0 -0
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro.egg-info/requires.txt +0 -0
- {wavesimpro-1.9.0 → wavesimpro-1.10.0}/src/wavesimpro.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wavesimpro
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10.0
|
|
4
4
|
Summary: WavesimPro Python API — cloud execution client for the Rayfos simulation platform
|
|
5
5
|
Author: Rayfos
|
|
6
6
|
Project-URL: Repository, https://github.com/rayfos/wavesimpro
|
|
@@ -59,8 +59,15 @@ field = wp.read_binary_field(run.download("output.bin"))
|
|
|
59
59
|
|
|
60
60
|
## What the API covers
|
|
61
61
|
|
|
62
|
-
- Setup helpers for domains, media, primitives (box,
|
|
63
|
-
|
|
62
|
+
- Setup helpers for domains, media, primitives (box, sphere, ellipsoid, cylinder, cone,
|
|
63
|
+
N-sided prism, STL, GDSII layouts, voxel arrays), sources (point, plane wave, Gaussian beam,
|
|
64
|
+
custom field, custom-from-file, engine-solved waveguide mode) and monitors:
|
|
65
|
+
`create_box_primitive`, `create_sphere_primitive`, `create_ellipsoid_primitive`,
|
|
66
|
+
`create_cylinder_primitive`, `create_cone_primitive`, `create_prism_primitive`,
|
|
67
|
+
`create_stl_primitive`, `create_gds_primitive` (with `create_gds_layer_config` /
|
|
68
|
+
`create_gds_structure_override`), `create_voxels_model_primitive`.
|
|
69
|
+
- Per-primitive sub-pixel flag (`subpixel=True/False` on every shape, STL and GDSII helper)
|
|
70
|
+
to choose which shapes get smoothed interfaces.
|
|
64
71
|
- Per-axis pixel sizes (`pixel_size=[dx, dy, dz]`) and sub-pixel permittivity averaging
|
|
65
72
|
(`subpixel_factor=`), when the compute node supports them.
|
|
66
73
|
- Preflight memory check and cost estimate before a run.
|
|
@@ -36,8 +36,15 @@ field = wp.read_binary_field(run.download("output.bin"))
|
|
|
36
36
|
|
|
37
37
|
## What the API covers
|
|
38
38
|
|
|
39
|
-
- Setup helpers for domains, media, primitives (box,
|
|
40
|
-
|
|
39
|
+
- Setup helpers for domains, media, primitives (box, sphere, ellipsoid, cylinder, cone,
|
|
40
|
+
N-sided prism, STL, GDSII layouts, voxel arrays), sources (point, plane wave, Gaussian beam,
|
|
41
|
+
custom field, custom-from-file, engine-solved waveguide mode) and monitors:
|
|
42
|
+
`create_box_primitive`, `create_sphere_primitive`, `create_ellipsoid_primitive`,
|
|
43
|
+
`create_cylinder_primitive`, `create_cone_primitive`, `create_prism_primitive`,
|
|
44
|
+
`create_stl_primitive`, `create_gds_primitive` (with `create_gds_layer_config` /
|
|
45
|
+
`create_gds_structure_override`), `create_voxels_model_primitive`.
|
|
46
|
+
- Per-primitive sub-pixel flag (`subpixel=True/False` on every shape, STL and GDSII helper)
|
|
47
|
+
to choose which shapes get smoothed interfaces.
|
|
41
48
|
- Per-axis pixel sizes (`pixel_size=[dx, dy, dz]`) and sub-pixel permittivity averaging
|
|
42
49
|
(`subpixel_factor=`), when the compute node supports them.
|
|
43
50
|
- Preflight memory check and cost estimate before a run.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "wavesimpro"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.10.0"
|
|
8
8
|
description = "WavesimPro Python API — cloud execution client for the Rayfos simulation platform"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -33,6 +33,14 @@ from .json_helper import (
|
|
|
33
33
|
create_simulation_domain,
|
|
34
34
|
create_stl_primitive,
|
|
35
35
|
create_box_primitive,
|
|
36
|
+
create_sphere_primitive,
|
|
37
|
+
create_ellipsoid_primitive,
|
|
38
|
+
create_cylinder_primitive,
|
|
39
|
+
create_cone_primitive,
|
|
40
|
+
create_prism_primitive,
|
|
41
|
+
create_gds_primitive,
|
|
42
|
+
create_gds_layer_config,
|
|
43
|
+
create_gds_structure_override,
|
|
36
44
|
create_medium,
|
|
37
45
|
create_point_source,
|
|
38
46
|
create_plane_wave_source,
|
|
@@ -46,7 +54,7 @@ from .json_helper import (
|
|
|
46
54
|
parse_progress_data,
|
|
47
55
|
)
|
|
48
56
|
|
|
49
|
-
__version__ = "1.
|
|
57
|
+
__version__ = "1.10.0"
|
|
50
58
|
__all__ = [
|
|
51
59
|
# Client
|
|
52
60
|
"RayfosClient",
|
|
@@ -78,6 +86,14 @@ __all__ = [
|
|
|
78
86
|
"create_simulation_domain",
|
|
79
87
|
"create_stl_primitive",
|
|
80
88
|
"create_box_primitive",
|
|
89
|
+
"create_sphere_primitive",
|
|
90
|
+
"create_ellipsoid_primitive",
|
|
91
|
+
"create_cylinder_primitive",
|
|
92
|
+
"create_cone_primitive",
|
|
93
|
+
"create_prism_primitive",
|
|
94
|
+
"create_gds_primitive",
|
|
95
|
+
"create_gds_layer_config",
|
|
96
|
+
"create_gds_structure_override",
|
|
81
97
|
"create_medium",
|
|
82
98
|
"create_point_source",
|
|
83
99
|
"create_plane_wave_source",
|
|
@@ -42,6 +42,84 @@ def create_simulation_domain(
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
|
|
45
|
+
# ---------------------------------------------------------------------------
|
|
46
|
+
# Primitive helpers
|
|
47
|
+
#
|
|
48
|
+
# Every primitive dict mirrors RayfosCommandModels.PrimitiveBase (Primitives.cs):
|
|
49
|
+
# Id (uuid), Name, ShapeType (enum serialised as its name, e.g. "Cylinder"),
|
|
50
|
+
# MediumId, Position {X,Y,Z: Length}, PositionAnchor (enum name), Rotation
|
|
51
|
+
# {X,Y,Z} in degrees, plus the per-shape properties. Lengths are {Value, Unit}.
|
|
52
|
+
# "PositioningMode": "CenterAndSize" is the Studio bookkeeping key the existing
|
|
53
|
+
# helpers already emit (ignored by the server).
|
|
54
|
+
#
|
|
55
|
+
# Sub-pixel flag ("SubPixel"): True = this primitive's interface voxels are
|
|
56
|
+
# probe-averaged (create_wavesim_properties' subpixel_factor probes per axis);
|
|
57
|
+
# False = centre-sampled staircase for this primitive; None (default) = key
|
|
58
|
+
# omitted, the primitive follows the simulation-level PermittivitySampling.Mode
|
|
59
|
+
# (the pre-1.10 behaviour).
|
|
60
|
+
# ---------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
_POSITION_ANCHORS = (
|
|
63
|
+
"Center", "BottomLeftFront", "BottomCenter", "BottomRightFront", "BottomLeftBack",
|
|
64
|
+
"BottomRightBack", "TopCenter", "TopLeftFront", "TopRightFront", "TopLeftBack", "TopRightBack",
|
|
65
|
+
)
|
|
66
|
+
# Anchors each shape's GetCanonicalCenterPosition() accepts (others throw on the server).
|
|
67
|
+
_BOX_ANCHORS = ("Center", "BottomLeftFront", "BottomCenter", "TopCenter")
|
|
68
|
+
_AXIAL_ANCHORS = ("Center", "BottomCenter", "TopCenter") # Cylinder, Cone, Prism
|
|
69
|
+
_AXES = ("X", "Y", "Z")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _check_anchor(anchor: str, allowed: Tuple[str, ...], shape: str) -> str:
|
|
73
|
+
a = str(anchor)
|
|
74
|
+
if a not in allowed:
|
|
75
|
+
raise ValueError(f"position_anchor for {shape} must be one of {list(allowed)}, got {anchor!r}")
|
|
76
|
+
return a
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _check_axis(axis: str) -> str:
|
|
80
|
+
a = str(axis).upper()
|
|
81
|
+
if a not in _AXES:
|
|
82
|
+
raise ValueError(f"axis must be 'X', 'Y' or 'Z', got {axis!r}")
|
|
83
|
+
return a
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _length(value: float, unit: str) -> Dict[str, Any]:
|
|
87
|
+
return {"Value": float(value), "Unit": unit}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _primitive_base(
|
|
91
|
+
shape_type: str,
|
|
92
|
+
name: str,
|
|
93
|
+
medium_id: str,
|
|
94
|
+
x: float,
|
|
95
|
+
y: float,
|
|
96
|
+
z: float,
|
|
97
|
+
rotation_x: float,
|
|
98
|
+
rotation_y: float,
|
|
99
|
+
rotation_z: float,
|
|
100
|
+
position_anchor: str,
|
|
101
|
+
unit: str,
|
|
102
|
+
subpixel: Optional[bool],
|
|
103
|
+
) -> Dict[str, Any]:
|
|
104
|
+
prim: Dict[str, Any] = {
|
|
105
|
+
"Id": str(uuid.uuid4()),
|
|
106
|
+
"Name": name,
|
|
107
|
+
"ShapeType": shape_type,
|
|
108
|
+
"MediumId": medium_id,
|
|
109
|
+
"PositioningMode": "CenterAndSize",
|
|
110
|
+
"Position": {"X": _length(x, unit), "Y": _length(y, unit), "Z": _length(z, unit)},
|
|
111
|
+
"PositionAnchor": position_anchor,
|
|
112
|
+
"Rotation": {"X": float(rotation_x), "Y": float(rotation_y), "Z": float(rotation_z)},
|
|
113
|
+
}
|
|
114
|
+
_apply_subpixel(prim, subpixel)
|
|
115
|
+
return prim
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _apply_subpixel(prim: Dict[str, Any], subpixel: Optional[bool]) -> None:
|
|
119
|
+
if subpixel is not None:
|
|
120
|
+
prim["SubPixel"] = bool(subpixel)
|
|
121
|
+
|
|
122
|
+
|
|
45
123
|
def create_stl_primitive(
|
|
46
124
|
name: str,
|
|
47
125
|
file_id: str,
|
|
@@ -55,7 +133,8 @@ def create_stl_primitive(
|
|
|
55
133
|
scale_x: float = 1.0,
|
|
56
134
|
scale_y: float = 1.0,
|
|
57
135
|
scale_z: float = 1.0,
|
|
58
|
-
unit: str = "Micrometers"
|
|
136
|
+
unit: str = "Micrometers",
|
|
137
|
+
subpixel: Optional[bool] = None,
|
|
59
138
|
) -> Dict[str, Any]:
|
|
60
139
|
"""
|
|
61
140
|
Create STL primitive structure
|
|
@@ -68,8 +147,10 @@ def create_stl_primitive(
|
|
|
68
147
|
rotation_x, rotation_y, rotation_z: Rotation angles in degrees
|
|
69
148
|
scale_x, scale_y, scale_z: Scale factors
|
|
70
149
|
unit: Unit of measurement
|
|
150
|
+
subpixel: True = sub-pixel average this mesh's interface voxels, False = staircase,
|
|
151
|
+
None (default) = key omitted, follow the simulation-level setting.
|
|
71
152
|
"""
|
|
72
|
-
|
|
153
|
+
prim = {
|
|
73
154
|
"Id": str(uuid.uuid4()),
|
|
74
155
|
"Name": name,
|
|
75
156
|
"ShapeType": "StlModel",
|
|
@@ -94,6 +175,8 @@ def create_stl_primitive(
|
|
|
94
175
|
},
|
|
95
176
|
"_tempStlData": {}
|
|
96
177
|
}
|
|
178
|
+
_apply_subpixel(prim, subpixel)
|
|
179
|
+
return prim
|
|
97
180
|
|
|
98
181
|
|
|
99
182
|
def create_box_primitive(
|
|
@@ -105,19 +188,46 @@ def create_box_primitive(
|
|
|
105
188
|
size_x: float,
|
|
106
189
|
size_y: float,
|
|
107
190
|
size_z: float,
|
|
108
|
-
unit: str = "Micrometers"
|
|
191
|
+
unit: str = "Micrometers",
|
|
192
|
+
subpixel: Optional[bool] = None,
|
|
193
|
+
position_anchor: str = "Center",
|
|
194
|
+
rotation_x: float = 0.0,
|
|
195
|
+
rotation_y: float = 0.0,
|
|
196
|
+
rotation_z: float = 0.0,
|
|
109
197
|
) -> Dict[str, Any]:
|
|
110
|
-
"""
|
|
111
|
-
|
|
198
|
+
"""
|
|
199
|
+
Create a box primitive (BoxPrimitive, CenterAndSize representation).
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
name: Primitive name
|
|
203
|
+
medium_id: Medium/Material ID
|
|
204
|
+
center_x, center_y, center_z: Position (what it refers to is set by position_anchor)
|
|
205
|
+
size_x, size_y, size_z: Full extents along X/Y/Z (Size.Width/Height/Depth)
|
|
206
|
+
unit: Unit of measurement for position and size
|
|
207
|
+
subpixel: True = sub-pixel average this box's interface voxels, False = staircase,
|
|
208
|
+
None (default) = key omitted, follow the simulation-level setting.
|
|
209
|
+
position_anchor: "Center" (default), "BottomLeftFront" (minimum corner),
|
|
210
|
+
"BottomCenter" (centre of the -Y face) or "TopCenter" (centre of the +Y face).
|
|
211
|
+
The server rejects any other anchor for a box.
|
|
212
|
+
rotation_x, rotation_y, rotation_z: Rotation in degrees
|
|
213
|
+
"""
|
|
214
|
+
anchor = _check_anchor(position_anchor, _BOX_ANCHORS, "Box")
|
|
215
|
+
prim: Dict[str, Any] = {
|
|
216
|
+
"Id": str(uuid.uuid4()),
|
|
217
|
+
# "Type" kept for older servers; "ShapeType" is the canonical discriminator (same value).
|
|
112
218
|
"Type": "Box",
|
|
219
|
+
"ShapeType": "Box",
|
|
113
220
|
"Name": name,
|
|
114
221
|
"MediumId": medium_id,
|
|
115
222
|
"PositioningMode": "CenterAndSize",
|
|
223
|
+
"Representation": "CenterAndSize",
|
|
116
224
|
"Position": {
|
|
117
225
|
"X": {"Value": center_x, "Unit": unit},
|
|
118
226
|
"Y": {"Value": center_y, "Unit": unit},
|
|
119
227
|
"Z": {"Value": center_z, "Unit": unit}
|
|
120
228
|
},
|
|
229
|
+
"PositionAnchor": anchor,
|
|
230
|
+
"Rotation": {"X": float(rotation_x), "Y": float(rotation_y), "Z": float(rotation_z)},
|
|
121
231
|
# Size3D on the server is Width/Height/Depth (X/Y/Z keys were silently ignored → 4 µm default).
|
|
122
232
|
"Size": {
|
|
123
233
|
"Width": {"Value": size_x, "Unit": unit},
|
|
@@ -125,6 +235,338 @@ def create_box_primitive(
|
|
|
125
235
|
"Depth": {"Value": size_z, "Unit": unit}
|
|
126
236
|
}
|
|
127
237
|
}
|
|
238
|
+
_apply_subpixel(prim, subpixel)
|
|
239
|
+
return prim
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def create_sphere_primitive(
|
|
243
|
+
name: str,
|
|
244
|
+
medium_id: str,
|
|
245
|
+
center_x: float,
|
|
246
|
+
center_y: float,
|
|
247
|
+
center_z: float,
|
|
248
|
+
radius: float,
|
|
249
|
+
rotation_x: float = 0.0,
|
|
250
|
+
rotation_y: float = 0.0,
|
|
251
|
+
rotation_z: float = 0.0,
|
|
252
|
+
position_anchor: str = "Center",
|
|
253
|
+
unit: str = "Micrometers",
|
|
254
|
+
subpixel: Optional[bool] = None,
|
|
255
|
+
) -> Dict[str, Any]:
|
|
256
|
+
"""
|
|
257
|
+
Create a sphere primitive (SpherePrimitive).
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
name: Primitive name
|
|
261
|
+
medium_id: Medium/Material ID
|
|
262
|
+
center_x, center_y, center_z: Sphere centre
|
|
263
|
+
radius: Radius (Length in ``unit``)
|
|
264
|
+
rotation_x, rotation_y, rotation_z: Rotation in degrees (no effect on a sphere)
|
|
265
|
+
position_anchor: Stored as given (default "Center"); the server always treats
|
|
266
|
+
Position as the centre of a sphere.
|
|
267
|
+
unit: Unit of measurement
|
|
268
|
+
subpixel: True / False / None (follow the simulation-level setting)
|
|
269
|
+
"""
|
|
270
|
+
anchor = _check_anchor(position_anchor, _POSITION_ANCHORS, "Sphere")
|
|
271
|
+
prim = _primitive_base("Sphere", name, medium_id, center_x, center_y, center_z,
|
|
272
|
+
rotation_x, rotation_y, rotation_z, anchor, unit, subpixel)
|
|
273
|
+
prim["Radius"] = _length(radius, unit)
|
|
274
|
+
return prim
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def create_ellipsoid_primitive(
|
|
278
|
+
name: str,
|
|
279
|
+
medium_id: str,
|
|
280
|
+
center_x: float,
|
|
281
|
+
center_y: float,
|
|
282
|
+
center_z: float,
|
|
283
|
+
radius_x: float,
|
|
284
|
+
radius_y: float,
|
|
285
|
+
radius_z: float,
|
|
286
|
+
rotation_x: float = 0.0,
|
|
287
|
+
rotation_y: float = 0.0,
|
|
288
|
+
rotation_z: float = 0.0,
|
|
289
|
+
position_anchor: str = "Center",
|
|
290
|
+
unit: str = "Micrometers",
|
|
291
|
+
subpixel: Optional[bool] = None,
|
|
292
|
+
) -> Dict[str, Any]:
|
|
293
|
+
"""
|
|
294
|
+
Create an ellipsoid primitive (EllipsoidPrimitive).
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
name: Primitive name
|
|
298
|
+
medium_id: Medium/Material ID
|
|
299
|
+
center_x, center_y, center_z: Ellipsoid centre
|
|
300
|
+
radius_x, radius_y, radius_z: Semi-axes along X/Y/Z (before rotation)
|
|
301
|
+
rotation_x, rotation_y, rotation_z: Rotation in degrees
|
|
302
|
+
position_anchor: Stored as given (default "Center"); the server always treats
|
|
303
|
+
Position as the centre of an ellipsoid.
|
|
304
|
+
unit: Unit of measurement
|
|
305
|
+
subpixel: True / False / None (follow the simulation-level setting)
|
|
306
|
+
"""
|
|
307
|
+
anchor = _check_anchor(position_anchor, _POSITION_ANCHORS, "Ellipsoid")
|
|
308
|
+
prim = _primitive_base("Ellipsoid", name, medium_id, center_x, center_y, center_z,
|
|
309
|
+
rotation_x, rotation_y, rotation_z, anchor, unit, subpixel)
|
|
310
|
+
prim["RadiusX"] = _length(radius_x, unit)
|
|
311
|
+
prim["RadiusY"] = _length(radius_y, unit)
|
|
312
|
+
prim["RadiusZ"] = _length(radius_z, unit)
|
|
313
|
+
return prim
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def create_cylinder_primitive(
|
|
317
|
+
name: str,
|
|
318
|
+
medium_id: str,
|
|
319
|
+
position_x: float,
|
|
320
|
+
position_y: float,
|
|
321
|
+
position_z: float,
|
|
322
|
+
radius: float,
|
|
323
|
+
height: float,
|
|
324
|
+
axis: str = "Z",
|
|
325
|
+
rotation_x: float = 0.0,
|
|
326
|
+
rotation_y: float = 0.0,
|
|
327
|
+
rotation_z: float = 0.0,
|
|
328
|
+
position_anchor: str = "BottomCenter",
|
|
329
|
+
unit: str = "Micrometers",
|
|
330
|
+
subpixel: Optional[bool] = None,
|
|
331
|
+
) -> Dict[str, Any]:
|
|
332
|
+
"""
|
|
333
|
+
Create a cylinder primitive (CylinderPrimitive).
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
name: Primitive name
|
|
337
|
+
medium_id: Medium/Material ID
|
|
338
|
+
position_x, position_y, position_z: Anchor point (see position_anchor)
|
|
339
|
+
radius: Radius
|
|
340
|
+
height: Extent along ``axis``
|
|
341
|
+
axis: "X", "Y" or "Z" (default "Z")
|
|
342
|
+
rotation_x, rotation_y, rotation_z: Rotation in degrees
|
|
343
|
+
position_anchor: "BottomCenter" (default, as the server and Studio): Position is the
|
|
344
|
+
centre of the base face and the cylinder extends +height along ``axis``;
|
|
345
|
+
"Center": Position is the geometric centre; "TopCenter": centre of the top face.
|
|
346
|
+
unit: Unit of measurement
|
|
347
|
+
subpixel: True / False / None (follow the simulation-level setting)
|
|
348
|
+
"""
|
|
349
|
+
anchor = _check_anchor(position_anchor, _AXIAL_ANCHORS, "Cylinder")
|
|
350
|
+
prim = _primitive_base("Cylinder", name, medium_id, position_x, position_y, position_z,
|
|
351
|
+
rotation_x, rotation_y, rotation_z, anchor, unit, subpixel)
|
|
352
|
+
prim["Radius"] = _length(radius, unit)
|
|
353
|
+
prim["Height"] = _length(height, unit)
|
|
354
|
+
prim["Axis"] = _check_axis(axis)
|
|
355
|
+
return prim
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def create_cone_primitive(
|
|
359
|
+
name: str,
|
|
360
|
+
medium_id: str,
|
|
361
|
+
position_x: float,
|
|
362
|
+
position_y: float,
|
|
363
|
+
position_z: float,
|
|
364
|
+
radius: float,
|
|
365
|
+
height: float,
|
|
366
|
+
axis: str = "Z",
|
|
367
|
+
rotation_x: float = 0.0,
|
|
368
|
+
rotation_y: float = 0.0,
|
|
369
|
+
rotation_z: float = 0.0,
|
|
370
|
+
position_anchor: str = "BottomCenter",
|
|
371
|
+
unit: str = "Micrometers",
|
|
372
|
+
subpixel: Optional[bool] = None,
|
|
373
|
+
) -> Dict[str, Any]:
|
|
374
|
+
"""
|
|
375
|
+
Create a cone primitive (ConePrimitive). The base is a disc of ``radius``; the apex
|
|
376
|
+
lies ``height`` further along +``axis``.
|
|
377
|
+
|
|
378
|
+
Args:
|
|
379
|
+
name: Primitive name
|
|
380
|
+
medium_id: Medium/Material ID
|
|
381
|
+
position_x, position_y, position_z: Anchor point (see position_anchor)
|
|
382
|
+
radius: Base radius
|
|
383
|
+
height: Base-to-apex distance along ``axis``
|
|
384
|
+
axis: "X", "Y" or "Z" (default "Z")
|
|
385
|
+
rotation_x, rotation_y, rotation_z: Rotation in degrees
|
|
386
|
+
position_anchor: "BottomCenter" (default, as the server and Studio): Position is the
|
|
387
|
+
centre of the base; "Center": Position is the CENTROID (height/4 above the base,
|
|
388
|
+
not height/2); "TopCenter": Position is the apex.
|
|
389
|
+
unit: Unit of measurement
|
|
390
|
+
subpixel: True / False / None (follow the simulation-level setting)
|
|
391
|
+
"""
|
|
392
|
+
anchor = _check_anchor(position_anchor, _AXIAL_ANCHORS, "Cone")
|
|
393
|
+
prim = _primitive_base("Cone", name, medium_id, position_x, position_y, position_z,
|
|
394
|
+
rotation_x, rotation_y, rotation_z, anchor, unit, subpixel)
|
|
395
|
+
prim["Radius"] = _length(radius, unit)
|
|
396
|
+
prim["Height"] = _length(height, unit)
|
|
397
|
+
prim["Axis"] = _check_axis(axis)
|
|
398
|
+
return prim
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def create_prism_primitive(
|
|
402
|
+
name: str,
|
|
403
|
+
medium_id: str,
|
|
404
|
+
position_x: float,
|
|
405
|
+
position_y: float,
|
|
406
|
+
position_z: float,
|
|
407
|
+
radius: float,
|
|
408
|
+
height: float,
|
|
409
|
+
number_of_sides: int = 6,
|
|
410
|
+
axis: str = "Z",
|
|
411
|
+
top_scale: float = 1.0,
|
|
412
|
+
twist_degrees: float = 0.0,
|
|
413
|
+
rotation_x: float = 0.0,
|
|
414
|
+
rotation_y: float = 0.0,
|
|
415
|
+
rotation_z: float = 0.0,
|
|
416
|
+
position_anchor: str = "BottomCenter",
|
|
417
|
+
unit: str = "Micrometers",
|
|
418
|
+
subpixel: Optional[bool] = None,
|
|
419
|
+
) -> Dict[str, Any]:
|
|
420
|
+
"""
|
|
421
|
+
Create a regular N-sided prism primitive (PrismPrimitive): a regular polygon with
|
|
422
|
+
``number_of_sides`` corners on a circle of ``radius`` extruded ``height`` along ``axis``.
|
|
423
|
+
|
|
424
|
+
Args:
|
|
425
|
+
name: Primitive name
|
|
426
|
+
medium_id: Medium/Material ID
|
|
427
|
+
position_x, position_y, position_z: Anchor point (see position_anchor)
|
|
428
|
+
radius: Circumradius of the bottom polygon
|
|
429
|
+
height: Extent along ``axis``
|
|
430
|
+
number_of_sides: Polygon corners, integer >= 3 (3 = triangular prism, 4 = square,
|
|
431
|
+
large N approaches a cylinder). Default 6.
|
|
432
|
+
axis: "X", "Y" or "Z" (default "Z")
|
|
433
|
+
top_scale: Top-ring radius factor: 1 = straight prism (default), 0 = pyramid,
|
|
434
|
+
> 1 = flared
|
|
435
|
+
twist_degrees: Rotation of the top ring about ``axis`` in degrees (default 0)
|
|
436
|
+
rotation_x, rotation_y, rotation_z: Rotation in degrees
|
|
437
|
+
position_anchor: "BottomCenter" (default, as the server and Studio), "Center" or
|
|
438
|
+
"TopCenter" (±height/2 along ``axis``, as for a cylinder).
|
|
439
|
+
unit: Unit of measurement
|
|
440
|
+
subpixel: True / False / None (follow the simulation-level setting)
|
|
441
|
+
"""
|
|
442
|
+
anchor = _check_anchor(position_anchor, _AXIAL_ANCHORS, "Prism")
|
|
443
|
+
n = int(number_of_sides)
|
|
444
|
+
if n != number_of_sides or n < 3:
|
|
445
|
+
raise ValueError(f"number_of_sides must be an integer >= 3, got {number_of_sides!r}")
|
|
446
|
+
if top_scale < 0:
|
|
447
|
+
raise ValueError(f"top_scale must be >= 0, got {top_scale!r}")
|
|
448
|
+
prim = _primitive_base("Prism", name, medium_id, position_x, position_y, position_z,
|
|
449
|
+
rotation_x, rotation_y, rotation_z, anchor, unit, subpixel)
|
|
450
|
+
prim["Radius"] = _length(radius, unit)
|
|
451
|
+
prim["Height"] = _length(height, unit)
|
|
452
|
+
prim["Axis"] = _check_axis(axis)
|
|
453
|
+
prim["NumberOfSides"] = n
|
|
454
|
+
prim["TopScale"] = float(top_scale)
|
|
455
|
+
prim["TwistDegrees"] = float(twist_degrees)
|
|
456
|
+
return prim
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def create_gds_layer_config(
|
|
460
|
+
layer_number: int,
|
|
461
|
+
medium_id: Optional[str] = None,
|
|
462
|
+
height_um: Optional[float] = None,
|
|
463
|
+
z_offset_um: Optional[float] = None,
|
|
464
|
+
) -> Dict[str, Any]:
|
|
465
|
+
"""
|
|
466
|
+
Per-layer settings for create_gds_primitive(layer_configs=...) (GdsLayerConfig).
|
|
467
|
+
|
|
468
|
+
Args:
|
|
469
|
+
layer_number: GDS layer number
|
|
470
|
+
medium_id: Medium for this layer; None = the GDS primitive's medium_id
|
|
471
|
+
height_um: Extrusion thickness in micrometres; None = the primitive's layer_height_um
|
|
472
|
+
z_offset_um: Bottom of the layer in micrometres relative to the primitive;
|
|
473
|
+
None = auto-stacked
|
|
474
|
+
"""
|
|
475
|
+
cfg: Dict[str, Any] = {"LayerNumber": int(layer_number)}
|
|
476
|
+
if medium_id is not None:
|
|
477
|
+
cfg["MediumId"] = medium_id
|
|
478
|
+
if height_um is not None:
|
|
479
|
+
cfg["Height"] = float(height_um)
|
|
480
|
+
if z_offset_um is not None:
|
|
481
|
+
cfg["ZOffset"] = float(z_offset_um)
|
|
482
|
+
return cfg
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def create_gds_structure_override(
|
|
486
|
+
structure_name: str,
|
|
487
|
+
layer_overrides: Optional[List[Dict[str, Any]]] = None,
|
|
488
|
+
) -> Dict[str, Any]:
|
|
489
|
+
"""
|
|
490
|
+
Per-structure (GDS cell) overrides for create_gds_primitive(structure_overrides=...)
|
|
491
|
+
(GdsStructureConfig). ``layer_overrides`` is a list built with create_gds_layer_config()
|
|
492
|
+
(same keys as GdsStructureLayerOverride: LayerNumber, MediumId, Height, ZOffset); unset
|
|
493
|
+
fields inherit from the primitive's layer_configs.
|
|
494
|
+
"""
|
|
495
|
+
cfg: Dict[str, Any] = {"StructureName": structure_name}
|
|
496
|
+
if layer_overrides is not None:
|
|
497
|
+
cfg["LayerOverrides"] = list(layer_overrides)
|
|
498
|
+
return cfg
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
def create_gds_primitive(
|
|
502
|
+
name: str,
|
|
503
|
+
file_id: str,
|
|
504
|
+
medium_id: str,
|
|
505
|
+
center_x: float = 0.0,
|
|
506
|
+
center_y: float = 0.0,
|
|
507
|
+
center_z: float = 0.0,
|
|
508
|
+
layer_height_um: float = 1.0,
|
|
509
|
+
selected_layers: Optional[List[int]] = None,
|
|
510
|
+
layer_configs: Optional[List[Dict[str, Any]]] = None,
|
|
511
|
+
structure_overrides: Optional[List[Dict[str, Any]]] = None,
|
|
512
|
+
metadata_file_id: Optional[str] = None,
|
|
513
|
+
voxelization_method: str = "ViaStl",
|
|
514
|
+
rotation_x: float = 0.0,
|
|
515
|
+
rotation_y: float = 0.0,
|
|
516
|
+
rotation_z: float = 0.0,
|
|
517
|
+
scale_x: float = 1.0,
|
|
518
|
+
scale_y: float = 1.0,
|
|
519
|
+
scale_z: float = 1.0,
|
|
520
|
+
position_anchor: str = "Center",
|
|
521
|
+
unit: str = "Micrometers",
|
|
522
|
+
subpixel: Optional[bool] = None,
|
|
523
|
+
) -> Dict[str, Any]:
|
|
524
|
+
"""
|
|
525
|
+
Create a GDSII layout primitive (GdsModelPrimitive) from an uploaded .gds file.
|
|
526
|
+
|
|
527
|
+
The layout's polygons are extruded per layer; Position is the centre of the top
|
|
528
|
+
structure's bounding box. Layer thickness and offsets are plain numbers in
|
|
529
|
+
MICROMETRES on the server model (not Length objects), whatever ``unit`` is.
|
|
530
|
+
|
|
531
|
+
Args:
|
|
532
|
+
name: Primitive name
|
|
533
|
+
file_id: File id of the uploaded GDS file (GdsDataId), as for create_stl_primitive
|
|
534
|
+
medium_id: Default medium for every layer
|
|
535
|
+
center_x, center_y, center_z: Position of the layout centre
|
|
536
|
+
layer_height_um: Default extrusion thickness of each layer in µm (LayerHeight)
|
|
537
|
+
selected_layers: Layer numbers to include; None = all layers
|
|
538
|
+
layer_configs: Per-layer settings from create_gds_layer_config(); None = every layer
|
|
539
|
+
uses medium_id / layer_height_um (legacy mode)
|
|
540
|
+
structure_overrides: Per-structure (cell) overrides from
|
|
541
|
+
create_gds_structure_override(); None = none
|
|
542
|
+
metadata_file_id: Optional uploaded layer-metadata YML file id (GdsMetadataId)
|
|
543
|
+
voxelization_method: "ViaStl" (default) or "Direct"
|
|
544
|
+
rotation_x, rotation_y, rotation_z: Rotation in degrees
|
|
545
|
+
scale_x, scale_y, scale_z: Scale factors
|
|
546
|
+
position_anchor: Stored as given (default "Center"); the server treats Position as
|
|
547
|
+
the layout centre whatever the anchor.
|
|
548
|
+
unit: Unit of Position
|
|
549
|
+
subpixel: True / False / None (follow the simulation-level setting)
|
|
550
|
+
"""
|
|
551
|
+
anchor = _check_anchor(position_anchor, _POSITION_ANCHORS, "GdsModel")
|
|
552
|
+
method = str(voxelization_method)
|
|
553
|
+
if method not in ("ViaStl", "Direct"):
|
|
554
|
+
raise ValueError(f"voxelization_method must be 'ViaStl' or 'Direct', got {voxelization_method!r}")
|
|
555
|
+
prim = _primitive_base("GdsModel", name, medium_id, center_x, center_y, center_z,
|
|
556
|
+
rotation_x, rotation_y, rotation_z, anchor, unit, subpixel)
|
|
557
|
+
prim["GdsDataId"] = file_id
|
|
558
|
+
prim["ScaleFactors"] = {"X": float(scale_x), "Y": float(scale_y), "Z": float(scale_z)}
|
|
559
|
+
prim["LayerHeight"] = float(layer_height_um)
|
|
560
|
+
prim["VoxelizationMethod"] = method
|
|
561
|
+
if metadata_file_id is not None:
|
|
562
|
+
prim["GdsMetadataId"] = metadata_file_id
|
|
563
|
+
if selected_layers is not None:
|
|
564
|
+
prim["SelectedLayers"] = [int(n) for n in selected_layers]
|
|
565
|
+
if layer_configs is not None:
|
|
566
|
+
prim["LayerConfigs"] = list(layer_configs)
|
|
567
|
+
if structure_overrides is not None:
|
|
568
|
+
prim["StructureOverrides"] = list(structure_overrides)
|
|
569
|
+
return prim
|
|
128
570
|
|
|
129
571
|
|
|
130
572
|
def create_medium(
|
|
@@ -189,9 +631,8 @@ def create_point_source(
|
|
|
189
631
|
return {
|
|
190
632
|
"Id": str(uuid.uuid4()),
|
|
191
633
|
"Name": name,
|
|
192
|
-
"Id": str(uuid.uuid4()),
|
|
193
634
|
"SourceType": "Point",
|
|
194
|
-
"
|
|
635
|
+
"IsEnabled": True,
|
|
195
636
|
"UseInternalPythonSource": False,
|
|
196
637
|
"Position": {
|
|
197
638
|
"X": {"Value": position_x, "Unit": unit},
|
|
@@ -357,7 +798,9 @@ def create_voxels_model_primitive(
|
|
|
357
798
|
grid_nz: int = 32,
|
|
358
799
|
data_format: str = "Float32",
|
|
359
800
|
data_type: str = "RefractiveIndex",
|
|
360
|
-
unit: str = "Micrometers"
|
|
801
|
+
unit: str = "Micrometers",
|
|
802
|
+
subpixel: Optional[bool] = None,
|
|
803
|
+
antialias_width: Optional[float] = None,
|
|
361
804
|
) -> Dict[str, Any]:
|
|
362
805
|
"""
|
|
363
806
|
Create VoxelsModel primitive for arbitrary refractive index distributions
|
|
@@ -372,6 +815,19 @@ def create_voxels_model_primitive(
|
|
|
372
815
|
data_format: 'Float32', 'Float64', 'Complex64', 'Complex128'
|
|
373
816
|
data_type: 'RefractiveIndex', 'ComplexRefractiveIndex', 'Permittivity', 'ComplexPermittivity'
|
|
374
817
|
unit: Unit of measurement
|
|
818
|
+
|
|
819
|
+
subpixel: True anti-aliases the array on the service:
|
|
820
|
+
- array at the simulation voxel size: softened IN PLACE by a normalised Gaussian of
|
|
821
|
+
``antialias_width`` voxels on the permittivity (same resolution, volume kept).
|
|
822
|
+
On reference shapes it halves the interface error vs true sub-pixel values.
|
|
823
|
+
- array finer by a whole number per axis (voxel size = simulation voxel / k): each
|
|
824
|
+
k_x x k_y x k_z block is averaged into one simulation voxel (the same rule as the
|
|
825
|
+
shapes' sub-pixel probes); cells the array only partly covers blend with what
|
|
826
|
+
lies underneath.
|
|
827
|
+
None/False: the array must be at the simulation voxel size and is copied voxel for
|
|
828
|
+
voxel. The simulation-level ``subpixel_factor`` does not apply to voxel arrays.
|
|
829
|
+
antialias_width: Gaussian width (standard deviation, voxels) for the in-place case;
|
|
830
|
+
None = 0.5 (best on average); thin waveguides prefer ~0.7. Range 0.1-3.
|
|
375
831
|
"""
|
|
376
832
|
return {
|
|
377
833
|
"ShapeType": "VoxelsModel",
|
|
@@ -395,7 +851,9 @@ def create_voxels_model_primitive(
|
|
|
395
851
|
},
|
|
396
852
|
"DataFormat": data_format,
|
|
397
853
|
"DataType": data_type,
|
|
398
|
-
"Rotation": {"X": 0, "Y": 0, "Z": 0}
|
|
854
|
+
"Rotation": {"X": 0, "Y": 0, "Z": 0},
|
|
855
|
+
**({"SubPixel": bool(subpixel)} if subpixel is not None else {}),
|
|
856
|
+
**({"AntiAliasWidth": float(antialias_width)} if antialias_width is not None else {}),
|
|
399
857
|
}
|
|
400
858
|
|
|
401
859
|
|
|
@@ -701,6 +1159,16 @@ def create_wavesim_properties(
|
|
|
701
1159
|
derives the iteration count from this distance and it OVERRIDES
|
|
702
1160
|
residual_norm_max_iterations (threshold still stops the run early).
|
|
703
1161
|
C++ engine only.
|
|
1162
|
+
subpixel_factor: Sub-pixel probe count per axis, s (1..64, 16 is the reference
|
|
1163
|
+
value). It is used by every primitive whose SubPixel is true; a primitive with
|
|
1164
|
+
no explicit flag follows the simulation-level mode, which this argument sets to
|
|
1165
|
+
SubPixel (s > 1) — so passing it alone smooths every primitive, STL and GDSII
|
|
1166
|
+
(the pre-1.10 behaviour). Per-primitive flags (``subpixel=True`` on the
|
|
1167
|
+
primitive helpers) are the preferred way to choose which shapes are smoothed.
|
|
1168
|
+
When this is None but some primitive carries an explicit flag, the factor is
|
|
1169
|
+
emitted with Mode "Staircase" and s = 16, so flagged primitives have a probe
|
|
1170
|
+
count and unflagged ones stay staircased. VoxelsModel arrays are never
|
|
1171
|
+
re-sampled.
|
|
704
1172
|
"""
|
|
705
1173
|
props = {
|
|
706
1174
|
"SimulationDomain": simulation_domain,
|
|
@@ -764,6 +1232,8 @@ def create_wavesim_properties(
|
|
|
764
1232
|
# Staircase. The service probes each voxel of primitives / STL / GDSII at
|
|
765
1233
|
# subpixel_factor points per axis and stores the mean permittivity; it does NOT
|
|
766
1234
|
# re-sample a VoxelsModel array (average that yourself before upload).
|
|
1235
|
+
# Mode is the default for primitives without an explicit "SubPixel" flag; flagged
|
|
1236
|
+
# primitives decide for themselves and use Factor as their probe count.
|
|
767
1237
|
if subpixel_factor is not None:
|
|
768
1238
|
s = int(subpixel_factor)
|
|
769
1239
|
if s < 1 or s > 64:
|
|
@@ -774,6 +1244,13 @@ def create_wavesim_properties(
|
|
|
774
1244
|
"Rule": "ArithmeticMean",
|
|
775
1245
|
"InterfaceOnly": True,
|
|
776
1246
|
}
|
|
1247
|
+
elif any(isinstance(p, dict) and "SubPixel" in p for p in (primitives or [])):
|
|
1248
|
+
props["PermittivitySampling"] = {
|
|
1249
|
+
"Mode": "Staircase",
|
|
1250
|
+
"Factor": 16,
|
|
1251
|
+
"Rule": "ArithmeticMean",
|
|
1252
|
+
"InterfaceOnly": True,
|
|
1253
|
+
}
|
|
777
1254
|
|
|
778
1255
|
return props
|
|
779
1256
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wavesimpro
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10.0
|
|
4
4
|
Summary: WavesimPro Python API — cloud execution client for the Rayfos simulation platform
|
|
5
5
|
Author: Rayfos
|
|
6
6
|
Project-URL: Repository, https://github.com/rayfos/wavesimpro
|
|
@@ -59,8 +59,15 @@ field = wp.read_binary_field(run.download("output.bin"))
|
|
|
59
59
|
|
|
60
60
|
## What the API covers
|
|
61
61
|
|
|
62
|
-
- Setup helpers for domains, media, primitives (box,
|
|
63
|
-
|
|
62
|
+
- Setup helpers for domains, media, primitives (box, sphere, ellipsoid, cylinder, cone,
|
|
63
|
+
N-sided prism, STL, GDSII layouts, voxel arrays), sources (point, plane wave, Gaussian beam,
|
|
64
|
+
custom field, custom-from-file, engine-solved waveguide mode) and monitors:
|
|
65
|
+
`create_box_primitive`, `create_sphere_primitive`, `create_ellipsoid_primitive`,
|
|
66
|
+
`create_cylinder_primitive`, `create_cone_primitive`, `create_prism_primitive`,
|
|
67
|
+
`create_stl_primitive`, `create_gds_primitive` (with `create_gds_layer_config` /
|
|
68
|
+
`create_gds_structure_override`), `create_voxels_model_primitive`.
|
|
69
|
+
- Per-primitive sub-pixel flag (`subpixel=True/False` on every shape, STL and GDSII helper)
|
|
70
|
+
to choose which shapes get smoothed interfaces.
|
|
64
71
|
- Per-axis pixel sizes (`pixel_size=[dx, dy, dz]`) and sub-pixel permittivity averaging
|
|
65
72
|
(`subpixel_factor=`), when the compute node supports them.
|
|
66
73
|
- Preflight memory check and cost estimate before a run.
|
|
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
|