wavesimpro 1.6.5__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.10.0/PKG-INFO +76 -0
- wavesimpro-1.10.0/README.md +53 -0
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/pyproject.toml +1 -1
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/src/wavesimpro/__init__.py +19 -1
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/src/wavesimpro/client.py +12 -2
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/src/wavesimpro/execute.py +51 -18
- wavesimpro-1.10.0/src/wavesimpro/json_helper.py +1336 -0
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/src/wavesimpro/simulate.py +11 -7
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/src/wavesimpro/validate.py +46 -21
- wavesimpro-1.10.0/src/wavesimpro.egg-info/PKG-INFO +76 -0
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/src/wavesimpro.egg-info/SOURCES.txt +1 -0
- wavesimpro-1.6.5/PKG-INFO +0 -22
- wavesimpro-1.6.5/src/wavesimpro/json_helper.py +0 -738
- wavesimpro-1.6.5/src/wavesimpro.egg-info/PKG-INFO +0 -22
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/setup.cfg +0 -0
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/src/wavesimpro/__main__.py +0 -0
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/src/wavesimpro/binary_utils.py +0 -0
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/src/wavesimpro/config.py +0 -0
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/src/wavesimpro/exceptions.py +0 -0
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/src/wavesimpro/py.typed +0 -0
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/src/wavesimpro/setup.py +0 -0
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/src/wavesimpro.egg-info/dependency_links.txt +0 -0
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/src/wavesimpro.egg-info/requires.txt +0 -0
- {wavesimpro-1.6.5 → wavesimpro-1.10.0}/src/wavesimpro.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wavesimpro
|
|
3
|
+
Version: 1.10.0
|
|
4
|
+
Summary: WavesimPro Python API — cloud execution client for the Rayfos simulation platform
|
|
5
|
+
Author: Rayfos
|
|
6
|
+
Project-URL: Repository, https://github.com/rayfos/wavesimpro
|
|
7
|
+
Keywords: wavesim,simulation,electromagnetic,rayfos,api
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering
|
|
13
|
+
Requires-Python: >=3.8
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: numpy>=1.20.0
|
|
16
|
+
Requires-Dist: requests>=2.28.0
|
|
17
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
18
|
+
Requires-Dist: tqdm>=4.60.0
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
21
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
22
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
23
|
+
|
|
24
|
+
# wavesimpro
|
|
25
|
+
|
|
26
|
+
Python client for the Rayfos Wavesim cloud: build a simulation setup, run it on a Rayfos
|
|
27
|
+
compute node, and read the results back as NumPy arrays.
|
|
28
|
+
|
|
29
|
+
Wavesim is a single-wavelength frequency-domain solver (vectorial Maxwell when a polarized
|
|
30
|
+
source is present, scalar Helmholtz otherwise). This package talks to the Rayfos JobServer
|
|
31
|
+
REST API; it does not contain the solver.
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install wavesimpro
|
|
37
|
+
python -m wavesimpro setup # one-time: API key + server URL wizard
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The wizard stores the credentials; `wavesimpro.configure(api_key=..., api_url=...)` sets
|
|
41
|
+
them for one process instead.
|
|
42
|
+
|
|
43
|
+
## Quick start
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import wavesimpro as wp
|
|
47
|
+
|
|
48
|
+
props = wp.create_wavesim_properties(
|
|
49
|
+
wavelength=1.0, pixel_size=0.1, boundary_width=5.0,
|
|
50
|
+
domain=wp.create_simulation_domain(20, 20, 20),
|
|
51
|
+
mediums=[wp.create_medium("Silicon", 3.48, 0.0)],
|
|
52
|
+
primitives=[wp.create_box_primitive("core", 0, 0, 0, 10, 0.5, 20, medium="Silicon")],
|
|
53
|
+
sources=[wp.create_mode_source("in", 0, 0, -8.0, polarization="X")],
|
|
54
|
+
monitors=[wp.create_monitor("out", 0, 0, 8.0, 10, 10, 0)],
|
|
55
|
+
)
|
|
56
|
+
run = wp.simulate(props, name="strip waveguide")
|
|
57
|
+
field = wp.read_binary_field(run.download("output.bin"))
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## What the API covers
|
|
61
|
+
|
|
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.
|
|
71
|
+
- Per-axis pixel sizes (`pixel_size=[dx, dy, dz]`) and sub-pixel permittivity averaging
|
|
72
|
+
(`subpixel_factor=`), when the compute node supports them.
|
|
73
|
+
- Preflight memory check and cost estimate before a run.
|
|
74
|
+
- Binary upload/download helpers for permittivity volumes, source fields and monitors.
|
|
75
|
+
|
|
76
|
+
See `CHANGELOG.md` for what each version added. Issues and feature requests: support@rayfos.com.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# wavesimpro
|
|
2
|
+
|
|
3
|
+
Python client for the Rayfos Wavesim cloud: build a simulation setup, run it on a Rayfos
|
|
4
|
+
compute node, and read the results back as NumPy arrays.
|
|
5
|
+
|
|
6
|
+
Wavesim is a single-wavelength frequency-domain solver (vectorial Maxwell when a polarized
|
|
7
|
+
source is present, scalar Helmholtz otherwise). This package talks to the Rayfos JobServer
|
|
8
|
+
REST API; it does not contain the solver.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pip install wavesimpro
|
|
14
|
+
python -m wavesimpro setup # one-time: API key + server URL wizard
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The wizard stores the credentials; `wavesimpro.configure(api_key=..., api_url=...)` sets
|
|
18
|
+
them for one process instead.
|
|
19
|
+
|
|
20
|
+
## Quick start
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import wavesimpro as wp
|
|
24
|
+
|
|
25
|
+
props = wp.create_wavesim_properties(
|
|
26
|
+
wavelength=1.0, pixel_size=0.1, boundary_width=5.0,
|
|
27
|
+
domain=wp.create_simulation_domain(20, 20, 20),
|
|
28
|
+
mediums=[wp.create_medium("Silicon", 3.48, 0.0)],
|
|
29
|
+
primitives=[wp.create_box_primitive("core", 0, 0, 0, 10, 0.5, 20, medium="Silicon")],
|
|
30
|
+
sources=[wp.create_mode_source("in", 0, 0, -8.0, polarization="X")],
|
|
31
|
+
monitors=[wp.create_monitor("out", 0, 0, 8.0, 10, 10, 0)],
|
|
32
|
+
)
|
|
33
|
+
run = wp.simulate(props, name="strip waveguide")
|
|
34
|
+
field = wp.read_binary_field(run.download("output.bin"))
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## What the API covers
|
|
38
|
+
|
|
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.
|
|
48
|
+
- Per-axis pixel sizes (`pixel_size=[dx, dy, dz]`) and sub-pixel permittivity averaging
|
|
49
|
+
(`subpixel_factor=`), when the compute node supports them.
|
|
50
|
+
- Preflight memory check and cost estimate before a run.
|
|
51
|
+
- Binary upload/download helpers for permittivity volumes, source fields and monitors.
|
|
52
|
+
|
|
53
|
+
See `CHANGELOG.md` for what each version added. Issues and feature requests: support@rayfos.com.
|
|
@@ -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,10 +33,19 @@ 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,
|
|
39
47
|
create_gaussian_beam_source,
|
|
48
|
+
create_mode_source,
|
|
40
49
|
create_voxels_model_primitive,
|
|
41
50
|
create_custom_field_source,
|
|
42
51
|
create_custom_from_file_source,
|
|
@@ -45,7 +54,7 @@ from .json_helper import (
|
|
|
45
54
|
parse_progress_data,
|
|
46
55
|
)
|
|
47
56
|
|
|
48
|
-
__version__ = "1.
|
|
57
|
+
__version__ = "1.10.0"
|
|
49
58
|
__all__ = [
|
|
50
59
|
# Client
|
|
51
60
|
"RayfosClient",
|
|
@@ -77,10 +86,19 @@ __all__ = [
|
|
|
77
86
|
"create_simulation_domain",
|
|
78
87
|
"create_stl_primitive",
|
|
79
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",
|
|
80
97
|
"create_medium",
|
|
81
98
|
"create_point_source",
|
|
82
99
|
"create_plane_wave_source",
|
|
83
100
|
"create_gaussian_beam_source",
|
|
101
|
+
"create_mode_source",
|
|
84
102
|
"create_voxels_model_primitive",
|
|
85
103
|
"create_custom_field_source",
|
|
86
104
|
"create_custom_from_file_source",
|
|
@@ -280,7 +280,7 @@ class RayfosClient:
|
|
|
280
280
|
def preflight_check(
|
|
281
281
|
self,
|
|
282
282
|
domain_um: tuple,
|
|
283
|
-
voxel_um
|
|
283
|
+
voxel_um, # float, or (dx, dy, dz) µm for a per-axis grid
|
|
284
284
|
boundary_sides_um: Sequence[Tuple[float, float]],
|
|
285
285
|
periodic: tuple = (False, False, False),
|
|
286
286
|
engine_preference: str = "Any",
|
|
@@ -329,6 +329,12 @@ class RayfosClient:
|
|
|
329
329
|
def _um(v: float) -> Dict[str, Any]:
|
|
330
330
|
return {"value": float(v), "unit": "Micrometers"}
|
|
331
331
|
|
|
332
|
+
voxels = (tuple(float(v) for v in voxel_um)
|
|
333
|
+
if isinstance(voxel_um, (list, tuple)) else (float(voxel_um),) * 3)
|
|
334
|
+
if len(voxels) != 3:
|
|
335
|
+
raise ValueError("voxel_um must be one number or (dx, dy, dz)")
|
|
336
|
+
anisotropic = any(abs(v - voxels[0]) > 1e-6 * max(voxels) for v in voxels)
|
|
337
|
+
|
|
332
338
|
body = {
|
|
333
339
|
"wavesimProperties": {
|
|
334
340
|
"simulationDomain": {
|
|
@@ -336,7 +342,11 @@ class RayfosClient:
|
|
|
336
342
|
"position": {"x": _um(0.0), "y": _um(0.0), "z": _um(0.0)},
|
|
337
343
|
"size": {"width": _um(size_x), "height": _um(size_y), "depth": _um(size_z)},
|
|
338
344
|
},
|
|
339
|
-
|
|
345
|
+
# voxelSize = the smallest axis (what scalar readers use); voxelSizes carries
|
|
346
|
+
# the per-axis pitch so the estimator sizes the grid the engine will pad.
|
|
347
|
+
"voxelSize": _um(min(voxels)),
|
|
348
|
+
**({"voxelSizes": {"x": _um(voxels[0]), "y": _um(voxels[1]), "z": _um(voxels[2])}}
|
|
349
|
+
if anisotropic else {}),
|
|
340
350
|
# boundarySize is the symmetric fallback older servers read; the
|
|
341
351
|
# per-side widths below are what the current estimator uses.
|
|
342
352
|
"boundarySize": _um(sides[0][0]),
|
|
@@ -92,11 +92,37 @@ def _normalize_boundary_widths(boundary_widths) -> Optional[List[Tuple[float, fl
|
|
|
92
92
|
return out
|
|
93
93
|
|
|
94
94
|
|
|
95
|
+
def pixel_sizes_um(pixel_size) -> Tuple[float, float, float]:
|
|
96
|
+
"""
|
|
97
|
+
Normalise a pixel size to a per-axis (dx, dy, dz) tuple in micrometres.
|
|
98
|
+
|
|
99
|
+
``pixel_size`` may be one number (isotropic, the usual case) or three
|
|
100
|
+
``[dx, dy, dz]`` (anisotropic: coarsen axes the field is band-limited along,
|
|
101
|
+
e.g. the transverse axes of a paraxial beam or a weakly guiding waveguide;
|
|
102
|
+
Python engine only). Every axis must be positive.
|
|
103
|
+
"""
|
|
104
|
+
if isinstance(pixel_size, (int, float, np.integer, np.floating)):
|
|
105
|
+
p = float(pixel_size)
|
|
106
|
+
return (p, p, p)
|
|
107
|
+
vals = tuple(float(v) for v in pixel_size)
|
|
108
|
+
if len(vals) != 3:
|
|
109
|
+
raise ValueError(f"pixel_size must be one number or [dx, dy, dz], got {pixel_size!r}")
|
|
110
|
+
if any(v <= 0 for v in vals):
|
|
111
|
+
raise ValueError(f"pixel_size components must be positive, got {vals}")
|
|
112
|
+
return vals # type: ignore[return-value]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def is_anisotropic(pixel_sizes: Sequence[float]) -> bool:
|
|
116
|
+
"""True when the three pitches differ beyond float round-off."""
|
|
117
|
+
m = max(pixel_sizes)
|
|
118
|
+
return any(abs(v - pixel_sizes[0]) > 1e-6 * m for v in pixel_sizes)
|
|
119
|
+
|
|
120
|
+
|
|
95
121
|
def execute_via_api(
|
|
96
122
|
refractive_index: np.ndarray,
|
|
97
123
|
source,
|
|
98
124
|
wavelength: float,
|
|
99
|
-
pixel_size
|
|
125
|
+
pixel_size, # float, or [dx, dy, dz] µm (see pixel_sizes_um)
|
|
100
126
|
threshold: float = 1e-2,
|
|
101
127
|
max_iterations: int = 1000,
|
|
102
128
|
boundary_width: Optional[float] = None, # in MICROMETERS; REQUIRED unless boundary_widths is given
|
|
@@ -134,7 +160,9 @@ def execute_via_api(
|
|
|
134
160
|
- dict with 'Es' (complex field array) and 'position' ([x,y,z] or [x,y,z,pol])
|
|
135
161
|
- list of such dicts for multiple sources
|
|
136
162
|
wavelength: Wavelength in micrometers
|
|
137
|
-
pixel_size: Pixel size in micrometers
|
|
163
|
+
pixel_size: Pixel size in micrometers — one number, or [dx, dy, dz] for a
|
|
164
|
+
per-axis grid (coarsen axes the field is band-limited along; Python
|
|
165
|
+
engine only, see pixel_sizes_um)
|
|
138
166
|
threshold: Convergence threshold (default: 1e-2)
|
|
139
167
|
max_iterations: Max iterations (default: 1000)
|
|
140
168
|
boundary_width: Absorbing boundary width in MICROMETERS (μm). Required —
|
|
@@ -248,13 +276,17 @@ def execute_via_api(
|
|
|
248
276
|
|
|
249
277
|
logger.info(f" Domain: [{nx}, {ny}, {nz}]")
|
|
250
278
|
logger.info(f" Wavelength: {wavelength:.3f} um")
|
|
251
|
-
|
|
279
|
+
ps = pixel_sizes_um(pixel_size)
|
|
280
|
+
anisotropic = is_anisotropic(ps)
|
|
281
|
+
ps_min = min(ps)
|
|
282
|
+
ps_label = f"({ps[0]:.4g}, {ps[1]:.4g}, {ps[2]:.4g})" if anisotropic else f"{ps[0]:.3f}"
|
|
283
|
+
logger.info(f" Pixel size: {ps_label} um")
|
|
252
284
|
logger.info(f" Threshold: {threshold:.2e}")
|
|
253
285
|
logger.info(f" Max iterations: {max_iterations}")
|
|
254
286
|
if pseudo_propagation_distance > 0:
|
|
255
287
|
logger.info(f" Pseudo propagation distance: {pseudo_propagation_distance} um (overrides max iterations)")
|
|
256
288
|
if boundary_sides_um is None:
|
|
257
|
-
logger.info(f" Boundary width: {boundary_width} um ({int(round(boundary_width /
|
|
289
|
+
logger.info(f" Boundary width: {boundary_width} um ({int(round(boundary_width / ps_min))} pixels on the finest axis)")
|
|
258
290
|
else:
|
|
259
291
|
logger.info(" Boundary widths (um): " + " ".join(
|
|
260
292
|
f"{ax}:[{left:g}, {right:g}]" for ax, (left, right) in zip("XYZ", boundary_sides_um)))
|
|
@@ -318,9 +350,9 @@ def execute_via_api(
|
|
|
318
350
|
|
|
319
351
|
# 5b. Preflight check — abort BEFORE creating a project / uploading anything
|
|
320
352
|
# if the simulation won't fit on the available compute targets.
|
|
321
|
-
domain_x_um = float(nx) *
|
|
322
|
-
domain_y_um = float(ny) *
|
|
323
|
-
domain_z_um = float(nz) *
|
|
353
|
+
domain_x_um = float(nx) * ps[0]
|
|
354
|
+
domain_y_um = float(ny) * ps[1]
|
|
355
|
+
domain_z_um = float(nz) * ps[2]
|
|
324
356
|
# The preflight describes exactly the grid the engine will pad: the same
|
|
325
357
|
# per-side boundary widths that go into the submitted properties.
|
|
326
358
|
preflight_sides_um = (boundary_sides_um if boundary_sides_um is not None
|
|
@@ -328,7 +360,7 @@ def execute_via_api(
|
|
|
328
360
|
try:
|
|
329
361
|
pre = client.preflight_check(
|
|
330
362
|
domain_um=(domain_x_um, domain_y_um, domain_z_um),
|
|
331
|
-
voxel_um=
|
|
363
|
+
voxel_um=ps,
|
|
332
364
|
boundary_sides_um=preflight_sides_um,
|
|
333
365
|
periodic=(bool(periodic[0]), bool(periodic[1]), bool(periodic[2])),
|
|
334
366
|
engine_preference=engine_preference,
|
|
@@ -379,7 +411,7 @@ def execute_via_api(
|
|
|
379
411
|
|
|
380
412
|
# 7. Validate parameters
|
|
381
413
|
validate_parameters(
|
|
382
|
-
em_data, sources_info, wavelength,
|
|
414
|
+
em_data, sources_info, wavelength, ps,
|
|
383
415
|
threshold, max_iterations, boundary_width, is_vectorial,
|
|
384
416
|
strict_validation=strict_validation,
|
|
385
417
|
gpu_memory_max_gb=gpu_memory_max_gb,
|
|
@@ -424,9 +456,9 @@ def execute_via_api(
|
|
|
424
456
|
|
|
425
457
|
# 10. Build WavesimProperties payload
|
|
426
458
|
logger.info("Building command payload...")
|
|
427
|
-
domain_x_um = float(nx) *
|
|
428
|
-
domain_y_um = float(ny) *
|
|
429
|
-
domain_z_um = float(nz) *
|
|
459
|
+
domain_x_um = float(nx) * ps[0]
|
|
460
|
+
domain_y_um = float(ny) * ps[1]
|
|
461
|
+
domain_z_um = float(nz) * ps[2]
|
|
430
462
|
|
|
431
463
|
simulation_domain = create_simulation_domain(domain_x_um, domain_y_um, domain_z_um)
|
|
432
464
|
background_medium = create_medium("background", "Background", background_ri)
|
|
@@ -435,7 +467,7 @@ def execute_via_api(
|
|
|
435
467
|
voxel_primitive = create_voxels_model_primitive(
|
|
436
468
|
primitive_name, em_data_id, "background",
|
|
437
469
|
0.0, 0.0, 0.0,
|
|
438
|
-
|
|
470
|
+
ps[0], ps[1], ps[2],
|
|
439
471
|
int(nx), int(ny), int(nz),
|
|
440
472
|
"Complex64", data_type,
|
|
441
473
|
)
|
|
@@ -459,9 +491,9 @@ def execute_via_api(
|
|
|
459
491
|
# centre, world 0,0,0). Keeping every client emitting the same shape
|
|
460
492
|
# of WavesimProperties means the server has one coordinate path, not
|
|
461
493
|
# one per client.
|
|
462
|
-
src_extent_x = float(src_nx) *
|
|
463
|
-
src_extent_y = float(src_ny) *
|
|
464
|
-
src_extent_z = float(src_nz) *
|
|
494
|
+
src_extent_x = float(src_nx) * ps[0]
|
|
495
|
+
src_extent_y = float(src_ny) * ps[1]
|
|
496
|
+
src_extent_z = float(src_nz) * ps[2]
|
|
465
497
|
position_x_centered = float(src["position"][0]) + src_extent_x / 2.0 - domain_x_um / 2.0
|
|
466
498
|
position_y_centered = float(src["position"][1]) + src_extent_y / 2.0 - domain_y_um / 2.0
|
|
467
499
|
position_z_centered = float(src["position"][2]) + src_extent_z / 2.0 - domain_z_um / 2.0
|
|
@@ -493,7 +525,8 @@ def execute_via_api(
|
|
|
493
525
|
monitors=monitors or [],
|
|
494
526
|
background_medium_id="background",
|
|
495
527
|
wavelength=float(wavelength),
|
|
496
|
-
voxel_size=
|
|
528
|
+
voxel_size=ps_min, # smallest axis: scalar readers over-resolve
|
|
529
|
+
voxel_sizes=list(ps) if anisotropic else None, # per-axis pitch, Python engine only
|
|
497
530
|
boundary_size_um=boundary_size_um,
|
|
498
531
|
boundary_sides_um=boundary_sides_um,
|
|
499
532
|
boundary_strength=boundary_strength,
|
|
@@ -534,7 +567,7 @@ def execute_via_api(
|
|
|
534
567
|
print(f" Version : {version_id}")
|
|
535
568
|
print(f" Command : {command_id}")
|
|
536
569
|
print(f" Mode : {_mode}")
|
|
537
|
-
print(f" Domain : {_domain_str} lambda={wavelength} um dx={
|
|
570
|
+
print(f" Domain : {_domain_str} lambda={wavelength} um dx={ps_label} um")
|
|
538
571
|
print(f" Engine : {_engine} | GPU: {_gpu}")
|
|
539
572
|
if preferred_machine_id:
|
|
540
573
|
print(f" Machine : {preferred_machine_id}")
|