Skip to content

Commit 64d9eff

Browse files
committed
UMFPACK crash at program termination
1 parent 414870e commit 64d9eff

3 files changed

Lines changed: 77 additions & 62 deletions

File tree

‎CHANGES.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55

66
Please see the release notes in ``doc/devsim.pdf`` or at [https://devsim.net](https://devsim.net) for more detailed information about changes.
77

8+
## Version 2.10.1
9+
10+
### UMFPACK Solver
11+
12+
Fixed issue with `UMFPACK` solver when the dynamic library is being unloaded at program termination.
13+
814
## Version 2.10.0
915

1016
### Regression results

‎umfpack/umfpack_loader.py‎

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from ctypes import *
22
import platform
33
import array
4+
import os
45

56
def debug_print(arg):
67
pass
@@ -96,18 +97,18 @@ def get_transpose(x):
9697
else:
9798
return UMFPACK_A
9899

99-
def get_dll_naming():
100+
def _get_dll_naming():
100101
systems = {
101102
'Linux' : {"prefix" : "lib", "suffix" : ".so"},
102103
'Darwin' : {"prefix" : "lib", "suffix" : ".dylib"},
103104
'Windows' : {"prefix" : "", "suffix" : ".dll"},
104105
}
105106
return systems[platform.system()]
106107

107-
def get_umfpack_name():
108-
return "./%(prefix)sumfpack_lgpl%(suffix)s" % get_dll_naming()
108+
def _get_umfpack_name():
109+
return "./%(prefix)sumfpack_lgpl%(suffix)s" % _get_dll_naming()
109110

110-
def load_umfpack_dll(dllname):
111+
def _load_umfpack_dll(dllname):
111112
dll = cdll.LoadLibrary(dllname)
112113
if not dll:
113114
raise RuntimeError("Cannot find UMFPACK dll")
@@ -119,7 +120,7 @@ def get_blas_name():
119120
else:
120121
return "%(prefix)sopenblas%(suffix)s" % get_dll_naming()
121122

122-
def load_blas_dll(gdata, blaslib = None, noexcept = False):
123+
def _load_blas_dll(gdata, blaslib = None, noexcept = False):
123124
#print(dll.blasw_load_dll)
124125
if blaslib:
125126
dllname = blaslib
@@ -145,7 +146,7 @@ def load_blas_dll(gdata, blaslib = None, noexcept = False):
145146
#print(h)
146147
return h
147148

148-
def load_blas_functions(gdata, h):
149+
def _load_blas_functions(gdata, h):
149150
gdata.dll.blasw_load_functions.restype = c_int
150151
gdata.dll.blasw_load_functions.argtypes = [c_void_p]
151152
i = gdata.dll.blasw_load_functions(h._handle)
@@ -176,27 +177,27 @@ def __del__(self):
176177
if self.umf_control.is_complex:
177178
if self.Symbolic:
178179
debug_print('umfpack_zi_free_symbolic 176')
179-
self.umf_control.gdata.dll.umfpack_zi_free_symbolic (byref(self.Symbolic))
180+
umf_dll.umfpack_zi_free_symbolic (byref(self.Symbolic))
180181
else:
181182
if self.Symbolic:
182183
debug_print('umfpack_di_free_symbolic 180')
183-
self.umf_control.gdata.dll.umfpack_di_free_symbolic (byref(self.Symbolic))
184+
umf_dll.umfpack_di_free_symbolic (byref(self.Symbolic))
184185
self.umf_control = None
185186

186187
def factor_symbolic(self, matrix):
187188
if self.umf_control.is_complex:
188189
if self.Symbolic:
189190
debug_print('umfpack_zi_free_symbolic 187')
190-
self.umf_control.gdata.dll.umfpack_zi_free_symbolic (byref(self.Symbolic))
191+
umf_dll.umfpack_zi_free_symbolic (byref(self.Symbolic))
191192
NULL = c_void_p()
192193
debug_print('umfpack_zi_symbolic 190/u')
193-
self.status = self.umf_control.gdata.dll.umfpack_zi_symbolic (matrix.n, matrix.n, matrix.AP, matrix.AI, matrix.AX, NULL, byref(self.Symbolic), self.umf_control.Control, self.umf_control.Info)
194+
self.status = umf_dll.umfpack_zi_symbolic (matrix.n, matrix.n, matrix.AP, matrix.AI, matrix.AX, NULL, byref(self.Symbolic), self.umf_control.Control, self.umf_control.Info)
194195
else:
195196
if self.Symbolic:
196197
debug_print('umfpack_di_free_symbolic 194')
197-
self.umf_control.gdata.dll.umfpack_di_free_symbolic (byref(self.Symbolic))
198+
umf_dll.umfpack_di_free_symbolic (byref(self.Symbolic))
198199
debug_print('umfpack_di_symbolic 196')
199-
self.status = self.umf_control.gdata.dll.umfpack_di_symbolic (matrix.n, matrix.n, matrix.AP, matrix.AI, matrix.AX, byref(self.Symbolic), self.umf_control.Control, self.umf_control.Info)
200+
self.status = umf_dll.umfpack_di_symbolic (matrix.n, matrix.n, matrix.AP, matrix.AI, matrix.AX, byref(self.Symbolic), self.umf_control.Control, self.umf_control.Info)
200201
return self.status
201202

202203
class di_numeric:
@@ -208,46 +209,46 @@ def __del__(self):
208209
if self.umf_control.is_complex:
209210
if self.Numeric:
210211
debug_print('umfpack_zi_free_numeric 209')
211-
self.umf_control.gdata.dll.umfpack_zi_free_numeric (byref(self.Numeric))
212+
umf_dll.umfpack_zi_free_numeric (byref(self.Numeric))
212213
else:
213214
if self.Numeric:
214215
debug_print('umfpack_di_free_numeric 213')
215-
self.umf_control.gdata.dll.umfpack_di_free_numeric (byref(self.Numeric))
216+
umf_dll.umfpack_di_free_numeric (byref(self.Numeric))
216217

217218
def factor_numeric(self, matrix, Symbolic):
218219
if self.umf_control.is_complex:
219220
if self.Numeric:
220221
debug_print('umfpack_zi_free_numeric 219')
221-
self.umf_control.gdata.dll.umfpack_zi_free_numeric (byref(self.Numeric))
222+
umf_dll.umfpack_zi_free_numeric (byref(self.Numeric))
222223
NULL = c_void_p()
223224
debug_print('umfpack_zi_numeric 222')
224-
self.status = self.umf_control.gdata.dll.umfpack_zi_numeric (matrix.AP, matrix.AI, matrix.AX, NULL, Symbolic.Symbolic, byref(self.Numeric), self.umf_control.Control, self.umf_control.Info)
225+
self.status = umf_dll.umfpack_zi_numeric (matrix.AP, matrix.AI, matrix.AX, NULL, Symbolic.Symbolic, byref(self.Numeric), self.umf_control.Control, self.umf_control.Info)
225226
else:
226227
if self.Numeric:
227228
debug_print('umfpack_di_free_numeric 226')
228-
self.umf_control.gdata.dll.umfpack_di_free_numeric (byref(self.Numeric))
229+
umf_dll.umfpack_di_free_numeric (byref(self.Numeric))
229230
debug_print('umfpack_di_numeric 228')
230-
self.status = self.umf_control.gdata.dll.umfpack_di_numeric (matrix.AP, matrix.AI, matrix.AX, Symbolic.Symbolic, byref(self.Numeric), self.umf_control.Control, self.umf_control.Info)
231+
self.status = umf_dll.umfpack_di_numeric (matrix.AP, matrix.AI, matrix.AX, Symbolic.Symbolic, byref(self.Numeric), self.umf_control.Control, self.umf_control.Info)
231232
return self.status
232233

233234
def solve(self, matrix, x, b, transpose):
234235
X = c_void_p(x.buffer_info()[0])
235236
B = c_void_p(b.buffer_info()[0])
236237
if self.umf_control.is_complex:
237238
NULL = c_void_p()
238-
self.status = self.umf_control.gdata.dll.umfpack_zi_solve (get_transpose(transpose), matrix.AP, matrix.AI, matrix.AX, NULL, X, NULL, B, NULL, self.Numeric, self.umf_control.Control, self.umf_control.Info)
239+
self.status = umf_dll.umfpack_zi_solve (get_transpose(transpose), matrix.AP, matrix.AI, matrix.AX, NULL, X, NULL, B, NULL, self.Numeric, self.umf_control.Control, self.umf_control.Info)
239240
else:
240-
self.status = self.umf_control.gdata.dll.umfpack_di_solve (get_transpose(transpose), matrix.AP, matrix.AI, matrix.AX, X, B, self.Numeric, self.umf_control.Control, self.umf_control.Info)
241+
self.status = umf_dll.umfpack_di_solve (get_transpose(transpose), matrix.AP, matrix.AI, matrix.AX, X, B, self.Numeric, self.umf_control.Control, self.umf_control.Info)
241242
return self.status
242243

243244
def determinant(self, x, r):
244245
X = c_void_p(x.buffer_info()[0])
245246
R = c_void_p(r.buffer_info()[0])
246247
if self.umf_control.is_complex:
247248
NULL = c_void_p()
248-
self.status = self.umf_control.gdata.dll.umfpack_zi_get_determinant (X, NULL, R, NULL, self.Numeric, self.umf_control.Info)
249+
self.status = umf_dll.umfpack_zi_get_determinant (X, NULL, R, NULL, self.Numeric, self.umf_control.Info)
249250
else:
250-
self.status = self.umf_control.gdata.dll.umfpack_di_get_determinant (X, R, self.Numeric, self.umf_control.Info)
251+
self.status = umf_dll.umfpack_di_get_determinant (X, R, self.Numeric, self.umf_control.Info)
251252
return self.status
252253

253254
class di_triplet:
@@ -279,7 +280,7 @@ def __init__(self, uc, Ap, Ai, Ax):
279280
def __del__(self):
280281
pass
281282

282-
class global_data:
283+
class _global_data:
283284
def __init__(self):
284285
self.printcb = None
285286
self.blaslibs = []
@@ -290,6 +291,22 @@ def __del__(self):
290291
self.blaslibs = None
291292
self.dll = None
292293

294+
def initialize_umfpack(self, math_libraries):
295+
self.dll = _load_umfpack_dll(os.path.join(os.path.dirname(__file__), _get_umfpack_name()))
296+
global umf_dll
297+
umf_dll = self.dll
298+
for b in math_libraries:
299+
h = _load_blas_dll(self, blaslib=b, noexcept=True)
300+
if h:
301+
mcount = _load_blas_functions(self, h)
302+
if mcount == 0:
303+
break
304+
if mcount != 0:
305+
raise RuntimeError('Missing %d math functions' % mcount)
306+
307+
global_data_instance = _global_data()
308+
umf_dll = None
309+
293310
class umf_control:
294311
def __init__(self, gdata, matrix_type):
295312
self.timer = None
@@ -315,18 +332,18 @@ def __del__(self):
315332

316333
def tic(self):
317334
self.timer = (c_double * 2)()
318-
self.gdata.dll.umfpack_tic(byref(self.timer))
335+
umf_dll.umfpack_tic(byref(self.timer))
319336

320337
def toc(self):
321-
self.gdata.dll.umfpack_toc (self.timer)
338+
umf_dll.umfpack_toc (self.timer)
322339
print ("\numfpack complete.\nTotal time: %5.2f seconds (CPU time), %5.2f seconds (wallclock time)\n" % ( self.timer [1], self.timer [0]))
323340

324341
def set_defaults(self):
325342
self.Control = (c_double * UMFPACK_CONTROL)()
326343
if self.is_complex:
327-
self.gdata.dll.umfpack_zi_defaults(self.Control)
344+
umf_dll.umfpack_zi_defaults(self.Control)
328345
else:
329-
self.gdata.dll.umfpack_di_defaults(self.Control)
346+
umf_dll.umfpack_di_defaults(self.Control)
330347
self.Info = (c_double * UMFPACK_INFO)()
331348

332349
def init_verbose(self):
@@ -335,37 +352,37 @@ def init_verbose(self):
335352
self.Control [UMFPACK_PRL] = 6
336353
# /* print the license agreement */
337354
if self.is_complex:
338-
self.gdata.dll.umfpack_zi_report_status (self.Control, UMFPACK_OK)
355+
umf_dll.umfpack_zi_report_status (self.Control, UMFPACK_OK)
339356
else:
340-
self.gdata.dll.umfpack_di_report_status (self.Control, UMFPACK_OK)
357+
umf_dll.umfpack_di_report_status (self.Control, UMFPACK_OK)
341358
self.Control [UMFPACK_PRL] = 5
342359
#
343360
# /* print the control parameters */
344361
if self.is_complex:
345-
self.gdata.dll.umfpack_zi_report_control(self.Control)
362+
umf_dll.umfpack_zi_report_control(self.Control)
346363
else:
347-
self.gdata.dll.umfpack_di_report_control(self.Control)
364+
umf_dll.umfpack_di_report_control(self.Control)
348365

349366
def print_vector(self, b, label):
350367
# /* print the right-hand-side */
351368
print ("\n%s: " % (label,), flush=True, end="")
352369
if self.is_complex:
353370
NULL = (c_void_p)()
354-
self.gdata.dll.umfpack_zi_report_vector.argtypes = [c_int, c_void_p, c_void_p, c_void_p]
355-
self.gdata.dll.umfpack_zi_report_vector.restype = None
356-
self.gdata.dll.umfpack_zi_report_vector (len(b)//2, b.buffer_info()[0], NULL, self.Control)
371+
umf_dll.umfpack_zi_report_vector.argtypes = [c_int, c_void_p, c_void_p, c_void_p]
372+
umf_dll.umfpack_zi_report_vector.restype = None
373+
umf_dll.umfpack_zi_report_vector (len(b)//2, b.buffer_info()[0], NULL, self.Control)
357374
else:
358-
self.gdata.dll.umfpack_di_report_vector.argtypes = [c_int, c_void_p, c_void_p]
359-
self.gdata.dll.umfpack_di_report_vector.restype = None
360-
self.gdata.dll.umfpack_di_report_vector (len(b), b.buffer_info()[0], self.Control)
375+
umf_dll.umfpack_di_report_vector.argtypes = [c_int, c_void_p, c_void_p]
376+
umf_dll.umfpack_di_report_vector.restype = None
377+
umf_dll.umfpack_di_report_vector (len(b), b.buffer_info()[0], self.Control)
361378

362379
def print_triplet(self, tm):
363380
print ("\nA: ")
364381
if self.is_complex:
365382
NULL = (c_void_p)()
366-
self.gdata.dll.umfpack_zi_report_triplet(tm.n, tm.n, tm.nz, tm.Ar, tm.Ac, tm.Av, NULL, self.Control)
383+
umf_dll.umfpack_zi_report_triplet(tm.n, tm.n, tm.nz, tm.Ar, tm.Ac, tm.Av, NULL, self.Control)
367384
else:
368-
self.gdata.dll.umfpack_di_report_triplet(tm.n, tm.n, tm.nz, tm.Ar, tm.Ac, tm.Av, self.Control)
385+
umf_dll.umfpack_di_report_triplet(tm.n, tm.n, tm.nz, tm.Ar, tm.Ac, tm.Av, self.Control)
369386

370387
def triplet_to_col(self, tm):
371388
n = tm.n
@@ -377,14 +394,14 @@ def triplet_to_col(self, tm):
377394
if self.is_complex:
378395
Ax = array.array('d', [0] * (2*nz1))
379396
matrix = di_matrix(self, Ap, Ai, Ax)
380-
self.status = self.gdata.dll.umfpack_zi_triplet_to_col (n, n, nz, tm.Ar, tm.Ac, tm.Av, NULL, matrix.AP, matrix.AI, matrix.AX, NULL, NULL)
397+
self.status = umf_dll.umfpack_zi_triplet_to_col (n, n, nz, tm.Ar, tm.Ac, tm.Av, NULL, matrix.AP, matrix.AI, matrix.AX, NULL, NULL)
381398
else:
382399
Ax = array.array('d', [0] * (nz1))
383400
matrix = di_matrix(self, Ap, Ai, Ax)
384-
self.status = self.gdata.dll.umfpack_di_triplet_to_col (n, n, nz, tm.Ar, tm.Ac, tm.Av, matrix.AP, matrix.AI, matrix.AX, NULL)
401+
self.status = umf_dll.umfpack_di_triplet_to_col (n, n, nz, tm.Ar, tm.Ac, tm.Av, matrix.AP, matrix.AI, matrix.AX, NULL)
385402

386403
if self.status < 0:
387-
self.gdata.dll.umfpack_di_report_status (self.Control, self.status)
404+
umf_dll.umfpack_di_report_status (self.Control, self.status)
388405
raise RuntimeError("umfpack triplet_to_col failed")
389406

390407
return matrix
@@ -393,21 +410,21 @@ def print_matrix(self, matrix):
393410
print("\nA: ")
394411
if self.is_complex:
395412
NULL = (c_void_p)()
396-
self.gdata.dll.umfpack_zi_report_matrix (matrix.n, matrix.n, matrix.AP, matrix.AI, matrix.AX, NULL, 1, self.Control)
413+
umf_dll.umfpack_zi_report_matrix (matrix.n, matrix.n, matrix.AP, matrix.AI, matrix.AX, NULL, 1, self.Control)
397414
else:
398-
self.gdata.dll.umfpack_di_report_matrix (matrix.n, matrix.n, matrix.AP, matrix.AI, matrix.AX, 1, self.Control)
415+
umf_dll.umfpack_di_report_matrix (matrix.n, matrix.n, matrix.AP, matrix.AI, matrix.AX, 1, self.Control)
399416

400417
def print_info(self):
401418
if self.is_complex:
402-
self.gdata.dll.umfpack_zi_report_info (self.Control, self.Info)
419+
umf_dll.umfpack_zi_report_info (self.Control, self.Info)
403420
else:
404-
self.gdata.dll.umfpack_di_report_info (self.Control, self.Info)
421+
umf_dll.umfpack_di_report_info (self.Control, self.Info)
405422

406423
def print_status(self):
407424
if self.is_complex:
408-
self.gdata.dll.umfpack_zi_report_status (self.Control, self.status)
425+
umf_dll.umfpack_zi_report_status (self.Control, self.status)
409426
else:
410-
self.gdata.dll.umfpack_di_report_status (self.Control, self.status)
427+
umf_dll.umfpack_di_report_status (self.Control, self.status)
411428

412429
def error_on_result(self, msg):
413430
if self.status != 0:
@@ -424,9 +441,9 @@ def symbolic(self, matrix):
424441
def print_symbolic(self, Symbolic):
425442
print("\nSymbolic factorization of A: ")
426443
if self.is_complex:
427-
self.gdata.dll.umfpack_zi_report_symbolic(Symbolic.Symbolic, self.Control)
444+
umf_dll.umfpack_zi_report_symbolic(Symbolic.Symbolic, self.Control)
428445
else:
429-
self.gdata.dll.umfpack_di_report_symbolic(Symbolic.Symbolic, self.Control)
446+
umf_dll.umfpack_di_report_symbolic(Symbolic.Symbolic, self.Control)
430447

431448
def numeric(self, matrix, Symbolic):
432449
Numeric = di_numeric(self)
@@ -437,9 +454,9 @@ def numeric(self, matrix, Symbolic):
437454
def print_numeric(self, Numeric):
438455
print ("\nNumeric factorization of A: ")
439456
if self.is_complex:
440-
self.gdata.dll.umfpack_zi_report_numeric (Numeric.Numeric, self.Control)
457+
umf_dll.umfpack_zi_report_numeric (Numeric.Numeric, self.Control)
441458
else:
442-
self.gdata.dll.umfpack_di_report_numeric (Numeric.Numeric, self.Control)
459+
umf_dll.umfpack_di_report_numeric (Numeric.Numeric, self.Control)
443460

444461
def solve(self, matrix, x, b, Numeric, transpose):
445462
if self.is_complex:

‎umfpack/umfshim.py‎

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,8 @@ def __del__(self):
2323
self.gdata=None
2424

2525
def initialize_umfpack(self):
26-
self.gdata = umf.global_data()
27-
self.gdata.dll = umf.load_umfpack_dll(os.path.join(os.path.dirname(__file__), umf.get_umfpack_name()))
28-
for b in devsim.get_parameter(name='info')['math_libraries']:
29-
h = umf.load_blas_dll(self.gdata, blaslib=b, noexcept=True)
30-
if h:
31-
mcount = umf.load_blas_functions(self.gdata, h)
32-
if mcount == 0:
33-
break
34-
if mcount != 0:
35-
raise RuntimeError('Missing %d math functions' % mcount)
26+
self.gdata = umf.global_data_instance
27+
self.gdata.initialize_umfpack(devsim.get_parameter(name='info')['math_libraries'])
3628

3729
def factor(self, **kwargs):
3830
self.status = False

0 commit comments

Comments
 (0)