Hello Fenics users and developers,
I’m trying to use a fenics code to reproduce the results of this paper as part of a validation process.
This is a fluid mechanics paper that involves a specific decomposition : q(x,r,\theta,t)=q_0(x,r)+\epsilon\hat{q}_1(x,r)e^{im\theta+(\sigma+i\omega)t}
Going from the Navier-Stokes equations N\partial_tq+M(q)=0 and obtaining a base flow q_0 from M(q_0)=0, this allows for computation of the perturbations as a generalised eigenvalue problem dM/dq(q_0)\hat{q}_1=(\sigma+i\omega)N\hat{q}_1
The nonlinear operator M is well–known in the case of the Navier Stokes equations but in this decomposition it is complex (\hat{q}_1 is complex as well).
I’ve read here that the UFL can handle complex values. The code below is an attempt to leverage automatic differentiation to obtain dM/dq(q_0).
from dolfin import *
from pdb import set_trace
# Trivial geometry
mesh = UnitSquareMesh(2,2)
r = SpatialCoordinate(mesh)[1]
# Physical parameters
m=-1
Re=200
# Taylor Hodd elements ; stable element pair
FE_vector=VectorElement("Lagrange",mesh.ufl_cell(),2,3)
FE_scalar=FiniteElement("Lagrange",mesh.ufl_cell(),1)
V=FunctionSpace(mesh,MixedElement([FE_vector,FE_scalar]))
# Test and trial functions
test = TestFunction(V)
trial = TrialFunction(V)
# Initial conditions
q = interpolate(Constant([1,0,0,0]), V)
# Gradient with x[0] is x, x[1] is r, x[2] is theta
def grad(v,m):
return as_tensor([[v[0].dx(0), v[0].dx(1), m*1j*v[0]/r],
[v[1].dx(0), v[1].dx(1), m*1j*v[1]/r-v[2]/r],
[v[2].dx(0), v[2].dx(1), m*1j*v[2]/r+v[1]/r]])
def grad_re(v):
return as_tensor([[v[0].dx(0), v[0].dx(1), 0],
[v[1].dx(0), v[1].dx(1), -v[2]/r],
[v[2].dx(0), v[2].dx(1), v[1]/r]])
def div(v,m): return v[0].dx(0) + (r*v[1]).dx(1)/r + m*1j*v[2]/r
# Navier Stokes variational form
def NS_form(m):
u,p=split(q)
test_u,test_m=split(test)
#mass (variational formulation)
M = div(u,m)*test_m*r*dx
#set_trace()
#momentum (different test functions and IBP)
M += dot(grad(u,m)*u, test_u) *r*dx # Convection
M += 1/Re*inner(grad(u,m), grad(test_u,m))*r*dx # Diffusion
M -= dot(p, div(test_u,m))*r*dx # Pressure
return M
# Compute baseflow
solve(NS_form(0) == 0, q, [])
from ufl.algorithms.compute_form_data import compute_form_data
pert_form=compute_form_data(NS_form(m),complex_mode=True)
parameters['linear_algebra_backend'] = 'Eigen'
L = as_backend_type(assemble(derivative(pert_form,q,trial))).sparray()
With my installation, dolfin 2019.1.0
installed using docker
I obtain the resulting traceback :
Traceback (most recent call last):
File "MWE.py", line 51, in <module>
pert_form=compute_form_data(NS_form(m),complex_mode=True)
File "/usr/local/lib/python3.6/dist-packages/ufl/algorithms/compute_form_data.py", line 418, in compute_form_data
check_form_arity(preprocessed_form, self.original_form.arguments(), complex_mode) # Currently testing how fast this is
File "/usr/local/lib/python3.6/dist-packages/ufl/algorithms/check_arities.py", line 177, in check_form_arity
check_integrand_arity(itg.integrand(), arguments, complex_mode)
File "/usr/local/lib/python3.6/dist-packages/ufl/algorithms/check_arities.py", line 159, in check_integrand_arity
arg_tuples = map_expr_dag(rules, expr, compress=False)
File "/usr/local/lib/python3.6/dist-packages/ufl/corealg/map_dag.py", line 37, in map_expr_dag
result, = map_expr_dags(function, [expression], compress=compress)
File "/usr/local/lib/python3.6/dist-packages/ufl/corealg/map_dag.py", line 86, in map_expr_dags
r = handlers[v._ufl_typecode_](v, *[vcache[u] for u in v.ufl_operands])
File "/usr/local/lib/python3.6/dist-packages/ufl/algorithms/check_arities.py", line 48, in sum
raise ArityMismatch("Adding expressions with non-matching form arguments {0} vs {1}.".format(_afmt(a), _afmt(b)))
ufl.algorithms.check_arities.ArityMismatch: Adding expressions with non-matching form arguments ('v_0',) vs ('conj(v_0)',).
I would be grateful on any insight as to why this error arises, how to go around it, or more generally how to handle complex values in UFL (I’ve found few examples) and how to solve my problem.
Cheers,