emerge 0.6.9__py3-none-any.whl → 0.6.10__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 CHANGED
@@ -18,7 +18,7 @@ along with this program; if not, see
18
18
  """
19
19
  import os
20
20
 
21
- __version__ = "0.6.9"
21
+ __version__ = "0.6.10"
22
22
 
23
23
  ############################################################
24
24
  # HANDLE ENVIRONMENT VARIABLES #
@@ -43,12 +43,13 @@ from loguru import logger
43
43
 
44
44
  LOG_CONTROLLER.set_default()
45
45
  logger.debug('Importing modules')
46
+ LOG_CONTROLLER._set_log_buffer()
46
47
 
47
48
  from ._emerge.simmodel import Simulation
48
49
  from ._emerge.material import Material, FreqCoordDependent, FreqDependent, CoordDependent
49
50
  from ._emerge import bc
50
51
  from ._emerge.solver import SolverBicgstab, SolverGMRES, SolveRoutine, ReverseCuthillMckee, Sorter, SolverPardiso, SolverUMFPACK, SolverSuperLU, EMSolver
51
- from ._emerge.cs import CoordinateSystem, CS, GCS, Plane, Axis, XAX, YAX, ZAX, XYPLANE, XZPLANE, YZPLANE, YXPLANE, ZXPLANE, ZYPLANE
52
+ from ._emerge.cs import CoordinateSystem, CS, GCS, Plane, Axis, XAX, YAX, ZAX, XYPLANE, XZPLANE, YZPLANE, YXPLANE, ZXPLANE, ZYPLANE, cs
52
53
  from ._emerge.coord import Line
53
54
  from ._emerge import geo
54
55
  from ._emerge.selection import Selection, FaceSelection, DomainSelection, EdgeSelection
@@ -62,4 +63,12 @@ from ._emerge.howto import _HowtoClass
62
63
 
63
64
  howto = _HowtoClass()
64
65
 
65
- logger.debug('Importing complete!')
66
+ logger.debug('Importing complete!')
67
+
68
+
69
+ ############################################################
70
+ # CONSTANTS #
71
+ ############################################################
72
+
73
+ CENTER = geo.Alignment.CENTER
74
+ CORNER = geo.Alignment.CORNER
emerge/_emerge/cs.py CHANGED
@@ -530,3 +530,39 @@ CS = CoordinateSystem
530
530
  # The global coordinate system
531
531
  GCS = CoordinateSystem(XAX, YAX, ZAX, np.zeros(3), _is_global=True)
532
532
 
533
+ def cs(axes: str, origin: tuple[float, float, float] = (0.,0.,0.,)) -> CoordinateSystem:
534
+ """Generate a coordinate system based on a simple string
535
+ The string must contain the letters x, X, y, Y, z and/or Z.
536
+ Small letters refer to positive axes and capitals to negative axes.
537
+
538
+ The string must be 3 characters long.
539
+
540
+ The first position indices which global axis gets assigned to the new local X-axis
541
+ The second position indicates the Y-axis
542
+ The third position indicates the Z-axis
543
+
544
+ Thus, rotating the global XYZ coordinate system 90 degrees around the Z axis would yield: yXz
545
+
546
+ Args:
547
+ axes (str): The axis description
548
+ origin (tuple[float, float, float], optional): The origin of the coordinate system. Defaults to (0.,0.,0.,).
549
+
550
+ Returns:
551
+ CoordinateSystem: The resultant coordinate system
552
+ """
553
+ if len(axes) != 3:
554
+ raise ValueError('Axis object must be of length 3')
555
+
556
+ axlib = {
557
+ 'x': Axis(np.array([1.0,0.,0.])),
558
+ 'X': Axis(np.array([-1.0,0.,0.])),
559
+ 'y': Axis(np.array([0.,1.0,0.])),
560
+ 'Y': Axis(np.array([0.,-1.0,0.])),
561
+ 'z': Axis(np.array([0.,0.,1.0])),
562
+ 'Z': Axis(np.array([0.,0.,-1.0])),
563
+ }
564
+ ax_obj = [axlib[ax] for ax in axes]
565
+
566
+ return (ax_obj[0]*ax_obj[1]*ax_obj[2]).displace(*origin)
567
+
568
+
@@ -206,6 +206,7 @@ def orthonormalize(axis: np.ndarray) -> tuple[np.ndarray, np.ndarray, np.ndarray
206
206
  Zaxis = np.abs(Zaxis/np.linalg.norm(Zaxis))
207
207
  return Xaxis, Yaxis, Zaxis
208
208
 
209
+
209
210
  class GeoPrism(GeoVolume):
210
211
  """The GepPrism class generalizes the GeoVolume for extruded convex polygons.
211
212
  Besides having a volumetric definitions, the class offers a .front_face
@@ -216,35 +217,65 @@ class GeoPrism(GeoVolume):
216
217
  """
217
218
  def __init__(self,
218
219
  volume_tag: int,
219
- front_tag: int,
220
- side_tags: list[int],):
220
+ front_tag: int | None = None,
221
+ side_tags: list[int] | None = None,
222
+ _axis: Axis | None = None):
221
223
  super().__init__(volume_tag)
222
- self.front_tag: int = front_tag
223
- self.back_tag: int = None
224
+
225
+
226
+
227
+ if front_tag is not None and side_tags is not None:
228
+ self.front_tag: int = front_tag
229
+ self.back_tag: int = None
224
230
 
225
- gmsh.model.occ.synchronize()
226
- o1 = gmsh.model.occ.get_center_of_mass(2, self.front_tag)
227
- n1 = gmsh.model.get_normal(self.front_tag, (0,0))
228
- self._add_face_pointer('back', o1, n1)
231
+ gmsh.model.occ.synchronize()
232
+ self._add_face_pointer('back', tag=self.front_tag)
229
233
 
230
- tags = gmsh.model.get_boundary(self.dimtags, oriented=False)
231
-
232
- for dim, tag in tags:
233
- if (dim,tag) in side_tags:
234
- continue
235
- o2 = gmsh.model.occ.get_center_of_mass(2, tag)
236
- n2 = gmsh.model.get_normal(tag, (0,0))
237
- self._add_face_pointer('front', o2, n2)
238
- self.back_tag = tag
239
- break
234
+ tags = gmsh.model.get_boundary(self.dimtags, oriented=False)
235
+
236
+ for dim, tag in tags:
237
+ if (dim,tag) in side_tags:
238
+ continue
239
+ self._add_face_pointer('front',tag=tag)
240
+ self.back_tag = tag
241
+ break
240
242
 
241
- self.side_tags: list[int] = [dt[1] for dt in tags if dt[1]!=self.front_tag and dt[1]!=self.back_tag]
243
+ self.side_tags: list[int] = [dt[1] for dt in tags if dt[1]!=self.front_tag and dt[1]!=self.back_tag]
242
244
 
243
- for tag in self.side_tags:
244
- o2 = gmsh.model.occ.get_center_of_mass(2, tag)
245
- n2 = gmsh.model.get_normal(tag, (0,0))
246
- self._add_face_pointer(f'side{tag}', o2, n2)
247
- self.back_tag = tag
245
+ for tag in self.side_tags:
246
+
247
+ self._add_face_pointer(f'side{tag}', tag=tag)
248
+ self.back_tag = tag
249
+
250
+ elif _axis is not None:
251
+ _axis = _parse_axis(_axis)
252
+ gmsh.model.occ.synchronize()
253
+ tags = gmsh.model.get_boundary(self.dimtags, oriented=False)
254
+ faces = []
255
+ for dim, tag in tags:
256
+ o1 = np.array(gmsh.model.occ.get_center_of_mass(2, tag))
257
+ n1 = np.array(gmsh.model.get_normal(tag, (0,0)))
258
+ if abs(np.sum(n1*_axis.np)) > 0.99:
259
+ dax = sum(o1 * _axis.np)
260
+ faces.append((o1, n1, dax, tag))
261
+
262
+ faces = sorted(faces, key=lambda x: x[2])
263
+ ftags = []
264
+ if len(faces) >= 2:
265
+ ftags.append(faces[0][3])
266
+ ftags.append(faces[-1][3])
267
+ self._add_face_pointer('front',faces[0][0], faces[0][1])
268
+ self._add_face_pointer('back', faces[-1][0], faces[-1][1])
269
+ elif len(faces)==1:
270
+ ftags.append(faces[0][3])
271
+ self._add_face_pointer('cap',faces[0][0], faces[0][1])
272
+
273
+ ictr = 1
274
+ for dim, tag in tags:
275
+ if tag in ftags:
276
+ continue
277
+ self._add_face_pointer(f'side{ictr}', tag=tag)
278
+ ictr += 1
248
279
 
249
280
  def outside(self, *exclude: Literal['front','back']) -> FaceSelection:
250
281
  """Select all outside faces except for the once specified by outside
@@ -462,9 +493,10 @@ class XYPolygon:
462
493
  ax, ay, az = axis
463
494
 
464
495
  volume = gmsh.model.occ.revolve(poly_fin.dimtags, x,y,z, ax, ay, az, angle*np.pi/180)
496
+
465
497
  tags = [t for d,t in volume if d==3]
466
- surftags = [t for d,t in volume if d==2]
467
- return GeoPrism(tags, surftags[0], surftags)
498
+ poly_fin.remove()
499
+ return GeoPrism(tags, _axis=axis)
468
500
 
469
501
  @staticmethod
470
502
  def circle(radius: float,
@@ -27,6 +27,12 @@ from typing import Literal
27
27
  from functools import reduce
28
28
 
29
29
  class Alignment(Enum):
30
+ """The alignment Enum describes if a box, cube or rectangle location
31
+ is specified for the center or the bottom - front - left corner (min X Y and Z)
32
+
33
+ Args:
34
+ Enum (_type_): _description_
35
+ """
30
36
  CENTER = 1
31
37
  CORNER = 2
32
38
 
@@ -285,9 +285,18 @@ class GeoObject:
285
285
 
286
286
  def _add_face_pointer(self,
287
287
  name: str,
288
- origin: np.ndarray,
289
- normal: np.ndarray):
290
- self._face_pointers[name] = _FacePointer(origin, normal)
288
+ origin: np.ndarray | None = None,
289
+ normal: np.ndarray | None = None,
290
+ tag: int | None = None):
291
+ if tag is not None:
292
+ o = gmsh.model.occ.get_center_of_mass(2, tag)
293
+ n = gmsh.model.get_normal(tag, (0,0))
294
+ self._face_pointers[name] = _FacePointer(o, n)
295
+ return
296
+ if origin is not None and normal is not None:
297
+ self._face_pointers[name] = _FacePointer(origin, normal)
298
+ return
299
+ raise ValueError('Eitehr a tag or an origin + normal must be provided!')
291
300
 
292
301
  def make_copy(self) -> GeoObject:
293
302
  new_dimtags = gmsh.model.occ.copy(self.dimtags)
@@ -18,11 +18,14 @@
18
18
  from loguru import logger
19
19
  import sys
20
20
  from typing import Literal
21
- from enum import Enum
22
21
  from pathlib import Path
23
22
  import os
24
- import gmsh
23
+ from collections import deque
25
24
 
25
+ _LOG_BUFFER = deque()
26
+
27
+ def _log_sink(message):
28
+ _LOG_BUFFER.append(message)
26
29
  ############################################################
27
30
  # FORMATS #
28
31
  ############################################################
@@ -82,6 +85,14 @@ class LogController:
82
85
  format=FORMAT_DICT.get(loglevel, INFO_FORMAT))
83
86
  self.std_handlers.append(handle_id)
84
87
 
88
+ def _set_log_buffer(self):
89
+ logger.add(_log_sink)
90
+
91
+ def _flush_log_buffer(self):
92
+ for msg in list(_LOG_BUFFER):
93
+ logger.opt(depth=6).log(msg.record["level"].name, msg.record["message"])
94
+ _LOG_BUFFER.clear()
95
+
85
96
  def set_std_loglevel(self, loglevel: str):
86
97
  handler = {"sink": sys.stdout,
87
98
  "level": loglevel,
@@ -310,6 +310,8 @@ class Material:
310
310
 
311
311
  self.color: str = color
312
312
  self.opacity: float = opacity
313
+ self._hash_key: int = -1
314
+
313
315
  if _neff is None:
314
316
  self._neff: Callable = lambda f: np.sqrt(self.ur._fmax(f)*self.er._fmax(f))
315
317
  else:
@@ -318,8 +320,14 @@ class Material:
318
320
  self._color_rgb = tuple(int(hex_str[i:i+2], 16)/255.0 for i in (0, 2, 4))
319
321
  self._metal: bool = _metal
320
322
 
323
+ def __hash__(self):
324
+ return self._hash_key
325
+
321
326
  def __str__(self) -> str:
322
- return f'Material({self.name})'
327
+ return f'Material({self.name}, {self._hash_key})'
328
+
329
+ def __repr__(self):
330
+ return f'Material({self.name}, {self._hash_key})'
323
331
 
324
332
  def initialize(self, xs: np.ndarray, ys: np.ndarray, zs: np.ndarray, ids: np.ndarray):
325
333
  """Initializes the Material properties to be evaluated at xyz-coordinates for
@@ -343,6 +351,7 @@ class Material:
343
351
  self.ur.reset()
344
352
  self.tand.reset()
345
353
  self.cond.reset()
354
+ self._hash_key = -1
346
355
 
347
356
  @property
348
357
  def frequency_dependent(self) -> bool:
emerge/_emerge/mesh3d.py CHANGED
@@ -544,22 +544,33 @@ class Mesh3D(Mesh):
544
544
  #arry = np.zeros((3,3,self.n_tets,), dtype=np.complex128)
545
545
  for vol in volumes:
546
546
  vol.material.reset()
547
-
547
+
548
548
  materials = []
549
+ i = 0
550
+ for vol in volumes:
551
+ if vol.material not in materials:
552
+ materials.append(vol.material)
553
+ vol.material._hash_key = i
554
+ i += 1
549
555
 
550
556
  xs = self.centers[0,:]
551
557
  ys = self.centers[1,:]
552
558
  zs = self.centers[2,:]
553
559
 
560
+ matassign = -1*np.ones((self.n_tets,), dtype=np.int64)
561
+
554
562
  for volume in sorted(volumes, key=lambda x: x._priority):
555
563
 
556
564
  for dimtag in volume.dimtags:
557
565
  etype, etag_list, ntags = gmsh.model.mesh.get_elements(*dimtag)
558
566
  for etags in etag_list:
559
567
  tet_ids = np.array([self.tet_t2i[t] for t in etags])
560
- volume.material.initialize(xs[tet_ids], ys[tet_ids], zs[tet_ids], tet_ids)
561
- if volume.material not in materials:
562
- materials.append(volume.material)
568
+ matassign[tet_ids] = volume.material._hash_key
569
+
570
+ for mat in materials:
571
+ ids = np.argwhere(matassign==mat._hash_key).flatten()
572
+ mat.initialize(xs[ids], ys[ids], zs[ids], ids)
573
+
563
574
 
564
575
  return materials
565
576
 
@@ -53,7 +53,7 @@ def run_job_multi(job: SimJob) -> SimJob:
53
53
  Returns:
54
54
  SimJob: The solved SimJob
55
55
  """
56
- routine = DEFAULT_ROUTINE.duplicate()._configure_routine('MP')
56
+ routine = DEFAULT_ROUTINE._configure_routine('MP')
57
57
  for A, b, ids, reuse, aux in job.iter_Ab():
58
58
  solution, report = routine.solve(A, b, ids, reuse, id=job.id)
59
59
  report.add(**aux)
@@ -306,11 +306,17 @@ class AbsorbingBoundary(RobinBC):
306
306
  Returns:
307
307
  complex: The γ-constant
308
308
  """
309
- return 1j*self.get_beta(k0)
309
+ if self.order == 2:
310
+
311
+ p0 = 1.06103
312
+ p2 = -0.84883
313
+ ky = k0*0.5
314
+ return 1j*k0*p0 - 1j*p2*ky**2/k0
315
+ else:
316
+ Factor = 1
317
+ return 1j*self.get_beta(k0)*Factor
310
318
 
311
- def get_Uinc(self, x_local: np.ndarray, y_local: np.ndarray, k0: float) -> np.ndarray:
312
- return np.zeros((3, len(x_local)), dtype=np.complex128)
313
-
319
+
314
320
  @dataclass
315
321
  class PortMode:
316
322
  modefield: np.ndarray
@@ -825,9 +831,9 @@ class LumpedPort(PortBC):
825
831
  self.Vdirection: Axis = direction # type: ignore
826
832
  self.type = 'TEM'
827
833
 
828
- logger.info('Constructing coordinate system from normal port')
829
- self.cs = Axis(self.selection.normal).construct_cs() # type: ignore
830
-
834
+ # logger.info('Constructing coordinate system from normal port')
835
+ # self.cs = Axis(self.selection.normal).construct_cs() # type: ignore
836
+ self.cs = GCS
831
837
  self.vintline: Line | None = None
832
838
  self.v_integration = True
833
839
 
@@ -881,14 +887,7 @@ class LumpedPort(PortBC):
881
887
  k0: float,
882
888
  which: Literal['E','H'] = 'E') -> np.ndarray:
883
889
  ''' Compute the port mode E-field in local coordinates (XY) + Z out of plane.'''
884
-
885
- px, py, pz = self.cs.in_local_basis(*self.Vdirection.np)
886
-
887
- Ex = px*np.ones_like(x_local)
888
- Ey = py*np.ones_like(x_local)
889
- Ez = pz*np.ones_like(x_local)
890
- Exyz = np.array([Ex, Ey, Ez])
891
- return Exyz
890
+ raise RuntimeError('This function should never be called in this context.')
892
891
 
893
892
  def port_mode_3d_global(self,
894
893
  x_global: np.ndarray,
@@ -911,10 +910,9 @@ class LumpedPort(PortBC):
911
910
  Returns:
912
911
  np.ndarray: The E-field in (3,N) indexing.
913
912
  """
914
- xl, yl, _ = self.cs.in_local_cs(x_global, y_global, z_global)
915
- Ex, Ey, Ez = self.port_mode_3d(xl, yl, k0)
916
- Exg, Eyg, Ezg = self.cs.in_global_basis(Ex, Ey, Ez)
917
- return np.array([Exg, Eyg, Ezg])
913
+ ON = np.ones_like(x_global)
914
+ Ex, Ey, Ez = self.Vdirection.np
915
+ return np.array([Ex*ON, Ey*ON, Ez*ON])
918
916
 
919
917
 
920
918
  class LumpedElement(RobinBC):
@@ -596,7 +596,7 @@ class PVDisplay(BaseDisplay):
596
596
 
597
597
 
598
598
  if scale=='log':
599
- T = lambda x: np.log10(np.abs(x))
599
+ T = lambda x: np.log10(np.abs(x+1e-12))
600
600
  elif scale=='symlog':
601
601
  T = lambda x: np.sign(x) * np.log10(1 + np.abs(x*np.log(10)))
602
602
  else:
@@ -422,9 +422,14 @@ def plot_sp(f: np.ndarray | list[np.ndarray], S: list[np.ndarray] | np.ndarray,
422
422
  show_plot: bool = True,
423
423
  figdata: tuple | None = None) -> tuple[plt.Figure, plt.Axes, plt.Axes]:
424
424
  """Plot S-parameters in dB and phase
425
+
426
+ One may provide:
427
+ - A single frequency with a single S-parameter
428
+ - A single frequency with a list of S-parameters
429
+ - A list of frequencies with a list of S-parameters
425
430
 
426
431
  Args:
427
- f (np.ndarray): Frequency vector
432
+ f (np.ndarray | list[np.ndarray]): Frequency vector or list of frequencies
428
433
  S (list[np.ndarray] | np.ndarray): S-parameters to plot (list or single array)
429
434
  dblim (list, optional): Decibel y-axis limit. Defaults to [-80, 5].
430
435
  xunit (str, optional): Frequency unit. Defaults to "GHz".
@@ -535,7 +540,7 @@ def plot_sp(f: np.ndarray | list[np.ndarray], S: list[np.ndarray] | np.ndarray,
535
540
 
536
541
 
537
542
  def plot_ff(
538
- theta: np.ndarray,
543
+ theta: np.ndarray | list[np.ndarray],
539
544
  E: Union[np.ndarray, Sequence[np.ndarray]],
540
545
  grid: bool = True,
541
546
  dB: bool = False,
@@ -554,7 +559,7 @@ def plot_ff(
554
559
 
555
560
  Parameters
556
561
  ----------
557
- theta : np.ndarray
562
+ theta : np.ndarray | list[np.ndarray]
558
563
  Angle array (radians).
559
564
  E : np.ndarray or sequence of np.ndarray
560
565
  Complex E-field samples; magnitude will be plotted.
@@ -575,6 +580,12 @@ def plot_ff(
575
580
  E_list = [E]
576
581
  else:
577
582
  E_list = list(E)
583
+
584
+ if not isinstance(theta, list):
585
+ thetas = [theta for _ in E_list]
586
+ else:
587
+ thetas = theta
588
+
578
589
  n_series = len(E_list)
579
590
 
580
591
  # Style broadcasting
@@ -591,6 +602,7 @@ def plot_ff(
591
602
 
592
603
  fig, ax = plt.subplots()
593
604
  for i, Ei in enumerate(E_list):
605
+ theta = thetas[i]
594
606
  mag = np.abs(Ei)
595
607
  if dB:
596
608
  mag = 20*np.log10(mag)
@@ -68,7 +68,7 @@ class Simulation:
68
68
  loglevel: Literal['TRACE','DEBUG','INFO','WARNING','ERROR'] = 'INFO',
69
69
  load_file: bool = False,
70
70
  save_file: bool = False,
71
- logfile: bool = False,
71
+ write_log: bool = False,
72
72
  path_suffix: str = ".EMResults"):
73
73
  """Generate a Simulation class object.
74
74
 
@@ -80,7 +80,7 @@ class Simulation:
80
80
  loglevel ("DEBUG","INFO","WARNING","ERROR", optional): The loglevel to use for loguru. Defaults to 'INFO'.
81
81
  load_file (bool, optional): If the simulatio model should be loaded from a file. Defaults to False.
82
82
  save_file (bool, optional): if the simulation file should be stored to a file. Defaults to False.
83
- logfile (bool, optional): If a file should be created that contains the entire log of the simulation. Defaults to False.
83
+ write_log (bool, optional): If a file should be created that contains the entire log of the simulation. Defaults to False.
84
84
  path_suffix (str, optional): The suffix that will be added to the results directory. Defaults to ".EMResults".
85
85
  """
86
86
 
@@ -113,9 +113,10 @@ class Simulation:
113
113
  self._initialize_simulation()
114
114
 
115
115
  self.set_loglevel(loglevel)
116
- if logfile:
117
- self.set_logfile()
116
+ if write_log:
117
+ self.set_write_log()
118
118
 
119
+ LOG_CONTROLLER._flush_log_buffer()
119
120
  self._update_data()
120
121
 
121
122
 
@@ -324,7 +325,7 @@ class Simulation:
324
325
  if loglevel not in ('TRACE','DEBUG'):
325
326
  gmsh.option.setNumber("General.Terminal", 0)
326
327
 
327
- def set_logfile(self) -> None:
328
+ def set_write_log(self) -> None:
328
329
  """Adds a file output for the logger."""
329
330
  LOG_CONTROLLER.set_write_file(self.modelpath)
330
331
 
@@ -15,7 +15,16 @@
15
15
  # along with this program; if not, see
16
16
  # <https://www.gnu.org/licenses/>.
17
17
 
18
- import cupy as cp # ty: ignore
18
+ import warnings
19
+ from loguru import logger
20
+
21
+ # Catch the Cuda warning and print it with Loguru.
22
+ with warnings.catch_warnings(record=True) as w:
23
+ warnings.simplefilter("always")
24
+ import cupy as cp
25
+ for warn in w:
26
+ logger.debug(f"{warn.category.__name__}: {warn.message}")
27
+
19
28
  import nvmath.bindings.cudss as cudss # ty: ignore
20
29
  from nvmath import CudaDataType # ty: ignore
21
30
 
@@ -23,9 +32,6 @@ from scipy.sparse import csr_matrix
23
32
  import numpy as np
24
33
  from typing import Literal
25
34
 
26
- from loguru import logger
27
-
28
-
29
35
  ############################################################
30
36
  # CONSTANTS #
31
37
  ############################################################
emerge/_emerge/solver.py CHANGED
@@ -504,6 +504,7 @@ class SolverSuperLU(Solver):
504
504
  logger.info(f'[ID={id}] Calling SuperLU Solver.')
505
505
  self.single = True
506
506
  if not reuse_factorization:
507
+ logger.trace('Computing LU-Decomposition')
507
508
  self.lu = splu(A, permc_spec='MMD_AT_PLUS_A', relax=0, diag_pivot_thresh=self._pivoting_threshold, options=self.options)
508
509
  x = self.lu.solve(b)
509
510
  aux = {
@@ -518,6 +519,7 @@ class SolverUMFPACK(Solver):
518
519
 
519
520
  def __init__(self):
520
521
  super().__init__()
522
+ logger.trace('Creating UMFPACK solver')
521
523
  self.A: np.ndarray = None
522
524
  self.b: np.ndarray = None
523
525
 
@@ -532,6 +534,7 @@ class SolverUMFPACK(Solver):
532
534
  def initialize(self):
533
535
  if self.initalized:
534
536
  return
537
+ logger.trace('Initializing UMFPACK Solver')
535
538
  self.umfpack = um.UmfpackContext('zl')
536
539
  self.umfpack.control[um.UMFPACK_PRL] = 0 # ty: ignore
537
540
  self.umfpack.control[um.UMFPACK_IRSTEP] = 2 # ty: ignore
@@ -542,7 +545,9 @@ class SolverUMFPACK(Solver):
542
545
  self.umfpack.control[um.UMFPACK_BLOCK_SIZE] = 64 # ty: ignore
543
546
  self.umfpack.control[um.UMFPACK_FIXQ] = -1 # ty: ignore
544
547
  self.initalized = True
548
+
545
549
  def reset(self) -> None:
550
+ logger.trace('Resetting UMFPACK solver state')
546
551
  self.fact_symb = False
547
552
 
548
553
  def set_options(self, pivoting_threshold: float | None = None) -> None:
@@ -562,13 +567,14 @@ class SolverUMFPACK(Solver):
562
567
  A.indptr = A.indptr.astype(np.int64)
563
568
  A.indices = A.indices.astype(np.int64)
564
569
  if self.fact_symb is False:
565
- logger.debug(f'[ID={id}] Executing symbollic factorization.')
570
+ logger.trace(f'[ID={id}] Executing symbollic factorization.')
566
571
  self.umfpack.symbolic(A)
567
572
  self.fact_symb = True
568
573
  if not reuse_factorization:
569
- #logger.debug('Executing numeric factorization.')
574
+ logger.trace(f'[ID={id}] Executing numeric factorization.')
570
575
  self.umfpack.numeric(A)
571
576
  self.A = A
577
+ logger.trace(f'[ID={id}] Solving linear system.')
572
578
  x = self.umfpack.solve(um.UMFPACK_A, self.A, b, autoTranspose = False ) # ty: ignore
573
579
  aux = {
574
580
  "Pivoting Threshold": str(self._pivoting_threshold),
@@ -596,12 +602,14 @@ class SolverPardiso(Solver):
596
602
  def solve(self, A, b, precon, reuse_factorization: bool = False, id: int = -1) -> tuple[np.ndarray, SolveReport]:
597
603
  logger.info(f'[ID={id}] Calling Pardiso Solver')
598
604
  if self.fact_symb is False:
599
- logger.debug(f'[ID={id}] Executing symbollic factorization.')
605
+ logger.trace(f'[ID={id}] Executing symbollic factorization.')
600
606
  self.solver.symbolic(A)
601
607
  self.fact_symb = True
602
608
  if not reuse_factorization:
609
+ logger.trace(f'[ID={id}] Executing numeric factorization.')
603
610
  self.solver.numeric(A)
604
611
  self.A = A
612
+ logger.trace(f'[ID={id}] Solving linear system.')
605
613
  x, error = self.solver.solve(A, b)
606
614
  if error != 0:
607
615
  logger.error(f'[ID={id}] Terminated with error code {error}')
@@ -634,13 +642,15 @@ class CuDSSSolver(Solver):
634
642
  logger.info(f'[ID={id}] Calling cuDSS Solver')
635
643
 
636
644
  if self.fact_symb is False:
637
- logger.debug('Executing symbollic factorization')
645
+ logger.trace(f'[ID={id}] Starting from symbollic factorization.')
638
646
  x = self._cudss.from_symbolic(A,b)
639
647
  self.fact_symb = True
640
648
  else:
641
649
  if reuse_factorization:
650
+ logger.trace(f'[ID={id}] Solving linear system.')
642
651
  x = self._cudss.from_solve(b)
643
652
  else:
653
+ logger.trace(f'[ID={id}] Starting from numeric factorization.')
644
654
  x = self._cudss.from_numeric(A,b)
645
655
 
646
656
  return x, SolveReport(solver=str(self), exit_code=0, aux={})
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: emerge
3
- Version: 0.6.9
3
+ Version: 0.6.10
4
4
  Summary: An open source EM FEM simulator in Python
5
5
  Project-URL: Homepage, https://github.com/FennisRobert/EMerge
6
6
  Project-URL: Issues, https://github.com/FennisRobert/EMerge/issues
@@ -1,4 +1,4 @@
1
- emerge/__init__.py,sha256=CADecqlZ97GZvSCPedEzhmI3N_1o0qeCaaxgjlUccio,2693
1
+ emerge/__init__.py,sha256=8FrSyF_ro5TDOwMM76VyItYnpfiK_LOumuCAugk2DiI,2977
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
@@ -10,21 +10,21 @@ emerge/_emerge/_cache_check.py,sha256=_m9rV-VcaC4uNfETZ2Rp1tkA-gZ5FD3xL3KOHlgdvy
10
10
  emerge/_emerge/bc.py,sha256=TeSVNkDgOGaoHw5raTzhUV0ngtyHa33sXAoL2hRn70M,8077
11
11
  emerge/_emerge/const.py,sha256=PTZZTSDOP5NsZ8XnJrKTY2P0tPUhmutBJ1yrm-t7xsI,129
12
12
  emerge/_emerge/coord.py,sha256=BKvyrcnHY-_bgHqysnByy5k9_DK4VVfr9KKkRaawG2E,4371
13
- emerge/_emerge/cs.py,sha256=YNT2Nn6Dh8fYPUMlT6w0msHnQpZREbbl_ZXTGNppCVs,18392
13
+ emerge/_emerge/cs.py,sha256=gULfov6s0jODOdQkH6NmGBbG5wvny1-bJU8fdAlpCHo,19730
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=z6MxW7Q2i1pu12pPaAvIf5PsP84ea3GY2MOG_daLx_8,19537
16
+ emerge/_emerge/geometry.py,sha256=OcQ0wvritkg7Q8oihQI_hLjDGx7JkFaPwfEeJ3_u3Bs,19987
17
17
  emerge/_emerge/howto.py,sha256=c4UxUNpA1tygr3OoR-LH-h0UZv-Tf9K8tpCiAU18BKE,8173
18
- emerge/_emerge/logsettings.py,sha256=DcUWIUUhdLe9ev5XC1bd5ZUrJz00MjABkY8rnekFrPY,3373
19
- emerge/_emerge/material.py,sha256=FITj4pGlJw6AwsxC275lMbbCJ38mIjwGpA9omblq6ck,15228
20
- emerge/_emerge/mesh3d.py,sha256=2expfu7YR6KbtaEeR7JELxXkTul0cFECRwwO5bpdgqE,34697
18
+ emerge/_emerge/logsettings.py,sha256=s8UboFEtB0aIuLB2FSL2WIbw0_kB363iHNIy4uGQi7w,3711
19
+ emerge/_emerge/material.py,sha256=bVuMyrmts08at4nUc4ttgYHPsY1cLYNKNmJ4RwgR9TY,15462
20
+ emerge/_emerge/mesh3d.py,sha256=qmdbuuR6W_5nMg7K5fts08v2lk0K8otUO6C4gS0Zjks,35008
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
24
  emerge/_emerge/selection.py,sha256=Clx3YopcYwaN61rX4wdDsEJo_0F-DWGe3AP8rPjvTzY,21368
25
- emerge/_emerge/simmodel.py,sha256=lzrWtPQlhKHs4QHTj-icg2tycCn_zhq4PITHhAhC9I0,20451
25
+ emerge/_emerge/simmodel.py,sha256=qycNtzKgNllQvPQrbSlKhimJQ1ucMIEM-BsKCrHJemE,20504
26
26
  emerge/_emerge/simulation_data.py,sha256=r9-9lpLeA1Z5HU3jDVOXV1H80GVawnXL5K81_dvmlE4,14506
27
- emerge/_emerge/solver.py,sha256=kZr_lNnLbHe2LBO9ujyHdfh47jc_qqnFgrlPwhZZMHE,49348
27
+ emerge/_emerge/solver.py,sha256=J7aIpW7Eni56wnVhXL2JSuwRf8HuTBQCUrXKx31u5EU,49927
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=o5P-lRAW_xWEOQ_jrT5zRciFZwq1LqCIXfaWurWdjmw,8082
@@ -38,8 +38,8 @@ emerge/_emerge/geo/modeler.py,sha256=_PMz3lFSa7FmJHWdY-4U1Sqbed-Egy85S_AdjlCldC4
38
38
  emerge/_emerge/geo/operations.py,sha256=lqfCU99uiLc0vDGqILpMP1YgKs1e-gwEcSLbI_gE6TA,12441
39
39
  emerge/_emerge/geo/pcb.py,sha256=MmY-A-Xnd85aQw6ouOnsZKcui_kH86fw4l0GoR4qQu0,53442
40
40
  emerge/_emerge/geo/pmlbox.py,sha256=gaIG_AoZNQnIyJ8C7x64U-Hw5dsmllWMiZDAH4iRoM0,8784
41
- emerge/_emerge/geo/polybased.py,sha256=loVJRBjYCTUlti5tHwfH8iU-Inb6n2sOS2Cw4gVKid4,31917
42
- emerge/_emerge/geo/shapes.py,sha256=-ct-TJh69oj5fqJcQql4pNk3acJWTIQzYOQeAFXDfWk,23319
41
+ emerge/_emerge/geo/polybased.py,sha256=3Lpbbw6o9ypTvInMNcLa-zF5jP8uOSn9c_Tiv_R85cc,33055
42
+ emerge/_emerge/geo/shapes.py,sha256=i0kcwC1EqOpXonJUhdpRKfed3MaFnPsEc_vgTfRSWwI,23532
43
43
  emerge/_emerge/geo/step.py,sha256=XcAiEN8W4umNmZdYmrGHX_aJUuiMgc6vgT-UIk8Gbqc,2689
44
44
  emerge/_emerge/geo/pcb_tools/calculator.py,sha256=VbMP2xC9i7OFwtqnnwfYgyJSEcJIjr2VIy_Ez1hYqlU,859
45
45
  emerge/_emerge/geo/pcb_tools/macro.py,sha256=0g-0anOFyxrEkFobiSu0cwWFRQ32xB8Az24mmwo0z6M,2992
@@ -50,8 +50,8 @@ emerge/_emerge/mth/pairing.py,sha256=i8bBvTeMmzgF0JdiDNJiTXxx913x4f10777pzD6FJo0
50
50
  emerge/_emerge/physics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
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
- emerge/_emerge/physics/microwave/microwave_3d.py,sha256=lKHaMcL8kztwUF4V9zUycT7Ec7aTZS9SAiZh6auzCYc,42379
54
- emerge/_emerge/physics/microwave/microwave_bc.py,sha256=dU2vi8amEewM1ZLgtOk4oYXknH_gzt2c6J9BH4aIJiw,42294
53
+ emerge/_emerge/physics/microwave/microwave_3d.py,sha256=ocyLCLt6iZ2FlmqLvNCqxSDKdFRirUFRQYGNi8xgyRk,42367
54
+ emerge/_emerge/physics/microwave/microwave_bc.py,sha256=YaEkSyOsC9Di7-JItijuRKD60ZA9CmEX8Tu8pViMN90,42114
55
55
  emerge/_emerge/physics/microwave/microwave_data.py,sha256=njeNfw_Is4bc97H-hefi-Bk8NSGMElXk0yzDb4v6mVk,50365
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
@@ -67,19 +67,19 @@ emerge/_emerge/physics/microwave/assembly/periodicbc.py,sha256=Zg1kgQMccDQA2oVEr
67
67
  emerge/_emerge/physics/microwave/assembly/robinbc.py,sha256=syJ-NuHHA0WDQECuaPdeW-OfzIGHmxxqalKiokSyJFI,17742
68
68
  emerge/_emerge/plot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
69
69
  emerge/_emerge/plot/display.py,sha256=TQLlKb-LkaG5ZOSLfxp9KXPlZPRFTxNj1LhVQ-Lp1-s,18476
70
- emerge/_emerge/plot/simple_plots.py,sha256=qMQoMdSdTMQX5LvjI1n_dpZ6e51LzRCUOZuu5uHPd3w,24806
70
+ emerge/_emerge/plot/simple_plots.py,sha256=lzAyLpY4yaAgMBgNkpeIxdrdSp5nQH6JmBI_ZfjzuhY,25229
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=GJ_fmU1AWLzPWwl3CQd50LOOmjEQ0JWaNFOk17Ux60M,38348
73
+ emerge/_emerge/plot/pyvista/display.py,sha256=Y8BT3ML9eeSQw_HLDmi3KCe0xtA8qOahOnCPGgvnM2g,38354
74
74
  emerge/_emerge/plot/pyvista/display_settings.py,sha256=k4JfiNuaVDpPZrZa0sIuuFFwLvYAWDS17tusUCVHNu0,1036
75
75
  emerge/_emerge/projects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
76
  emerge/_emerge/projects/_gen_base.txt,sha256=DqQz36PZg6v1ovQjHvPjd0t4AIbmikZdb9dmrNYsK3w,598
77
77
  emerge/_emerge/projects/_load_base.txt,sha256=bHsZ4okxa9uu8qP4UOxSAeIQzuwpRtN0i71rg8wuqMA,473
78
78
  emerge/_emerge/projects/generate_project.py,sha256=TNw-0SpLc82MBq0bd9hB_yqvBZCgmuPonCBsHTp91uk,1450
79
- emerge/_emerge/solve_interfaces/cudss_interface.py,sha256=-SjiTNIyE7iJ8Bm14Cva5e2lpJDgfiS2Mvz1Bgy-UL4,9688
79
+ emerge/_emerge/solve_interfaces/cudss_interface.py,sha256=Iszyy7RuuCa_FgfROEyTSSWbmR2LzMUkEcR8klzIKOQ,9915
80
80
  emerge/_emerge/solve_interfaces/pardiso_interface.py,sha256=iVFxToMmIzhj3hcAP-O_MDHKz82ePFIHY1us11kzUBU,15305
81
- emerge-0.6.9.dist-info/METADATA,sha256=yAvC6lujrzubYu_H2qBafFx1k3c_kuoO3gD83cldhtA,3338
82
- emerge-0.6.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
83
- emerge-0.6.9.dist-info/entry_points.txt,sha256=8rFvAXticpKg4OTC8JEvAksnduW72KIEskCGG9XnFf8,43
84
- emerge-0.6.9.dist-info/licenses/LICENSE,sha256=VOCXWddrjMN5j7TvnSAOh1Dx7jkugdwq9Lqhycf5inc,17852
85
- emerge-0.6.9.dist-info/RECORD,,
81
+ emerge-0.6.10.dist-info/METADATA,sha256=tmedxST_2MpgTZXZK7GGc0RMNt_9DjEMKlJjw6IFh0g,3339
82
+ emerge-0.6.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
83
+ emerge-0.6.10.dist-info/entry_points.txt,sha256=8rFvAXticpKg4OTC8JEvAksnduW72KIEskCGG9XnFf8,43
84
+ emerge-0.6.10.dist-info/licenses/LICENSE,sha256=VOCXWddrjMN5j7TvnSAOh1Dx7jkugdwq9Lqhycf5inc,17852
85
+ emerge-0.6.10.dist-info/RECORD,,