emerge 0.5.2__py3-none-any.whl → 0.5.3__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/_emerge/bc.py +3 -12
- emerge/_emerge/const.py +5 -0
- emerge/_emerge/elements/nedleg2.py +2 -2
- emerge/_emerge/geo/pcb.py +110 -13
- emerge/_emerge/geo/pcb_tools/calculator.py +2 -2
- emerge/_emerge/geometry.py +1 -1
- emerge/_emerge/logsettings.py +12 -13
- emerge/_emerge/material.py +4 -0
- emerge/_emerge/mth/integrals.py +1 -1
- emerge/_emerge/physics/microwave/adaptive_freq.py +1 -5
- emerge/_emerge/physics/microwave/assembly/assembler.py +62 -39
- emerge/_emerge/physics/microwave/assembly/curlcurl.py +1 -8
- emerge/_emerge/physics/microwave/microwave_3d.py +33 -26
- emerge/_emerge/physics/microwave/microwave_bc.py +97 -27
- emerge/_emerge/physics/microwave/microwave_data.py +3 -5
- emerge/_emerge/physics/microwave/sc.py +26 -26
- emerge/_emerge/physics/microwave/simjob.py +8 -3
- emerge/_emerge/simmodel.py +12 -8
- emerge/_emerge/simulation_data.py +5 -1
- emerge/_emerge/solve_interfaces/cudss_interface.py +238 -0
- emerge/_emerge/solver.py +285 -107
- emerge/cli.py +1 -1
- emerge/lib.py +2 -5
- {emerge-0.5.2.dist-info → emerge-0.5.3.dist-info}/METADATA +5 -1
- {emerge-0.5.2.dist-info → emerge-0.5.3.dist-info}/RECORD +28 -26
- {emerge-0.5.2.dist-info → emerge-0.5.3.dist-info}/WHEEL +0 -0
- {emerge-0.5.2.dist-info → emerge-0.5.3.dist-info}/entry_points.txt +0 -0
- {emerge-0.5.2.dist-info → emerge-0.5.3.dist-info}/licenses/LICENSE +0 -0
emerge/_emerge/simmodel.py
CHANGED
|
@@ -51,11 +51,9 @@ Known problems/solutions:
|
|
|
51
51
|
--------------------------
|
|
52
52
|
"""
|
|
53
53
|
|
|
54
|
-
|
|
55
54
|
class SimulationError(Exception):
|
|
56
55
|
pass
|
|
57
56
|
|
|
58
|
-
|
|
59
57
|
############################################################
|
|
60
58
|
# BASE 3D SIMULATION MODEL #
|
|
61
59
|
############################################################
|
|
@@ -93,7 +91,6 @@ class Simulation3D:
|
|
|
93
91
|
|
|
94
92
|
self.mesh: Mesh3D = Mesh3D(self.mesher)
|
|
95
93
|
self.select: Selector = Selector()
|
|
96
|
-
self.set_loglevel(loglevel)
|
|
97
94
|
|
|
98
95
|
## STATES
|
|
99
96
|
self.__active: bool = False
|
|
@@ -102,9 +99,6 @@ class Simulation3D:
|
|
|
102
99
|
|
|
103
100
|
self.display: PVDisplay = PVDisplay(self.mesh)
|
|
104
101
|
|
|
105
|
-
if logfile:
|
|
106
|
-
self.set_logfile()
|
|
107
|
-
|
|
108
102
|
self.save_file: bool = save_file
|
|
109
103
|
self.load_file: bool = load_file
|
|
110
104
|
|
|
@@ -115,6 +109,10 @@ class Simulation3D:
|
|
|
115
109
|
|
|
116
110
|
self._initialize_simulation()
|
|
117
111
|
|
|
112
|
+
self.set_loglevel(loglevel)
|
|
113
|
+
if logfile:
|
|
114
|
+
self.set_logfile()
|
|
115
|
+
|
|
118
116
|
self._update_data()
|
|
119
117
|
|
|
120
118
|
|
|
@@ -286,6 +284,8 @@ class Simulation3D:
|
|
|
286
284
|
loglevel ('DEBUG','INFO','WARNING','ERROR'): The loglevel
|
|
287
285
|
"""
|
|
288
286
|
LOG_CONTROLLER.set_std_loglevel(loglevel)
|
|
287
|
+
if loglevel not in ('TRACE','DEBUG'):
|
|
288
|
+
gmsh.option.setNumber("General.Terminal", 0)
|
|
289
289
|
|
|
290
290
|
def set_logfile(self) -> None:
|
|
291
291
|
"""Adds a file output for the logger."""
|
|
@@ -318,7 +318,6 @@ class Simulation3D:
|
|
|
318
318
|
|
|
319
319
|
return None
|
|
320
320
|
|
|
321
|
-
|
|
322
321
|
def set_periodic_cell(self, cell: PeriodicCell, excluded_faces: list[FaceSelection] | None = None):
|
|
323
322
|
"""Set the given periodic cell object as the simulations peridicity.
|
|
324
323
|
|
|
@@ -332,7 +331,7 @@ class Simulation3D:
|
|
|
332
331
|
def commit_geometry(self, *geometries: GeoObject | list[GeoObject]) -> None:
|
|
333
332
|
"""Finalizes and locks the current geometry state of the simulation.
|
|
334
333
|
|
|
335
|
-
The geometries may be provided (legacy behavior) but are automatically managed
|
|
334
|
+
The geometries may be provided (legacy behavior) but are automatically managed in the background.
|
|
336
335
|
|
|
337
336
|
"""
|
|
338
337
|
geometries_parsed: Any = None
|
|
@@ -375,7 +374,12 @@ class Simulation3D:
|
|
|
375
374
|
self.mesher.set_mesh_size(self.mw.get_discretizer(), self.mw.resolution)
|
|
376
375
|
|
|
377
376
|
try:
|
|
377
|
+
gmsh.logger.start()
|
|
378
378
|
gmsh.model.mesh.generate(3)
|
|
379
|
+
logs = gmsh.logger.get()
|
|
380
|
+
gmsh.logger.stop()
|
|
381
|
+
for log in logs:
|
|
382
|
+
logger.trace('[GMSH] '+log)
|
|
379
383
|
except Exception:
|
|
380
384
|
logger.error('GMSH Mesh error detected.')
|
|
381
385
|
print(_GMSH_ERROR_TEXT)
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
import numpy as np
|
|
20
20
|
from loguru import logger
|
|
21
|
-
from typing import TypeVar, Generic, Any, List, Union, Dict
|
|
21
|
+
from typing import TypeVar, Generic, Any, List, Union, Dict, Generator
|
|
22
22
|
from collections import defaultdict
|
|
23
23
|
|
|
24
24
|
T = TypeVar("T")
|
|
@@ -187,6 +187,10 @@ class DataContainer:
|
|
|
187
187
|
self.entries.append(entry)
|
|
188
188
|
return entry
|
|
189
189
|
|
|
190
|
+
def iterate(self) -> Generator[tuple[dict[str, float], dict[str, Any]], None, None]:
|
|
191
|
+
for entry in self.entries:
|
|
192
|
+
yield entry.vars, entry.data
|
|
193
|
+
|
|
190
194
|
@property
|
|
191
195
|
def last(self) -> DataEntry:
|
|
192
196
|
"""Returns the last added entry"""
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# EMerge is an open source Python based FEM EM simulation module.
|
|
2
|
+
# Copyright (C) 2025 Robert Fennis.
|
|
3
|
+
|
|
4
|
+
# This program is free software; you can redistribute it and/or
|
|
5
|
+
# modify it under the terms of the GNU General Public License
|
|
6
|
+
# as published by the Free Software Foundation; either version 2
|
|
7
|
+
# of the License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program; if not, see
|
|
16
|
+
# <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
import cupy as cp # ty: ignore
|
|
19
|
+
import nvmath.bindings.cudss as cudss # ty: ignore
|
|
20
|
+
from nvmath import CudaDataType # ty: ignore
|
|
21
|
+
|
|
22
|
+
from scipy.sparse import csr_matrix
|
|
23
|
+
import numpy as np
|
|
24
|
+
|
|
25
|
+
from loguru import logger
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
############################################################
|
|
29
|
+
# CONSTANTS #
|
|
30
|
+
############################################################
|
|
31
|
+
|
|
32
|
+
ALG_NEST_DISS_METIS = cudss.AlgType.ALG_DEFAULT
|
|
33
|
+
ALG_COLAMD = cudss.AlgType.ALG_1
|
|
34
|
+
ALG_COLAMD_BLOCK_TRI = cudss.AlgType.ALG_2
|
|
35
|
+
ALG_AMD = cudss.AlgType.ALG_3
|
|
36
|
+
|
|
37
|
+
FLOAT64 = CudaDataType.CUDA_R_64F
|
|
38
|
+
FLOAT32 = CudaDataType.CUDA_R_32F
|
|
39
|
+
COMPLEX128 = CudaDataType.CUDA_C_64F
|
|
40
|
+
COMPLEX64 = CudaDataType.CUDA_C_32F
|
|
41
|
+
INT64 = CudaDataType.CUDA_R_64I
|
|
42
|
+
INT32 = CudaDataType.CUDA_R_32I
|
|
43
|
+
|
|
44
|
+
INDEX_BASE = cudss.IndexBase.ZERO
|
|
45
|
+
|
|
46
|
+
def _c_pointer(arry) -> int:
|
|
47
|
+
return int(arry.data.ptr)
|
|
48
|
+
|
|
49
|
+
############################################################
|
|
50
|
+
# INTERFACE #
|
|
51
|
+
############################################################
|
|
52
|
+
|
|
53
|
+
class CuDSSInterface:
|
|
54
|
+
def __init__(self):
|
|
55
|
+
self.A_cu = None
|
|
56
|
+
self.b_cu = None
|
|
57
|
+
self.x_cu = None
|
|
58
|
+
self.A_cobj = None
|
|
59
|
+
self.b_cobj = None
|
|
60
|
+
self.x_cobj = None
|
|
61
|
+
self.A_pattern = None
|
|
62
|
+
|
|
63
|
+
self._handle = cudss.create()
|
|
64
|
+
self._config = cudss.config_create()
|
|
65
|
+
self._data = cudss.data_create(self._handle)
|
|
66
|
+
|
|
67
|
+
self.MTYPE = cudss.MatrixType.SYMMETRIC
|
|
68
|
+
self.MVIEW = cudss.MatrixViewType.FULL
|
|
69
|
+
self.RALG = cudss.AlgType.ALG_DEFAULT
|
|
70
|
+
self.VTYPE = CudaDataType.CUDA_R_64F
|
|
71
|
+
|
|
72
|
+
self._INDPTR = None
|
|
73
|
+
self._ROW_START: int | None = None
|
|
74
|
+
self._ROW_END: int | None = None
|
|
75
|
+
self._IND = None
|
|
76
|
+
self._VAL = None
|
|
77
|
+
self._NNZ: int | None = None
|
|
78
|
+
self._COMP: bool = True
|
|
79
|
+
self._PRES: int = 2
|
|
80
|
+
self._COL_IDS = None
|
|
81
|
+
|
|
82
|
+
self._initialized = False
|
|
83
|
+
|
|
84
|
+
param = cudss.ConfigParam.REORDERING_ALG
|
|
85
|
+
dtype = cudss.get_config_param_dtype(int(param))
|
|
86
|
+
reorder_alg = np.array(self.RALG, dtype=dtype)
|
|
87
|
+
|
|
88
|
+
cudss.config_set(
|
|
89
|
+
self._config,
|
|
90
|
+
int(param),
|
|
91
|
+
reorder_alg.ctypes.data,
|
|
92
|
+
reorder_alg.nbytes
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
def set_algorithm(self, alg_type: cudss.AlgType):
|
|
96
|
+
self.RALG = alg_type
|
|
97
|
+
|
|
98
|
+
def init_type(self):
|
|
99
|
+
if self._PRES == 1:
|
|
100
|
+
if self._COMP:
|
|
101
|
+
self.c_dtype = cp.complex64
|
|
102
|
+
self.VTYPE = COMPLEX64
|
|
103
|
+
else:
|
|
104
|
+
self.c_dtype = cp.float32
|
|
105
|
+
self.VTYPE = FLOAT32
|
|
106
|
+
else:
|
|
107
|
+
if self._COMP:
|
|
108
|
+
self.c_dtype = cp.complex128
|
|
109
|
+
self.VTYPE = COMPLEX128
|
|
110
|
+
else:
|
|
111
|
+
self.c_dtype = cp.float64
|
|
112
|
+
self.VTYPE = FLOAT64
|
|
113
|
+
|
|
114
|
+
def submit_matrix(self, A: csr_matrix):
|
|
115
|
+
self.N = A.shape[0]
|
|
116
|
+
|
|
117
|
+
if np.iscomplexobj(A):
|
|
118
|
+
self._COMP = True
|
|
119
|
+
else:
|
|
120
|
+
self._COMP = False
|
|
121
|
+
|
|
122
|
+
self.init_type()
|
|
123
|
+
|
|
124
|
+
self.A_cu = cp.sparse.csr_matrix(A).astype(self.c_dtype)
|
|
125
|
+
|
|
126
|
+
self._INDPTR = cp.ascontiguousarray(self.A_cu.indptr.astype(cp.int32))
|
|
127
|
+
self._IND = cp.ascontiguousarray(self.A_cu.indices.astype(cp.int32))
|
|
128
|
+
self._VAL = cp.ascontiguousarray(self.A_cu.data)
|
|
129
|
+
self._NNZ = int(self._VAL.size)
|
|
130
|
+
self._ROW_START = self._INDPTR[:-1]
|
|
131
|
+
self._ROW_END = self._INDPTR[1:]
|
|
132
|
+
self._COL_IDS = self.A_cu.indices.astype(cp.int32)
|
|
133
|
+
|
|
134
|
+
def submit_vector(self, b: np.ndarray):
|
|
135
|
+
self.b_cu = cp.array(b).astype(self.c_dtype)
|
|
136
|
+
|
|
137
|
+
def create_solvec(self):
|
|
138
|
+
self.x_cu = cp.empty_like(self.b_cu)
|
|
139
|
+
|
|
140
|
+
def _update_dss_data(self):
|
|
141
|
+
cudss.matrix_set_values(self.A_cobj, _c_pointer(self._VAL))
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
self.b_cobj = cudss.matrix_create_dn(self.N, 1, self.N, _c_pointer(self.b_cu),
|
|
145
|
+
int(self.VTYPE), int(cudss.Layout.COL_MAJOR))
|
|
146
|
+
self.x_cobj = cudss.matrix_create_dn(self.N, 1, self.N, _c_pointer(self.x_cu),
|
|
147
|
+
int(self.VTYPE), int(cudss.Layout.COL_MAJOR))
|
|
148
|
+
|
|
149
|
+
def _create_dss_data(self):
|
|
150
|
+
self.A_cobj = cudss.matrix_create_csr(
|
|
151
|
+
self.N,self.N,self._NNZ,
|
|
152
|
+
_c_pointer(self._ROW_START),
|
|
153
|
+
_c_pointer(self._ROW_END),
|
|
154
|
+
_c_pointer(self._COL_IDS),
|
|
155
|
+
_c_pointer(self._VAL),
|
|
156
|
+
int(INT32),
|
|
157
|
+
int(self.VTYPE),
|
|
158
|
+
int(self.MTYPE),
|
|
159
|
+
int(self.MVIEW),
|
|
160
|
+
int(INDEX_BASE),
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
self.b_cobj = cudss.matrix_create_dn(self.N, 1, self.N, _c_pointer(self.b_cu),
|
|
164
|
+
int(self.VTYPE), int(cudss.Layout.COL_MAJOR))
|
|
165
|
+
self.x_cobj = cudss.matrix_create_dn(self.N, 1, self.N, _c_pointer(self.x_cu),
|
|
166
|
+
int(self.VTYPE), int(cudss.Layout.COL_MAJOR))
|
|
167
|
+
|
|
168
|
+
def from_symbolic(self, A: csr_matrix, b: np.ndarray) -> np.ndarray:
|
|
169
|
+
"""Solves Ax=b starting from the symbolic factorization
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
A (csr_matrix): The input sparse matrix
|
|
173
|
+
b (np.ndarray): The solution vector b
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
np.ndarray: The solved vector
|
|
177
|
+
"""
|
|
178
|
+
self.submit_matrix(A)
|
|
179
|
+
self.submit_vector(b)
|
|
180
|
+
self.create_solvec()
|
|
181
|
+
self._create_dss_data()
|
|
182
|
+
self._symbolic()
|
|
183
|
+
self._numeric(False)
|
|
184
|
+
return self._solve()
|
|
185
|
+
|
|
186
|
+
def from_numeric(self, A: csr_matrix, b: np.ndarray) -> np.ndarray:
|
|
187
|
+
"""Solves Ax=b starting from the Numeric factorization
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
A (csr_matrix): The input sparse matrix
|
|
191
|
+
b (np.ndarray): The solution vector b
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
np.ndarray: The solved vector
|
|
195
|
+
"""
|
|
196
|
+
self.submit_matrix(A)
|
|
197
|
+
self.submit_vector(b)
|
|
198
|
+
self.create_solvec()
|
|
199
|
+
self._update_dss_data()
|
|
200
|
+
self._numeric(True)
|
|
201
|
+
return self._solve()
|
|
202
|
+
|
|
203
|
+
def from_solve(self, b: np.ndarray) -> np.ndarray:
|
|
204
|
+
"""Solves Ax=b only with a new b vector.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
A (csr_matrix): The input sparse matrix
|
|
208
|
+
b (np.ndarray): The solution vector b
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
np.ndarray: The solved vector
|
|
212
|
+
"""
|
|
213
|
+
self.submit_vector(b)
|
|
214
|
+
self.create_solvec()
|
|
215
|
+
return self._solve()
|
|
216
|
+
|
|
217
|
+
def _symbolic(self):
|
|
218
|
+
logger.trace('Executing symbolic factorization')
|
|
219
|
+
cudss.execute(self._handle, cudss.Phase.ANALYSIS, self._config, self._data,
|
|
220
|
+
self.A_cobj, self.x_cobj, self.b_cobj)
|
|
221
|
+
|
|
222
|
+
def _numeric(self, refactorize: bool = False):
|
|
223
|
+
if refactorize:
|
|
224
|
+
logger.trace('Refactoring matrix')
|
|
225
|
+
phase = cudss.Phase.REFACTORIZATION
|
|
226
|
+
else:
|
|
227
|
+
phase = cudss.Phase.FACTORIZATION
|
|
228
|
+
logger.trace('Executing numerical factorization')
|
|
229
|
+
cudss.execute(self._handle, phase, self._config, self._data,
|
|
230
|
+
self.A_cobj, self.x_cobj, self.b_cobj)
|
|
231
|
+
|
|
232
|
+
def _solve(self) -> np.ndarray:
|
|
233
|
+
logger.trace('Solving matrix problem')
|
|
234
|
+
cudss.execute(self._handle, cudss.Phase.SOLVE, self._config, self._data,
|
|
235
|
+
self.A_cobj, self.x_cobj, self.b_cobj)
|
|
236
|
+
cp.cuda.runtime.deviceSynchronize()
|
|
237
|
+
x_host = cp.asnumpy(self.x_cu).ravel()
|
|
238
|
+
return x_host
|