PETScUserPreconditioner does not work with PETScKrylovMatrix
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
DOLFIN |
Fix Released
|
Medium
|
Johan Hake |
Bug Description
There seems to be a problem with passing matrix-free preconditioners to PETSc: The combination of PETScKrylovMatrix and PETScUserPrecon
[0]PETSC ERROR: No support for this operation for this object type!
[0]PETSC ERROR: Matrix format shell does not have a built-in PETSc direct solver!
Here's a minimal example which triggers the error:
from dolfin import *
mesh = UnitSquare(32, 32)
V = FunctionSpace(mesh, 'CG', 1)
bc = DirichletBC(V, Constant(0.0), lambda x, on_boundary: on_boundary)
u = TrialFunction(V); v = TestFunction(V);
A, b = assemble_system( inner(grad(u), grad(v))*dx, Constant(1.0)*v*dx, bc)
class KrylovMatrix(
def __init__(self) :
def mult(self, *args) :
y = PETScVector(
class IdentityPrecond
def __init__(self) :
def solve(self, *args) :
y = Function(V)
solve(A,
x_petsc = PETScVector(
MyPrecon = IdentityPrecond
KrylovSolver = PETScKrylovSolv
KrylovSolver.
KrylovSolver.
Changed in dolfin: | |
status: | New → Confirmed |
Changed in dolfin: | |
importance: | Undecided → Medium |
Changed in dolfin: | |
milestone: | none → 0.9.12 |
Changed in dolfin: | |
assignee: | nobody → Garth Wells (garth-wells) |
Changed in dolfin: | |
milestone: | 1.0-beta → 1.0-rc1 |
Changed in dolfin: | |
assignee: | Garth Wells (garth-wells) → nobody |
Changed in dolfin: | |
milestone: | 1.0-rc1 → 1.1.0 |
Changed in dolfin: | |
status: | In Progress → Fix Released |
Changed in dolfin: | |
status: | Fix Released → Fix Committed |
Changed in dolfin: | |
status: | Fix Committed → Fix Released |
Hi,
I came to care about matrix-free in Dolfin, so I decided to have a look at this problem.
The basic problem with the current trunk is obvious from the traceback at the end of the error message:
[0]PETSC ERROR: MatGetFactor() line 3644 in src/mat/ interface/ matrix. c pc/impls/ factor/ ilu/ilu. c pc/interface/ precon. c
[0]PETSC ERROR: PCSetUp_ILU() line 202 in src/ksp/
[0]PETSC ERROR: PCSetUp() line 795 in src/ksp/
It's in PCSetUp_ILU, but we have told PETScKrylovSolver to use our supplied preconditioner; clearly that's not being registered. Taking a look at dolfin/ la/PETScKrylovS olver.cpp, the constructor that takes in a PETScUserPrecon ditioner assigns it to pc_dolfin, but pc_dolfin is never used again. However, with this patch:
####### ####### ###### 1.0.0-orig/ /dolfin/ la/PETScKrylovS olver.cpp dolfin- 1.0.0// dolfin/ la/PETScKrylovS olver.cpp 1.0.0-orig/ /dolfin/ la/PETScKrylovS olver.cpp 2012-01-28 18:16:39.181840758 +0000 1.0.0// dolfin/ la/PETScKrylovS olver.cpp 2012-01-28 18:17:13.392732888 +0000 oner->set( *this); oner_set = true; _set) ditioner: :setup( *_ksp, *pc_dolfin);
diff -urN dolfin-
--- dolfin-
+++ dolfin-
@@ -243,6 +243,11 @@
preconditi
preconditi
}
+ else if (pc_dolfin && !preconditioner
+ {
+ PETScUserPrecon
+ preconditioner_set = true;
+ }
// Solve linear system number( ) == 0) ####### ######
if (MPI::process_
#######
the user preconditioner is registered, and it goes into the solve method defined in Python in the example above. However, the solve method as written gives a strange error
args[ 0].set_ local(args[ 1])
TypeError: contiguous numpy array of 'double' expected. Make sure that the numpy array is contiguous and uses dtype='d'.
so I replaced it with
####### ####### ######
from dolfin import *
mesh = UnitSquare(32, 32)
V = FunctionSpace(mesh, 'CG', 1)
bc = DirichletBC(V, Constant(0.0), lambda x, on_boundary: on_boundary)
u = TrialFunction(V); v = TestFunction(V);
A, b = assemble_system( inner(grad(u), grad(v))*dx, Constant(1.0)*v*dx, bc)
class KrylovMatrix( PETScKrylovMatr ix) :
PETScKrylovMat rix.__init_ _(self, V.dim(), V.dim())
def __init__(self) :
def mult(self, *args) : V.dim() )
A.mult( args[0] ,y)
args[1] .set_local( y.array( ))
y = PETScVector(
class IdentityPrecond itioner( PETScUserPrecon ditioner) :
PETScUserPreco nditioner. __init_ _(self)
def __init__(self) :
def solve(self, *args) : args[0] )):
args[ 0][i] = args[1][i]
for i in range(len(
y = Function(V) y.vector( ),b) V.dim() )
solve(A,
x_petsc = PETScVector(
MyPrecon = IdentityPrecond itioner( ) er("cg" , MyPrecon)
KrylovSolver = PETScKrylovSolv
KrylovSolver. solve(KrylovMat rix(), x_petsc, down_cast(b)) solve(A, x_petsc, down_cast(b)) # works
#KrylovSolver.
print (x_petsc - y.vector( )).norm( "l2") ####### ######
#######
which now works:
[pef@aislinn: ~/src/dolfin/ userpc] $ python userpc.py
5.01929900219e-13