ngsPETSc 0.0.7a7__tar.gz

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.
@@ -0,0 +1,10 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Umberto Zerbinati
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6
+ copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7
+
8
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9
+
10
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,54 @@
1
+ Metadata-Version: 2.1
2
+ Name: ngsPETSc
3
+ Version: 0.0.7a7
4
+ Summary: NGSolve/Netgen interface to PETSc
5
+ Home-page: https://github.com/NGSolve/ngsPETSc
6
+ License: MIT
7
+ Author: Umberto Zerbinati
8
+ Author-email: umberto.zerbinati@maths.ox.ac.uk
9
+ Maintainer: Umberto Zerbinati
10
+ Maintainer-email: umberto.zerbinati@maths.ox.ac.uk
11
+ Requires-Python: >=3.9,<4.0
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Requires-Dist: mpi4py (>=4,<5)
22
+ Requires-Dist: netgen-mesher (>=6.2,<7.0)
23
+ Requires-Dist: netgen-occt (>=7.8,<8.0)
24
+ Requires-Dist: numpy (>=2,<3)
25
+ Requires-Dist: petsc4py (>=3.22.1,<4.0.0)
26
+ Requires-Dist: scipy (>=1,<2)
27
+ Project-URL: Documentation, https://ngspetsc.readthedocs.io/en/latest/
28
+ Project-URL: Repository, https://github.com/NGSolve/ngsPETSc
29
+ Description-Content-Type: text/markdown
30
+
31
+ # ngsPETSc
32
+
33
+ ngsPETSc is an interface between PETSc and NGSolve/NETGEN that enables the use of NETGEN meshes and geometries in PETSc-based solvers while providing NGSolve users access to the wide array of linear, nonlinear solvers, and time-steppers available in PETSc.
34
+
35
+ [![ngsPETSc](https://github.com/UZerbinati/ngsPETSc/actions/workflows/ngsPETSc.yml/badge.svg)](https://github.com/UZerbinati/ngsPETSc/actions/workflows/ngsPETSc.yml)
36
+ [![Documentation Status](https://readthedocs.org/projects/ngspetsc/badge/?version=latest)](https://ngspetsc.readthedocs.io/en/latest/?badge=latest)
37
+
38
+ ## Installation
39
+ If you already have NGSolve (with MPI support) and PETSc installed, you can install ngsPETSc via pip:
40
+ ```bash
41
+
42
+ git clone https://github.com/UZerbinati/ngsPETSc.git
43
+ cd ngsPETSc
44
+ pip install .
45
+ ```
46
+ Alternatively, you can also build PETSc, SLEPc, and NGSolve from source following the instructions in the [documentation](https://ngspetsc.readthedocs.io/en/latest/installation.html).
47
+
48
+ ## Getting started
49
+
50
+ To get started with ngsPETSc, check out the [documentation](https://ngspetsc.readthedocs.io/en/latest/).
51
+ To test the installation, you can run the tests in the `tests` folder, via the Makefile in the root directory of the repository:
52
+ ```bash
53
+ make test
54
+ ```
@@ -0,0 +1,24 @@
1
+ # ngsPETSc
2
+
3
+ ngsPETSc is an interface between PETSc and NGSolve/NETGEN that enables the use of NETGEN meshes and geometries in PETSc-based solvers while providing NGSolve users access to the wide array of linear, nonlinear solvers, and time-steppers available in PETSc.
4
+
5
+ [![ngsPETSc](https://github.com/UZerbinati/ngsPETSc/actions/workflows/ngsPETSc.yml/badge.svg)](https://github.com/UZerbinati/ngsPETSc/actions/workflows/ngsPETSc.yml)
6
+ [![Documentation Status](https://readthedocs.org/projects/ngspetsc/badge/?version=latest)](https://ngspetsc.readthedocs.io/en/latest/?badge=latest)
7
+
8
+ ## Installation
9
+ If you already have NGSolve (with MPI support) and PETSc installed, you can install ngsPETSc via pip:
10
+ ```bash
11
+
12
+ git clone https://github.com/UZerbinati/ngsPETSc.git
13
+ cd ngsPETSc
14
+ pip install .
15
+ ```
16
+ Alternatively, you can also build PETSc, SLEPc, and NGSolve from source following the instructions in the [documentation](https://ngspetsc.readthedocs.io/en/latest/installation.html).
17
+
18
+ ## Getting started
19
+
20
+ To get started with ngsPETSc, check out the [documentation](https://ngspetsc.readthedocs.io/en/latest/).
21
+ To test the installation, you can run the tests in the `tests` folder, via the Makefile in the root directory of the repository:
22
+ ```bash
23
+ make test
24
+ ```
@@ -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"
@@ -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
@@ -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)