前回、以下の本の1次元FEMプログラム(VBA)をPython化してみましたが、今度は2次元FEMをPython化してみました。
価格:2592円(税込、送料無料) (2017/4/16時点)
本編の一部とExcel(VBA)はこちらからダウンロードできます。
http://souzousha.iinaa.net/www/FEM/Download.htm
# -*- coding: utf-8 -*- import math class Material: def __init__(self,no): self.no = no self.young = .0 self.poisson = .0 self.thickness = .0 class Element: def __init__(self,no): self.no = no self.node = [0,0,0] # 節点番号 self.x = [.0,.0,.0] # 節点番号のX座標 self.y = [.0,.0,.0] self.u = [.0 for i in range(6)] # 節点番号の変位 self.elNode = [0,0,0,0,0,0] self.matNo = 0 self.area = .0 self.Bmat = [[.0 for i in range(6)] for j in range(3)] self.Smat = [[.0 for i in range(6)] for j in range(3)] self.Dmat = [[.0 for i in range(3)] for j in range(3)] self.Kmat = [[.0 for i in range(6)] for j in range(6)] self.stress = [.0 for i in range(9)] # 要素の応力 def setDmat(self,mat): a = mat.young / (1+mat.poisson) / (1-mat.poisson) b = a * mat.poisson c = 0.5 * mat.young / (1+mat.poisson) self.Dmat = [[a,b,0,], [b,a,0,], [0,0,c]] def setBmat(self): self.elNode = [2*self.node[0],2*self.node[0]+1, 2*self.node[1],2*self.node[1]+1, 2*self.node[2],2*self.node[2]+1] Ai = self.y[1] - self.y[2] Aj = self.y[2] - self.y[0] Ak = self.y[0] - self.y[1] Bi = self.x[2] - self.x[1] Bj = self.x[0] - self.x[2] Bk = self.x[1] - self.x[0] dl = Bk * Aj - Ak * Bj self.area = 0.5 * dl self.Bmat = [[Ai/dl, 0,Aj/dl, 0,Ak/dl, 0], [ 0,Bi/dl, 0,Bj/dl, 0,Bk/dl], [Bi/dl,Ai/dl,Bj/dl,Aj/dl,Bk/dl,Ak/dl]] def setSmat(self): for i in range(3): for j in range(6): s = 0 for k in range(3): s += self.Dmat[i][k]*self.Bmat[k][j] self.Smat[i][j] = s def setKmat(self,mat): #要素剛性行列の設定 v = mat.thickness * self.area for i in range(6): for j in range(6): s = 0 for k in range(3): s += self.Bmat[k][i]*self.Smat[k][j] self.Kmat[i][j] = v * s def calcStress(self): for i in range(3): s = 0 for j in range(6): s += self.Smat[i][j] * self.u[j] self.stress[i] = s cc = 0.5 * (self.stress[0] + self.stress[1]) ss = 0.5 * (self.stress[0] - self.stress[1]) cr = math.sqrt(ss*ss+self.stress[2]*self.stress[2]) self.stress[3] = cc + cr self.stress[4] = cc - cr self.stress[5] = cr if cr <= ss: self.stress[6] = 0 else: wk = abs((ss+cr)/(ss-cr)) self.stress[6] = 57.29577951 * math.atan(math.sqrt(wk)) if self.stress[6] < 0: self.stress[6] = -self.stress[6] self.stress[6] = 90 - self.stress[6] self.stress[7] = math.sqrt(self.stress[3]*self.stress[3] - self.stress[3] * self.stress[4] + self.stress[4] * self.stress[4]) if self.stress[4] > 0: self.stress[8] = self.stress[3] elif self.stress[3] > 0: self.stress[8] = self.stress[3] - self.stress[4] else: self.stress[8] = - self.stress[4] class Fem2D(): def setNodeData(self): '''節点データ設定''' f = open('node.txt') lines = f.readlines() f.close() lines = lines[1:] self.x = [] self.y = [] self.force = [] self.nodeCond = [] self.disp = [] n = 0 for line in lines: line = line.strip('\n') d = line.split('\t') d = [x if x is not '' else 0 for x in d] + [0,0,0,0] self.x.append(float(d[1])) self.y.append(float(d[2])) self.nodeCond.append(int(d[3])) self.nodeCond.append(int(d[4])) self.disp.append(float(d[5])) self.disp.append(float(d[6])) self.force.append(float(d[7])) self.force.append(float(d[8])) n += 1 self.numberOfNode = n def setMaterialData(self): '''材料データ設定''' self.mats = [] m = Material(0) m.young = 20000.0 m.poisson = 0.3 m.thickness = 1.0 self.mats.append(m) def setElementData(self): '''要素データ設定''' f = open('elem.txt') lines = f.readlines() lines = lines[1:] f.close() self.elems = [] for line in lines: d = line.split('\t') no = int(d[0])-1 e = Element(no) n0 = int(d[1])-1 n1 = int(d[2])-1 n2 = int(d[3])-1 e.node = [n0,n1,n2] e.matNo = int(d[4])-1 e.x[0] = self.x[n0] e.x[1] = self.x[n1] e.x[2] = self.x[n2] e.y[0] = self.y[n0] e.y[1] = self.y[n1] e.y[2] = self.y[n2] self.elems.append(e) self.numberOfElement = len(self.elems) def setElementMatrix(self): '''要素剛性行列設定''' for i in range(self.numberOfElement): n = self.elems[i].matNo self.elems[i].setDmat(self.mats[n]) self.elems[i].setBmat() self.elems[i].setSmat() self.elems[i].setKmat(self.mats[n]) def setBandWidth(self): n = 0 for k in range(self.numberOfElement): for i in range(6): for j in range(6): ii = self.elems[k].elNode[i] jj = self.elems[k].elNode[j] - ii if jj > n: n = jj self.bandWidth = n def setTotalMatrix(self): '''全体剛性行列設定''' i = self.numberOfNode*2 j = self.bandWidth+1 self.totalMat = [[0 for a in range(j)] for b in range(i)] for k in range(self.numberOfElement): for i in range(6): for j in range(6): ii = self.elems[k].elNode[i] jj = self.elems[k].elNode[j]-ii if jj >= 0: self.totalMat[ii][jj] += self.elems[k].Kmat[i][j] def setBoundaryCondition(self): '''境界条件による全体剛性行列,荷重ベクトルの変更''' for i in range(self.numberOfNode*2): if self.nodeCond[i] != 0: self.totalMat[i][0] = 1e30 self.force[i] = self.totalMat[i][0]*self.disp[i] def saveTotalMatrix(self,fp='matrix.txt'): '''全体剛性行列の保存''' f = open(fp,'w') for i in range(self.numberOfNode*2): for j in range(self.bandWidth+1): f.write(str(self.totalMat[i][j])+'\t') f.write('\n') f.close() print('saveTotalMat: %s' % fp) def solver(self): '''連立方程式の解(ガウスの消去法)''' nfreedom = self.numberOfNode*2 akj = ['' for i in range(nfreedom)] aik = ['' for i in range(nfreedom)] n1 = self.bandWidth + 1 n2 = nfreedom for k in range(n2): m = self.bandWidth + 1 if k+self.bandWidth+1 > n2: m = n2 - k for j in range(1,m): akj[j] = self.totalMat[k][j]/self.totalMat[k][0] aik[j] = self.totalMat[k][j] for i in range(1,m): it = i + k im1 = i for j in range(i,m): jt = j - im1 self.totalMat[it][jt] -= aik[i]*akj[j] for k in range(n2-1): self.force[k] = self.force[k]/self.totalMat[k][0] m = self.bandWidth + 1 if (k+self.bandWidth+1)>n2: m = n2 - k for i in range(1,m): it = i + k self.force[it] -= self.totalMat[k][i]*self.force[k] self.disp[n2-1] = self.force[n2-1] / self.totalMat[n2-1][0] for k in range(n2-2,-1,-1): s = 0 m = self.bandWidth + 1 if (k+self.bandWidth+1)> n2: m = n2-k for j in range(1,m): jt = j + k s += self.totalMat[k][j]*self.disp[jt] self.disp[k] = self.force[k] - s / self.totalMat[k][0] def saveNodeDisp(self): '''求まった節点変位データの保存''' f = open('disp.txt','w') for i in range(self.numberOfNode): f.write('%d\t' % (i+1)) f.write('%f\t' % self.disp[2*i]) f.write('%f\n' % self.disp[2*i+1]) f.close() print('saveNodeDisp: disp.txt') def setStress(self): '''応力の設定''' for i in range(self.numberOfElement): e = self.elems[i] for j in range(6): k = e.elNode[j] e.u[j] = self.disp[k] e.calcStress() def saveStress(self): '''求まった応力データの保存''' f = open('stress.txt','w') for i in range(self.numberOfElement): for j in range(9): f.write(str(self.elems[i].stress[j])+'\t') f.write('\n') f.close() print('saveStress: stress.txt') def main(self): self.setNodeData() self.setMaterialData() self.setElementData() self.setElementMatrix() self.setBandWidth() self.setTotalMatrix() self.saveTotalMatrix() self.setBoundaryCondition() self.saveTotalMatrix('matrix2.txt') self.solver() self.saveNodeDisp() self.setStress() self.saveStress() def main(): fem = Fem2D() fem.main() if __name__ == '__main__': main()
プログラミングしてみれば、理解できると思ったけど、そんなことはなかったぜ。
流れくらいは分かったけど。