This tutorial shows how to implement in MFront
mean-field homogenization schemes within the framework of 3d linear
elasticity, for biphasic media.
These homogenization schemes are part of the namespace
tfel::material::homogenization::elasticity
. They are
implemented via the DSL
@MaterialLaw
.
The implemented schemes for biphasic media are:
For dilute scheme and Mori-Tanaka scheme, the following assumptions are made:
For Voigt, Reuss and Hashin-Shtrikman bounds, the following assumptions are made:
We begin with a basic example: a particulate composite with spherical inclusions.
MFront
Here is the header of the mfront
file:
Here we want to let the user choose which scheme he wants to use:
dilute scheme, Mori-Tanaka scheme… Hence, a real parameter is defined as
an input, which can be 0 for dilute scheme, 1 for Mori-Tanaka…
(f
is the volume fraction of inclusion phase).
@StateVariable real scheme;
scheme.setEntryName("HomogenizationScheme");
@StateVariable stress E0;
E0.setEntryName("MatrixYoungModulus");
@StateVariable real nu0;
nu0.setEntryName("MatrixPoissonRatio");
@StateVariable stress Ei;
Ei.setEntryName("InclusionYoungModulus");
@StateVariable real nui;
nui.setEntryName("InclusionPoissonRatio");
@StateVariable real f;
f.setEntryName("InclusionVolumeFraction");
It is important not to forget the header files that must be included:
@TFELLibraries {"Material"};
@Includes{
#include "TFEL/Material/LinearHomogenizationSchemes.hxx"
#include "TFEL/Material/LinearHomogenizationBounds.hxx"
}
Note that @TFELLibraries
lets the user specify a
TFEL
library to link with. The header
LinearHomogenizationSchemes.hxx
is needed for dilute scheme
and Mori-Tanaka scheme, whereas here
LinearHomogenizationBounds.hxx
will be used for computing
upper Hashin-Shtrikman (HS) bound. It is indeed known that the lower
Hashin-Shtrikman bound is equal to the Mori-Tanaka scheme with
spheres.
We choose the Young homogenized modulus E
to be the
output of our Function
.
Here is the implementation of the different homogenized schemes:
@Function{
using namespace tfel::material::homogenization::elasticity;
std::pair<stress,real> pa;
if (scheme==real(0)){
pa=computeSphereDiluteScheme<real,stress>(E0,nu0,f,Ei,nui);
}
if (scheme==real(1)){
pa=computeSphereMoriTanakaScheme<real,stress>(E0,nu0,f,Ei,nui);
};
if (scheme==real(2)){
std::array<real,2> tab_f={1-f,f};
auto k0=E0/3/(1-2*nu0);
auto ki=Ei/3/(1-2*nui);
std::array<stress,2> tab_k={k0,ki};
auto mu0=E0/2/(1+nu0);
auto mui=Ei/2/(1+nui);
std::array<stress,2> tab_mu={mu0,mui};
auto pa2=computeIsotropicHashinShtrikmanBounds<3u,2u,real,stress>(tab_f,tab_k,tab_mu);
auto UB=std::get<1>(pa2);
auto kh=std::get<0>(UB);
auto muh=std::get<1>(UB);
auto Eh=9*kh*muh/(muh+3*kh);
auto nuh=(3*kh-2*muh)/2/(3*kh+muh);
pa={Eh,nuh};
};
E=std::get<0>(pa);
}
Hence, pa
is a std::pair
that returns the
Young homogenized modulus and the homogenized Poisson ratio. The
computation of dilute scheme and Mori-Tanaka scheme are
straightforward.
The function computeIsotropicHashinShtrikmanBounds
necessitates to give the arrays of volume fractions tab_f
,
bulk moduli tab_k
and shear moduli tab_mu
. The
function returns a pair of pair. The first pair is lower HS bound, the
second is upper HS bound (that we want here). Each bound is a pair whose
first element is the bulk modulus, and whose second element is the shear
modulus. The function is also available for plain strain elasticity (the
first template argument is the dimension).
We choose interface
python
to compute the
schemes for a volume fraction of spheres which goes from 0 to 1.
Here is the python
file :
import src.biphasic as bip
from matplotlib import pyplot as plt
import numpy as np
frac=np.linspace(0,1,200)
E_DS=np.array([bip.biphasic_Spherical(0,1e9,0.2,100e9,0.3,f)/1e11 for f in frac])
E_MT=np.array([bip.biphasic_Spherical(1,1e9,0.2,100e9,0.3,f)/1e11 for f in frac])
E_HS=np.array([bip.biphasic_Spherical(2,1e9,0.2,100e9,0.3,f)/1e11 for f in frac])
plt.figure()
g1,=plt.plot(frac,E_DS,color="blue")
g2,=plt.plot(frac,E_MT,color="red")
g3,=plt.plot(frac,E_HS,color="black")
plt.legend([g1,g2,g3],['Dilute','Mori-Tanaka','upper HS bound'])
plt.xlabel(r'$f$')
plt.ylabel(r'$E/E_0$',rotation='horizontal')
plt.show()
plt.close()
The results are given by the following figure.
The example of a composite with ellipsoidal inclusions can be implemented considering various examples of distributions. We will focus on Mori-Tanaka scheme, but dilute scheme can also be computed.
MFront
The first lines are not so different from example 1, except the fact
that we now define a real
parameter distrib
to
let the user choose the distribution of ellipsoids: isotropic,
transverse isotropic, or oriented. We also introduce the semi-lengths
a
,b
,c
of the ellipsoid.
@StateVariable real distrib;
distrib.setEntryName("TypeOfDistribution");
@StateVariable stress E0;
E0.setEntryName("MatrixYoungModulus");
@StateVariable real nu0;
nu0.setEntryName("MatrixPoissonRatio");
@StateVariable stress Ei;
Ei.setEntryName("InclusionYoungModulus");
@StateVariable real nui;
nui.setEntryName("InclusionPoissonRatio");
@StateVariable real f;
f.setEntryName("InclusionVolumeFraction");
@StateVariable length a;
a.setEntryName("FirstSemiLength");
@StateVariable length b;
b.setEntryName("SecondSemiLength");
@StateVariable length c;
c.setEntryName("ThirdSemiLength");
Note that the orientation for the oriented case will be fixed in the
mfront
file, and it will be the same for the transverse
isotropic case which necessitates to gives the direction of one of the
axes of the ellipsoid. But those orientations could also be inputs of
the law.
Here is the Function
block:
@Function{
tfel::math::tvector<3u,real> n_a={1,0,0};
tfel::math::tvector<3u,real> n_b={0,1,0};
using namespace tfel::material::homogenization::elasticity;
if (distrib==real(0)){
auto pa = computeIsotropicMoriTanakaScheme<real,stress,length>(E0,nu0,f,Ei,nui,a,b,c);
E1=std::get<0>(pa);
}
if (distrib==real(1)){
auto Chom=computeTransverseIsotropicMoriTanakaScheme<real,stress,length>(E0,nu0,f,Ei,nui,n_a,a,b,c);
auto Shom=invert(Chom);
E1=1/Shom(0,0);
}
if (distrib==real(2)){
auto Chom=computeOrientedMoriTanakaScheme<real,stress,length>(E0,nu0,f,Ei,nui,n_a,a,n_b,b,c);
auto Shom=invert(Chom);
E1=1/Shom(0,0);
}
}
For computeTransverseIsotropicMoriTanakaScheme
, only one
vector n_a
is used. It specifies the direction of
transverse isotropy. The ellipsoid has one axis aligned with this
vector, and the semi-length of this axis is specified immediately after
n_a
(here a
). This is in fact a special case
of transverse isotropy for which the ellipsoid rotates around one of its
principal axes. For computeOrientedMoriTanakaScheme
, the
first vector n_a
is the direction of one axis, whose
semi-length is precised immediately after (here a
) and the
same goes for the second vector and second semi-length. If the vectors
are not normals, an error is returned. However, the norms of these
vectors can be different from 1.
We choose interface
python
to compute the
schemes for a volume fraction of ellipsoids which goes from 0 to 1.
Here is the python
file :
import src.biphasic as bip
from matplotlib import pyplot as plt
import numpy as np
frac=np.linspace(0,1,200)
E_I=np.array([bip.biphasic_Ellipsoidal(0,1e9,0.2,100e9,0.3,f,30,1,1)/1e11 for f in frac])
E_TI=np.array([bip.biphasic_Ellipsoidal(1,1e9,0.2,100e9,0.3,f,1,30,1)/1e11 for f in frac])
E_O=np.array([bip.biphasic_Ellipsoidal(2,1e9,0.2,100e9,0.3,f,30,1,1)/1e11 for f in frac])
plt.figure()
g1,=plt.plot(frac,E_I,color="blue")
g2,=plt.plot(frac,E_TI,color="red")
g3,=plt.plot(frac,E_O,color="green")
plt.legend([g1,g2,g3],['Isotropic','Transverse Isotropic','Oriented'])
plt.xlabel(r'$f$')
plt.ylabel(r'$E^{1}/E^{1}_0$',rotation='horizontal')
plt.show()
plt.close()
We see here that we chose prolate spheroids for the ellipsoids, with
aspect ratio of 30. The first case is the isotropic distribution, the
second case is the transverse isotropic distribution where the biggest
axis rotates in the y-z
plane, and in the last case, the
biggest axis is oriented in the x
direction. The results
are given by the following figure.