Creating custom anisotropic Lagrange element

Hi all,

I am trying to use Basix for building a custom anisotropic finite element defined, in a rectangle, as product of order 2 elements in the x variable and order 1 elements in the y variable. Specifically, this element will be defined by evaluating Lagrange polynomials on the following points:

o---o---o
|       |
|       |
o---o---o

We have the following set of polynomials spanned by each element: { 1, y, x, xy, x^2, x^2y }.

For that, I followed the steps in Creating a custom element — Basix 0.10.0.0 documentation.

First, we define the following 6x9 matrix to store the coefficients

import numpy as np
wcoeffs = np.zeros((6,9))
wcoeffs[0,0] = 1
wcoeffs[1,1] = 1
wcoeffs[2,3] = 1
wcoeffs[3,4] = 1
wcoeffs[4,6] = 1
wcoeffs[5,7] = 1

The Ciarlet functionals are, in this case, evaluations at the 4 corners and 2 edges of the quadrilateral.

#
# Nodes:
#
x = [ [], [], [], [] ]
# Corners 
x[0].append(np.array([[0.0, 0.0]]))
x[0].append(np.array([[1.0, 0.0]]))
x[0].append(np.array([[0.0, 1.0]]))
x[0].append(np.array([[1.0, 1.0]]))

# Edges
x[1].append(np.array([[0.5, 0.0]]))
x[1].append(np.array([[0.5, 1.0]]))
x[1].append(np.zeros((0,2)))
x[1].append(np.zeros((0,2)))

# Empty array of points inside the 2d cell
x[2].append(np.zeros((0,2)))

As all the DOFs are point evaluations the matrices are all identity matrices for the entities that have a point:

M = [ [], [], [], [] ]
# 4 corners
for _ in range(4):
  M[0].append(np.array([[[[1.0]]]]))
# 2 edges
M[1].append(np.array([[[[1.0]]]]))
M[1].append(np.array([[[[1.0]]]]))
M[1].append(np.zeros((0, 1, 0, 1)))
M[1].append(np.zeros((0, 1, 0, 1)))
# Inside cell
M[2].append(np.zeros((0, 1, 0, 1)))

Now we create the element

import dolfinx
import basix
from basix import CellType, MapType, SobolevSpace, PolysetType
import basix.ufl
P2xP1 = basix.ufl.custom_element(
  cell_type=CellType.quadrilateral,
  reference_value_shape=[],
  wcoeffs=wcoeffs,
  x=x,
  M=M,
  interpolation_nderivs=0,
  map_type=MapType.identity,
  sobolev_space=SobolevSpace.H1,
  discontinuous=False,
  embedded_subdegree=1,
  embedded_superdegree=2,
  polyset_type=PolysetType.standard,
)

And compute the matrix for a Poisson problem in a single cell (a 1x1 mesh)

from mpi4py import MPI
from dolfinx import fem, mesh
import ufl
from ufl import dx, grad, inner
msh = mesh.create_rectangle(
    comm=MPI.COMM_WORLD,
    points=((0.0, 0.0), (1.0, 1.0)),
    n=(1,1),
    cell_type=mesh.CellType.quadrilateral,
)
V = fem.functionspace(msh, P2xP1) 
u = ufl.TrialFunction(V)
v = ufl.TestFunction(V)
a = inner(grad(u), grad(v)) * dx

# Matrix
import scipy
A=dolfinx.fem.assemble_matrix(dolfinx.fem.form(a))
As = scipy.sparse.csr_matrix((A.data, A.indices, A.indptr))
def my_print(A, float_formatter = "{:.1f}".format):
  np.set_printoptions(formatter={'float_kind':float_formatter})
  print(A)
A_arr = As.toarray()
print("Matrix shape:", A_arr.shape)
my_print(A_arr)

According to the number of degrees of freedom for this the element, I expected a 6x6 matrix. But, unexpectedly, I obtain a 8x6 matrix, where the two extra rows are composed by zeros. In particular, this the result of running the minimal script defined above:

Matrix shape: (8, 6)
[[0.9 0.1 0.3 0.1 -0.8 -0.5]
 [0.1 0.9 0.1 0.3 -0.8 -0.5]
 [0.3 0.1 0.9 0.1 -0.5 -0.8]
 [0.1 0.3 0.1 0.9 -0.5 -0.8]
 [-0.8 -0.8 -0.5 -0.5 2.3 0.4]
 [-0.5 -0.5 -0.8 -0.8 0.4 2.3]
 [0.0 0.0 0.0 0.0 0.0 0.0]
 [0.0 0.0 0.0 0.0 0.0 0.0]]

Any help would be appreciated!
Thanks!

Hello,

There’s likely as assumption somewhere in Basix that each edge has the same number of DOFs associated with it. I’ll take a look and see if I can work out where this is (and how much stuff will break if I remove this assumption).

Hello again,

I have been testing a simpler anisotropic custom element, in this case the basis functions are constant (P0) in the x variable and order 1 polynomials (P1) in the y variable. That is, the element is defined by evaluating Lagrange polynomials on the following points:

----o----
|       |                                                  
|       |
----o----

Again, if I use Basix to compute the a FE matrix corresponding in a mesh defined by only one cell (the unit square), I obtain two rows more than expected.

Specifically, I expected a 2x2 matrix (the same than for P1 elements in an 1-dimensional interval in the y-axis, as the element is constant in the x-axis).

But, I obtain a 4x2 matrix, where again the two extra rows are composed by zeros!

Matrix shape: (4, 2)
[[1.0 -1.0]
 [-1.0 1.0]
 [0.0 0.0]
 [0.0 0.0]]

Interestingly, the elements of the matrix appear to be correct for a Laplace 1-d matrix. Maybe if there were any right way for “cutting” these two extra rows, everything would be solved…
Thank you!!

By the way: is there any way in Dolfinx for removing rows in a Matrix?

Maybe that would let me let cutting the two extra zero-rows and then building the linear system corresponding to my problem and then solving it (I am trying to program anisotropic Stokes elements).

Thanks again!

Rafa