Periodic boundary condition of rectangle unit cells

Dear all,
I’m practicing fenics base on the problem “Periodic homogenization of linear elastic materials”. In this example, the considered 2D plane strain problem deals with a skewed unit cell of dimensions 1×3–√/21×3/2 consisting of circular inclusions (numbered 11) of radius RR with elastic properties (Er,νr)(Er,νr) and embedded in a matrix material (numbered 00) of properties (Em,νm)(Em,νm) following an hexagonal pattern.

I’m trying to redo this example but consider a rectangle unit cell of dimension of 1xsqrt(3) as following:

The mesh of this problem is created using Gmsh with the geometry as following:

// Gmsh project created on Mon Sep 14 09:33:57 2015
a = 1.;
R = 0.2;
t = Pi/3;
b = 2*Sin(t)*a;


d = 1.;

nx = 80;
nR = R*nx;
ns = nx-2*nR;

Point(1) = {0, 0, 0, d};
Point(2) = {a, 0, 0, d};
Point(3) = {a, b, 0, d};
Point(4) = {c, b, 0, d};
Point(5) = {R,0,0,d};
Point(6) = {a-R,0,0,d};
Point(7) = {a,R,0,d};
Point(8) = {a,b-R,0,d};
Point(9) = {a-R,b,0,d};
Point(10) = {R,b,0,d};
Point(11) = {0,b-R,0,d};
Point(12) = {0,R,0,d};
Point(13) = {a/2,b/2,0,d};


Line(1) = {1, 5};
Line(2) = {5, 6};
Line(3) = {6, 2};
Line(4) = {2, 7};
Line(5) = {7, 8};
Line(6) = {8, 3};
Line(7) = {3, 9};
Line(8) = {9, 10};
Line(9) = {10, 4};
Line(10) = {4, 11};
Line(11) = {11, 12};
Line(12) = {12, 1};
Circle(13) = {5, 1, 12};
Circle(14) = {7, 2, 6};
Circle(15) = {9, 3, 8};
Circle(16) = {11, 4, 10};


Line Loop(19) = {1, 13, 12};
Plane Surface(20) = {19};
Line Loop(21) = {3, 4, 14};
Plane Surface(22) = {21};
Line Loop(23) = {7, 15, 6};
Plane Surface(24) = {23};
Line Loop(25) = {10, 16, 9};
Plane Surface(26) = {25};



Transfinite Line{1,3,4,6,7,9,10,12} = nR;
Transfinite Line{2,5,8,11} = ns;
Transfinite Line{14,16} = nR;
Transfinite Line{13,15} = nR;
Transfinite Line{18,19,20,17} = nR;

Periodic Line{1} = {9};
Periodic Line{2} = {8};
Periodic Line{3} = {7};
Periodic Line{4} = {12};
Periodic Line{5} = {11};
Periodic Line{6} = {10};

Physical Line(1) = {1,2,3};
Physical Line(2) = {4,5,6};
Physical Line(3) = {7,8,9};
Physical Line(4) = {10,11,12};

Physical Surface(0) = {18};
Physical Surface(1) = {20,22,24,26,27};


//+
Point(14) = {a/2+R, b/2, 0, 1.0};
//+
Point(15) = {a/2-R, b/2, 0, 1.0};
//+
Point(16) = {a/2, b/2-R, 0, 1.0};
//+
Point(17) = {a/2, b/2+R, 0, 1.0};

//+
Circle(17) = {14, 13, 17};
//+
Circle(18) = {17, 13, 15};
//+
Circle(19) = {15, 13, 16};
//+
Circle(20) = {16, 13, 14};
//+
Curve Loop(26) = {18, 19, 20, 17};
Plane Surface(27) = {26};//+
Curve Loop(17) = {11, -13, 2, -14, 5, -15, 8, -16};
//+
Plane Surface(18) = {26, 17};

//+
Transfinite Curve {17, 18, 19, 20} = nR Using Progression 1;

and then was mesh and implemented to fenics to solve the problem of Periodic homogenization of linear elastic materials with the code following:

from __future__ import print_function
from dolfin import *
import numpy as np
import matplotlib.pyplot as plt
%matplotlib notebook

a = 1.         # unit cell width
b = 1.         # unit cell height

R = 0.2        # inclusion radius
vol = a*b      # unit cell volume
# we define the unit cell vertices coordinates for later use
vertices = np.array([[0, 0.],
                     [a, 0.],
                     [a, b],
                     [0, b],
                     [a/2, b/2]])
mesh = Mesh()
with XDMFFile("homo_rec.xdmf") as in_file:
    in_file.read(mesh)
    mvc_cells = MeshValueCollection("size_t", mesh, mesh.topology().dim())
    in_file.read(mvc_cells, "name_to_read")
subdomains = cpp.mesh.MeshFunctionSizet(mesh, mvc_cells)
plot(subdomains)
plt.show()
# class used to define the periodic boundary map
class PeriodicBoundary(SubDomain):
    def __init__(self, vertices, tolerance=DOLFIN_EPS):
        """ vertices stores the coordinates of the 4 unit cell corners"""
        SubDomain.__init__(self, tolerance)
        self.tol = tolerance
        self.vv = vertices
        self.a1 = self.vv[1,:]-self.vv[0,:] # first vector generating periodicity
        self.a2 = self.vv[3,:]-self.vv[0,:] # second vector generating periodicity
        # check if UC vertices form indeed a parallelogram
        assert np.linalg.norm(self.vv[2, :]-self.vv[3, :] - self.a1) <= self.tol
        assert np.linalg.norm(self.vv[2, :]-self.vv[1, :] - self.a2) <= self.tol

    def inside(self, x, on_boundary):
        # return True if on left or bottom boundary AND NOT on one of the
        # bottom-right or top-left vertices
        return bool((near(x[0], self.vv[0,0] + x[1]*self.a2[0]/self.vv[3,1], self.tol) or
                     near(x[1], self.vv[0,1] + x[0]*self.a1[1]/self.vv[1,0], self.tol)) and
                     (not ((near(x[0], self.vv[1,0], self.tol) and near(x[1], self.vv[1,1], self.tol)) or
                     (near(x[0], self.vv[3,0], self.tol) and near(x[1], self.vv[3,1], self.tol)))) and on_boundary)

    def map(self, x, y):
        if near(x[0], self.vv[2,0], self.tol) and near(x[1], self.vv[2,1], self.tol): # if on top-right corner
            y[0] = x[0] - (self.a1[0]+self.a2[0])
            y[1] = x[1] - (self.a1[1]+self.a2[1])
        elif near(x[0], self.vv[1,0] + x[1]*self.a2[0]/self.vv[2,1], self.tol): # if on right boundary
            y[0] = x[0] - self.a1[0]
            y[1] = x[1] - self.a1[1]
        else:   # should be on top boundary
            y[0] = x[0] - self.a2[0]
            y[1] = x[1] - self.a2[1]
Em = 50e3
num = 0.2
Er = 210e3
nur = 0.3
material_parameters = [(Em, num), (Er, nur)]
nphases = len(material_parameters)
def eps(v):
    return sym(grad(v))
def sigma(v, i, Eps):
    E, nu = material_parameters[i]
    lmbda = E*nu/(1+nu)/(1-2*nu)
    mu = E/2/(1+nu)
    return lmbda*tr(eps(v) + Eps)*Identity(2) + 2*mu*(eps(v)+Eps)
Ve = VectorElement("CG", mesh.ufl_cell(), 2)
Re = VectorElement("R", mesh.ufl_cell(), 0)
W = FunctionSpace(mesh, MixedElement([Ve, Re]), constrained_domain=PeriodicBoundary())
V = FunctionSpace(mesh, Ve)

v_,lamb_ = TestFunctions(W)
dv, dlamb = TrialFunctions(W)
w = Function(W)
dx = Measure('dx')(subdomain_data=subdomains)

Eps = Constant(((0, 0), (0, 0)))
#print(Eps)
F = sum([inner(sigma(dv, i, Eps), eps(v_))*dx(i) for i in range(nphases)])
a, L = lhs(F), rhs(F)
a += dot(lamb_,dv)*dx + dot(dlamb,v_)*dx
def macro_strain(i):
    """returns the macroscopic strain for the 3 elementary load cases"""
    Eps_Voigt = np.zeros((3,))
    Eps_Voigt[i] = 1
    return np.array([[Eps_Voigt[0], Eps_Voigt[2]/2.],
                    [Eps_Voigt[2]/2., Eps_Voigt[1]]])
def stress2Voigt(s):
    return as_vector([s[0,0], s[1,1], s[0,1]])

Chom = np.zeros((3, 3))
for (j, case) in enumerate(["Exx", "Eyy", "Exy"]):
    print("Solving {} case...".format(case))
    Eps.assign(Constant(macro_strain(j)))
    solve(a == L, w, [], solver_parameters={"linear_solver": "cg"})
    (v, lamb) = split(w)
    Sigma = np.zeros((3,))
    for k in range(3):
        Sigma[k] = assemble(sum([stress2Voigt(sigma(v, i, Eps))[k]*dx(i) for i in range(nphases)]))/vol
    Chom[j, :] = Sigma

print(np.array_str(Chom, precision=2))

However the results are not correct in compare to those of original example

could you please explain and help me to solve this problem

Best regards

Please note that your geo file is not well-defined, as c is not defined as part of the file.

Also note that legacy dolfin can only do periodic condtions where the degrees of freedom align on each interface.

This has been added as a feature of dolfinx_mpc

1 Like

Considering your first comment " lease note that your geo file is not well-defined, as c is not defined as part of the file":
Actually, in my case, I’m trying to model the periodic homogenization with a rectangle unit cell (not skewed cell as the original example), so it doesn’t need to define the c parameter.
for your second comment: “Also note that legacy dolfin can only do periodic condtions where the degrees of freedom align on each interface”
do you mean that when using dolfin to solve the periodic problem can lead the wrong results?

If you dont need the variable i would suggest removing it from the example. By keeping unused features in the code you make it harder for people to parse.

Yes, as dolfin does not throw errors if it cant map a dof to another. As you are using a unit square i would suggest testing your code with a built in mesh (UnitSquareMesh), and see if you Get sensible results.

Thank you very much for your helps

Dear,
Considering your proposal of using dolfinx instead of dolfin, now I’m trying to convert .msh file (created using Gmsh) to .xdmf file in fenicsx base on the following code:

import dolfinx
import meshio
msh = meshio.read("homo_rec.msh")
for cell in msh.cells:
    quad_cells = cell.data
for key in msh.cell_data_dict["gmsh:physical"].keys():
    if key == "quad":
        quad_data = msh.cell_data_dict["gmsh:physical"][key]
mesh =meshio.Mesh(points=msh.points,
                           cells=[("quad", quad_cells)],
                           cell_data={"name_to_read":[quad_data]})
meshio.write("homo_rec.xdmf",mesh)

import dolfinx
from dolfinx.io import XDMFFile

with XDMFFile(MPI.COMM_WORLD, "homo_rec.xdmf", "w") as file:
    file.read_mesh(mesh)

however, it is noted that (although the meshio has been successfully installed through ubuntu) :

ModuleNotFoundError                       Traceback (most recent call last)
Cell In [3], line 2
      1 import dolfinx
----> 2 import meshio
      3 msh = meshio.read("homo_rec.msh")
      4 for cell in msh.cells:

ModuleNotFoundError: No module named 'meshio'

Can you help me, please!

I cannot help you with an import error of a module. It states that it cannot find meshio on your system. So, Where is it installed? Is it on your PYTHONPATH? Does it show if you do python3 -m pip list?

When I call " python3 -m pip list", it is noted that there was meshio 5.3.4 (the first line in the picture attached bellow)

And what does python3 -c "import meshio" return?

when I recall “import meshio”, it still returns:

ModuleNotFoundError                       Traceback (most recent call last)
Cell In [1], line 1
----> 1 import meshio

ModuleNotFoundError: No module named 'meshio'

Then this is a general issue with your installation of meshio and your python environment. Please report the issue at: Sign in to GitHub · GitHub following the guidelines of the issue templates

The problem of meshio was solved. However, there was still another error when I use the following code to transform from .msh file to .xdmf file in dolfinx:

import dolfinx
import meshio
from mpi4py import MPI

msh = meshio.read("homo_rec.msh")
for cell in msh.cells:
    quad_cells = cell.data
for key in msh.cell_data_dict["gmsh:physical"].keys():
    if key == "quad":
        quad_data = msh.cell_data_dict["gmsh:physical"][key]
        mesh =meshio.Mesh(points=msh.points,
                          cells=[("quad", quad_cells)],
                          cell_data={"name_to_read":[quad_data]})
        meshio.write("homo_rec.xdmf",mesh)

import dolfinx
from dolfinx.io import XDMFFile

with dolfinx.io.XDMFFile(MPI.COMM_WORLD, "homo_rec.xdmf", "r") as xdmf:
       mesh = xdmf.read_mesh(name="Grid")

there was a notice of error:

RuntimeError                              Traceback (most recent call last)
Cell In [1], line 19
     16 import dolfinx
     17 from dolfinx.io import XDMFFile
---> 19 with dolfinx.io.XDMFFile(MPI.COMM_WORLD, "homo_rec.xdmf", "r") as xdmf:
     20        mesh = xdmf.read_mesh(name="Grid")

RuntimeError: Unable to open HDF5 file. File homo_rec.h5 does not exist.

Hey, it seems that your periodic condition imposed is not suitable for a rectangular items.

Hi,
I have a implementation for periodic that might be helpful for you.

Obs: there’s only a slight difference, since I followed the comecs tutorial too.

cheers,
Felipe

I am not sure what you mean by this?
Could you provide an example code of what you are trying to do and what is not working?