How to use `NewtonSolver` instead of `NonlinearVariationalSolver`?

Hello, all!

Is it possible to explicitly re-create the functionality of NonlinearVariationalSolver using NewtonSolver in fenics (dolfin version 2019.1.0)?

I’ve attempted to apply this example to set a NewtonSolver for the nonlinear Poisson demo as follows:

from dolfin import *

class Problem(NonlinearProblem):
   def __init__(self, J, F, bcs):
       self.bilinear_form = J
       self.linear_form = F
       self.bcs = bcs
       NonlinearProblem.__init__(self)

   def F(self, b, x):
       assemble(self.linear_form, b)
       for bc in self.bcs:
           bc.apply(b, x)

   def J(self, A, x):
       assemble(self.bilinear_form, A)
       for bc in self.bcs:
           bc.apply(A)

mesh = UnitSquareMesh(32, 32)

V = FunctionSpace(mesh, "CG", 1)
g = Constant(1.0)
bcs = [DirichletBC(V, g, "near(x[0], 1.0) and on_boundary")]
u = Function(V)
v = TestFunction(V)
f = Expression("x[0]*sin(x[1])", degree=2)
F = inner((1 + u**2)*grad(u), grad(v))*dx - f*v*dx
J = derivative(F, u)

problem = Problem(J, F, bcs)
custom_solver = NewtonSolver()
custom_solver.solve(problem, u.vector())

Running the script produces:

Newton iteration 0: r (abs) = 5.745e+00 (tol = 1.000e-10) r (rel) = 1.000e+00 (tol = 1.000e-09)
Newton iteration 1: r (abs) = 9.035e-03 (tol = 1.000e-10) r (rel) = 1.573e-03 (tol = 1.000e-09)
Newton iteration 2: r (abs) = 2.718e-04 (tol = 1.000e-10) r (rel) = 4.732e-05 (tol = 1.000e-09)
Newton iteration 3: r (abs) = 1.267e-07 (tol = 1.000e-10) r (rel) = 2.205e-08 (tol = 1.000e-09)
Newton iteration 4: r (abs) = 3.773e-14 (tol = 1.000e-10) r (rel) = 6.568e-15 (tol = 1.000e-09)
Newton solver finished in 4 iterations and 4 linear solver iterations.

whereas the use of NonlinearVariationalSolver as:

problem = NonlinearVariationalProblem(F, u, bcs, J)
solver = NonlinearVariationalSolver(problem)
solver.solve()

results in different residuals during iterations:

Solving nonlinear variational problem.
  Newton iteration 0: r (abs) = 1.776e+01 (tol = 1.000e-10) r (rel) = 1.000e+00 (tol = 1.000e-09)
  Newton iteration 1: r (abs) = 9.035e-03 (tol = 1.000e-10) r (rel) = 5.087e-04 (tol = 1.000e-09)
  Newton iteration 2: r (abs) = 2.718e-04 (tol = 1.000e-10) r (rel) = 1.530e-05 (tol = 1.000e-09)
  Newton iteration 3: r (abs) = 1.267e-07 (tol = 1.000e-10) r (rel) = 7.130e-09 (tol = 1.000e-09)
  Newton iteration 4: r (abs) = 3.773e-14 (tol = 1.000e-10) r (rel) = 2.124e-15 (tol = 1.000e-09)
  Newton solver finished in 4 iterations and 4 linear solver iterations.

I would suggest you have a look at: Bitbucket
as it describes how J and F is created in the nonlinear-variational solver.

Note that there is only a difference in the 0th iteration.

2 Likes

Thank you @dokken!

The solution is simply to assemble with SystemAssembler.