gsim 0.0.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.0.0/PKG-INFO +128 -0
- gsim-0.0.0/README.md +82 -0
- gsim-0.0.0/pyproject.toml +217 -0
- gsim-0.0.0/setup.cfg +4 -0
- gsim-0.0.0/src/gsim/__init__.py +16 -0
- gsim-0.0.0/src/gsim/gcloud.py +169 -0
- gsim-0.0.0/src/gsim/palace/__init__.py +120 -0
- gsim-0.0.0/src/gsim/palace/mesh/__init__.py +50 -0
- gsim-0.0.0/src/gsim/palace/mesh/generator.py +956 -0
- gsim-0.0.0/src/gsim/palace/mesh/gmsh_utils.py +484 -0
- gsim-0.0.0/src/gsim/palace/mesh/pipeline.py +188 -0
- gsim-0.0.0/src/gsim/palace/ports/__init__.py +35 -0
- gsim-0.0.0/src/gsim/palace/ports/config.py +363 -0
- gsim-0.0.0/src/gsim/palace/stack/__init__.py +149 -0
- gsim-0.0.0/src/gsim/palace/stack/extractor.py +602 -0
- gsim-0.0.0/src/gsim/palace/stack/materials.py +161 -0
- gsim-0.0.0/src/gsim/palace/stack/visualization.py +630 -0
- gsim-0.0.0/src/gsim/viz.py +86 -0
- gsim-0.0.0/src/gsim.egg-info/PKG-INFO +128 -0
- gsim-0.0.0/src/gsim.egg-info/SOURCES.txt +22 -0
- gsim-0.0.0/src/gsim.egg-info/dependency_links.txt +1 -0
- gsim-0.0.0/src/gsim.egg-info/requires.txt +37 -0
- gsim-0.0.0/src/gsim.egg-info/top_level.txt +1 -0
- gsim-0.0.0/tests/test_gsim.py +155 -0
gsim-0.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gsim
|
|
3
|
+
Version: 0.0.0
|
|
4
|
+
Author-email: flaport <floris.laporte@gmail.com>
|
|
5
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
6
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
7
|
+
Classifier: Operating System :: OS Independent
|
|
8
|
+
Requires-Python: <3.14,>=3.12
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: gdsfactory>=8.32.2
|
|
11
|
+
Requires-Dist: gdsfactoryplus>=1.3.7
|
|
12
|
+
Requires-Dist: gmsh
|
|
13
|
+
Requires-Dist: meshio>=5.0.0
|
|
14
|
+
Requires-Dist: plotly
|
|
15
|
+
Requires-Dist: pydantic>=2.10.6
|
|
16
|
+
Requires-Dist: pyvista>=0.43.0
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: altair>=5.5.0; extra == "dev"
|
|
19
|
+
Requires-Dist: build>=1.2.0; extra == "dev"
|
|
20
|
+
Requires-Dist: griffe>=1.5.6; extra == "dev"
|
|
21
|
+
Requires-Dist: ipykernel>=6.29.5; extra == "dev"
|
|
22
|
+
Requires-Dist: matplotlib>=3.10.0; extra == "dev"
|
|
23
|
+
Requires-Dist: mkautodoc>=0.2.0; extra == "dev"
|
|
24
|
+
Requires-Dist: mkdocs-autorefs>=1.3.0; extra == "dev"
|
|
25
|
+
Requires-Dist: mkdocs-material>=9.6.0; extra == "dev"
|
|
26
|
+
Requires-Dist: mkdocs-shadcn>=0.2; extra == "dev"
|
|
27
|
+
Requires-Dist: mkdocs>=1.6.1; extra == "dev"
|
|
28
|
+
Requires-Dist: mkdocstrings[python]>=0.27.0; extra == "dev"
|
|
29
|
+
Requires-Dist: mkinit>=1.1.0; extra == "dev"
|
|
30
|
+
Requires-Dist: mypy>=1.15.0; extra == "dev"
|
|
31
|
+
Requires-Dist: nb-clean>=4.0.1; extra == "dev"
|
|
32
|
+
Requires-Dist: nbconvert>=7.16.6; extra == "dev"
|
|
33
|
+
Requires-Dist: papermill>=2.6.0; extra == "dev"
|
|
34
|
+
Requires-Dist: plotly>=6.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pre-commit>=4.1.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pyright>=1.1.0; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-cov>=6.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-randomly>=3.16.0; extra == "dev"
|
|
39
|
+
Requires-Dist: pytest-xdist>=3.6.0; extra == "dev"
|
|
40
|
+
Requires-Dist: pytest>=8.3.0; extra == "dev"
|
|
41
|
+
Requires-Dist: ruff>=0.9.0; extra == "dev"
|
|
42
|
+
Requires-Dist: towncrier>=24.0.0; extra == "dev"
|
|
43
|
+
Requires-Dist: vega-datasets>=0.9.0; extra == "dev"
|
|
44
|
+
Requires-Dist: nbstripout>=0.8.1; extra == "dev"
|
|
45
|
+
Requires-Dist: ty>=0.0.13; extra == "dev"
|
|
46
|
+
|
|
47
|
+
# Gsim 0.0.0
|
|
48
|
+
|
|
49
|
+
> a GDSFactory Simulation Plugin
|
|
50
|
+
|
|
51
|
+

|
|
52
|
+
|
|
53
|
+
## Overview
|
|
54
|
+
|
|
55
|
+
Gsim bridges the gap between circuit layout design (using [GDSFactory](https://gdsfactory.github.io/gdsfactory/)) and electromagnetic simulation (using [Palace](https://awslabs.github.io/palace/)). It automates the conversion of IC component layouts into simulation-ready mesh files and configuration.
|
|
56
|
+
|
|
57
|
+
## Features
|
|
58
|
+
|
|
59
|
+
- **Layer Stack Extraction**: Extract layer stacks from PDK definitions with a comprehensive material properties database
|
|
60
|
+
- **Port Configuration**: Convert GDSFactory ports into Palace-compatible port definitions (inplane, via, and CPW ports)
|
|
61
|
+
- **Mesh Generation**: Generate GMSH-compatible finite element meshes with configurable quality presets
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pip install gsim
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
For development:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
git clone https://github.com/doplaydo/gsim
|
|
73
|
+
cd gsim
|
|
74
|
+
pip install -e .[dev]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Quick Start
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from gsim.palace import (
|
|
81
|
+
get_stack,
|
|
82
|
+
configure_inplane_port,
|
|
83
|
+
extract_ports,
|
|
84
|
+
generate_mesh,
|
|
85
|
+
MeshConfig,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Get layer stack from active PDK
|
|
89
|
+
stack = get_stack()
|
|
90
|
+
|
|
91
|
+
# Configure ports on your component
|
|
92
|
+
configure_inplane_port(c.ports["o1"], layer="topmetal2", length=5.0)
|
|
93
|
+
configure_inplane_port(c.ports["o2"], layer="topmetal2", length=5.0)
|
|
94
|
+
|
|
95
|
+
# Extract configured ports
|
|
96
|
+
ports = extract_ports(c, stack)
|
|
97
|
+
|
|
98
|
+
# Generate mesh
|
|
99
|
+
result = generate_mesh(
|
|
100
|
+
component=c,
|
|
101
|
+
stack=stack,
|
|
102
|
+
ports=ports,
|
|
103
|
+
output_dir="./simulation",
|
|
104
|
+
config=MeshConfig.default(),
|
|
105
|
+
)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Mesh Presets
|
|
109
|
+
|
|
110
|
+
| Preset | Refined Size | Max Size | Use Case |
|
|
111
|
+
| ------- | ------------ | -------- | --------------------------------- |
|
|
112
|
+
| Coarse | 10.0 µm | 600.0 µm | Fast iteration (~2.5 elements/λ) |
|
|
113
|
+
| Default | 5.0 µm | 300.0 µm | Balanced accuracy (~5 elements/λ) |
|
|
114
|
+
| Fine | 2.0 µm | 70.0 µm | High accuracy (~10 elements/λ) |
|
|
115
|
+
|
|
116
|
+
## Port Types
|
|
117
|
+
|
|
118
|
+
- **Inplane ports**: Horizontal ports on single metal layer for CPW gaps
|
|
119
|
+
- **Via ports**: Vertical ports between two metal layers for microstrip structures
|
|
120
|
+
- **CPW ports**: Multi-element ports for proper Coplanar Waveguide excitation
|
|
121
|
+
|
|
122
|
+
## Documentation
|
|
123
|
+
|
|
124
|
+
See the [documentation](https://doplaydo.github.io/gsim/) for detailed API reference and examples.
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
Copyright 2026 GDSFactory
|
gsim-0.0.0/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Gsim 0.0.0
|
|
2
|
+
|
|
3
|
+
> a GDSFactory Simulation Plugin
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Gsim bridges the gap between circuit layout design (using [GDSFactory](https://gdsfactory.github.io/gdsfactory/)) and electromagnetic simulation (using [Palace](https://awslabs.github.io/palace/)). It automates the conversion of IC component layouts into simulation-ready mesh files and configuration.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Layer Stack Extraction**: Extract layer stacks from PDK definitions with a comprehensive material properties database
|
|
14
|
+
- **Port Configuration**: Convert GDSFactory ports into Palace-compatible port definitions (inplane, via, and CPW ports)
|
|
15
|
+
- **Mesh Generation**: Generate GMSH-compatible finite element meshes with configurable quality presets
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install gsim
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
For development:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
git clone https://github.com/doplaydo/gsim
|
|
27
|
+
cd gsim
|
|
28
|
+
pip install -e .[dev]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from gsim.palace import (
|
|
35
|
+
get_stack,
|
|
36
|
+
configure_inplane_port,
|
|
37
|
+
extract_ports,
|
|
38
|
+
generate_mesh,
|
|
39
|
+
MeshConfig,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Get layer stack from active PDK
|
|
43
|
+
stack = get_stack()
|
|
44
|
+
|
|
45
|
+
# Configure ports on your component
|
|
46
|
+
configure_inplane_port(c.ports["o1"], layer="topmetal2", length=5.0)
|
|
47
|
+
configure_inplane_port(c.ports["o2"], layer="topmetal2", length=5.0)
|
|
48
|
+
|
|
49
|
+
# Extract configured ports
|
|
50
|
+
ports = extract_ports(c, stack)
|
|
51
|
+
|
|
52
|
+
# Generate mesh
|
|
53
|
+
result = generate_mesh(
|
|
54
|
+
component=c,
|
|
55
|
+
stack=stack,
|
|
56
|
+
ports=ports,
|
|
57
|
+
output_dir="./simulation",
|
|
58
|
+
config=MeshConfig.default(),
|
|
59
|
+
)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Mesh Presets
|
|
63
|
+
|
|
64
|
+
| Preset | Refined Size | Max Size | Use Case |
|
|
65
|
+
| ------- | ------------ | -------- | --------------------------------- |
|
|
66
|
+
| Coarse | 10.0 µm | 600.0 µm | Fast iteration (~2.5 elements/λ) |
|
|
67
|
+
| Default | 5.0 µm | 300.0 µm | Balanced accuracy (~5 elements/λ) |
|
|
68
|
+
| Fine | 2.0 µm | 70.0 µm | High accuracy (~10 elements/λ) |
|
|
69
|
+
|
|
70
|
+
## Port Types
|
|
71
|
+
|
|
72
|
+
- **Inplane ports**: Horizontal ports on single metal layer for CPW gaps
|
|
73
|
+
- **Via ports**: Vertical ports between two metal layers for microstrip structures
|
|
74
|
+
- **CPW ports**: Multi-element ports for proper Coplanar Waveguide excitation
|
|
75
|
+
|
|
76
|
+
## Documentation
|
|
77
|
+
|
|
78
|
+
See the [documentation](https://doplaydo.github.io/gsim/) for detailed API reference and examples.
|
|
79
|
+
|
|
80
|
+
## License
|
|
81
|
+
|
|
82
|
+
Copyright 2026 GDSFactory
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
build-backend = "setuptools.build_meta"
|
|
3
|
+
requires = ["setuptools>=61", "uv", "build", "wheel"]
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
authors = [{name = "flaport", email = "floris.laporte@gmail.com"}]
|
|
7
|
+
classifiers = [
|
|
8
|
+
"Programming Language :: Python :: 3.12",
|
|
9
|
+
"Programming Language :: Python :: 3.13",
|
|
10
|
+
"Operating System :: OS Independent"
|
|
11
|
+
]
|
|
12
|
+
dependencies = [
|
|
13
|
+
"gdsfactory>=8.32.2",
|
|
14
|
+
"gdsfactoryplus>=1.3.7",
|
|
15
|
+
"gmsh",
|
|
16
|
+
"meshio>=5.0.0",
|
|
17
|
+
"plotly",
|
|
18
|
+
"pydantic>=2.10.6",
|
|
19
|
+
"pyvista>=0.43.0"
|
|
20
|
+
]
|
|
21
|
+
description = ""
|
|
22
|
+
name = "gsim"
|
|
23
|
+
readme = "README.md"
|
|
24
|
+
requires-python = ">=3.12,<3.14"
|
|
25
|
+
version = "0.0.0"
|
|
26
|
+
|
|
27
|
+
[project.optional-dependencies]
|
|
28
|
+
dev = [
|
|
29
|
+
"altair>=5.5.0",
|
|
30
|
+
"build>=1.2.0",
|
|
31
|
+
"griffe>=1.5.6",
|
|
32
|
+
"ipykernel>=6.29.5",
|
|
33
|
+
"matplotlib>=3.10.0",
|
|
34
|
+
"mkautodoc>=0.2.0",
|
|
35
|
+
"mkdocs-autorefs>=1.3.0",
|
|
36
|
+
"mkdocs-material>=9.6.0",
|
|
37
|
+
"mkdocs-shadcn>=0.2",
|
|
38
|
+
"mkdocs>=1.6.1",
|
|
39
|
+
"mkdocstrings[python]>=0.27.0",
|
|
40
|
+
"mkinit>=1.1.0",
|
|
41
|
+
"mypy>=1.15.0",
|
|
42
|
+
"nb-clean>=4.0.1",
|
|
43
|
+
"nbconvert>=7.16.6",
|
|
44
|
+
"papermill>=2.6.0",
|
|
45
|
+
"plotly>=6.0.0",
|
|
46
|
+
"pre-commit>=4.1.0",
|
|
47
|
+
"pyright>=1.1.0",
|
|
48
|
+
"pytest-cov>=6.0.0",
|
|
49
|
+
"pytest-randomly>=3.16.0",
|
|
50
|
+
"pytest-xdist>=3.6.0",
|
|
51
|
+
"pytest>=8.3.0",
|
|
52
|
+
"ruff>=0.9.0",
|
|
53
|
+
"towncrier>=24.0.0",
|
|
54
|
+
"vega-datasets>=0.9.0",
|
|
55
|
+
"nbstripout>=0.8.1",
|
|
56
|
+
"ty>=0.0.13"
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
[[tool.bver.file]]
|
|
60
|
+
src = "README.md"
|
|
61
|
+
|
|
62
|
+
[[tool.bver.file]]
|
|
63
|
+
src = "pyproject.toml"
|
|
64
|
+
|
|
65
|
+
[[tool.bver.file]]
|
|
66
|
+
src = "src/gsim/__init__.py"
|
|
67
|
+
|
|
68
|
+
[tool.mypy]
|
|
69
|
+
mypy_path = ["src"]
|
|
70
|
+
python_version = "3.12"
|
|
71
|
+
strict = true
|
|
72
|
+
|
|
73
|
+
[[tool.mypy.overrides]]
|
|
74
|
+
implicit_reexport = true
|
|
75
|
+
module = "gsim"
|
|
76
|
+
|
|
77
|
+
[[tool.mypy.overrides]]
|
|
78
|
+
check_untyped_defs = false
|
|
79
|
+
disable_error_code = ["no-untyped-def", "no-untyped-call", "var-annotated", "assignment"]
|
|
80
|
+
disallow_any_generics = false
|
|
81
|
+
disallow_untyped_defs = false
|
|
82
|
+
# The Palace subpackage is still evolving and uses optional dependencies
|
|
83
|
+
# (e.g., gmsh, plotly). Keep mypy strict overall, but relax it here so
|
|
84
|
+
# contributors aren't blocked by large refactors during early development.
|
|
85
|
+
module = "gsim.palace.*"
|
|
86
|
+
warn_return_any = false
|
|
87
|
+
|
|
88
|
+
[[tool.mypy.overrides]]
|
|
89
|
+
ignore_errors = true
|
|
90
|
+
module = "tests.*"
|
|
91
|
+
|
|
92
|
+
[[tool.mypy.overrides]]
|
|
93
|
+
ignore_missing_imports = true
|
|
94
|
+
module = "gmsh"
|
|
95
|
+
|
|
96
|
+
[[tool.mypy.overrides]]
|
|
97
|
+
ignore_missing_imports = true
|
|
98
|
+
module = "gmsh.*"
|
|
99
|
+
|
|
100
|
+
[[tool.mypy.overrides]]
|
|
101
|
+
ignore_missing_imports = true
|
|
102
|
+
module = "plotly"
|
|
103
|
+
|
|
104
|
+
[[tool.mypy.overrides]]
|
|
105
|
+
ignore_missing_imports = true
|
|
106
|
+
module = "plotly.*"
|
|
107
|
+
|
|
108
|
+
[tool.pylsp-mypy]
|
|
109
|
+
enabled = true
|
|
110
|
+
live_mode = true
|
|
111
|
+
strict = true
|
|
112
|
+
|
|
113
|
+
[tool.pyright]
|
|
114
|
+
exclude = ["tests", "**/__pycache__", "**/.venv"]
|
|
115
|
+
include = ["src"]
|
|
116
|
+
pythonVersion = "3.12"
|
|
117
|
+
reportMissingImports = "none"
|
|
118
|
+
reportMissingTypeStubs = "none"
|
|
119
|
+
|
|
120
|
+
[tool.pytest.ini_options]
|
|
121
|
+
addopts = '--tb=short'
|
|
122
|
+
norecursedirs = ["scripts"]
|
|
123
|
+
testpaths = ["tests"]
|
|
124
|
+
|
|
125
|
+
[tool.ruff]
|
|
126
|
+
fix = true
|
|
127
|
+
target-version = "py312"
|
|
128
|
+
|
|
129
|
+
[tool.ruff.format]
|
|
130
|
+
docstring-code-format = true
|
|
131
|
+
|
|
132
|
+
[tool.ruff.lint] # see https://docs.astral.sh/ruff/rules
|
|
133
|
+
ignore = [
|
|
134
|
+
"ANN", # flake8-annotations (too noisy for evolving API)
|
|
135
|
+
"BLE001", # blind exception (common around optional deps / wrappers)
|
|
136
|
+
"C408", # unnecessary-collection-call
|
|
137
|
+
"C901", # complex-structure
|
|
138
|
+
"COM812", # missing-trailing-comma
|
|
139
|
+
"D417", # undocumented-param (google convention is strict here)
|
|
140
|
+
"D105", # undocumented-magic-method
|
|
141
|
+
"EM101", # exception-must-not-use-string-literal
|
|
142
|
+
"EM102", # exception-must-not-use-f-string-literal
|
|
143
|
+
"E741", # ambiguous-variable-name
|
|
144
|
+
"ERA001", # commented-out-code
|
|
145
|
+
"FBT", # boolean-trap (fine for public API, use keywords in docs/examples)
|
|
146
|
+
"FIX001", # line-contains-fixme
|
|
147
|
+
"FIX002", # line-contains-todo
|
|
148
|
+
"FIX004", # line-contains-hack
|
|
149
|
+
"N803", # invalid-argument-name
|
|
150
|
+
"N806", # non-lowercase-variable-in-function
|
|
151
|
+
"PLC0414", # useless-import-alias
|
|
152
|
+
"PLR", # pylint refactor (too strict for this codebase right now)
|
|
153
|
+
"PLR0913", # too-many-arguments
|
|
154
|
+
"PLR2004", # magic-value-comparison
|
|
155
|
+
"PLW2901", # redefined-loop-name
|
|
156
|
+
"PTH123", # Path.open preferred
|
|
157
|
+
"S110", # try-except-pass
|
|
158
|
+
"RET504", # unnecessary-assign
|
|
159
|
+
"S324", # hashlib-insecure-hash-function
|
|
160
|
+
"TC001", # typing-only-first-party-import
|
|
161
|
+
"TC002", # typing-only-third-party-import
|
|
162
|
+
"TC003", # typing-only-standard-library-import
|
|
163
|
+
"TC006", # runtime-cast-value
|
|
164
|
+
"TD001", # invalid-todo-tag
|
|
165
|
+
"TD002", # missing-todo-author
|
|
166
|
+
"TD003", # missing-todo-link
|
|
167
|
+
"TID252", # relative-imports
|
|
168
|
+
"TRY003" # raise-vanilla-args
|
|
169
|
+
]
|
|
170
|
+
select = ["ALL"]
|
|
171
|
+
|
|
172
|
+
[tool.ruff.lint.per-file-ignores]
|
|
173
|
+
"*.ipynb" = [
|
|
174
|
+
"ANN", # flake8-annotations
|
|
175
|
+
"ARG001", # unused-function-argument
|
|
176
|
+
"D", # pydocstyle
|
|
177
|
+
"E402", # module-import-not-at-top-of-file
|
|
178
|
+
"E501", # line-too-long
|
|
179
|
+
"F821", # undefined-name
|
|
180
|
+
"FBT003", # boolean-positional-value-in-call
|
|
181
|
+
"N816", # mixed-case-variable-in-global-scope
|
|
182
|
+
"NPY", # numpy (allow legacy RNG calls in notebooks)
|
|
183
|
+
"PLC2401", # non-ascii-name
|
|
184
|
+
"S101", # assert
|
|
185
|
+
"SLF001", # private-member-access
|
|
186
|
+
"T201" # print
|
|
187
|
+
]
|
|
188
|
+
"scripts/*.py" = [
|
|
189
|
+
"ANN", # flake8-annotations
|
|
190
|
+
"ARG001", # unused-function-argument
|
|
191
|
+
"D", # pydocstyle
|
|
192
|
+
"E402", # module-import-not-at-top-of-file
|
|
193
|
+
"E501", # line-too-long
|
|
194
|
+
"F821", # undefined-name
|
|
195
|
+
"FBT003", # boolean-positional-value-in-call
|
|
196
|
+
"INP001", # implicit-namespace-package
|
|
197
|
+
"N816", # mixed-case-variable-in-global-scope
|
|
198
|
+
"PLC2401", # non-ascii-name
|
|
199
|
+
"S101", # assert
|
|
200
|
+
"SLF001", # private-member-access
|
|
201
|
+
"T201" # print
|
|
202
|
+
]
|
|
203
|
+
"tests/**/*.py" = [
|
|
204
|
+
"ANN", # flake8-annotations
|
|
205
|
+
"D", # pydocstyle
|
|
206
|
+
"INP001", # implicit-namespace-package
|
|
207
|
+
"PLC0415", # allow imports inside tests
|
|
208
|
+
"PT011", # pytest-raises-too-broad
|
|
209
|
+
"S101", # assert
|
|
210
|
+
"T201" # print
|
|
211
|
+
]
|
|
212
|
+
|
|
213
|
+
[tool.ruff.lint.pydocstyle]
|
|
214
|
+
convention = "google"
|
|
215
|
+
|
|
216
|
+
[tool.setuptools.packages.find]
|
|
217
|
+
where = ["src"]
|
gsim-0.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""GSIM - GDSFactory+ Simulation Tools.
|
|
2
|
+
|
|
3
|
+
This package provides APIs and client SDKs for accessing simulation tools
|
|
4
|
+
of gdsfactory+.
|
|
5
|
+
|
|
6
|
+
Currently includes:
|
|
7
|
+
- palace: Palace EM simulation API
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
__version__ = "0.0.0"
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"__version__",
|
|
16
|
+
]
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""GDSFactory+ cloud simulation interface.
|
|
2
|
+
|
|
3
|
+
This module provides an interface to run simulations on
|
|
4
|
+
the GDSFactory+ cloud infrastructure.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from gsim import gcloud
|
|
8
|
+
|
|
9
|
+
# Run simulation (uploads, starts, waits, downloads)
|
|
10
|
+
results = gcloud.run_simulation("./sim", job_type="palace")
|
|
11
|
+
|
|
12
|
+
# Or use solver-specific wrappers:
|
|
13
|
+
from gsim import palace as pa
|
|
14
|
+
results = pa.run_simulation("./sim")
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import zipfile
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import TYPE_CHECKING
|
|
22
|
+
|
|
23
|
+
from gdsfactoryplus import sim # type: ignore[import-untyped]
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
from collections.abc import Callable
|
|
27
|
+
from typing import Literal
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _get_job_definition(job_type: str):
|
|
31
|
+
"""Get JobDefinition enum value by name."""
|
|
32
|
+
job_type_upper = job_type.upper()
|
|
33
|
+
if not hasattr(sim.JobDefinition, job_type_upper):
|
|
34
|
+
valid = [e.name for e in sim.JobDefinition]
|
|
35
|
+
raise ValueError(f"Unknown job type '{job_type}'. Valid types: {valid}")
|
|
36
|
+
return getattr(sim.JobDefinition, job_type_upper)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def upload_simulation_dir(input_dir: str | Path, job_type: str):
|
|
40
|
+
"""Zip all files in a directory and upload for simulation.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
input_dir: Directory containing simulation files
|
|
44
|
+
job_type: Simulation type (e.g., "palace")
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
PreJob object from gdsfactoryplus
|
|
48
|
+
"""
|
|
49
|
+
input_dir = Path(input_dir)
|
|
50
|
+
zip_path = Path("_gsim_upload.zip")
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_STORED) as zf:
|
|
54
|
+
for file in input_dir.rglob("*"):
|
|
55
|
+
if file.is_file():
|
|
56
|
+
zf.write(file, arcname=file.relative_to(input_dir))
|
|
57
|
+
|
|
58
|
+
job_definition = _get_job_definition(job_type)
|
|
59
|
+
pre_job = sim.upload_simulation(path=zip_path, job_definition=job_definition)
|
|
60
|
+
finally:
|
|
61
|
+
if zip_path.exists():
|
|
62
|
+
zip_path.unlink()
|
|
63
|
+
|
|
64
|
+
return pre_job
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def run_simulation(
|
|
68
|
+
output_dir: str | Path,
|
|
69
|
+
job_type: Literal["palace"] = "palace",
|
|
70
|
+
verbose: bool = True,
|
|
71
|
+
on_started: Callable | None = None,
|
|
72
|
+
) -> dict[str, Path]:
|
|
73
|
+
"""Run a simulation on GDSFactory+ cloud.
|
|
74
|
+
|
|
75
|
+
This function handles the complete workflow:
|
|
76
|
+
1. Uploads simulation files
|
|
77
|
+
2. Starts the simulation job
|
|
78
|
+
3. Waits for completion
|
|
79
|
+
4. Downloads results
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
output_dir: Directory containing the simulation files
|
|
83
|
+
job_type: Type of simulation (default: "palace")
|
|
84
|
+
verbose: Print progress messages (default True)
|
|
85
|
+
on_started: Optional callback called with job object when simulation starts
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Dict mapping result filename to local Path.
|
|
89
|
+
|
|
90
|
+
Raises:
|
|
91
|
+
RuntimeError: If simulation fails
|
|
92
|
+
|
|
93
|
+
Example:
|
|
94
|
+
>>> results = gcloud.run_simulation("./sim", job_type="palace")
|
|
95
|
+
Uploading simulation... done
|
|
96
|
+
Job started: palace-abc123
|
|
97
|
+
Waiting for completion... done (2m 34s)
|
|
98
|
+
Downloading results... done
|
|
99
|
+
"""
|
|
100
|
+
output_dir = Path(output_dir)
|
|
101
|
+
|
|
102
|
+
if not output_dir.exists():
|
|
103
|
+
raise FileNotFoundError(f"Output directory not found: {output_dir}")
|
|
104
|
+
|
|
105
|
+
# Upload
|
|
106
|
+
if verbose:
|
|
107
|
+
print("Uploading simulation... ", end="", flush=True) # noqa: T201
|
|
108
|
+
|
|
109
|
+
pre_job = upload_simulation_dir(output_dir, job_type)
|
|
110
|
+
|
|
111
|
+
if verbose:
|
|
112
|
+
print("done") # noqa: T201
|
|
113
|
+
|
|
114
|
+
# Start
|
|
115
|
+
job = sim.start_simulation(pre_job)
|
|
116
|
+
|
|
117
|
+
if verbose:
|
|
118
|
+
print(f"Job started: {job.job_name}") # noqa: T201
|
|
119
|
+
|
|
120
|
+
if on_started:
|
|
121
|
+
on_started(job)
|
|
122
|
+
|
|
123
|
+
# Wait
|
|
124
|
+
finished_job = sim.wait_for_simulation(job)
|
|
125
|
+
|
|
126
|
+
# Check status
|
|
127
|
+
if finished_job.exit_code != 0:
|
|
128
|
+
raise RuntimeError(
|
|
129
|
+
f"Simulation failed with exit code {finished_job.exit_code}. "
|
|
130
|
+
f"Status: {finished_job.status.value}"
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Download
|
|
134
|
+
results = sim.download_results(finished_job)
|
|
135
|
+
|
|
136
|
+
if verbose and results:
|
|
137
|
+
first_path = next(iter(results.values()))
|
|
138
|
+
download_dir = first_path.parent
|
|
139
|
+
print(f"Downloaded {len(results)} files to {download_dir}") # noqa: T201
|
|
140
|
+
|
|
141
|
+
return results
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def print_job_summary(job) -> None:
|
|
145
|
+
"""Print a formatted summary of a simulation job.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
job: Job object from gdsfactoryplus
|
|
149
|
+
"""
|
|
150
|
+
if job.started_at and job.finished_at:
|
|
151
|
+
delta = job.finished_at - job.started_at
|
|
152
|
+
minutes, seconds = divmod(int(delta.total_seconds()), 60)
|
|
153
|
+
duration = f"{minutes}m {seconds}s"
|
|
154
|
+
else:
|
|
155
|
+
duration = "N/A"
|
|
156
|
+
|
|
157
|
+
size_kb = job.output_size_bytes / 1024
|
|
158
|
+
size_str = f"{size_kb:.1f} KB" if size_kb < 1024 else f"{size_kb / 1024:.2f} MB"
|
|
159
|
+
files = list(job.download_urls.keys()) if job.download_urls else []
|
|
160
|
+
|
|
161
|
+
print(f"{'Job:':<12} {job.job_name}") # noqa: T201
|
|
162
|
+
print(f"{'Status:':<12} {job.status.value} (exit {job.exit_code})") # noqa: T201
|
|
163
|
+
print(f"{'Duration:':<12} {duration}") # noqa: T201
|
|
164
|
+
mem_gb = job.requested_memory_mb // 1024
|
|
165
|
+
print(f"{'Resources:':<12} {job.requested_cpu} CPU / {mem_gb} GB") # noqa: T201
|
|
166
|
+
print(f"{'Output:':<12} {size_str}") # noqa: T201
|
|
167
|
+
print(f"{'Files:':<12} {len(files)} files") # noqa: T201
|
|
168
|
+
for f in files:
|
|
169
|
+
print(f" - {f}") # noqa: T201
|