You can create a custom nonlinear problem instance that allows arbitrary code to execute while forming the residual and/or Jacobian. See the following example:
from dolfin import *
mesh = UnitSquareMesh(10,10)
V = FunctionSpace(mesh,"Lagrange",1)
u = Function(V)
v = TestFunction(V)
x = SpatialCoordinate(mesh)
f = x[0]*x[1]
res = (1.0+u*u)*inner(grad(u),grad(v))*dx + inner(u,v)*dx - inner(f,v)*dx
Dres = derivative(res,u)
class CustomNonlinearProblem(NonlinearProblem):
def F(self,b,x):
#########################################
print("Executing arbitrary Python code.")
#########################################
return assemble(res,tensor=b)
def J(self,A,x):
return assemble(Dres,tensor=A)
problem = CustomNonlinearProblem()
solver = PETScSNESSolver()
solver.solve(problem,u.vector())