FEniCS / dolfinx

Next generation FEniCS problem solving environment
https://fenicsproject.org
GNU Lesser General Public License v3.0
720 stars 177 forks source link

ArityMismatch: Failure to conjugate test function in complex Form #2003

Closed xanfus closed 2 years ago

xanfus commented 2 years ago

I've executed FEniCSx Poisson equation solution implementation via Binder with no error: https://notebooks.gesis.org/binder/jupyter/user/jorgensd-dolfinx-tutorial-3spk02o2/notebooks/chapter1/fundamentals_code.ipynb

The notebook is executed at my virtual machine (guest Ubuntu 20.04.3, host Win10, via Docker) at cell #9 with following output:

---------------------------------------------------------------------------
ArityMismatch                             Traceback (most recent call last)
Input In [15], in <module>
      1 from dolfinx.fem import LinearProblem
----> 2 problem = LinearProblem(a, L, bcs=[bc], petsc_options={"ksp_type": "preonly", "pc_type": "lu"})
      3 uh = problem.solve()

File /usr/local/dolfinx-complex/lib/python3.8/dist-packages/dolfinx/fem/problem.py:71, in LinearProblem.__init__(self, a, L, bcs, u, petsc_options, form_compiler_parameters, jit_parameters)
     33 def __init__(self, a: ufl.Form, L: ufl.Form, bcs: typing.List[DirichletBCMetaClass] = [],
     34              u: Function = None, petsc_options={}, form_compiler_parameters={}, jit_parameters={}):
     35     """Initialize solver for a linear variational problem.
     36 
     37     Parameters
   (...)
     69         problem = LinearProblem(a, L, [bc0, bc1], petsc_options={"ksp_type": "preonly", "pc_type": "lu"})
     70     """
---> 71     self._a = create_form(a, form_compiler_parameters=form_compiler_parameters, jit_parameters=jit_parameters)
     72     self._A = create_matrix(self._a)
     74     self._L = create_form(L, form_compiler_parameters=form_compiler_parameters, jit_parameters=jit_parameters)

File /usr/local/dolfinx-complex/lib/python3.8/dist-packages/dolfinx/fem/forms.py:140, in form(form, dtype, form_compiler_parameters, jit_parameters)
    137         return list(map(lambda sub_form: _create_form(sub_form), form))
    138     return form
--> 140 return _create_form(form)

File /usr/local/dolfinx-complex/lib/python3.8/dist-packages/dolfinx/fem/forms.py:135, in form.<locals>._create_form(form)
    132 """Recursively convert ufl.Forms to dolfinx.fem.Form, otherwise
    133 return form argument"""
    134 if isinstance(form, ufl.Form):
--> 135     return _form(form)
    136 elif isinstance(form, collections.Iterable):
    137     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:109, in form.<locals>._form(form)
    106 if mesh is None:
    107     raise RuntimeError("Expecting to find a Mesh in the form.")
--> 109 ufcx_form, module, code = jit.ffcx_jit(mesh.comm, form,
    110                                        form_compiler_parameters=form_compiler_parameters,
    111                                        jit_parameters=jit_parameters)
    113 # For each argument in form extract its function space
    114 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:209, in ffcx_jit(ufl_object, form_compiler_parameters, jit_parameters)
    207 # Switch on type and compile, returning cffi object
    208 if isinstance(ufl_object, ufl.Form):
--> 209     r = ffcx.codegeneration.jit.compile_forms([ufl_object], parameters=p_ffcx, **p_jit)
    210 elif isinstance(ufl_object, ufl.FiniteElementBase):
    211     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:170, in check_integrand_arity(expr, arguments, complex_mode)
    168 for arg, conj in arg_tuples:
    169     if arg.number() == 0 and not conj:
--> 170         raise ArityMismatch("Failure to conjugate test function in complex Form")
    171     elif arg.number() > 0 and conj:
    172         raise ArityMismatch("Argument {0} is spuriously conjugated in complex Form".format(arg))

ArityMismatch: Failure to conjugate test function in complex Form
jorgensd commented 2 years ago

To run in complex mode, you need to write

a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx
L = ufl.inner(f, v) * ufl.dx

as explained in: https://fenics.readthedocs.io/projects/ufl/en/latest/manual/form_language.html?highlight=Complex#inner