Different results for the same mesh created differently (Hyperelasticity)

Hi
I am solving a hyperelasticity problem. The domain is a simple unit cube including 6 elements (1 element on each edge) which is fixed from the left face and a pressure is applied on the right face. I created the mesh using 2 different approaches. In the first approach I used FEniCS built-in function. In the second approach I made exactly the same mesh in GMSH and imported into the FEniCS. Here is the code when mesh was built in FEniCS:

from dolfin import *

class Left(SubDomain):
    def inside(self, x, on_boundary):
        return abs(x[0] - 0.0) < DOLFIN_EPS and on_boundary

class Right(SubDomain):
    def inside(self, x, on_boundary):
        return abs(x[0] - 1.0) < DOLFIN_EPS and on_boundary

mesh = UnitCubeMesh.create(1,1,1,CellType.Type.tetrahedron)
#mesh = BoxMesh(Point(0, 0, 0), Point(1, 1, 1), 1, 1, 1)

left = Left()
right = Right()

boundaries = MeshFunction('size_t', mesh, mesh.topology().dim()-1)
subdomains = MeshFunction('size_t', mesh, mesh.topology().dim())
n = FacetNormal(mesh)

boundaries.set_all(0)
left.mark(boundaries, 1)
right.mark(boundaries, 2)

V = VectorFunctionSpace(mesh, 'CG', degree=2)

du  = TrialFunction(V)           # Trial function
v  = TestFunction(V)             # Test function
u  = Function(V)

dx = Measure('dx', domain=mesh, subdomain_data=subdomains, metadata={'quadrature_degree': 2})
ds = Measure('ds', domain=mesh, subdomain_data=boundaries, metadata={'quadrature_degree': 2})

d = u.geometric_dimension()
I = Identity(d)             # Identity tensor
F = I + grad(u)             # Deformation gradient
C = F.T*F
Ic = tr(C)
J  = det(F)
Ic_bar = pow(J,-2./3.)*Ic

K =  1E6

Pressure = Constant((1.))
c_1 = 10.

psi = c_1 * (Ic_bar - 3.) * dx + 0.5 *  K * pow(ln(J),2) * dx - inner(Pressure * n, u) * ds(2)

F1 = derivative(psi, u, v)
# Compute Jacobian of F
Jac = derivative(F1, u, du)

bc_1 = DirichletBC(V, Constant((0., 0., 0.)), boundaries, 1)
bcs = [bc_1]

problem = NonlinearVariationalProblem(F1, u, bcs, Jac)
solver = NonlinearVariationalSolver(problem)
solver.solve()

File("fenics.pvd") << u

Here is the geo file of the GMSH:

// Gmsh  

Point(1) = {0, 0, 0,1};
Point(2) = {0, 1, 0,1};
Point(3) = {0, 0, 1,1};
Point(4) = {0, 1, 1,1};
Point(5) = {1, 0, 0,1};
Point(6) = {1, 1, 0,1};
Point(7) = {1, 0, 1,1};
Point(8) = {1, 1, 1,1};
Line(1) = {1, 3};
Line(2) = {7, 3};
Line(3) = {7, 5};
Line(4) = {5, 1};
Line(5) = {1, 2};
Line(6) = {2, 4};
Line(7) = {4, 3};
Line(8) = {2, 6};
Line(9) = {6, 8};
Line(10) = {8, 4};
Line(11) = {6, 5};
Line(12) = {8, 7};
Line Loop(13) = {8, 9, 10, -6};
Plane Surface(14) = {13};
Line Loop(15) = {8, 11, 4, 5};
Plane Surface(16) = {15};
Line Loop(17) = {6, 7, -1, 5};
Plane Surface(18) = {17};
Line Loop(19) = {4, 1, -2, 3};
Plane Surface(20) = {19};
Line Loop(21) = {11, -3, -12, -9};
Plane Surface(22) = {21};
Line Loop(23) = {7, -2, -12, 10};
Plane Surface(24) = {23};
Surface Loop(25) = {14, 16, 22, 20, 18, 24};
Volume(26) = {25};


Transfinite Surface {14,16,18,20,22,24};
Transfinite Line{1,2,3,4,5,6,7,8,9,10,11,12}=2;
Physical Volume(29) = {26};

// LEFT BOUNDARY
Physical Surface(1) = {18};

// RIGHT BOUNDARY
Physical Surface(2) = {22};

and this is the FEniCS code when the mesh is imported from GMSH:

from dolfin import *

mesh = Mesh("MESH.xml")
boundaries = MeshFunction("size_t", mesh, "MESH_facet_region.xml")
subdomains = MeshFunction("size_t", mesh, "MESH_physical_region.xml")

n = FacetNormal(mesh)

V = VectorFunctionSpace(mesh, 'CG', degree=2)

du  = TrialFunction(V)           # Trial function
v  = TestFunction(V)             # Test function
u  = Function(V)

dx = Measure('dx', domain=mesh, subdomain_data=subdomains, metadata={'quadrature_degree': 2})
ds = Measure('ds', domain=mesh, subdomain_data=boundaries, metadata={'quadrature_degree': 2})

d = u.geometric_dimension()
I = Identity(d)             # Identity tensor
F = I + grad(u)             # Deformation gradient
C = F.T*F
Ic = tr(C)
J  = det(F)
Ic_bar = pow(J,-2./3.)*Ic

K =  1E6

# Total potential energy
Pressure = Constant((1))
c_1 = 10.

psi = c_1 * (Ic_bar - 3.)  * dx + 0.5 *  K * pow(ln(J),2) * dx - inner(Pressure * n, u) * ds(2)

F1 = derivative(psi, u, v)

# Compute Jacobian of F
Jac = derivative(F1, u, du)

bc_1 = DirichletBC(V, Constant((0., 0., 0.)), boundaries, 1)
bcs = [bc_1]

problem = NonlinearVariationalProblem(F1, u, bcs, Jac)
solver = NonlinearVariationalSolver(problem)
solver.solve()

File("gmsh.pvd") << u

If we look into the results, we can see that the results are significantly different. For example this is displacement contour in Z direction:

As it was shown, the results are completely different while I expect the same results as everything are the same in 2 approaches. The only difference is the way the mesh has been created. Even if we increase the polynomial order from 1 to 2, the results are still different.
It is confusing why the results for such a simple mesh are not matched. Does anybody have any idea what is wrong in here?

I claim that the meshes are not the same, see attached picture:

}
I would also recommend you not to use xml to load meshes, as it has been deprecated for a while. The suggested way of converting a mesh from gmsh is by using meshio.

Also, to make sure that your visualization is P2 data is saved, use xdmf.write_checkpoint.
Here is a script doing all of the suggested actions:

from dolfin import *
import meshio
import numpy as np
class Left(SubDomain):
    def inside(self, x, on_boundary):
        return abs(x[0] - 0.0) < DOLFIN_EPS and on_boundary

class Right(SubDomain):
    def inside(self, x, on_boundary):
        return abs(x[0] - 1.0) < DOLFIN_EPS and on_boundary


def problem(gmsh=True):
    if gmsh:
        msh = meshio.read("mesh.msh")
        points = msh.points
        cells = np.vstack([cells.data for cells in msh.cells
                           if cells.type == "tetra"])
        cell_data = np.vstack([msh.cell_data_dict["gmsh:physical"][key]
                            for key in
                            msh.cell_data_dict["gmsh:physical"].keys()
                            if key =="tetra"])
        mesh = meshio.Mesh(points=points,
                           cells=[("tetra", cells)],
                           cell_data={"name_to_read": cell_data})
        meshio.write("mesh.xdmf", mesh)


        # Write line mesh
        facet_cells = np.vstack([cells.data for cells in msh.cells
                                 if cells.type == "triangle"])
        facet_data = np.vstack([msh.cell_data_dict["gmsh:physical"][key]
                             for key in
                             msh.cell_data_dict["gmsh:physical"].keys()
                                 if key == "triangle"])

        facet_mesh = meshio.Mesh(points=points,
                             cells=[("triangle", facet_cells)],
                             cell_data={"name_to_read": facet_data})
        meshio.write("boundaries.xdmf", facet_mesh)

        mesh = Mesh()
        with XDMFFile("mesh.xdmf") as infile:
            infile.read(mesh)
            mvcv = MeshValueCollection("size_t", mesh, mesh.topology().dim())
            infile.read(mvcv, "name_to_read")
        subdomains = cpp.mesh.MeshFunctionSizet(mesh, mvcv)
        mvc = MeshValueCollection("size_t", mesh, mesh.topology().dim()-1)
        with XDMFFile("boundaries.xdmf") as infile:
            infile.read(mvc, "name_to_read")
        boundaries = cpp.mesh.MeshFunctionSizet(mesh, mvc)

    else:
        mesh = UnitCubeMesh.create(1,1,1,CellType.Type.tetrahedron)
        left = Left()
        right = Right()

        boundaries = MeshFunction('size_t', mesh, mesh.topology().dim()-1)
        subdomains = MeshFunction('size_t', mesh, mesh.topology().dim())

        boundaries.set_all(0)
        left.mark(boundaries, 1)
        right.mark(boundaries, 2)

    n = FacetNormal(mesh)

    V = VectorFunctionSpace(mesh, 'CG', degree=2)

    du  = TrialFunction(V)           # Trial function
    v  = TestFunction(V)             # Test function
    u  = Function(V)

    dx = Measure('dx', domain=mesh, subdomain_data=subdomains, metadata={'quadrature_degree': 2})
    ds = Measure('ds', domain=mesh, subdomain_data=boundaries, metadata={'quadrature_degree': 2})

    d = u.geometric_dimension()
    I = Identity(d)             # Identity tensor
    F = I + grad(u)             # Deformation gradient
    C = F.T*F
    Ic = tr(C)
    J  = det(F)
    Ic_bar = pow(J,-2./3.)*Ic

    K =  1E6

    # Total potential energy
    Pressure = Constant((1))
    c_1 = 10.

    psi = c_1 * (Ic_bar - 3.)  * dx + 0.5 *  K * pow(ln(J),2) * dx - inner(Pressure * n, u) * ds(2)

    F1 = derivative(psi, u, v)

    # Compute Jacobian of F
    Jac = derivative(F1, u, du)

    bc_1 = DirichletBC(V, Constant((0., 0., 0.)), boundaries, 1)
    bcs = [bc_1]

    problem = NonlinearVariationalProblem(F1, u, bcs, Jac)
    solver = NonlinearVariationalSolver(problem)
    solver.solve()
    if gmsh:
         XDMFFile("gmsh.xdmf").write_checkpoint(u,"u",0, append=False)
    else:
         XDMFFile("built_in.xdmf").write_checkpoint(u,"u",0,append=False)

problem(True)
problem(False)
3 Likes

Thanks dokken for your response. There are 2 questions in here:
1 - If I use GMSH the msh file (created in GMSH) I get this error:

  File "", line 108, in <module>
    problem(True)
  File "", line 17, in problem
    cells = np.vstack([cells.data for cells in msh.cells
  File "", line 18, in <listcomp>
    if cells.type == "tetra"])
AttributeError: 'str' object has no attribute 'type'

How can I resolve it?

2 - If I use the built-in mesh from FEniCS, it works fine without error and creates 2 files including buit_in.h5 and built_in.xdmf. So how can I visualize the results in Paraview? Sorry but I am not that familiar with xdmf format
Thanks!

I just copied your geo file and it seems to work fine without any problems, namely

fileString = r"""
// Gmsh  

Point(1) = {0, 0, 0,1};
Point(2) = {0, 1, 0,1};
Point(3) = {0, 0, 1,1};
Point(4) = {0, 1, 1,1};
Point(5) = {1, 0, 0,1};
Point(6) = {1, 1, 0,1};
Point(7) = {1, 0, 1,1};
Point(8) = {1, 1, 1,1};
Line(1) = {1, 3};
Line(2) = {7, 3};
Line(3) = {7, 5};
Line(4) = {5, 1};
Line(5) = {1, 2};
Line(6) = {2, 4};
Line(7) = {4, 3};
Line(8) = {2, 6};
Line(9) = {6, 8};
Line(10) = {8, 4};
Line(11) = {6, 5};
Line(12) = {8, 7};
Line Loop(13) = {8, 9, 10, -6};
Plane Surface(14) = {13};
Line Loop(15) = {8, 11, 4, 5};
Plane Surface(16) = {15};
Line Loop(17) = {6, 7, -1, 5};
Plane Surface(18) = {17};
Line Loop(19) = {4, 1, -2, 3};
Plane Surface(20) = {19};
Line Loop(21) = {11, -3, -12, -9};
Plane Surface(22) = {21};
Line Loop(23) = {7, -2, -12, 10};
Plane Surface(24) = {23};
Surface Loop(25) = {14, 16, 22, 20, 18, 24};
Volume(26) = {25};


Transfinite Surface {14,16,18,20,22,24};
Transfinite Line{1,2,3,4,5,6,7,8,9,10,11,12}=2;
Physical Volume(29) = {26};

// LEFT BOUNDARY
Physical Surface(1) = {18};

// RIGHT BOUNDARY
Physical Surface(2) = {22};
"""

with open("geofile.geo", "w") as fil:
    fil.write(fileString)

import os, meshio, numpy as np
os.system("gmsh -3 geofile.geo -o geofile.msh")
msh = meshio.read("geofile.msh")

msh.points
# array([[0., 0., 0.],
#        [0., 1., 0.],
#        [0., 0., 1.],
#        [0., 1., 1.],
#        [1., 0., 0.],
#        [1., 1., 0.],
#        [1., 0., 1.],
#        [1., 1., 1.]])

cellsMesh = np.vstack([
    cell.data for cell in msh.cells if cell.type == "tetra"
])
# array([[3, 5, 0, 1],
#        [2, 7, 0, 3],
#        [5, 3, 0, 7],
#        [7, 2, 0, 6],
#        [7, 6, 0, 4],
#        [0, 5, 7, 4]])

You should be able to open the built_in.xdmf file in Paraview without any problems.

1 Like

Hi
The previous error was solved by uninstalling and installing the meshio.
Now another issue comes up when using the mesh from the gmsh. Here is the error:

/usr/local/lib/python3.5/dist-packages/h5py/__init__.py:40: UserWarning: h5py is running against HDF5 1.8.16 when it was built against 1.10.4, this may cause problems
  '{0}.{1}.{2}'.format(*version.hdf5_built_version_tuple)
Warning! ***HDF5 library version mismatched error***
The HDF5 header files used to compile this application do not match
the version used by the HDF5 library to which this application is linked.
Data corruption or segmentation faults may occur if the application continues.
This can happen when an application was compiled by one version of HDF5 but
linked with a different version of static or shared HDF5 library.
You should recompile the application or check your shared library related
settings such as 'LD_LIBRARY_PATH'.
You can, at your own risk, disable this warning by setting the environment
variable 'HDF5_DISABLE_VERSION_CHECK' to a value of '1'.
Setting it to 2 or higher will suppress the warning messages totally.
Headers are 1.10.4, library is 1.8.16
	    SUMMARY OF THE HDF5 CONFIGURATION
	    =================================

General Information:
-------------------
		   HDF5 Version: 1.8.16
		  Configured on: Tue Aug 28 18:30:08 UTC 2018
		  Configured by: buildd@lgw01-amd64-024
		 Configure mode: production
		    Host system: x86_64-pc-linux-gnu
	      Uname information: Linux lgw01-amd64-024 4.4.0-128-generic #154-Ubuntu SMP Fri May 25 14:15:18 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
		       Byte sex: little-endian
		      Libraries: static, shared
	     Installation point: /usr
		    Flavor name: openmpi

I removed h5py and installed it again but still I am getting the same error. Do you have any idea how I might resolve it?
Thanks again

Try : Gmsh 4.4.1 in FEniCS? Meshio

1 Like

Uninstalling and re-installing the h5py resolved the issue:

sudo pip3 uninstall h5py
pip3 install --no-binary=h5py h5py --user

Thanks for the sample code you proposed. Now it works fine.