Issue while implementing as_tensor method

Hello! I’ve been trying to solve a PDE for a 2x2 Q tensor, symmetric and with Trace(Q) = 0, and the approach that I’ve been following is by first define a vector space and from it built the tensor entity. Here I put the tensor that I want to build:
Screenshot_20230424_094002
So far I’ve been OK, but I get the following error when I use the solve function:

AttributeError: 'ListTensor' object has no attribute 'vector'

I’m not sure if my approach is correct and if so, how to pass correctly to the solve function.
Here’s my code:

## Define vector elements and function spaces
## Define function spaces
Q = VectorFunctionSpace(mesh, 'P', 2)
U = VectorFunctionSpace(mesh, 'P', 2)
q = TrialFunction(Q)
r = TestFunction(Q)
q_ten = as_tensor(((cos(q[0]), sin(q[1])),
                   (sin(q[1]), -cos(q[0]))))
r_ten = as_tensor(((r[0], 0),
                   (0, r[1])))
## Define boundaries
inflow   = 'near(x[0], 0)'                     
outflow  = 'near(x[0], 0.5)'
walls    = 'near(x[1], 0) || near(x[1], 0.2)'

## Define inflow profile for the velocity
inflow_profile = ('10.0*1.5*(0.1 - x[1])*x[1]*pow(0.1, 2)', '0')

## Define boundary conditions for the velocity
bcu_inflow = DirichletBC(U, 
                         Expression(inflow_profile, 
                                    degree=2), 
                         inflow)
bcu_walls = DirichletBC(U, 
                        Constant((0, 0)), 
                        walls)
bcu = [bcu_inflow, bcu_walls]         ## Colect all boundary conditions for the velocity
## Define boundary conditions for the order parameter
## Define initial value for the order parameter
io = '0.8'
initial_order = Expression((io, io), degree=2)

bcq_inflow = DirichletBC(Q, 
                          initial_order, 
                          outflow)
bcq_walls = DirichletBC(Q, 
                        initial_order, 
                        walls)
bcq = [bcq_inflow, bcq_walls]        ## Colect all boundary conditions for the order parameter
## Define trial and test functions
q_int = TrialFunction(Q)
u = TrialFunction(U)
r_int = TestFunction(Q)
v = TestFunction(U)
## Declare trial and test functions as tensors
q = as_tensor(((q_int[0],  q_int[1]), 
               (q_int[1], -q_int[0])))
r = as_tensor(((r_int[0],  r_int[1]),
               (r_int[1], -r_int[0])))

# Define functions for solutions at previous and current time steps
q_n_int = Function(Q)
u_n = Function(U)
q_int   = Function(Q)
u_   = Function(U)

## Declare previous functions as tensors
q_n = as_tensor(((q_n_int[0], q_n_int[1]),
                 (q_n_int[1], -q_n_int[0])))
q_ = as_tensor(((q_int[0],   q_int[1]),
                 (q_int[1], -q_int[0])))
## Define epsilon tensor
def epsilon(u):
    return sym(nabla_grad(u))

## Define vorticity tensor
def omega(u):
    return skew(nabla_grad(u))

## Define L tensor
def L(u):
    L1 = (1/3.) * dot((lamb*epsilon(u) + omega(u)), Identity(len(u)))
    L2 = (1/3.) * dot((lamb*epsilon(u) - omega(u)), Identity(len(u)))
    return L1 + L2

## Define N tensor
def N(q, u):
    N1 = dot(lamb*epsilon(u) + omega(u), q)
    N2 = dot(q, lamb*epsilon(u) - omega(u))
    N3 = -2*lamb*(q + Identity(mesh.geometry().dim())/3.) * inner(q, nabla_grad(u))
    return N1 + N2 + N3

## Define expressions used in variational forms
k1 = Constant(dt)
k2 = Constant(Pe)
## Define variational problem for step 1
F1 = inner((q - q_n) / k1, r)*dx                      \
    + inner(dot(u_n, nabla_grad(q_n)),r)*dx           \
    - (1/k2) * inner(nabla_grad(q), nabla_grad(r))*dx \
    - inner(L(u_n), r)*dx                             \
    - inner(N(q_n, u_n), r)*dx
a1 = lhs(F1)
L1 = rhs(F1)

# Assemble matrices
A1 = assemble(a1)

# Apply boundary conditions to matrices
[bc.apply(A1) for bc in bcq]
# Time-stepping
t = 0
for n in range(num_steps):
    
    # Update current time
    t += dt

    # Step 1: Tentative velocity step
    b1 = assemble(L1)
    [bc.apply(b1) for bc in bcq]
    solve(A1, q_.vector(), b1, 'bicgstab', 'hypre_amg')

Hope you can help me.
Thanks!

The unknow is q_int,

and thus you should send in q_int.vector()

Thanks, that solve the issue!
But I have another question, what happens when I declare the as_tensor functions?
Just to be sure, help me with my reasoning:

  • I provide a vector as an input for the tensor entity.
  • Next, FEniCS uses that vector as entries for the tensor (in the way that I defined) and solves but for the tensor equation.
  • And finally it stores the solution in a vector.

Am I right or I am missing something?

Sorry for the silly question, and thank you very much, really!

as_tensor is a representation used by ufl to define tensor quantities.
This tensor quantity is used in your variational form, thus, you solve with your constraint applied.
The unknown is still a vector (as it is the function that contains the dofs you are solving for).

1 Like