UFLException: Invalid argument type <class 'ufl.equation.Equation'>

Hi everyone,
I’m trying to combine the poisson equation with another equation and solve them both together: (2 Equations with 2 unknowns).

the equations are as following:

After defining the Domain and the BCs i tried to define the variational Problem as following:

u1 = ufl.TrialFunction(V)
v1 = ufl.TestFunction(V)

u2 =fem.Function(V)
v2 = ufl.TestFunction(V)

f =  u2/A

#Solving the linear equation
a = ufl.inner(ufl.grad(u1), ufl.grad(v1)) * ufl.dx
L = ufl.inner(f , v1) * ufl.dx

problem1 = fem.petsc.LinearProblem(a, L, bc1, petsc_options={"ksp_type": "preonly", "pc_type": "lu"})
uh = problem1.solve()

#Solving the nonlinear equation
F = ufl.inner(u2*u2/A,v2)*ufl.dx - ufl.inner(ufl.inner(ufl.grad(u1),ufl.grad(u2)),v2)*ufl.dx

problem2 = fem.petsc.NonlinearProblem(F == 0, u2, bc2)
ui = problem2.solve()

as i run the code i face this following error:

ERROR:UFL:Invalid argument type <class 'ufl.equation.Equation'>.
---------------------------------------------------------------------------
UFLException                              Traceback (most recent call last)
Input In [16], in <cell line: 1>()
----> 1 problem2 = fem.petsc.NonlinearProblem(F == 0, u2, bc2)
      2 ui = problem2.solve()

File /usr/local/dolfinx-complex/lib/python3.8/dist-packages/dolfinx/fem/petsc.py:623, in NonlinearProblem.__init__(self, F, u, bcs, J, form_compiler_params, jit_params)
    621     V = u.function_space
    622     du = ufl.TrialFunction(V)
--> 623     J = ufl.derivative(F, u, du)
    625 self._a = _create_form(J, form_compiler_params=form_compiler_params,
    626                        jit_params=jit_params)
    627 self.bcs = bcs

File /usr/local/lib/python3.9/dist-packages/ufl/formoperators.py:305, in derivative(form, coefficient, argument, coefficient_derivatives)
    301     else:
    302         return CoordinateDerivative(form, coefficients,
    303                                     arguments, coefficient_derivatives)
--> 305 error("Invalid argument type %s." % str(type(form)))

File /usr/local/lib/python3.9/dist-packages/ufl/log.py:158, in Logger.error(self, *message)
    156 "Write error message and raise an exception."
    157 self._log.error(*message)
--> 158 raise self._exception_type(self._format_raw(*message))

UFLException: Invalid argument type <class 'ufl.equation.Equation'>.

is there anything that i’m missing that is causing this problem?
i would really want to know too, wether i defined the variational formulation right or not if possible.

i would really appreciate your help.

Best regards.
Midouchk

As shown in: Implementation — FEniCSx tutorial
You should not use F==0 but simply
problem = fem.petsc.NonlinearProblem(F, uh, bcs=bc2)

However, please note that your variational form is not well-defined, as you are mixing in the trial function u1 with the actual unknown function u1. Are you sure you didn’t want to use uh instead of u1 in

first of all thank you for your response.

yes! i needed to use uh instead of u2 in the variational form. However even after changing the F==0 to F in fem.petsc.NonlinearProblem i still get this Error.

---------------------------------------------------------------------------
ArityMismatch                             Traceback (most recent call last)
Input In [9], in <cell line: 24>()
     20 #Solving the nonlinear equation
     22 F = ufl.inner(u2*u2/A,v2)*ufl.dx - ufl.inner(ufl.inner(ufl.grad(uh),ufl.grad(u2)),v2)*ufl.dx
---> 24 problem2 = fem.petsc.NonlinearProblem(F, u2, bc2)
     25 ui = problem2.solve()

File /usr/local/dolfinx-complex/lib/python3.8/dist-packages/dolfinx/fem/petsc.py:625, in NonlinearProblem.__init__(self, F, u, bcs, J, form_compiler_params, jit_params)
    622     du = ufl.TrialFunction(V)
    623     J = ufl.derivative(F, u, du)
--> 625 self._a = _create_form(J, form_compiler_params=form_compiler_params,
    626                        jit_params=jit_params)
    627 self.bcs = bcs

File /usr/local/dolfinx-complex/lib/python3.8/dist-packages/dolfinx/fem/forms.py:139, in form(form, dtype, form_compiler_params, jit_params)
    136         return list(map(lambda sub_form: _create_form(sub_form), form))
    137     return form
--> 139 return _create_form(form)

File /usr/local/dolfinx-complex/lib/python3.8/dist-packages/dolfinx/fem/forms.py:134, in form.<locals>._create_form(form)
    131 """Recursively convert ufl.Forms to dolfinx.fem.Form, otherwise
    132 return form argument"""
    133 if isinstance(form, ufl.Form):
--> 134     return _form(form)
    135 elif isinstance(form, collections.abc.Iterable):
    136     return list(map(lambda sub_form: _create_form(sub_form), form))

File /usr/local/dolfinx-complex/lib/python3.8/dist-packages/dolfinx/fem/forms.py:108, in form.<locals>._form(form)
    105 if mesh is None:
    106     raise RuntimeError("Expecting to find a Mesh in the form.")
--> 108 ufcx_form, module, code = jit.ffcx_jit(mesh.comm, form,
    109                                        form_compiler_params=form_compiler_params,
    110                                        jit_params=jit_params)
    112 # For each argument in form extract its function space
    113 V = [arg.ufl_function_space()._cpp_object for arg in form.arguments()]

File /usr/local/dolfinx-complex/lib/python3.8/dist-packages/dolfinx/jit.py:56, in mpi_jit_decorator.<locals>.mpi_jit(comm, *args, **kwargs)
     51 @functools.wraps(local_jit)
     52 def mpi_jit(comm, *args, **kwargs):
     53 
     54     # Just call JIT compiler when running in serial
     55     if comm.size == 1:
---> 56         return local_jit(*args, **kwargs)
     58     # Default status (0 == ok, 1 == fail)
     59     status = 0

File /usr/local/dolfinx-complex/lib/python3.8/dist-packages/dolfinx/jit.py:204, in ffcx_jit(ufl_object, form_compiler_params, jit_params)
    202 # Switch on type and compile, returning cffi object
    203 if isinstance(ufl_object, ufl.Form):
--> 204     r = ffcx.codegeneration.jit.compile_forms([ufl_object], parameters=p_ffcx, **p_jit)
    205 elif isinstance(ufl_object, ufl.FiniteElementBase):
    206     r = ffcx.codegeneration.jit.compile_elements([ufl_object], parameters=p_ffcx, **p_jit)

File /usr/local/lib/python3.9/dist-packages/ffcx/codegeneration/jit.py:168, in compile_forms(forms, parameters, cache_dir, timeout, cffi_extra_compile_args, cffi_verbose, cffi_debug, cffi_libraries)
    165     for name in form_names:
    166         decl += form_template.format(name=name)
--> 168     impl = _compile_objects(decl, forms, form_names, module_name, p, cache_dir,
    169                             cffi_extra_compile_args, cffi_verbose, cffi_debug, cffi_libraries)
    170 except Exception:
    171     # remove c file so that it will not timeout next time
    172     c_filename = cache_dir.joinpath(module_name + ".c")

File /usr/local/lib/python3.9/dist-packages/ffcx/codegeneration/jit.py:232, in _compile_objects(decl, ufl_objects, object_names, module_name, parameters, cache_dir, cffi_extra_compile_args, cffi_verbose, cffi_debug, cffi_libraries)
    228 import ffcx.compiler
    230 # JIT uses module_name as prefix, which is needed to make names of all struct/function
    231 # unique across modules
--> 232 _, code_body = ffcx.compiler.compile_ufl_objects(ufl_objects, prefix=module_name, parameters=parameters)
    234 ffibuilder = cffi.FFI()
    235 ffibuilder.set_source(module_name, code_body, include_dirs=[ffcx.codegeneration.get_include_path()],
    236                       extra_compile_args=cffi_extra_compile_args, libraries=cffi_libraries)

File /usr/local/lib/python3.9/dist-packages/ffcx/compiler.py:98, in compile_ufl_objects(ufl_objects, object_names, prefix, parameters, visualise)
     96 # Stage 1: analysis
     97 cpu_time = time()
---> 98 analysis = analyze_ufl_objects(ufl_objects, parameters)
     99 _print_timing(1, time() - cpu_time)
    101 # Stage 2: intermediate representation

File /usr/local/lib/python3.9/dist-packages/ffcx/analysis.py:75, in analyze_ufl_objects(ufl_objects, parameters)
     72     else:
     73         raise TypeError("UFL objects not recognised.")
---> 75 form_data = tuple(_analyze_form(form, parameters) for form in forms)
     76 for data in form_data:
     77     elements += data.unique_sub_elements

File /usr/local/lib/python3.9/dist-packages/ffcx/analysis.py:75, in <genexpr>(.0)
     72     else:
     73         raise TypeError("UFL objects not recognised.")
---> 75 form_data = tuple(_analyze_form(form, parameters) for form in forms)
     76 for data in form_data:
     77     elements += data.unique_sub_elements

File /usr/local/lib/python3.9/dist-packages/ffcx/analysis.py:156, in _analyze_form(form, parameters)
    153 complex_mode = "_Complex" in parameters["scalar_type"]
    155 # Compute form metadata
--> 156 form_data = ufl.algorithms.compute_form_data(
    157     form,
    158     do_apply_function_pullbacks=True,
    159     do_apply_integral_scaling=True,
    160     do_apply_geometry_lowering=True,
    161     preserve_geometry_types=(ufl.classes.Jacobian,),
    162     do_apply_restrictions=True,
    163     do_append_everywhere_integrals=False,  # do not add dx integrals to dx(i) in UFL
    164     complex_mode=complex_mode)
    166 # Determine unique quadrature degree, quadrature scheme and
    167 # precision per each integral data
    168 for id, integral_data in enumerate(form_data.integral_data):
    169     # Iterate through groups of integral data. There is one integral
    170     # data for all integrals with same domain, itype, subdomain_id
   (...)
    176 
    177     # Extract precision

File /usr/local/lib/python3.9/dist-packages/ufl/algorithms/compute_form_data.py:407, 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)
    403 # TODO: This is a very expensive check... Replace with something
    404 # faster!
    405 preprocessed_form = reconstruct_form_from_integral_data(self.integral_data)
--> 407 check_form_arity(preprocessed_form, self.original_form.arguments(), complex_mode)  # Currently testing how fast this is
    409 # TODO: This member is used by unit tests, change the tests to
    410 # remove this!
    411 self.preprocessed_form = preprocessed_form

File /usr/local/lib/python3.9/dist-packages/ufl/algorithms/check_arities.py:177, in check_form_arity(form, arguments, complex_mode)
    175 def check_form_arity(form, arguments, complex_mode=False):
    176     for itg in form.integrals():
--> 177         check_integrand_arity(itg.integrand(), arguments, complex_mode)

File /usr/local/lib/python3.9/dist-packages/ufl/algorithms/check_arities.py:159, in check_integrand_arity(expr, arguments, complex_mode)
    156 arguments = tuple(sorted(set(arguments),
    157                          key=lambda x: (x.number(), x.part())))
    158 rules = ArityChecker(arguments)
--> 159 arg_tuples = map_expr_dag(rules, expr, compress=False)
    160 args = tuple(a[0] for a in arg_tuples)
    161 if args != arguments:

File /usr/local/lib/python3.9/dist-packages/ufl/corealg/map_dag.py:36, in map_expr_dag(function, expression, compress, vcache, rcache)
     17 def map_expr_dag(function, expression,
     18                  compress=True,
     19                  vcache=None,
     20                  rcache=None):
     21     """Apply a function to each subexpression node in an expression DAG.
     22 
     23     If *compress* is ``True`` (default) the output object from
   (...)
     34     Return the result of the final function call.
     35     """
---> 36     result, = map_expr_dags(function, [expression], compress=compress,
     37                             vcache=vcache,
     38                             rcache=rcache)
     39     return result

File /usr/local/lib/python3.9/dist-packages/ufl/corealg/map_dag.py:99, in map_expr_dags(function, expressions, compress, vcache, rcache)
     97     r = handlers[v._ufl_typecode_](v)
     98 else:
---> 99     r = handlers[v._ufl_typecode_](v, *[vcache[u] for u in v.ufl_operands])
    101 # Optionally check if r is in rcache, a memory optimization
    102 # to be able to keep representation of result compact
    103 if compress:

File /usr/local/lib/python3.9/dist-packages/ufl/algorithms/check_arities.py:48, in ArityChecker.sum(self, o, a, b)
     46 def sum(self, o, a, b):
     47     if a != b:
---> 48         raise ArityMismatch("Adding expressions with non-matching form arguments {0} vs {1}.".format(_afmt(a), _afmt(b)))
     49     return a

ArityMismatch: Adding expressions with non-matching form arguments ('conj(v_0)', 'conj(v_1)') vs ('conj(v_0)', 'v_1').

i tried to understand where this Error is coming from but didn’t understand much.

i’ve seen in other posts that defining the unknown function of a NonlinearProblem as a TrialFunction could lead to such an Error, which is not my case as i defined it as Function(V).

Could you maybe explain it to me?

I guess you want to use ufl.dot here, as you are running dolfinx in complex mode and thus have to follow the rules of:
https://fenics.readthedocs.io/projects/ufl/en/latest/manual/form_language.html?highlight=Complex#sesquilinearity

Hello everyone,

I’m trying to solve a nonlinear problem using Dolfinx and this formulation:

ui = problem2.solve()

doesn’t seem to work as presented here.
Could you maybe share how to solve this type of formulation and get the values of the unknown Function in order to simulate them, in comparison with the LinearProblem solver as described in the Tutorial:

from dolfinx import io
with io.VTKFile(domain.comm, "output.pvd", "w") as vtk:
    vtk.write([uh._cpp_object])
with io.XDMFFile(domain.comm, "output.xdmf", "w") as xdmf:
    xdmf.write_mesh(domain)
    xdmf.write_function(uh)

i found in the Dolfinx Tutorial that the NonLinearFunction is solved with:

from dolfinx import nls

solver = nls.petsc.NewtonSolver(MPI.COMM_WORLD, problem)
solver.convergence_criterion = "incremental"
solver.rtol = 1e-6
solver.report = True

from petsc4py import PETSc

ksp = solver.krylov_solver
opts = PETSc.Options()
option_prefix = ksp.getOptionsPrefix()
opts[f"{option_prefix}ksp_type"] = "cg"
opts[f"{option_prefix}pc_type"] = "gamg"
opts[f"{option_prefix}pc_factor_mat_solver_type"] = "mumps"
ksp.setFromOptions()

from dolfinx import log

log.set_log_level(log.LogLevel.INFO)
n, converged = solver.solve(uh)
assert(converged)
print(f"Number of interations: {n:d}")

how could i access the solution in order to save it as a pvd-file and plot it on ParaView?
Looking forward for your help.

This is explained in:
https://jorgensd.github.io/dolfinx-tutorial/chapter2/nonlinpoisson_code.html#test-problem
as you send in the solution function to write the solution to uh to your solve

uh is what you should write to file.

Thank you for your help!
it worked as you mentioned.