Nonlinear solver not working properly

Hi, I am trying to apply fem analysis on a 1d nonlinear timoshenko spatial beam, where there is 9 dofs. I tried to implement in the following way

from dolfinx import log, default_scalar_type
from dolfinx.fem.petsc import NonlinearProblem
from dolfinx.nls.petsc import NewtonSolver
import pyvista
import numpy as np
import ufl
from basix.ufl import element, mixed_element
from dolfinx import fem, io, mesh
from ufl import (Measure, SpatialCoordinate, TestFunctions, TrialFunctions, div, exp, inner, grad)
from mpi4py import MPI
from dolfinx import fem, mesh, plot
L = 1.0
points = np.array([[0.0, 0.0, 0.0], [L, 0.0, 0.0]])
# Create a 1D mesh for the beam
beam_mesh = mesh.create_interval(MPI.COMM_WORLD, 5, points[:,0])

displacement1 = element("Lagrange", beam_mesh.basix_cell(), degree=1)
displacement2 = element("Lagrange", beam_mesh.basix_cell(), degree=1)
displacement3 = element("Lagrange", beam_mesh.basix_cell(), degree=1)
curvature1 = element("Lagrange", beam_mesh.basix_cell(), degree=1)
curvature2 = element("Lagrange", beam_mesh.basix_cell(), degree=1)
curvature3 = element("Lagrange", beam_mesh.basix_cell(), degree=1)
rotation1 = element("Lagrange", beam_mesh.basix_cell(), degree=1)
rotation2 = element("Lagrange", beam_mesh.basix_cell(), degree=1)
rotation3 = element("Lagrange", beam_mesh.basix_cell(), degree=1)

element = mixed_element([displacement1, displacement2, displacement3, curvature1, curvature2, curvature3, rotation1, rotation2, rotation3])
#defining functionspace

V = fem.functionspace(beam_mesh, element)

#define functions for displacements

#u = fem.Function(V)
(z1, z2, z3, k1, k2, k3, p1, p2, p3) = TrialFunctions(V)
(u1, u2, u3, v1, v2, v3, w1, w2, w3) = TestFunctions(V)

x = SpatialCoordinate(beam_mesh)

G = fem.Constant(beam_mesh, 2.50e9)
A = fem.Constant(beam_mesh, 1.0e-6)
K_s = fem.Constant(beam_mesh, 0.851)
E = fem.Constant(beam_mesh, 200e9)
P = fem.Constant(beam_mesh, -10.0)
G = fem.Constant(beam_mesh, 75e9)

dx = Measure("dx", beam_mesh)





#domain = mesh.create_box(MPI.COMM_WORLD, [[0.0, 0.0, 0.0], [L, 0.001, 0.001]], [5, 1, 1], mesh.CellType.hexahedron)
#V = fem.functionspace(domain, ("Lagrange", 2, (domain.geometry.dim, )))

# several derivatives with respect to x, y, z
dz1_dx = grad(z1)[0]
du1_dx = grad(u1)[0]

strain_11 = dz1_dx + 0.5 * (dz1_dx)**2
strain_12 = 0.5 * p2
strain_13 = 0.5 * p3

del_strain11 = du1_dx + 0.5 * (du1_dx)**2
del_strain12 = 0.5 * w2
del_strain13 = 0.5 * w3

stress_11 = E * strain_11
stress_12 = G * strain_12
stress_13 = G * strain_13

a = inner(del_strain11, stress_11) * dx + inner(del_strain12, stress_12) * dx + inner(del_strain13, stress_13) * dx

#Next, we define the body force on the reference configuration (B), and nominal traction (T).

B = fem.Constant(beam_mesh, default_scalar_type((0, 0, 0)))
T = fem.Constant(beam_mesh, default_scalar_type((0, 0, 0)))


# Function returning True for points on the left boundary
def left_end(x):
    return np.isclose(x[0], 0.0)

# 2. Locate the degrees of freedom (DoFs) at the left boundary for both displacement and rotation
fdim = beam_mesh.topology.dim - 1  # Geometrical dimension for the boundary (1D case: 0-dimensional points)
facets_left = mesh.locate_entities_boundary(beam_mesh, fdim, left_end)

# Locate DoFs for both displacement (w) and rotation (phi)
V_z1, _ = V.sub(0).collapse()  # Subspace for displacement
V_z2, _ = V.sub(1).collapse()  # Subspace for rotation
V_z3, _ = V.sub(2).collapse()  # Subspace for displacement
V_k1, _ = V.sub(3).collapse()  # Subspace for rotation
V_k2, _ = V.sub(3).collapse()  # Subspace for displacement
V_k3, _ = V.sub(5).collapse()  # Subspace for rotation
V_p1, _ = V.sub(6).collapse()  # Subspace for displacement
V_p2, _ = V.sub(7).collapse()  # Subspace for rotation
V_p3, _ = V.sub(8).collapse()  # Subspace for displacement


dofs_z1_left = fem.locate_dofs_topological((V.sub(0), V_z1), fdim, facets_left)
dofs_z2_left = fem.locate_dofs_topological((V.sub(1), V_z2), fdim, facets_left)
dofs_z3_left = fem.locate_dofs_topological((V.sub(2), V_z3), fdim, facets_left)
dofs_k1_left = fem.locate_dofs_topological((V.sub(3), V_k1), fdim, facets_left)
dofs_k2_left = fem.locate_dofs_topological((V.sub(4), V_k2), fdim, facets_left)
dofs_k3_left = fem.locate_dofs_topological((V.sub(5), V_k3), fdim, facets_left)
dofs_p1_left = fem.locate_dofs_topological((V.sub(6), V_p1), fdim, facets_left)
dofs_p2_left = fem.locate_dofs_topological((V.sub(7), V_p2), fdim, facets_left)
dofs_p3_left = fem.locate_dofs_topological((V.sub(8), V_p3), fdim, facets_left)

# 3. Apply Dirichlet boundary conditions for z, k, p = 0

# Define zero-valued functions for the boundary conditions
zero_z1 = fem.Function(V_z1)  # Function for displacement boundary condition (w = 0)
zero_z2 = fem.Function(V_z2)  # Function for rotation boundary condition (phi = 0)
zero_z3 = fem.Function(V_z3) 
zero_k1 = fem.Function(V_k1) 
zero_k2 = fem.Function(V_k2) 
zero_k3 = fem.Function(V_k3) 
zero_p1 = fem.Function(V_p1) 
zero_p2 = fem.Function(V_p2) 
zero_p3 = fem.Function(V_p3) 
zero_z1.interpolate(lambda x: np.zeros_like(x[0]))  
zero_z2.interpolate(lambda x: np.zeros_like(x[0]))
zero_z3.interpolate(lambda x: np.zeros_like(x[0]))
zero_k1.interpolate(lambda x: np.zeros_like(x[0]))
zero_k2.interpolate(lambda x: np.zeros_like(x[0]))
zero_k3.interpolate(lambda x: np.zeros_like(x[0]))
zero_p1.interpolate(lambda x: np.zeros_like(x[0]))
zero_p2.interpolate(lambda x: np.zeros_like(x[0]))
zero_p3.interpolate(lambda x: np.zeros_like(x[0]))

# Create the boundary condition objects
bc_z1_left = fem.dirichletbc(zero_z1, dofs_z1_left, V.sub(0))  # BC for displacement
bc_z2_left = fem.dirichletbc(zero_z2, dofs_z2_left, V.sub(1))  # BC for rotation
bc_z3_left = fem.dirichletbc(zero_z3, dofs_z3_left, V.sub(2))  # BC for rotation
bc_k1_left = fem.dirichletbc(zero_k1, dofs_k1_left, V.sub(3))  # BC for displacement
bc_k2_left = fem.dirichletbc(zero_k2, dofs_k2_left, V.sub(4))  # BC for rotation
bc_k3_left = fem.dirichletbc(zero_k3, dofs_k3_left, V.sub(5))  # BC for rotation
bc_p1_left = fem.dirichletbc(zero_p1, dofs_p1_left, V.sub(6))  # BC for displacement
bc_p2_left = fem.dirichletbc(zero_p2, dofs_p2_left, V.sub(7))  # BC for rotation
bc_p3_left = fem.dirichletbc(zero_p3, dofs_p3_left, V.sub(8))  # BC for rotation

# Combine the boundary conditions
bcs = [bc_z1_left, bc_z2_left,bc_z3_left, bc_k1_left, bc_k2_left, bc_k3_left, bc_p1_left, bc_p2_left, bc_p3_left] 

def right_end(x):
    return np.isclose(x[0], L)

facets_right = mesh.locate_entities_boundary(beam_mesh, fdim, right_end)

# Check if any facets were found at the right end
if len(facets_right) == 0:
    raise ValueError("No boundary facets found at the right end of the beam.")

# Create an array of markers (use 1 for the right end)
values_right = np.full(len(facets_right), 1, dtype=np.int32)

# Create the meshtags object for the boundary
boundary_markers = mesh.meshtags(beam_mesh, fdim, facets_right, values_right)

# Define boundary measure with subdomain markers
ds = Measure("ds", domain=beam_mesh, subdomain_data=boundary_markers)

# Define the body force term in the weak form
body_force_term = inner(u1, B[0]) * dx + inner(u2, B[1]) * dx + inner(u3, B[2]) * dx
# Define the nodal force term in the weak form (traction)
traction_term = inner(u1, T[0]) * ds(1) + inner(u2, T[1]) * ds(1) + inner(u3, T[2]) * ds(1)

# Complete the right-hand side of the weak form
rhs = body_force_term + traction_term

# Full variational form combining strain and body/nodal forces
F = a - rhs


u = fem.Function(V)

from dolfinx.jit import ffcx_jit

# Increase the timeout for JIT compilation
jit_options = {"timeout": 600}  # Increase the timeout (in seconds) to 10 minutes

# Use the updated JIT options when creating the form
problem = NonlinearProblem(F, u, bcs, jit_options=jit_options) 

after some times, it is showing errors like jit timeout.
what might be the issue here?

I am getting the following error

---------------------------------------------------------------------------
ArityMismatch                             Traceback (most recent call last)
Cell In[39], line 7
      4 jit_options = {"timeout": 600}  # Increase the timeout (in seconds) to 10 minutes
      6 # Use the updated JIT options when creating the form
----> 7 problem = NonlinearProblem(F, u, bcs, jit_options=jit_options)

File /opt/tljh/user/lib/python3.10/site-packages/dolfinx/fem/petsc.py:897, in NonlinearProblem.__init__(self, F, u, bcs, J, form_compiler_options, jit_options)
    868 def __init__(
    869     self,
    870     F: ufl.form.Form,
   (...)
    875     jit_options: typing.Optional[dict] = None,
    876 ):
    877     """Initialize solver for solving a non-linear problem using Newton's method`.
    878 
    879     Args:
   (...)
    895 
    896     """
--> 897     self._L = _create_form(
    898         F, form_compiler_options=form_compiler_options, jit_options=jit_options
    899     )
    901     # Create the Jacobian matrix, dF/du
    902     if J is None:

File /opt/tljh/user/lib/python3.10/site-packages/dolfinx/fem/forms.py:249, in form(form, dtype, form_compiler_options, jit_options, entity_maps)
    246         return list(map(lambda sub_form: _create_form(sub_form), form))
    247     return form
--> 249 return _create_form(form)

File /opt/tljh/user/lib/python3.10/site-packages/dolfinx/fem/forms.py:244, in form.<locals>._create_form(form)
    241 """Recursively convert ufl.Forms to dolfinx.fem.Form, otherwise
    242 return form argument"""
    243 if isinstance(form, ufl.Form):
--> 244     return _form(form)
    245 elif isinstance(form, collections.abc.Iterable):
    246     return list(map(lambda sub_form: _create_form(sub_form), form))

File /opt/tljh/user/lib/python3.10/site-packages/dolfinx/fem/forms.py:186, in form.<locals>._form(form)
    184 if mesh is None:
    185     raise RuntimeError("Expecting to find a Mesh in the form.")
--> 186 ufcx_form, module, code = jit.ffcx_jit(
    187     mesh.comm, form, form_compiler_options=form_compiler_options, jit_options=jit_options
    188 )
    190 # For each argument in form extract its function space
    191 V = [arg.ufl_function_space()._cpp_object for arg in form.arguments()]

File /opt/tljh/user/lib/python3.10/site-packages/dolfinx/jit.py:51, in mpi_jit_decorator.<locals>.mpi_jit(comm, *args, **kwargs)
     47 @functools.wraps(local_jit)
     48 def mpi_jit(comm, *args, **kwargs):
     49     # Just call JIT compiler when running in serial
     50     if comm.size == 1:
---> 51         return local_jit(*args, **kwargs)
     53     # Default status (0 == ok, 1 == fail)
     54     status = 0

File /opt/tljh/user/lib/python3.10/site-packages/dolfinx/jit.py:201, in ffcx_jit(ufl_object, form_compiler_options, jit_options)
    199 # Switch on type and compile, returning cffi object
    200 if isinstance(ufl_object, ufl.Form):
--> 201     r = ffcx.codegeneration.jit.compile_forms([ufl_object], options=p_ffcx, **p_jit)
    202 elif isinstance(ufl_object, ufl.AbstractFiniteElement):
    203     r = ffcx.codegeneration.jit.compile_elements([ufl_object], options=p_ffcx, **p_jit)

File /opt/tljh/user/lib/python3.10/site-packages/ffcx/codegeneration/jit.py:256, in compile_forms(forms, options, cache_dir, timeout, cffi_extra_compile_args, cffi_verbose, cffi_debug, cffi_libraries, visualise)
    253     for name in form_names:
    254         decl += form_template.format(name=name)
--> 256     impl = _compile_objects(
    257         decl,
    258         forms,
    259         form_names,
    260         module_name,
    261         p,
    262         cache_dir,
    263         cffi_extra_compile_args,
    264         cffi_verbose,
    265         cffi_debug,
    266         cffi_libraries,
    267         visualise=visualise,
    268     )
    269 except Exception as e:
    270     try:
    271         # remove c file so that it will not timeout next time

File /opt/tljh/user/lib/python3.10/site-packages/ffcx/codegeneration/jit.py:383, in _compile_objects(decl, ufl_objects, object_names, module_name, options, cache_dir, cffi_extra_compile_args, cffi_verbose, cffi_debug, cffi_libraries, visualise)
    379 libraries = _libraries + cffi_libraries if cffi_libraries is not None else _libraries
    381 # JIT uses module_name as prefix, which is needed to make names of all struct/function
    382 # unique across modules
--> 383 _, code_body = ffcx.compiler.compile_ufl_objects(
    384     ufl_objects, prefix=module_name, options=options, visualise=visualise
    385 )
    387 ffibuilder = cffi.FFI()
    389 ffibuilder.set_source(
    390     module_name,
    391     code_body,
   (...)
    394     libraries=libraries,
    395 )

File /opt/tljh/user/lib/python3.10/site-packages/ffcx/compiler.py:108, in compile_ufl_objects(ufl_objects, options, object_names, prefix, visualise)
    106 # Stage 1: analysis
    107 cpu_time = time()
--> 108 analysis = analyze_ufl_objects(ufl_objects, options["scalar_type"])  # type: ignore
    109 _print_timing(1, time() - cpu_time)
    111 # Stage 2: intermediate representation

File /opt/tljh/user/lib/python3.10/site-packages/ffcx/analysis.py:94, in analyze_ufl_objects(ufl_objects, scalar_type)
     91     else:
     92         raise TypeError("UFL objects not recognised.")
---> 94 form_data = tuple(_analyze_form(form, scalar_type) for form in forms)
     95 for data in form_data:
     96     elements += data.unique_sub_elements

File /opt/tljh/user/lib/python3.10/site-packages/ffcx/analysis.py:94, in <genexpr>(.0)
     91     else:
     92         raise TypeError("UFL objects not recognised.")
---> 94 form_data = tuple(_analyze_form(form, scalar_type) for form in forms)
     95 for data in form_data:
     96     elements += data.unique_sub_elements

File /opt/tljh/user/lib/python3.10/site-packages/ffcx/analysis.py:180, in _analyze_form(form, scalar_type)
    177 complex_mode = np.issubdtype(scalar_type, np.complexfloating)
    179 # Compute form metadata
--> 180 form_data = ufl.algorithms.compute_form_data(
    181     form,
    182     do_apply_function_pullbacks=True,
    183     do_apply_integral_scaling=True,
    184     do_apply_geometry_lowering=True,
    185     preserve_geometry_types=(ufl.classes.Jacobian,),
    186     do_apply_restrictions=True,
    187     do_append_everywhere_integrals=False,  # do not add dx integrals to dx(i) in UFL
    188     complex_mode=complex_mode,
    189 )
    191 # Determine unique quadrature degree and quadrature scheme
    192 # per each integral data
    193 for id, integral_data in enumerate(form_data.integral_data):
    194     # Iterate through groups of integral data. There is one integral
    195     # data for all integrals with same domain, itype, subdomain_id
   (...)
    199     # all integrals in this integral data group, i.e. must be the
    200     # same for for the same (domain, itype, subdomain_id)

File /opt/tljh/user/lib/python3.10/site-packages/ufl/algorithms/compute_form_data.py:427, in compute_form_data(form, do_apply_function_pullbacks, do_apply_integral_scaling, do_apply_geometry_lowering, preserve_geometry_types, do_apply_default_restrictions, do_apply_restrictions, do_estimate_degrees, do_append_everywhere_integrals, complex_mode)
    424 preprocessed_form = reconstruct_form_from_integral_data(self.integral_data)
    426 # TODO: Test how fast this is
--> 427 check_form_arity(preprocessed_form, self.original_form.arguments(), complex_mode)
    429 # TODO: This member is used by unit tests, change the tests to
    430 # remove this!
    431 self.preprocessed_form = preprocessed_form

File /opt/tljh/user/lib/python3.10/site-packages/ufl/algorithms/check_arities.py:211, in check_form_arity(form, arguments, complex_mode)
    209 """Check the arity of a form."""
    210 for itg in form.integrals():
--> 211     check_integrand_arity(itg.integrand(), arguments, complex_mode)

File /opt/tljh/user/lib/python3.10/site-packages/ufl/algorithms/check_arities.py:192, in check_integrand_arity(expr, arguments, complex_mode)
    190 arguments = tuple(sorted(set(arguments), key=lambda x: (x.number(), x.part())))
    191 rules = ArityChecker(arguments)
--> 192 arg_tuples = map_expr_dag(rules, expr, compress=False)
    193 args = tuple(a[0] for a in arg_tuples)
    194 if args != arguments:

File /opt/tljh/user/lib/python3.10/site-packages/ufl/corealg/map_dag.py:35, in map_expr_dag(function, expression, compress, vcache, rcache)
     15 def map_expr_dag(function, expression, compress=True, vcache=None, rcache=None):
     16     """Apply a function to each subexpression node in an expression DAG.
     17 
     18     If the same function is called multiple times in a transformation
   (...)
     33         The result of the final function call
     34     """
---> 35     (result,) = map_expr_dags(
     36         function, [expression], compress=compress, vcache=vcache, rcache=rcache
     37     )
     38     return result

File /opt/tljh/user/lib/python3.10/site-packages/ufl/corealg/map_dag.py:101, in map_expr_dags(function, expressions, compress, vcache, rcache)
     99 # Cache miss: Get transformed operands, then apply transformation
    100 if cutoff_types[v._ufl_typecode_]:
--> 101     r = handlers[v._ufl_typecode_](v)
    102 else:
    103     r = handlers[v._ufl_typecode_](v, *[vcache[u] for u in v.ufl_operands])

File /opt/tljh/user/lib/python3.10/site-packages/ufl/algorithms/check_arities.py:46, in ArityChecker.nonlinear_operator(self, o)
     44 for t in traverse_unique_terminals(o):
     45     if t._ufl_typecode_ == Argument._ufl_typecode_:
---> 46         raise ArityMismatch(
     47             f"Applying nonlinear operator {o._ufl_class_.__name__} to "
     48             f"expression depending on form argument {t}."
     49         )
     50 return self._et

ArityMismatch: Applying nonlinear operator Power to expression depending on form argument v_1. 

Nonlinear problems shouldn’t use TrialFunctions, but a dolfinx.fem.Function with a ufl.split on the variable after instantiation

1 Like

See also A nonlinear Poisson equation — FEniCSx tutorial.

1 Like