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
[0]PETSC ERROR: PCSetUp_ILU() line 202 in src/ksp/pc/impls/factor/ilu/ilu.c
[0]PETSC ERROR: PCSetUp() line 795 in src/ksp/pc/interface/precon.c
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/PETScKrylovSolver.cpp, the constructor that takes in a PETScUserPreconditioner assigns it to pc_dolfin, but pc_dolfin is never used again. However, with this patch:
// Solve linear system
if (MPI::process_number() == 0)
####################
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(PETScKrylovMatrix) :
def __init__(self) : PETScKrylovMatrix.__init__(self, V.dim(), V.dim())
def mult(self, *args) :
y = PETScVector(V.dim()) A.mult(args[0],y) args[1].set_local(y.array())
class IdentityPreconditioner(PETScUserPreconditioner) :
def __init__(self) : PETScUserPreconditioner.__init__(self)
def solve(self, *args) :
for i in range(len(args[0])): args[0][i] = args[1][i]
y = Function(V)
solve(A,y.vector(),b)
x_petsc = PETScVector(V.dim())
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