emerge 0.6.5__py3-none-any.whl → 0.6.7__py3-none-any.whl
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.
Potentially problematic release.
This version of emerge might be problematic. Click here for more details.
- emerge/__init__.py +2 -1
- emerge/_emerge/geo/__init__.py +1 -1
- emerge/_emerge/geo/operations.py +97 -23
- emerge/_emerge/geo/pcb.py +54 -14
- emerge/_emerge/geo/shapes.py +101 -30
- emerge/_emerge/geometry.py +45 -14
- emerge/_emerge/howto.py +1 -1
- emerge/_emerge/physics/microwave/microwave_bc.py +2 -4
- emerge/_emerge/physics/microwave/microwave_data.py +13 -0
- emerge/_emerge/plot/pyvista/display.py +113 -15
- emerge/_emerge/selection.py +1 -0
- emerge/_emerge/simmodel.py +10 -8
- emerge/_emerge/solver.py +4 -4
- {emerge-0.6.5.dist-info → emerge-0.6.7.dist-info}/METADATA +1 -1
- {emerge-0.6.5.dist-info → emerge-0.6.7.dist-info}/RECORD +18 -18
- {emerge-0.6.5.dist-info → emerge-0.6.7.dist-info}/WHEEL +0 -0
- {emerge-0.6.5.dist-info → emerge-0.6.7.dist-info}/entry_points.txt +0 -0
- {emerge-0.6.5.dist-info → emerge-0.6.7.dist-info}/licenses/LICENSE +0 -0
emerge/__init__.py
CHANGED
|
@@ -18,7 +18,7 @@ along with this program; if not, see
|
|
|
18
18
|
"""
|
|
19
19
|
import os
|
|
20
20
|
|
|
21
|
-
__version__ = "0.6.
|
|
21
|
+
__version__ = "0.6.7"
|
|
22
22
|
|
|
23
23
|
############################################################
|
|
24
24
|
# HANDLE ENVIRONMENT VARIABLES #
|
|
@@ -52,6 +52,7 @@ from ._emerge.cs import CoordinateSystem, CS, GCS, Plane, Axis, XAX, YAX, ZAX, X
|
|
|
52
52
|
from ._emerge.coord import Line
|
|
53
53
|
from ._emerge import geo
|
|
54
54
|
from ._emerge.selection import Selection, FaceSelection, DomainSelection, EdgeSelection
|
|
55
|
+
from ._emerge.geometry import select
|
|
55
56
|
from ._emerge.mth.common_functions import norm, coax_rout, coax_rin
|
|
56
57
|
from ._emerge.physics.microwave.sc import stratton_chu
|
|
57
58
|
from ._emerge.periodic import RectCell, HexCell
|
emerge/_emerge/geo/__init__.py
CHANGED
|
@@ -19,6 +19,6 @@ from .pcb import PCB
|
|
|
19
19
|
from .pmlbox import pmlbox
|
|
20
20
|
from .horn import Horn
|
|
21
21
|
from .shapes import Cylinder, CoaxCylinder, Box, XYPlate, HalfSphere, Sphere, Plate, OldBox, Alignment, Cone
|
|
22
|
-
from .operations import subtract, add, embed, remove, rotate, mirror, change_coordinate_system, translate, intersect
|
|
22
|
+
from .operations import subtract, add, embed, remove, rotate, mirror, change_coordinate_system, translate, intersect, unite, expand_surface
|
|
23
23
|
from .polybased import XYPolygon, GeoPrism, Disc, Curve
|
|
24
24
|
from .step import STEPItems
|
emerge/_emerge/geo/operations.py
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
# along with this program; if not, see
|
|
16
16
|
# <https://www.gnu.org/licenses/>.
|
|
17
17
|
|
|
18
|
-
from typing import TypeVar
|
|
19
|
-
from ..geometry import GeoSurface, GeoVolume, GeoObject, GeoPoint, GeoEdge
|
|
18
|
+
from typing import TypeVar, overload
|
|
19
|
+
from ..geometry import GeoSurface, GeoVolume, GeoObject, GeoPoint, GeoEdge, GeoPolygon
|
|
20
20
|
from ..cs import CoordinateSystem, GCS
|
|
21
21
|
import gmsh
|
|
22
22
|
import numpy as np
|
|
@@ -60,7 +60,7 @@ def add(main: T, tool: T,
|
|
|
60
60
|
main._exists = False
|
|
61
61
|
if remove_tool:
|
|
62
62
|
tool._exists = False
|
|
63
|
-
return output # type: ignore
|
|
63
|
+
return output.set_material(main.material) # type: ignore
|
|
64
64
|
|
|
65
65
|
def remove(main: T, tool: T,
|
|
66
66
|
remove_object: bool = True,
|
|
@@ -90,7 +90,7 @@ def remove(main: T, tool: T,
|
|
|
90
90
|
main._exists = False
|
|
91
91
|
if remove_tool:
|
|
92
92
|
tool._exists = False
|
|
93
|
-
return output # type: ignore
|
|
93
|
+
return output.set_material(main.material) # type: ignore
|
|
94
94
|
|
|
95
95
|
subtract = remove
|
|
96
96
|
|
|
@@ -122,7 +122,7 @@ def intersect(main: T, tool: T,
|
|
|
122
122
|
main._exists = False
|
|
123
123
|
if remove_tool:
|
|
124
124
|
tool._exists = False
|
|
125
|
-
return output #type:ignore
|
|
125
|
+
return output.set_material(main.material) #type:ignore
|
|
126
126
|
|
|
127
127
|
def embed(main: GeoVolume, other: GeoSurface) -> None:
|
|
128
128
|
''' Embeds a surface into a volume in the GMSH model.
|
|
@@ -144,7 +144,8 @@ def rotate(main: GeoVolume,
|
|
|
144
144
|
c0: tuple[float, float, float],
|
|
145
145
|
ax: tuple[float, float, float],
|
|
146
146
|
angle: float,
|
|
147
|
-
|
|
147
|
+
make_copy: bool = False,
|
|
148
|
+
degree=True) -> GeoObject:
|
|
148
149
|
"""Rotates a GeoVolume object around an axist defined at a coordinate.
|
|
149
150
|
|
|
150
151
|
Args:
|
|
@@ -159,17 +160,23 @@ def rotate(main: GeoVolume,
|
|
|
159
160
|
"""
|
|
160
161
|
if degree:
|
|
161
162
|
angle = angle * np.pi/180
|
|
162
|
-
|
|
163
|
-
|
|
163
|
+
|
|
164
|
+
if make_copy:
|
|
165
|
+
rotate_obj = main.make_copy()
|
|
166
|
+
else:
|
|
167
|
+
rotate_obj = main
|
|
168
|
+
|
|
169
|
+
gmsh.model.occ.rotate(rotate_obj.dimtags, *c0, *ax, -angle)
|
|
164
170
|
# Rotate the facepointers
|
|
165
|
-
for fp in
|
|
171
|
+
for fp in rotate_obj._all_pointers:
|
|
166
172
|
fp.rotate(c0, ax, angle)
|
|
167
|
-
return
|
|
173
|
+
return rotate_obj
|
|
168
174
|
|
|
169
175
|
def translate(main: GeoVolume,
|
|
170
176
|
dx: float = 0,
|
|
171
177
|
dy: float = 0,
|
|
172
|
-
dz: float = 0
|
|
178
|
+
dz: float = 0,
|
|
179
|
+
make_copy: bool = False) -> GeoObject:
|
|
173
180
|
"""Translates the GeoVolume object along a given displacement
|
|
174
181
|
|
|
175
182
|
Args:
|
|
@@ -177,17 +184,23 @@ def translate(main: GeoVolume,
|
|
|
177
184
|
dx (float, optional): The X-displacement in meters. Defaults to 0.
|
|
178
185
|
dy (float, optional): The Y-displacement in meters. Defaults to 0.
|
|
179
186
|
dz (float, optional): The Z-displacement in meters. Defaults to 0.
|
|
187
|
+
make_copy (bool, optional): Whether to make a copy first before translating.
|
|
180
188
|
|
|
181
189
|
Returns:
|
|
182
|
-
|
|
190
|
+
GeoObject: The translated object
|
|
183
191
|
"""
|
|
184
|
-
|
|
192
|
+
|
|
193
|
+
if make_copy:
|
|
194
|
+
trans_obj = main.make_copy()
|
|
195
|
+
else:
|
|
196
|
+
trans_obj = main
|
|
197
|
+
gmsh.model.occ.translate(trans_obj.dimtags, dx, dy, dz)
|
|
185
198
|
|
|
186
199
|
# Rotate the facepointers
|
|
187
|
-
for fp in
|
|
200
|
+
for fp in trans_obj._all_pointers:
|
|
188
201
|
fp.translate(dx, dy, dz)
|
|
189
202
|
|
|
190
|
-
return
|
|
203
|
+
return trans_obj
|
|
191
204
|
|
|
192
205
|
def mirror(main: GeoObject,
|
|
193
206
|
origin: tuple[float, float, float] = (0.0, 0.0, 0.0),
|
|
@@ -199,6 +212,7 @@ def mirror(main: GeoObject,
|
|
|
199
212
|
main (GeoVolume): The object to mirror
|
|
200
213
|
origin (tuple[float, float, float], optional): The point of origin in meters. Defaults to (0.0, 0.0, 0.0).
|
|
201
214
|
direction (tuple[float, float, float], optional): The normal axis defining the plane of reflection. Defaults to (1.0, 0.0, 0.0).
|
|
215
|
+
make_copy (bool, optional): Whether to make a copy first before mirroring.
|
|
202
216
|
|
|
203
217
|
Returns:
|
|
204
218
|
GeoVolume: The mirrored GeoVolume object
|
|
@@ -211,14 +225,12 @@ def mirror(main: GeoObject,
|
|
|
211
225
|
d = -(a*x0 + b*y0 + c*z0)
|
|
212
226
|
if (a==0) and (b==0) and (c==0):
|
|
213
227
|
return main
|
|
228
|
+
|
|
214
229
|
mirror_obj = main
|
|
215
230
|
if make_copy:
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
else:
|
|
220
|
-
gmsh.model.occ.mirror(main.dimtags, a,b,c,d)
|
|
221
|
-
|
|
231
|
+
mirror_obj = main.make_copy()
|
|
232
|
+
gmsh.model.occ.mirror(mirror_obj.dimtags, a,b,c,d)
|
|
233
|
+
|
|
222
234
|
for fp in mirror_obj._all_pointers:
|
|
223
235
|
fp.mirror(origin, direction)
|
|
224
236
|
return mirror_obj
|
|
@@ -237,7 +249,7 @@ def change_coordinate_system(main: GeoObject,
|
|
|
237
249
|
old_cs (CoordinateSystem, optional): The old coordinate system. Defaults to GCS.
|
|
238
250
|
|
|
239
251
|
Returns:
|
|
240
|
-
|
|
252
|
+
GeoObject: The output object
|
|
241
253
|
"""
|
|
242
254
|
if new_cs._is_global and old_cs._is_global:
|
|
243
255
|
return main
|
|
@@ -254,4 +266,66 @@ def change_coordinate_system(main: GeoObject,
|
|
|
254
266
|
for fp in main._all_pointers:
|
|
255
267
|
fp.affine_transform(M1)
|
|
256
268
|
fp.affine_transform(M2)
|
|
257
|
-
return main
|
|
269
|
+
return main
|
|
270
|
+
|
|
271
|
+
@overload
|
|
272
|
+
def unite(*objects: GeoVolume) -> GeoVolume: ...
|
|
273
|
+
|
|
274
|
+
@overload
|
|
275
|
+
def unite(*objects: GeoSurface) -> GeoSurface: ...
|
|
276
|
+
|
|
277
|
+
@overload
|
|
278
|
+
def unite(*objects: GeoEdge) -> GeoEdge: ...
|
|
279
|
+
|
|
280
|
+
@overload
|
|
281
|
+
def unite(*objects: GeoPolygon) -> GeoSurface: ...
|
|
282
|
+
|
|
283
|
+
def unite(*objects: GeoObject) -> GeoObject:
|
|
284
|
+
"""Applies a fusion consisting of all geometries in the argument.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
GeoObject: The resultant object
|
|
288
|
+
"""
|
|
289
|
+
main, *rest = objects
|
|
290
|
+
if not rest:
|
|
291
|
+
return main
|
|
292
|
+
main._exists = False
|
|
293
|
+
dts = []
|
|
294
|
+
for other in rest:
|
|
295
|
+
dts.extend(other.dimtags)
|
|
296
|
+
other._exists = False
|
|
297
|
+
|
|
298
|
+
new_dimtags, mapping = gmsh.model.occ.fuse(main.dimtags, dts)
|
|
299
|
+
|
|
300
|
+
new_obj = GeoObject.from_dimtags(new_dimtags)._take_tools(*objects)
|
|
301
|
+
new_obj.set_material(main.material)
|
|
302
|
+
new_obj.prio_set(main._priority)
|
|
303
|
+
|
|
304
|
+
return new_obj
|
|
305
|
+
|
|
306
|
+
def expand_surface(surface: GeoSurface, distance: float) -> GeoSurface:
|
|
307
|
+
"""EXPERIMENTAL: Expands an input surface. The surface must exist on a 2D plane.
|
|
308
|
+
|
|
309
|
+
The output surface does not inherit material properties.
|
|
310
|
+
|
|
311
|
+
If any problems occur, reach out through email.
|
|
312
|
+
|
|
313
|
+
Args:
|
|
314
|
+
surface (GeoSurface): The input surface to expand
|
|
315
|
+
distance (float): The exapansion distance
|
|
316
|
+
|
|
317
|
+
Returns:
|
|
318
|
+
GeoSurface: The output surface
|
|
319
|
+
"""
|
|
320
|
+
surfs = []
|
|
321
|
+
for tag in surface.tags:
|
|
322
|
+
looptags, _ = gmsh.model.occ.get_curve_loops(tag)
|
|
323
|
+
new_curves = []
|
|
324
|
+
for looptag in looptags:
|
|
325
|
+
curve_tags = gmsh.model.occ.offset_curve(looptag, distance)
|
|
326
|
+
loop_tag = gmsh.model.occ.addCurveLoop([t for d,t in curve_tags])
|
|
327
|
+
new_curves.append(loop_tag)
|
|
328
|
+
surftag = gmsh.model.occ.addPlaneSurface(new_curves)
|
|
329
|
+
surfs.append(surftag)
|
|
330
|
+
surf = GeoSurface(surfs)
|
|
331
|
+
return surf
|
emerge/_emerge/geo/pcb.py
CHANGED
|
@@ -22,7 +22,7 @@ from ..geometry import GeoPolygon, GeoVolume, GeoSurface
|
|
|
22
22
|
from ..material import Material, AIR, COPPER
|
|
23
23
|
from .shapes import Box, Plate, Cylinder
|
|
24
24
|
from .polybased import XYPolygon
|
|
25
|
-
from .operations import change_coordinate_system
|
|
25
|
+
from .operations import change_coordinate_system, unite
|
|
26
26
|
from .pcb_tools.macro import parse_macro
|
|
27
27
|
from .pcb_tools.calculator import PCBCalculator
|
|
28
28
|
|
|
@@ -310,7 +310,6 @@ class StripCurve(StripTurn):
|
|
|
310
310
|
points: list[tuple[float, float]] = []
|
|
311
311
|
Npts = int(np.ceil(abs(self.angle/self.dang)))
|
|
312
312
|
R = self.radius-np.sign(self.angle)*self.width/2
|
|
313
|
-
print(R, self.circ_origin, self._xhat, self._yhat)
|
|
314
313
|
for i in range(Npts):
|
|
315
314
|
ang = abs((i+1)/Npts * self.angle * np.pi/180)
|
|
316
315
|
pnew = self.circ_origin + R*(self._xhat*np.cos(ang)+self._yhat*np.sin(ang))
|
|
@@ -324,7 +323,6 @@ class StripCurve(StripTurn):
|
|
|
324
323
|
|
|
325
324
|
Npts = int(np.ceil(abs(self.angle/self.dang)))
|
|
326
325
|
R = self.radius+np.sign(self.angle)*self.width/2
|
|
327
|
-
print(R, self.circ_origin, self._xhat, self._yhat)
|
|
328
326
|
for i in range(Npts):
|
|
329
327
|
ang = abs((i+1)/Npts * self.angle * np.pi/180)
|
|
330
328
|
pnew = self.circ_origin + R*(self._xhat*np.cos(ang)+self._yhat*np.sin(ang))
|
|
@@ -965,8 +963,18 @@ class PCB:
|
|
|
965
963
|
Returns:
|
|
966
964
|
float: the z-height
|
|
967
965
|
"""
|
|
966
|
+
if layer <= 0:
|
|
967
|
+
return self._zs[layer]
|
|
968
968
|
return self._zs[layer-1]
|
|
969
969
|
|
|
970
|
+
@property
|
|
971
|
+
def top(self) -> float:
|
|
972
|
+
return self._zs[-1]
|
|
973
|
+
|
|
974
|
+
@property
|
|
975
|
+
def bottom(self) -> float:
|
|
976
|
+
return self._zs[0]
|
|
977
|
+
|
|
970
978
|
def _get_z(self, element: RouteElement) -> float :
|
|
971
979
|
"""Return the z-height of a given Route Element
|
|
972
980
|
|
|
@@ -981,6 +989,31 @@ class PCB:
|
|
|
981
989
|
return path.z
|
|
982
990
|
raise RouteException('Requesting z-height of route element that is not contained in a path.')
|
|
983
991
|
|
|
992
|
+
def add_vias(self, *coordinates: tuple[float, float], radius: float,
|
|
993
|
+
z1: float | None = None,
|
|
994
|
+
z2: float | None = None,
|
|
995
|
+
segments: int = 6) -> None:
|
|
996
|
+
"""Add a series of vias provided by a list of coordinates.
|
|
997
|
+
|
|
998
|
+
Make sure to define the radius explicitly, otherwise the radius gets interpreted as a coordinate:
|
|
999
|
+
|
|
1000
|
+
>>> pcb.add_vias((x1,y1), (x1,y2), radius=1)
|
|
1001
|
+
|
|
1002
|
+
Args:
|
|
1003
|
+
*coordinates (tuple(float, float)): A series of coordinates
|
|
1004
|
+
radius (float): The radius
|
|
1005
|
+
z1 (float | None, optional): The bottom z-coordinate. Defaults to None.
|
|
1006
|
+
z2 (float | None, optional): The top z-coordinate. Defaults to None.
|
|
1007
|
+
segments (int, optional): The number of segmets for the via. Defaults to 6.
|
|
1008
|
+
"""
|
|
1009
|
+
if z1 is None:
|
|
1010
|
+
z1 = self.z(0)
|
|
1011
|
+
if z2 is None:
|
|
1012
|
+
z2 = self.z(-1)
|
|
1013
|
+
|
|
1014
|
+
for x,y in coordinates:
|
|
1015
|
+
self.vias.append(Via(x,y,z1,z2,radius,segments))
|
|
1016
|
+
|
|
984
1017
|
def load(self, name: str) -> StripLine:
|
|
985
1018
|
"""Acquire the x,y, coordinate associated with the label name.
|
|
986
1019
|
|
|
@@ -1062,7 +1095,7 @@ class PCB:
|
|
|
1062
1095
|
GeoSurface: _description_
|
|
1063
1096
|
"""
|
|
1064
1097
|
if width is None or height is None or origin is None:
|
|
1065
|
-
if self.width is None or self.length is None or self.origin:
|
|
1098
|
+
if self.width is None or self.length is None or self.origin is None:
|
|
1066
1099
|
raise RouteException('Cannot define a plane with no possible definition of its size.')
|
|
1067
1100
|
width = self.width
|
|
1068
1101
|
height = self.length
|
|
@@ -1077,6 +1110,7 @@ class PCB:
|
|
|
1077
1110
|
|
|
1078
1111
|
plane = Plate(origin, (width*self.unit, 0, 0), (0, height*self.unit, 0)) # type: ignore
|
|
1079
1112
|
plane = change_coordinate_system(plane, self.cs) # type: ignore
|
|
1113
|
+
plane.set_material(COPPER)
|
|
1080
1114
|
return plane # type: ignore
|
|
1081
1115
|
|
|
1082
1116
|
def generate_pcb(self,
|
|
@@ -1123,7 +1157,7 @@ class PCB:
|
|
|
1123
1157
|
"""Generate the Air Block object
|
|
1124
1158
|
|
|
1125
1159
|
This requires that the width, depth and origin are deterimed. This
|
|
1126
|
-
can either be done manually or via the .
|
|
1160
|
+
can either be done manually or via the .determine_bounds() method.
|
|
1127
1161
|
|
|
1128
1162
|
Returns:
|
|
1129
1163
|
GeoVolume: The PCB Block
|
|
@@ -1247,7 +1281,13 @@ class PCB:
|
|
|
1247
1281
|
plate = change_coordinate_system(plate, self.cs)
|
|
1248
1282
|
return plate # type: ignore
|
|
1249
1283
|
|
|
1250
|
-
|
|
1284
|
+
@overload
|
|
1285
|
+
def generate_vias(self, merge=Literal[True]) -> GeoVolume: ...
|
|
1286
|
+
|
|
1287
|
+
@overload
|
|
1288
|
+
def generate_vias(self, merge=Literal[False]) -> list[Cylinder]: ...
|
|
1289
|
+
|
|
1290
|
+
def generate_vias(self, merge=False) -> list[Cylinder] | GeoVolume:
|
|
1251
1291
|
"""Generates the via objects.
|
|
1252
1292
|
|
|
1253
1293
|
Args:
|
|
@@ -1321,7 +1361,7 @@ class PCB:
|
|
|
1321
1361
|
Returns:
|
|
1322
1362
|
list[Polygon] | GeoSurface: The output stripline polygons possibly merged if merge = True.
|
|
1323
1363
|
"""
|
|
1324
|
-
polys = []
|
|
1364
|
+
polys: list[GeoSurface] = []
|
|
1325
1365
|
allx = []
|
|
1326
1366
|
ally = []
|
|
1327
1367
|
|
|
@@ -1353,19 +1393,19 @@ class PCB:
|
|
|
1353
1393
|
poly = self._gen_poly(pcbpoly.xys, pcbpoly.z)
|
|
1354
1394
|
poly.material = pcbpoly.material
|
|
1355
1395
|
polys.append(poly)
|
|
1396
|
+
xs, ys = zip(*pcbpoly.xys)
|
|
1397
|
+
allx.extend(xs)
|
|
1398
|
+
ally.extend(ys)
|
|
1399
|
+
|
|
1356
1400
|
|
|
1357
1401
|
self.xs = allx
|
|
1358
1402
|
self.ys = ally
|
|
1359
1403
|
|
|
1360
1404
|
self.traces = polys
|
|
1405
|
+
|
|
1361
1406
|
if merge:
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
tags.extend(p.tags)
|
|
1365
|
-
if p.material != COPPER:
|
|
1366
|
-
logger.warning(f'Merging a polygon with material {p.material} into a single polygon that will be COPPER.')
|
|
1367
|
-
polys = GeoSurface(tags)
|
|
1368
|
-
polys.material = COPPER
|
|
1407
|
+
polys = unite(*polys)
|
|
1408
|
+
|
|
1369
1409
|
return polys
|
|
1370
1410
|
|
|
1371
1411
|
############################################################
|
emerge/_emerge/geo/shapes.py
CHANGED
|
@@ -30,10 +30,20 @@ class Alignment(Enum):
|
|
|
30
30
|
CENTER = 1
|
|
31
31
|
CORNER = 2
|
|
32
32
|
|
|
33
|
+
|
|
33
34
|
class Box(GeoVolume):
|
|
34
|
-
"""
|
|
35
|
+
"""Creates a box volume object.
|
|
36
|
+
Specify the alignment of the box with the provided position. The options are CORNER (default)
|
|
37
|
+
for the front-left-bottom node of the box or CENTER for the center of the box.
|
|
35
38
|
|
|
36
|
-
|
|
39
|
+
Args:
|
|
40
|
+
width (float): The x-size
|
|
41
|
+
depth (float): The y-size
|
|
42
|
+
height (float): The z-size
|
|
43
|
+
position (tuple, optional): The position of the box. Defaults to (0,0,0).
|
|
44
|
+
alignment (Alignment, optional): Which point of the box is placed at the position.
|
|
45
|
+
Defaults to Alignment.CORNER.
|
|
46
|
+
"""
|
|
37
47
|
|
|
38
48
|
def __init__(self,
|
|
39
49
|
width: float,
|
|
@@ -91,10 +101,15 @@ class Box(GeoVolume):
|
|
|
91
101
|
|
|
92
102
|
tags = list(reduce(lambda a,b: a+b, tagslist))
|
|
93
103
|
return FaceSelection(tags)
|
|
94
|
-
|
|
104
|
+
|
|
95
105
|
|
|
96
106
|
class Sphere(GeoVolume):
|
|
107
|
+
"""Generates a sphere objected centered ont he position with the given radius
|
|
97
108
|
|
|
109
|
+
Args:
|
|
110
|
+
radius (float): The sphere radius
|
|
111
|
+
position (tuple, optional): The center position. Defaults to (0,0,0).
|
|
112
|
+
"""
|
|
98
113
|
def __init__(self,
|
|
99
114
|
radius: float,
|
|
100
115
|
position: tuple = (0,0,0)):
|
|
@@ -108,7 +123,19 @@ class Sphere(GeoVolume):
|
|
|
108
123
|
x,y,z = position
|
|
109
124
|
self.tags: list[int] = [gmsh.model.occ.addSphere(x,y,z,radius),]
|
|
110
125
|
|
|
126
|
+
|
|
111
127
|
class XYPlate(GeoSurface):
|
|
128
|
+
"""Generates and XY-plane oriented plate
|
|
129
|
+
|
|
130
|
+
Specify the alignment of the plate with the provided position. The options are CORNER (default)
|
|
131
|
+
for the front-left node of the plate or CENTER for the center of the plate.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
width (float): The x-size of the plate
|
|
135
|
+
depth (float): The y-size of the plate
|
|
136
|
+
position (tuple, optional): The position of the alignment node. Defaults to (0,0,0).
|
|
137
|
+
alignment (Alignment, optional): Which node to align to. Defaults to Alignment.CORNER.
|
|
138
|
+
"""
|
|
112
139
|
def __init__(self,
|
|
113
140
|
width: float,
|
|
114
141
|
depth: float,
|
|
@@ -134,7 +161,19 @@ class XYPlate(GeoSurface):
|
|
|
134
161
|
|
|
135
162
|
|
|
136
163
|
class Plate(GeoSurface):
|
|
137
|
-
|
|
164
|
+
"""A generalized 2D rectangular plate in XYZ-space.
|
|
165
|
+
|
|
166
|
+
The plate is specified by an origin (o) in meters coordinate plus two vectors (u,v) in meters
|
|
167
|
+
that span two of the sides such that all points of the plate are defined by:
|
|
168
|
+
p1 = o
|
|
169
|
+
p2 = o+u
|
|
170
|
+
p3 = o+v
|
|
171
|
+
p4 = o+u+v
|
|
172
|
+
Args:
|
|
173
|
+
origin (tuple[float, float, float]): The origin of the plate in meters
|
|
174
|
+
u (tuple[float, float, float]): The u-axis of the plate
|
|
175
|
+
v (tuple[float, float, float]): The v-axis of the plate
|
|
176
|
+
"""
|
|
138
177
|
def __init__(self,
|
|
139
178
|
origin: tuple[float, float, float],
|
|
140
179
|
u: tuple[float, float, float],
|
|
@@ -172,27 +211,43 @@ class Plate(GeoSurface):
|
|
|
172
211
|
tags: list[int] = [gmsh.model.occ.addPlaneSurface([tag_wire,]),]
|
|
173
212
|
super().__init__(tags)
|
|
174
213
|
|
|
214
|
+
|
|
175
215
|
class Cylinder(GeoVolume):
|
|
216
|
+
"""Generates a Cylinder object in 3D space.
|
|
217
|
+
The cylinder will always be placed in the origin of the provided CoordinateSystem.
|
|
218
|
+
The bottom cylinder plane is always placed in the XY-plane. The length of the cylinder is
|
|
219
|
+
oriented along the Z-axis.
|
|
176
220
|
|
|
221
|
+
By default the cylinder uses the Open Cascade modeling for a cylinder. In this representation
|
|
222
|
+
the surface of the cylinder is approximated with a tolerance thay may be irregular.
|
|
223
|
+
As an alternative, the argument Nsections may be provided in which case the Cylinder is replaced
|
|
224
|
+
by an extrusion of a regular N-sided polygon.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
radius (float): The radius of the Cylinder
|
|
228
|
+
height (float): The height of the Cylinder
|
|
229
|
+
cs (CoordinateSystem, optional): The coordinate system. Defaults to GCS.
|
|
230
|
+
Nsections (int, optional): The number of sections. Defaults to None.
|
|
231
|
+
"""
|
|
177
232
|
def __init__(self,
|
|
178
233
|
radius: float,
|
|
179
234
|
height: float,
|
|
180
|
-
cs: CoordinateSystem =
|
|
181
|
-
Nsections: int = None):
|
|
235
|
+
cs: CoordinateSystem = GCS,
|
|
236
|
+
Nsections: int | None = None):
|
|
182
237
|
"""Generates a Cylinder object in 3D space.
|
|
183
|
-
The
|
|
184
|
-
The bottom
|
|
238
|
+
The cylinder will always be placed in the origin of the provided CoordinateSystem.
|
|
239
|
+
The bottom cylinder plane is always placed in the XY-plane. The length of the cylinder is
|
|
185
240
|
oriented along the Z-axis.
|
|
186
241
|
|
|
187
|
-
By default the
|
|
188
|
-
the surface of the
|
|
242
|
+
By default the cylinder uses the Open Cascade modeling for a cylinder. In this representation
|
|
243
|
+
the surface of the cylinder is approximated with a tolerance thay may be irregular.
|
|
189
244
|
As an alternative, the argument Nsections may be provided in which case the Cylinder is replaced
|
|
190
245
|
by an extrusion of a regular N-sided polygon.
|
|
191
246
|
|
|
192
247
|
Args:
|
|
193
248
|
radius (float): The radius of the Cylinder
|
|
194
249
|
height (float): The height of the Cylinder
|
|
195
|
-
cs (CoordinateSystem, optional): The coordinate system. Defaults to
|
|
250
|
+
cs (CoordinateSystem, optional): The coordinate system. Defaults to GCS.
|
|
196
251
|
Nsections (int, optional): The number of sections. Defaults to None.
|
|
197
252
|
"""
|
|
198
253
|
ax = cs.zax.np
|
|
@@ -233,33 +288,46 @@ class Cylinder(GeoVolume):
|
|
|
233
288
|
xo, yo, zo = self.cs.in_global_cs(x.flatten(), y.flatten(), z.flatten())
|
|
234
289
|
return xo, yo, zo
|
|
235
290
|
|
|
291
|
+
|
|
236
292
|
class CoaxCylinder(GeoVolume):
|
|
237
|
-
"""
|
|
238
|
-
|
|
293
|
+
"""Generates a Coaxial cylinder object in 3D space.
|
|
294
|
+
The coaxial cylinder will always be placed in the origin of the provided CoordinateSystem.
|
|
295
|
+
The bottom coax plane is always placed in the XY-plane. The lenth of the coax is
|
|
296
|
+
oriented along the Z-axis.
|
|
297
|
+
|
|
298
|
+
By default the coax uses the Open Cascade modeling for a cylinder. In this representation
|
|
299
|
+
the surface of the cylinder is approximated with a tolerance thay may be irregular.
|
|
300
|
+
As an alternative, the argument Nsections may be provided in which case the Cylinder is replaced
|
|
301
|
+
by an extrusion of a regular N-sided polygon.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
radius (float): The radius of the Cylinder
|
|
305
|
+
height (float): The height of the Cylinder
|
|
306
|
+
cs (CoordinateSystem, optional): The coordinate system. Defaults to GCS.
|
|
307
|
+
Nsections (int, optional): The number of sections. Defaults to None.
|
|
308
|
+
"""
|
|
239
309
|
def __init__(self,
|
|
240
310
|
rout: float,
|
|
241
311
|
rin: float,
|
|
242
312
|
height: float,
|
|
243
|
-
cs: CoordinateSystem =
|
|
244
|
-
Nsections: int = None):
|
|
245
|
-
"""Generates a Coaxial
|
|
246
|
-
The coaxial
|
|
313
|
+
cs: CoordinateSystem = GCS,
|
|
314
|
+
Nsections: int | None = None):
|
|
315
|
+
"""Generates a Coaxial cylinder object in 3D space.
|
|
316
|
+
The coaxial cylinder will always be placed in the origin of the provided CoordinateSystem.
|
|
247
317
|
The bottom coax plane is always placed in the XY-plane. The lenth of the coax is
|
|
248
318
|
oriented along the Z-axis.
|
|
249
319
|
|
|
250
|
-
By default the coax uses the Open Cascade modeling for a
|
|
251
|
-
the surface of the
|
|
320
|
+
By default the coax uses the Open Cascade modeling for a cylinder. In this representation
|
|
321
|
+
the surface of the cylinder is approximated with a tolerance thay may be irregular.
|
|
252
322
|
As an alternative, the argument Nsections may be provided in which case the Cylinder is replaced
|
|
253
323
|
by an extrusion of a regular N-sided polygon.
|
|
254
324
|
|
|
255
325
|
Args:
|
|
256
326
|
radius (float): The radius of the Cylinder
|
|
257
327
|
height (float): The height of the Cylinder
|
|
258
|
-
cs (CoordinateSystem, optional): The coordinate system. Defaults to
|
|
328
|
+
cs (CoordinateSystem, optional): The coordinate system. Defaults to GCS.
|
|
259
329
|
Nsections (int, optional): The number of sections. Defaults to None.
|
|
260
330
|
"""
|
|
261
|
-
if cs is None:
|
|
262
|
-
cs = GCS
|
|
263
331
|
if rout <= rin:
|
|
264
332
|
raise ValueError("Outer radius must be greater than inner radius.")
|
|
265
333
|
|
|
@@ -297,10 +365,9 @@ class CoaxCylinder(GeoVolume):
|
|
|
297
365
|
|
|
298
366
|
xo, yo, zo = self.cs.in_global_cs(x.flatten(), y.flatten(), z.flatten())
|
|
299
367
|
return xo, yo, zo
|
|
300
|
-
return super().boundary()
|
|
301
368
|
|
|
302
369
|
class HalfSphere(GeoVolume):
|
|
303
|
-
|
|
370
|
+
"""A half sphere volume."""
|
|
304
371
|
def __init__(self,
|
|
305
372
|
radius: float,
|
|
306
373
|
position: tuple = (0,0,0),
|
|
@@ -326,8 +393,6 @@ class HalfSphere(GeoVolume):
|
|
|
326
393
|
self._add_face_pointer('back',np.array(position), np.array(direction))
|
|
327
394
|
self._add_face_pointer('bottom',np.array(position), np.array(direction))
|
|
328
395
|
self._add_face_pointer('face',np.array(position), np.array(direction))
|
|
329
|
-
|
|
330
|
-
|
|
331
396
|
|
|
332
397
|
|
|
333
398
|
class OldBox(GeoVolume):
|
|
@@ -353,8 +418,6 @@ class OldBox(GeoVolume):
|
|
|
353
418
|
alignment (Alignment, optional): Which point of the box is placed at the position.
|
|
354
419
|
Defaults to Alignment.CORNER.
|
|
355
420
|
"""
|
|
356
|
-
|
|
357
|
-
|
|
358
421
|
if alignment is Alignment.CORNER:
|
|
359
422
|
position = (position[0]+width/2, position[1]+depth/2, position[2])
|
|
360
423
|
elif alignment is Alignment.CENTER:
|
|
@@ -436,7 +499,6 @@ class OldBox(GeoVolume):
|
|
|
436
499
|
self._add_face_pointer('right', pc + width/2*wax, wax)
|
|
437
500
|
self._add_face_pointer('top', pc + height/2*hax, hax)
|
|
438
501
|
self._add_face_pointer('bottom', pc - height/2*hax, -hax)
|
|
439
|
-
|
|
440
502
|
|
|
441
503
|
def outside(self, *exclude: Literal['bottom','top','right','left','front','back']) -> FaceSelection:
|
|
442
504
|
"""Select all outside faces except for the once specified by outside
|
|
@@ -449,8 +511,17 @@ class OldBox(GeoVolume):
|
|
|
449
511
|
tags = list(reduce(lambda a,b: a+b, tagslist))
|
|
450
512
|
return FaceSelection(tags)
|
|
451
513
|
|
|
514
|
+
|
|
452
515
|
class Cone(GeoVolume):
|
|
453
|
-
|
|
516
|
+
"""Constructis a cone that starts at position p0 and is aimed in the given direction.
|
|
517
|
+
r1 is the start radius and r2 the end radius. The magnitude of direction determines its length.
|
|
518
|
+
|
|
519
|
+
Args:
|
|
520
|
+
p0 (tuple[float, float, float]): _description_
|
|
521
|
+
direction (tuple[float, float, float]): _description_
|
|
522
|
+
r1 (float): _description_
|
|
523
|
+
r2 (float): _description_
|
|
524
|
+
"""
|
|
454
525
|
def __init__(self, p0: tuple[float, float, float],
|
|
455
526
|
direction: tuple[float, float, float],
|
|
456
527
|
r1: float,
|
emerge/_emerge/geometry.py
CHANGED
|
@@ -411,8 +411,8 @@ class GeoObject:
|
|
|
411
411
|
self._priority = _GEOMANAGER.highest_priority()+10
|
|
412
412
|
return self
|
|
413
413
|
|
|
414
|
-
def
|
|
415
|
-
"""Returns the complete set of
|
|
414
|
+
def boundary(self, exclude: tuple[FaceNames,...] | None = None, tags: list[int] | None = None) -> FaceSelection:
|
|
415
|
+
"""Returns the complete set of boundary faces.
|
|
416
416
|
|
|
417
417
|
If implemented, it is possible to exclude a set of faces based on their name
|
|
418
418
|
or a list of tags (integers)
|
|
@@ -420,8 +420,13 @@ class GeoObject:
|
|
|
420
420
|
Returns:
|
|
421
421
|
FaceSelection: The selected faces
|
|
422
422
|
"""
|
|
423
|
+
if exclude is None:
|
|
424
|
+
exclude = tuple()
|
|
425
|
+
|
|
423
426
|
if tags is None:
|
|
424
427
|
tags = []
|
|
428
|
+
|
|
429
|
+
|
|
425
430
|
for name in exclude:
|
|
426
431
|
tags.extend(self.face(name).tags)
|
|
427
432
|
dimtags = gmsh.model.get_boundary(self.dimtags, True, False)
|
|
@@ -441,6 +446,22 @@ class GeoObject:
|
|
|
441
446
|
|
|
442
447
|
return FaceSelection(self._face_tags(name, tool))
|
|
443
448
|
|
|
449
|
+
def faces(self, *names: FaceNames, tool: GeoObject | None = None) -> FaceSelection:
|
|
450
|
+
"""Returns the FaceSelection for a given face names.
|
|
451
|
+
|
|
452
|
+
The face name must be defined for the type of geometry.
|
|
453
|
+
|
|
454
|
+
Args:
|
|
455
|
+
name (FaceNames): The name of the face to select.
|
|
456
|
+
|
|
457
|
+
Returns:
|
|
458
|
+
FaceSelection: The selected face
|
|
459
|
+
"""
|
|
460
|
+
tags = []
|
|
461
|
+
for name in names:
|
|
462
|
+
tags.extend(self._face_tags(name, tool))
|
|
463
|
+
return FaceSelection(tags)
|
|
464
|
+
|
|
444
465
|
@property
|
|
445
466
|
def dimtags(self) -> list[tuple[int, int]]:
|
|
446
467
|
return [(self.dim, tag) for tag in self.tags]
|
|
@@ -448,15 +469,6 @@ class GeoObject:
|
|
|
448
469
|
@property
|
|
449
470
|
def embeddings(self) -> list[tuple[int,int]]:
|
|
450
471
|
return []
|
|
451
|
-
|
|
452
|
-
def boundary(self) -> FaceSelection:
|
|
453
|
-
if self.dim == 3:
|
|
454
|
-
tags = gmsh.model.get_boundary(self.dimtags, oriented=False)
|
|
455
|
-
return FaceSelection([t[1] for t in tags])
|
|
456
|
-
if self.dim == 2:
|
|
457
|
-
return FaceSelection(self.tags)
|
|
458
|
-
else:
|
|
459
|
-
raise ValueError('Can only generate faces for objects of dimension 2 or higher.')
|
|
460
472
|
|
|
461
473
|
@staticmethod
|
|
462
474
|
def from_dimtags(dimtags: list[tuple[int,int]]) -> GeoVolume | GeoSurface | GeoObject:
|
|
@@ -549,6 +561,25 @@ class GeoPolygon(GeoSurface):
|
|
|
549
561
|
self.points: list[int] = []
|
|
550
562
|
self.lines: list[int] = []
|
|
551
563
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
564
|
+
|
|
565
|
+
############################################################
|
|
566
|
+
# SHORT FUNCTIONS #
|
|
567
|
+
############################################################
|
|
568
|
+
|
|
569
|
+
def select(*items: Selection | GeoObject) -> Selection:
|
|
570
|
+
"""Generate a selection from a series of selections and/or objects that share the same dimension.
|
|
571
|
+
|
|
572
|
+
Raises:
|
|
573
|
+
ValueError: Raised if the dimensions provided are not consistent
|
|
574
|
+
|
|
575
|
+
Returns:
|
|
576
|
+
Selection: An output selection object.
|
|
577
|
+
"""
|
|
578
|
+
dim = items[0].dim
|
|
579
|
+
tags = []
|
|
580
|
+
for item in items:
|
|
581
|
+
if item.dim!=dim:
|
|
582
|
+
raise ValueError(f'Cannot group of objects with a dissimilar dimensions. Trying to include {item} in a list of dimension {dim}.')
|
|
583
|
+
tags.extend(item.tags)
|
|
584
|
+
return Selection.from_dim_tags(dim, tags)
|
|
585
|
+
|
emerge/_emerge/howto.py
CHANGED
|
@@ -69,7 +69,7 @@ class _HowtoClass:
|
|
|
69
69
|
|
|
70
70
|
The naming convention is left(-X), right(+X), front(-Y), back(+Y), bottom(-Z), top(+Z)
|
|
71
71
|
All outside faces can be selected using
|
|
72
|
-
>>> outside = object.
|
|
72
|
+
>>> outside = object.boundary()
|
|
73
73
|
|
|
74
74
|
If objects are the results from operations, you can access the faces from the
|
|
75
75
|
source objects using the optional tool argument
|
|
@@ -787,7 +787,6 @@ class LumpedPort(PortBC):
|
|
|
787
787
|
width: float | None = None,
|
|
788
788
|
height: float | None = None,
|
|
789
789
|
direction: Axis | None = None,
|
|
790
|
-
Idirection: Axis | None = None,
|
|
791
790
|
active: bool = False,
|
|
792
791
|
power: float = 1,
|
|
793
792
|
Z0: float = 50):
|
|
@@ -814,7 +813,7 @@ class LumpedPort(PortBC):
|
|
|
814
813
|
if width is None:
|
|
815
814
|
if not isinstance(face, GeoObject):
|
|
816
815
|
raise ValueError(f'The width, height and direction must be defined. Information cannot be extracted from {face}')
|
|
817
|
-
width, height, direction
|
|
816
|
+
width, height, direction = face._data('width','height','vdir')
|
|
818
817
|
if width is None or height is None or direction is None:
|
|
819
818
|
raise ValueError(f'The width, height and direction could not be extracted from {face}')
|
|
820
819
|
|
|
@@ -828,7 +827,6 @@ class LumpedPort(PortBC):
|
|
|
828
827
|
self.width: float = width
|
|
829
828
|
self.height: float = height # type: ignore
|
|
830
829
|
self.Vdirection: Axis = direction # type: ignore
|
|
831
|
-
self.Idirection: Axis = Idirection # type: ignore
|
|
832
830
|
self.type = 'TEM'
|
|
833
831
|
|
|
834
832
|
logger.info('Constructing coordinate system from normal port')
|
|
@@ -836,7 +834,6 @@ class LumpedPort(PortBC):
|
|
|
836
834
|
|
|
837
835
|
self.vintline: Line | None = None
|
|
838
836
|
self.v_integration = True
|
|
839
|
-
self.iintline: Line | None = None
|
|
840
837
|
|
|
841
838
|
@property
|
|
842
839
|
def surfZ(self) -> float:
|
|
@@ -923,6 +920,7 @@ class LumpedPort(PortBC):
|
|
|
923
920
|
Exg, Eyg, Ezg = self.cs.in_global_basis(Ex, Ey, Ez)
|
|
924
921
|
return np.array([Exg, Eyg, Ezg])
|
|
925
922
|
|
|
923
|
+
|
|
926
924
|
class LumpedElement(RobinBC):
|
|
927
925
|
|
|
928
926
|
_include_stiff: bool = True
|
|
@@ -731,6 +731,19 @@ class MWField:
|
|
|
731
731
|
x: float | None = None,
|
|
732
732
|
y: float | None = None,
|
|
733
733
|
z: float | None = None) -> EHField:
|
|
734
|
+
"""Create a cartesian cut plane (XY, YZ or XZ) and compute the E and H-fields there
|
|
735
|
+
|
|
736
|
+
Only one coordiante and thus cutplane may be defined. If multiple are defined only the last (x->y->z) is used.
|
|
737
|
+
|
|
738
|
+
Args:
|
|
739
|
+
ds (float): The discretization step size
|
|
740
|
+
x (float | None, optional): The X-coordinate in case of a YZ-plane. Defaults to None.
|
|
741
|
+
y (float | None, optional): The Y-coordinate in case of an XZ-plane. Defaults to None.
|
|
742
|
+
z (float | None, optional): The Z-coordinate in case of an XY-plane. Defaults to None.
|
|
743
|
+
|
|
744
|
+
Returns:
|
|
745
|
+
EHField: The resultant EHField object
|
|
746
|
+
"""
|
|
734
747
|
xb, yb, zb = self.basis.bounds
|
|
735
748
|
xs = np.linspace(xb[0], xb[1], int((xb[1]-xb[0])/ds))
|
|
736
749
|
ys = np.linspace(yb[0], yb[1], int((yb[1]-yb[0])/ds))
|
|
@@ -26,7 +26,7 @@ from typing import Iterable, Literal, Callable, Any
|
|
|
26
26
|
from ..display import BaseDisplay
|
|
27
27
|
from .display_settings import PVDisplaySettings
|
|
28
28
|
from matplotlib.colors import ListedColormap
|
|
29
|
-
|
|
29
|
+
from itertools import cycle
|
|
30
30
|
### Color scale
|
|
31
31
|
|
|
32
32
|
# Define the colors we want to use
|
|
@@ -40,6 +40,40 @@ cmap_names = Literal['bgy','bgyw','kbc','blues','bmw','bmy','kgy','gray','dimgra
|
|
|
40
40
|
'bkr','bky','coolwarm','gwv','bjy','bwy','cwr','colorwheel','isolum','rainbow','fire',
|
|
41
41
|
'cet_fire','gouldian','kbgyw','cwr','CET_CBL1','CET_CBL3','CET_D1A']
|
|
42
42
|
|
|
43
|
+
|
|
44
|
+
def _gen_c_cycle():
|
|
45
|
+
colors = [
|
|
46
|
+
"#0000aa",
|
|
47
|
+
"#aa0000",
|
|
48
|
+
"#009900",
|
|
49
|
+
"#990099",
|
|
50
|
+
"#994400",
|
|
51
|
+
"#005588"
|
|
52
|
+
]
|
|
53
|
+
return cycle(colors)
|
|
54
|
+
|
|
55
|
+
C_CYCLE = _gen_c_cycle()
|
|
56
|
+
|
|
57
|
+
class _RunState:
|
|
58
|
+
|
|
59
|
+
def __init__(self):
|
|
60
|
+
self.state: bool = False
|
|
61
|
+
self.ctr: int = 0
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def run(self):
|
|
65
|
+
self.state = True
|
|
66
|
+
self.ctr = 0
|
|
67
|
+
|
|
68
|
+
def stop(self):
|
|
69
|
+
self.state = False
|
|
70
|
+
self.ctr = 0
|
|
71
|
+
|
|
72
|
+
def step(self):
|
|
73
|
+
self.ctr += 1
|
|
74
|
+
|
|
75
|
+
ANIM_STATE = _RunState()
|
|
76
|
+
|
|
43
77
|
def gen_cmap(mesh, N: int = 256):
|
|
44
78
|
# build a linear grid of data‐values (not strictly needed for pure colormap)
|
|
45
79
|
vmin, vmax = mesh['values'].min(), mesh['values'].max()
|
|
@@ -201,6 +235,7 @@ class PVDisplay(BaseDisplay):
|
|
|
201
235
|
self._stop: bool = False
|
|
202
236
|
self._objs: list[_AnimObject] = []
|
|
203
237
|
self._do_animate: bool = False
|
|
238
|
+
self._closed_via_x: bool = False
|
|
204
239
|
self._Nsteps: int = 0
|
|
205
240
|
self._fps: int = 25
|
|
206
241
|
self._ruler: ScreenRuler = ScreenRuler(self, 0.001)
|
|
@@ -216,6 +251,15 @@ class PVDisplay(BaseDisplay):
|
|
|
216
251
|
self._ctr: int = 0
|
|
217
252
|
|
|
218
253
|
self.camera_position = (1, -1, 1) # +X, +Z, -Y
|
|
254
|
+
|
|
255
|
+
def _wire_close_events(self):
|
|
256
|
+
self._closed = False
|
|
257
|
+
|
|
258
|
+
def mark_closed(*_):
|
|
259
|
+
self._closed = True
|
|
260
|
+
self._stop = True
|
|
261
|
+
|
|
262
|
+
self._plot.add_key_event('q', lambda: mark_closed())
|
|
219
263
|
|
|
220
264
|
def _update_camera(self):
|
|
221
265
|
x,y,z = self._plot.camera.position
|
|
@@ -241,8 +285,12 @@ class PVDisplay(BaseDisplay):
|
|
|
241
285
|
self._update_camera()
|
|
242
286
|
self._add_aux_items()
|
|
243
287
|
if self._do_animate:
|
|
288
|
+
self._wire_close_events()
|
|
289
|
+
self.add_text('Press Q to close!',color='red', position='upper_left')
|
|
244
290
|
self._plot.show(auto_close=False, interactive_update=True, before_close_callback=self._close_callback)
|
|
245
291
|
self._animate()
|
|
292
|
+
|
|
293
|
+
|
|
246
294
|
else:
|
|
247
295
|
self._plot.show()
|
|
248
296
|
self._reset()
|
|
@@ -261,25 +309,55 @@ class PVDisplay(BaseDisplay):
|
|
|
261
309
|
self._plot = pv.Plotter()
|
|
262
310
|
self._stop = False
|
|
263
311
|
self._objs = []
|
|
312
|
+
C_CYCLE = _gen_c_cycle()
|
|
264
313
|
|
|
265
|
-
def _close_callback(self):
|
|
314
|
+
def _close_callback(self, arg):
|
|
266
315
|
"""The private callback function that stops the animation.
|
|
267
316
|
"""
|
|
268
317
|
self._stop = True
|
|
318
|
+
print('CLOSE!')
|
|
269
319
|
|
|
270
320
|
def _animate(self) -> None:
|
|
271
321
|
"""Private function that starts the animation loop.
|
|
272
322
|
"""
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
323
|
+
|
|
324
|
+
self._stop = False
|
|
325
|
+
|
|
326
|
+
# guard values
|
|
327
|
+
steps = max(1, int(self._Nsteps))
|
|
328
|
+
fps = max(1, int(self._fps))
|
|
329
|
+
dt = 1.0 / fps
|
|
330
|
+
next_tick = time.perf_counter()
|
|
331
|
+
step = 0
|
|
332
|
+
|
|
333
|
+
while (not self._stop
|
|
334
|
+
and not self._closed_via_x
|
|
335
|
+
and self._plot.render_window is not None):
|
|
336
|
+
# process window/UI events so close button works
|
|
337
|
+
self._plot.update()
|
|
338
|
+
|
|
339
|
+
now = time.perf_counter()
|
|
340
|
+
if now >= next_tick:
|
|
341
|
+
step = (step + 1) % steps
|
|
342
|
+
phi = np.exp(1j * (step / steps) * 2*np.pi)
|
|
343
|
+
|
|
344
|
+
# update all animated objects
|
|
278
345
|
for aobj in self._objs:
|
|
279
|
-
phi = np.exp(1j*(step/self._Nsteps)*2*np.pi)
|
|
280
346
|
aobj.update(phi)
|
|
281
|
-
|
|
282
|
-
|
|
347
|
+
|
|
348
|
+
# draw one frame
|
|
349
|
+
self._plot.render()
|
|
350
|
+
|
|
351
|
+
# schedule next frame; catch up if we fell behind
|
|
352
|
+
next_tick += dt
|
|
353
|
+
if now > next_tick + dt:
|
|
354
|
+
next_tick = now + dt
|
|
355
|
+
|
|
356
|
+
# be kind to the CPU
|
|
357
|
+
time.sleep(0.001)
|
|
358
|
+
|
|
359
|
+
# ensure cleanup pathway runs once
|
|
360
|
+
self._close_callback(None)
|
|
283
361
|
|
|
284
362
|
def animate(self, Nsteps: int = 35, fps: int = 25) -> PVDisplay:
|
|
285
363
|
""" Turns on the animation mode with the specified number of steps and FPS.
|
|
@@ -357,11 +435,29 @@ class PVDisplay(BaseDisplay):
|
|
|
357
435
|
return None
|
|
358
436
|
|
|
359
437
|
## OBLIGATORY METHODS
|
|
360
|
-
def add_object(self, obj: GeoObject | Selection, *args, **kwargs):
|
|
361
|
-
|
|
438
|
+
def add_object(self, obj: GeoObject | Selection, mesh: bool = False, volume_mesh: bool = True, *args, **kwargs):
|
|
439
|
+
|
|
440
|
+
show_edges = False
|
|
441
|
+
opacity = obj.opacity
|
|
442
|
+
line_width = 0.5
|
|
443
|
+
color = obj.color_rgb
|
|
444
|
+
style='surface'
|
|
445
|
+
|
|
446
|
+
if mesh is True:
|
|
447
|
+
show_edges = True
|
|
448
|
+
opacity = 0.7
|
|
449
|
+
line_width= 1
|
|
450
|
+
style='wireframe'
|
|
451
|
+
color=next(C_CYCLE)
|
|
452
|
+
|
|
453
|
+
kwargs = setdefault(kwargs, color=color, opacity=opacity, line_width=line_width, show_edges=show_edges, pickable=True, style=style)
|
|
454
|
+
mesh_obj = self.mesh(obj)
|
|
362
455
|
|
|
363
|
-
|
|
364
|
-
|
|
456
|
+
if mesh is True and volume_mesh is True:
|
|
457
|
+
mesh_obj = mesh_obj.extract_all_edges()
|
|
458
|
+
|
|
459
|
+
actor = self._plot.add_mesh(mesh_obj, *args, **kwargs)
|
|
460
|
+
self._plot.add_mesh(self._volume_edges(_select(obj)), color='#000000', line_width=2, show_edges=True)
|
|
365
461
|
|
|
366
462
|
def add_scatter(self, xs: np.ndarray, ys: np.ndarray, zs: np.ndarray):
|
|
367
463
|
"""Adds a scatter point cloud
|
|
@@ -501,7 +597,7 @@ class PVDisplay(BaseDisplay):
|
|
|
501
597
|
if self._do_animate:
|
|
502
598
|
def on_update(obj: _AnimObject, phi: complex):
|
|
503
599
|
field = obj.T(np.real(obj.field*phi))
|
|
504
|
-
obj.grid[
|
|
600
|
+
obj.grid[name] = field
|
|
505
601
|
self._objs.append(_AnimObject(field_flat, T, grid, actor, on_update)) # type: ignore
|
|
506
602
|
|
|
507
603
|
|
|
@@ -524,6 +620,8 @@ class PVDisplay(BaseDisplay):
|
|
|
524
620
|
if abs_position is not None:
|
|
525
621
|
final_position = abs_position
|
|
526
622
|
viewport = True
|
|
623
|
+
else:
|
|
624
|
+
final_position = abs_position
|
|
527
625
|
self._plot.add_text(
|
|
528
626
|
text,
|
|
529
627
|
position=final_position,
|
emerge/_emerge/selection.py
CHANGED
emerge/_emerge/simmodel.py
CHANGED
|
@@ -319,24 +319,26 @@ class Simulation:
|
|
|
319
319
|
def view(self,
|
|
320
320
|
selections: list[Selection] | None = None,
|
|
321
321
|
use_gmsh: bool = False,
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
322
|
+
plot_mesh: bool = False,
|
|
323
|
+
volume_mesh: bool = True,
|
|
324
|
+
opacity: float | None = None) -> None:
|
|
325
325
|
"""View the current geometry in either the BaseDisplay object (PVDisplay only) or
|
|
326
326
|
the GMSH viewer.
|
|
327
327
|
|
|
328
328
|
Args:
|
|
329
|
-
selections (list[Selection], optional):
|
|
330
|
-
use_gmsh (bool, optional):
|
|
331
|
-
|
|
332
|
-
|
|
329
|
+
selections (list[Selection] | None, optional): Optional selections to highlight. Defaults to None.
|
|
330
|
+
use_gmsh (bool, optional): If GMSH's GUI should be used. Defaults to False.
|
|
331
|
+
plot_mesh (bool, optional): If the mesh should be plot instead of the object. Defaults to False.
|
|
332
|
+
volume_mesh (bool, optional): If the internal mesh should be plot instead of only the surface boundary mesh. Defaults to True
|
|
333
|
+
opacity (float | None, optional): The object/mesh opacity. Defaults to None.
|
|
334
|
+
|
|
333
335
|
"""
|
|
334
336
|
if not (self.display is not None and self.mesh.defined) or use_gmsh:
|
|
335
337
|
gmsh.model.occ.synchronize()
|
|
336
338
|
gmsh.fltk.run()
|
|
337
339
|
return
|
|
338
340
|
for geo in _GEOMANAGER.all_geometries():
|
|
339
|
-
self.display.add_object(geo)
|
|
341
|
+
self.display.add_object(geo, mesh=plot_mesh, opacity=opacity, volume_mesh=volume_mesh)
|
|
340
342
|
if selections:
|
|
341
343
|
[self.display.add_object(sel, color='red', opacity=0.3) for sel in selections]
|
|
342
344
|
self.display.show()
|
emerge/_emerge/solver.py
CHANGED
|
@@ -674,7 +674,7 @@ class SolverARPACK(EigSolver):
|
|
|
674
674
|
target_k0: float = 0,
|
|
675
675
|
which: str = 'LM',
|
|
676
676
|
sign: float = 1.0) -> tuple[np.ndarray, np.ndarray]:
|
|
677
|
-
logger.info(f'Searching around β = {target_k0:.2f} rad/m')
|
|
677
|
+
logger.info(f'Searching around β = {target_k0:.2f} rad/m with ARPACK')
|
|
678
678
|
sigma = sign*(target_k0**2)
|
|
679
679
|
eigen_values, eigen_modes = eigs(A, k=nmodes, M=B, sigma=sigma, which=which)
|
|
680
680
|
return eigen_values, eigen_modes
|
|
@@ -698,7 +698,7 @@ class SmartARPACK_BMA(EigSolver):
|
|
|
698
698
|
which: str = 'LM',
|
|
699
699
|
sign: float = 1.) -> tuple[np.ndarray, np.ndarray]:
|
|
700
700
|
|
|
701
|
-
logger.info(f'Searching around β = {target_k0:.2f} rad/m')
|
|
701
|
+
logger.info(f'Searching around β = {target_k0:.2f} rad/m with SmartARPACK (BMA)')
|
|
702
702
|
qs = np.geomspace(1, self.search_range, self.symmetric_steps)
|
|
703
703
|
tot_eigen_values = []
|
|
704
704
|
tot_eigen_modes = []
|
|
@@ -747,7 +747,7 @@ class SmartARPACK(EigSolver):
|
|
|
747
747
|
target_k0: float = 0,
|
|
748
748
|
which: str = 'LM',
|
|
749
749
|
sign: float = 1.) -> tuple[np.ndarray, np.ndarray]:
|
|
750
|
-
logger.info(f'Searching around β = {target_k0:.2f} rad/m')
|
|
750
|
+
logger.info(f'Searching around β = {target_k0:.2f} rad/m with SmartARPACK')
|
|
751
751
|
qs = np.geomspace(1, self.search_range, self.symmetric_steps)
|
|
752
752
|
tot_eigen_values = []
|
|
753
753
|
tot_eigen_modes = []
|
|
@@ -1062,7 +1062,7 @@ class SolveRoutine:
|
|
|
1062
1062
|
if direct or A.shape[0] < 1000:
|
|
1063
1063
|
return self.solvers[EMSolver.LAPACK] # type: ignore
|
|
1064
1064
|
else:
|
|
1065
|
-
return self.solvers[EMSolver.
|
|
1065
|
+
return self.solvers[EMSolver.SMART_ARPACK_BMA] # type: ignore
|
|
1066
1066
|
|
|
1067
1067
|
def solve(self, A: csr_matrix | csr_matrix,
|
|
1068
1068
|
b: np.ndarray,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
emerge/__init__.py,sha256=
|
|
1
|
+
emerge/__init__.py,sha256=YUioR8ldVN1lYGhEP8GA_DZ5XDBpsoEczbrssVIEg3o,2642
|
|
2
2
|
emerge/__main__.py,sha256=WVf16sfrOI910QWohrQDaChZdRifMNoS6VKzCT6f3ZA,92
|
|
3
3
|
emerge/cli.py,sha256=NU1uhwuZ6i50680v3_I4kDZPTHqz74gOYK71UBhb8oE,666
|
|
4
4
|
emerge/ext.py,sha256=IBoHH5PQFj5pYMfp6r-uMpNNgbSe8c0g9x8qjBzzVmU,223
|
|
@@ -13,18 +13,18 @@ emerge/_emerge/coord.py,sha256=BKvyrcnHY-_bgHqysnByy5k9_DK4VVfr9KKkRaawG2E,4371
|
|
|
13
13
|
emerge/_emerge/cs.py,sha256=YNT2Nn6Dh8fYPUMlT6w0msHnQpZREbbl_ZXTGNppCVs,18392
|
|
14
14
|
emerge/_emerge/dataset.py,sha256=UcSAJ_siLrOjNBBWRWsS3GUZUpayp63EM6pP6ClwKDI,1534
|
|
15
15
|
emerge/_emerge/geo2d.py,sha256=e_HkX1GQ2iYrdO0zeEgzVOzfGyU1WGJyjeGBAobOttE,3323
|
|
16
|
-
emerge/_emerge/geometry.py,sha256=
|
|
17
|
-
emerge/_emerge/howto.py,sha256=
|
|
16
|
+
emerge/_emerge/geometry.py,sha256=2mxVF2Ezd_rK9y6LecgrK1wZ7NbtzROz2BXgu_mPMjg,19190
|
|
17
|
+
emerge/_emerge/howto.py,sha256=c4UxUNpA1tygr3OoR-LH-h0UZv-Tf9K8tpCiAU18BKE,8173
|
|
18
18
|
emerge/_emerge/logsettings.py,sha256=DcUWIUUhdLe9ev5XC1bd5ZUrJz00MjABkY8rnekFrPY,3373
|
|
19
19
|
emerge/_emerge/material.py,sha256=HTjQ8wDzkBwYA1sLPRuqR8lPeoXsW-4m5K3yXoKqjXQ,4022
|
|
20
20
|
emerge/_emerge/mesh3d.py,sha256=Kszo-ogeByvoAVmrCIASc44PRIw-MblxNtwFB0AHa1A,34500
|
|
21
21
|
emerge/_emerge/mesher.py,sha256=fKgPb6oZe_bqp0XYfZ6UNgBfRaAS3-tjUtZX8NalJe8,13199
|
|
22
22
|
emerge/_emerge/periodic.py,sha256=xfdKKq3qX7iBBestnRizOzJNfXlpr9lCPkiYhfrRIR8,12013
|
|
23
23
|
emerge/_emerge/plot.py,sha256=cf1I9mj7EIUJcq8vmANlUkqoV6QqVaJaP-zlC-T9E18,8041
|
|
24
|
-
emerge/_emerge/selection.py,sha256=
|
|
25
|
-
emerge/_emerge/simmodel.py,sha256=
|
|
24
|
+
emerge/_emerge/selection.py,sha256=x8cGN93BAmO80C0gn6feWcW126vorscsZVzhreTOLxs,21298
|
|
25
|
+
emerge/_emerge/simmodel.py,sha256=v1cTMuyknJ5yvd6-AyjWFTd4BdYp31laNa0N8jv04QQ,19743
|
|
26
26
|
emerge/_emerge/simulation_data.py,sha256=r9-9lpLeA1Z5HU3jDVOXV1H80GVawnXL5K81_dvmlE4,14506
|
|
27
|
-
emerge/_emerge/solver.py,sha256=
|
|
27
|
+
emerge/_emerge/solver.py,sha256=77qhdRBdZJCneGYEQXkqWvY7btNDrebSJ4Vo124L-ak,48604
|
|
28
28
|
emerge/_emerge/system.py,sha256=p4HNz7d_LMRNE9Gk75vVdFecDH2iN_groAM9u-yQTpk,1618
|
|
29
29
|
emerge/_emerge/elements/__init__.py,sha256=I3n9aic6lJW-oGeqTEZ-Fpxvyl2i-WqsHdnrM3v1oB8,799
|
|
30
30
|
emerge/_emerge/elements/femdata.py,sha256=3rFVz1-PLtqxnDFvTH1Q9dA98lO5VyjcFKecCJCwfQ4,8020
|
|
@@ -32,14 +32,14 @@ emerge/_emerge/elements/index_interp.py,sha256=DlDy2KrhM5QsF6jYQIl4BJndr9F9wnjFM
|
|
|
32
32
|
emerge/_emerge/elements/ned2_interp.py,sha256=kMhbjS1fACa1fmhSkQTU35jS3iF63dJcFe5DHl4Xo78,32541
|
|
33
33
|
emerge/_emerge/elements/nedelec2.py,sha256=chU3Ewz7grKZtpyglj2qFJYHvBzCXFQZa1skzjfHoPo,6138
|
|
34
34
|
emerge/_emerge/elements/nedleg2.py,sha256=qVPKtJpT7UCA5dcI_mXNX7Co4tzVCvlxQv5VtsLuKN8,8468
|
|
35
|
-
emerge/_emerge/geo/__init__.py,sha256=
|
|
35
|
+
emerge/_emerge/geo/__init__.py,sha256=TQyNbiBOlSYBTKm5Tk2egBqKlqnwnNUt1sHqiYsvpWA,1142
|
|
36
36
|
emerge/_emerge/geo/horn.py,sha256=h4GzGzEkXgWaQgoBMvhFgGsqOrNRB3CJg3RBKXigCz0,4186
|
|
37
37
|
emerge/_emerge/geo/modeler.py,sha256=gbxmwXAdR7kKW_EFbkd1QPVqJWKJpnTufI7lxaqPyjU,15573
|
|
38
|
-
emerge/_emerge/geo/operations.py,sha256=
|
|
39
|
-
emerge/_emerge/geo/pcb.py,sha256=
|
|
38
|
+
emerge/_emerge/geo/operations.py,sha256=7u3KNa7QbFq358m7FjBX1J6b3APPkzMXTjYn7f6qfpM,12004
|
|
39
|
+
emerge/_emerge/geo/pcb.py,sha256=MmY-A-Xnd85aQw6ouOnsZKcui_kH86fw4l0GoR4qQu0,53442
|
|
40
40
|
emerge/_emerge/geo/pmlbox.py,sha256=TNjuyPtuqrAU5Yl8GrLlievuwYf3hUKJaCEz0cXKSzo,7922
|
|
41
41
|
emerge/_emerge/geo/polybased.py,sha256=loVJRBjYCTUlti5tHwfH8iU-Inb6n2sOS2Cw4gVKid4,31917
|
|
42
|
-
emerge/_emerge/geo/shapes.py,sha256
|
|
42
|
+
emerge/_emerge/geo/shapes.py,sha256=-ct-TJh69oj5fqJcQql4pNk3acJWTIQzYOQeAFXDfWk,23319
|
|
43
43
|
emerge/_emerge/geo/step.py,sha256=XcAiEN8W4umNmZdYmrGHX_aJUuiMgc6vgT-UIk8Gbqc,2689
|
|
44
44
|
emerge/_emerge/geo/pcb_tools/calculator.py,sha256=eGYUXdXmHUJCPlfJyY96S87wjeAVFG-e4sPOwbYj0eA,832
|
|
45
45
|
emerge/_emerge/geo/pcb_tools/macro.py,sha256=0g-0anOFyxrEkFobiSu0cwWFRQ32xB8Az24mmwo0z6M,2992
|
|
@@ -51,8 +51,8 @@ emerge/_emerge/physics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
51
51
|
emerge/_emerge/physics/microwave/__init__.py,sha256=QHeILGYWmvbfLl1o9wrTiWLm0evfXDgS0JiikUoMTts,28
|
|
52
52
|
emerge/_emerge/physics/microwave/adaptive_freq.py,sha256=aWhijhCVAbnuwkru-I1AaRdY20uyozf6OWRIh9r2ijg,9786
|
|
53
53
|
emerge/_emerge/physics/microwave/microwave_3d.py,sha256=5P8yyr6e6hFHBS1JAFHq8gsU1CxFG1LTelKVggv7AjY,42007
|
|
54
|
-
emerge/_emerge/physics/microwave/microwave_bc.py,sha256
|
|
55
|
-
emerge/_emerge/physics/microwave/microwave_data.py,sha256=
|
|
54
|
+
emerge/_emerge/physics/microwave/microwave_bc.py,sha256=itUDUVGPda_qdHyl45PVsc2OSKgjDwHHgmwYflN4l5Y,42316
|
|
55
|
+
emerge/_emerge/physics/microwave/microwave_data.py,sha256=cgm3i5-MbB6x_7znxAeDw2IpOPwP9cue0vWI68udwcM,47386
|
|
56
56
|
emerge/_emerge/physics/microwave/periodic.py,sha256=wYSUgLFVtCLqSG3EDKoCDRU93iPUzBdXzVRdHTRmbpI,3000
|
|
57
57
|
emerge/_emerge/physics/microwave/port_functions.py,sha256=aVU__AkVk8b1kH2J_oDLF5iNReCxC9nzCtesFSSSSQo,2112
|
|
58
58
|
emerge/_emerge/physics/microwave/sc.py,sha256=WZvoPhmHkfEv619RhmN09sXDBV0ryTqybwErA8Rc7lU,4735
|
|
@@ -70,7 +70,7 @@ emerge/_emerge/plot/display.py,sha256=TQLlKb-LkaG5ZOSLfxp9KXPlZPRFTxNj1LhVQ-Lp1-
|
|
|
70
70
|
emerge/_emerge/plot/simple_plots.py,sha256=q3IuoW4qrp5xv2S3vsVgATdE1QajWmA5_59Ma7I6GA0,24433
|
|
71
71
|
emerge/_emerge/plot/matplotlib/mpldisplay.py,sha256=szKafDrgdAW5Nyc5UOHuJC87n0WGkXYackOVv182TDQ,8671
|
|
72
72
|
emerge/_emerge/plot/pyvista/__init__.py,sha256=CPclatEu6mFnJZzCQk09g6T6Fh20WTbiLAJGSwAnPXU,30
|
|
73
|
-
emerge/_emerge/plot/pyvista/display.py,sha256=
|
|
73
|
+
emerge/_emerge/plot/pyvista/display.py,sha256=5IYVtT8ZwFu1NRwwzrzoY_FmPwjeRAfsQbg9NK383zE,37098
|
|
74
74
|
emerge/_emerge/plot/pyvista/display_settings.py,sha256=K2OhzKqeFzMXlEfZ5F4CQ9sN3l7nOgVjLplZBuMPjvE,899
|
|
75
75
|
emerge/_emerge/projects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
76
|
emerge/_emerge/projects/_gen_base.txt,sha256=DqQz36PZg6v1ovQjHvPjd0t4AIbmikZdb9dmrNYsK3w,598
|
|
@@ -78,8 +78,8 @@ emerge/_emerge/projects/_load_base.txt,sha256=94o0eSWoDKlNR336EmhpG_S5syQHIUPHQx
|
|
|
78
78
|
emerge/_emerge/projects/generate_project.py,sha256=TNw-0SpLc82MBq0bd9hB_yqvBZCgmuPonCBsHTp91uk,1450
|
|
79
79
|
emerge/_emerge/solve_interfaces/cudss_interface.py,sha256=-SjiTNIyE7iJ8Bm14Cva5e2lpJDgfiS2Mvz1Bgy-UL4,9688
|
|
80
80
|
emerge/_emerge/solve_interfaces/pardiso_interface.py,sha256=iVFxToMmIzhj3hcAP-O_MDHKz82ePFIHY1us11kzUBU,15305
|
|
81
|
-
emerge-0.6.
|
|
82
|
-
emerge-0.6.
|
|
83
|
-
emerge-0.6.
|
|
84
|
-
emerge-0.6.
|
|
85
|
-
emerge-0.6.
|
|
81
|
+
emerge-0.6.7.dist-info/METADATA,sha256=J3r6jeI0a4A9x5fzG1t-h1ZL28y1SJizCz17i0Hwdrk,3304
|
|
82
|
+
emerge-0.6.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
83
|
+
emerge-0.6.7.dist-info/entry_points.txt,sha256=8rFvAXticpKg4OTC8JEvAksnduW72KIEskCGG9XnFf8,43
|
|
84
|
+
emerge-0.6.7.dist-info/licenses/LICENSE,sha256=SuHm9Fw32RI6tylP2YCyTPITMwpueazVUZwUMFRE_zk,17856
|
|
85
|
+
emerge-0.6.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|