Dernière fois J'ai publié un article Quelqu'un a déjà écrit la méthode des éléments finis (FEM) en python. *** damyarou *** J'ai joué avec la source de *** ***, je vais donc l'écrire sous forme d'article.
Obtenez l'exemple de source et les exemples de données sur la [page d'accueil] de damyarou (http://civilyarou.web.fc2.com/py_FEM/sub_j_py_fem.html#3Dfrm).
--Source de l'échantillon: [py_fem_3dfrm.py] (http://civilyarou.web.fc2.com/py_FEM/data_3dfrm/py_fem_3dfrm.py) Programme d'analyse de la structure du squelette en trois dimensions
--Exemple de données: inp_3dfrm_grid.txt Données d'entrée d'analyse FEM (1)
Veuillez consulter la [page d'accueil] de damyarou (http://civilyarou.web.fc2.com/py_FEM/sub_j_py_fem.html#3Dfrm) pour savoir comment l'utiliser. Le résultat des exemples de données est comme ceci
npoin nele nsec npfix nlod
392 759 4 16 392
sec E po A J Iy Iz theta
sec alpha gamma gkX gkY gkZ
1 2.5500000e+06 2.0000000e-01 6.0000000e-01 0.0000000e+00 1.8000000e-02 5.0000000e-02 0.0000000e+00
・ ・ ・ ・ ・ ・<Omission>・ ・ ・ ・ ・ ・・
758 337 321 2
759 321 303 2
node dis-x dis-y dis-z rot-x rot-y rot-z
1 0.0000000e+00 0.0000000e+00 0.0000000e+00 -1.6243780e-04 1.9410889e-04 0.0000000e+00
2 0.0000000e+00 0.0000000e+00 -1.4268342e-04 -1.1792525e-04 3.1402105e-04 0.0000000e+00
3 0.0000000e+00 0.0000000e+00 -2.2831328e-04 -5.0801073e-05 4.0898102e-04 0.0000000e+00
4 0.0000000e+00 0.0000000e+00 -2.4248770e-04 2.1716711e-05 4.5111583e-04 0.0000000e+00
5 0.0000000e+00 0.0000000e+00 -1.8982394e-04 7.9402252e-05 4.3238604e-04 0.0000000e+00
6 0.0000000e+00 0.0000000e+00 -9.5023442e-05 1.0306705e-04 3.6727765e-04 0.0000000e+00
・ ・ ・ ・ ・ ・<Omission>・ ・ ・ ・ ・ ・・
elem nodei N_i Sy_i Sz_i Mx_i My_i Mz_i
elem nodej N_j Sy_j Sz_j Mx_j My_j Mz_j
1 1 0.0000000e+00 0.0000000e+00 9.9678698e+01 -7.9374360e+01 9.7946784e+01 0.0000000e+00
1 2 0.0000000e+00 0.0000000e+00 -9.9678698e+01 7.9374360e+01 -1.9762548e+02 0.0000000e+00
2 2 0.0000000e+00 0.0000000e+00 5.0466963e+01 -6.2857564e+01 1.9762548e+02 0.0000000e+00
2 3 0.0000000e+00 0.0000000e+00 -5.0466963e+01 6.2857564e+01 -2.4809244e+02 0.0000000e+00
3 3 0.0000000e+00 0.0000000e+00 -1.4652296e+01 -2.7890607e+01 2.4809244e+02 0.0000000e+00
3 4 0.0000000e+00 0.0000000e+00 1.4652296e+01 2.7890607e+01 -2.3344015e+02 0.0000000e+00
・ ・ ・ ・ ・ ・<Ce qui suit est omis>・ ・ ・ ・ ・ ・・
Cependant, il n'est pas intéressant de simplement copier et calculer Je l'ai divisé en classes suivantes.
FramePython.py
from inpData import inpData
from kMatrix import kMatrix
from gMatrix import gMatrix
from fMatrix import fMatrix
from outData import outData
classe | Utilisation |
---|---|
inpData | Lire les données d'entrée |
kMatrix | Matrice de rigidité pour chaque élément |
gMatrix | Matrice de rigidité du système entier |
fMatrix | Matrice de rigidité de la charge |
outData | Écrire les données de sortie |
FramePython.py
fnameR= 'inp_grid.txt'
fnameW= 'out_grid.txt'
inp = inpData(fnameR)
inp.PRINP_3DFRM()
inpData.py
def __init__(self, fnameR):
f=open(fnameR,'r')
self.setdata(f)
f.close()
def setdata(self, f):
text=f.readline()
text=text.strip()
text=text.split()
self.npoin=int(text[0]) # Number of nodes
self.nele =int(text[1]) # Number of elements
self.nsec =int(text[2]) # Number of sections
self.npfix=int(text[3]) # Number of restricted nodes
self.nlod =int(text[4]) # Number of loaded nodes
self.nod=2 # Number of nodes per element
self.nfree=6 # Degree of freedom per node
self.n12=self.nod*self.nfree
self.n = self.nfree*self.npoin
self.x =np.zeros([3, self.npoin], dtype=np.float64) # Coordinates of nodes
self.deltaT=np.zeros(self.npoin, dtype=np.float64) # Temperature change of nodes
self.ae =np.zeros([12, self.nsec], dtype=np.float64) # Section characteristics
self.node =np.zeros([self.nod+1, self.nele], dtype=np.int) # Node-element relationship
self.fp =np.zeros(self.nfree*self.npoin,dtype=np.float64) # External force vector
self.mpfix =np.zeros([self.nfree, self.npoin],dtype=np.int) # Ristrict conditions
self.rdis =np.zeros([self.nfree, self.npoin],dtype=np.float64) # Ristricted displacement
# section characteristics
for i in range(0, self.nsec):
text=f.readline()
text=text.strip()
text=text.split()
self.ae[0,i] =float(text[0]) # E : elastic modulus
self.ae[1,i] =float(text[1]) # po : Poisson's ratio
self.ae[2,i] =float(text[2]) # aa : section area
self.ae[3,i] =float(text[3]) # aix : tortional constant
self.ae[4,i] =float(text[4]) # aiy : moment of inertia aroutd y-axis
self.ae[5,i] =float(text[5]) # aiz : moment of inertia around z-axis
self.ae[6,i] =float(text[6]) # theta : chord angle
self.ae[7,i] =float(text[7]) # alpha : thermal expansion coefficient
self.ae[8,i] =float(text[8]) # gamma : unit weight of material
self.ae[9,i] =float(text[9]) # gkX : acceleration in X-direction
self.ae[10,i]=float(text[10]) # gkY : acceleration in Y-direction
self.ae[11,i]=float(text[11]) # gkZ : acceleration in Z-direction
# element-node
for i in range(0, self.nele):
text=f.readline()
text=text.strip()
text=text.split()
self.node[0,i]=int(text[0]) #node_1
self.node[1,i]=int(text[1]) #node_2
self.node[2,i]=int(text[2]) #section characteristic number
# node coordinates
for i in range(0, self.npoin):
text=f.readline()
text=text.strip()
text=text.split()
self.x[0,i]=float(text[0]) # x-coordinate
self.x[1,i]=float(text[1]) # y-coordinate
self.x[2,i]=float(text[2]) # z-coordinate
self.deltaT[i]=float(text[3]) # Temperature change
# boundary conditions (0:free, 1:restricted)
for i in range(0, self.npfix):
text=f.readline()
text=text.strip()
text=text.split()
lp=int(text[0]) #fixed node
self.mpfix[0,lp-1]=int(text[1]) #fixed in x-direction
self.mpfix[1,lp-1]=int(text[2]) #fixed in y-direction
self.mpfix[2,lp-1]=int(text[3]) #fixed in z-direction
self.mpfix[3,lp-1]=int(text[4]) #fixed in rotation around x-axis
self.mpfix[4,lp-1]=int(text[5]) #fixed in rotation around y-axis
self.mpfix[5,lp-1]=int(text[6]) #fixed in rotation around z-axis
self.rdis[0,lp-1]=float(text[7]) #fixed displacement in x-direction
self.rdis[1,lp-1]=float(text[8]) #fixed displacement in y-direction
self.rdis[2,lp-1]=float(text[9]) #fixed displacement in z-direction
self.rdis[3,lp-1]=float(text[10]) #fixed rotation around x-axis
self.rdis[4,lp-1]=float(text[11]) #fixed rotation around y-axis
self.rdis[5,lp-1]=float(text[12]) #fixed rotation around z-axis
# load
if 0<self.nlod:
for i in range(0, self.nlod):
text=f.readline()
text=text.strip()
text=text.split()
lp=int(text[0]) #loaded node
self.fp[6*lp-6]=float(text[1]) #load in x-direction
self.fp[6*lp-5]=float(text[2]) #load in y-direction
self.fp[6*lp-4]=float(text[3]) #load in z-direction
self.fp[6*lp-3]=float(text[4]) #moment around x-axis
self.fp[6*lp-2]=float(text[5]) #moment around y-axis
self.fp[6*lp-1]=float(text[6]) #moment around z-axis
FramePython.py
gmat = gMatrix(inp.n)
fmat = fMatrix(inp)
for ne in range(0,inp.nele):
k= kMatrix(ne, inp)
gmat.set_kMatrix(k) # assembly of stiffness matrix
fmat.set_fMatrix(k) # assembly of load vectors
kMatrix.py
def __init__(self, ne, input):
self.ne = ne
self.inp = input
self.iNo = self.inp.node[0,self.ne]
self.jNo = self.inp.node[1,self.ne]
self.eNo = self.inp.node[2,self.ne]
i = self.iNo-1
j = self.jNo-1
self.x1= self.inp.x[0,i]
self.y1= self.inp.x[1,i]
self.z1= self.inp.x[2,i]
self.x2= self.inp.x[0,j]
self.y2= self.inp.x[1,j]
self.z2= self.inp.x[2,j]
xx = self.x2-self.x1
yy = self.y2-self.y1
zz = self.z2-self.z1
self.el = np.sqrt(xx**2+yy**2+zz**2)
m = self.eNo-1
self.ee = self.inp.ae[0,m] # elastic modulus
self.po = self.inp.ae[1,m] # Poisson's ratio
self.aa = self.inp.ae[2,m] # section area
self.aix = self.inp.ae[3,m] # tortional constant
self.aiy = self.inp.ae[4,m] # moment of inertia around y-axis
self.aiz = self.inp.ae[5,m] # moment of inertia around z-axis
self.theta = self.inp.ae[6,m] # theta : chord angle
self.alpha = self.inp.ae[7,m] # alpha : thermal expansion coefficient
self.gamma = self.inp.ae[8,m] # gamma : unit weight of material
self.gkX = self.inp.ae[9,m] # gkX : acceleration in X-direction
self.gkY = self.inp.ae[10,m] # gkY : acceleration in Y-direction
self.gkZ = self.inp.ae[11,m] # gkZ : acceleration in Z-direction
self.GJ=self.ee/2/(1+self.po)*self.aix
self.EA=self.ee*self.aa
self.EIy=self.ee*self.aiy
self.EIz=self.ee*self.aiz
# Work vector for matrix assembly
ir = np.zeros(12, dtype=np.int)
ir[11]=6*j+5; ir[10]=ir[11]-1; ir[9]=ir[10]-1; ir[8]=ir[9]-1; ir[7]=ir[8]-1; ir[6]=ir[7]-1
ir[5] =6*i+5; ir[4] =ir[5]-1 ; ir[3]=ir[4]-1 ; ir[2]=ir[3]-1; ir[1]=ir[2]-1; ir[0]=ir[1]-1
self.ir = ir
self.ek = self.SM_3DFRM()
self.tt = self.TM_3DFRM()
def SM_3DFRM(self):
ek = np.zeros([12,12],dtype=np.float64) # local stiffness matrix
ek[ 0, 0]= self.EA/self.el
ek[ 0, 6]=-self.EA/self.el
ek[ 1, 1]= 12*self.EIz/self.el**3
ek[ 1, 5]= 6*self.EIz/self.el**2
ek[ 1, 7]=-12*self.EIz/self.el**3
ek[ 1,11]= 6*self.EIz/self.el**2
ek[ 2, 2]= 12*self.EIy/self.el**3
ek[ 2, 4]= -6*self.EIy/self.el**2
ek[ 2, 8]=-12*self.EIy/self.el**3
ek[ 2,10]= -6*self.EIy/self.el**2
ek[ 3, 3]= self.GJ/self.el
ek[ 3, 9]=-self.GJ/self.el
ek[ 4, 2]= -6*self.EIy/self.el**2
ek[ 4, 4]= 4*self.EIy/self.el
ek[ 4, 8]= 6*self.EIy/self.el**2
ek[ 4,10]= 2*self.EIy/self.el
ek[ 5, 1]= 6*self.EIz/self.el**2
ek[ 5, 5]= 4*self.EIz/self.el
ek[ 5, 7]= -6*self.EIz/self.el**2
ek[ 5,11]= 2*self.EIz/self.el
ek[ 6, 0]=-self.EA/self.el
ek[ 6, 6]= self.EA/self.el
ek[ 7, 1]=-12*self.EIz/self.el**3
ek[ 7, 5]= -6*self.EIz/self.el**2
ek[ 7, 7]= 12*self.EIz/self.el**3
ek[ 7,11]= -6*self.EIz/self.el**2
ek[ 8, 2]=-12*self.EIy/self.el**3
ek[ 8, 4]= 6*self.EIy/self.el**2
ek[ 8, 8]= 12*self.EIy/self.el**3
ek[ 8,10]= 6*self.EIy/self.el**2
ek[ 9, 3]=-self.GJ/self.el
ek[ 9, 9]= self.GJ/self.el
ek[10, 2]= -6*self.EIy/self.el**2
ek[10, 4]= 2*self.EIy/self.el
ek[10, 8]= 6*self.EIy/self.el**2
ek[10,10]= 4*self.EIy/self.el
ek[11, 1]= 6*self.EIz/self.el**2
ek[11, 5]= 2*self.EIz/self.el
ek[11, 7]= -6*self.EIz/self.el**2
ek[11,11]= 4*self.EIz/self.el
return ek
def TM_3DFRM(self):
tt=np.zeros([12,12],dtype=np.float64) # transformation matrix
t1=np.zeros([3,3],dtype=np.float64)
t2=np.zeros([3,3],dtype=np.float64)
theta=np.radians(self.theta)#(self.inp.ae[6,m]) # chord angle
t1[0,0]=1
t1[1,1]= np.cos(theta)
t1[1,2]= np.sin(theta)
t1[2,1]=-np.sin(theta)
t1[2,2]= np.cos(theta)
ll=(self.x2-self.x1)/self.el
mm=(self.y2-self.y1)/self.el
nn=(self.z2-self.z1)/self.el
if self.x2-self.x1==0.0 and self.y2-self.y1==0.0:
t2[0,2]=nn
t2[1,0]=nn
t2[2,1]=1.0
else:
qq=np.sqrt(ll**2+mm**2)
t2[0,0]=ll
t2[0,1]=mm
t2[0,2]=nn
t2[1,0]=-mm/qq
t2[1,1]= ll/qq
t2[2,0]=-ll*nn/qq
t2[2,1]=-mm*nn/qq
t2[2,2]=qq
t3=np.dot(t1,t2)
tt[0:3,0:3] =t3[0:3,0:3]
tt[3:6,3:6] =t3[0:3,0:3]
tt[6:9,6:9] =t3[0:3,0:3]
tt[9:12,9:12]=t3[0:3,0:3]
return tt
def ck(self):
return np.dot(np.dot(self.tt.T,self.ek),self.tt) # Stiffness matrix in global coordinate
gMatrix.py
def __init__(self, n):
self.gk = np.zeros([n,n], dtype=np.float64) # Global stiffness matrix
self.kmat = {}
def set_kMatrix(self, k):
self.kmat[k.ne] = k
ck = k.ck()
for i in range(0,12):
it=k.ir[i]
for j in range(0,12):
jt=k.ir[j]
self.gk[it,jt]=self.gk[it,jt]+ck[i,j]
fMatrix.py
def __init__(self, input):
self.inp = input
self.fp = self.inp.fp.copy()
def set_fMatrix(self, k):
tfe_l=self.TFVEC_3DFRM(k)
tt = k.tt
tfe =np.dot(tt.T,tfe_l) # Thermal load vector in global coordinate
bfe =self.BFVEC_3DFRM( k) # Body force vector in global coordinate
for i in range(0,12):
it=k.ir[i]
self.fp[it]=self.fp[it]+tfe[i]+bfe[i]
def TFVEC_3DFRM(self, k):
# Thermal load vector in local coordinate system
tfe_l=np.zeros(12,dtype=np.float64)
i= k.iNo-1
j= k.jNo-1
E = k.ee # elastic modulus
AA = k.aa # section area
alpha = k.alpha # thermal expansion coefficient
tempe=0.5*(self.inp.deltaT[i]+self.inp.deltaT[j])
tfe_l[0]=-E*AA*alpha*tempe
tfe_l[6]= E*AA*alpha*tempe
return tfe_l
def BFVEC_3DFRM(self, k):
# Body force vector in global coordinate system
bfe_g =np.zeros(12,dtype=np.float64)
AA = k.aa # section area
gamma = k.gamma # unit weight of material
gkX = k.gkX # seismic coefficient in X-direction
gkY = k.gkY # seismic coefficient in Y-direction
gkZ = k.gkZ # seismic coefficient in Z-direction
el = k.el
bfe_g[0]=0.5*gamma*AA*el*gkX
bfe_g[1]=0.5*gamma*AA*el*gkY
bfe_g[2]=0.5*gamma*AA*el*gkZ
bfe_g[6]=0.5*gamma*AA*el*gkX
bfe_g[7]=0.5*gamma*AA*el*gkY
bfe_g[8]=0.5*gamma*AA*el*gkZ
return bfe_g
FramePython.py
# treatment of boundary conditions
for i in range(0,inp.npoin):
for j in range(0,inp.nfree):
if inp.mpfix[j,i]==1:
iz=i*inp.nfree+j
fmat.fp[iz]=0.0
for k in range(0,inp.n):
fmat.fp[k]=fmat.fp[k]-inp.rdis[j,i]*gmat.gk[k,iz]
gmat.gk[k,iz]=0.0
gmat.gk[iz,iz]=1.0
Les équations linéaires simultanées sont résolues par numpy.linalg.solve (A, b).
FramePython.py
# solution of simultaneous linear equations
result = np.linalg.solve(gmat.gk, fmat.fp)
FramePython.py
out = outData(inp, result, gmat)
out.PROUT_3DFRM(fnameW)
dtime=time.time()-start
print('n={0} time={1:.3f}'.format(inp.n,dtime)+' sec')
fout=open(fnameW,'a')
print('n={0} time={1:.3f}'.format(inp.n,dtime)+' sec',file=fout)
fout.close()
outData.py
def __init__(self, input, result, gmat):
self.inp = input
self.disg = result
self.fsec = np.zeros([self.inp.n12, self.inp.nele], dtype=np.float64) # Section force vector
# recovery of restricted displacements
for i in range(0,self.inp.npoin):
for j in range(0,self.inp.nfree):
if self.inp.mpfix[j,i]==1:
iz=i*self.inp.nfree+j
self.disg[iz]=self.inp.rdis[j,i]
# calculation of section force
work =np.zeros(self.inp.n12, dtype=np.float64) # work vector for section force calculation
for ne in range(0,self.inp.nele):
k = gmat.kmat[ne]
i = k.iNo-1
j = k.jNo-1
ek = k.ek # Stiffness matrix in local coordinate
tt = k.tt # Transformation matrix
E = k.ee # elastic modulus
AA = k.aa # section area
alpha = k.alpha # thermal expansion coefficient
tempe = 0.5*(self.inp.deltaT[i]+self.inp.deltaT[j])
work[0]=self.disg[6*i] ; work[1] =self.disg[6*i+1]; work[2]= self.disg[6*i+2]
work[3]=self.disg[6*i+3]; work[4] =self.disg[6*i+4]; work[5]= self.disg[6*i+5]
work[6]=self.disg[6*j] ; work[7] =self.disg[6*j+1]; work[8]= self.disg[6*j+2]
work[9]=self.disg[6*j+3]; work[10]=self.disg[6*j+4]; work[11]=self.disg[6*j+5]
self.fsec[:,ne]=np.dot(ek,np.dot(tt,work))
self.fsec[0,ne]=self.fsec[0,ne]+E*AA*alpha*tempe
self.fsec[6,ne]=self.fsec[6,ne]-E*AA*alpha*tempe
La source modifiée est ici.
$ git clone -b "#2" https://github.com/sasaco/FramePython.git
Lorsque l'environnement est prêt, accédez au répertoire du code source et appuyez sur FramePython.py pour démarrer l'analyse.
npoin nele nsec npfix nlod
392 759 4 16 392
sec E po A J Iy Iz theta
sec alpha gamma gkX gkY gkZ
1 2.5500000e+06 2.0000000e-01 6.0000000e-01 0.0000000e+00 1.8000000e-02 5.0000000e-02 0.0000000e+00
・ ・ ・ ・ ・ ・<Omission>・ ・ ・ ・ ・ ・・
758 337 321 2
759 321 303 2
node dis-x dis-y dis-z rot-x rot-y rot-z
1 0.0000000e+00 0.0000000e+00 0.0000000e+00 -1.6243780e-04 1.9410889e-04 0.0000000e+00
2 0.0000000e+00 0.0000000e+00 -1.4268342e-04 -1.1792525e-04 3.1402105e-04 0.0000000e+00
3 0.0000000e+00 0.0000000e+00 -2.2831328e-04 -5.0801073e-05 4.0898102e-04 0.0000000e+00
4 0.0000000e+00 0.0000000e+00 -2.4248770e-04 2.1716711e-05 4.5111583e-04 0.0000000e+00
5 0.0000000e+00 0.0000000e+00 -1.8982394e-04 7.9402252e-05 4.3238604e-04 0.0000000e+00
6 0.0000000e+00 0.0000000e+00 -9.5023442e-05 1.0306705e-04 3.6727765e-04 0.0000000e+00
・ ・ ・ ・ ・ ・<Omission>・ ・ ・ ・ ・ ・・
elem nodei N_i Sy_i Sz_i Mx_i My_i Mz_i
elem nodej N_j Sy_j Sz_j Mx_j My_j Mz_j
1 1 0.0000000e+00 0.0000000e+00 9.9678698e+01 -7.9374360e+01 9.7946784e+01 0.0000000e+00
1 2 0.0000000e+00 0.0000000e+00 -9.9678698e+01 7.9374360e+01 -1.9762548e+02 0.0000000e+00
2 2 0.0000000e+00 0.0000000e+00 5.0466963e+01 -6.2857564e+01 1.9762548e+02 0.0000000e+00
2 3 0.0000000e+00 0.0000000e+00 -5.0466963e+01 6.2857564e+01 -2.4809244e+02 0.0000000e+00
3 3 0.0000000e+00 0.0000000e+00 -1.4652296e+01 -2.7890607e+01 2.4809244e+02 0.0000000e+00
3 4 0.0000000e+00 0.0000000e+00 1.4652296e+01 2.7890607e+01 -2.3344015e+02 0.0000000e+00
・ ・ ・ ・ ・ ・<Ce qui suit est omis>・ ・ ・ ・ ・ ・・
L'analyse a été effectuée correctement.
Recommended Posts