Hi Massimiliano,
This error occurs because E_[i,j] is not a “true” UFL scalar. Because it has free indices, it represents a tensor-like quantity. Specifically, it fails the test is_true_ufl_scalar in ufl.checks because its attribute ufl_free_indices is a non-empty tuple. Thus, the only way to achieve what you want in this case is to use the expanded expression using fixed (int) indices.
In general this could become quite cumbersome, so I’ve written a function element_wise(expr, func) that takes an expression expr (with arbitrary shape) and a function func (having one argument) and applies that function element-wise to all elements of expr. See below for this function and examples of its use:
from fenics import (UnitSquareMesh, FunctionSpace, VectorFunctionSpace,
TensorFunctionSpace, Function, as_tensor, sym, grad)
from ufl import (i, j, exp, sqrt)
mesh = UnitSquareMesh(2,2)
U = FunctionSpace(mesh, 'Lagrange', 2)
V = VectorFunctionSpace(mesh, 'Lagrange', 2)
W = TensorFunctionSpace(mesh, 'Lagrange', 2, shape=(2,4,3))
u = Function(U)
v = Function(V)
w = Function(W)
def element_wise(expr, func):
if not expr.ufl_shape:
return as_tensor(func(expr))
else:
def build_matrix(expr, func, idx=tuple(), axis=0):
if axis == len(expr.ufl_shape) - 1:
return [func(expr[idx+(i,)]) for i in range(expr.ufl_shape[axis])]
else:
return [build_matrix(expr, func, idx+(i,), axis+1) for i in range(expr.ufl_shape[axis])]
return as_tensor(build_matrix(expr, func))
# Example 1: `exp` of a scalar Function
u_exp = element_wise(u, exp)
print(u_exp.ufl_shape)
# Example 2: element-wise `sqrt` of a vector Function
v_sqrt = element_wise(v, sqrt)
print(v_sqrt.ufl_shape)
# Example 3: tensor Function squared element-wise
w_squared = element_wise(w, lambda x: x**2)
print(w_squared.ufl_shape)
# Example 4: element-wise square of symmetric gradient of a vector Function
b = as_tensor([[1,2,3],
[4,5,6],
[7,8,9]])
E = sym(grad(v))
E_squared = element_wise(E, lambda x: x**2)
print(E_squared.ufl_shape)
Q = b[i, j] * element_wise(E_squared, lambda x: x**2)[i,j]
print(Q.ufl_shape)
producing
()
(2,)
(2, 4, 3)
(2, 2)
()
Note that you should apply free indexing after using element_wise, i.e.
Q = b[i, j] * element_wise(E_squared, lambda x: x**2)[i,j]
not
Q = b[i, j] * element_wise(E_squared[i,j], lambda x: x**2)