palace-toolkit 0.1.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.
- palace_toolkit-0.1.0/MANIFEST.in +1 -0
- palace_toolkit-0.1.0/PKG-INFO +29 -0
- palace_toolkit-0.1.0/README.md +176 -0
- palace_toolkit-0.1.0/pyproject.toml +48 -0
- palace_toolkit-0.1.0/setup.cfg +4 -0
- palace_toolkit-0.1.0/setup.py +54 -0
- palace_toolkit-0.1.0/src/palace_toolkit.egg-info/PKG-INFO +29 -0
- palace_toolkit-0.1.0/src/palace_toolkit.egg-info/SOURCES.txt +23 -0
- palace_toolkit-0.1.0/src/palace_toolkit.egg-info/dependency_links.txt +1 -0
- palace_toolkit-0.1.0/src/palace_toolkit.egg-info/requires.txt +27 -0
- palace_toolkit-0.1.0/src/palace_toolkit.egg-info/top_level.txt +1 -0
- palace_toolkit-0.1.0/src/palacetoolkit/__init__.py +31 -0
- palace_toolkit-0.1.0/src/palacetoolkit/analytic.py +60 -0
- palace_toolkit-0.1.0/src/palacetoolkit/geometry.py +48 -0
- palace_toolkit-0.1.0/src/palacetoolkit/mesh.py +468 -0
- palace_toolkit-0.1.0/src/palacetoolkit/mode_solver.py +955 -0
- palace_toolkit-0.1.0/src/palacetoolkit/palace_runtime.py +37 -0
- palace_toolkit-0.1.0/src/palacetoolkit/plot_farfield.py +292 -0
- palace_toolkit-0.1.0/src/palacetoolkit/s_plot.py +29 -0
- palace_toolkit-0.1.0/src/palacetoolkit/simulation.py +508 -0
- palace_toolkit-0.1.0/src/palacetoolkit/utils.py +460 -0
- palace_toolkit-0.1.0/src/palacetoolkit/verify_topology.py +793 -0
- palace_toolkit-0.1.0/src/palacetoolkit/viz.py +999 -0
- palace_toolkit-0.1.0/tests/test_docs_notebooks.py +72 -0
- palace_toolkit-0.1.0/tools/build_palace.py +247 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include tools/build_palace.py
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: palace-toolkit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: PALACE electromagnetic simulation course materials
|
|
5
|
+
Requires-Python: >=3.8
|
|
6
|
+
Requires-Dist: gmsh
|
|
7
|
+
Requires-Dist: numpy
|
|
8
|
+
Requires-Dist: scipy
|
|
9
|
+
Requires-Dist: meshio
|
|
10
|
+
Requires-Dist: mfem
|
|
11
|
+
Requires-Dist: pyvista
|
|
12
|
+
Requires-Dist: enlighten
|
|
13
|
+
Requires-Dist: pint
|
|
14
|
+
Provides-Extra: plot
|
|
15
|
+
Requires-Dist: pandas; extra == "plot"
|
|
16
|
+
Requires-Dist: matplotlib; extra == "plot"
|
|
17
|
+
Provides-Extra: palace-cpu
|
|
18
|
+
Requires-Dist: palacetoolkit-palace-cpu>=0.1.0; extra == "palace-cpu"
|
|
19
|
+
Provides-Extra: docs
|
|
20
|
+
Requires-Dist: mkdocs; extra == "docs"
|
|
21
|
+
Requires-Dist: mkdocs-material; extra == "docs"
|
|
22
|
+
Requires-Dist: mkdocs-jupyter; extra == "docs"
|
|
23
|
+
Requires-Dist: pyvista[jupyter]; extra == "docs"
|
|
24
|
+
Requires-Dist: nbconvert; extra == "docs"
|
|
25
|
+
Requires-Dist: ipykernel; extra == "docs"
|
|
26
|
+
Requires-Dist: papermill; extra == "docs"
|
|
27
|
+
Requires-Dist: pytest; extra == "docs"
|
|
28
|
+
Requires-Dist: nb-clean; extra == "docs"
|
|
29
|
+
Requires-Dist: pre-commit; extra == "docs"
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# PalaceToolkit
|
|
2
|
+
|
|
3
|
+
A Python toolkit for open-source electromagnetic simulation with
|
|
4
|
+
[Palace](https://awslabs.github.io/palace/) and [Gmsh](https://gmsh.info/).
|
|
5
|
+
PalaceToolkit provides a declarative pipeline that takes you from geometry
|
|
6
|
+
definition to post-processed S-parameters and far-field plots — no commercial
|
|
7
|
+
licence required.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
| Module | Description |
|
|
12
|
+
|--------|-------------|
|
|
13
|
+
| `palace.mesh` | Priority-based boolean pipeline for multi-material Gmsh models with automatic size-field grading. |
|
|
14
|
+
| `palace.simulation` | Run Palace via Apptainer/MPI and extract S-parameters and impedance. |
|
|
15
|
+
| `palace.verify_topology` | Validate that a 3D tetrahedral mesh is topologically consistent for Palace/MFEM. |
|
|
16
|
+
| `palace.analytic` | Closed-form transmission-line formulas (CPW impedance, effective index, …). |
|
|
17
|
+
| `palace.s_plot` | Quick matplotlib plots of Palace S-parameter CSV files. |
|
|
18
|
+
| `palace.view_mesh` | Interactive PyVista viewer with per-group colouring. |
|
|
19
|
+
| `palace.viz` | Headless-safe visualisation helpers that export standalone HTML for docs and notebooks. |
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
### Prerequisites
|
|
24
|
+
|
|
25
|
+
* Python ≥ 3.8
|
|
26
|
+
* [Gmsh](https://gmsh.info/) (the `gmsh` Python package is pulled automatically)
|
|
27
|
+
|
|
28
|
+
### Install the package
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Clone the repository
|
|
32
|
+
git clone https://github.com/EpsilonForge/PalaceToolkit.git
|
|
33
|
+
cd PalaceToolkit
|
|
34
|
+
|
|
35
|
+
# Create a virtual environment and install in editable mode
|
|
36
|
+
python -m venv .venv
|
|
37
|
+
source .venv/bin/activate
|
|
38
|
+
|
|
39
|
+
# Local clone install (recommended for now)
|
|
40
|
+
./tools/install_local_editable.sh
|
|
41
|
+
|
|
42
|
+
# Or equivalent manual commands:
|
|
43
|
+
pip install https://github.com/EpsilonForge/PalaceToolkit/releases/download/palace-cpu-vX.Y.Z/<wheel-file>.whl
|
|
44
|
+
pip install -e ".[plot,docs]"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Default runtime is binary-first when `palacetoolkit-palace-cpu` is installed.
|
|
48
|
+
|
|
49
|
+
By default, `./tools/install_local_editable.sh` fetches the latest
|
|
50
|
+
GA-built binary wheel from GitHub Releases.
|
|
51
|
+
|
|
52
|
+
To force local binary package mode from the checkout:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
PALACETOOLKIT_BINARY_SOURCE=local ./tools/install_local_editable.sh
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Compatibility Policy
|
|
59
|
+
|
|
60
|
+
- Stable releases of `palace-toolkit` are validated against a matching stable release of `palacetoolkit-palace-cpu`.
|
|
61
|
+
- The default local clone path (`./tools/install_local_editable.sh`) installs both packages from the same repository checkout and is the reference development workflow.
|
|
62
|
+
- Nightly Palace builds are supported for power users through opt-in source builds and are treated as best-effort (no stability guarantee across commits).
|
|
63
|
+
- If API/runtime behavior differs between stable and nightly Palace, `palace-toolkit` stable behavior is defined by the stable `palacetoolkit-palace-cpu` line.
|
|
64
|
+
|
|
65
|
+
See `docs/getting-started/compatibility-policy.md` for the full policy and release cadence.
|
|
66
|
+
|
|
67
|
+
### Release Tags and CI Publishing
|
|
68
|
+
|
|
69
|
+
- `palace-cpu-vX.Y.Z` triggers binary build/publish workflow for `palacetoolkit-palace-cpu`.
|
|
70
|
+
- `vX.Y.Z` triggers main package build/publish workflow for `palace-toolkit`.
|
|
71
|
+
- Both workflows also support manual dispatch from GitHub Actions.
|
|
72
|
+
|
|
73
|
+
### Optional: Power-user source build (nightly/custom)
|
|
74
|
+
|
|
75
|
+
Source builds are opt-in and disabled by default.
|
|
76
|
+
Use this only if you need custom flags (CUDA/HIP/MAGMA/etc.) or nightly Palace.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
PALACETOOLKIT_BUILD_PALACE=1 \
|
|
80
|
+
PALACETOOLKIT_CLONE_NIGHTLY=1 \
|
|
81
|
+
PALACETOOLKIT_PALACE_WITH_CUDA=0 \
|
|
82
|
+
PALACETOOLKIT_PALACE_WITH_HIP=0 \
|
|
83
|
+
PALACETOOLKIT_PALACE_WITH_MAGMA=0 \
|
|
84
|
+
pip install -e .
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Source builds are cached at:
|
|
88
|
+
|
|
89
|
+
`~/.cache/palacetoolkit/palace/<source-key>-<platform>-<options-hash>/build/bin/palace`
|
|
90
|
+
|
|
91
|
+
On subsequent installs, the cached build is reused automatically. Useful controls:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Force rebuild even when cache exists
|
|
95
|
+
PALACETOOLKIT_FORCE_PALACE_REBUILD=1 pip install -e .
|
|
96
|
+
|
|
97
|
+
# Use a local Palace source tree instead of cloning nightly
|
|
98
|
+
PALACETOOLKIT_PALACE_SOURCE=/path/to/palace PALACETOOLKIT_BUILD_PALACE=1 pip install -e .
|
|
99
|
+
|
|
100
|
+
# Override parallel build jobs
|
|
101
|
+
PALACETOOLKIT_PALACE_JOBS=8 pip install -e .
|
|
102
|
+
|
|
103
|
+
# Extra custom CMake args
|
|
104
|
+
PALACETOOLKIT_PALACE_EXTRA_CMAKE_ARGS="-DCMAKE_BUILD_TYPE=Release" pip install -e .
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The core install pulls `gmsh`, `numpy`, `meshio`, `pyvista`,
|
|
108
|
+
`enlighten`, and `pint`. The optional dependency groups are:
|
|
109
|
+
|
|
110
|
+
| Group | Extra packages |
|
|
111
|
+
|-------|---------------|
|
|
112
|
+
| `plot` | `pandas`, `matplotlib` |
|
|
113
|
+
| `docs` | `mkdocs`, `mkdocs-material`, `pyvista[jupyter]`, `nbconvert`, `ipykernel`, `papermill`, `nb-clean`, `pre-commit` |
|
|
114
|
+
|
|
115
|
+
## Quick start
|
|
116
|
+
|
|
117
|
+
Below is a minimal example that creates a coaxial geometry, meshes it, runs
|
|
118
|
+
Palace, and plots the S-parameters:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
import palacetoolkit as ptk
|
|
122
|
+
from ptk.mesh import Entity, run_meshing_pipeline
|
|
123
|
+
from ptk.simulation import run_palace
|
|
124
|
+
from ptk.s_plot import plot_s_params
|
|
125
|
+
|
|
126
|
+
# 1. Define entities with names, priorities and materials
|
|
127
|
+
inner = Entity(name="inner_conductor", ...)
|
|
128
|
+
dielectric = Entity(name="dielectric", ...)
|
|
129
|
+
outer = Entity(name="outer_conductor", ...)
|
|
130
|
+
|
|
131
|
+
# 2. Run the boolean pipeline — cuts, fragments, and meshes
|
|
132
|
+
run_meshing_pipeline([inner, dielectric, outer], output="coax.msh")
|
|
133
|
+
|
|
134
|
+
# 3. Run Palace with a JSON config
|
|
135
|
+
run_palace("coax.json", np=4)
|
|
136
|
+
|
|
137
|
+
# 4. Plot results
|
|
138
|
+
plot_s_params("postpro/coax")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
See `docs/examples/` notebooks for worked examples covering waveguides,
|
|
142
|
+
dipole antennas, horn antennas, and planar microwave circuits.
|
|
143
|
+
|
|
144
|
+
## Building the docs
|
|
145
|
+
|
|
146
|
+
The documentation site is built with
|
|
147
|
+
[MkDocs Material](https://squidfunk.github.io/mkdocs-material/).
|
|
148
|
+
A [justfile](https://github.com/casey/just) automates the full pipeline.
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# Install docs dependencies (if not already)
|
|
152
|
+
pip install -e ".[docs]"
|
|
153
|
+
|
|
154
|
+
# Register the virtualenv as a Jupyter kernel
|
|
155
|
+
just ipykernel
|
|
156
|
+
|
|
157
|
+
# Full build: execute notebooks → build site
|
|
158
|
+
just docs-full
|
|
159
|
+
|
|
160
|
+
# Run documentation doctests (executes notebooks and fails on errors)
|
|
161
|
+
just doctest
|
|
162
|
+
|
|
163
|
+
# Or run each step individually:
|
|
164
|
+
just nbrun # execute docs example notebooks with papermill
|
|
165
|
+
just nbdocs # no-op (MkDocs renders .ipynb directly)
|
|
166
|
+
just docs # build the MkDocs static site
|
|
167
|
+
|
|
168
|
+
# Serve locally for development
|
|
169
|
+
just serve # starts a dev server on http://localhost:8080
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Other useful recipes
|
|
173
|
+
|
|
174
|
+
| Recipe | Description |
|
|
175
|
+
|--------|-------------|
|
|
176
|
+
| `just nbclean` | Strip cell outputs from docs example notebooks for clean commits. |
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "palace-toolkit"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "PALACE electromagnetic simulation course materials"
|
|
5
|
+
requires-python = ">=3.8"
|
|
6
|
+
dependencies = [
|
|
7
|
+
"gmsh",
|
|
8
|
+
"numpy",
|
|
9
|
+
"scipy",
|
|
10
|
+
"meshio",
|
|
11
|
+
"mfem",
|
|
12
|
+
"pyvista",
|
|
13
|
+
"enlighten",
|
|
14
|
+
"pint",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.optional-dependencies]
|
|
18
|
+
plot = ["pandas", "matplotlib"]
|
|
19
|
+
palace-cpu = ["palacetoolkit-palace-cpu>=0.1.0"]
|
|
20
|
+
docs = [
|
|
21
|
+
"mkdocs",
|
|
22
|
+
"mkdocs-material",
|
|
23
|
+
"mkdocs-jupyter",
|
|
24
|
+
"pyvista[jupyter]",
|
|
25
|
+
"nbconvert",
|
|
26
|
+
"ipykernel",
|
|
27
|
+
"papermill",
|
|
28
|
+
"pytest",
|
|
29
|
+
"nb-clean",
|
|
30
|
+
"pre-commit",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[tool.pytest.ini_options]
|
|
34
|
+
testpaths = ["tests"]
|
|
35
|
+
markers = [
|
|
36
|
+
"docs: execute documentation notebooks",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[tool.setuptools]
|
|
40
|
+
package-dir = {"" = "src"}
|
|
41
|
+
|
|
42
|
+
[tool.setuptools.packages.find]
|
|
43
|
+
where = ["src"]
|
|
44
|
+
include = ["palacetoolkit", "palacetoolkit.*"]
|
|
45
|
+
|
|
46
|
+
[build-system]
|
|
47
|
+
requires = ["setuptools>=45", "wheel"]
|
|
48
|
+
build-backend = "setuptools.build_meta"
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from setuptools import setup
|
|
7
|
+
from setuptools.command.build_py import build_py as _build_py
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _wants_palace_build() -> bool:
|
|
11
|
+
raw = os.environ.get("PALACETOOLKIT_BUILD_PALACE", "0").strip().lower()
|
|
12
|
+
return raw not in {"0", "false", "no", "off"}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _run_palace_build() -> None:
|
|
16
|
+
tools_dir = Path(__file__).parent / "tools"
|
|
17
|
+
script = tools_dir / "build_palace.py"
|
|
18
|
+
ns: dict[str, object] = {}
|
|
19
|
+
with script.open("r", encoding="utf-8") as f:
|
|
20
|
+
code = compile(f.read(), str(script), "exec")
|
|
21
|
+
exec(code, ns)
|
|
22
|
+
ns["ensure_palace_cached_build"]()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class build_py(_build_py):
|
|
26
|
+
def run(self) -> None:
|
|
27
|
+
if _wants_palace_build():
|
|
28
|
+
self.announce("PalaceToolkit: opt-in Palace source build requested", level=3)
|
|
29
|
+
_run_palace_build()
|
|
30
|
+
else:
|
|
31
|
+
self.announce("PalaceToolkit: skipping Palace source build (default)", level=3)
|
|
32
|
+
super().run()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
cmdclass: dict[str, type] = {"build_py": build_py}
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
from setuptools.command.editable_wheel import editable_wheel as _editable_wheel
|
|
39
|
+
|
|
40
|
+
class editable_wheel(_editable_wheel):
|
|
41
|
+
def run(self) -> None:
|
|
42
|
+
if _wants_palace_build():
|
|
43
|
+
self.announce("PalaceToolkit: opt-in Palace source build requested", level=3)
|
|
44
|
+
_run_palace_build()
|
|
45
|
+
else:
|
|
46
|
+
self.announce("PalaceToolkit: skipping Palace source build (default)", level=3)
|
|
47
|
+
super().run()
|
|
48
|
+
|
|
49
|
+
cmdclass["editable_wheel"] = editable_wheel
|
|
50
|
+
except Exception:
|
|
51
|
+
# Older setuptools versions may not expose editable_wheel.
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
setup(cmdclass=cmdclass)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: palace-toolkit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: PALACE electromagnetic simulation course materials
|
|
5
|
+
Requires-Python: >=3.8
|
|
6
|
+
Requires-Dist: gmsh
|
|
7
|
+
Requires-Dist: numpy
|
|
8
|
+
Requires-Dist: scipy
|
|
9
|
+
Requires-Dist: meshio
|
|
10
|
+
Requires-Dist: mfem
|
|
11
|
+
Requires-Dist: pyvista
|
|
12
|
+
Requires-Dist: enlighten
|
|
13
|
+
Requires-Dist: pint
|
|
14
|
+
Provides-Extra: plot
|
|
15
|
+
Requires-Dist: pandas; extra == "plot"
|
|
16
|
+
Requires-Dist: matplotlib; extra == "plot"
|
|
17
|
+
Provides-Extra: palace-cpu
|
|
18
|
+
Requires-Dist: palacetoolkit-palace-cpu>=0.1.0; extra == "palace-cpu"
|
|
19
|
+
Provides-Extra: docs
|
|
20
|
+
Requires-Dist: mkdocs; extra == "docs"
|
|
21
|
+
Requires-Dist: mkdocs-material; extra == "docs"
|
|
22
|
+
Requires-Dist: mkdocs-jupyter; extra == "docs"
|
|
23
|
+
Requires-Dist: pyvista[jupyter]; extra == "docs"
|
|
24
|
+
Requires-Dist: nbconvert; extra == "docs"
|
|
25
|
+
Requires-Dist: ipykernel; extra == "docs"
|
|
26
|
+
Requires-Dist: papermill; extra == "docs"
|
|
27
|
+
Requires-Dist: pytest; extra == "docs"
|
|
28
|
+
Requires-Dist: nb-clean; extra == "docs"
|
|
29
|
+
Requires-Dist: pre-commit; extra == "docs"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MANIFEST.in
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.py
|
|
5
|
+
src/palace_toolkit.egg-info/PKG-INFO
|
|
6
|
+
src/palace_toolkit.egg-info/SOURCES.txt
|
|
7
|
+
src/palace_toolkit.egg-info/dependency_links.txt
|
|
8
|
+
src/palace_toolkit.egg-info/requires.txt
|
|
9
|
+
src/palace_toolkit.egg-info/top_level.txt
|
|
10
|
+
src/palacetoolkit/__init__.py
|
|
11
|
+
src/palacetoolkit/analytic.py
|
|
12
|
+
src/palacetoolkit/geometry.py
|
|
13
|
+
src/palacetoolkit/mesh.py
|
|
14
|
+
src/palacetoolkit/mode_solver.py
|
|
15
|
+
src/palacetoolkit/palace_runtime.py
|
|
16
|
+
src/palacetoolkit/plot_farfield.py
|
|
17
|
+
src/palacetoolkit/s_plot.py
|
|
18
|
+
src/palacetoolkit/simulation.py
|
|
19
|
+
src/palacetoolkit/utils.py
|
|
20
|
+
src/palacetoolkit/verify_topology.py
|
|
21
|
+
src/palacetoolkit/viz.py
|
|
22
|
+
tests/test_docs_notebooks.py
|
|
23
|
+
tools/build_palace.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
gmsh
|
|
2
|
+
numpy
|
|
3
|
+
scipy
|
|
4
|
+
meshio
|
|
5
|
+
mfem
|
|
6
|
+
pyvista
|
|
7
|
+
enlighten
|
|
8
|
+
pint
|
|
9
|
+
|
|
10
|
+
[docs]
|
|
11
|
+
mkdocs
|
|
12
|
+
mkdocs-material
|
|
13
|
+
mkdocs-jupyter
|
|
14
|
+
pyvista[jupyter]
|
|
15
|
+
nbconvert
|
|
16
|
+
ipykernel
|
|
17
|
+
papermill
|
|
18
|
+
pytest
|
|
19
|
+
nb-clean
|
|
20
|
+
pre-commit
|
|
21
|
+
|
|
22
|
+
[palace-cpu]
|
|
23
|
+
palacetoolkit-palace-cpu>=0.1.0
|
|
24
|
+
|
|
25
|
+
[plot]
|
|
26
|
+
pandas
|
|
27
|
+
matplotlib
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
palacetoolkit
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""PalaceToolkit — utilities for Palace electromagnetic simulations.
|
|
2
|
+
|
|
3
|
+
Import as::
|
|
4
|
+
|
|
5
|
+
from palacetoolkit.analytic import cpw_impedance
|
|
6
|
+
from palacetoolkit.mesh import Entity, run_meshing_pipeline
|
|
7
|
+
from palacetoolkit.simulation import run_palace, generate_palace_config
|
|
8
|
+
from palacetoolkit.viz import view_mesh
|
|
9
|
+
from palacetoolkit.verify_topology import analyse_mesh
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from palacetoolkit.analytic import * # noqa: F401,F403
|
|
13
|
+
from palacetoolkit.mesh import * # noqa: F401,F403
|
|
14
|
+
from palacetoolkit.simulation import * # noqa: F401,F403
|
|
15
|
+
from palacetoolkit.verify_topology import * # noqa: F401,F403
|
|
16
|
+
|
|
17
|
+
# Optional submodules — silently skip when extra deps are missing
|
|
18
|
+
try:
|
|
19
|
+
from palacetoolkit.s_plot import * # noqa: F401,F403
|
|
20
|
+
except ImportError:
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
from palacetoolkit.viz import * # noqa: F401,F403
|
|
25
|
+
except ImportError:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
from palacetoolkit.utils import * # noqa: F401,F403
|
|
30
|
+
except ImportError:
|
|
31
|
+
pass
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Analytic closed-form expressions for transmission line parameters."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
def _K_over_Kp(k: float, kp: float) -> float:
|
|
6
|
+
"""Approximate ratio K(k)/K(k') using the Hilberg formula."""
|
|
7
|
+
def _s(x: float) -> float:
|
|
8
|
+
return np.log(
|
|
9
|
+
2 * (np.sqrt(1 + x) + (4 * x) ** 0.25)
|
|
10
|
+
/ (np.sqrt(1 + x) - (4 * x) ** 0.25)
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
if k >= 1.0 / np.sqrt(2):
|
|
14
|
+
return _s(k) / (2 * np.pi)
|
|
15
|
+
else:
|
|
16
|
+
return 2 * np.pi / _s(kp)
|
|
17
|
+
|
|
18
|
+
def cpw_impedance(w: float, s: float, h: float, eps_r: float) -> float:
|
|
19
|
+
"""Compute the characteristic impedance of a CPW line.
|
|
20
|
+
|
|
21
|
+
Uses the conformal mapping approach with elliptic integral ratios K(k)/K(k').
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
w: Centre conductor width.
|
|
25
|
+
s: Gap between centre conductor and ground.
|
|
26
|
+
h: Substrate thickness.
|
|
27
|
+
eps_r: Relative permittivity of the substrate.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Z0: Characteristic impedance in Ohms.
|
|
31
|
+
"""
|
|
32
|
+
k = w / (w + 2 * s)
|
|
33
|
+
k1 = np.sinh(np.pi * w / (4 * h)) / np.sinh(np.pi * (w + 2 * s) / (4 * h))
|
|
34
|
+
|
|
35
|
+
kp = np.sqrt(1 - k ** 2)
|
|
36
|
+
k1p = np.sqrt(1 - k1 ** 2)
|
|
37
|
+
|
|
38
|
+
kok = _K_over_Kp(k, kp)
|
|
39
|
+
k1ok = _K_over_Kp(k1, k1p)
|
|
40
|
+
|
|
41
|
+
eps_eff = 1 + ((eps_r - 1) / 2) * k1ok / kok
|
|
42
|
+
Z0 = 30 * np.pi / (kok * np.sqrt(eps_eff))
|
|
43
|
+
return Z0
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def cpw_effective_index(w: float, s: float, h: float, eps_r: float) -> float:
|
|
47
|
+
"""Return the effective refractive index of a CPW line.
|
|
48
|
+
|
|
49
|
+
Uses the same conformal-mapping model as :func:`cpw_impedance`.
|
|
50
|
+
"""
|
|
51
|
+
k = w / (w + 2 * s)
|
|
52
|
+
k1 = np.sinh(np.pi * w / (4 * h)) / np.sinh(np.pi * (w + 2 * s) / (4 * h))
|
|
53
|
+
|
|
54
|
+
kp = np.sqrt(1 - k ** 2)
|
|
55
|
+
k1p = np.sqrt(1 - k1 ** 2)
|
|
56
|
+
kok = _K_over_Kp(k, kp)
|
|
57
|
+
k1ok = _K_over_Kp(k1, k1p)
|
|
58
|
+
|
|
59
|
+
eps_eff = 1 + ((eps_r - 1) / 2) * k1ok / kok
|
|
60
|
+
return np.sqrt(eps_eff)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import gmsh
|
|
2
|
+
|
|
3
|
+
def extract_tag(obj):
|
|
4
|
+
"""
|
|
5
|
+
Extract the Gmsh tag from an object.
|
|
6
|
+
|
|
7
|
+
If object contains only one tag, return it as an integer, otherwise, preserve its
|
|
8
|
+
container.
|
|
9
|
+
|
|
10
|
+
Most gmsh functions return list of tuples like [(2, 5), (2, 8), (2, 10), ...], where the
|
|
11
|
+
first number is dimensionality and the second is the integer tag associated to that object.
|
|
12
|
+
|
|
13
|
+
Examples
|
|
14
|
+
--------
|
|
15
|
+
>>> extract_tag((3, 6))
|
|
16
|
+
6
|
|
17
|
+
|
|
18
|
+
>>> entities = [(2, 5), (2, 8), (2, 10)]
|
|
19
|
+
>>> [extract_tag(e) for e in entities]
|
|
20
|
+
[5, 8, 10]
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
if isinstance(obj, list) and len(obj) == 1:
|
|
24
|
+
return extract_tag(obj[0])
|
|
25
|
+
elif isinstance(obj, tuple):
|
|
26
|
+
return obj[1]
|
|
27
|
+
else:
|
|
28
|
+
raise ValueError("Expected a tuple or single-element list")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Convenience functions to extract extrema of the bounding box of an entity
|
|
32
|
+
def xmin(dimtag):
|
|
33
|
+
return gmsh.model.occ.getBoundingBox(dimtag[0], dimtag[1])[0]
|
|
34
|
+
|
|
35
|
+
def ymin(dimtag):
|
|
36
|
+
return gmsh.model.occ.getBoundingBox(dimtag[0], dimtag[1])[1]
|
|
37
|
+
|
|
38
|
+
def zmin(dimtag):
|
|
39
|
+
return gmsh.model.occ.getBoundingBox(dimtag[0], dimtag[1])[2]
|
|
40
|
+
|
|
41
|
+
def xmax(dimtag):
|
|
42
|
+
return gmsh.model.occ.getBoundingBox(dimtag[0], dimtag[1])[3]
|
|
43
|
+
|
|
44
|
+
def ymax(dimtag):
|
|
45
|
+
return gmsh.model.occ.getBoundingBox(dimtag[0], dimtag[1])[4]
|
|
46
|
+
|
|
47
|
+
def zmax(dimtag):
|
|
48
|
+
return gmsh.model.occ.getBoundingBox(dimtag[0], dimtag[1])[5]
|