setupEM 0.1.1__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.
- setupem-0.1.1/PKG-INFO +57 -0
- setupem-0.1.1/README.md +47 -0
- setupem-0.1.1/pyproject.toml +24 -0
- setupem-0.1.1/setup.cfg +4 -0
- setupem-0.1.1/src/examples/pcb_lowpass/palace_pcb_lowpass.py +120 -0
- setupem-0.1.1/src/examples/sg13_balun_140-170/palace_balun_mesh2.py +120 -0
- setupem-0.1.1/src/examples/sg13_microstrip_fast/palace_demo_line.py +117 -0
- setupem-0.1.1/src/examples/sg13_rfcmim/palace_rfcmim.py +114 -0
- setupem-0.1.1/src/setupEM/__init__.py +9 -0
- setupem-0.1.1/src/setupEM/setupEM.py +2141 -0
- setupem-0.1.1/src/setupEM.egg-info/PKG-INFO +57 -0
- setupem-0.1.1/src/setupEM.egg-info/SOURCES.txt +14 -0
- setupem-0.1.1/src/setupEM.egg-info/dependency_links.txt +1 -0
- setupem-0.1.1/src/setupEM.egg-info/entry_points.txt +2 -0
- setupem-0.1.1/src/setupEM.egg-info/requires.txt +2 -0
- setupem-0.1.1/src/setupEM.egg-info/top_level.txt +2 -0
setupem-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: setupEM
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Python tool for configuration of gds2palace workflow with GUI.
|
|
5
|
+
Author-email: Volker Muehlhaus <volker@muehlhaus.com>
|
|
6
|
+
Requires-Python: >=3.9
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: gds2palace>=0.1.2
|
|
9
|
+
Requires-Dist: PySide6
|
|
10
|
+
|
|
11
|
+
# Create EM Simulation model from GDSII layout files
|
|
12
|
+
|
|
13
|
+
setupEM provides a graphical user interface (Qt based) to configured gds2palace workflow.
|
|
14
|
+
gds2palace enables an RFIC FEM simulation workflow based on the Palace FEM solver by AWS.
|
|
15
|
+
|
|
16
|
+
# Installation
|
|
17
|
+
To install the setupEM, activate the venv where you want to install.
|
|
18
|
+
|
|
19
|
+
Documentation for the gds2palace workflow assumes that you have created a Python venv
|
|
20
|
+
named "palace" in ~/venv/palace and installed the modules there.
|
|
21
|
+
|
|
22
|
+
If you follow this, you would first activate the venv:
|
|
23
|
+
```
|
|
24
|
+
source ~\venv\palace\bin\activate
|
|
25
|
+
```
|
|
26
|
+
and then install setupEM and dependencies via PyPI:
|
|
27
|
+
```
|
|
28
|
+
pip install setupEM
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
To upgrade to the latest version, do
|
|
32
|
+
```
|
|
33
|
+
pip install setupEM --upgrade
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
## Missing libraries on installation
|
|
38
|
+
If you see this error message when trying to run setupEM:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
qt.qpa.plugin: From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin. qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
you need to install additional Qt libraries:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
sudo apt update
|
|
48
|
+
sudo apt install libxcb-cursor0 libxcb-xinerama0 libxcb-xkb1 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-render0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-xfixes0 libxcb-xinput0 libxcb-xv0 libxcb-util1 libxkbcommon-x11-0
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# Dependencies
|
|
53
|
+
This module also installs these dependencies:
|
|
54
|
+
gds2palace
|
|
55
|
+
PySide6
|
|
56
|
+
|
|
57
|
+
|
setupem-0.1.1/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Create EM Simulation model from GDSII layout files
|
|
2
|
+
|
|
3
|
+
setupEM provides a graphical user interface (Qt based) to configured gds2palace workflow.
|
|
4
|
+
gds2palace enables an RFIC FEM simulation workflow based on the Palace FEM solver by AWS.
|
|
5
|
+
|
|
6
|
+
# Installation
|
|
7
|
+
To install the setupEM, activate the venv where you want to install.
|
|
8
|
+
|
|
9
|
+
Documentation for the gds2palace workflow assumes that you have created a Python venv
|
|
10
|
+
named "palace" in ~/venv/palace and installed the modules there.
|
|
11
|
+
|
|
12
|
+
If you follow this, you would first activate the venv:
|
|
13
|
+
```
|
|
14
|
+
source ~\venv\palace\bin\activate
|
|
15
|
+
```
|
|
16
|
+
and then install setupEM and dependencies via PyPI:
|
|
17
|
+
```
|
|
18
|
+
pip install setupEM
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
To upgrade to the latest version, do
|
|
22
|
+
```
|
|
23
|
+
pip install setupEM --upgrade
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
## Missing libraries on installation
|
|
28
|
+
If you see this error message when trying to run setupEM:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
qt.qpa.plugin: From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin. qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
you need to install additional Qt libraries:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
sudo apt update
|
|
38
|
+
sudo apt install libxcb-cursor0 libxcb-xinerama0 libxcb-xkb1 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-render0 libxcb-shape0 libxcb-shm0 libxcb-sync1 libxcb-xfixes0 libxcb-xinput0 libxcb-xv0 libxcb-util1 libxkbcommon-x11-0
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# Dependencies
|
|
43
|
+
This module also installs these dependencies:
|
|
44
|
+
gds2palace
|
|
45
|
+
PySide6
|
|
46
|
+
|
|
47
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "setupEM"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "Python tool for configuration of gds2palace workflow with GUI."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "Volker Muehlhaus", email = "volker@muehlhaus.com" }
|
|
12
|
+
]
|
|
13
|
+
dependencies = [
|
|
14
|
+
"gds2palace>=0.1.2",
|
|
15
|
+
"PySide6"
|
|
16
|
+
]
|
|
17
|
+
requires-python = ">=3.9"
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
setupEM = "setupEM.setupEM:main"
|
|
21
|
+
|
|
22
|
+
[tool.setuptools.package-data]
|
|
23
|
+
"setupEM" = ["../examples/*"]
|
|
24
|
+
|
setupem-0.1.1/setup.cfg
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# MODEL FOR GMSH WITH PALACE
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import subprocess
|
|
6
|
+
|
|
7
|
+
# we expect gds2palace in the same directory as this model file
|
|
8
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'gds2palace')))
|
|
9
|
+
from gds2palace import *
|
|
10
|
+
|
|
11
|
+
# Model comments
|
|
12
|
+
#
|
|
13
|
+
# PCB low pass example, everything is in unit micron (GDS and XML stackup)
|
|
14
|
+
# Port excitation only, so that we get S11 and S21. Reverse path data is padded with zeros.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# ======================== workflow settings ================================
|
|
18
|
+
|
|
19
|
+
#start solver after creating the model?
|
|
20
|
+
start_simulation = False
|
|
21
|
+
run_command = ['./run_sim']
|
|
22
|
+
|
|
23
|
+
# ===================== input files and path settings =======================
|
|
24
|
+
|
|
25
|
+
gds_filename = "pcb_lowpass.gds" # geometries
|
|
26
|
+
XML_filename = "pcb_ro4003.xml" # stackup
|
|
27
|
+
|
|
28
|
+
# preprocess GDSII for safe handling of cutouts/holes?
|
|
29
|
+
preprocess_gds = True
|
|
30
|
+
|
|
31
|
+
# merge via polygons with distance less than .. microns, set to 0 to disable via merging.
|
|
32
|
+
merge_polygon_size = 0
|
|
33
|
+
|
|
34
|
+
# get path for this simulation file
|
|
35
|
+
script_path = utilities.get_script_path(__file__)
|
|
36
|
+
|
|
37
|
+
# use script filename as model basename
|
|
38
|
+
model_basename = utilities.get_basename(__file__)
|
|
39
|
+
|
|
40
|
+
# set and create directory for simulation output
|
|
41
|
+
sim_path = utilities.create_sim_path (script_path,model_basename)
|
|
42
|
+
print('Simulation data directory: ', sim_path)
|
|
43
|
+
|
|
44
|
+
# change path to models script path
|
|
45
|
+
modelDir = os.path.dirname(os.path.abspath(__file__))
|
|
46
|
+
os.chdir(modelDir)
|
|
47
|
+
|
|
48
|
+
# ======================== simulation settings ================================
|
|
49
|
+
|
|
50
|
+
settings = {}
|
|
51
|
+
|
|
52
|
+
settings['unit'] = 1e-6 # geometry is in MILLIMETER for PCB example
|
|
53
|
+
settings['margin'] = 2000 # distance in microns from GDSII geometry boundary to simulation boundary
|
|
54
|
+
settings['air_around'] = [1000,1000,1000,1000,2000, 10000] # airbox size to simulation boundary
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
settings['fstart'] = 0.1e9
|
|
58
|
+
settings['fstop'] = 6.0e9
|
|
59
|
+
settings['fstep'] = 0.05e9
|
|
60
|
+
|
|
61
|
+
settings['refined_cellsize'] = 200 # mesh cell size in conductor region
|
|
62
|
+
settings['cells_per_wavelength'] = 10 # how many mesh cells per wavelength, must be 10 or more
|
|
63
|
+
|
|
64
|
+
settings['meshsize_max'] = 5000 # in project units, override cells_per_wavelength
|
|
65
|
+
settings['adaptive_mesh_iterations'] = 0
|
|
66
|
+
settings['z_thickness_factor'] = 1
|
|
67
|
+
|
|
68
|
+
# settings['nogui'] = True # create files without showing 3D model
|
|
69
|
+
# settings['nogui'] = ('nogui' in sys.argv) # check if nogui specified on command line, then create files without showing 3D model
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# Ports from GDSII Data, polygon geometry from specified special layer
|
|
73
|
+
# Excitations can be switched off by voltage=0, those S-parameter will be incomplete then
|
|
74
|
+
|
|
75
|
+
simulation_ports = simulation_setup.all_simulation_ports()
|
|
76
|
+
# instead of in-plane port specified with target_layername, we here use via port specified with from_layername and to_layername
|
|
77
|
+
simulation_ports.add_port(simulation_setup.simulation_port(portnumber=1, voltage=1, port_Z0=50, source_layernum=201, from_layername='Bottom', to_layername='Top', direction='z'))
|
|
78
|
+
simulation_ports.add_port(simulation_setup.simulation_port(portnumber=2, voltage=0, port_Z0=50, source_layernum=202, from_layername='Bottom', to_layername='Top', direction='z'))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# ======================== simulation ================================
|
|
82
|
+
|
|
83
|
+
# get technology stackup data
|
|
84
|
+
materials_list, dielectrics_list, metals_list = stackup_reader.read_substrate (XML_filename)
|
|
85
|
+
# get list of layers from technology
|
|
86
|
+
layernumbers = metals_list.getlayernumbers()
|
|
87
|
+
layernumbers.extend(simulation_ports.portlayers)
|
|
88
|
+
|
|
89
|
+
# read geometries from GDSII, only purpose 0
|
|
90
|
+
allpolygons = gds_reader.read_gds(gds_filename, layernumbers, purposelist=[0], metals_list=metals_list, preprocess=preprocess_gds, merge_polygon_size=merge_polygon_size)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
########### create model ###########
|
|
94
|
+
|
|
95
|
+
settings['simulation_ports'] = simulation_ports
|
|
96
|
+
settings['materials_list'] = materials_list
|
|
97
|
+
settings['dielectrics_list'] = dielectrics_list
|
|
98
|
+
settings['metals_list'] = metals_list
|
|
99
|
+
settings['layernumbers'] = layernumbers
|
|
100
|
+
settings['allpolygons'] = allpolygons
|
|
101
|
+
settings['sim_path'] = sim_path
|
|
102
|
+
settings['model_basename'] = model_basename
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# list of ports that are excited (set voltage to zero in port excitation to skip an excitation!)
|
|
106
|
+
excite_ports = simulation_ports.all_active_excitations()
|
|
107
|
+
config_name, data_dir = simulation_setup.create_palace (excite_ports, settings)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
# for convenience, write run script to model directory
|
|
111
|
+
utilities.create_run_script(sim_path)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
if start_simulation:
|
|
115
|
+
try:
|
|
116
|
+
os.chdir(sim_path)
|
|
117
|
+
subprocess.run(run_command, shell=True)
|
|
118
|
+
except:
|
|
119
|
+
print(f"Unable to run Palace using command ",run_command)
|
|
120
|
+
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# MODEL FOR GMSH WITH PALACE
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import subprocess
|
|
6
|
+
|
|
7
|
+
# we expect gds2palace in the same directory as this model file
|
|
8
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'gds2palace')))
|
|
9
|
+
from gds2palace import *
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Model comments
|
|
13
|
+
#
|
|
14
|
+
# Balun from D-Band phase shifter design by Rupok Das, Neural Semi, in Tapeout July 2025
|
|
15
|
+
# Design frequency 140-170 GHz
|
|
16
|
+
# https://github.com/IHP-GmbH/TO_July2025/tree/main/FMD_QNC_D_Band_Phase_Shifter
|
|
17
|
+
# Ports: Model uses a via port that is defined between Metal3 and TopMetal2
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# ======================== workflow settings ================================
|
|
21
|
+
|
|
22
|
+
# preview model/mesh only, without running solver?
|
|
23
|
+
start_simulation = False
|
|
24
|
+
run_command = ['start', 'wsl.exe']
|
|
25
|
+
|
|
26
|
+
# ===================== input files and path settings =======================
|
|
27
|
+
|
|
28
|
+
gds_filename = "Balun_140-170G_RupokDas_with_ports.gds" # geometries
|
|
29
|
+
XML_filename = "SG13G2_nosub.xml" # stackup
|
|
30
|
+
|
|
31
|
+
# preprocess GDSII for safe handling of cutouts/holes?
|
|
32
|
+
preprocess_gds = False
|
|
33
|
+
|
|
34
|
+
# merge via polygons with distance less than .. microns, set to 0 to disable via merging.
|
|
35
|
+
merge_polygon_size = 2.0
|
|
36
|
+
|
|
37
|
+
# get path for this simulation file
|
|
38
|
+
script_path = utilities.get_script_path(__file__)
|
|
39
|
+
|
|
40
|
+
# use script filename as model basename
|
|
41
|
+
model_basename = utilities.get_basename(__file__)
|
|
42
|
+
|
|
43
|
+
# set and create directory for simulation output
|
|
44
|
+
sim_path = utilities.create_sim_path (script_path,model_basename)
|
|
45
|
+
print('Simulation data directory: ', sim_path)
|
|
46
|
+
|
|
47
|
+
# change path to models script path
|
|
48
|
+
modelDir = os.path.dirname(os.path.abspath(__file__))
|
|
49
|
+
os.chdir(modelDir)
|
|
50
|
+
|
|
51
|
+
# ======================== simulation settings ================================
|
|
52
|
+
|
|
53
|
+
settings = {}
|
|
54
|
+
|
|
55
|
+
settings['unit'] = 1e-6 # geometry is in microns
|
|
56
|
+
settings['margin'] = 50 # distance in microns from GDSII geometry boundary to simulation boundary
|
|
57
|
+
|
|
58
|
+
settings['fstart'] = 100e9
|
|
59
|
+
settings['fstop'] = 200e9
|
|
60
|
+
settings['fstep'] = 1e9
|
|
61
|
+
|
|
62
|
+
settings['refined_cellsize'] = 2 # mesh cell size in conductor region
|
|
63
|
+
settings['cells_per_wavelength'] = 10 # how many mesh cells per wavelength, must be 10 or more
|
|
64
|
+
|
|
65
|
+
settings['meshsize_max'] = 70 # microns, override cells_per_wavelength
|
|
66
|
+
settings['adaptive_mesh_iterations'] = 0
|
|
67
|
+
settings['z_thickness_factor'] = 0.33
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# ports from GDSII Data, polygon geometry from specified special layer
|
|
71
|
+
# note that for multiport simulation, excitations are switched on/off in simulation_setup.createSimulation below
|
|
72
|
+
|
|
73
|
+
simulation_ports = simulation_setup.all_simulation_ports()
|
|
74
|
+
# instead of in-plane port specified with target_layername, we here use via port specified with from_layername and to_layername
|
|
75
|
+
simulation_ports.add_port(simulation_setup.simulation_port(portnumber=1, voltage=1, port_Z0=50, source_layernum=201, from_layername='Metal3', to_layername='TopMetal2', direction='z'))
|
|
76
|
+
simulation_ports.add_port(simulation_setup.simulation_port(portnumber=2, voltage=1, port_Z0=50, source_layernum=202, from_layername='Metal3', to_layername='TopMetal2', direction='z'))
|
|
77
|
+
simulation_ports.add_port(simulation_setup.simulation_port(portnumber=3, voltage=1, port_Z0=50, source_layernum=203, from_layername='Metal3', to_layername='TopMetal2', direction='z'))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# ======================== simulation ================================
|
|
81
|
+
|
|
82
|
+
# get technology stackup data
|
|
83
|
+
materials_list, dielectrics_list, metals_list = stackup_reader.read_substrate (XML_filename)
|
|
84
|
+
# get list of layers from technology
|
|
85
|
+
layernumbers = metals_list.getlayernumbers()
|
|
86
|
+
layernumbers.extend(simulation_ports.portlayers)
|
|
87
|
+
|
|
88
|
+
# read geometries from GDSII, only purpose 0
|
|
89
|
+
allpolygons = gds_reader.read_gds(gds_filename, layernumbers, purposelist=[0], metals_list=metals_list, preprocess=preprocess_gds, merge_polygon_size=merge_polygon_size)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
########### create model ###########
|
|
93
|
+
|
|
94
|
+
settings['simulation_ports'] = simulation_ports
|
|
95
|
+
settings['materials_list'] = materials_list
|
|
96
|
+
settings['dielectrics_list'] = dielectrics_list
|
|
97
|
+
settings['metals_list'] = metals_list
|
|
98
|
+
settings['layernumbers'] = layernumbers
|
|
99
|
+
settings['allpolygons'] = allpolygons
|
|
100
|
+
settings['sim_path'] = sim_path
|
|
101
|
+
settings['model_basename'] = model_basename
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# list of ports that are excited (set voltage to zero in port excitation to skip an excitation!)
|
|
105
|
+
excite_ports = simulation_ports.all_active_excitations()
|
|
106
|
+
config_name, data_dir = simulation_setup.create_palace (excite_ports, settings)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# for convenience, write run script to model directory
|
|
110
|
+
utilities.create_run_script(sim_path)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if start_simulation:
|
|
114
|
+
try:
|
|
115
|
+
os.chdir(sim_path)
|
|
116
|
+
subprocess.run(run_command, shell=True)
|
|
117
|
+
except:
|
|
118
|
+
print(f"Unable to run Palace using command ",run_command)
|
|
119
|
+
|
|
120
|
+
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# MODEL FOR GMSH WITH PALACE
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import subprocess
|
|
6
|
+
|
|
7
|
+
# we expect gds2palace in the same directory as this model file
|
|
8
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'gds2palace')))
|
|
9
|
+
from gds2palace import *
|
|
10
|
+
|
|
11
|
+
# Model comments
|
|
12
|
+
#
|
|
13
|
+
# Ports: Model uses a via port that is defined between Metal1 and TopMetal2 (not using in-plane port here)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# ======================== workflow settings ================================
|
|
17
|
+
|
|
18
|
+
#start solver after creating the model?
|
|
19
|
+
start_simulation = False
|
|
20
|
+
run_command = ['./run_sim']
|
|
21
|
+
|
|
22
|
+
# ===================== input files and path settings =======================
|
|
23
|
+
|
|
24
|
+
gds_filename = "line_short_viaport.gds" # geometries
|
|
25
|
+
XML_filename = "SG13G2_nosub.xml" # stackup
|
|
26
|
+
|
|
27
|
+
# preprocess GDSII for safe handling of cutouts/holes?
|
|
28
|
+
preprocess_gds = False
|
|
29
|
+
|
|
30
|
+
# merge via polygons with distance less than .. microns, set to 0 to disable via merging.
|
|
31
|
+
merge_polygon_size = 0
|
|
32
|
+
|
|
33
|
+
# get path for this simulation file
|
|
34
|
+
script_path = utilities.get_script_path(__file__)
|
|
35
|
+
|
|
36
|
+
# use script filename as model basename
|
|
37
|
+
model_basename = utilities.get_basename(__file__)
|
|
38
|
+
|
|
39
|
+
# set and create directory for simulation output
|
|
40
|
+
sim_path = utilities.create_sim_path (script_path,model_basename)
|
|
41
|
+
print('Simulation data directory: ', sim_path)
|
|
42
|
+
|
|
43
|
+
# change path to models script path
|
|
44
|
+
modelDir = os.path.dirname(os.path.abspath(__file__))
|
|
45
|
+
os.chdir(modelDir)
|
|
46
|
+
|
|
47
|
+
# ======================== simulation settings ================================
|
|
48
|
+
|
|
49
|
+
settings = {}
|
|
50
|
+
|
|
51
|
+
settings['unit'] = 1e-6 # geometry is in microns
|
|
52
|
+
settings['margin'] = 50 # distance in microns from GDSII geometry boundary to simulation boundary
|
|
53
|
+
|
|
54
|
+
settings['fstart'] = 0e9
|
|
55
|
+
settings['fstop'] = 50e9
|
|
56
|
+
settings['fstep'] = 2.5e9
|
|
57
|
+
|
|
58
|
+
settings['refined_cellsize'] = 5 # mesh cell size in conductor region
|
|
59
|
+
settings['cells_per_wavelength'] = 10 # how many mesh cells per wavelength, must be 10 or more
|
|
60
|
+
|
|
61
|
+
settings['meshsize_max'] = 70 # microns, override cells_per_wavelength
|
|
62
|
+
settings['adaptive_mesh_iterations'] = 0
|
|
63
|
+
settings['z_thickness_factor'] = 0.33
|
|
64
|
+
|
|
65
|
+
# settings['nogui'] = True # create files without showing 3D model
|
|
66
|
+
# settings['nogui'] = ('nogui' in sys.argv) # check if nogui specified on command line, then create files without showing 3D model
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# Ports from GDSII Data, polygon geometry from specified special layer
|
|
70
|
+
# Excitations can be switched off by voltage=0, those S-parameter will be incomplete then
|
|
71
|
+
|
|
72
|
+
simulation_ports = simulation_setup.all_simulation_ports()
|
|
73
|
+
# instead of in-plane port specified with target_layername, we here use via port specified with from_layername and to_layername
|
|
74
|
+
simulation_ports.add_port(simulation_setup.simulation_port(portnumber=1, voltage=1, port_Z0=50, source_layernum=201, from_layername='Metal1', to_layername='TopMetal2', direction='z'))
|
|
75
|
+
simulation_ports.add_port(simulation_setup.simulation_port(portnumber=2, voltage=0, port_Z0=50, source_layernum=202, from_layername='Metal1', to_layername='TopMetal2', direction='z'))
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# ======================== simulation ================================
|
|
79
|
+
|
|
80
|
+
# get technology stackup data
|
|
81
|
+
materials_list, dielectrics_list, metals_list = stackup_reader.read_substrate (XML_filename)
|
|
82
|
+
# get list of layers from technology
|
|
83
|
+
layernumbers = metals_list.getlayernumbers()
|
|
84
|
+
layernumbers.extend(simulation_ports.portlayers)
|
|
85
|
+
|
|
86
|
+
# read geometries from GDSII, only purpose 0
|
|
87
|
+
allpolygons = gds_reader.read_gds(gds_filename, layernumbers, purposelist=[0], metals_list=metals_list, preprocess=preprocess_gds, merge_polygon_size=merge_polygon_size)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
########### create model ###########
|
|
91
|
+
|
|
92
|
+
settings['simulation_ports'] = simulation_ports
|
|
93
|
+
settings['materials_list'] = materials_list
|
|
94
|
+
settings['dielectrics_list'] = dielectrics_list
|
|
95
|
+
settings['metals_list'] = metals_list
|
|
96
|
+
settings['layernumbers'] = layernumbers
|
|
97
|
+
settings['allpolygons'] = allpolygons
|
|
98
|
+
settings['sim_path'] = sim_path
|
|
99
|
+
settings['model_basename'] = model_basename
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# list of ports that are excited (set voltage to zero in port excitation to skip an excitation!)
|
|
103
|
+
excite_ports = simulation_ports.all_active_excitations()
|
|
104
|
+
config_name, data_dir = simulation_setup.create_palace (excite_ports, settings)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# for convenience, write run script to model directory
|
|
108
|
+
utilities.create_run_script(sim_path)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
if start_simulation:
|
|
112
|
+
try:
|
|
113
|
+
os.chdir(sim_path)
|
|
114
|
+
subprocess.run(run_command, shell=True)
|
|
115
|
+
except:
|
|
116
|
+
print(f"Unable to run Palace using command ",run_command)
|
|
117
|
+
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# MODEL FOR GMSH WITH PALACE
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import subprocess
|
|
6
|
+
|
|
7
|
+
# we expect gds2palace in the same directory as this model file
|
|
8
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), 'gds2palace')))
|
|
9
|
+
from gds2palace import *
|
|
10
|
+
|
|
11
|
+
# Model comments
|
|
12
|
+
#
|
|
13
|
+
# Ports: Model uses a via port that is defined between Metal1 and TopMetal2 (not using in-plane port here)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# ======================== workflow settings ================================
|
|
17
|
+
|
|
18
|
+
#start solver after creating the model?
|
|
19
|
+
start_simulation = False
|
|
20
|
+
run_command = ['./run_sim']
|
|
21
|
+
|
|
22
|
+
# ===================== input files and path settings =======================
|
|
23
|
+
|
|
24
|
+
gds_filename = "rfcmim_30x15x10_full.gds" # geometries
|
|
25
|
+
XML_filename = "SG13G2_200um.xml" # stackup
|
|
26
|
+
|
|
27
|
+
# preprocess GDSII for safe handling of cutouts/holes?
|
|
28
|
+
preprocess_gds = True
|
|
29
|
+
|
|
30
|
+
# merge via polygons with distance less than .. microns, set to 0 to disable via merging.
|
|
31
|
+
merge_polygon_size = 2
|
|
32
|
+
|
|
33
|
+
# get path for this simulation file
|
|
34
|
+
script_path = utilities.get_script_path(__file__)
|
|
35
|
+
|
|
36
|
+
# use script filename as model basename
|
|
37
|
+
model_basename = utilities.get_basename(__file__)
|
|
38
|
+
|
|
39
|
+
# set and create directory for simulation output
|
|
40
|
+
sim_path = utilities.create_sim_path (script_path,model_basename)
|
|
41
|
+
print('Simulation data directory: ', sim_path)
|
|
42
|
+
|
|
43
|
+
# change path to models script path
|
|
44
|
+
modelDir = os.path.dirname(os.path.abspath(__file__))
|
|
45
|
+
os.chdir(modelDir)
|
|
46
|
+
|
|
47
|
+
# ======================== simulation settings ================================
|
|
48
|
+
|
|
49
|
+
settings = {}
|
|
50
|
+
|
|
51
|
+
settings['unit'] = 1e-6 # geometry is in microns
|
|
52
|
+
settings['margin'] = 50 # distance in microns from GDSII geometry boundary to simulation boundary
|
|
53
|
+
|
|
54
|
+
settings['fstart'] = 0e9
|
|
55
|
+
settings['fstop'] = 100e9
|
|
56
|
+
settings['fstep'] = 1e9
|
|
57
|
+
|
|
58
|
+
settings['refined_cellsize'] = 2 # mesh cell size in conductor region
|
|
59
|
+
settings['cells_per_wavelength'] = 10 # how many mesh cells per wavelength, must be 10 or more
|
|
60
|
+
|
|
61
|
+
settings['meshsize_max'] = 70 # microns, override cells_per_wavelength
|
|
62
|
+
settings['adaptive_mesh_iterations'] = 0
|
|
63
|
+
settings['z_thickness_factor'] = 0.33
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# Ports from GDSII Data, polygon geometry from specified special layer
|
|
67
|
+
# Excitations can be switched off by voltage=0, those S-parameter will be incomplete then
|
|
68
|
+
|
|
69
|
+
simulation_ports = simulation_setup.all_simulation_ports()
|
|
70
|
+
# instead of in-plane port specified with target_layername, we here use via port specified with from_layername and to_layername
|
|
71
|
+
simulation_ports.add_port(simulation_setup.simulation_port(portnumber=1, voltage=1, port_Z0=50, source_layernum=201, from_layername='Metal1', to_layername='TopMetal1', direction='z'))
|
|
72
|
+
simulation_ports.add_port(simulation_setup.simulation_port(portnumber=2, voltage=1, port_Z0=50, source_layernum=202, from_layername='Metal1', to_layername='Metal5', direction='z'))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# ======================== simulation ================================
|
|
76
|
+
|
|
77
|
+
# get technology stackup data
|
|
78
|
+
materials_list, dielectrics_list, metals_list = stackup_reader.read_substrate (XML_filename)
|
|
79
|
+
# get list of layers from technology
|
|
80
|
+
layernumbers = metals_list.getlayernumbers()
|
|
81
|
+
layernumbers.extend(simulation_ports.portlayers)
|
|
82
|
+
|
|
83
|
+
# read geometries from GDSII, only purpose 0
|
|
84
|
+
allpolygons = gds_reader.read_gds(gds_filename, layernumbers, purposelist=[0], metals_list=metals_list, preprocess=preprocess_gds, merge_polygon_size=merge_polygon_size)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
########### create model ###########
|
|
88
|
+
|
|
89
|
+
settings['simulation_ports'] = simulation_ports
|
|
90
|
+
settings['materials_list'] = materials_list
|
|
91
|
+
settings['dielectrics_list'] = dielectrics_list
|
|
92
|
+
settings['metals_list'] = metals_list
|
|
93
|
+
settings['layernumbers'] = layernumbers
|
|
94
|
+
settings['allpolygons'] = allpolygons
|
|
95
|
+
settings['sim_path'] = sim_path
|
|
96
|
+
settings['model_basename'] = model_basename
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# list of ports that are excited (set voltage to zero in port excitation to skip an excitation!)
|
|
100
|
+
excite_ports = simulation_ports.all_active_excitations()
|
|
101
|
+
config_name, data_dir = simulation_setup.create_palace (excite_ports, settings)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# for convenience, write run script to model directory
|
|
105
|
+
utilities.create_run_script(sim_path)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
if start_simulation:
|
|
109
|
+
try:
|
|
110
|
+
os.chdir(sim_path)
|
|
111
|
+
subprocess.run(run_command, shell=True)
|
|
112
|
+
except:
|
|
113
|
+
print(f"Unable to run Palace using command ",run_command)
|
|
114
|
+
|