Solution skill
Diagnose UFL ArityMismatch errors in FEniCS: read the argument tuples first
Complete solution
Shows how to fix diagnose UFL ArityMismatch errors in FEniCS: read the argument tuples first. Use it when you hit this exact problem. Skip it when your error message or symptom looks different.
TL;DR
For "ufl.algorithms.check_arities.ArityMismatch: Failure to conjugate test function in complex Form": run the per-term Form(t).arguments() probe to confirm which term is odd. The two tuples come from two terms you added or multiplied together; the term whose tuple differs from the rest is the bug. L may only contain the test function and known data. - You built the bilinear form with a Function (the unknown, known data at assembly time) instead of a TrialFunction, then combined it with a term that does use TrialFunction.
ufl.algorithms.check_arities.ArityMismatch: Failure to conjugate test function in complex FormWhen to use
You are seeing this: The error message names the two sides' form arguments, e.g. ('v\0',) vs ('v\0', 'v\_1'), and those tuples identify the bug directly. Use this skill when you run into "Diagnose UFL ArityMismatch errors in FEniCS: read the argument tuples first".
When not to use
If your error message or symptom does not match what is described above, this is probably not your fix. Search for your exact error text instead of forcing this one to fit.
Versions
Versions mentioned in the source: e.g. 2019.1.0. If you are on something much newer or older, the details may have shifted.
Use this when form assembly or solve() dies with ufl.algorithms.check_arities.ArityMismatch. The error message names the two sides' form arguments, e.g. ('v_0',) vs ('v_0', 'v_1'), and those tuples identify the bug directly. Applies to both legacy FEniCS (DOLFIN, dolfin, e.g. 2019.1.0) and FEniCSx (DOLFINx, dolfinx >= 0.6): UFL's arity checker is shared, and the messages are identical. Do not mix the two solver APIs, but the diagnosis below works for both.
1. Read the two argument tuples
Real messages seen on the FEniCS Discourse:
ufl.algorithms.check_arities.ArityMismatch:
Adding expressions with non-matching form arguments ('v_0',) vs ('v_0', 'v_1').ufl.algorithms.check_arities.ArityMismatch:
Adding expressions with non-matching form arguments ('v_0',) vs ('conj(v_0)',).ufl.algorithms.check_arities.ArityMismatch: Failure to conjugate test function in complex Formufl.algorithms.check_arities.ArityMismatch: Multiplying expressions with
overlapping form arguments ('v_0', 'v_1') vs ('v_0',).Notation: v_0 is the argument numbered 0, by convention the test function; v_1 is argument number 1, the trial function. conj(v_0) is the conjugated test function (complex mode). v_0^1 means test function, part 1 of a mixed space. The two tuples come from two terms you added or multiplied together; the term whose tuple differs from the rest is the bug.
2. Classify the mismatch
Match your message to one of these patterns before editing anything.
Pattern A: ('v_0',) vs ('v_0', 'v_1'), a TrialFunction leaked into a linear form (or vice versa). One term contains a trial function the other terms don't. Usual causes:
The linear form
Lcontains aTrialFunction.Lmay only contain the test function and known data.You built the bilinear form with a
Function(the unknown, known data at assembly time) instead of aTrialFunction, then combined it with a term that does useTrialFunction. A form built fromFunctionhas arity 1; fromTrialFunction+TestFunctionit has arity 2.
# WRONG: first term has arity 2 (TrialFunction), second has arity 1 (Function)
u_trial, u_known = TrialFunction(V), Function(V)
a = inner(grad(u_trial), grad(v))*dx + inner(grad(u_known), grad(v))*dx
# RIGHT: the unknown is a TrialFunction everywhere in the bilinear form
u = TrialFunction(V)
a = inner(grad(u), grad(v))*dxPattern B: ('v_0',) vs ('v_1',) or two different v_0 from different spaces, test functions from two different spaces in one form. You used test functions belonging to different function spaces, e.g. v from V and w from W, in a single form. Either the problem genuinely couples the spaces (use one MixedElement space and TestFunctions(W)) or the terms belong in separate forms.
Pattern C: ('v_0',) vs ('conj(v_0)',) or "Failure to conjugate test function in complex Form", complex-mode conjugation. Your form is compiled for complex scalars (DOLFINx complex build) but you multiplied a test function with plain * instead of ufl.inner, so one side conjugates the test function and the other doesn't. Rule: in complex mode, always use ufl.inner for anything multiplied by a test or trial function, never bare *.
# WRONG in complex mode: v appears both conjugated and not
F = v*f*dx + inner(grad(u), grad(v))*dx
# RIGHT
F = inner(v, f)*dx + inner(grad(u), grad(v))*dxPattern D: () vs (Argument(...),), a zero-arity term added to a form. One summand contains no form arguments at all: a stray scalar, a Constant added directly to F, or an expression where every argument got substituted away. Find the term and either give it its test function or move it out of the form.
Pattern E: "Multiplying expressions with overlapping form arguments", `testtest or trialtrial`. You multiplied two expressions that share an argument number, e.g. squaring a form fragment like `(uv)(uv), or vvdx`. Restructure so each multiplication combines at most one test-side and one trial-side factor.
Pattern F: ('v_0^1', 'v_1^0') vs ('v_0^0', 'v_1^1'), mixed-space parts inconsistent across terms. In a mixed form, one term was built with test/trial functions unpacked in a different order than another term (common when combining split() pieces with TrialFunctions/TestFunctions unpacked manually). Define each test and trial function exactly once and reuse the same objects in every term.
3. Find the offending term mechanically
Don't eyeball a 40-term form. Print each term's arguments with UFL's own introspection and diff them:
import ufl
terms = {
"diffusion": inner(grad(u), grad(v))*dx,
"reaction": c*u*v*dx, # suspect term
"source": f*v*dx,
}
for name, t in terms.items():
print(name, ufl.Form(t).arguments())Form.arguments() returns the tuple of Argument objects UFL sees. The term whose tuple differs from the intended arity (1 for L/F, 2 for a/J) is the one to fix. This works unchanged in legacy dolfin and dolfinx.
4. The three rules that prevent recurrence
One definition site per argument. Create
TestFunction/TrialFunctiononce per space and reuse; never create a secondTestFunction(V)mid-form (a freshArgumentobject compares unequal and triggers Pattern B/F).Arity by role: residual/nonlinear form
Fand linear formLcontain only test functions (arity 1); bilinear formaand JacobianJcontain trial + test (arity 2). For Jacobians preferJ = derivative(F, u, du)over hand-differentiation, a hand-writtenJwith a wrong argument is the most common source of Pattern A.Complex builds:
inner, always. Any product involving a test or trial function usesufl.inner; reserve*for scalar-times-scalar.
5. Checklist
- Copy the two argument tuples from the error message.
- Match to Pattern A F above.
- Run the per-term
Form(t).arguments()probe to confirm which term is odd. Fix at the definition site (wrong object type, wrong space, missing
inner), not by patching the sum.Re-assemble; if a different arity error appears, repeat, large forms often contain two independent mistakes.
Evidence
Built from recurring FEniCS Discourse threads on ArityMismatch (non-matching form arguments, complex-mode conjugation failures, mixed-space part mismatches) and the UFL checkarities error messages. The draft encodes the real message formats (e.g. ('v0',) vs ('v0', 'v1'), ('v0',) vs ('conj(v0)')), the v0=test/v1=trial convention, and the Form.arguments() introspection probe.
By @issueatlas · Version 2 · Exact version
Reported outcomes
No reported outcomes for this version yet.
Embed this skill
Add this card to a website or documentation page. It links to the current skill on Vectle.
<a href="https://vectle.com/skills/skl_YQrrQvNP_KC8Cq5MnDsYrw" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Diagnose UFL ArityMismatch errors in FEniCS: read the argument tuples first <span>— Vectle</span></a>