ngsPETSc 0.0.7a7__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.
- ngsPETSc/__init__.py +46 -0
- ngsPETSc/eps.py +184 -0
- ngsPETSc/ksp.py +292 -0
- ngsPETSc/mat.py +146 -0
- ngsPETSc/nullspace.py +55 -0
- ngsPETSc/pc.py +172 -0
- ngsPETSc/plex.py +215 -0
- ngsPETSc/snes.py +180 -0
- ngsPETSc/utils/__init__.py +0 -0
- ngsPETSc/utils/fenicsx.py +83 -0
- ngsPETSc/utils/firedrake/__init__.py +0 -0
- ngsPETSc/utils/firedrake/hierarchies.py +266 -0
- ngsPETSc/utils/firedrake/meshes.py +307 -0
- ngsPETSc/utils/ngs/__init__.py +0 -0
- ngsPETSc/vec.py +117 -0
- ngspetsc-0.0.7a7.dist-info/LICENSE.txt +10 -0
- ngspetsc-0.0.7a7.dist-info/METADATA +54 -0
- ngspetsc-0.0.7a7.dist-info/RECORD +19 -0
- ngspetsc-0.0.7a7.dist-info/WHEEL +4 -0
ngsPETSc/__init__.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'''
|
|
2
|
+
ngsPETSc is a NGSolve/Netgen interface to PETSc
|
|
3
|
+
'''
|
|
4
|
+
from ngsPETSc.plex import *
|
|
5
|
+
|
|
6
|
+
__all__ = []
|
|
7
|
+
|
|
8
|
+
#Firedrake
|
|
9
|
+
try:
|
|
10
|
+
import firedrake
|
|
11
|
+
except ImportError:
|
|
12
|
+
firedrake = None
|
|
13
|
+
|
|
14
|
+
if firedrake:
|
|
15
|
+
from ngsPETSc.utils.firedrake.meshes import *
|
|
16
|
+
from ngsPETSc.utils.firedrake.hierarchies import *
|
|
17
|
+
__all__ = __all__ + ["FiredrakeMesh", "NetgenHierarchy"]
|
|
18
|
+
|
|
19
|
+
#FEniCSx
|
|
20
|
+
try:
|
|
21
|
+
import dolfinx
|
|
22
|
+
except ImportError:
|
|
23
|
+
dolfinx = None
|
|
24
|
+
|
|
25
|
+
if dolfinx:
|
|
26
|
+
from ngsPETSc.utils.fenicsx import *
|
|
27
|
+
|
|
28
|
+
#Netgen
|
|
29
|
+
try:
|
|
30
|
+
import ngsolve
|
|
31
|
+
except ImportError:
|
|
32
|
+
ngsolve = None
|
|
33
|
+
|
|
34
|
+
if ngsolve:
|
|
35
|
+
from ngsPETSc.mat import *
|
|
36
|
+
from ngsPETSc.vec import *
|
|
37
|
+
from ngsPETSc.nullspace import *
|
|
38
|
+
from ngsPETSc.pc import *
|
|
39
|
+
from ngsPETSc.ksp import *
|
|
40
|
+
from ngsPETSc.snes import *
|
|
41
|
+
from ngsPETSc.eps import *
|
|
42
|
+
__all__ = __all__ + ["Matrix","VectorMapping","MeshMapping",
|
|
43
|
+
"KrylovSolver","EigenSolver","NullSpace",
|
|
44
|
+
"PETScPreconditioner", "NonLinearSolver"]
|
|
45
|
+
|
|
46
|
+
VERSION = "0.0.5"
|
ngsPETSc/eps.py
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
'''
|
|
2
|
+
This module contains all the functions related to the SLEPc eigenvalue
|
|
3
|
+
solver (EPS/PEP) interface for NGSolve
|
|
4
|
+
'''
|
|
5
|
+
from petsc4py import PETSc
|
|
6
|
+
try:
|
|
7
|
+
from slepc4py import SLEPc
|
|
8
|
+
except ImportError:
|
|
9
|
+
import warnings
|
|
10
|
+
warnings.warn("Import Warning: it was not possible to import SLEPc")
|
|
11
|
+
SLEPc = None
|
|
12
|
+
|
|
13
|
+
from mpi4py import MPI
|
|
14
|
+
|
|
15
|
+
from ngsolve import GridFunction
|
|
16
|
+
|
|
17
|
+
from ngsPETSc import Matrix, VectorMapping
|
|
18
|
+
class EigenSolver():
|
|
19
|
+
"""
|
|
20
|
+
This calss creates a SLEPc Eigen Problem Solver (EPS/PEP) from NGSolve
|
|
21
|
+
variational problem pencil, i.e.
|
|
22
|
+
a0(u,v)+lam*a1(u,v)+(lam^2)*a2(u,v)+ ... = 0
|
|
23
|
+
Inspired by Firedrake Eigensolver class.
|
|
24
|
+
|
|
25
|
+
:arg pencil: tuple containing the bilinear forms a: V x V -> K composing
|
|
26
|
+
the pencil, e.g. (m,a) with a = BilinearForm(grad(u),grad(v)*dx) and
|
|
27
|
+
m = BilinearForm(-1*u*v*dx)
|
|
28
|
+
|
|
29
|
+
:arg fes: finite element space V
|
|
30
|
+
|
|
31
|
+
:arg nev: number of requested eigenvalue
|
|
32
|
+
|
|
33
|
+
:arg ncv: dimension of the internal subspace used by SLEPc,
|
|
34
|
+
by Default by SLEPc.DECIDE
|
|
35
|
+
|
|
36
|
+
:arg solverParameters: parameters to be passed to the KSP solver
|
|
37
|
+
|
|
38
|
+
:arg optionsPrefix: special solver options prefix for this specific Krylov solver
|
|
39
|
+
|
|
40
|
+
"""
|
|
41
|
+
if SLEPc is not None:
|
|
42
|
+
def __init__(self, pencil, fes, nev, ncv=SLEPc.DECIDE, optionsPrefix=None,
|
|
43
|
+
solverParameters=None):
|
|
44
|
+
self.comm = MPI.COMM_WORLD
|
|
45
|
+
if not isinstance(pencil, tuple): pencil=tuple([pencil])
|
|
46
|
+
self.penLength = len(pencil)
|
|
47
|
+
self.fes = fes
|
|
48
|
+
self.nev = nev
|
|
49
|
+
self.ncv = ncv
|
|
50
|
+
self.solverParameters = solverParameters
|
|
51
|
+
self.optionsPrefix = optionsPrefix
|
|
52
|
+
options_object = PETSc.Options()
|
|
53
|
+
if solverParameters is not None:
|
|
54
|
+
for optName, optValue in self.solverParameters.items():
|
|
55
|
+
options_object[optName] = optValue
|
|
56
|
+
|
|
57
|
+
self.pencilMats = []
|
|
58
|
+
self.pencilFlags = []
|
|
59
|
+
for a in pencil:
|
|
60
|
+
self.pencilFlags += [a.flags.ToDict()]
|
|
61
|
+
self.pencilMats += [Matrix(a.Assemble().mat, fes).mat]
|
|
62
|
+
self.pencilMats[-1].setOptionsPrefix(self.optionsPrefix)
|
|
63
|
+
self.pencilMats[-1].setFromOptions()
|
|
64
|
+
self.eps = None
|
|
65
|
+
self.pep = None
|
|
66
|
+
if self.penLength > 2:
|
|
67
|
+
self.isEPS = False
|
|
68
|
+
else:
|
|
69
|
+
self.isEPS = True
|
|
70
|
+
self.setUpEPS()
|
|
71
|
+
|
|
72
|
+
def setUpEPS(self):
|
|
73
|
+
'''
|
|
74
|
+
This function setup a SLEPc EPS if the pencil has shape either (m,a)
|
|
75
|
+
or is simply a single matrix.
|
|
76
|
+
'''
|
|
77
|
+
self.eps = SLEPc.EPS().create()
|
|
78
|
+
self.eps.setType(SLEPc.EPS.Type.KRYLOVSCHUR)
|
|
79
|
+
if self.penLength == 1:
|
|
80
|
+
flag0 = self.pencilFlags[0]
|
|
81
|
+
if "symmetric" in flag0.keys():
|
|
82
|
+
if flag0["symmetric"]:
|
|
83
|
+
self.eps.setProblemType(SLEPc.EPS.ProblemType.HEP)
|
|
84
|
+
else:
|
|
85
|
+
self.eps.setProblemType(SLEPc.EPS.ProblemType.NHEP)
|
|
86
|
+
else:
|
|
87
|
+
self.eps.setProblemType(SLEPc.EPS.ProblemType.NHEP)
|
|
88
|
+
self.eps.setOperators(self.pencilMats[0])
|
|
89
|
+
else:
|
|
90
|
+
flag0 = self.pencilFlags[0]
|
|
91
|
+
flag1 = self.pencilFlags[1]
|
|
92
|
+
if "symmetric" in flag0.keys() and "symmetric" in flag1.keys():
|
|
93
|
+
if flag0["symmetric"] and flag1["symmetric"]:
|
|
94
|
+
self.eps.setProblemType(SLEPc.EPS.ProblemType.GHEP)
|
|
95
|
+
else:
|
|
96
|
+
self.eps.setProblemType(SLEPc.EPS.ProblemType.GNHEP)
|
|
97
|
+
else:
|
|
98
|
+
self.eps.setProblemType(SLEPc.EPS.ProblemType.GNHEP)
|
|
99
|
+
self.pencilMats[0].scale(-1)
|
|
100
|
+
self.eps.setOperators(self.pencilMats[1], self.pencilMats[0])
|
|
101
|
+
self.eps.setDimensions(self.nev, self.ncv)
|
|
102
|
+
self.eps.setOptionsPrefix(self.optionsPrefix)
|
|
103
|
+
self.eps.setFromOptions()
|
|
104
|
+
|
|
105
|
+
def solve(self):
|
|
106
|
+
'''
|
|
107
|
+
This function solve the eigenprobelm
|
|
108
|
+
'''
|
|
109
|
+
self.eps.solve()
|
|
110
|
+
self.nconv = self.eps.getConverged()
|
|
111
|
+
if self.nconv == 0:
|
|
112
|
+
raise RuntimeError("Did not converge any eigenvalues.")
|
|
113
|
+
return self.nconv
|
|
114
|
+
|
|
115
|
+
def view(self):
|
|
116
|
+
'''
|
|
117
|
+
This function setup display the information about SLEPc EPS/PEP
|
|
118
|
+
'''
|
|
119
|
+
self.eps.view()
|
|
120
|
+
|
|
121
|
+
def eigenValue(self, i):
|
|
122
|
+
'''
|
|
123
|
+
This function return the eigenvalue of the eigenproblem
|
|
124
|
+
|
|
125
|
+
:arg i: index of the eigenvalue we are intrested in.
|
|
126
|
+
|
|
127
|
+
'''
|
|
128
|
+
lam = None
|
|
129
|
+
if self.isEPS:
|
|
130
|
+
lam = self.eps.getEigenvalue(i)
|
|
131
|
+
return lam
|
|
132
|
+
|
|
133
|
+
def eigenFunction(self, i):
|
|
134
|
+
'''
|
|
135
|
+
This function return the eigenfunction of the eigenproblem
|
|
136
|
+
|
|
137
|
+
:arg i: index of the eigenfunction we are intrested in.
|
|
138
|
+
|
|
139
|
+
'''
|
|
140
|
+
self.vecMap = VectorMapping(self.fes)
|
|
141
|
+
eigenModeReal = GridFunction(self.fes)
|
|
142
|
+
eigenModeImag = GridFunction(self.fes)
|
|
143
|
+
eignModePETScReal = self.pencilMats[0].createVecLeft()
|
|
144
|
+
eignModePETScImag = self.pencilMats[0].createVecLeft()
|
|
145
|
+
if self.isEPS:
|
|
146
|
+
self.eps.getEigenvector(i, eignModePETScReal, eignModePETScImag)
|
|
147
|
+
self.vecMap.ngsVec(eignModePETScReal,eigenModeReal.vec)
|
|
148
|
+
self.vecMap.ngsVec(eignModePETScImag,eigenModeImag.vec)
|
|
149
|
+
return eigenModeReal, eigenModeImag
|
|
150
|
+
|
|
151
|
+
def eigenValues(self, indeces):
|
|
152
|
+
'''
|
|
153
|
+
This function return the eigenvalues of the eigenproblem
|
|
154
|
+
|
|
155
|
+
:arg indeces: indeces of the eigenvalues we are intrested in.
|
|
156
|
+
|
|
157
|
+
'''
|
|
158
|
+
lams = []
|
|
159
|
+
if self.isEPS:
|
|
160
|
+
for i in indeces:
|
|
161
|
+
lams = lams + [self.eps.getEigenvalue(i)]
|
|
162
|
+
return lams
|
|
163
|
+
|
|
164
|
+
def eigenFunctions(self, indeces):
|
|
165
|
+
'''
|
|
166
|
+
This function return a multidim with
|
|
167
|
+
the eigenfunctions of the eigenproblem
|
|
168
|
+
|
|
169
|
+
:arg indeces: indeces of the eigenfunctions we are intrested in.
|
|
170
|
+
|
|
171
|
+
'''
|
|
172
|
+
self.vecMap = VectorMapping(self.fes)
|
|
173
|
+
eigenModesReal = GridFunction(self.fes, multidim=self.nev)
|
|
174
|
+
eigenModesImag = GridFunction(self.fes, multidim=self.nev)
|
|
175
|
+
k = 0
|
|
176
|
+
eignModePETScReal = self.pencilMats[0].createVecLeft()
|
|
177
|
+
eignModePETScImag = self.pencilMats[0].createVecLeft()
|
|
178
|
+
for i in indeces:
|
|
179
|
+
if self.isEPS:
|
|
180
|
+
self.eps.getEigenvector(i, eignModePETScReal, eignModePETScImag)
|
|
181
|
+
self.vecMap.ngsVec(eignModePETScReal,eigenModesReal.vecs[k])
|
|
182
|
+
self.vecMap.ngsVec(eignModePETScImag,eigenModesImag.vecs[k])
|
|
183
|
+
k += 1
|
|
184
|
+
return eigenModesReal, eigenModesImag
|
ngsPETSc/ksp.py
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
'''
|
|
2
|
+
This module contains all the functions related to the PETSc linear
|
|
3
|
+
system solver (KSP) interface for NGSolve
|
|
4
|
+
'''
|
|
5
|
+
from petsc4py import PETSc
|
|
6
|
+
from ngsolve import la, BilinearForm, FESpace, BitArray, Projector
|
|
7
|
+
from ngsPETSc import Matrix, VectorMapping, PETScPreconditioner, NullSpace
|
|
8
|
+
|
|
9
|
+
def createFromBilinearForm(a, freeDofs, solverParameters):
|
|
10
|
+
"""
|
|
11
|
+
This function creates a PETSc matrix from an NGSolve bilinear form
|
|
12
|
+
"""
|
|
13
|
+
a.Assemble()
|
|
14
|
+
#Setting deafult matrix type
|
|
15
|
+
if "ngs_mat_type" not in solverParameters:
|
|
16
|
+
solverParameters["ngs_mat_type"] = "aij"
|
|
17
|
+
#Assembling matrix if not of type Python
|
|
18
|
+
if solverParameters["ngs_mat_type"] not in ["python"]:
|
|
19
|
+
if hasattr(a.mat, "row_pardofs"):
|
|
20
|
+
dofs = a.mat.row_pardofs
|
|
21
|
+
else:
|
|
22
|
+
dofs = None
|
|
23
|
+
mat = Matrix(a.mat, (dofs, freeDofs, None), solverParameters["ngs_mat_type"])
|
|
24
|
+
return (a.mat, mat.mat)
|
|
25
|
+
raise ValueError("ngs_mat_type {} is not supported.".format(solverParameters["ngs_mat_type"]))
|
|
26
|
+
|
|
27
|
+
def createFromMatrix(a, freeDofs, solverParameters):
|
|
28
|
+
"""
|
|
29
|
+
This function creates a PETSc matrix from an NGSolve bilinear form
|
|
30
|
+
"""
|
|
31
|
+
#Setting deafult matrix type
|
|
32
|
+
if "ngs_mat_type" not in solverParameters:
|
|
33
|
+
solverParameters["ngs_mat_type"] = "aij"
|
|
34
|
+
#Assembling matrix if not of type Python
|
|
35
|
+
if solverParameters["ngs_mat_type"] not in ["python"]:
|
|
36
|
+
if hasattr(a, "row_pardofs"):
|
|
37
|
+
dofs = a.row_pardofs
|
|
38
|
+
else:
|
|
39
|
+
dofs = None
|
|
40
|
+
mat = Matrix(a, (dofs, freeDofs, None), solverParameters["ngs_mat_type"])
|
|
41
|
+
pscMat = mat.mat
|
|
42
|
+
return (a, pscMat)
|
|
43
|
+
if solverParameters["ngs_mat_type"] == "python":
|
|
44
|
+
_, pscMat = createFromAction(a, freeDofs, solverParameters)
|
|
45
|
+
return (a, pscMat)
|
|
46
|
+
raise ValueError("ngs_mat_type {} is not supported.".format(solverParameters["ngs_mat_type"]))
|
|
47
|
+
|
|
48
|
+
def createFromPC(a, freeDofs, solverParameters):
|
|
49
|
+
"""
|
|
50
|
+
This function creates a PETSc matrix from an ngsPETSc PETSc Preconditioner
|
|
51
|
+
"""
|
|
52
|
+
class Wrap(object):
|
|
53
|
+
"""
|
|
54
|
+
This class wraps a PETSc Preconditioner as PETSc Python matrix
|
|
55
|
+
"""
|
|
56
|
+
def __init__(self, a, dofs, freeDofs):
|
|
57
|
+
self.a = a
|
|
58
|
+
self.mapping = VectorMapping((dofs,freeDofs,{"bsize": [1]}))
|
|
59
|
+
self.ngX = a.CreateColVector()
|
|
60
|
+
self.ngY = a.CreateColVector()
|
|
61
|
+
if hasattr(a, "actingDofs"):
|
|
62
|
+
self.prj = Projector(mask=a.actingDofs, range=True)
|
|
63
|
+
else:
|
|
64
|
+
self.prj = Projector(mask=freeDofs, range=True)
|
|
65
|
+
|
|
66
|
+
def mult(self, mat, X, Y): #pylint: disable=W0613
|
|
67
|
+
"""
|
|
68
|
+
PETSc matrix-vector product
|
|
69
|
+
"""
|
|
70
|
+
self.mapping.ngsVec(X, (self.prj*self.ngX).Evaluate())
|
|
71
|
+
self.a.Mult(self.ngX, self.ngY)
|
|
72
|
+
self.mapping.petscVec((self.prj*self.ngY).Evaluate(), Y)
|
|
73
|
+
#Grabbing comm information
|
|
74
|
+
if hasattr(a, "row_pardofs"):
|
|
75
|
+
dofs = a.row_pardofs
|
|
76
|
+
comm = dofs.comm.mpi4py
|
|
77
|
+
elif "dofs" in solverParameters:
|
|
78
|
+
dofs = solverParameters["dofs"]
|
|
79
|
+
comm = dofs.comm.mpi4py
|
|
80
|
+
else:
|
|
81
|
+
dofs = None
|
|
82
|
+
comm = PETSc.COMM_SELF
|
|
83
|
+
pythonA = Wrap(a, dofs, freeDofs)
|
|
84
|
+
pscA = PETSc.Mat().create(comm=comm)
|
|
85
|
+
pscA.setSizes([sum(freeDofs), sum(freeDofs)])
|
|
86
|
+
pscA.setType("python")
|
|
87
|
+
pscA.setPythonContext(pythonA)
|
|
88
|
+
pscA.setUp()
|
|
89
|
+
return (a.ngsMat, pscA)
|
|
90
|
+
|
|
91
|
+
def createFromAction(a, freeDofs, solverParameters):
|
|
92
|
+
"""
|
|
93
|
+
This function creates a matrix free PETSc matrix from an NGSolve matrix
|
|
94
|
+
"""
|
|
95
|
+
class Wrap(object):
|
|
96
|
+
"""
|
|
97
|
+
This class wraps an NGSolve matrix as PETSc Python matrix
|
|
98
|
+
"""
|
|
99
|
+
def __init__(self, a, dofs, freeDofs, comm):
|
|
100
|
+
self.a = a
|
|
101
|
+
self.dofs = dofs
|
|
102
|
+
self.freeDofs = freeDofs
|
|
103
|
+
self.comm = comm
|
|
104
|
+
self.mapping = VectorMapping((dofs,freeDofs,{"bsize": (1,1)}))
|
|
105
|
+
self.ngX = a.CreateColVector()
|
|
106
|
+
self.ngY = a.CreateColVector()
|
|
107
|
+
|
|
108
|
+
def mult(self, mat, X, Y): #pylint: disable=W0613
|
|
109
|
+
"""
|
|
110
|
+
PETSc matrix-vector product
|
|
111
|
+
"""
|
|
112
|
+
self.mapping.ngsVec(X, self.ngX)
|
|
113
|
+
self.a.Mult(self.ngX, self.ngY)
|
|
114
|
+
self.mapping.petscVec(self.ngY, Y)
|
|
115
|
+
|
|
116
|
+
if hasattr(a, "row_pardofs"):
|
|
117
|
+
dofs = a.row_pardofs
|
|
118
|
+
comm = dofs.comm.mpi4py
|
|
119
|
+
entrysize = a.local_mat.entrysizes[0]
|
|
120
|
+
_, rnumberGlobal = dofs.EnumerateGlobally(freeDofs) #samrc
|
|
121
|
+
elif "dofs" in solverParameters:
|
|
122
|
+
dofs = solverParameters["dofs"]
|
|
123
|
+
comm = dofs.comm.mpi4py
|
|
124
|
+
entrysize = dofs.entrysize
|
|
125
|
+
_, rnumberGlobal = dofs.EnumerateGlobally(freeDofs) #samrc
|
|
126
|
+
else:
|
|
127
|
+
dofs = None
|
|
128
|
+
comm = PETSc.COMM_SELF
|
|
129
|
+
entrysize = 1
|
|
130
|
+
rnumberGlobal = sum(freeDofs)
|
|
131
|
+
pythonA = Wrap(a, dofs, freeDofs, comm)
|
|
132
|
+
pscA = PETSc.Mat().create(comm=comm)
|
|
133
|
+
pscA.setSizes(size=(rnumberGlobal*entrysize,
|
|
134
|
+
rnumberGlobal*entrysize), bsize=entrysize)
|
|
135
|
+
pscA.setType("python")
|
|
136
|
+
pscA.setPythonContext(pythonA)
|
|
137
|
+
pscA.setUp()
|
|
138
|
+
return (a, pscA)
|
|
139
|
+
|
|
140
|
+
parse = {BilinearForm: createFromBilinearForm,
|
|
141
|
+
la.SparseMatrixd: createFromMatrix,
|
|
142
|
+
la.ParallelMatrix: createFromMatrix,
|
|
143
|
+
PETScPreconditioner: createFromPC,
|
|
144
|
+
la.BaseMatrix: createFromAction}
|
|
145
|
+
|
|
146
|
+
class KrylovSolver():
|
|
147
|
+
"""
|
|
148
|
+
This class creates a PETSc Krylov Solver (KSP) for NGSolve.
|
|
149
|
+
Inspired by Firedrake linear solver class.
|
|
150
|
+
|
|
151
|
+
:arg a: either the bilinear form, ngs Matrix or a petsc4py matrix
|
|
152
|
+
|
|
153
|
+
:arg dofsDescr: either finite element space
|
|
154
|
+
|
|
155
|
+
:arg p: either the bilinear form, ngs Matrix or petsc4py matrix actin as a preconditioner
|
|
156
|
+
|
|
157
|
+
:arg nullspace: either a PETSc NullSpace or ngsPETSc PETSc Preconditioner
|
|
158
|
+
or touple of ngsPETSc PETSc Preconditioner.
|
|
159
|
+
|
|
160
|
+
:arg solverParameters: parameters to be passed to the KS P solver
|
|
161
|
+
|
|
162
|
+
:arg optionsPrefix: special solver options prefix for this specific Krylov solver
|
|
163
|
+
|
|
164
|
+
"""
|
|
165
|
+
def __init__(self, a, dofsDescr, p=None, nullspace=None, optionsPrefix="",
|
|
166
|
+
solverParameters={}):
|
|
167
|
+
# Grabbing dofs information
|
|
168
|
+
if isinstance(dofsDescr, FESpace):
|
|
169
|
+
freeDofs = dofsDescr.FreeDofs()
|
|
170
|
+
elif isinstance(dofsDescr, BitArray):
|
|
171
|
+
freeDofs = dofsDescr
|
|
172
|
+
else:
|
|
173
|
+
raise ValueError("dofsDescr must be either FESpace or BitArray")
|
|
174
|
+
#Construct operator
|
|
175
|
+
pscA = None
|
|
176
|
+
for key in parse: #pylint: disable=C0206
|
|
177
|
+
if isinstance(a, key):
|
|
178
|
+
ngsA, pscA = parse[key](a, freeDofs, solverParameters)
|
|
179
|
+
if pscA is None:
|
|
180
|
+
raise ValueError("a of type {} not supported.".format(type(a)))
|
|
181
|
+
if p is not None:
|
|
182
|
+
for key in parse: #pylint: disable=C0206
|
|
183
|
+
if isinstance(p, key):
|
|
184
|
+
if hasattr(ngsA, "row_pardofs"):
|
|
185
|
+
solverParameters["dofs"] = ngsA.row_pardofs
|
|
186
|
+
_, pscP = parse[key](p, freeDofs, solverParameters)
|
|
187
|
+
break
|
|
188
|
+
else:
|
|
189
|
+
pscP = pscA
|
|
190
|
+
#Construct vector mapping
|
|
191
|
+
if hasattr(ngsA, "row_pardofs"):
|
|
192
|
+
dofs = ngsA.row_pardofs
|
|
193
|
+
else:
|
|
194
|
+
dofs = None
|
|
195
|
+
if hasattr(ngsA.local_mat, "entrysizes"):
|
|
196
|
+
entrysize = ngsA.local_mat.entrysizes
|
|
197
|
+
else:
|
|
198
|
+
entrysize = [1]
|
|
199
|
+
self.mapping = VectorMapping((dofs,freeDofs,{"bsize":entrysize}))
|
|
200
|
+
#Fixing PETSc options
|
|
201
|
+
options_object = PETSc.Options()
|
|
202
|
+
for optName, optValue in solverParameters.items():
|
|
203
|
+
options_object[optName] = optValue
|
|
204
|
+
|
|
205
|
+
#Setting PETSc Options
|
|
206
|
+
pscA.setOptionsPrefix(optionsPrefix)
|
|
207
|
+
pscA.setFromOptions()
|
|
208
|
+
|
|
209
|
+
#Setting up nullspace
|
|
210
|
+
if nullspace is not None:
|
|
211
|
+
if isinstance(nullspace, (list, tuple)):
|
|
212
|
+
for ns in nullspace:
|
|
213
|
+
if isinstance(ns, PETSc.NullSpace):
|
|
214
|
+
pscA.setNullSpace(ns)
|
|
215
|
+
elif isinstance(ns, NullSpace):
|
|
216
|
+
if ns.near:
|
|
217
|
+
pscA.setNearNullSpace(ns.nullspace)
|
|
218
|
+
else:
|
|
219
|
+
pscA.setNullSpace(ns.nullspace)
|
|
220
|
+
else:
|
|
221
|
+
raise ValueError("nullspace must be either \
|
|
222
|
+
PETSc.NullSpace or NullSpace")
|
|
223
|
+
if isinstance(nullspace, PETSc.NullSpace):
|
|
224
|
+
pscA.setNullSpace(nullspace)
|
|
225
|
+
elif isinstance(nullspace, NullSpace):
|
|
226
|
+
if nullspace.near:
|
|
227
|
+
pscA.setNearNullSpace(nullspace.nullspace)
|
|
228
|
+
else:
|
|
229
|
+
pscA.setNullSpace(nullspace.nullspace)
|
|
230
|
+
else:
|
|
231
|
+
raise ValueError("nullspace must be either \
|
|
232
|
+
PETSc.NullSpace or NullSpace")
|
|
233
|
+
|
|
234
|
+
#Setting up KSP
|
|
235
|
+
self.ksp = PETSc.KSP().create(comm=pscA.getComm())
|
|
236
|
+
self.ksp.setOperators(A=pscA, P=pscP)
|
|
237
|
+
self.ksp.setOptionsPrefix(optionsPrefix)
|
|
238
|
+
self.ksp.setFromOptions()
|
|
239
|
+
self.pscX, self.pscB = pscA.createVecs()
|
|
240
|
+
|
|
241
|
+
#Attaching operator
|
|
242
|
+
self.ngsA = ngsA
|
|
243
|
+
|
|
244
|
+
def solve(self, b, x, mapping=None):
|
|
245
|
+
"""
|
|
246
|
+
This function solves the linear system
|
|
247
|
+
|
|
248
|
+
:arg b: right hand side of the linear system
|
|
249
|
+
:arg x: solution of the linear system
|
|
250
|
+
"""
|
|
251
|
+
if mapping is None:
|
|
252
|
+
mapping = self.mapping
|
|
253
|
+
mapping.petscVec(x, self.pscX)
|
|
254
|
+
mapping.petscVec(b, self.pscB)
|
|
255
|
+
self.ksp.solve(self.pscB, self.pscX)
|
|
256
|
+
mapping.ngsVec(self.pscX, x)
|
|
257
|
+
|
|
258
|
+
def operator(self):
|
|
259
|
+
"""
|
|
260
|
+
This function returns the operator of the KSP solver
|
|
261
|
+
"""
|
|
262
|
+
return KSPOpeator(self)
|
|
263
|
+
|
|
264
|
+
class KSPOpeator(la.BaseMatrix):
|
|
265
|
+
"""
|
|
266
|
+
This class wraps a PETSc KSP solver as an NGSolve matrix
|
|
267
|
+
"""
|
|
268
|
+
def __init__(self, ksp):
|
|
269
|
+
la.BaseMatrix.__init__(self)
|
|
270
|
+
self.ksp = ksp
|
|
271
|
+
|
|
272
|
+
def Shape(self):
|
|
273
|
+
'''
|
|
274
|
+
Shape of the BaseMatrix
|
|
275
|
+
|
|
276
|
+
'''
|
|
277
|
+
return self.ksp.ngsA.shape
|
|
278
|
+
|
|
279
|
+
def CreateVector(self,col):
|
|
280
|
+
'''
|
|
281
|
+
Create vector corresponding to the matrix
|
|
282
|
+
|
|
283
|
+
:arg col: True if one want a column vector
|
|
284
|
+
|
|
285
|
+
'''
|
|
286
|
+
return self.ksp.ngsA.CreateVector(not col)
|
|
287
|
+
|
|
288
|
+
def Mult(self, x, y):
|
|
289
|
+
"""
|
|
290
|
+
Matrix-vector product
|
|
291
|
+
"""
|
|
292
|
+
self.ksp.solve(x, y)
|
ngsPETSc/mat.py
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
'''
|
|
2
|
+
This module contains all the functions related to wrapping NGSolve matrices to
|
|
3
|
+
PETSc matrices using the petsc4py interface.
|
|
4
|
+
'''
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from ngsolve import FESpace
|
|
8
|
+
from petsc4py import PETSc
|
|
9
|
+
|
|
10
|
+
class Matrix(object):
|
|
11
|
+
'''
|
|
12
|
+
This class creates a PETSc Matrix
|
|
13
|
+
|
|
14
|
+
:arg ngsMat: the NGSolve matrix
|
|
15
|
+
|
|
16
|
+
:arg freeDofs: free DOFs of the FE spaces used to construct the matrix
|
|
17
|
+
|
|
18
|
+
:arg matType: type of PETSc matrix, i.e. PETSc sparse: aij,
|
|
19
|
+
MKL sparse: aijmkl or CUDA: aijcusparse
|
|
20
|
+
|
|
21
|
+
'''
|
|
22
|
+
def __init__(self, ngsMat, parDescr, matType="aij", petscMat=None):
|
|
23
|
+
if not isinstance(parDescr, (tuple, list)):
|
|
24
|
+
samerc = True
|
|
25
|
+
if isinstance(parDescr, FESpace):
|
|
26
|
+
dofs = parDescr.ParallelDofs()
|
|
27
|
+
self.freeDofs = (parDescr.FreeDofs(),parDescr.FreeDofs())
|
|
28
|
+
comm = dofs.comm.mpi4py
|
|
29
|
+
else:
|
|
30
|
+
dofs, freeDofs, dofsInfo = parDescr
|
|
31
|
+
self.freeDofs = (freeDofs,freeDofs)
|
|
32
|
+
if dofs is not None:
|
|
33
|
+
comm = dofs.comm.mpi4py
|
|
34
|
+
else:
|
|
35
|
+
### create suitable dofs
|
|
36
|
+
comm = PETSc.COMM_SELF
|
|
37
|
+
dofs = type('', (object,), {'entrysize':dofsInfo["bsize"][0]})()
|
|
38
|
+
else:
|
|
39
|
+
samerc = False
|
|
40
|
+
if isinstance(parDescr[0], FESpace) and isinstance(parDescr[1], FESpace):
|
|
41
|
+
dofs = parDescr[0].ParallelDofs()
|
|
42
|
+
self.freeDofs = (parDescr[0].FreeDofs(),parDescr[1].FreeDofs())
|
|
43
|
+
comm = dofs.comm.mpi4py
|
|
44
|
+
elif isinstance(parDescr[0], (tuple, list)):
|
|
45
|
+
dofs = parDescr[0][0]
|
|
46
|
+
self.freeDofs = (parDescr[0][1], parDescr[1][1])
|
|
47
|
+
if dofs is not None:
|
|
48
|
+
comm = dofs.comm.mpi4py
|
|
49
|
+
else:
|
|
50
|
+
### create suitable dofs
|
|
51
|
+
comm = PETSc.COMM_SELF
|
|
52
|
+
else:
|
|
53
|
+
samerc = True
|
|
54
|
+
dofs = parDescr[0]
|
|
55
|
+
self.freeDofs = (parDescr[1], parDescr[1])
|
|
56
|
+
if dofs is not None:
|
|
57
|
+
comm = dofs.comm.mpi4py
|
|
58
|
+
else:
|
|
59
|
+
### create suitable dofs
|
|
60
|
+
comm = PETSc.COMM_SELF
|
|
61
|
+
|
|
62
|
+
localMat = ngsMat.local_mat
|
|
63
|
+
entryHeight, entryWidth = localMat.entrysizes
|
|
64
|
+
if entryHeight != entryWidth: raise RuntimeError ("Only square entries are allowed.")
|
|
65
|
+
|
|
66
|
+
valMat, colMat, indMat = localMat.CSR()
|
|
67
|
+
indMat = np.array(indMat).astype(PETSc.IntType)
|
|
68
|
+
colMat = np.array(colMat).astype(PETSc.IntType)
|
|
69
|
+
if entryHeight > 1:
|
|
70
|
+
petscLocalMat = PETSc.Mat().createBAIJ(size=(entryHeight*localMat.height,
|
|
71
|
+
entryWidth*localMat.width),
|
|
72
|
+
bsize=entryHeight,
|
|
73
|
+
csr=(indMat,colMat,valMat),
|
|
74
|
+
comm=PETSc.COMM_SELF)
|
|
75
|
+
else:
|
|
76
|
+
petscLocalMat = PETSc.Mat().createAIJ(size=(localMat.height,
|
|
77
|
+
localMat.width),
|
|
78
|
+
csr=(indMat,colMat,valMat),
|
|
79
|
+
comm=PETSc.COMM_SELF)
|
|
80
|
+
if self.freeDofs[0] is not None or self.freeDofs[1] is not None:
|
|
81
|
+
rowIsFreeLocal = None
|
|
82
|
+
if self.freeDofs[0] is not None:
|
|
83
|
+
rowLocalMatFree = np.flatnonzero(self.freeDofs[0]).astype(PETSc.IntType)
|
|
84
|
+
rowIsFreeLocal = PETSc.IS().createBlock(indices=rowLocalMatFree,
|
|
85
|
+
bsize=entryHeight,comm=PETSc.COMM_SELF)
|
|
86
|
+
colIsFreeLocal = rowIsFreeLocal
|
|
87
|
+
if self.freeDofs[1] is not None and not samerc:
|
|
88
|
+
colLocalMatFree = np.flatnonzero(self.freeDofs[1]).astype(PETSc.IntType)
|
|
89
|
+
colIsFreeLocal = PETSc.IS().createBlock(indices=colLocalMatFree,
|
|
90
|
+
bsize=entryHeight,comm=PETSc.COMM_SELF)
|
|
91
|
+
petscLocalMat = petscLocalMat.createSubMatrices(rowIsFreeLocal, colIsFreeLocal)[0]
|
|
92
|
+
|
|
93
|
+
if comm.Get_size() > 1:
|
|
94
|
+
# is this a BUG in the bindings?
|
|
95
|
+
#rparallelDofs = ngsMat.row_pardofs
|
|
96
|
+
rparallelDofs = ngsMat.col_pardofs
|
|
97
|
+
rglobalNums, rnumberGlobal = rparallelDofs.EnumerateGlobally(self.freeDofs[0])
|
|
98
|
+
if self.freeDofs[0] is not None:
|
|
99
|
+
rglobalNums = np.array(rglobalNums, dtype=PETSc.IntType)[self.freeDofs[0]]
|
|
100
|
+
rlocalGlobalMap = PETSc.LGMap().create(indices=rglobalNums,
|
|
101
|
+
bsize=entryHeight,
|
|
102
|
+
comm=comm)
|
|
103
|
+
if not samerc:
|
|
104
|
+
# is this a BUG in the bindings?
|
|
105
|
+
#cparallelDofs = ngsMat.col_pardofs
|
|
106
|
+
cparallelDofs = ngsMat.row_pardofs
|
|
107
|
+
cglobalNums, cnumberGlobal = cparallelDofs.EnumerateGlobally(self.freeDofs[1])
|
|
108
|
+
if self.freeDofs[1] is not None:
|
|
109
|
+
cglobalNums = np.array(cglobalNums, dtype=PETSc.IntType)[self.freeDofs[1]]
|
|
110
|
+
clocalGlobalMap = PETSc.LGMap().create(indices=cglobalNums,
|
|
111
|
+
bsize=entryWidth,
|
|
112
|
+
comm=comm)
|
|
113
|
+
else:
|
|
114
|
+
clocalGlobalMap = rlocalGlobalMap
|
|
115
|
+
cnumberGlobal = rnumberGlobal
|
|
116
|
+
|
|
117
|
+
mat = PETSc.Mat().create(comm=comm)
|
|
118
|
+
mat.setSizes(size=(rnumberGlobal*entryHeight,
|
|
119
|
+
cnumberGlobal*entryHeight), bsize=entryHeight)
|
|
120
|
+
mat.setType(PETSc.Mat.Type.IS)
|
|
121
|
+
mat.setLGMap(rlocalGlobalMap, clocalGlobalMap)
|
|
122
|
+
mat.setISLocalMat(petscLocalMat)
|
|
123
|
+
mat.assemble()
|
|
124
|
+
if matType != 'is':
|
|
125
|
+
mat.convert(matType)
|
|
126
|
+
if petscMat is None:
|
|
127
|
+
self.mat = mat
|
|
128
|
+
else:
|
|
129
|
+
mat.copy(petscMat)
|
|
130
|
+
else:
|
|
131
|
+
mat = petscLocalMat
|
|
132
|
+
mat.convert(matType)
|
|
133
|
+
if matType != 'is':
|
|
134
|
+
mat.convert(matType)
|
|
135
|
+
|
|
136
|
+
if petscMat is None:
|
|
137
|
+
self.mat = mat
|
|
138
|
+
else:
|
|
139
|
+
mat.copy(petscMat)
|
|
140
|
+
|
|
141
|
+
def view(self):
|
|
142
|
+
'''
|
|
143
|
+
This function display PETSc Mat info
|
|
144
|
+
|
|
145
|
+
'''
|
|
146
|
+
self.mat.view()
|