This notebook contains all codes necessary to reproduce the study published in the article "A Characteristic-based constitutive law for dispersed fibers". The notebook was created using SageMathCloud (SMC) (http://cloud.sagemath.com), which is the best place to run and modify the current code.
To run the code on SMC, simply copy this notebook over to SMC. Open the notebook and set the jupyter notebook kernel to SageMath. All source codes were written in Python and the computational engine is SageMath. Here is a tutorial for SageMath: http://doc.sagemath.org/html/en/tutorial/index.html
Copyright © Liang Ge (liang.ge@gmail.com)
In this analysis we assumed the mean fiber direction is along the $x$ axis. Two Eulerian angles $\Theta$ and $\Phi$ define the fiber direction vector, $e_f=(\cos(\Theta), \sin(\Theta)\cos(\Phi), \sin(\Theta)\sin(\Phi))$.
The fiber stretching ratio after deformation is $\lambda_f=\textbf{C}:e_i\otimes e_j$, where $\textbf{C}$ is the right Cauchy-Green deformation tensor and is linked to the deformation gradient tensor $\textbf{F}$ as $\textbf{C}=\textbf{F}^T \textbf{F}$.
The fiber family was assumed to have a $\pi$ periodic von-Mises distribution: \begin{equation} \varrho(\Theta)=4\sqrt{\frac{b}{2\pi}}\frac{\displaystyle{e^{b\cos(2\Theta)+b}}}{\text{erfi}(\sqrt{2b})} \end{equation}
The characteristic invariant is defined as
\begin{align} \Lambda_2&=\frac{1}{4\pi}\int_{\Theta=0}^\pi \int_{\Phi=0}^{2\pi} \rho(\Theta) (\lambda_f^2-1)^2 d\Phi \sin(\Theta) d\Theta\\ &=\frac{1}{4\pi}\int_{\Theta=0}^\pi \varrho(\Theta) \sin(\Theta) \left[\int_{\Phi=0}^{2\pi} (\lambda_f^2-1)^2 d\Phi \right] d\Theta \end{align}The following cell calculates the integral over $\Phi$ \begin{equation} g=\frac{1}{4\pi}\int_{\Phi=0}^{2\pi} (\lambda_f^2-1)^2 d\Phi \end{equation}
In [1]:
def ef(theta, phi):
# This returns the fiber orientation vector
a=sin(theta)
v=vector([cos(theta), a*cos(phi), a*sin(phi)])
return v
def lambda_f(C, theta_f, phi_f):
# This function returns fiber stretch $\lambda_f^2$ after deformation
a=ef(theta_f, phi_f)*C*ef(theta_f, phi_f)
return a
def rhom(theta, phi, b):
# This function returns the pi periodic von Mises distribution without the normalization factor
rho=exp(b*(cos(2*theta)+1))
return rho
def KKK(b):
# This function return the normalization factor for the von Mises distribution function
import scipy.special
erfi=-I*scipy.special.erf(complex(I*sqrt(2*b)))
KKK=1./(4*sqrt(b/2/pi)/erfi)
return KKK
from sage.symbolic.integration.integral import definite_integral
# Define right Cauchy-Green deformation tensor
var('C11, C12, C13, C21, C22, C23, C31, C32, C33')
C=matrix(SR, 3, 3, [[C11, C12, C13], [C12, C22, C23], [C13, C23, C33]])
# $\frac{1}{4\pi} (\lambda_f^2-1)^2
var('theta_f, phi_f')
L_phi(theta_f, phi_f,b,K)=((lambda_f(C, theta_f=theta_f, phi_f=phi_f))-1)^2/4/pi
# Integral over Phi from 0 to 2\pi
g(theta_f)=definite_integral(L_phi(theta_f, phi_f), phi_f, 0, 2*pi).simplify_trig()
show(g)
In [2]:
def reorg(func, terms):
tmpfunc=copy(func).simplify_full()
coefs=[]
for each in terms:
coef=tmpfunc.coefficient(each)
coefs.append(coef)
tmpfunc=(tmpfunc-coef*each).simplify_full()
coefs.append(tmpfunc)
return coefs
Terms=[cos(theta_f)^4, sin(theta_f)^4, cos(theta_f)^2*sin(theta_f)^2, cos(theta_f)^2, sin(theta_f)^2]
M=reorg(g, Terms)
show(M)
In [3]:
import matplotlib.pyplot as plt
from numpy import array
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
minorLocator = MultipleLocator(1)
from matplotlib import colors
from cycler import cycler
import matplotlib
# \kappas _ 1 to 5 (NI=0 to 4)
def kappas(b,terms,NI):
intgrnd=rhom(theta_f, phi_f, b)*terms[NI]*sin(theta_f)
return numerical_integral(intgrnd, 0, pi, params=[b])[0]/KKK(b)
FF=[]
for kI in xrange(5):
FF.append([])
for ni in xrange(11):
b=max(ni,1e-6)
FF[kI].append((b, kappas(b, Terms, kI)))
matplotlib.rcParams.update({'font.size': 15})
plt.rc('lines', linewidth=2)
fig, ax1=plt.subplots()
from scipy import interpolate
import numpy as np
x1,y1=zip(*FF[0])
xnew = np.linspace(np.array(x1).min(),np.array(x1).max(),300)
tck = interpolate.splrep(np.array(x1), np.array(y1), s=0)
power_smooth = interpolate.splev(xnew, tck, der=0)
k1,=ax1.plot(xnew,power_smooth, 'r-', label='$\kappa_1$')
x1,y1=zip(*FF[1])
xnew = np.linspace(np.array(x1).min(),np.array(x1).max(),300)
tck = interpolate.splrep(np.array(x1), np.array(y1), s=0)
power_smooth = interpolate.splev(xnew, tck, der=0)
k2,=ax1.plot(xnew,power_smooth, 'g-.', label='$\kappa_2$', dashes=(8,2,1,2))
x1,y1=zip(*FF[2])
xnew = np.linspace(np.array(x1).min(),np.array(x1).max(),300)
tck = interpolate.splrep(np.array(x1), np.array(y1), s=0)
power_smooth = interpolate.splev(xnew, tck, der=0)
k3,=ax1.plot(xnew,power_smooth, 'b--', label='$\kappa_3$', dashes=(10,5))
x1,y1=zip(*FF[3])
xnew = np.linspace(np.array(x1).min(),np.array(x1).max(),300)
tck = interpolate.splrep(np.array(x1), np.array(y1), s=0)
power_smooth = interpolate.splev(xnew, tck, der=0)
k4,=ax1.plot(xnew,power_smooth, 'c:', label='$\kappa_4$')
x1,y1=zip(*FF[4])
xnew = np.linspace(np.array(x1).min(),np.array(x1).max(),300)
tck = interpolate.splrep(np.array(x1), np.array(y1), s=0)
power_smooth = interpolate.splev(xnew, tck, der=0)
k5,=ax1.plot(xnew,power_smooth, 'm-.', label='$\kappa_5$', dashes=(20,2,1,2))
ax1.legend([k1, k2, k3, k4, k5], ['$\kappa_1$','$\kappa_2$','$\kappa_3$','$\kappa_4$','$\kappa_5$'], bbox_to_anchor=(0.95, 0.7))
ax1.set_ylabel('$\kappa_{i\,(i=1,5)}$', fontsize=25)
ax1.set_xlabel('$b$', fontsize=25)
ax1.xaxis.set_minor_locator(MultipleLocator(1))
ax1.yaxis.set_minor_locator(MultipleLocator(2))
plt.savefig('Fig3.png')
In [4]:
var('gamma, l1')
F_Shearing=matrix(SR, 3, 3, [1, gamma, 0, 0, sqrt(1-gamma^2), 0, 0, 0, 1/sqrt(1-gamma^2)])
F_Stretch=matrix(SR, 3, 3, [l1, 0, 0, 0, 1/sqrt(l1), 0, 0, 0, 1/sqrt(l1)])
F_Total=F_Shearing*F_Stretch
C_Total=F_Total.transpose()*F_Total
In [ ]:
def Lambda(gamma,l1,b_in, C_in):
"""
Calculates the characteristic invariant \Lambda_2 using Eqn. (20)"""
lmd=1
for ni in xrange(5):
lmd+=M[ni](C11=C_in[0][0], C12=C_in[0][1], C13=C_in[0][2],
C21=C_in[1][0], C22=C_in[1][1], C23=C_in[1][2],
C31=C_in[2][0], C32=C_in[2][1], C33=C_in[2][2])*kappas(b_in, Terms, NI=ni)
return lmd
def W_CH(l1_in, b_in, k1, k2):
r"""
Calculates the strain energy function using the characteristic invariant"""
W=[]
for ni in range(21):
gamma_in=0.01*ni
lambda_2 = Lambda(gamma_in, l1_in, b_in, C_Total(gamma=gamma_in, l1=l1_in))
W_ch=k1/(2*k2)*(exp(k2*lambda_2)-1)
W.append([gamma_in,W_ch])
return W
def strain_energy_DI(b_in, C_in, k1, k2):
r"""
This function calculates the strain energy function of dispersed fiber family using the direct integration approach"""
import scipy.integrate
wch_integral(theta_f,phi_f)=((exp(k2*(lambda_f(C=C_in, theta_f=theta_f, phi_f=phi_f)-1)^2)-1)
*rhom(theta_f, phi_f,b=b_in))*sin(theta_f)/4/pi*k1/k2/2
W=scipy.integrate.dblquad(wch_integral, 0, 2*pi, lambda x:0, lambda x:pi, epsabs=1e-5, epsrel=1e-5)
return W[0]/KKK(b=b_in)
def W_DI(l1_in, b_in, k1, k2):
W=[]
for ni in range(21):
gamma_in = 0.01*ni
W_di=strain_energy_DI(b_in, C_Total(gamma=gamma_in, l1=l1_in), k1, k2)
W.append([gamma_in, W_di])
return W
def W_GST(l1_in, b_in, k1, k2):
r"""
Calculates the strain energy function using the GST invariant
"""
W=[]
import scipy.integrate
for ni in range(21):
gamma_in=0.01 * ni
lambda_f_gst_itg(x,y)=((lambda_f(C=C_Total(gamma=gamma_in, l1=l1_in), theta_f=x, phi_f=y)-1))*rhom(x, y,b=b_in)*sin(x)/4/pi
E_i = scipy.integrate.dblquad(lambda_f_gst_itg, 0, 2*pi, lambda x:0, lambda x:pi, epsabs=1e-6, epsrel=1e-6)[0]/ KKK(b=b_in)
W_g=k1/(2*k2)*(exp(k2*E_i^2)-1)
W.append([gamma_in, W_g])
return W
def Strain_Energy_Comparison(lll, bbb, k1, k2, Filename):
ppp=[]
labels=['CH', 'DI', 'GST']
psi_ch=W_CH(l1_in=lll,b_in=bbb, k1=k1, k2=k2)
ppp.append(list_plot(psi_ch, color=rainbow(5)[0], plotjoined=True, linestyle="--", marker="o", legend_label=labels[0]))
psi_di=W_DI(l1_in=lll, b_in=bbb, k1=k1, k2=k2)
ppp.append(list_plot(psi_di, color=rainbow(5)[1], plotjoined=True, legend_label=labels[1]))
psi_gst=W_GST(l1_in=lll, b_in=bbb, k1=k1, k2=k2)
ppp.append(list_plot(psi_gst, color=rainbow(5)[2], plotjoined=True, legend_label=labels[2]))
bb=plot(sum(ppp))
bb.save(Filename,legend_loc="upper center")
import os.path, os
LL=[1.0, 1.1, 1.2]
Bs=[1., 5., 10.]
K2s=[1, 10, 50]
for eachl in LL:
for eachb in Bs:
for eachk2 in K2s:
filename='SE_L_%.3s_b_%.4s_k_%.3s.png' %(eachl, eachb, eachk2)
Strain_Energy_Comparison(lll=eachl, bbb=eachb, k1=996, k2=eachk2, Filename=filename)