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.

@@ -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 underwater.
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