Ok, in case someone else arrives: the problem is that SNES moves function evaluation in the ‘x’ vector, whereas the residuals depend on ‘u’, so the solution is to update things correspondingly:
def F(self, snes, x, F):
x = PETScVector(x)
F = PETScVector(F)
x.vec().copy(self.u.vector().vec())
self.u.vector().apply("")
assemble(self.L, tensor=F)
for bc in self.bcs:
bc.apply(F, x)
bc.apply(F, self.u.vector())
def J(self, snes, x, J, P):
J = PETScMatrix(J)
x.copy(self.u.vector().vec())
self.u.vector().apply("")
assemble(self.a, tensor=J)
for bc in self.bcs:
bc.apply(J)
The ‘apply’ lines are required to update ghost dofs in parallel… you can actually remove that if your code will only be run in serial.
Best!