basicemergesolverhelperpackage 0.0.2__tar.gz → 0.0.4__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.
- {basicemergesolverhelperpackage-0.0.2 → basicemergesolverhelperpackage-0.0.4}/PKG-INFO +1 -1
- {basicemergesolverhelperpackage-0.0.2 → basicemergesolverhelperpackage-0.0.4}/setup.py +2 -2
- basicemergesolverhelperpackage-0.0.4/src/basicemergesolverhelperpackage/EMergeConstants.py +44 -0
- basicemergesolverhelperpackage-0.0.4/src/basicemergesolverhelperpackage/EMergeHelperFunctions.py +495 -0
- basicemergesolverhelperpackage-0.0.4/src/basicemergesolverhelperpackage/__init__.py +9 -0
- {basicemergesolverhelperpackage-0.0.2 → basicemergesolverhelperpackage-0.0.4}/src/basicemergesolverhelperpackage.egg-info/PKG-INFO +1 -1
- {basicemergesolverhelperpackage-0.0.2 → basicemergesolverhelperpackage-0.0.4}/src/basicemergesolverhelperpackage.egg-info/SOURCES.txt +3 -0
- basicemergesolverhelperpackage-0.0.4/src/basicemergesolverhelperpackage.egg-info/top_level.txt +1 -0
- basicemergesolverhelperpackage-0.0.2/src/basicemergesolverhelperpackage.egg-info/top_level.txt +0 -1
- {basicemergesolverhelperpackage-0.0.2 → basicemergesolverhelperpackage-0.0.4}/LICENSE +0 -0
- {basicemergesolverhelperpackage-0.0.2 → basicemergesolverhelperpackage-0.0.4}/README.md +0 -0
- {basicemergesolverhelperpackage-0.0.2 → basicemergesolverhelperpackage-0.0.4}/setup.cfg +0 -0
- {basicemergesolverhelperpackage-0.0.2 → basicemergesolverhelperpackage-0.0.4}/src/basicemergesolverhelperpackage.egg-info/dependency_links.txt +0 -0
- {basicemergesolverhelperpackage-0.0.2 → basicemergesolverhelperpackage-0.0.4}/src/basicemergesolverhelperpackage.egg-info/requires.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: basicemergesolverhelperpackage
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Mesh creation and plot utilities for EMerge solver or other FEM solver.
|
|
5
5
|
Home-page: https://github.com/LubomirJagos42/basic-emerge-solver-helper-package
|
|
6
6
|
Author: Lubomir Jagos
|
|
@@ -5,14 +5,14 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name="basicemergesolverhelperpackage",
|
|
8
|
-
version="0.0.
|
|
8
|
+
version="0.0.4",
|
|
9
9
|
author="Lubomir Jagos",
|
|
10
10
|
author_email="lubomir.jagos.42@gmail.com",
|
|
11
11
|
description="Mesh creation and plot utilities for EMerge solver or other FEM solver.",
|
|
12
12
|
long_description="Helper methods to make easier to do simulation when working with imported STEP files from FreeCAD",
|
|
13
13
|
long_description_content_type="text/markdown",
|
|
14
14
|
url="https://github.com/LubomirJagos42/basic-emerge-solver-helper-package",
|
|
15
|
-
packages=find_packages(where=
|
|
15
|
+
packages=find_packages(where="src"),
|
|
16
16
|
package_dir={"": "src"},
|
|
17
17
|
classifiers=[
|
|
18
18
|
"Programming Language :: Python :: 3",
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
m = 1.0
|
|
4
|
+
cm = 1e-2
|
|
5
|
+
mm = 1e-3
|
|
6
|
+
um = 1e-6
|
|
7
|
+
nm = 1e-9
|
|
8
|
+
|
|
9
|
+
GOhm = 1e9
|
|
10
|
+
MOhm = 1e6
|
|
11
|
+
kOhm = 1e3
|
|
12
|
+
Ohm = 1.0
|
|
13
|
+
mOhm = 1e-3
|
|
14
|
+
uOhm = 1e-6
|
|
15
|
+
|
|
16
|
+
H = 1.0
|
|
17
|
+
mH = 1e-3
|
|
18
|
+
uH = 1e-6
|
|
19
|
+
nH = 1e-9
|
|
20
|
+
pH = 1e-12
|
|
21
|
+
|
|
22
|
+
F = 1.0
|
|
23
|
+
mF = 1e-3
|
|
24
|
+
uF = 1e-6
|
|
25
|
+
nF = 1e-9
|
|
26
|
+
pF = 1e-12
|
|
27
|
+
|
|
28
|
+
class series_impedance:
|
|
29
|
+
def __init__(self, R=0.0, L=0.0, C=0.0):
|
|
30
|
+
self.R = R
|
|
31
|
+
self.L = L
|
|
32
|
+
self.C = C
|
|
33
|
+
|
|
34
|
+
def __call__(self, f):
|
|
35
|
+
return self.R + 1j*2*np.pi*f*self.L + (0.0 if self.C==0.0 else 1/(1j*2*np.pi*f*self.C))
|
|
36
|
+
|
|
37
|
+
class parallel_impedance:
|
|
38
|
+
def __init__(self, R=0.0, L=0.0, C=0.0):
|
|
39
|
+
self.R = R
|
|
40
|
+
self.L = L
|
|
41
|
+
self.C = C
|
|
42
|
+
|
|
43
|
+
def __call__(self, f):
|
|
44
|
+
return 1/((0.0 if self.R==0.0 else 1/self.R) + (0.0 if self.L==0 else 1/(1j*2*np.pi*f*self.L)) + 1j*2*np.pi*f*self.C)
|
basicemergesolverhelperpackage-0.0.4/src/basicemergesolverhelperpackage/EMergeHelperFunctions.py
ADDED
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
import emerge as em
|
|
2
|
+
import emerge._emerge.geometry as emergeGeo
|
|
3
|
+
import emerge._emerge.physics.microwave.microwave_bc as emergeMicrowaveBC
|
|
4
|
+
from typing import Callable, Literal
|
|
5
|
+
import gmsh
|
|
6
|
+
import os
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
from emerge.plot import smith, plot_sp
|
|
10
|
+
|
|
11
|
+
class EMergeHelperFunctions:
|
|
12
|
+
simulationObj = None
|
|
13
|
+
materialList = {}
|
|
14
|
+
portList = {}
|
|
15
|
+
_generatedPortIndex = 1
|
|
16
|
+
_temporaryInternalPortIndex = 1 #this shouldn't exists, but it's helper counter if port somehow will be from more objects
|
|
17
|
+
|
|
18
|
+
def __init__(self, simulationObj):
|
|
19
|
+
self.simulationObj = simulationObj
|
|
20
|
+
print("EMerge helper created")
|
|
21
|
+
|
|
22
|
+
def getAllObjectByName(self, name: str):
|
|
23
|
+
resultObjList = []
|
|
24
|
+
for geometryObj in self.simulationObj.state.manager.geometry_list[self.simulationObj.modelname].values():
|
|
25
|
+
if geometryObj.name == name or geometryObj.name.startswith(name+"_"):
|
|
26
|
+
resultObjList.append(geometryObj)
|
|
27
|
+
|
|
28
|
+
return resultObjList
|
|
29
|
+
|
|
30
|
+
def getObjectSurface(self, name: str):
|
|
31
|
+
boundaryObjList = []
|
|
32
|
+
for geometryObj in self.simulationObj.state.manager.geometry_list[self.simulationObj.modelname].values():
|
|
33
|
+
if geometryObj.name == name or geometryObj.name.startswith(name+"_"):
|
|
34
|
+
if isinstance(geometryObj, emergeGeo.GeoSurface):
|
|
35
|
+
boundaryObjList.append(geometryObj)
|
|
36
|
+
else:
|
|
37
|
+
boundaryObjList.append(geometryObj.boundary())
|
|
38
|
+
|
|
39
|
+
return boundaryObjList
|
|
40
|
+
|
|
41
|
+
def getObjectVolume(self, name: str):
|
|
42
|
+
resultObjList = []
|
|
43
|
+
for geometryObj in self.simulationObj.state.manager.geometry_list[self.simulationObj.modelname].values():
|
|
44
|
+
if geometryObj.name == name or geometryObj.name.startswith(name+"_"):
|
|
45
|
+
if isinstance(geometryObj, emergeGeo.GeoVolume):
|
|
46
|
+
resultObjList.append(geometryObj)
|
|
47
|
+
|
|
48
|
+
return resultObjList
|
|
49
|
+
|
|
50
|
+
def importStepFile(self, name:str, filename:str,directory:list[str] | str = "", unit:float=1.0, priority:int=-1, materialName:str = ""):
|
|
51
|
+
targetDirectory:str = ""
|
|
52
|
+
if directory != "" and directory != []:
|
|
53
|
+
if type(directory) == str:
|
|
54
|
+
targetDirectory = directory
|
|
55
|
+
elif type(directory) == list:
|
|
56
|
+
for dirName in directory:
|
|
57
|
+
targetDirectory = os.path.join(targetDirectory, dirName)
|
|
58
|
+
|
|
59
|
+
stepObjectGroup = em.geo.step.STEPItems(name=name, filename=os.path.join(targetDirectory, filename), unit=unit)
|
|
60
|
+
|
|
61
|
+
for geoObj in stepObjectGroup.objects:
|
|
62
|
+
geoObj.prio_set(priority)
|
|
63
|
+
if materialName != "":
|
|
64
|
+
geoObj.set_material(self.materialList[materialName])
|
|
65
|
+
|
|
66
|
+
def setObjSize(self, name:str, size:float):
|
|
67
|
+
objectList = self.getAllObjectByName(name)
|
|
68
|
+
for obj in objectList:
|
|
69
|
+
self.simulationObj.mesher.set_size(obj, size)
|
|
70
|
+
|
|
71
|
+
def setObjBoundarySize(self, name:str, size:float):
|
|
72
|
+
objectList = self.getObjectSurface(name)
|
|
73
|
+
for obj in objectList:
|
|
74
|
+
self.simulationObj.mesher.set_boundary_size(obj, size)
|
|
75
|
+
|
|
76
|
+
def setObjFaceSize(self, name:str, size:float):
|
|
77
|
+
objectList = self.getObjectSurface(name)
|
|
78
|
+
for obj in objectList:
|
|
79
|
+
self.simulationObj.mesher.set_face_size(obj, size)
|
|
80
|
+
|
|
81
|
+
def setObjVolumeSize(self, name:str, size:float):
|
|
82
|
+
objectList = self.getObjectVolume(name)
|
|
83
|
+
for obj in objectList:
|
|
84
|
+
self.simulationObj.mesher.set_domain_size(obj, size)
|
|
85
|
+
|
|
86
|
+
def setLumpedElementToObject(
|
|
87
|
+
self,
|
|
88
|
+
name: str,
|
|
89
|
+
impedance_function: Callable | None = None,
|
|
90
|
+
width: float | None = None,
|
|
91
|
+
height: float | None = None,
|
|
92
|
+
):
|
|
93
|
+
objectList = self.getObjectSurface(name)
|
|
94
|
+
for obj in objectList:
|
|
95
|
+
self.simulationObj.mw.bc.LumpedElement(face=obj, impedance_function=impedance_function, width=width, height=height)
|
|
96
|
+
|
|
97
|
+
def setBoundaryConditionToObject(self, name: str, type: str):
|
|
98
|
+
objectList = self.getObjectSurface(name)
|
|
99
|
+
for obj in objectList:
|
|
100
|
+
if type.lower() == "absorbing":
|
|
101
|
+
self.simulationObj.mw.bc.AbsorbingBoundary(obj)
|
|
102
|
+
elif type == "PEC":
|
|
103
|
+
self.simulationObj.mw.bc.PEC(obj)
|
|
104
|
+
elif type == "PMC":
|
|
105
|
+
self.simulationObj.mw.bc.PMC(obj)
|
|
106
|
+
else:
|
|
107
|
+
raise Exception(f"ERROR: Unknown type of boundary condition: {type}")
|
|
108
|
+
|
|
109
|
+
def createGmshNamedGroup(self, geometryObjName: str, groupName: str, groupTag: int = -1, useBoundary: bool = False, useSuffixToRecognizeGeometryName: bool = True):
|
|
110
|
+
objectTag1DList = []
|
|
111
|
+
objectTag2DList = []
|
|
112
|
+
objectTag3DList = []
|
|
113
|
+
|
|
114
|
+
for geometryObj in self.simulationObj.state.manager.geometry_list[self.simulationObj.modelname].values():
|
|
115
|
+
if geometryObj.name == geometryObjName or geometryObj.name.startswith(geometryObjName + ('_' if useSuffixToRecognizeGeometryName else '')):
|
|
116
|
+
for tagTuple in (geometryObj.boundary().dimtags if (useBoundary and not isinstance(geometryObj, emergeGeo.GeoSurface)) else geometryObj.dimtags):
|
|
117
|
+
if tagTuple[0] == 1:
|
|
118
|
+
objectTag1DList.append(tagTuple[1])
|
|
119
|
+
if tagTuple[0] == 2:
|
|
120
|
+
objectTag2DList.append(tagTuple[1])
|
|
121
|
+
if tagTuple[0] == 3:
|
|
122
|
+
objectTag3DList.append(tagTuple[1])
|
|
123
|
+
|
|
124
|
+
if groupTag > -1:
|
|
125
|
+
gmsh.model.addPhysicalGroup(1, objectTag1DList, name=groupName, tag=groupTag)
|
|
126
|
+
gmsh.model.addPhysicalGroup(2, objectTag2DList, name=groupName, tag=groupTag + 1)
|
|
127
|
+
gmsh.model.addPhysicalGroup(3, objectTag3DList, name=groupName, tag=groupTag + 2)
|
|
128
|
+
else:
|
|
129
|
+
gmsh.model.addPhysicalGroup(1, objectTag1DList, name=groupName)
|
|
130
|
+
gmsh.model.addPhysicalGroup(2, objectTag2DList, name=groupName)
|
|
131
|
+
gmsh.model.addPhysicalGroup(3, objectTag3DList, name=groupName)
|
|
132
|
+
|
|
133
|
+
def addMaterial(self, name, materialObj, color="#000000", opacity: float = 1.0):
|
|
134
|
+
self.materialList[name] = materialObj
|
|
135
|
+
self.materialList[name].color = color
|
|
136
|
+
self.materialList[name].opacity = opacity
|
|
137
|
+
|
|
138
|
+
def getMaterial(self, name):
|
|
139
|
+
#
|
|
140
|
+
# Get material from internal material list
|
|
141
|
+
#
|
|
142
|
+
materialObj = self.materialList[name] if name in self.materialList.keys() else None
|
|
143
|
+
|
|
144
|
+
#
|
|
145
|
+
# If material not found try to scan all geometries and their assigned materials if it will be found
|
|
146
|
+
#
|
|
147
|
+
if materialObj == None:
|
|
148
|
+
for geometryObj in self.simulationObj.state.manager.geometry_list[self.simulationObj.modelname].values():
|
|
149
|
+
if geometryObj.material.name == name:
|
|
150
|
+
materialObj = geometryObj.material
|
|
151
|
+
break
|
|
152
|
+
|
|
153
|
+
return materialObj
|
|
154
|
+
|
|
155
|
+
def setMaterialColor(self, name, color="#000000", opacity: float = 1.0):
|
|
156
|
+
"""Setter for color and opacity
|
|
157
|
+
:param name: Name of material
|
|
158
|
+
:param color: Color string in html for like #FF0000 (red)
|
|
159
|
+
:param opacity: Makes material transparent (0.0) or non-transparent (1.0)
|
|
160
|
+
"""
|
|
161
|
+
self.materialList[name].color = color
|
|
162
|
+
self.materialList[name].opacity = opacity
|
|
163
|
+
|
|
164
|
+
def addPort(
|
|
165
|
+
self,
|
|
166
|
+
name="",
|
|
167
|
+
portStart=[0.0, 0.0, 0.0],
|
|
168
|
+
width=0.0,
|
|
169
|
+
height=0.0,
|
|
170
|
+
R=50.0,
|
|
171
|
+
direction=em.ZAX,
|
|
172
|
+
excitationAmplitude:float=0.0,
|
|
173
|
+
geometryObject:em._emerge.geometry.GeoObject=None,
|
|
174
|
+
portNumber:int=-1,
|
|
175
|
+
|
|
176
|
+
modalModeType: Literal['TE','TM','TEM'] | None = None,
|
|
177
|
+
modalMixedMaterials: bool = False,
|
|
178
|
+
modalImpedanceDefinition: Literal['PV','PI','VI'] = 'PV',
|
|
179
|
+
|
|
180
|
+
rectangularWaveguideMode: tuple[int, int] = (0, 0),
|
|
181
|
+
rectangularWaveguidePermittivity: float = 1.0,
|
|
182
|
+
|
|
183
|
+
coaxPortInnerRadius: float = 0.0,
|
|
184
|
+
coaxPortOuterRadius: float = 0.0,
|
|
185
|
+
coaxPortPermittivity: float = 1.0,
|
|
186
|
+
):
|
|
187
|
+
self.portList[name] = {}
|
|
188
|
+
self.portList[name]['portStart'] = portStart
|
|
189
|
+
self.portList[name]['width'] = width
|
|
190
|
+
self.portList[name]['height'] = height
|
|
191
|
+
self.portList[name]['R'] = R
|
|
192
|
+
self.portList[name]['direction'] = direction
|
|
193
|
+
self.portList[name]['excitationAmplitude'] = excitationAmplitude
|
|
194
|
+
self.portList[name]['object'] = geometryObject
|
|
195
|
+
self.portList[name]['portNumber'] = self._generatedPortIndex if portNumber == -1 else portNumber
|
|
196
|
+
|
|
197
|
+
self.portList[name]["modalModeType"] = modalModeType
|
|
198
|
+
self.portList[name]["modalMixedMaterials"] = modalMixedMaterials
|
|
199
|
+
self.portList[name]["modalImpedanceDefinition"] = modalImpedanceDefinition
|
|
200
|
+
|
|
201
|
+
self.portList[name]["rectangularWaveguideMode"] = rectangularWaveguideMode
|
|
202
|
+
self.portList[name]["rectangularWaveguidePermittivity"] = rectangularWaveguidePermittivity
|
|
203
|
+
|
|
204
|
+
self.portList[name]["coaxPortInnerRadius"] = coaxPortInnerRadius
|
|
205
|
+
self.portList[name]["coaxPortOuterRadius"] = coaxPortOuterRadius
|
|
206
|
+
self.portList[name]["coaxPortPermittivity"] = coaxPortPermittivity
|
|
207
|
+
|
|
208
|
+
if portNumber == -1:
|
|
209
|
+
self._generatedPortIndex += 1
|
|
210
|
+
|
|
211
|
+
def addLumpedPort(
|
|
212
|
+
self,
|
|
213
|
+
name = "",
|
|
214
|
+
portStart = [0.0, 0.0, 0.0],
|
|
215
|
+
width = 0.0,
|
|
216
|
+
height = 0.0,
|
|
217
|
+
R = 50.0,
|
|
218
|
+
direction = em.ZAX,
|
|
219
|
+
power:float = 0.0,
|
|
220
|
+
geometryObject:em._emerge.geometry.GeoObject = None,
|
|
221
|
+
portNumber:int = -1
|
|
222
|
+
):
|
|
223
|
+
self.addPort(
|
|
224
|
+
name=name,
|
|
225
|
+
portStart=portStart,
|
|
226
|
+
width=width,
|
|
227
|
+
height=height,
|
|
228
|
+
R=R,
|
|
229
|
+
direction=direction,
|
|
230
|
+
excitationAmplitude=power,
|
|
231
|
+
geometryObject=geometryObject,
|
|
232
|
+
portNumber=portNumber
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
def addModalPort(
|
|
236
|
+
self,
|
|
237
|
+
name = "",
|
|
238
|
+
mode: Literal["TE", "TM", "TEM"] = "TE",
|
|
239
|
+
mixedMaterials: bool = False,
|
|
240
|
+
impedanceDefinition: Literal["PV", "PI", "VI"] = "PV",
|
|
241
|
+
power:float = 0.0,
|
|
242
|
+
geometryObject:em._emerge.geometry.GeoObject = None,
|
|
243
|
+
portNumber:int = -1
|
|
244
|
+
):
|
|
245
|
+
self.addPort(
|
|
246
|
+
name=name,
|
|
247
|
+
modalModeType=mode,
|
|
248
|
+
modalMixedMaterials=mixedMaterials,
|
|
249
|
+
modalImpedanceDefinition=impedanceDefinition,
|
|
250
|
+
excitationAmplitude=power,
|
|
251
|
+
geometryObject=geometryObject,
|
|
252
|
+
portNumber=portNumber
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
def addRectangularWaveguidePort(
|
|
256
|
+
self,
|
|
257
|
+
name = "",
|
|
258
|
+
mode: tuple[int, int] = (0,0),
|
|
259
|
+
er: float = 1.0,
|
|
260
|
+
power:float = 1.0,
|
|
261
|
+
geometryObject:em._emerge.geometry.GeoObject = None,
|
|
262
|
+
portNumber:int = -1
|
|
263
|
+
):
|
|
264
|
+
self.addPort(
|
|
265
|
+
name=name,
|
|
266
|
+
rectangularWaveguideMode = mode,
|
|
267
|
+
rectangularWaveguidePermittivity = er,
|
|
268
|
+
excitationAmplitude=power,
|
|
269
|
+
geometryObject=geometryObject,
|
|
270
|
+
portNumber=portNumber
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
def addCoaxPort(
|
|
274
|
+
self,
|
|
275
|
+
name = "",
|
|
276
|
+
inner_radius: float = 0.0,
|
|
277
|
+
outer_radius: float = 0.0,
|
|
278
|
+
er: float = 1.0,
|
|
279
|
+
power:float = 1.0,
|
|
280
|
+
geometryObject:em._emerge.geometry.GeoObject = None,
|
|
281
|
+
portNumber:int = -1
|
|
282
|
+
):
|
|
283
|
+
self.addPort(
|
|
284
|
+
name=name,
|
|
285
|
+
coaxPortInnerRadius = inner_radius,
|
|
286
|
+
coaxPortOuterRadius = outer_radius,
|
|
287
|
+
coaxPortPermittivity = er,
|
|
288
|
+
excitationAmplitude=power,
|
|
289
|
+
geometryObject=geometryObject,
|
|
290
|
+
portNumber=portNumber
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def getPort(self, name):
|
|
295
|
+
return self.portList[name]
|
|
296
|
+
|
|
297
|
+
def getPortByNumber(self, portNumber):
|
|
298
|
+
resultPortObj = None
|
|
299
|
+
for portObj in self.portList:
|
|
300
|
+
if portNumber == portObj['portNumber']:
|
|
301
|
+
resultPortObj = portObj
|
|
302
|
+
return resultPortObj
|
|
303
|
+
|
|
304
|
+
def getPortNumber(self, name):
|
|
305
|
+
for portObj in self.portList:
|
|
306
|
+
if portObj['portNumber'] == name:
|
|
307
|
+
return portObj['portNumber']
|
|
308
|
+
|
|
309
|
+
def setPortAsLumpedPort(self, name, searchObjectName="") -> list[emergeMicrowaveBC.LumpedPort]:
|
|
310
|
+
portObj = self.getPort(name)
|
|
311
|
+
resultBoundaryConditionList = []
|
|
312
|
+
|
|
313
|
+
#
|
|
314
|
+
# Port object can be splitted since there was fragmentation operation in EMerge
|
|
315
|
+
#
|
|
316
|
+
portGeometryObjectList = self.getAllObjectByName(name if searchObjectName == "" else searchObjectName)
|
|
317
|
+
for geometryObj in portGeometryObjectList:
|
|
318
|
+
if portObj['excitationAmplitude'] > 0.0:
|
|
319
|
+
resultObj = self.simulationObj.mw.bc.LumpedPort(
|
|
320
|
+
face=geometryObj,
|
|
321
|
+
port_number=portObj['portNumber'],
|
|
322
|
+
width=portObj['width'],
|
|
323
|
+
height=portObj['height'],
|
|
324
|
+
direction=portObj['direction'],
|
|
325
|
+
Z0=portObj['R'],
|
|
326
|
+
power=portObj['excitationAmplitude']
|
|
327
|
+
)
|
|
328
|
+
else:
|
|
329
|
+
resultObj = self.simulationObj.mw.bc.LumpedPort(
|
|
330
|
+
face=geometryObj,
|
|
331
|
+
port_number=portObj['portNumber'],
|
|
332
|
+
width=portObj['width'],
|
|
333
|
+
height=portObj['height'],
|
|
334
|
+
direction=portObj['direction'],
|
|
335
|
+
Z0=portObj['R']
|
|
336
|
+
)
|
|
337
|
+
resultBoundaryConditionList.append(resultObj)
|
|
338
|
+
|
|
339
|
+
self._temporaryInternalPortIndex += 1
|
|
340
|
+
|
|
341
|
+
return resultBoundaryConditionList
|
|
342
|
+
|
|
343
|
+
def setPortAsModalPort(self, name, searchObjectName="") -> list[emergeMicrowaveBC.ModalPort]:
|
|
344
|
+
"""Experimental implementation not tested on real world example!!!"""
|
|
345
|
+
|
|
346
|
+
resultBoundaryConditionList = []
|
|
347
|
+
|
|
348
|
+
portObj = self.getPort(name)
|
|
349
|
+
portGeometryObjectList = self.getAllObjectByName(name if searchObjectName == "" else searchObjectName)
|
|
350
|
+
|
|
351
|
+
for geometryObj in portGeometryObjectList:
|
|
352
|
+
resultObj = self.simulationObj.mw.bc.ModalPort(
|
|
353
|
+
face = geometryObj,
|
|
354
|
+
port_number=portObj['portNumber'],
|
|
355
|
+
power = portObj['excitationAmplitude'],
|
|
356
|
+
modetype = portObj["modalModeType"],
|
|
357
|
+
number_of_modes = 1,
|
|
358
|
+
mixed_materials = portObj["modalMixedMaterials"],
|
|
359
|
+
impedance_definition = portObj["modalImpedanceDefinition"]
|
|
360
|
+
)
|
|
361
|
+
resultBoundaryConditionList.append(resultObj)
|
|
362
|
+
|
|
363
|
+
return resultBoundaryConditionList
|
|
364
|
+
|
|
365
|
+
def setPortAsRectangularWaveguidePort(self, name, searchObjectName="") -> list[emergeMicrowaveBC.RectangularWaveguide]:
|
|
366
|
+
"""Experimental implementation not tested on real world example!!!"""
|
|
367
|
+
|
|
368
|
+
resultBoundaryConditionList = []
|
|
369
|
+
|
|
370
|
+
portObj = self.getPort(name)
|
|
371
|
+
portGeometryObjectList = self.getAllObjectByName(name if searchObjectName == "" else searchObjectName)
|
|
372
|
+
|
|
373
|
+
for geometryObj in portGeometryObjectList:
|
|
374
|
+
resultObj = self.simulationObj.mw.bc.RectangularWaveguide(
|
|
375
|
+
face = geometryObj,
|
|
376
|
+
port_number=portObj['portNumber'],
|
|
377
|
+
power = portObj['excitationAmplitude'],
|
|
378
|
+
mode = portObj["rectangularWaveguideMode"],
|
|
379
|
+
er = portObj["rectangularWaveguidePermittivity"]
|
|
380
|
+
)
|
|
381
|
+
resultBoundaryConditionList.append(resultObj)
|
|
382
|
+
|
|
383
|
+
return resultBoundaryConditionList
|
|
384
|
+
|
|
385
|
+
def setPortAsCoaxPort(self, name, searchObjectName="") -> list[emergeMicrowaveBC.CoaxPort]:
|
|
386
|
+
"""Experimental implementation not tested on real world example!!!"""
|
|
387
|
+
|
|
388
|
+
resultBoundaryConditionList = []
|
|
389
|
+
|
|
390
|
+
portObj = self.getPort(name)
|
|
391
|
+
portGeometryObjectList = self.getAllObjectByName(name if searchObjectName == "" else searchObjectName)
|
|
392
|
+
|
|
393
|
+
for geometryObj in portGeometryObjectList:
|
|
394
|
+
resultObj = self.simulationObj.mw.bc.CoaxPort(
|
|
395
|
+
face = geometryObj,
|
|
396
|
+
port_number=portObj['portNumber'],
|
|
397
|
+
power = portObj['excitationAmplitude'],
|
|
398
|
+
rad_in_out = (portObj["coaxPortInnerRadius"], portObj["coaxPortInnerRadius"]),
|
|
399
|
+
er = portObj["coaxPortPermittivity"]
|
|
400
|
+
)
|
|
401
|
+
resultBoundaryConditionList.append(resultObj)
|
|
402
|
+
|
|
403
|
+
return resultBoundaryConditionList
|
|
404
|
+
|
|
405
|
+
def plotSParamUsingPortName(self, sourcePortName, targetPortName, dblim=[-40, 0], plotSmithChart=False):
|
|
406
|
+
sourcePortNumber = self.getPortNumber(sourcePortName)
|
|
407
|
+
targetPortNumber = self.getPortNumber(targetPortName)
|
|
408
|
+
|
|
409
|
+
self.plotSParamUsingPortNumbers(sourcePortNumber, targetPortNumber, dblim, plotSmithChart)
|
|
410
|
+
|
|
411
|
+
def plotSParamUsingPortNumbers(self, sourcePortNumber, targetPortNumber, dblim=[-40, 0], xunit="GHz", plotSmithChart=False, plotInterpolatedPoints:int=-1, plotS11=False):
|
|
412
|
+
simulationResult = self.simulationObj.data.mw
|
|
413
|
+
|
|
414
|
+
freqs = simulationResult.scalar.grid.freq
|
|
415
|
+
fmin = freqs.min()
|
|
416
|
+
fmax = freqs.max()
|
|
417
|
+
|
|
418
|
+
if plotInterpolatedPoints > 0:
|
|
419
|
+
#
|
|
420
|
+
# Add points into frequency axis and interpolate computed S param over these points it makes graph line smooth but it can provide wrong result!!!
|
|
421
|
+
#
|
|
422
|
+
freq_dense = np.linspace(fmin, fmax, plotInterpolatedPoints)
|
|
423
|
+
S_data = simulationResult.scalar.grid.model_S(sourcePortNumber, targetPortNumber, freq_dense)
|
|
424
|
+
plotLabel = f'S{sourcePortNumber}{targetPortNumber}'
|
|
425
|
+
plot_sp(freq_dense, S_data, labels=plotLabel, dblim=dblim)
|
|
426
|
+
else:
|
|
427
|
+
S21_data = simulationResult.scalar.grid.S(sourcePortNumber, targetPortNumber)
|
|
428
|
+
S11_data = simulationResult.scalar.grid.S(sourcePortNumber, sourcePortNumber)
|
|
429
|
+
plotLabel_S11 = f'S{sourcePortNumber}{sourcePortNumber}'
|
|
430
|
+
plotLabel_S21 = f'S{targetPortNumber}{sourcePortNumber}'
|
|
431
|
+
if plotS11:
|
|
432
|
+
plot_sp(freqs, [S11_data, S21_data], labels=[plotLabel_S11, plotLabel_S21], dblim=dblim, xunit=xunit)
|
|
433
|
+
else:
|
|
434
|
+
plot_sp(freqs, [S21_data], labels=[plotLabel_S21], dblim=dblim, xunit=xunit)
|
|
435
|
+
|
|
436
|
+
if plotSmithChart:
|
|
437
|
+
smith(S_data, f=freq_dense, labels=plotLabel) # smith chart
|
|
438
|
+
|
|
439
|
+
def addObjectToView(self, nameOrList: str | list, opacity:float=0.1):
|
|
440
|
+
objectList = []
|
|
441
|
+
if type(nameOrList) == str:
|
|
442
|
+
objectList = self.getAllObjectByName(nameOrList)
|
|
443
|
+
if type(nameOrList) == list:
|
|
444
|
+
for oneName in nameOrList:
|
|
445
|
+
objectList.extend(self.getAllObjectByName(oneName))
|
|
446
|
+
|
|
447
|
+
for geoObject in objectList:
|
|
448
|
+
self.simulationObj.display.add_object(geoObject, opacity=opacity)
|
|
449
|
+
|
|
450
|
+
def create_emerge_plane_data(self, port_start, port_stop, normal):
|
|
451
|
+
"""
|
|
452
|
+
Computes origin, u, and v vectors for an EMerge Plane using
|
|
453
|
+
start/stop diagonal points and a surface normal vector.
|
|
454
|
+
|
|
455
|
+
Inputs can be FreeCAD vectors or standard (x, y, z) tuples.
|
|
456
|
+
"""
|
|
457
|
+
# 1. Convert everything to numpy arrays for clean math
|
|
458
|
+
p1 = np.array([port_start[0], port_start[1], port_start[2]])
|
|
459
|
+
p4 = np.array([port_stop[0], port_stop[1], port_stop[2]])
|
|
460
|
+
n = np.array([normal[0], normal[1], normal[2]])
|
|
461
|
+
|
|
462
|
+
# Normalize the normal vector to ensure it is a unit vector
|
|
463
|
+
n = n / np.linalg.norm(n)
|
|
464
|
+
|
|
465
|
+
# 2. Calculate the full diagonal vector across the port
|
|
466
|
+
diag = p4 - p1
|
|
467
|
+
|
|
468
|
+
# 3. Project the diagonal vector to eliminate any component pointing
|
|
469
|
+
# along the normal (ensures the math stays strictly flat on the 2D plane)
|
|
470
|
+
diag_planar = diag - np.dot(diag, n) * n
|
|
471
|
+
|
|
472
|
+
# 4. Determine the primary coordinate alignment for the 'u' axis.
|
|
473
|
+
# We choose an axis that isn't parallel to our normal vector.
|
|
474
|
+
if abs(n[0]) < 0.9:
|
|
475
|
+
ref_dir = np.array([1.0, 0.0, 0.0]) # Fallback to X axis alignment
|
|
476
|
+
else:
|
|
477
|
+
ref_dir = np.array([0.0, 1.0, 0.0]) # Fallback to Y axis alignment
|
|
478
|
+
|
|
479
|
+
# Generate an orthogonal direction for 'u' using a cross product
|
|
480
|
+
u_direction = np.cross(n, ref_dir)
|
|
481
|
+
u_axis = u_direction / np.linalg.norm(u_direction)
|
|
482
|
+
|
|
483
|
+
# Generate the perpendicular 'v' direction
|
|
484
|
+
v_axis = np.cross(n, u_axis)
|
|
485
|
+
|
|
486
|
+
# 5. Project the planar diagonal onto our newly established u and v axes
|
|
487
|
+
u_magnitude = np.dot(diag_planar, u_axis)
|
|
488
|
+
v_magnitude = np.dot(diag_planar, v_axis)
|
|
489
|
+
|
|
490
|
+
# 6. Reconstruct the final u and v vectors as clean 3D tuples
|
|
491
|
+
u = tuple(u_axis * u_magnitude)
|
|
492
|
+
v = tuple(v_axis * v_magnitude)
|
|
493
|
+
origin = tuple(p1)
|
|
494
|
+
|
|
495
|
+
return origin, u, v
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: basicemergesolverhelperpackage
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Mesh creation and plot utilities for EMerge solver or other FEM solver.
|
|
5
5
|
Home-page: https://github.com/LubomirJagos42/basic-emerge-solver-helper-package
|
|
6
6
|
Author: Lubomir Jagos
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
LICENSE
|
|
2
2
|
README.md
|
|
3
3
|
setup.py
|
|
4
|
+
src/basicemergesolverhelperpackage/EMergeConstants.py
|
|
5
|
+
src/basicemergesolverhelperpackage/EMergeHelperFunctions.py
|
|
6
|
+
src/basicemergesolverhelperpackage/__init__.py
|
|
4
7
|
src/basicemergesolverhelperpackage.egg-info/PKG-INFO
|
|
5
8
|
src/basicemergesolverhelperpackage.egg-info/SOURCES.txt
|
|
6
9
|
src/basicemergesolverhelperpackage.egg-info/dependency_links.txt
|
basicemergesolverhelperpackage-0.0.4/src/basicemergesolverhelperpackage.egg-info/top_level.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
basicemergesolverhelperpackage
|
basicemergesolverhelperpackage-0.0.2/src/basicemergesolverhelperpackage.egg-info/top_level.txt
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|