emerge 0.6.8__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 +12 -3
- emerge/_emerge/cs.py +36 -0
- emerge/_emerge/geo/polybased.py +58 -26
- emerge/_emerge/geo/shapes.py +6 -0
- emerge/_emerge/geometry.py +21 -5
- emerge/_emerge/logsettings.py +13 -2
- emerge/_emerge/material.py +19 -3
- emerge/_emerge/mesh3d.py +15 -4
- emerge/_emerge/physics/microwave/microwave_3d.py +1 -1
- emerge/_emerge/physics/microwave/microwave_bc.py +33 -39
- emerge/_emerge/physics/microwave/microwave_data.py +29 -2
- emerge/_emerge/plot/pyvista/display.py +33 -5
- emerge/_emerge/plot/pyvista/display_settings.py +4 -1
- emerge/_emerge/plot/simple_plots.py +56 -28
- emerge/_emerge/projects/_load_base.txt +1 -2
- emerge/_emerge/selection.py +4 -0
- emerge/_emerge/simmodel.py +15 -9
- emerge/_emerge/solve_interfaces/cudss_interface.py +10 -4
- emerge/_emerge/solver.py +14 -4
- emerge/lib.py +256 -250
- {emerge-0.6.8.dist-info → emerge-0.6.10.dist-info}/METADATA +2 -1
- {emerge-0.6.8.dist-info → emerge-0.6.10.dist-info}/RECORD +25 -25
- {emerge-0.6.8.dist-info → emerge-0.6.10.dist-info}/WHEEL +0 -0
- {emerge-0.6.8.dist-info → emerge-0.6.10.dist-info}/entry_points.txt +0 -0
- {emerge-0.6.8.dist-info → emerge-0.6.10.dist-info}/licenses/LICENSE +0 -0
|
@@ -284,15 +284,16 @@ class PVDisplay(BaseDisplay):
|
|
|
284
284
|
self._ruler.min_length = max(1e-3, min(self._mesh.edge_lengths))
|
|
285
285
|
self._update_camera()
|
|
286
286
|
self._add_aux_items()
|
|
287
|
+
# self._plot.renderer.enable_depth_peeling(20, 0.8)
|
|
288
|
+
# self._plot.enable_anti_aliasing(self.set.anti_aliassing)
|
|
287
289
|
if self._do_animate:
|
|
288
290
|
self._wire_close_events()
|
|
289
291
|
self.add_text('Press Q to close!',color='red', position='upper_left')
|
|
290
292
|
self._plot.show(auto_close=False, interactive_update=True, before_close_callback=self._close_callback)
|
|
291
293
|
self._animate()
|
|
292
|
-
|
|
293
|
-
|
|
294
294
|
else:
|
|
295
295
|
self._plot.show()
|
|
296
|
+
|
|
296
297
|
self._reset()
|
|
297
298
|
|
|
298
299
|
def set_mesh(self, mesh: Mesh3D):
|
|
@@ -440,8 +441,20 @@ class PVDisplay(BaseDisplay):
|
|
|
440
441
|
opacity = obj.opacity
|
|
441
442
|
line_width = 0.5
|
|
442
443
|
color = obj.color_rgb
|
|
444
|
+
metal = obj._metal
|
|
443
445
|
style='surface'
|
|
444
446
|
|
|
447
|
+
# Default render settings
|
|
448
|
+
metallic = 0.05
|
|
449
|
+
roughness = 0.5
|
|
450
|
+
pbr = False
|
|
451
|
+
|
|
452
|
+
if metal:
|
|
453
|
+
pbr = True
|
|
454
|
+
metallic = 0.8
|
|
455
|
+
roughness = 0.3
|
|
456
|
+
|
|
457
|
+
# Default keyword arguments when plotting Mesh mode.
|
|
445
458
|
if mesh is True:
|
|
446
459
|
show_edges = True
|
|
447
460
|
opacity = 0.7
|
|
@@ -449,13 +462,28 @@ class PVDisplay(BaseDisplay):
|
|
|
449
462
|
style='wireframe'
|
|
450
463
|
color=next(C_CYCLE)
|
|
451
464
|
|
|
452
|
-
|
|
465
|
+
# Defining the default keyword arguments for PyVista
|
|
466
|
+
kwargs = setdefault(kwargs, color=color,
|
|
467
|
+
opacity=opacity,
|
|
468
|
+
metallic=metallic,
|
|
469
|
+
pbr=pbr,
|
|
470
|
+
roughness=roughness,
|
|
471
|
+
line_width=line_width,
|
|
472
|
+
show_edges=show_edges,
|
|
473
|
+
pickable=True,
|
|
474
|
+
style=style)
|
|
453
475
|
mesh_obj = self.mesh(obj)
|
|
454
476
|
|
|
455
477
|
if mesh is True and volume_mesh is True:
|
|
456
478
|
mesh_obj = mesh_obj.extract_all_edges()
|
|
457
|
-
|
|
458
479
|
actor = self._plot.add_mesh(mesh_obj, *args, **kwargs)
|
|
480
|
+
|
|
481
|
+
# Push 3D Geometries back to avoid Z-fighting with 2D geometries.
|
|
482
|
+
if obj.dim==3:
|
|
483
|
+
mapper = actor.GetMapper()
|
|
484
|
+
mapper.SetResolveCoincidentTopology(1)
|
|
485
|
+
mapper.SetRelativeCoincidentTopologyPolygonOffsetParameters(1,1)
|
|
486
|
+
|
|
459
487
|
self._plot.add_mesh(self._volume_edges(_select(obj)), color='#000000', line_width=2, show_edges=True)
|
|
460
488
|
|
|
461
489
|
def add_scatter(self, xs: np.ndarray, ys: np.ndarray, zs: np.ndarray):
|
|
@@ -568,7 +596,7 @@ class PVDisplay(BaseDisplay):
|
|
|
568
596
|
|
|
569
597
|
|
|
570
598
|
if scale=='log':
|
|
571
|
-
T = lambda x: np.log10(np.abs(x))
|
|
599
|
+
T = lambda x: np.log10(np.abs(x+1e-12))
|
|
572
600
|
elif scale=='symlog':
|
|
573
601
|
T = lambda x: np.sign(x) * np.log10(1 + np.abs(x*np.log(10)))
|
|
574
602
|
else:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from typing import Literal
|
|
1
2
|
|
|
2
3
|
class PVDisplaySettings:
|
|
3
4
|
|
|
@@ -22,4 +23,6 @@ class PVDisplaySettings:
|
|
|
22
23
|
self.background_bottom: str = "#c0d2e8"
|
|
23
24
|
self.background_top: str = "#ffffff"
|
|
24
25
|
self.grid_line_color: str = "#8e8e8e"
|
|
25
|
-
self.z_boost: float = 1e-
|
|
26
|
+
self.z_boost: float = 0#1e-9
|
|
27
|
+
self.depth_peeling: bool = True
|
|
28
|
+
self.anti_aliassing: Literal["msaa","ssaa",'fxaa'] = "msaa"
|
|
@@ -406,25 +406,30 @@ and sparse frequency annotations (e.g., labeled by frequency).
|
|
|
406
406
|
plt.tight_layout()
|
|
407
407
|
plt.show()
|
|
408
408
|
|
|
409
|
-
def plot_sp(f: np.ndarray, S: list[np.ndarray] | np.ndarray,
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
409
|
+
def plot_sp(f: np.ndarray | list[np.ndarray], S: list[np.ndarray] | np.ndarray,
|
|
410
|
+
dblim=[-40, 5],
|
|
411
|
+
xunit="GHz",
|
|
412
|
+
levelindicator: int | float | None = None,
|
|
413
|
+
noise_floor=-150,
|
|
414
|
+
fill_areas: list[tuple] | None = None,
|
|
415
|
+
spec_area: list[tuple[float,...]] | None = None,
|
|
416
|
+
unwrap_phase=False,
|
|
417
|
+
logx: bool = False,
|
|
418
|
+
labels: list[str] | None = None,
|
|
419
|
+
linestyles: list[str] | None = None,
|
|
420
|
+
colorcycle: list[int] | None = None,
|
|
421
|
+
filename: str | None = None,
|
|
422
|
+
show_plot: bool = True,
|
|
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".
|
|
@@ -444,7 +449,12 @@ def plot_sp(f: np.ndarray, S: list[np.ndarray] | np.ndarray,
|
|
|
444
449
|
Ss = [S]
|
|
445
450
|
else:
|
|
446
451
|
Ss = S
|
|
447
|
-
|
|
452
|
+
|
|
453
|
+
if not isinstance(f, list):
|
|
454
|
+
fs = [f for _ in Ss]
|
|
455
|
+
else:
|
|
456
|
+
fs = f
|
|
457
|
+
|
|
448
458
|
if linestyles is None:
|
|
449
459
|
linestyles = ['-' for _ in S]
|
|
450
460
|
|
|
@@ -452,7 +462,8 @@ def plot_sp(f: np.ndarray, S: list[np.ndarray] | np.ndarray,
|
|
|
452
462
|
colorcycle = [i for i, S in enumerate(S)]
|
|
453
463
|
|
|
454
464
|
unitdivider: dict[str, float] = {"MHz": 1e6, "GHz": 1e9, "kHz": 1e3}
|
|
455
|
-
|
|
465
|
+
|
|
466
|
+
fs = [f / unitdivider[xunit] for f in fs]
|
|
456
467
|
|
|
457
468
|
if figdata is None:
|
|
458
469
|
# Create two subplots: one for magnitude and one for phase
|
|
@@ -463,10 +474,10 @@ def plot_sp(f: np.ndarray, S: list[np.ndarray] | np.ndarray,
|
|
|
463
474
|
minphase, maxphase = -180, 180
|
|
464
475
|
|
|
465
476
|
maxy = 0
|
|
466
|
-
for s, ls, cid in zip(Ss, linestyles, colorcycle):
|
|
477
|
+
for f, s, ls, cid in zip(fs, Ss, linestyles, colorcycle):
|
|
467
478
|
# Calculate and plot magnitude in dB
|
|
468
479
|
SdB = 20 * np.log10(np.abs(s) + 10**(noise_floor/20) * np.random.rand(*s.shape) + 10**((noise_floor-30)/20))
|
|
469
|
-
ax_mag.plot(
|
|
480
|
+
ax_mag.plot(f, SdB, label="Magnitude (dB)", linestyle=ls, color=EMERGE_COLORS[cid % len(EMERGE_COLORS)])
|
|
470
481
|
if np.max(SdB) > maxy:
|
|
471
482
|
maxy = np.max(SdB)
|
|
472
483
|
# Calculate and plot phase in degrees
|
|
@@ -475,12 +486,12 @@ def plot_sp(f: np.ndarray, S: list[np.ndarray] | np.ndarray,
|
|
|
475
486
|
phase = np.unwrap(phase, period=360)
|
|
476
487
|
minphase = min(np.min(phase), minphase)
|
|
477
488
|
maxphase = max(np.max(phase), maxphase)
|
|
478
|
-
ax_phase.plot(
|
|
489
|
+
ax_phase.plot(f, phase, label="Phase (degrees)", linestyle=ls, color=EMERGE_COLORS[cid % len(EMERGE_COLORS)])
|
|
479
490
|
|
|
480
491
|
# Annotate level indicators if specified
|
|
481
492
|
if isinstance(levelindicator, (int, float)) and levelindicator is not None:
|
|
482
493
|
lvl = levelindicator
|
|
483
|
-
fcross = hintersections(
|
|
494
|
+
fcross = hintersections(f, SdB, lvl)
|
|
484
495
|
for fs in fcross:
|
|
485
496
|
ax_mag.annotate(
|
|
486
497
|
f"{str(fs)[:4]}{xunit}",
|
|
@@ -500,16 +511,18 @@ def plot_sp(f: np.ndarray, S: list[np.ndarray] | np.ndarray,
|
|
|
500
511
|
f2 = fmax / unitdivider[xunit]
|
|
501
512
|
ax_mag.fill_between([f1, f2], vmin,vmax, color='red', alpha=0.2)
|
|
502
513
|
# Configure magnitude plot (ax_mag)
|
|
514
|
+
fmin = min([min(f) for f in fs])
|
|
515
|
+
fmax = max([max(f) for f in fs])
|
|
503
516
|
ax_mag.set_ylabel("Magnitude (dB)")
|
|
504
517
|
ax_mag.set_xlabel(f"Frequency ({xunit})")
|
|
505
|
-
ax_mag.axis([
|
|
518
|
+
ax_mag.axis([fmin, fmax, dblim[0], max(maxy*1.1,dblim[1])]) # type: ignore
|
|
506
519
|
ax_mag.axhline(y=0, color="k", linewidth=1)
|
|
507
520
|
ax_mag.xaxis.set_minor_locator(tck.AutoMinorLocator(2))
|
|
508
521
|
ax_mag.yaxis.set_minor_locator(tck.AutoMinorLocator(2))
|
|
509
522
|
# Configure phase plot (ax_phase)
|
|
510
523
|
ax_phase.set_ylabel("Phase (degrees)")
|
|
511
524
|
ax_phase.set_xlabel(f"Frequency ({xunit})")
|
|
512
|
-
ax_phase.axis([
|
|
525
|
+
ax_phase.axis([fmin, fmax, minphase, maxphase]) # type: ignore
|
|
513
526
|
ax_phase.xaxis.set_minor_locator(tck.AutoMinorLocator(2))
|
|
514
527
|
ax_phase.yaxis.set_minor_locator(tck.AutoMinorLocator(2))
|
|
515
528
|
if logx:
|
|
@@ -527,7 +540,7 @@ def plot_sp(f: np.ndarray, S: list[np.ndarray] | np.ndarray,
|
|
|
527
540
|
|
|
528
541
|
|
|
529
542
|
def plot_ff(
|
|
530
|
-
theta: np.ndarray,
|
|
543
|
+
theta: np.ndarray | list[np.ndarray],
|
|
531
544
|
E: Union[np.ndarray, Sequence[np.ndarray]],
|
|
532
545
|
grid: bool = True,
|
|
533
546
|
dB: bool = False,
|
|
@@ -546,7 +559,7 @@ def plot_ff(
|
|
|
546
559
|
|
|
547
560
|
Parameters
|
|
548
561
|
----------
|
|
549
|
-
theta : np.ndarray
|
|
562
|
+
theta : np.ndarray | list[np.ndarray]
|
|
550
563
|
Angle array (radians).
|
|
551
564
|
E : np.ndarray or sequence of np.ndarray
|
|
552
565
|
Complex E-field samples; magnitude will be plotted.
|
|
@@ -567,6 +580,12 @@ def plot_ff(
|
|
|
567
580
|
E_list = [E]
|
|
568
581
|
else:
|
|
569
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
|
+
|
|
570
589
|
n_series = len(E_list)
|
|
571
590
|
|
|
572
591
|
# Style broadcasting
|
|
@@ -583,6 +602,7 @@ def plot_ff(
|
|
|
583
602
|
|
|
584
603
|
fig, ax = plt.subplots()
|
|
585
604
|
for i, Ei in enumerate(E_list):
|
|
605
|
+
theta = thetas[i]
|
|
586
606
|
mag = np.abs(Ei)
|
|
587
607
|
if dB:
|
|
588
608
|
mag = 20*np.log10(mag)
|
|
@@ -612,6 +632,8 @@ def plot_ff(
|
|
|
612
632
|
def plot_ff_polar(
|
|
613
633
|
theta: np.ndarray,
|
|
614
634
|
E: Union[np.ndarray, Sequence[np.ndarray]],
|
|
635
|
+
dB: bool = False,
|
|
636
|
+
dBfloor: float = -30,
|
|
615
637
|
labels: Optional[List[str]] = None,
|
|
616
638
|
linestyles: Union[str, List[str]] = "-",
|
|
617
639
|
linewidth: float = 2.0,
|
|
@@ -649,6 +671,8 @@ def plot_ff_polar(
|
|
|
649
671
|
E_list = list(E)
|
|
650
672
|
n_series = len(E_list)
|
|
651
673
|
|
|
674
|
+
if dB:
|
|
675
|
+
E_list = [20*np.log10(np.clip(np.abs(e), a_min=10**(dBfloor/20), a_max = 1e9)) for e in E_list]
|
|
652
676
|
# Style broadcasting
|
|
653
677
|
def _broadcast(param, default):
|
|
654
678
|
if isinstance(param, list):
|
|
@@ -665,11 +689,15 @@ def plot_ff_polar(
|
|
|
665
689
|
ax.set_theta_zero_location(zero_location) # type: ignore
|
|
666
690
|
ax.set_theta_direction(-1 if clockwise else 1) # type: ignore
|
|
667
691
|
ax.set_rlabel_position(rlabel_angle) # type: ignore
|
|
692
|
+
ymin = min([min(E) for E in E_list])
|
|
693
|
+
ymax = max([max(E) for E in E_list])
|
|
694
|
+
yrange = ymax-ymin
|
|
668
695
|
|
|
696
|
+
ax.set_ylim(ymin-0.05*yrange, ymax+0.05*yrange)
|
|
669
697
|
for i, Ei in enumerate(E_list):
|
|
670
|
-
|
|
698
|
+
|
|
671
699
|
ax.plot(
|
|
672
|
-
theta,
|
|
700
|
+
theta, Ei,
|
|
673
701
|
linestyle=linestyles[i],
|
|
674
702
|
linewidth=linewidth,
|
|
675
703
|
marker=markers[i],
|
|
@@ -17,8 +17,7 @@ with em.Simulation("myfile", load_file=True) as m:
|
|
|
17
17
|
S11 = data.S(1,1)
|
|
18
18
|
S21 = data.S(2,1)
|
|
19
19
|
plt.plot_sp(f/1e9, [S11, S21])
|
|
20
|
-
|
|
21
|
-
m.set_mesh(m.data.mw.field[0].mesh)
|
|
20
|
+
|
|
22
21
|
m.display.add_object(m['box'])
|
|
23
22
|
m.display.add_surf(*m.data.mw.field[0].cutplane(1*mm, z=5*mm).scalar('Ez','real'))
|
|
24
23
|
m.display.show()
|
emerge/_emerge/selection.py
CHANGED
|
@@ -205,6 +205,10 @@ class Selection:
|
|
|
205
205
|
def centers(self) -> list[tuple[float, float, float],]:
|
|
206
206
|
return [gmsh.model.occ.get_center_of_mass(self.dim, tag) for tag in self.tags]
|
|
207
207
|
|
|
208
|
+
@property
|
|
209
|
+
def _metal(self) -> bool:
|
|
210
|
+
return False
|
|
211
|
+
|
|
208
212
|
@property
|
|
209
213
|
def opacity(self) -> float:
|
|
210
214
|
return 0.6
|
emerge/_emerge/simmodel.py
CHANGED
|
@@ -31,7 +31,7 @@ from typing import Literal, Generator, Any
|
|
|
31
31
|
from loguru import logger
|
|
32
32
|
import numpy as np
|
|
33
33
|
import gmsh # type: ignore
|
|
34
|
-
import
|
|
34
|
+
import cloudpickle
|
|
35
35
|
import os
|
|
36
36
|
import inspect
|
|
37
37
|
from pathlib import Path
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
117
|
-
self.
|
|
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
|
|
|
@@ -181,7 +182,10 @@ class Simulation:
|
|
|
181
182
|
|
|
182
183
|
# Restier the Exit GMSH function on proper program abortion
|
|
183
184
|
register(self._exit_gmsh)
|
|
184
|
-
|
|
185
|
+
else:
|
|
186
|
+
gmsh.finalize()
|
|
187
|
+
gmsh.initialize()
|
|
188
|
+
|
|
185
189
|
# Create a new GMSH model or load it
|
|
186
190
|
if not self.load_file:
|
|
187
191
|
gmsh.model.add(self.modelname)
|
|
@@ -283,7 +287,8 @@ class Simulation:
|
|
|
283
287
|
# Pack and save data
|
|
284
288
|
dataset = dict(simdata=self.data, mesh=self.mesh)
|
|
285
289
|
data_path = self.modelpath / 'simdata.emerge'
|
|
286
|
-
|
|
290
|
+
with open(str(data_path), "wb") as f_out:
|
|
291
|
+
cloudpickle.dump(dataset, f_out)
|
|
287
292
|
logger.info(f"Saved simulation data to: {data_path}")
|
|
288
293
|
|
|
289
294
|
def load(self) -> None:
|
|
@@ -304,7 +309,8 @@ class Simulation:
|
|
|
304
309
|
#self.mesh.update([])
|
|
305
310
|
|
|
306
311
|
# Load data
|
|
307
|
-
|
|
312
|
+
with open(str(data_path), "rb") as f_in:
|
|
313
|
+
datapack= cloudpickle.load(f_in)
|
|
308
314
|
self.data = datapack['simdata']
|
|
309
315
|
self._set_mesh(datapack['mesh'])
|
|
310
316
|
logger.info(f"Loaded simulation data from: {data_path}")
|
|
@@ -319,7 +325,7 @@ class Simulation:
|
|
|
319
325
|
if loglevel not in ('TRACE','DEBUG'):
|
|
320
326
|
gmsh.option.setNumber("General.Terminal", 0)
|
|
321
327
|
|
|
322
|
-
def
|
|
328
|
+
def set_write_log(self) -> None:
|
|
323
329
|
"""Adds a file output for the logger."""
|
|
324
330
|
LOG_CONTROLLER.set_write_file(self.modelpath)
|
|
325
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
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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={})
|