Layered Solid Element in fenicsx?

I have a problem of a composite plate where the properties keep changing in every layer. I know I can create multiple sub-domains and apply the properties accordingly.
But if I have too many layers (>200), the number of elements become too large and so does the computational time.

I came across a layered solid element like SOLID185 in ansys where inside a single element I can have multiple integration layers through the thickness.

How can I implement this in fenicsx??

Thanks!

I would suggest using a standard function space (P1) on hexahedra, and use a high order quadrature space for your material (maybe with custom points) to specify an «overintegration» per element to capture the material variation.

How do I define a custom quadrature space??

The below code does not let me create an element using custom quadrature. (dolfinx = ‘0.8.0’)

Q_element = basix.ufl.quadrature_element(
    domain.basix_cell(),
    value_shape=(6, 6),
    scheme="gauss_jacobi",degree = deg_quad)
Q = fem.functionspace(domain, Q_element)

But I can specify my custom points here. What does this actually do??

ufl.Measure("dx" , domain = domain , metadata={"quadrature_scheme": "custom", "quadrature_points": [[1.0, 0.5], ...], "quadrature_weights": [1.0, ...]})

Here is a minimal example:

import dolfinx.fem.petsc
from mpi4py import MPI
import dolfinx
import basix.ufl
import ufl

mesh = dolfinx.mesh.create_unit_cube(
    MPI.COMM_WORLD, 10, 10, 10, cell_type=dolfinx.mesh.CellType.hexahedron
)

q_points, q_weights = basix.make_quadrature(
    mesh.basix_cell(), 5, basix.QuadratureType.gll
)

el = basix.ufl.quadrature_element(mesh.basix_cell(), points=q_points, weights=q_weights)
Q = dolfinx.fem.functionspace(mesh, el)
q = dolfinx.fem.Function(Q)
q.interpolate(lambda x: x[0] + x[1] + x[2])

V = dolfinx.fem.functionspace(mesh, ("CG", 1))
u = ufl.TrialFunction(V)
v = ufl.TestFunction(V)
a = q * ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx
dolfinx.fem.petsc.assemble_matrix(dolfinx.fem.form(a))


import matplotlib.pyplot as plt

ax = plt.figure().add_subplot(projection="3d")
ax.scatter(q_points[:, 0], q_points[:, 1], q_points[:, 2])
plt.savefig("gll_points.png")

you can make value_shape whatever tensor the data you have is.

As long as you have a quadrature element in the form, you do not need to change the integration measure, as it picks up the degree when compiling the form.

Thank you! This works for me.

I have one more doubt

  1. For a complex case, where the number of layers in my composite plate model are not constant everywhere. Eg. region A has 10 layers, B has 4 layers, C has 7 layers. Can I define different quad points for each region? say ( 2 * 2 * 10 ) for A, ( 2 * 2 * 4 ) for B, ( 2 * 2 * 7 ) for C.

It is not straightforward to do that at the moment.
What you could do is to split the integrals into regions, depending on the number of layers in each region, and have a quadrature space describing the material coefficient in each of those layers with its own quadrature rule.

Thanks a lot! I’ll try that