CALFEM för Python
Vad är CALFEM för Python Delmängd av CALFEM implementerat i Python Använder Numpy för matrishantering Stödjer nätgenerering med triangle och gmsh Plottning med wxwidgets och PyOpenGL
CALFEM för Python pycalfem Elementrutiner Systemrutiner pycalfem_utils Inläsningsrutiner Nätgenerering Plottningsfunktioner pycalfem_classes Basklasser för plottning och uppritning
Generell procedur för FE beräkning Definiera modellen Generera element matriser Assemblera in elementraser i den globala styvhetsmatrisen Lös systemet av ekvationer Beräkna elementkrafter
Exempel 1 exs1.py
Example 1 system of springs
1. Importera NumPy och PyCALFEM from numpy import * from pycalfem import * Gör alla funktioner i numpy och pycalfem tillgängliga för skriptet
2. Skapa topologi-array edof Alla fält som definierar indata definieras som array:er i Numpy Edof = array([ [1,2], [2,3], [2,3] ]) Frihetsgrader i topologimatrisen börjar med index 1
3. Skapa styvhetsmatris / kraftvektor zeros funktionen returnerar en array med nollor K=matrix(zeros((3,3))) f=matrix(zeros((3,1))) matrix returnerar en matris instans, som kan användas i matrisfunktioner.
4. Skapa elementmatriser k=1500. ep1=k ep2=2.*k Ke1=spring1e(ep1) Ke2=spring1e(ep2)
5. Assemblera elementmatriser Index i NumPy börjar alltid med 0 assem(edof[0,:], K, Ke2) assem(edof[1,:], K, Ke1) assem(edof[2,:], K, Ke2) print("stiffness matrix K:") print(k) Stiffness matrix K: [[ 3000. -3000. 0.] [-3000. 7500. -4500.] [ 0. -4500. 4500.]]
6. Lösning av ekvationssystem NumPy index dvs börjar med 0. (frihetsgrad 2) bc = array med föreskrivna frihetsgrader. Värden föreskrivs i separat array. Om denna ej anges föreskrivs variablerna till 0.0 bc = array([1,3]) f[1]=100 a,r = solveq(k, f, bc) Löser ekvationsystem med avseende på randvillkor bc och krafvektor f. Returnerar nodvariabler och reaktioner.
6a Lösning av ekvations system utskrift print("displacements a:") print(a) print("reaction forces Q:") print(q) Displacements a: [[ 0. ] [ 0.01333333] [ 0. ]] Reaction forces Q: [[-40.] [ 0.] [-60.]]
7. Beräkning av elementkrafter ed1=extracteldisp(edof[0,:],a) ed2=extracteldisp(edof[1,:],a) ed3=extracteldisp(edof[2,:],a) Extraherar element förskjutningarna från den globala lösningsvektorn es1=spring1s(ep2,ed1) es2=spring1s(ep1,ed2) es3=spring1s(ep2,ed3) Alterantiv användning av extract för att extrahera alla elementförskjutningar till ed ed=extract(edof, a)
7a Utskrift av elementkrafter print "N1 = "+str(es1) print "N2 = "+str(es2) print "N3 = "+str(es3) N1 = 40.0 N2 = -20.0 N3 = -40.0
Exempel 2 exs3.py
Exempel 2
1. Topolgi-array Edof Edof = array([ [1,2,5,6], [5,6,7,8], [3,4,5,6] ]) Observera att inga elementnummer anges i första kolumnen.
2. Styvhetsmatris och lastvektor K=matrix(zeros((8,8))) f=matrix(zeros((8,1)))
3. Elementegenskaper E=2.0e11 A1=6.0e-4 A2=3.0e-4 A3=10.0e-4 ep1=[e,a1] ep2=[e,a2] ep3=[e,a3] Elementegenskaper kan ges som listor och arrayer
4. Elementkoordinater ex1=array([0., 1.6]) ex2=array([1.6, 1.6]) ex3=array([0., 1.6]) ey1=array([0., 0.]) ey2=array([0., 1.2]) ey3=array([1.2, 0.])
5. Elementmatriser Ke1=bar2e(ex1,ey1,ep1) Ke2=bar2e(ex2,ey2,ep2) Ke3=bar2e(ex3,ey3,ep3)
6. Assemblering och lösning av ekv. system assem(edof[0,:],k,ke1) assem(edof[1,:],k,ke2) assem(edof[2,:],k,ke3) Assemblering print("stiffness matrix K:") print(k) bc=array([1,2,3,4,7,8]) f[5]=-80e3 [a,r]=solveq(k,f,bc) Lösning av ekvationssystem print("displacements a:") print(a) print("reaction forces r:") print(r)
7. Beräkning av elementkrafter ed1=extracteldisp(edof[0,:],a); N1=bar2s(ex1,ey1,ep1,ed1) ed2=extracteldisp(edof[1,:],a); N2=bar2s(ex2,ey2,ep2,ed2) ed3=extracteldisp(edof[2,:],a); N3=bar2s(ex3,ey3,ep3,ed3) print("n1 = "+str(n1)) print("n2 = "+str(n2)) print("n3 = "+str(n3))
Exempel 3 exs4a.py
Exempel 3
Topologi - Edof Edof = array([ [1, 2, 5, 6], [3, 4, 7, 8], [5, 6, 9, 10], [7, 8, 11, 12], [7, 8, 5, 6], [11, 12, 9, 10], [3, 4, 5, 6], [7, 8, 9, 10], [1, 2, 7, 8], [5, 6, 11, 12] ])
Styvhetsmatris och elementegenskaper K=zeros([12,12]) f=zeros([12,1]) A=25.0e-4 E=2.1e11 ep=[e,a]
Elementkoordinater ex = array([ [0., 2.], [0., 2.], [2., 4.], [2., 4.], [2., 2.], [4., 4.], [0., 2.], [2., 4.], [0., 2.], [2., 4.] ]) ey = array([ [2., 2.], [0., 0.], [2., 2.], [0., 0.], [0., 2.], [0., 2.], [0., 2.], [0., 2.], [2., 0.], [2., 0.] ])
Assemblering med loopar elx = rad n i ex ely = rad n i ey eltopo = rad n i Edof Loop över flera variabler for elx, ely, eltopo in zip(ex, ey, Edof): Ke = bar2e(elx, ely,ep) assem(eltopo,k,ke)
Beräkning av elementkrafter kompakt form ed=extracteldisp(edof,a) N=zeros([Edof.shape[0]]) Extraherar alla element förskjutningar till ed print("element forces:") i = 0 for elx, ely, eld in zip(ex, ey, ed): N[i] = bar2s(elx,ely,ep,eld) print("n%d = %g" % (i+1,n[i])) i+=1
Använda koordinat matriser
Skapa ex, ey från coord, dof och edof coord = array([ [0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0] ]) dof = createdofs(coord.shape[0],1) edof = array([ [1,2,3], [1,3,4] ]) # --- Beräkna element koordinater ex, ey = coordxtr(edof, coord, dof) 4 1 3 2
Tips Storlek på systemmatris ndofs = edof.max() Skapa en matris med samma storlek som en annan matris B = zeros([a.shape[0],a.shape[1]])
Modulstruktur # -*- coding: utf-8 -*- from numpy import * from pycalfem import * def createinput():... def solveproblem(...):... def createreport(...):... if name == main :... = createinput()... = solveproblem(...) createreport(...) name == main när filen körs från IDLE eller Python. name!= main när filen importeras som en modul dvs import model Huvudprogram
Allmänt om uppgiften Indatagenerering Användargränssnitt Nätgenerering Beräkning Elementmatriser Assemblering Lösning Elementkrafter Redovisning av utdata Resultatrapport Diagram Arbetsblad 2
Nätgenerering " eller hur man syr ihop många element "
Nätgenerering För större problem måste topologin skapas med hjälp av algoritmer Utgår ofta från en geometrisk beskrivning Kriterier kan sättas som anger hur tätt elemennätet skall genereras Area/Volymskriterier Explicit angivelse av antal element på ränder Resultat från tidigare beräkning kan ligga till grund för hur ett nät skall förbättras, adaptivt nät.
Nätgenering Strukturerad nätgenerering Regel finns för strukturen på nätet Koordinatsystem anger element position Ostrukturerad nätgenerering Algoritm fyller volym ytor med element Ofta begränsade till triangel- eller tetraederelement
Ostrukturerat nät
Strukturerade nät
Strukturerade nät
GMSH 3D finite element grid generator Pre- och postprocessering Hanterar både strukturerade och ostrukturerade mesh Använder en rand-beskrivning för att beskriva geometrier Linjer, cirklar, splines ytor mm Geometrier beskrivs i ett eget språk
Nätgenerering och Calfem för Python Nätgenerering med GMSH kan göras direkt i CALFEM för Python Modulerna pycalfem_geodata och pycalfem_mesh Geometri beskrivs i GeoData klassen Nätgenerering görs sedan med GmshMesher klassen Resultatet av nätgenereringen är matriser som kan användas direkt i CALFEM
Exempel t 7 6 3 2 6 2 5 3 d 7 5 4 1 h 4 0 0 1 w
Importera moduler # ------ Needed module imports ------- from pycalfem import * from pycalfem_utils import * from pycalfem_geodata import * from pycalfem_mesh import * import pycalfem_vis as pcv import visvis as vv from math import sqrt, pow
Variabler för problembeskrivning # ------ Problem parameters ------ w = 100.0 h = 10.0 t = 1.0 d = h/2 D = identity(2,'float') * 1.0 ep = [1.0, 1]
Skapa punkter # ------ Create geometry instance ------------ g = GeoData() g.addpoint([0, 0]) # 0 g.addpoint([w, 0]) # 1 g.addpoint([w, h]) # 2 g.addpoint([w-w/2.+t/2., h]) # 3 g.addpoint([w-w/2+t/2, h-d]) # 4 g.addpoint([w-w/2-t/2, h-d]) # 5 g.addpoint([w-w/2-t/2, h]) # 6 g.addpoint([0.,h]) # 7
Skapa linjer Markörer för att ange var randvillkoren skall tillämpas g.addspline([0, 1]) #0 g.addspline([1, 2]) #1 g.addspline([2, 3], marker=80) #2 g.addspline([3, 4]) #3 g.addspline([4, 5]) #4 g.addspline([5, 6]) #5 g.addspline([6, 7], marker=90) #6 g.addspline([7, 0]) #7
Skapa yta/ytor Linjer som beskriver ytan g.addsurface([0,1,2,3,4,5,6,7])
Nätgenerering eltype = 3 dofspernode = 1 Variabler för elementtyp. Kan vara bra att ha senare mesher = GmshMesher(geoData = g, gmshexecpath = None, elsizefactor = 0.5, eltype = eltype, dofspernode= dofspernode) Styr storleken på de genererade elementen coords, edof, dofs, bdofs, elementmarkers = mesher.create() Strukturer som anger frihetsgrader och information för de tidigare definierade markörerna
Assemblering ndofs = size(dofs) ex, ey = coordxtr(edof, coords, dofs) K = zeros([ndofs,ndofs]) Beräkna totala antalet frihetsgrader for eltopo, elx, ely in zip(edof, ex, ey): Ke = flw2i4e(elx, ely, ep, D) assem(eltopo, K, Ke) Extraherar elementkoordinater och topologi för ett element i taget assem modifierar styvhetsmatrisen direkt behöver inte returneras som i MATLAB
Randvillkor f = zeros([ndofs,1]) bc = array([],'i') bcval = array([],'i') Randvillkor lagras i 2 arrays en för frihetsgrad och en för värdet bc, bcval = applybc(bdofs, bc, bcval, 80, 0.0) bc, bcval = applybc(bdofs, bc, bcval, 90, 10.0) applybc tillämpar randvillkoret på angiven markör. Finns också applyforce för att uppdatera lastvektorn
Lösning av ekvationssystem a,r = solveq(k,f,bc,bcval) ed = extracteldisp(edof,a) Samma syntax som CALFEM Beräkning av elementkrafter maxflow = [] for i in range(edof.shape[0]): es, et, eci = flw2i4s(ex[i,:], ey[i,:], ep, D, ed[i,:]) maxflow.append( math.sqrt( math.pow(es[0,0],2) + math.pow(es[0,1],2)) ) Värdet på flödet i element beräknas här.
Visualisering pcv.drawgeometry(g, drawpoints=true, labelcurves=true, title="geometry") vv.figure() pcv.drawelementvalues( maxflow, coords, edof, dofspernode, eltype, dodrawmesh=false, title="max flows") vv.figure() pcv.drawnodalvalues(a, coords, edof, dofspernode, eltype, dodrawmesh=false, title="nodal values") app = vv.use() app.create() app.run() Ser till att uppdatera fönstren Värdet på flödet i element beräknas här.
Visualisering - Geometri
Visualisering - Nodvärden
Visualisering - Elementflöden
Objektorientering
Klasser Grupperar data och funktioner till en enhet Funktioner i klassen opererar på data i klassen Möjligör enklare och mer lättförstådd kod Kan utökas i framtiden utan att existerande kod behöver ändras Alla datatyper i python är klasser
Exempel på klass Konstruktor. Anropas när klassen instantieras (skapas) Alla klassfunktioner har self som första parameter, vilken är en variabel som pekar på den egna instansen. Skickas automatiskt till funktionerna. class Point: def init (self, x, y): self._x = x self._y = y def show(self): print "x =", self._x, ", y =", self._y def setposition(self, x, y): self._x = x self._y = y def getposition(self): return self._x, self._y p1 = Point(0.0, 0.0) p1.show() p1.setposition(2.0, 3.0) p1.show() x = 0.0, y = 0.0 x = 2.0, y = 3.0 x = 1.0, y = 2.0 1.0 2.0 p2 = Point(1.0, 2.0) p2.show() x, y = p2.getposition() print x, y
Arv Nya klasser kan ärva funktionalitet från andra klasser Funktionalitet kan läggas till utan att påverka existerande kod
Exempel på arv class Circle(Point): def init (self, x, y, radius): Point. init (self, x, y) self._radius = radius Anropa Points konstruktor def show(self): x, y = self.getposition() print "x =", x, ", y =", y, ", radius =", self._radius def setradius(self, radius): self._radius = radius def getradius(self): return self._radius def getarea(self): return pi*self._radius**2 if name == " main ": c1 = Circle(0.0, 0.0, 1.0) c1.setposition(1.0, 2.0) c1.show() print "area =", c1.getarea() setposition från Point
Visualisation in Python
2D 3D Tkinter Canvas widget Python Gnuplot matplotlib Outline PyOpenGL vpython Visualisation Toolkit VTK
Python Gnuplot Python interface to Gnuplot Allows direct plotting of Python and Numeric data types in Gnuplot Depends on an external application Does not integrate with GUI-toolkits
Examples
Code import Gnuplot from Numeric import * points1 = [[0,1.2],[1.1,5.2],[2,-0.3]] x = arrayrange(0.0, 1.8, 0.1) y = 3-2*x + 2*sin(4*x) points2 = transpose(array([x,y])) gnuplot = Gnuplot.Gnuplot() d1 = Gnuplot.Data(points1, with='lines', title='points1') d2 = Gnuplot.Data(points2, with='linespoints', title='points2') d3 = Gnuplot.Data(x, y, with='linespoints', title='x and y') gnuplot.title('simple Python-Gnuplot demo') gnuplot.xlabel('t') gnuplot.plot(d1, d2) gnuplot.hardcopy(filename='tmp.ps', enhanced=1, mode='eps', color=0, fontname='times-roman', fontsize=28) gnuplot('set term png small') gnuplot('set output "tmp.png"') gnuplot.plot(d1, d2, d3)
matplotlib Python module for 2D plotting No dependencies on external applications Close to MATLAB syntax Many backends for export Integrates into wxwindows, Tkinter etc. Supports Numeric
Examples
Simple from pylab import * plot([1,2,3,4]) show()
from pylab import * plot([1,2,3,4],[1,4,9,16]) show() x and y series
axis and saving from pylab import * plot([1,2,3,4], [1,4,9,16], 'ro') axis([0, 6, 0, 20]) savefig('secondfig.png') show()
Setting properties from pylab import * from Numeric import * x = arange(0.0, 2*pi, 0.1) y = sin(x) x1 = arange(0.0, 2*pi, 0.1) y1 = cos(x1) x2 = arange(0.0, 2*pi, 0.1) y2 = sin(2*x2) plot(x, y, linewidth=2.0) line, = plot(x, y, 'o') line.set_antialiased(false) # turn off antialising lines = plot(x1, y1, x2, y2) set(lines, color='r', linewidth=2.0) set(lines, 'color', 'r', 'linewidth', 2.0) show()
Setting properties
Subplots from pylab import * def f(t): s1 = cos(2*pi*t) e1 = exp(-t) return multiply(s1,e1) t1 = arange(0.0, 5.0, 0.1) t2 = arange(0.0, 5.0, 0.02) numrows=2 numcols=1 fignum=1 figure(1) subplot(211) plot(t1, f(t1), 'bo', t2, f(t2), 'k') subplot(212) plot(t2, cos(2*pi*t2), 'r--') show() numrows=2 numcols=1 fignum=1
Subplots
Multiple figures from pylab import * figure(1) plot([1,2,3]) figure(2) plot([4,5,6]) figure(1) title('easy as 1,2,3') show() # the first figure # a second figure # figure 1 current # figure 1 title
Multiple figures
Fonts from pylab import * font = {'fontname' : 'Courier', 'color' : 'r', 'fontweight' : 'bold', 'fontsize' : 11} plot([1,2,3]) title('a title', font, fontsize=12) text(0.5, 2.5, 'a line', font, color='k') xlabel('time (s)', font) ylabel('voltage (mv)', font) show()
Fonts
Mathematical text from pylab import * t = arange(0.0, 2.0, 0.01) s = sin(2*pi*t) plot(t,s) title(r'$\alpha_i > \beta_i$', fontsize=20) text(1, -0.6, r'$\sum_{i=0}^\infty x_i$', fontsize=20) text(0.6, 0.6, r'$\cal{a}\rm{sin}(2 \omega t)$', fontsize=20) xlabel('time (s)') ylabel('volts (mv)') savefig('mathtext_tut', dpi=50) show()
Mathematical text
Plot window controls Save plot Zoom Pan Next view Previous view Reset view to default
Visualisation Toolkit Open Source 3d graphics toolkit Language bindings to C++, Java, Python, Tcl Implements most visualisation algorithms available Uses a the Visualisation network concept Large and complex to use Easier in Python : )
Simple example # load VTK extensions from vtkpython import * # create a rendering window and renderer ren = vtkrenderer() renwin = vtkrenderwindow() renwin.addrenderer(ren) renwin.setsize(300,300) iren = vtkrenderwindowinteractor() iren.setrenderwindow(renwin) # create an actor and give it cone geometry cone = vtkconesource() cone.setresolution(8) conemapper = vtkpolydatamapper() conemapper.setinput(cone.getoutput()) coneactor = vtkactor() coneactor.setmapper(conemapper) # assign our actor to the renderer ren.addactor(coneactor) # enable user interface interactor iren.initialize() iren.start()