Domain with multiple different orthotropic materials in dolphinx

Hi everyone, Hi interested,

I trying to build some example to experiment and learn how to approach problems with multiple domains.
Therefore, I would like to build a stackup of different materials with different behaviours.

This is done with the following code:

Define the material stackup

from pymaterial.materials import IsotropicMaterial, TransverselyIsotropicMaterial, OrthotropicMaterial

mat0 = {
    "name": "steal",
    "thickness": 0.3,
    "stiff_tens": IsotropicMaterial(Em=2e11,nu=0.3, density=7850).get_stiffness() # from ANSYS
}

mat2 = {
    "name": "E-glass",
    "thickness": 0.3,
    "stiff_tens": OrthotropicMaterial(E_x=4.5e10, 
                                       E_y=1e10, 
                                       E_z=1e10, 
                                       nu_xy=0.3, 
                                       nu_yz=0.4, 
                                       nu_xz=0.3,
                                       G_xy=5e9,
                                       G_yz=3.8462e9,
                                       G_xz=5e9,
                                       density=2000
                                       ).get_stiffness() # from ANSYS Epoxy E-Glass UD
}

mat3 = {
    "name": "carbon fibre",
    "thickness": 0.3,
    "stiff_tens": OrthotropicMaterial(E_x=2.3e11, 
                                      E_y=2.3e10, 
                                      E_z=2.3e10, 
                                      nu_xy=0.2, 
                                      nu_yz=0.4, 
                                      nu_xz=0.2,
                                      G_xy=9e9,
                                      G_yz=8.2143e9,
                                      G_xz=9e9,
                                      density=1800
                                      ).get_stiffness() # from ANSYS Carbon Fiber (230 GPa)
}


stack = [
    mat1, 
    mat2, 
    mat3
    ]

Build the model and load it into fenics

import numpy as np
import gmsh
from mpi4py import MPI


gmsh.initialize()
model = gmsh.model()
name = "Material Stack"

model.add(name)
model.setCurrent(name)

width, length = 1, 1
thickness = 0
gdim = 3  # Geometric dimension of the mesh
model_rank = 0
mesh_comm = MPI.COMM_WORLD

if mesh_comm.rank == model_rank:
    boxes = []
    coms = []
    for i in range(len(stack)):
        elem = stack[i]
        elem_thickness = elem["thickness"]
        start_height = thickness
        end_height = thickness + elem_thickness
        boxes.append(model.occ.addBox(0, 0, start_height, width, length, elem_thickness))
        thickness = end_height
        coms.append([width/2, length/2, start_height + elem_thickness/2])
    
    model.occ.synchronize()
        
    for i in range(len(boxes)-1):
        model.occ.fragment([(3,boxes[i])], [(3,boxes[i+1])])

    for dim_,id_ in model.getEntities(3):
        com = gmsh.model.occ.getCenterOfMass(dim_, id_)
        # print(com)
        for i in range(len(coms)):
            if not np.allclose(com, coms[i]):
                continue
            tag = i
            model.addPhysicalGroup(3, [id_], tag=tag)
            model.setPhysicalName(3, tag, stack[i]["name"])
            break
    model.mesh.generate(dim=3)
    # gmsh.model.mesh.optimize("Netgen")

# Create DOLFINx distributed mesh
from dolfinx.io.gmshio import model_to_mesh
mesh, cell_markers, facet_markers = model_to_mesh(model, mesh_comm, model_rank)
gmsh.finalize()

Defining the problem

In the particular case one approach would be to define a Tensorfunction which represents the stiffness tensor C.
Like:

import ufl

def epsilon(u):
    return ufl.sym(ufl.grad(u)) # Equivalent to 0.5*(ufl.nabla_grad(u) + ufl.nabla_grad(u).T)

def strain2voigt(e):
    """e is a 2nd-order tensor, returns its Voigt vectorial representation"""
    return ufl.as_vector([e[0,0],e[1,1],2*e[0,1]])


def voigt2stress(s):
    """
    s is a stress-like vector (no 2 factor on last component)
    returns its tensorial representation
    """
    return ufl.as_tensor([[s[0], s[2]],
                     [s[2], s[1]]])
def sigma(u):
    return voigt2stress(ufl.dot(stiff_tens, strain2voigt(epsilon(u))))

and

from dolfinx.fem import VectorFunctionSpace, TrialFunction, TestFunction
import ufl

V = VectorFunctionSpace(mesh, ('Lagrange', 1))

# Define variational problem
u = ufl.TrialFunction(V)
v = ufl.TestFunction(V)
u = Function(V, name='Displacement')
a = ufl.inner(sigma(u), epsilon(v))* ufl.dx

The problem: generating the spacial dependent tensor function

But whatever I tried to build such a tensor function it did not work:

from dolfinx.fem import TensorFunctionSpace, Function, Constant
import ufl
from petsc4py.PETSc import ScalarType

Q = TensorFunctionSpace(mesh, ("CG", 2))  # CG-Lagrange element, 2-degree of freedom (2nd order element)
stiff_tens=Function(Q)# often symbolized by "C"
material_tags = np.unique(cell_markers.values)
for tag in material_tags:
    cells = cell_markers.find(tag)
    if tag < len(stack):
        material = stack[i]
        stiff_tens.x.array[cells]=np.array(list([material["stiff_tens"]])*len(cells), dtype=ScalarType)

which throws the following error:

ValueError                                Traceback (most recent call last)
Cell In[61], line 12
     10 if tag < len(stack):
     11     material = stack[i]
---> 12     stiff_tens.x.array[cells]=np.array(list([material["stiff_tens"]])*len(cells), dtype=ScalarType)

ValueError: shape mismatch: value array of shape (402,6,6) could not be broadcast to indexing result of shape (402,)

Another question:

dolphin had something called Subdomains, where I could also define other partial differential equations on. For me this means that I could perform the integration with one stiffness tensor over each material domain separetly and then add all matrices together. How would this look in dolphinx or is this not possible?

Thanks in advance!

First I have to fix some small mistakes, I made in my post above and because I did not find an edit option I post my fixes here:

The model creation was missing a sync

import numpy as np
import gmsh
from mpi4py import MPI


gmsh.initialize()
model = gmsh.model()
name = "Battery Stack"

model.add(name)
model.setCurrent(name)

width, length = 1, 1
thickness = 0
gdim = 3  # Geometric dimension of the mesh
model_rank = 0
mesh_comm = MPI.COMM_WORLD

if mesh_comm.rank == model_rank:
    boxes = []
    coms = []
    for i in range(len(stack)):
        elem = stack[i]
        elem_thickness = elem["thickness"]
        start_height = thickness
        end_height = thickness + elem_thickness
        boxes.append(model.occ.addBox(0, 0, start_height, width, length, elem_thickness))
        thickness = end_height
        coms.append([width/2, length/2, start_height + elem_thickness/2])
    
    model.occ.synchronize()
        
    for i in range(len(boxes)-1):
        model.occ.fragment([(3,boxes[i])], [(3,boxes[i+1])])
    model.occ.synchronize()  # <-- Inserted this to fix an issue with the mesh

    for dim_,id_ in model.getEntities(3):
        com = gmsh.model.occ.getCenterOfMass(dim_, id_)
        # print(com)
        for i in range(len(coms)):
            if not np.allclose(com, coms[i]):
                continue
            tag = i
            model.addPhysicalGroup(3, [id_], tag=tag)
            model.setPhysicalName(3, tag, stack[i]["name"])
            break
    model.mesh.generate(dim=3)
    # gmsh.model.mesh.optimize("Netgen")

# Create DOLFINx distributed mesh
from dolfinx.io.gmshio import model_to_mesh
mesh, cell_markers, facet_markers = model_to_mesh(model, mesh_comm, model_rank)
gmsh.finalize()

Voigt notation had to account for three dimensions

import ufl

def epsilon(u):
    return ufl.sym(ufl.grad(u)) # Equivalent to 0.5*(ufl.nabla_grad(u) + ufl.nabla_grad(u).T)

def strain2voigt(e, dim: int = 3):
    """e is a 2nd-order tensor, returns its Voigt vectorial representation"""
    if dim == 3:
        return ufl.as_vector([e[0,0],e[1,1],e[2,2],2*e[1,2], 2*e[0,2],2*e[0,1]])
    else:
        return ufl.as_vector([e[0,0],e[1,1],2*e[0,1]])


def voigt2stress(s, dim: int = 3):
    """
    s is a stress-like vector (no 2 factor on last component)
    returns its tensorial representation
    """
    if dim == 3:
        return ufl.as_tensor([
                              [s[0], s[5], s[4]],
                              [s[5], s[1], s[3]],
                              [s[4], s[3], s[2]]
                            ])
    else:
        return ufl.as_tensor([
                                [s[0], s[2]],
                                [s[2], s[1]]
                            ])
def sigma(u, stiff_tens):
    return voigt2stress(ufl.dot(stiff_tens, strain2voigt(epsilon(u))))

With the help of the following to post assemble matrix of subdomain I tried to assemble the stiffness matrix over each subdomain:

from dolfinx.fem import VectorFunctionSpace
import ufl
import dolfinx

V = VectorFunctionSpace(mesh, ('CG', 2)) # CG-Lagrange element, 2-degree of freedom (2nd order element)

# Define variational problem
u = ufl.TrialFunction(V)
v = ufl.TestFunction(V)

material_tags = np.unique(cell_markers.values)
stiffnesses = []
for tag in material_tags:
    cells = cell_markers.find(tag)
    if tag < len(stack):
        material = stack[tag]
        dx_domain = ufl.Measure('dx', domain=mesh, subdomain_data=cell_markers.find(tag), subdomain_id=tag)
        stiffness = ufl.as_matrix(material["stiff_tens"])
        a = ufl.inner(sigma(u, stiffness), epsilon(v))* dx_domain
        stiffnesses.append(a)

This worked (kind of) until I wanted to solve my problem:

from dolfinx.fem.petsc import LinearProblem


mat = stiffnesses
result = mat[0] + mat[1] + mat[2] # trying to add the different domains back together

problem = LinearProblem(result, L, bcs=[bc], petsc_options={"ksp_type": "preonly", "pc_type": "lu"})
uh = problem.solve()

results in:

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
Cell In[18], line 5
      3 mat = stiffnesses
      4 result = mat[0] + mat[1] + mat[2]
----> 5 problem = LinearProblem(result, L, bcs=[bc], petsc_options={"ksp_type": "preonly", "pc_type": "lu"})
      6 uh = problem.solve()

File /usr/local/dolfinx-complex/lib/python3.10/dist-packages/dolfinx/fem/petsc.py:566, in LinearProblem.__init__(self, a, L, bcs, u, petsc_options, form_compiler_options, jit_options)
    538 def __init__(self, a: ufl.Form, L: ufl.Form, bcs: typing.List[DirichletBCMetaClass] = [],
    539              u: typing.Optional[_Function] = None, petsc_options={}, form_compiler_options={}, jit_options={}):
    540     """Initialize solver for a linear variational problem.
    541 
    542     Args:
   (...)
    564                                                "pc_factor_mat_solver_type": "mumps"})
    565     """
--> 566     self._a = _create_form(a, form_compiler_options=form_compiler_options, jit_options=jit_options)
    567     self._A = create_matrix(self._a)
    569     self._L = _create_form(L, form_compiler_options=form_compiler_options, jit_options=jit_options)

File /usr/local/dolfinx-complex/lib/python3.10/dist-packages/dolfinx/fem/forms.py:176, in form(form, dtype, form_compiler_options, jit_options)
    173         return list(map(lambda sub_form: _create_form(sub_form), form))
    174     return form
--> 176 return _create_form(form)
...
--> 138     assert all([id(d) == id(data[0]) for d in data])
    139     subdomains[integral_type] = data[0]
    141 mesh = domain.ufl_cargo()

AssertionError: 

Can someone, PLEASE, tell me how to merge the matrixies of the different domains back together? OR is there a better way?

Additionally, I also tried to assemble each matrix before I add them together, but the code from the @dokken - tutorial did not work in this case:

import dolfinx

dolfinx.fem.petsc.assemble_matrix(mat[0], bcs=[bc])

returns:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[23], line 1
----> 1 dolfinx.fem.petsc.assemble_matrix(mat[0], bcs=[bc])

File /usr/lib/python3.10/functools.py:889, in singledispatch..wrapper(*args, **kw)
    885 if not args:
    886     raise TypeError(f'{funcname} requires at least '
    887                     '1 positional argument')
--> 889 return dispatch(args[0].__class__)(*args, **kw)

File /usr/local/dolfinx-complex/lib/python3.10/dist-packages/dolfinx/fem/petsc.py:340, in assemble_matrix(a, bcs, diagonal, constants, coeffs)
    336 @functools.singledispatch
    337 def assemble_matrix(a: typing.Any, bcs: typing.List[DirichletBCMetaClass] = [],
    338                     diagonal: float = 1.0,
    339                     constants=None, coeffs=None) -> PETSc.Mat:
--> 340     return _assemble_matrix_form(a, bcs, diagonal, constants, coeffs)

File /usr/local/dolfinx-complex/lib/python3.10/dist-packages/dolfinx/fem/petsc.py:351, in _assemble_matrix_form(a, bcs, diagonal, constants, coeffs)
    343 @assemble_matrix.register(FormMetaClass)
    344 def _assemble_matrix_form(a: form_types, bcs: typing.List[DirichletBCMetaClass] = [],
    345                           diagonal: float = 1.0,
    346                           constants=None, coeffs=None) -> PETSc.Mat:
    347     """Assemble bilinear form into a matrix. The returned matrix is not
    348     finalised, i.e. ghost values are not accumulated.
...

Did you forget to `#include `? Or ,
, , etc. Some automatic
conversions are optional and require extra headers to be included
when compiling your pybind11 module.

And the error message does not help me much.

Use a DG-0 function and interpolate the stiffness for each subdomain into the appropriate block of cells, e.g.:

import dolfinx as dfx
import numpy as np
import ufl
from mpi4py import MPI

# Create mesh and function space for stiffness tensor
mesh = dfx.mesh.create_unit_square(MPI.COMM_WORLD, 2, 1)
T = dfx.fem.TensorFunctionSpace(mesh, ("DG", 0), shape=(3, 3))
stiffness = dfx.fem.Function(T)

# Locate cells corresponding to each domain
tol = 1e-6
dom1 = dfx.mesh.locate_entities(mesh, mesh.topology.dim, lambda x: x[0] < 0.5 + tol)
dom2 = dfx.mesh.locate_entities(mesh, mesh.topology.dim, lambda x: x[0] > 0.5 - tol)

# Interpolate stiffnesses for each domain
def tensor(x, a):
    I = np.eye(3).reshape((3 * 3, 1))
    return np.broadcast_to(a * I, (3 * 3, x.shape[1]))
stiffness.interpolate(lambda x: tensor(x, 1.0), dom1)
stiffness.interpolate(lambda x: tensor(x, 2.0), dom2)

# Export the stiffness tensor for verification
with dfx.io.XDMFFile(MPI.COMM_WORLD, "stiffness.xdmf", "w") as xdmf:
    xdmf.write_mesh(mesh)
    xdmf.write_function(stiffness)

# Example usage in a bilinear form
def epsilon(u):
    return ufl.sym(ufl.grad(u))
def strain2voigt(e):
    return ufl.as_vector([e[0,0],e[1,1],2*e[0,1]])
V = dfx.fem.VectorFunctionSpace(mesh, ("CG", 1))
u = ufl.TrialFunction(V)
v = ufl.TestFunction(V)
a = ufl.inner(
    ufl.dot(ufl.as_matrix(stiffness), strain2voigt(epsilon(u))),
    strain2voigt(epsilon(v))
) * ufl.dx

Note that stiffness.interpolate requires a Python function that takes one argument, x, and returns an array of shape (tensor_size, x.shape[1]), where tensor_size is the size of your stiffness tensor. E.g. for the 3x3 stiffness matrix in my 2D example, the size is 3 \times 3 = 9.

2 Likes

Thank you so much!
For everyone interested, here is the complete code:

from pymaterial.materials import IsotropicMaterial, TransverselyIsotropicMaterial, OrthotropicMaterial
import numpy as np
import numpy as np
import gmsh
from mpi4py import MPI

mat0 = {
    "thickness": 0.3,
    "stiff_tens": IsotropicMaterial(Em=2e11,nu=0.3, density=7850).get_stiffness() # steel from ANSYS
}

mat1 = {
    "thickness": 0.3,
    "stiff_tens": OrthotropicMaterial(E_x=4.5e10, 
                                       E_y=1e10, 
                                       E_z=1e10, 
                                       nu_xy=0.3, 
                                       nu_yz=0.4, 
                                       nu_xz=0.3,
                                       G_xy=5e9,
                                       G_yz=3.8462e9,
                                       G_xz=5e9,
                                       density=2000
                                       ).get_stiffness() # from ANSYS Epoxy E-Glass UD
}

mat2 = {
    "thickness": 0.3,
    "stiff_tens": OrthotropicMaterial(E_x=2.3e11, 
                                      E_y=2.3e10, 
                                      E_z=2.3e10, 
                                      nu_xy=0.2, 
                                      nu_yz=0.4, 
                                      nu_xz=0.2,
                                      G_xy=9e9,
                                      G_yz=8.2143e9,
                                      G_xz=9e9,
                                      density=1800
                                      ).get_stiffness() # from ANSYS Carbon Fiber (230 GPa)
}


stack = [
    mat0, 
    mat1, 
    mat2
    ]

width, length = 1, 1
thickness = 0
gdim = 3  # Geometric dimension of the mesh
model_rank = 0
mesh_comm = MPI.COMM_WORLD

#=================
# generate mesh
#=================
gmsh.initialize()
model = gmsh.model()
name = "Battery Stack"

model.add(name)
model.setCurrent(name)
if mesh_comm.rank == model_rank:
    boxes = []
    coms = []
    for i in range(len(stack)):
        elem = stack[i]
        elem_thickness = elem["thickness"]
        start_height = thickness
        end_height = thickness + elem_thickness
        boxes.append(model.occ.addBox(0, 0, start_height, width, length, elem_thickness))
        thickness = end_height
        coms.append([width/2, length/2, start_height + elem_thickness/2])
    
    model.occ.synchronize()
        
    for i in range(len(boxes)-1):
        results = model.occ.fragment([(3,boxes[i])], [(3,boxes[i+1])])
        print(results)
    model.occ.synchronize()

    for dim_,id_ in model.getEntities(3):
        com = gmsh.model.occ.getCenterOfMass(dim_, id_)
        # print(com)
        for i in range(len(coms)):
            if not np.allclose(com, coms[i]):
                continue
            tag = i
            model.addPhysicalGroup(3, [id_], tag=tag)
            model.setPhysicalName(3, tag, stack[i]["name"])
            break
    model.mesh.generate(dim=3)
    # gmsh.model.mesh.optimize("Netgen")

# Create DOLFINx distributed mesh
from dolfinx.io.gmshio import model_to_mesh
mesh, cell_markers, facet_markers = model_to_mesh(model, mesh_comm, model_rank)
gmsh.finalize()

#=======================
# assemble siffness tensor
#=======================
material_tags = np.unique(cell_markers.values)
T = dolfinx.fem.TensorFunctionSpace(mesh, ("DG", 0), shape=(6, 6))
stiffness = dolfinx.fem.Function(T)

def tensor(x, tens):
    tens_reshaped = tens.reshape((6 * 6, 1))
    return np.broadcast_to(tens_reshaped, (6 * 6, x.shape[1]))

for tag in material_tags:
    domain = cell_markers.find(tag)
    if tag < len(stack):
        material = stack[tag]
        stiffness.interpolate(lambda x: tensor(x, material["stiff_tens"].astype(np.float32)), domain)

#=======================
# helpers
#=======================
def epsilon(u):
    return ufl.sym(ufl.grad(u)) # Equivalent to 0.5*(ufl.nabla_grad(u) + ufl.nabla_grad(u).T)

def strain2voigt(e, dim: int = 3):
    """e is a 2nd-order tensor, returns its Voigt vectorial representation"""
    if dim == 3:
        return ufl.as_vector([e[0,0],e[1,1],e[2,2],2*e[1,2], 2*e[0,2],2*e[0,1]])
    else:
        return ufl.as_vector([e[0,0],e[1,1],2*e[0,1]])


def voigt2stress(s, dim: int = 3):
    """
    s is a stress-like vector (no 2 factor on last component)
    returns its tensorial representation
    """
    if dim == 3:
        return ufl.as_tensor([
                              [s[0], s[5], s[4]],
                              [s[5], s[1], s[3]],
                              [s[4], s[3], s[2]]
                            ])
    else:
        return ufl.as_tensor([
                                [s[0], s[2]],
                                [s[2], s[1]]
                            ])
def sigma(u, stiff_tens):
    return voigt2stress(ufl.dot(stiff_tens, strain2voigt(epsilon(u))))
#=======================
# problem
#=======================
from dolfinx.fem import FunctionSpace
import ufl

element = ufl.VectorElement('CG', mesh.ufl_cell(), 2)# CG-Lagrange element, 2-degree of freedom (2nd order element)
V = FunctionSpace(mesh, element)

# Define variational problem
u = ufl.TrialFunction(V)
v = ufl.TestFunction(V)

a = ufl.inner(
    ufl.dot(ufl.as_matrix(stiffness), strain2voigt(epsilon(u))),
    strain2voigt(epsilon(v))
) * ufl.dx

#=======================
# loading
#=======================
from dolfinx.fem import Constant
from petsc4py.PETSc import ScalarType
import ufl


body_force = Constant(mesh, ScalarType((0, 0, 0))) # force on body

def surface_force(x):
    return np.isclose(x[1], length)

fdim = mesh.topology.dim - 1
traction_facets = dolfinx.mesh.locate_entities_boundary(mesh, fdim, surface_force)

traction = Constant(mesh, ScalarType((0, 10/((0.3*3)*width), 0))) # force on surface
ds = ufl.Measure("ds", domain=mesh)
L = ufl.inner(body_force, v) * ufl.dx + ufl.inner(traction, v) * ds

#=======================
# boundary conditions
#=======================
def clamped_boundary(x):
    return np.isclose(x[1], 0)

fdim = mesh.topology.dim - 1
boundary_facets = dolfinx.mesh.locate_entities_boundary(mesh, fdim, clamped_boundary)

u_D = np.array([0,0,0], dtype=ScalarType)
bc = dolfinx.fem.dirichletbc(u_D, dolfinx.fem.locate_dofs_topological(V, fdim, boundary_facets), V)

#=======================
# solve
#=======================
from dolfinx.fem.petsc import LinearProblem


problem = LinearProblem(a, L, bcs=[bc], petsc_options={"ksp_type": "preonly", "pc_type": "lu"})
uh = problem.solve()

#=======================
# export
#=======================
from dolfinx import io
from pathlib import Path

with io.XDMFFile(mesh.comm, Path("/home/fenics/shared/") / "output.xdmf", "w") as xdmf:
    xdmf.write_mesh(mesh)
    xdmf.write_meshtags(cell_markers)
    uh.name = "Deformation"
    xdmf.write_function(uh)

Why dont you use the symmetry=True flag of the TensorFunctionSpace?

No reason. If you want symmetry, you can use symmetry=True. There was an issue where symmetric tensors weren’t working, but it appears to be fixed.

1 Like

I think it is not fixed!
With:

import ufl
import dolfinx
import numpy as np
from petsc4py.PETSc import ScalarType


material_tags = np.unique(cell_markers.values)
T = dolfinx.fem.TensorFunctionSpace(mesh, ("DG", 0), shape=(6, 6), symmetry=True) # added symmetry flag
stiffness = dolfinx.fem.Function(T, dtype=ScalarType)

def tensor(x, tens):
    tens_reshaped = tens.reshape((6 * 6, 1))
    return np.broadcast_to(tens_reshaped, (6 * 6, x.shape[1]))

for tag in material_tags:
    domain = cell_markers.find(tag)
    if tag < len(stack):
        material = stack[tag]
        stiffness.interpolate(lambda x: tensor(x, material["stiff_tens"].astype(ScalarType)), domain)

and the the rest staying the same
I get a simillar looking issue, when trying to do:

from dolfinx.fem.petsc import LinearProblem


problem = LinearProblem(a, L, bcs=[bc], petsc_options={"ksp_type": "preonly", "pc_type": "lu"})
uh = problem.solve()
---------------------------------------------------------------------------
UFLException                              Traceback (most recent call last)
Cell In[29], line 4
      1 from dolfinx.fem.petsc import LinearProblem
----> 4 problem = LinearProblem(a, L, bcs=[bc], petsc_options={"ksp_type": "preonly", "pc_type": "lu"})
      5 uh = problem.solve()

File /usr/local/dolfinx-real/lib/python3.10/dist-packages/dolfinx/fem/petsc.py:566, in LinearProblem.__init__(self, a, L, bcs, u, petsc_options, form_compiler_options, jit_options)
    538 def __init__(self, a: ufl.Form, L: ufl.Form, bcs: typing.List[DirichletBCMetaClass] = [],
    539              u: typing.Optional[_Function] = None, petsc_options={}, form_compiler_options={}, jit_options={}):
    540     """Initialize solver for a linear variational problem.
    541 
    542     Args:
   (...)
    564                                                "pc_factor_mat_solver_type": "mumps"})
    565     """
--> 566     self._a = _create_form(a, form_compiler_options=form_compiler_options, jit_options=jit_options)
    567     self._A = create_matrix(self._a)
    569     self._L = _create_form(L, form_compiler_options=form_compiler_options, jit_options=jit_options)

File /usr/local/dolfinx-real/lib/python3.10/dist-packages/dolfinx/fem/forms.py:176, in form(form, dtype, form_compiler_options, jit_options)
    173         return list(map(lambda sub_form: _create_form(sub_form), form))
    174     return form
--> 176 return _create_form(form)
...
    133 "Write error message and raise an exception."
    134 self._log.error(*message)
--> 135 raise self._exception_type(self._format_raw(*message))

UFLException: Expecting pulled back expression with shape '(6, 6)', got '(21,)'

I have the latest docker image of dolfinx:stabel with:

Name: fenics-dolfinx
Version: 0.6.0
Summary: DOLFINx Python interface
Home-page: UNKNOWN
Author: FEniCS Project
Author-email: 
License: UNKNOWN
Location: /usr/local/dolfinx-complex/lib/python3.10/dist-packages
Requires: cffi, fenics-ffcx, fenics-ufl, mpi4py, numpy, petsc4py
Required-by:

and I am not sure in which version the fixed it

Ok. It seems like, the 6.0.0 version is several month old. and the fix was only added recently so its probably not implemented yet (June 2023). If I am mistaken, please correct me!

You can try the dolfinx/dolfinx:nightly docker image and see if the error goes away.

1 Like