emerge 0.4.11__py3-none-any.whl → 0.5.1__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 +15 -8
- emerge/_emerge/bc.py +41 -2
- emerge/_emerge/geo/__init__.py +1 -1
- emerge/_emerge/geo/pcb.py +49 -11
- emerge/_emerge/howto.py +2 -2
- emerge/_emerge/logsettings.py +83 -5
- emerge/_emerge/mesh3d.py +30 -12
- emerge/_emerge/mth/common_functions.py +28 -1
- emerge/_emerge/mth/integrals.py +25 -3
- emerge/_emerge/mth/optimized.py +126 -33
- emerge/_emerge/mth/pairing.py +97 -0
- emerge/_emerge/periodic.py +22 -0
- emerge/_emerge/physics/microwave/assembly/assembler.py +129 -155
- emerge/_emerge/physics/microwave/assembly/curlcurl.py +35 -3
- emerge/_emerge/physics/microwave/assembly/periodicbc.py +130 -0
- emerge/_emerge/physics/microwave/microwave_3d.py +3 -3
- emerge/_emerge/physics/microwave/microwave_bc.py +5 -4
- emerge/_emerge/physics/microwave/microwave_data.py +2 -2
- emerge/_emerge/physics/microwave/sparam.py +2 -2
- emerge/_emerge/projects/_gen_base.txt +1 -1
- emerge/_emerge/simmodel.py +137 -126
- emerge/_emerge/solve_interfaces/pardiso_interface.py +468 -0
- emerge/_emerge/solver.py +102 -31
- emerge/lib.py +276 -41
- {emerge-0.4.11.dist-info → emerge-0.5.1.dist-info}/METADATA +1 -1
- {emerge-0.4.11.dist-info → emerge-0.5.1.dist-info}/RECORD +29 -27
- emerge/_emerge/pardiso/pardiso_solver.py +0 -455
- {emerge-0.4.11.dist-info → emerge-0.5.1.dist-info}/WHEEL +0 -0
- {emerge-0.4.11.dist-info → emerge-0.5.1.dist-info}/entry_points.txt +0 -0
- {emerge-0.4.11.dist-info → emerge-0.5.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
emerge/__init__.py,sha256=
|
|
1
|
+
emerge/__init__.py,sha256=sK2yLrvngIeUOfRJ-YivFP_9J8lbcy-DLZvEI5FBhCc,2559
|
|
2
2
|
emerge/__main__.py,sha256=WVf16sfrOI910QWohrQDaChZdRifMNoS6VKzCT6f3ZA,92
|
|
3
3
|
emerge/cli.py,sha256=xrNPoX5VtUA0KPRRwZPxC0rGtBDKc2FF8Ro-uPuO-Hg,665
|
|
4
|
-
emerge/lib.py,sha256=
|
|
4
|
+
emerge/lib.py,sha256=uOvBbOtPkwXjLygzs-s7Wf-2oM1YfCPGiz1E2UkVXgU,17869
|
|
5
5
|
emerge/plot.py,sha256=AH2D9rKeWUXlSOlh-pUUfLt0oxVLcqF_piki-BmPEg0,83
|
|
6
6
|
emerge/pyvista.py,sha256=-Ht2YcZYsh8-dici5ZPNAWwsis6uz5wNj8n8mxv5fog,42
|
|
7
7
|
emerge/_emerge/__init__.py,sha256=hYCXbPCoyjAc3EUsYc4yz8ct6crlYHB9B02o_Am9ITs,1646
|
|
8
|
-
emerge/_emerge/bc.py,sha256=
|
|
8
|
+
emerge/_emerge/bc.py,sha256=J-Axq-oWcCL_n_4cee3z3hPV67Typ6o4_9o9PFLEZJ4,8488
|
|
9
9
|
emerge/_emerge/coord.py,sha256=BKvyrcnHY-_bgHqysnByy5k9_DK4VVfr9KKkRaawG2E,4371
|
|
10
10
|
emerge/_emerge/cs.py,sha256=ncpedffKF9cJFm0DE_7FOQrHngxLhIv9ciV1-uR-TTw,17880
|
|
11
11
|
emerge/_emerge/dataset.py,sha256=UcSAJ_siLrOjNBBWRWsS3GUZUpayp63EM6pP6ClwKDI,1534
|
|
12
12
|
emerge/_emerge/geo2d.py,sha256=e_HkX1GQ2iYrdO0zeEgzVOzfGyU1WGJyjeGBAobOttE,3323
|
|
13
13
|
emerge/_emerge/geometry.py,sha256=gWLdmkP4Sb-OHinCSuXiNw1BV7hQ8_zmo0PrcfEJXEA,16784
|
|
14
|
-
emerge/_emerge/howto.py,sha256=
|
|
15
|
-
emerge/_emerge/logsettings.py,sha256=
|
|
14
|
+
emerge/_emerge/howto.py,sha256=qY3v6DynB9ZBVeYa3sPFq1cDuvf2zyjnLShknqYyvKQ,8208
|
|
15
|
+
emerge/_emerge/logsettings.py,sha256=0iwTLwyGebBxDCGYMsLfoouQ8Ze2qrF2n0Iqv7FYD0w,2654
|
|
16
16
|
emerge/_emerge/material.py,sha256=8c3bEov76xqpH1w9s3ZGZ47EuofUNjVeI_IO4RG15Rk,3879
|
|
17
|
-
emerge/_emerge/mesh3d.py,sha256=
|
|
17
|
+
emerge/_emerge/mesh3d.py,sha256=5dGayT9HWDe7STn0_ZofXtmvthZypR57b7YmIBeI8Yg,30759
|
|
18
18
|
emerge/_emerge/mesher.py,sha256=cYq6AS1xUWpCrx3JCml5OCoDwNR0Z6FnFFOcH7QoSa4,12654
|
|
19
|
-
emerge/_emerge/periodic.py,sha256=
|
|
19
|
+
emerge/_emerge/periodic.py,sha256=oKYa3P_PREngrWwhwTpCSVYeo7JT7KjM9GuW1lY-0h0,10613
|
|
20
20
|
emerge/_emerge/plot.py,sha256=cf1I9mj7EIUJcq8vmANlUkqoV6QqVaJaP-zlC-T9E18,8041
|
|
21
21
|
emerge/_emerge/selection.py,sha256=HoRILOW52pJG1griLqdI5NsIEa3kwB0lsSojVcWtaBA,21087
|
|
22
|
-
emerge/_emerge/simmodel.py,sha256=
|
|
22
|
+
emerge/_emerge/simmodel.py,sha256=6qxuNvjBnY4PI0R8xMTfinXgkAnSyD1eHTDKhaCiC00,17816
|
|
23
23
|
emerge/_emerge/simulation_data.py,sha256=E3567Ro1YxQlidwZrc5G8IxG46Gnfy-k0wYWxckt1Iw,14128
|
|
24
|
-
emerge/_emerge/solver.py,sha256=
|
|
24
|
+
emerge/_emerge/solver.py,sha256=zkyYlykaDmuRy8VoQo3Z6tWi4cQtbUXY7ph0PclXOLc,40403
|
|
25
25
|
emerge/_emerge/system.py,sha256=p4HNz7d_LMRNE9Gk75vVdFecDH2iN_groAM9u-yQTpk,1618
|
|
26
26
|
emerge/_emerge/elements/__init__.py,sha256=I3n9aic6lJW-oGeqTEZ-Fpxvyl2i-WqsHdnrM3v1oB8,799
|
|
27
27
|
emerge/_emerge/elements/femdata.py,sha256=Gul5JJQq_gEDjFyf9RwLU-E7Aoh7hIpmrR7nL8SX4Hg,7893
|
|
@@ -30,36 +30,37 @@ emerge/_emerge/elements/legrange2.py,sha256=6pqQ6O8FyFBWCPwtvSN5yRxUG3L6pgGssw4B
|
|
|
30
30
|
emerge/_emerge/elements/ned2_interp.py,sha256=w7L8E_ksTjKHaJfVlelfNLIZTXACcb3fDmquYWlHIZY,27264
|
|
31
31
|
emerge/_emerge/elements/nedelec2.py,sha256=lzjGxKYq02DJ0AX4m3rX690Ve1MP-70mSQ462yrJZ20,6110
|
|
32
32
|
emerge/_emerge/elements/nedleg2.py,sha256=Hn_Vh8aRL1740-i1nKu-VdwgLLRZINPHLbQPKSGci5Y,9415
|
|
33
|
-
emerge/_emerge/geo/__init__.py,sha256=
|
|
33
|
+
emerge/_emerge/geo/__init__.py,sha256=ERmbdr8NUnDQWK-E-Bbc4Kl8AQczjpIP5BnwtZmcurE,1102
|
|
34
34
|
emerge/_emerge/geo/horn.py,sha256=eIGzjTa3AmhOXT3cSlPetDlW-l1PR-hG6zjSc6dCrz0,4171
|
|
35
35
|
emerge/_emerge/geo/modeler.py,sha256=s7JaizoqByT_YLSXw0h4o8sBlPDoZZW5iGOCJHqoYJo,15382
|
|
36
36
|
emerge/_emerge/geo/operations.py,sha256=7IPuuI0xZB8eTaJhaJjn9m48uyTS95FM78vO9GaF21I,9516
|
|
37
|
-
emerge/_emerge/geo/pcb.py,sha256=
|
|
37
|
+
emerge/_emerge/geo/pcb.py,sha256=nm9FKP_B97bFPRLa20vbRc23m0xxUK4djjQ_Kp855K4,47577
|
|
38
38
|
emerge/_emerge/geo/pmlbox.py,sha256=i9Ejxfwu3tZ4DOx4Ru5-FHX7f4rULy291z-119up-O4,7892
|
|
39
39
|
emerge/_emerge/geo/polybased.py,sha256=4J5ExvL-yw4NtA1ZZfIYdj3J5g0vpzq_nlCsIjFQFBU,19473
|
|
40
40
|
emerge/_emerge/geo/shapes.py,sha256=TTdlHG-OPogS19UCt6EeZqb8tb7WxZ6ZZHxBHIOrKuQ,17206
|
|
41
41
|
emerge/_emerge/geo/step.py,sha256=XcAiEN8W4umNmZdYmrGHX_aJUuiMgc6vgT-UIk8Gbqc,2689
|
|
42
42
|
emerge/_emerge/geo/pcb_tools/calculator.py,sha256=oumN7-0kejVDxZklE_JTnrDt5ywaHv_2Ef6D7mNABbc,812
|
|
43
43
|
emerge/_emerge/geo/pcb_tools/macro.py,sha256=ZlKDIZQTXjgklUJZVkaDa17eHIfo9ssq1jXouOSqSUU,2865
|
|
44
|
-
emerge/_emerge/mth/common_functions.py,sha256=
|
|
45
|
-
emerge/_emerge/mth/integrals.py,sha256=
|
|
46
|
-
emerge/_emerge/mth/optimized.py,sha256=
|
|
47
|
-
emerge/_emerge/
|
|
44
|
+
emerge/_emerge/mth/common_functions.py,sha256=oURfF-8p_0s1dKbUATc15dnKHFwvqWa6GC-JMW9UwnI,2061
|
|
45
|
+
emerge/_emerge/mth/integrals.py,sha256=Ypmd1r0CDQHQ-kWKdfhY_nypDDzTpTcTKpNdBeHieps,3565
|
|
46
|
+
emerge/_emerge/mth/optimized.py,sha256=K0YQ_faD6aETox2HKYlIIUJElqaGc8zrYEI9SedpQCc,16493
|
|
47
|
+
emerge/_emerge/mth/pairing.py,sha256=xNz_t1Vbxz5e8XsBW4JolRWPa_VTr2Gf1rW1G9lqfRo,3515
|
|
48
48
|
emerge/_emerge/physics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
49
49
|
emerge/_emerge/physics/microwave/__init__.py,sha256=QHeILGYWmvbfLl1o9wrTiWLm0evfXDgS0JiikUoMTts,28
|
|
50
50
|
emerge/_emerge/physics/microwave/adaptive_freq.py,sha256=5Ph2V4TTDjrFMeI7MI20JID9BNUNQ_ygtDSHj5Bkpmw,9736
|
|
51
|
-
emerge/_emerge/physics/microwave/microwave_3d.py,sha256=
|
|
52
|
-
emerge/_emerge/physics/microwave/microwave_bc.py,sha256=
|
|
53
|
-
emerge/_emerge/physics/microwave/microwave_data.py,sha256=
|
|
51
|
+
emerge/_emerge/physics/microwave/microwave_3d.py,sha256=4Ffe7KfyvmndVYIrv2IMA9yczU1Efoo8OrHbTpJtHJE,47034
|
|
52
|
+
emerge/_emerge/physics/microwave/microwave_bc.py,sha256=7nTlrVzOFNxfFdOZKcF9R7AGmB5K_ssKDte8DL7HNO4,35527
|
|
53
|
+
emerge/_emerge/physics/microwave/microwave_data.py,sha256=CBG3sLoKXaR6wBdFl-dv6tDVY1_OI3m6FAYt9iCAw4I,43695
|
|
54
54
|
emerge/_emerge/physics/microwave/periodic.py,sha256=wYSUgLFVtCLqSG3EDKoCDRU93iPUzBdXzVRdHTRmbpI,3000
|
|
55
55
|
emerge/_emerge/physics/microwave/port_functions.py,sha256=aVU__AkVk8b1kH2J_oDLF5iNReCxC9nzCtesFSSSSQo,2112
|
|
56
56
|
emerge/_emerge/physics/microwave/sc.py,sha256=EjbbHEZ1zc42V0s8ItrN8jIXkrg3N5R495gfurZ2Wck,4992
|
|
57
57
|
emerge/_emerge/physics/microwave/simjob.py,sha256=DzkniH4yVi_dYyLuKVzMnvve8u-HtOKoXkaF1kUplRo,4678
|
|
58
|
-
emerge/_emerge/physics/microwave/sparam.py,sha256=
|
|
58
|
+
emerge/_emerge/physics/microwave/sparam.py,sha256=9bbnuJhdhwUlqf2kehZ_R9ieFN6toUUqW_ppULLhpV0,4959
|
|
59
59
|
emerge/_emerge/physics/microwave/touchstone.py,sha256=I1gtdCv3FYaYjhWQRgjIp-QSS9caTD-axkbiO-48E4E,5792
|
|
60
|
-
emerge/_emerge/physics/microwave/assembly/assembler.py,sha256=
|
|
61
|
-
emerge/_emerge/physics/microwave/assembly/curlcurl.py,sha256=
|
|
60
|
+
emerge/_emerge/physics/microwave/assembly/assembler.py,sha256=oIlH8aJWD0kb5KPzHXT45e01xExpY6H0E43GVEBFSUQ,20573
|
|
61
|
+
emerge/_emerge/physics/microwave/assembly/curlcurl.py,sha256=fO1r1lyPF5U3UvlQg2Zg1gnnpODrWIv-qVEYDWYXqgM,18976
|
|
62
62
|
emerge/_emerge/physics/microwave/assembly/generalized_eigen.py,sha256=wtLKCndYgqKLCH0mSni9bu8yhnPi9ksIAafvToyy2TQ,16171
|
|
63
|
+
emerge/_emerge/physics/microwave/assembly/periodicbc.py,sha256=Zg1kgQMccDQA2oVErpfldv6v2oYfc9Y3xWcpfg93-FY,4646
|
|
63
64
|
emerge/_emerge/physics/microwave/assembly/robinbc.py,sha256=tJg5GzOGuNybu5qdtOuIgcpem6IVAMrPFre_SENLg44,16246
|
|
64
65
|
emerge/_emerge/plot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
65
66
|
emerge/_emerge/plot/display.py,sha256=akwFUOgVEZEIyY6eo05jeFgNvKXy41blwpHohAtn8OM,18247
|
|
@@ -70,11 +71,12 @@ emerge/_emerge/plot/pyvista/__init__.py,sha256=CPclatEu6mFnJZzCQk09g6T6Fh20WTbiL
|
|
|
70
71
|
emerge/_emerge/plot/pyvista/display.py,sha256=PJnM5yDSYrTPT0Ts7Sia2LOkaSs8h1Mj_Gt7q9lF-i4,32908
|
|
71
72
|
emerge/_emerge/plot/pyvista/display_settings.py,sha256=OFxZWasZ-AN71l41rRybTb_mn2z5rFfdusqRXDCJr-w,848
|
|
72
73
|
emerge/_emerge/projects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
|
-
emerge/_emerge/projects/_gen_base.txt,sha256=
|
|
74
|
+
emerge/_emerge/projects/_gen_base.txt,sha256=_4McYD9Sb1KWRsrGV51mNNAJNYkjm_IemMnCdAsGuLo,607
|
|
74
75
|
emerge/_emerge/projects/_load_base.txt,sha256=JTAhWvHXJQYKe-aDD4HDdmE7f3VXxeurhDzwFCegrEg,511
|
|
75
76
|
emerge/_emerge/projects/generate_project.py,sha256=TNw-0SpLc82MBq0bd9hB_yqvBZCgmuPonCBsHTp91uk,1450
|
|
76
|
-
emerge
|
|
77
|
-
emerge-0.
|
|
78
|
-
emerge-0.
|
|
79
|
-
emerge-0.
|
|
80
|
-
emerge-0.
|
|
77
|
+
emerge/_emerge/solve_interfaces/pardiso_interface.py,sha256=3fMRzAQgi9hcP4xLwF-Uqnw8a7rv9RY_ckxc2M2qLQ4,15173
|
|
78
|
+
emerge-0.5.1.dist-info/METADATA,sha256=0U-pN9h-zb8VCt0LKDEZuNUGluWG9buqY2aO9RARyLg,2900
|
|
79
|
+
emerge-0.5.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
80
|
+
emerge-0.5.1.dist-info/entry_points.txt,sha256=8rFvAXticpKg4OTC8JEvAksnduW72KIEskCGG9XnFf8,43
|
|
81
|
+
emerge-0.5.1.dist-info/licenses/LICENSE,sha256=6tAv8fkWA_-Ell_nboaXajWH3H-vRftIr_4CU2t0S4Y,15180
|
|
82
|
+
emerge-0.5.1.dist-info/RECORD,,
|
|
@@ -1,455 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2016 Adrian Haas and ETH Zürich
|
|
2
|
-
# Modifications Copyright (c) 2025 Robert Fennis
|
|
3
|
-
#
|
|
4
|
-
# SPDX-License-Identifier: BSD-3-Clause AND GPL-2.0-or-later
|
|
5
|
-
#
|
|
6
|
-
# This file incorporates code from the PyPardiso project, which is
|
|
7
|
-
# distributed under the BSD 3-Clause License. You may redistribute
|
|
8
|
-
# and/or modify this file under either
|
|
9
|
-
#
|
|
10
|
-
# * the terms of the BSD 3-Clause License (see below), or
|
|
11
|
-
# * the terms of the GNU General Public License, version 2 or later.
|
|
12
|
-
#
|
|
13
|
-
# ----------------------------------------------------------------------
|
|
14
|
-
# BSD 3-Clause License
|
|
15
|
-
#
|
|
16
|
-
# Redistribution and use in source and binary forms, with or without
|
|
17
|
-
# modification, are permitted provided that the following conditions are
|
|
18
|
-
# met:
|
|
19
|
-
# 1. Redistributions of source code must retain the above copyright
|
|
20
|
-
# notice, this list of conditions and the following disclaimer.
|
|
21
|
-
# 2. Redistributions in binary form must reproduce the above copyright
|
|
22
|
-
# notice, this list of conditions and the following disclaimer in the
|
|
23
|
-
# documentation and/or other materials provided with the distribution.
|
|
24
|
-
# 3. Neither the name of ETH Zürich nor the names of its contributors
|
|
25
|
-
# may be used to endorse or promote products derived from this
|
|
26
|
-
# software without specific prior written permission.
|
|
27
|
-
#
|
|
28
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
29
|
-
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
30
|
-
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
31
|
-
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
32
|
-
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
33
|
-
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
34
|
-
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
35
|
-
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
36
|
-
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
37
|
-
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
38
|
-
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
39
|
-
# DAMAGE.
|
|
40
|
-
# ----------------------------------------------------------------------
|
|
41
|
-
|
|
42
|
-
# coding: utf-8
|
|
43
|
-
import scipy.sparse as sp
|
|
44
|
-
# coding: utf-8
|
|
45
|
-
import os
|
|
46
|
-
import sys
|
|
47
|
-
import glob
|
|
48
|
-
import ctypes
|
|
49
|
-
import warnings
|
|
50
|
-
import hashlib
|
|
51
|
-
import site
|
|
52
|
-
from ctypes.util import find_library
|
|
53
|
-
|
|
54
|
-
import numpy as np
|
|
55
|
-
import scipy.sparse as sp
|
|
56
|
-
from scipy.sparse import SparseEfficiencyWarning, csr_matrix
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
_PARDISO_ERROR_CODES = """
|
|
60
|
-
0 | No error.
|
|
61
|
-
-1 | Input inconsistent.
|
|
62
|
-
-2 | Not enough memory.
|
|
63
|
-
-3 | Reordering problem.
|
|
64
|
-
-4 | Zero pivot, numerical fac. or iterative refinement problem.
|
|
65
|
-
-5 | Unclassified (internal) error.
|
|
66
|
-
-6 | Preordering failed (matrix types 11(real and nonsymmetric), 13(complex and nonsymmetric) only).
|
|
67
|
-
-7 | Diagonal Matrix problem.
|
|
68
|
-
-8 | 32-bit integer overflow problem.
|
|
69
|
-
-10 | No license file pardiso.lic found.
|
|
70
|
-
-11 | License is expired.
|
|
71
|
-
-12 | Wrong username or hostname.
|
|
72
|
-
-100 | Reached maximum number of Krylov-subspace iteration in iterative solver.
|
|
73
|
-
-101 | No sufficient convergence in Krylov-subspace iteration within 25 iterations.
|
|
74
|
-
-102 | Error in Krylov-subspace iteration.
|
|
75
|
-
-103 | Bread-Down in Krylov-subspace iteration
|
|
76
|
-
"""
|
|
77
|
-
|
|
78
|
-
class MKL_Complex16(ctypes.Structure):
|
|
79
|
-
_fields_ = [("real", ctypes.c_double),
|
|
80
|
-
("imag", ctypes.c_double)]
|
|
81
|
-
|
|
82
|
-
cpx16_p = ctypes.POINTER(MKL_Complex16)
|
|
83
|
-
|
|
84
|
-
class PyPardisoSolver:
|
|
85
|
-
"""
|
|
86
|
-
Python interface to the Intel MKL PARDISO library for solving large sparse linear systems of equations Ax=b.
|
|
87
|
-
|
|
88
|
-
Pardiso documentation: https://software.intel.com/en-us/node/470282
|
|
89
|
-
|
|
90
|
-
--- Basic usage ---
|
|
91
|
-
matrix type: real (float64) and nonsymetric
|
|
92
|
-
methods: solve, factorize
|
|
93
|
-
|
|
94
|
-
- use the "solve(A,b)" method to solve Ax=b for x, where A is a sparse CSR (or CSC) matrix and b is a numpy array
|
|
95
|
-
- use the "factorize(A)" method first, if you intend to solve the system more than once for different right-hand
|
|
96
|
-
sides, the factorization will be reused automatically afterwards
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
--- Advanced usage ---
|
|
100
|
-
methods: get_iparm, get_iparms, set_iparm, set_matrix_type, set_phase
|
|
101
|
-
|
|
102
|
-
- additional options can be accessed by setting the iparms (see Pardiso documentation for description)
|
|
103
|
-
- other matrix types can be chosen with the "set_matrix_type" method. complex matrix types are currently not
|
|
104
|
-
supported. pypardiso is only teste for mtype=11 (real and nonsymetric)
|
|
105
|
-
- the solving phases can be set with the "set_phase" method
|
|
106
|
-
- The out-of-core (OOC) solver either fails or crashes my computer, be careful with iparm[60]
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
--- Statistical info ---
|
|
110
|
-
methods: set_statistical_info_on, set_statistical_info_off
|
|
111
|
-
|
|
112
|
-
- the Pardiso solver writes statistical info to the C stdout if desired
|
|
113
|
-
- if you use pypardiso from within a jupyter notebook you can turn the statistical info on and capture the output
|
|
114
|
-
real-time by wrapping your call to "solve" with wurlitzer.sys_pipes() (https://github.com/minrk/wurlitzer,
|
|
115
|
-
https://pypi.python.org/pypi/wurlitzer/)
|
|
116
|
-
- wurlitzer dosen't work on windows, info appears in notebook server console window if used from jupyter notebook
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
--- Memory usage ---
|
|
120
|
-
methods: remove_stored_factorization, free_memory
|
|
121
|
-
|
|
122
|
-
- remove_stored_factorization can be used to delete the wrapper's copy of matrix A
|
|
123
|
-
- free_memory releases the internal memory of the solver
|
|
124
|
-
|
|
125
|
-
"""
|
|
126
|
-
|
|
127
|
-
def __init__(self, mtype=11, phase=13, size_limit_storage=5e7):
|
|
128
|
-
|
|
129
|
-
self.libmkl = None
|
|
130
|
-
|
|
131
|
-
# custom mkl_rt path in environment variable
|
|
132
|
-
mkl_rt = os.environ.get('PYPARDISO_MKL_RT')
|
|
133
|
-
|
|
134
|
-
# Look for the mkl_rt shared library with ctypes.util.find_library
|
|
135
|
-
if mkl_rt is None:
|
|
136
|
-
mkl_rt = find_library('mkl_rt')
|
|
137
|
-
# also look for mkl_rt.1, Windows-specific, see
|
|
138
|
-
# https://github.com/haasad/PyPardisoProject/issues/12
|
|
139
|
-
if mkl_rt is None:
|
|
140
|
-
mkl_rt = find_library('mkl_rt.1')
|
|
141
|
-
|
|
142
|
-
# If we can't find mkl_rt with find_library, we search the directory
|
|
143
|
-
# tree, using a few assumptions:
|
|
144
|
-
# - the shared library can be found in a subdirectory of sys.prefix
|
|
145
|
-
# https://docs.python.org/3.9/library/sys.html#sys.prefix
|
|
146
|
-
# or in the user site in case of user-local installation like
|
|
147
|
-
# `pip install --user`
|
|
148
|
-
# https://peps.python.org/pep-0370/
|
|
149
|
-
# https://docs.python.org/3/library/site.html#site.USER_BASE
|
|
150
|
-
# - either in `lib` (linux and macOS) or `Library\bin` (windows)
|
|
151
|
-
# - if there are multiple matches for `mkl_rt`, try shorter paths
|
|
152
|
-
# first
|
|
153
|
-
if mkl_rt is None:
|
|
154
|
-
globs = glob.glob(
|
|
155
|
-
f'{sys.prefix}/[Ll]ib*/**/*mkl_rt*', recursive=True
|
|
156
|
-
) or glob.glob(
|
|
157
|
-
f'{site.USER_BASE}/[Ll]ib*/**/*mkl_rt*', recursive=True
|
|
158
|
-
)
|
|
159
|
-
for path in sorted(globs, key=len):
|
|
160
|
-
try:
|
|
161
|
-
self.libmkl = ctypes.CDLL(path)
|
|
162
|
-
break
|
|
163
|
-
except (OSError, ImportError):
|
|
164
|
-
pass
|
|
165
|
-
|
|
166
|
-
if self.libmkl is None:
|
|
167
|
-
raise ImportError(
|
|
168
|
-
'Shared library mkl_rt not found. '
|
|
169
|
-
'Use environment variable PYPARDISO_MKL_RT to provide a custom path.'
|
|
170
|
-
)
|
|
171
|
-
else:
|
|
172
|
-
self.libmkl = ctypes.CDLL(mkl_rt)
|
|
173
|
-
|
|
174
|
-
self._mkl_pardiso = self.libmkl.pardiso
|
|
175
|
-
|
|
176
|
-
# determine 32bit or 64bit architecture
|
|
177
|
-
if ctypes.sizeof(ctypes.c_void_p) == 8:
|
|
178
|
-
self._pt_type = (ctypes.c_int64, np.int64)
|
|
179
|
-
else:
|
|
180
|
-
self._pt_type = (ctypes.c_int32, np.int32)
|
|
181
|
-
|
|
182
|
-
self._mkl_pardiso.argtypes = [ctypes.POINTER(self._pt_type[0]), # pt
|
|
183
|
-
ctypes.POINTER(ctypes.c_int32), # maxfct
|
|
184
|
-
ctypes.POINTER(ctypes.c_int32), # mnum
|
|
185
|
-
ctypes.POINTER(ctypes.c_int32), # mtype
|
|
186
|
-
ctypes.POINTER(ctypes.c_int32), # phase
|
|
187
|
-
ctypes.POINTER(ctypes.c_int32), # n
|
|
188
|
-
ctypes.POINTER(None), # a
|
|
189
|
-
ctypes.POINTER(ctypes.c_int32), # ia
|
|
190
|
-
ctypes.POINTER(ctypes.c_int32), # ja
|
|
191
|
-
ctypes.POINTER(ctypes.c_int32), # perm
|
|
192
|
-
ctypes.POINTER(ctypes.c_int32), # nrhs
|
|
193
|
-
ctypes.POINTER(ctypes.c_int32), # iparm
|
|
194
|
-
ctypes.POINTER(ctypes.c_int32), # msglvl
|
|
195
|
-
ctypes.POINTER(None), # b
|
|
196
|
-
ctypes.POINTER(None), # x
|
|
197
|
-
ctypes.POINTER(ctypes.c_int32)] # error
|
|
198
|
-
|
|
199
|
-
self._mkl_pardiso.restype = None
|
|
200
|
-
|
|
201
|
-
self.pt = np.zeros(64, dtype=self._pt_type[1])
|
|
202
|
-
self.iparm = np.zeros(64, dtype=np.int32)
|
|
203
|
-
self.perm = np.zeros(0, dtype=np.int32)
|
|
204
|
-
|
|
205
|
-
self.mtype = mtype
|
|
206
|
-
self.phase = phase
|
|
207
|
-
self.msglvl = False
|
|
208
|
-
|
|
209
|
-
self.factorized_A = csr_matrix((0, 0))
|
|
210
|
-
self.size_limit_storage = size_limit_storage
|
|
211
|
-
self._solve_transposed = False
|
|
212
|
-
|
|
213
|
-
def factorize(self, A):
|
|
214
|
-
"""
|
|
215
|
-
Factorize the matrix A, the factorization will automatically be used if the same matrix A is passed to the
|
|
216
|
-
solve method. This will drastically increase the speed of solve, if solve is called more than once for the
|
|
217
|
-
same matrix A
|
|
218
|
-
|
|
219
|
-
--- Parameters ---
|
|
220
|
-
A: sparse square CSR matrix (scipy.sparse.csr.csr_matrix), CSC matrix also possible
|
|
221
|
-
"""
|
|
222
|
-
|
|
223
|
-
self._check_A(A)
|
|
224
|
-
|
|
225
|
-
if A.nnz > self.size_limit_storage:
|
|
226
|
-
self.factorized_A = self._hash_csr_matrix(A)
|
|
227
|
-
else:
|
|
228
|
-
self.factorized_A = A.copy()
|
|
229
|
-
|
|
230
|
-
self.set_phase(12)
|
|
231
|
-
b = np.zeros((A.shape[0], 1))
|
|
232
|
-
self._call_pardiso(A, b)
|
|
233
|
-
|
|
234
|
-
def solve(self, A, b):
|
|
235
|
-
"""
|
|
236
|
-
solve Ax=b for x
|
|
237
|
-
|
|
238
|
-
--- Parameters ---
|
|
239
|
-
A: sparse square CSR matrix (scipy.sparse.csr.csr_matrix), CSC matrix also possible
|
|
240
|
-
b: numpy ndarray
|
|
241
|
-
right-hand side(s), b.shape[0] needs to be the same as A.shape[0]
|
|
242
|
-
|
|
243
|
-
--- Returns ---
|
|
244
|
-
x: numpy ndarray
|
|
245
|
-
solution of the system of linear equations, same shape as input b
|
|
246
|
-
"""
|
|
247
|
-
|
|
248
|
-
self._check_A(A)
|
|
249
|
-
b = self._check_b(A, b)
|
|
250
|
-
|
|
251
|
-
if self._is_already_factorized(A):
|
|
252
|
-
self.set_phase(33)
|
|
253
|
-
else:
|
|
254
|
-
self.set_phase(13)
|
|
255
|
-
|
|
256
|
-
x = self._call_pardiso(A, b)
|
|
257
|
-
|
|
258
|
-
# it is possible to call the solver with empty columns, but computationally expensive to check this
|
|
259
|
-
# beforehand, therefore only the result is checked for infinite elements.
|
|
260
|
-
# if not np.isfinite(x).all():
|
|
261
|
-
# warnings.warn('The result contains infinite elements. Make sure that matrix A contains no empty columns.',
|
|
262
|
-
# PyPardisoWarning)
|
|
263
|
-
# --> this check doesn't work consistently, maybe add an advanced input check method for A
|
|
264
|
-
|
|
265
|
-
return x
|
|
266
|
-
|
|
267
|
-
def _is_already_factorized(self, A):
|
|
268
|
-
if isinstance(self.factorized_A, str):
|
|
269
|
-
return self._hash_csr_matrix(A) == self.factorized_A
|
|
270
|
-
else:
|
|
271
|
-
return self._csr_matrix_equal(A, self.factorized_A)
|
|
272
|
-
|
|
273
|
-
def _csr_matrix_equal(self, a1, a2):
|
|
274
|
-
return all((np.array_equal(a1.indptr, a2.indptr),
|
|
275
|
-
np.array_equal(a1.indices, a2.indices),
|
|
276
|
-
np.array_equal(a1.data, a2.data)))
|
|
277
|
-
|
|
278
|
-
def _hash_csr_matrix(self, matrix):
|
|
279
|
-
return (hashlib.sha1(matrix.indices).hexdigest() +
|
|
280
|
-
hashlib.sha1(matrix.indptr).hexdigest() +
|
|
281
|
-
hashlib.sha1(matrix.data).hexdigest())
|
|
282
|
-
|
|
283
|
-
def _check_A(self, A):
|
|
284
|
-
if A.shape[0] != A.shape[1]:
|
|
285
|
-
raise ValueError('Matrix A needs to be square, but has shape: {}'.format(A.shape))
|
|
286
|
-
|
|
287
|
-
if sp.issparse(A) and A.format == "csr":
|
|
288
|
-
self._solve_transposed = False
|
|
289
|
-
self.set_iparm(12, 1)
|
|
290
|
-
elif sp.issparse(A) and A.format == "csc":
|
|
291
|
-
self._solve_transposed = True
|
|
292
|
-
self.set_iparm(12, 0)
|
|
293
|
-
else:
|
|
294
|
-
msg = 'PyPardiso requires matrix A to be in CSR or CSC format, but matrix A is: {}'.format(type(A))
|
|
295
|
-
raise TypeError(msg)
|
|
296
|
-
|
|
297
|
-
# scipy allows unsorted csr-indices, which lead to completely wrong pardiso results
|
|
298
|
-
if not A.has_sorted_indices:
|
|
299
|
-
A.sort_indices()
|
|
300
|
-
|
|
301
|
-
# scipy allows csr matrices with empty rows. a square matrix with an empty row is singular. calling
|
|
302
|
-
# pardiso with a matrix A that contains empty rows leads to a segfault, same applies for csc with
|
|
303
|
-
# empty columns
|
|
304
|
-
if not np.diff(A.indptr).all():
|
|
305
|
-
row_col = 'column' if self._solve_transposed else 'row'
|
|
306
|
-
raise ValueError('Matrix A is singular, because it contains empty {}(s)'.format(row_col))
|
|
307
|
-
|
|
308
|
-
def _check_b(self, A, b):
|
|
309
|
-
if sp.issparse(b):
|
|
310
|
-
warnings.warn('PyPardiso requires the right-hand side b to be a dense array for maximum efficiency',
|
|
311
|
-
SparseEfficiencyWarning)
|
|
312
|
-
b = b.todense()
|
|
313
|
-
|
|
314
|
-
# pardiso expects fortran (column-major) order for b
|
|
315
|
-
if not b.flags.f_contiguous:
|
|
316
|
-
b = np.asfortranarray(b)
|
|
317
|
-
|
|
318
|
-
if b.shape[0] != A.shape[0]:
|
|
319
|
-
raise ValueError("Dimension mismatch: Matrix A {} and array b {}".format(A.shape, b.shape))
|
|
320
|
-
|
|
321
|
-
if b.dtype != np.float64:
|
|
322
|
-
if b.dtype in [np.float16, np.float32, np.int16, np.int32, np.int64]:
|
|
323
|
-
warnings.warn("Array b's data type was converted from {} to float64".format(str(b.dtype)),
|
|
324
|
-
PyPardisoWarning)
|
|
325
|
-
b = b.astype(np.float64)
|
|
326
|
-
elif b.dtype in (np.complex128, np.complex64):
|
|
327
|
-
b = b.astype(np.complex128)
|
|
328
|
-
else:
|
|
329
|
-
raise TypeError('Dtype {} for array b is not supported'.format(str(b.dtype)))
|
|
330
|
-
|
|
331
|
-
return b
|
|
332
|
-
|
|
333
|
-
def _call_pardiso(self, A, b):
|
|
334
|
-
self.set_iparm(2,3)
|
|
335
|
-
self.set_iparm(3,6)
|
|
336
|
-
self.set_iparm(10,13)
|
|
337
|
-
self.set_iparm(13,2)
|
|
338
|
-
|
|
339
|
-
x = np.zeros_like(b)
|
|
340
|
-
pardiso_error = ctypes.c_int32(0)
|
|
341
|
-
c_int32_p = ctypes.POINTER(ctypes.c_int32)
|
|
342
|
-
c_float64_p = ctypes.POINTER(ctypes.c_double)
|
|
343
|
-
|
|
344
|
-
# 1-based indexing
|
|
345
|
-
ia = A.indptr + 1
|
|
346
|
-
ja = A.indices + 1
|
|
347
|
-
|
|
348
|
-
mtype = 3
|
|
349
|
-
|
|
350
|
-
if A.dtype == np.complex128:
|
|
351
|
-
val_ptr = A.data.ctypes.data_as(cpx16_p)
|
|
352
|
-
rhs_ptr = b.ctypes.data_as(cpx16_p)
|
|
353
|
-
x_ptr = x.ctypes.data_as(cpx16_p)
|
|
354
|
-
else:
|
|
355
|
-
val_ptr = A.data.ctypes.data_as(c_float64_p)
|
|
356
|
-
rhs_ptr = b.ctypes.data_as(c_float64_p)
|
|
357
|
-
x_ptr = x.ctypes.data_as(c_float64_p)
|
|
358
|
-
|
|
359
|
-
self._mkl_pardiso(self.pt.ctypes.data_as(ctypes.POINTER(self._pt_type[0])), # pt
|
|
360
|
-
ctypes.byref(ctypes.c_int32(1)), # maxfct
|
|
361
|
-
ctypes.byref(ctypes.c_int32(1)), # mnum
|
|
362
|
-
ctypes.byref(ctypes.c_int32(mtype)), # mtype -> 11 for real-nonsymetric
|
|
363
|
-
ctypes.byref(ctypes.c_int32(self.phase)), # phase -> 13
|
|
364
|
-
ctypes.byref(ctypes.c_int32(A.shape[0])), # N -> number of equations/size of matrix
|
|
365
|
-
val_ptr, # A -> non-zero entries in matrix
|
|
366
|
-
ia.ctypes.data_as(c_int32_p), # ia -> csr-indptr
|
|
367
|
-
ja.ctypes.data_as(c_int32_p), # ja -> csr-indices
|
|
368
|
-
self.perm.ctypes.data_as(c_int32_p), # perm -> empty
|
|
369
|
-
ctypes.byref(ctypes.c_int32(1 if b.ndim == 1 else b.shape[1])), # nrhs
|
|
370
|
-
self.iparm.ctypes.data_as(c_int32_p), # iparm-array
|
|
371
|
-
ctypes.byref(ctypes.c_int32(self.msglvl)), # msg-level -> 1: statistical info is printed
|
|
372
|
-
rhs_ptr, # b -> right-hand side vector/matrix
|
|
373
|
-
x_ptr, # x -> output
|
|
374
|
-
ctypes.byref(pardiso_error)) # pardiso error
|
|
375
|
-
|
|
376
|
-
if pardiso_error.value != 0:
|
|
377
|
-
raise PyPardisoError(pardiso_error.value)
|
|
378
|
-
else:
|
|
379
|
-
return np.ascontiguousarray(x) # change memory-layout back from fortran to c order
|
|
380
|
-
|
|
381
|
-
def get_iparms(self):
|
|
382
|
-
"""Returns a dictionary of iparms"""
|
|
383
|
-
return dict(enumerate(self.iparm, 1))
|
|
384
|
-
|
|
385
|
-
def get_iparm(self, i):
|
|
386
|
-
"""Returns the i-th iparm (1-based indexing)"""
|
|
387
|
-
return self.iparm[i-1]
|
|
388
|
-
|
|
389
|
-
def set_iparm(self, i, value):
|
|
390
|
-
"""set the i-th iparm to 'value' (1-based indexing)"""
|
|
391
|
-
if i not in {1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 18, 19, 21, 24, 25, 27, 28, 31, 34, 35, 36, 37, 56, 60}:
|
|
392
|
-
warnings.warn('{} is no input iparm. See the Pardiso documentation.'.format(value), PyPardisoWarning)
|
|
393
|
-
self.iparm[i-1] = value
|
|
394
|
-
|
|
395
|
-
def set_matrix_type(self, mtype):
|
|
396
|
-
"""Set the matrix type (see Pardiso documentation)"""
|
|
397
|
-
self.mtype = mtype
|
|
398
|
-
|
|
399
|
-
def set_statistical_info_on(self):
|
|
400
|
-
"""Display statistical info (appears in notebook server console window if pypardiso is
|
|
401
|
-
used from jupyter notebook, use wurlitzer to redirect info to the notebook)"""
|
|
402
|
-
self.msglvl = 1
|
|
403
|
-
|
|
404
|
-
def set_statistical_info_off(self):
|
|
405
|
-
"""Turns statistical info off"""
|
|
406
|
-
self.msglvl = 0
|
|
407
|
-
|
|
408
|
-
def set_phase(self, phase):
|
|
409
|
-
"""Set the phase(s) for the solver. See the Pardiso documentation for details."""
|
|
410
|
-
self.phase = phase
|
|
411
|
-
|
|
412
|
-
def remove_stored_factorization(self):
|
|
413
|
-
"""removes the stored factorization, this will free the memory in python, but the factorization in pardiso
|
|
414
|
-
is still accessible with a direct call to self._call_pardiso(A,b) with phase=33"""
|
|
415
|
-
self.factorized_A = sp.csr_matrix((0, 0))
|
|
416
|
-
|
|
417
|
-
def free_memory(self, everything=False):
|
|
418
|
-
"""release mkl's internal memory, either only for the factorization (ie the LU-decomposition) or all of
|
|
419
|
-
mkl's internal memory if everything=True"""
|
|
420
|
-
self.remove_stored_factorization()
|
|
421
|
-
A = sp.csr_matrix((0, 0))
|
|
422
|
-
b = np.zeros(0)
|
|
423
|
-
self.set_phase(-1 if everything else 0)
|
|
424
|
-
self._call_pardiso(A, b)
|
|
425
|
-
self.set_phase(13)
|
|
426
|
-
|
|
427
|
-
def pardiso_solve(self, A: csr_matrix, b: np.ndarray):
|
|
428
|
-
if sp.issparse(A) and A.format == "csc":
|
|
429
|
-
A = A.tocsr()
|
|
430
|
-
|
|
431
|
-
self._check_A(A)
|
|
432
|
-
|
|
433
|
-
if not self._is_already_factorized(A):
|
|
434
|
-
self.factorize(A)
|
|
435
|
-
|
|
436
|
-
try:
|
|
437
|
-
x = self.solve(A, b)
|
|
438
|
-
except PyPardisoError as e:
|
|
439
|
-
print('Error Codes:')
|
|
440
|
-
print(_PARDISO_ERROR_CODES)
|
|
441
|
-
|
|
442
|
-
return x.squeeze()
|
|
443
|
-
|
|
444
|
-
class PyPardisoWarning(UserWarning):
|
|
445
|
-
pass
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
class PyPardisoError(Exception):
|
|
449
|
-
|
|
450
|
-
def __init__(self, value):
|
|
451
|
-
self.value = value
|
|
452
|
-
|
|
453
|
-
def __str__(self):
|
|
454
|
-
return ('The Pardiso solver failed with error code {}. '
|
|
455
|
-
'See Pardiso documentation for details.'.format(self.value))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|