Till Eulenspiegels lustige Serie/ Schwingende Platten/ Skripte
Kurzbeschreibung
BearbeitenDie Skripte sind auf Systemen wie dem Raspberry Pi lauffähig und sind autonom. Sie benutzen absolut keine speziellen Bibliotheken. Die Listings verzichten auf die farbenfrohe Auszeichnung von Syntax, damit man sie einfach aus der Webseite ausschneiden kann.
Das Skript ritz.py berechnet mit den Formeln von Ritz (sollten alle fehlerfrei abgetippt sein?) die Serien von Chladni-Klangfiguren als Svg-Dateien. Die lange Laufzeit von 1 Min wird in einem behinderten Algorithmus verbraucht, der Punktmengen zu Linien vereinen will und das nur schlecht hinkriegt. Lohnt sich kaum, den zu verbessern. Es entstehen 'single-xy.svg' für Einzelfiguren, sowie dekorativ bunte aber sonst nutzlose Ueberlagerungen 'multi-x.svg'. Massen von unverständlichen Debug-Zeilen werden aufs Terminal gespuckt. Alles ignorieren.
Angebaut wurde eine vollständige Neuberechnung der stehenden Wellen von Grund auf. Der Grad der Approximation wurde um Eins angehoben, denn wir haben Mahlwerke für Zahlen, von denen ein Autor vor 100 Jahren nur träumen konnte. Die Matrixelemente des Potenzial-Operators werden zwischen orthonormalen Sätzen von Basisfunktionen errechnet und die Eigenwerte/Eigenvektoren der symmetrischen Matrizen komplett rausgeholt. Der Algorithmus der Jacobi-Rotationen tut es blitzartig und genau; die Dimension der Matrizen bleibt unter 16. Es gibt mehr Graphen und deswegen 2 Minuten Laufzeit. Die Ergebnis-Datei "ritzmodes.txt" enthält alle Basisfamilien, Eigenwerte, Eigenvektoren. Nur wenige Graphen haben subtile Unterschiede zwischen beiden Versionen.
Das Skript chladni.py rechnet eine Approximation der Klangfiguren mit einem anderen Orthonormalsystem durch, nämlich mit den Polynomen an Stelle der physikalisch besser motivierten Balkenfunktionen. Aber mit einer etwas höheren Dimension der Matrizen kommt man auch hier zu ganz brauchbaren Ergebnissen. Die Integralrechnung für die Matrixelemente ist leichter. Chladni.py importiert Funktionen aus Ritz.py.
Un die Versionen im Vergleich anzuschauen, gibt es dieses Shellskript, das die Bilder paarweise verschmilzt und anzeigt. Man benutze Alt-F4, um weiter zu gehen.
################### # watch.sh compare image pairs from 2 modes of ritz.py # depends on: rsvg-convert pngtopnm pnmcat gview. goon() { local A F G L N L=A; N=1 if [ -n "$1" ]; then L=$1; fi while [ $N -lt 16 ]; do A="$L$N"; F="single-1-$A.svg"; G="single-2-$A.svg"; N=$((N+1)) if [ -f $F ]; then rsvg-convert $F -z 0.8 | pngtopnm >f.pnm rsvg-convert $G -z 0.8 | pngtopnm >g.pnm pnmcat -leftright f.pnm g.pnm >h.pnm echo "Chladni $A" gview h.pnm # ersetze durch xview,... irgendeinen Bildbetrachter else N=20; fi done } for X in A B C D E F; do goon $X ; done ##############
Listing ritz.py
Bearbeiten# -*- coding: utf-8 -*- # W.Ritz 1909, Loesungen der Plattenschwingung. Stehende Wellen, Knotenlinien. # quadratische Platte, Basis aus 7 mal 7 Wellenfunktionen from math import sqrt, pi, sin, cos, sinh, cosh def div(p,q) : return int(p/q) def tanh(x): return sinh(x)/cosh(x) def coth(x) : return cosh(x)/sinh(x) ###### primitive plot class svgdump : def plotbegin(sd, w,h,f) : # args: width height zoomfactor W=str(w); H=str(h); u=''; fw=str(f*w); fh=str(f*h) s=( '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n'+ '<!DOCTYPE svg>\n'+ '<svg xmlns="http://www.w3.org/2000/svg"\n'+ ' xmlns:xlink="http://www.w3.org/1999/xlink"\n'+ ' width="'+W+'" height="'+H+'" viewBox="0 0 '+fw+' '+fh+'">\n') return s def plotend(sd) : return '</svg>\n' def move(sd,x,y) : return 'M'+str(x)+','+str(y) def line(sd,x,y) : return 'L'+str(x)+','+str(y) def ball(sd, x,y,r,col) : return ('<circle fill="'+col+'" cx="'+str(x)+'" cy="'+str(y)+ '" r="'+str(r)+'" />\n') def labl(sd,s,x,y, size=14,fill='#000') : f=' font-family="Arial"' t='<tspan x="'+str(x)+'" y="'+str(y)+'">'+s+'</tspan>'; fsz= str(size) return ('<text fill="'+fill+'"'+f+' font-size="'+fsz+'px">'+t+'</text>\n') def path(sd,w,s,lc='#000',fc='none') : # path w=with lc=linecolor fc=fillcol t='<path fill="'+fc+'" stroke="'+lc+'" stroke-width="'+str(w)+'" ' t+= ' stroke-linecap="round" ' return t + 'd="\n'+s+'" />\n' # end class svgdump def aprx(x) : # 3-digit approximation y= (-x) if(x<0) else x; z= int(1e3*y+1e-3); z= (-z) if (x<0) else z return z/1000.0 def curve(sd,scale,xy, fill='#000', width=1, bkgr='none') : (xs,fx,xmin, ys,fy,ymin) = scale; s=''; n= div(len(xy),2) for i in range(n) : x= aprx(xmin+fx*(xy[2*i]-xs)); y= aprx(ymin+fy*(xy[2*i+1]-ys)) s+= sd.move(x,y) if(i==0) else sd.line(x,y) return sd.path(width,s,lc=fill,fc=bkgr) def curveset(sd,scale,xyz, fill='#000', width=1, bkgr='none') : (xs,fx,xmin, ys,fy,ymin) = scale; s=''; n= len(xyz) print('curveset n='+str(n)) for i in range(n) : px,py,pz= tuple(xyz[i]) x= aprx(xmin+fx*(px-xs)); y= aprx(ymin+fy*(py-ys)) s+= sd.move(x,y) if(pz==0) else sd.line(x,y) return sd.path(width,s,lc=fill,fc=bkgr) def ballset(sd,scale,plt, fill='#000', r=5) : (xs,fx,xmin, ys,fy,ymin) = scale; s=''; n= len(plt) for i in range(n) : x= aprx(xmin+fx*(plt[i][0]-xs)); y= aprx(ymin+fy*(plt[i][1]-ys)) s+= sd.ball(x,y,r,fill) return s def label(sd,scale,txt,tx,ty) : # tx,ty plot coordinates not pixels (xs,fx,xmin, ys,fy,ymin) = scale x= aprx(xmin+fx*(tx-xs)); y= aprx(ymin+fy*(ty-ys)) return sd.labl(txt,x,y) def bareplot(fn,x,y) : # common x list, numerous y lists. write file fn.svg n=len(x); m=len(y); xys=[[]]*(m+1); winx=800; winy=600 xmin=min(x); xmax=max(x); ymin=y[0][0]; ymax=ymin for k in range(m): z=min(y[k]); ymin=min(ymin,z) for k in range(m): z=max(y[k]); ymax=max(ymax,z) xyf=[ xmin,ymin, xmax,ymin, xmax,ymax, xmin,ymax, xmin,ymin]; xys[0]=xyf for k in range(m) : cv=[0]*(2*n); xys[k+1]= cv for i in range(n) : cv[2*i]=x[i]; cv[2*i+1]=y[k][i] xs,fx,xpix= xmin, (winx-50)/(xmax-xmin+0.0),25 # scale of user units ys,fy,ypix= ymin,(-winy+50)/(ymax-ymin+0.0),winy-25 scale=(xs,fx,xpix, ys,fy,ypix) colo=['#777','#000','#00a','#077','#0a0','#770','#a00'] sd=svgdump(); buf=sd.plotbegin(winx,winy,1); i=0; dy=(ymax-ymin)/20.0 for t in xys : buf += curve(sd,scale, t, fill=colo[i%7]); i +=1 g=open(fn+'.svg','w'); g.write(buf+sd.plotend()); g.close() #### end plot def basisfunc(n,x,par) : # Ritz orthonormalbasis u=[0.0]*n; k,a,b,q= tuple(par) u[0]=1.0/sqrt(2); u[1]=x*sqrt(3/2.0); even=True for i in range(2,n) : if even : z=k[i]*x; u[i]= (a[i]*cos(z)+b[i]*cosh(z))/q[i] else : z=k[i]*x; u[i]= (a[i]*sin(z)+b[i]*sinh(z))/q[i] even= not even return u # Tupel Basisfunktionen(x) def initbasis(n=11,dbg=1) : # par=initbasis() Parameter der Basisfunktionen def fehler(z,sign) : return sin(z)*cosh(z)+sign*cos(z)*sinh(z) def interpol(xa,xb, ya,yb) : # interpolate x at y=0, given ya*yb < 0 return xa + ya*(xa-xb)/(yb-ya+0.0) def findzero(z,sign) : epsi=1e-10; dz=0.1 za=z-3*dz; ya=fehler(za,sign); bracket=False; ok= False; count=0 while (not bracket)and(count<25) : # Klammer um Nullstelle zb=za+dz; yb=fehler(zb,sign); bracket=(yb*ya)<0 if not bracket : za=zb;ya=yb; count+=1 if bracket : emax=epsi*(abs(ya)+abs(yb)); # print('bracket '+str([count,ya,yb])) while (not ok) and (count<50) : z=interpol(za,zb,ya,yb); y=fehler(z,sign) if (ya*y)>0 : ya=y;za=z else : yb=y;zb=z ok= (abs(y)<emax); count +=1 if ok and (dbg==1): print('n,c,z='+str([n,count,z])) if not ok: print('exit not ok n='+str(n)+' count='+str(count)); exit() return z ### k=[0]*n; a=[0]*n; b=[0]*n; q=[0]*n; even=True for m in range(2,n) : sign= 1 if even else -1; z= (m-1/2.0)*pi/2.0 z= findzero(z,sign) # solve tan(z)+ sign*tanh(z)=0 if even : a[m]=cosh(z); b[m]=cos(z) else : a[m]=sinh(z); b[m]=sin(z) k[m]=z; q[m]=sqrt(a[m]*a[m]+b[m]*b[m]) even= not even return [k,a,b,q] def platewave(tpe,x,y,pars) : # alle Ritz-Approximationen der stehenden Wellen u=basisfunc(7,x,pars); u0,u1,u2,u3,u4,u5,u6= tuple(u) v=basisfunc(7,y,pars); v0,v1,v2,v3,v4,v5,v6= tuple(v) # print('u='+str(u)); print('v='+str(v)) deltamu=0.0; lambd=[0]*15; w=[0]*15; wb=[0]*15 # A. in x und y ungerade, symmetrisch: w(x,y)=w(y,x)=-w(-x,y)=-w(x,-y) if tpe=='A' : lambd[0]= 12.43 - 18.0*deltamu w[0]= (u1*v1 + 0.0394*(u1*v3+v1*u3)-0.0040*u3*v3-0.0034*(u1*v5+u5*v1) +0.0011*(u3*v5+u5*v3)-0.0019*u5*v5) lambd[1]=378-57*deltamu w[1]= (-0.075*u1*v1+(u1*v3+u3*v1)+0.173*u3*v3+0.045*(u1*v5+u5*v1) -0.015*(u3*v5+u5*v3)-0.029*u5*v5) lambd[2]=1554 w[2]= (0.009*u1*v1-0.075*(u1*v3+v1*u3)+u3*v3-0.057*(u1*v5+u5*v1) +0.121*(u3*v5+u5*v3)-0.007*u5*v5) lambd[3]=2945 w[3]= u1*v5+u5*v1 lambd[4]=6303 w[4]= u3*v5+u5*v3 lambd[5]=13674 w[5]= u5*v5; last=5 # B. in x und y ungerade, antisymmetrisch: w(x,y)=-w(y,x)=-w(-x,y)=-w(x,-y) elif tpe=='B' : lambd[0]=316.1-270*deltamu w[0]= u1*v3-v1*u3+ 0.0002*(u1*v5-v1*u5)+0.0033*(u3*v5-v3*u5) lambd[1]=2713 w[1]=u1*v5-v1*u5 lambd[2]=5570 w[2]=u3*v5-v3*u5; last=2 # C. in x und y gerade, symmetrisch: w(x,y)=w(y,x)=w(-x,y)=w(x,-y) elif tpe=='C' : lambd[0]= 35.73+20.8*deltamu w[0]=(u0*v2+u2*v0-0.0238*u2*v2+0.0130*(u0*v4+v0*u4) +0.0026*(u2*v4+v2*u4)+0.0016*u4*v4) lambd[1]=266.0-274*deltamu w[1]= (0.0122*(u0*v2+v0*u2)+u2*v2-0.0188*(u0*v4+v0*u4) +0.0880*(u4*v2+v4*u2)-0.0044*u4*v4) lambd[2]=941 w[2]= u0*v4+v0*u4 lambd[3]=2020 w[3]= u2*v4+v2*u4 lambd[4]=5480 w[4]= u4*v4 lambd[5]=5640 w[5]= u0*v6+v0*u6 lambd[6]=7840 w[6]= u2*v6+v2*u6 lambd[7]=15120 w[7]= u4*v6+v4*u6 lambd[8]=28740 w[8]= u6*v6; last=8 # D. in x und y gerade, antisymm: w(x,y)=-w(y,x)=w(-x,y)=w(x,-y) elif tpe=='D' : lambd[0]=26.40 w[0]=u0*v2-v0*u2-0.0129*(u0*v4-v0*u4)-0.0045*(u2*v4-v2*u4) lambd[1]= 886 w[1]=u0*v4-v0*u4 lambd[2]=1702 w[2]=u2*v4-v2*u4 lambd[3]=5500 w[3]= u0*v6-v0*u6 lambd[4]=7310 w[4]= u2*v6-v2*u6 lambd[5]=13840 w[5]= u4*v6-v4*u6; last=5 # E. Doppeltoene (Chladni-Figuren nicht 90Grd-symm,) elif (tpe=='E')or(tpe=='F')or(tpe=='G') : # Entartung a*w(x,y)+b*w(y,x) (a,b)=(1,0),(1,-1) lambd[0]=80.8-73*deltamu w[0]=(u1*v2-0.0682*u3*v0 +0.0760*u3*v2+0.0260*u1*v4 +0.0073*u5*v0-0.0027*u3*v4-0.0112*u5*v2+0.0030*u5*v4) z= (v1*u2-0.0682*v3*u0 +0.0760*v3*u2+0.0260*v1*u4 +0.0073*v5*u0-0.0027*v3*u4-0.0112*v5*u2+0.0030*v5*u4) wb[0]=w[0]-z lambd[1]=237.1 w[1]= (+0.0678*u1*v2+u3*v0-0.0150*u3*v2+0.0355*u1*v4 +0.0000*u5*v0+0.0100*u3*v4-0.0007*u5*v2+0.0016*u5*v4) z= (+0.0678*v1*u2+v3*u0-0.0150*v3*u2+0.0355*v1*u4 +0.0000*v5*u0+0.0100*v3*u4-0.0007*v5*u2+0.0016*v5*u4) wb[1]=w[1]-z lambd[2]=746 w[2]=(-0.0709*u1*v2+0.0214*u3*v0+u3*v2-0.1260*u1*v4 -0.0038*u5*v0+0.1234*u3*v4-0.0095*u5*v2-0.0100*u5*v4) z= (-0.0709*v1*u2+0.0214*v3*u0+v3*u2-0.1260*v1*u4 -0.0038*v5*u0+0.1234*v3*u4-0.0095*v5*u2-0.0100*v5*u4) wb[2]=w[2]-z lambd[3]=1131 w[3]= u1*v4; wb[3]=u1*v4-u4*v1 lambd[4]=2497 w[4]=u5*v0; wb[4]=u5*v0-u0*v5 lambd[5]=3240 w[5]=u3*v4; wb[5]=u3*v4-u4*v3 lambd[6]=3927 w[6]=u5*v2; wb[6]=u5*v2-u2*v5 lambd[7]=9030 w[7]=u5*v4; wb[7]=u5*v4-v5*u4 lambd[8]=6036 w[8]=u1*v6; wb[8]=u1*v6-v1*u6 lambd[9]=10380 w[9]=u3*v6; wb[9]=u3*v6-v3*u6 lambd[10]=20400 w[10]=u5*v6; wb[10]=u5*v6-v5*u6; last=10 if (tpe=='F')or(tpe=='G') : w=wb else : print('Invalid type tpe='+tpe); exit() return lambd[:last+1], w[:last+1] def ballplot(fn,xa,ya,xb,yb,pball,pcurve) : # dots in pball, lines in pcurve winx=1000; winy=1000; xmin=xa;ymin=ya;xmax=xb;ymax=yb; rad=5; wid=3 xyf=[xmin,ymin, xmax,ymin, xmax,ymax, xmin,ymax, xmin,ymin] xs,fx,xpix= xmin, (winx-50)/(xmax-xmin+0.0),25 # scale user units, pixel@min ys,fy,ypix= ymin,(-winy+50)/(ymax-ymin+0.0),winy-25 scale=(xs,fx,xpix, ys,fy,ypix) colo=['#777','#000','#00a','#077','#0a0','#770','#a00'] sd=svgdump(); buf=sd.plotbegin(winx,winy,1); i=0; dy=(ymax-ymin)/20.0 # for t in xys : buf += curve(sd,scale, t, fill=colo[i%7]); i +=1 buf += curve(sd,scale, xyf, fill=colo[i%7],bkgr='#ff9') # frame for k in range(len(pball)) : buf+= ballset(sd,scale,pball[k],fill=colo[(k+1)%7], r=rad) for k in range(len(pcurve)) : buf+= curveset(sd,scale,pcurve[k],fill=colo[(k+1)%7], width=wid) g=open(fn+'.svg','w'); g.write(buf+sd.plotend()); g.close() def getlines(plt,d,ang) : # transform pointset to lines, max neighb distance d def dist(a,b,c,d) : u=c-a; v=d-b; return sqrt(u*u+v*v) def inline(plt,i,k) : # forbid bend angles with cosine < ang. j=prev[i]; ok= (j<0) if not ok : xa,ya=tuple(plt[j]); xb,yb=tuple(plt[i]); xc,yc=tuple(plt[k]) sp=(xc-xb)*(xb-xa)+(yc-yb)*(yb-ya) # scalar product nab=dist(xa,ya, xb,yb); nbc=dist(xb,yb, xc,yc) ok=(sp>(ang*nab*nbc)) return ok n=len(plt); next=[-1]*n; prev=[-1]*n; seen=[0]*n; done=False; i=-1 print('Point set size '+str(n)) while not done : if i<0 : i=0 # find unseen isolated point # while (i<n) and (seen[i]>0) and ((next[i]>=0)or(prev[i]>=0)) : i+=1 while (i<n) and ((seen[i]>0) or (next[i]>=0) or (prev[i]>=0)) : i+=1 # if i<n : seen[i]=1; # print('new start '+str(i)+'/'+str(n)) if i<n : # try to continue point i xa,ya= tuple(plt[i]); k=0; dmin=1000; kmin=-1; seen[i]=1 while (k<n) and (next[i]<0) : if (k!= i) and (prev[k]==-1) : xb,yb= tuple(plt[k]); dx=dist(xa,ya,xb,yb) if dx<dmin : dmin=dx; kmin=k k+=1 if (dmin<d) and inline(plt,i,kmin) : k=kmin; next[i]=k;prev[k]=i; ok = (xb>xa) or (yb>ya) if (not ok) and (prev[i]<0) and(next[k]<0) : # flip orientation next[k]=i;prev[i]=k else : i=k else : i=-1 else : done=True single=0; loops=0; paths=[]; seen=[0]*n for i in range(n) : if (next[i]<0)and(prev[i]<0) : single+=1 elif seen[i]==0 : seen[i]=1; links=0; j=i; go=True while (next[j]>=0)and go : j=next[j]; go=(seen[j]==0); seen[j]=1;links+=1 k=i; go=True while (prev[k]>=0)and go : k=prev[k]; go=(seen[k]==0); seen[k]=1;links+=1 print('Path '+str([k,j,links])); paths+=[[k,j]] print('Singles: '+str(single)+' Paths: '+str(len(paths))) return paths, next def mirrors(xyz,subset) : # symmetrie +-x, +-y. fuer subsets ABCDE # subset F,G: xyz doppelt so gross n=len(xyz); f= 2 if(subset=='F') else 4; xyzm=[[]]*(f*n) for i in range(n) : x,y,z= tuple(xyz[i]); xyzm[i]=[x,y,z]; xyzm[n+i]=[-x,-y,z] if subset != 'F' : xyzm[2*n+i]=[-x,y,z]; xyzm[3*n+i]=[x,-y,z] return xyzm def plotstuff(subset,curves,debug,version='1') : if debug<=2 : ballplot('multi-'+version+'-'+subset, -100,-100, 100,100, [], curves) if debug==2 : # Einzelkurven for i in range(len(curves)) : ballplot('single-'+version+'-'+subset+str(i+1), -100,-100, 100,100, [], [curves[i]]) def knotenbild(subset, w, debug=0, version='1') : # Chladni-Figur Knotenlinien # debug=2 macht Kurven mit Namen 'single'+subset+version dmin= 2.1; angle=0.6 n=len(w); m=len(w[0][0]); plot=[[]]*m; xy=[[]]*m print('Knotenbild n='+str(n)+' m='+str(m)+' n2='+str(len(w[0]))) for k in range(m) : # Nullstellen in Teilmenge k plt=[] for i in range(n) : z=w[0][i][k] if z==0 : plt+=[[0,i]] # abs(z)<epsilon? for i in range(1,n) : z=w[i][0][k] if z==0 : plt+= [[i,0]] for j in range(1,n) : # lineare Interpolationen der Nulldurchgaenge z=w[i][j][k]; x=w[i-1][j][k]; y=w[i][j-1][k]; u=w[i-1][j-1][k] if z==0 : plt+= [[i,j]] # max 1 Punkt per Paar (i,j) elif (z*x)<0 : plt += [[i-1 -x/(z-x+0.0), j]] elif (z*y)<0 : plt += [[i,j-1 -y/(z-y+0.0)]] # diagonal, z*u und x*y ? mehr Punkte elif (u*z)<0 : plt += [[i-1 -u/(z-u+0.0), j-1 -u/(z-u+0.0) ]] elif (x*y)<0 : plt += [[i-1 -x/(y-x+0.0), j-1 -y/(x-y+0.0) ]] plot[k]=plt; print('k='+str(k)+' len(plt)='+str(len(plt))) if debug==1 : ballplot('ball-'+subset,0,0,100,100,plot,[]) # 500K svg curves=[]; # m= min(3,m) # debug for i in range(m) : paths,next = getlines(plot[i], dmin,angle) # schlecht und langsam xyz=[]; plt=plot[i] print('Plotting paths '+str(len(paths))) for k in range(len(paths)) : h,j=paths[k]; z=0 while h != j : xyz+=[[plt[h][0],plt[h][1],z]]; z=1; h=next[h] xyz+=[[plt[j][0],plt[j][1],1]] curves+= [xyz] if (debug==3) else [mirrors(xyz,subset)] plotstuff(subset,curves,debug,version) return curves def simplecase(subset, dbg=0) : # subsets: A B C D E F G # case F,G needs w on x=-100..100,y=0..100, later node[-x,-y]=node[x,y] def vscale(f,v) : # scale vector v n=len(v); u=[0]*n for i in range(n) : u[i]=f*v[i] return u pars=initbasis(); nx=100; ny=100; w=[[]]*(nx+1) nodiag=('EFG'.find(subset)>=0); xs= (-1) if(subset=='G') else 1 sign=(-1) if('BD'.find(subset)>=0) else 1 # EFG no x=y mirror! for ix in range(nx+1) : x= ix/(nx+0.0); w[ix]=[[]]*(ny+1); ymax= (nx+1) if nodiag else (ix+1) for iy in range(ymax) : y= iy/(ny+0.0) la, w[ix][iy] = platewave(subset, xs*x,y,pars) if not nodiag : # x=y mirror for ix in range(nx+1) : for iy in range(ix) : w[iy][ix]= vscale(sign,w[ix][iy]) # Symm-Achse x=y print('Wellenwerte: '+str([len(w),len(w[0]),len(w[0][0])])) if ('ABCDE'.find(subset)>=0) : curves=knotenbild(subset, w, debug=dbg) if (subset=='F')or(subset=='G') : curves=knotenbild(subset, w, debug=3) return curves def specialcase(compute=0,version='1') : def merger(c1,c2) : n1=len(c1); n2=len(c2); d1=[[]]*(2*n1); d2=[[]]*(2*n2) for i in range(n1) : x,y,z= tuple(c1[i]); d1[i]=[x,y,z]; d1[n1+i]=[-x,-y,z] for i in range(n2) : x,y,z= tuple(c2[i]); d2[i]=[-x,y,z]; d2[n2+i]=[x,-y,z] return d1+d2 if compute==0 : curv1= simplecase('F') # quadrant x>0 y>0 curv2= simplecase('G') # quadrant x<0 y>0 else : curv1= computedcase('F', big=(compute==2)) curv2= computedcase('G', big=(compute==2)) m1=len(curv1); m2=len(curv2); curves=[[]]*m1 if m1 != m2 : print('specialcase m1 != m2, exit'); exit() for i in range(m1) : curves[i]= merger(curv1[i],curv2[i]) plotstuff('F', curves, debug=2, version=version) ### Eigenwerte nach wikipedias Algorithmus def rotjacobi(a,x,count,dbg=0) : # after en.wikipedia, Jacobi_rotation n=len(a); gain=0; tiny=1e-33; giant=1e33 for k in range(n): # upper triangle k<l, one similarity transf per pair for l in range(k+1,n) : # todo: keep list of pivots= largest z per row? z=a[k][l]; ok=(abs(z)<tiny) if ok : a[k][l]=0 # experiment else : # later transform with (c-s|sc) on indexpairs (kl) gain+=abs(z) # sign t=-abs(b)+... !! v=(a[l][l]-a[k][k]); b=v/(2.0*z); t= -abs(b)+sqrt(1+b*b) t=(-t) if(b<0) else t # if v=0, t=1, angle pi/4. if t>giant : s=0; c=1; tz=v elif t<-giant : s=0; c=-1; tz=-v else : u=sqrt(1.0+t*t); c=1.0/u; s=c*t; tz=t*z a[k][k] -= tz; a[l][l] += tz; a[k][l]=0 for h in range(n) : if (h!=k) and (h!=l) : # rotate pair {a_hk,a_hl}, use index symmetry. (hk,kh)= (h,k) if (h<k) else (k,h); ak=a[hk][kh] (hl,lh)= (h,l) if (h<l) else (l,h); al=a[hl][lh] a[hk][kh]= c*ak-s*al; a[hl][lh]= s*ak+c*al for h in range(n) : # rotate columns, no transpose later xk=x[k][h];xl=x[l][h]; x[k][h]= c*xk-s*xl; x[l][h]= s*xk+c*xl return gain def eigenloop(ma) : # symmetric matrix ma n=len(ma); x=[[]]*n; m=[[]]*n; epsi=1e-33; j=0; gain=1; eval=[0]*n for i in range(n) : x[i]=[0]*n; x[i][i]=1; m[i]=[0]*n for k in range(n) : m[i][k]=ma[i][k] while (j<(2*n))and(gain>epsi) : # matrix m is transformed gain=rotjacobi(m,x,j,dbg=1); j+=1; # print('Gain='+str(gain)) for i in range(n) : eval[i]=m[i][i] return eval,x # eval=eigenval list, rows of x are the eigenvectors def eigentest(m,ev,x,dbg=0) : # Gleichungen m x_i = ev_i x_i n=len(m); y=[0]*n; z=[0]*n; norms=0 for j in range(n) : # test eigenvector j, eigenval j norm=0 for i in range(n) : z[i]= ev[j]*x[j][i]; y[i]=0 for k in range(n) : y[i]+= m[i][k]*x[j][k] d=y[i]-z[i]; norm += d*d norms+= norm if dbg==1 : print('Eigenval '+str(j)+' Norm='+str(norm)) return norms ##### def fe(x) : return ('%11d' % x) if(type(x)==type(0)) else ('%+6.4e' % x) def fdump(s,m) : # vector or matrix debug dump n=len(m); ismat= (type(m[0])==type([])); t='' if not ismat : t='Vector '+s+' Dim='+str(n)+'\n' for k in range(n) : t+=' '+fe(m[k]) else : j=len(m[0]); t='Matrix '+s+' Dim='+str(n)+'*'+str(j)+'\n' for i in range(n) : for k in range(j) : t+=' '+fe(m[i][k]) if i<(n-1) : t+='\n' return t def norm(a) : n=len(a); z=0.0 for i in range(n) : z += a[i]*a[i] return sqrt(z) def wsum(a,b,f,g) : # weighted sum of 2 vectors n=len(a); c=[0]*n for i in range(n) : c[i]= f*a[i]+g*b[i] return c def dbasisfunc(n,x,par,dg=1) : # Ritz orthonormalbasis, derivatives du=[0.0]*n; k,a,b,q= tuple(par) du[0]=0; du[1]=sqrt(3/2.0); even=True; y=1 if dg==1 : # first deriv for i in range(2,n) : if even : z=k[i]*x; du[i]= (-a[i]*sin(z)+b[i]*sinh(z))*k[i]/q[i] else : z=k[i]*x; du[i]= ( a[i]*cos(z)+b[i]*cosh(z))*k[i]/q[i] even= not even else : # other degree up to 4 du[1]=0; feven=[cos,sin,cos,sin,cos]; fodd=[sin,cos,sin,cos,sin] se=[1,-1,-1,1,1]; so=[1,1,-1,-1,1] heven=[cosh,sinh,cosh,sinh,cosh]; hodd=[sinh,cosh,sinh,cosh,sinh] for i in range(2,n) : # dg==0 function itself y=1; z=k[i]*x for j in range(dg) : y *= k[i] if even : du[i]= (a[i]*se[dg]*feven[dg](z)+b[i]*heven[dg](z))*y/q[i] else : du[i]= (a[i]*so[dg]*fodd[dg](z)+b[i]*hodd[dg](z))*y/q[i] even= not even return du # Tupel def alphaomega(m,n,par) : # alpha= um'*un', omega=um"*un integrals. if (m==0) or (n==0) : alpha=0; omega=0 elif (m==1)and(n==1) : alpha=3; omega=0 else : k, u1, du1= tuple(par) # u1, du1; Liste von Basisfunc und Ableitg bei x=1 km=k[m]; kn=k[n] if (m==n)and(m%2==0) : ch=cosh(km); co= cos(km); ch2=ch*ch; co2=co*co; q=ch2+co2 alpha= (km*km*(ch2-co2)+6*km*(co2*ch2*tanh(km)))/q omega= (-km*km*(ch2-co2)+2*km*(co2*ch2*tanh(km)))/q elif (m==n) and (m%2==1) : sh=sinh(km); si= sin(km); sh2=sh*sh; si2=si*si; q=sh2-si2 alpha= (km*km*(sh2+si2)+6*km*(si2*sh2*coth(km)))/q omega= (-km*km*(sh2+si2)+2*km*(si2*sh2*coth(km)))/q elif (m+n)%2 == 1 : alpha=0; omega=0 # equal parity --> vanishes else : # vanish if m+n is odd km4=km*km*km*km; kn4=kn*kn*kn*kn; q=km4-kn4 alpha= 2*(km4*u1[m]*du1[n]-kn4*u1[n]*du1[m])/q omega= 2*km4*(du1[m]*u1[n]-u1[m]*du1[n])/q return alpha,omega def vmatrix(m,n,p,q, mu, par): # Element zwischen um*vn, up*vq. if (m==p)and(n==q) : k,u1,du1= tuple(par) z=k[m];km4=z*z*z*z; z=k[n]; kn4=z*z*z*z amm,omm= alphaomega(m,m,par); ann,onn= alphaomega(n,n,par) v= km4+kn4+2*mu*omm*onn + 2*(1-mu)*amm*ann else : amp,omp= alphaomega(m,p,par); anq,onq= alphaomega(n,q,par) aqn,oqn= alphaomega(q,n,par); apm,opm= alphaomega(p,m,par) v= mu*(omp*oqn+opm*onq)+2*(1-mu)*anq*amp return v def ritzmatrix(serie='A', mode=0, normalize=False, big=False) : # Auswahl einer symmetrischen Orthonormalbasis aus dem VONS der Stabwellen # return: Matrix des V-operators in dieser Basis, Index-triplets der Basis # dbg mode=1 : zeilen = Faktoren u1v1 u1v3 u1v5 u3v3 u3v5 u5v5 wie im Artikel # big=False # big Approximation einen Grad hoeher n=11; mu=0.225 # Querkontraktions-Parameter, Glas pars=initbasis(n=n,dbg=0); k,a,b,q= tuple(pars) u1= basisfunc(n,1,pars); du1=dbasisfunc(n,1,pars) vpar=[k, u1, du1] # ixtrip= pairs with target index and sign contrib if serie=='A' : # index triplets ui*vj itarget(base 1!). odd odd sym ixtrip= [[1,1,1],[1,3,2],[3,1,2],[3,3,3],[1,5,4],[5,1,4], [3,5,5],[5,3,5],[5,5,6]] if big : ixtrip+=[[1,7,7],[7,1,7],[3,7,8],[7,3,8],[5,7,9],[7,5,9],[7,7,10]] if serie=='B' : # odd odd antisym ixtrip=[[1,3,1],[3,1,-1],[1,5,2],[5,1,-2],[3,5,3],[5,3,-3]] if big: ixtrip+= [[1,7,4],[7,1,-4], [3,7,5],[7,3,-5], [5,7,6],[7,5,-6]] if serie=='C' : # even even sym ixtrip=[[0,2,1],[2,0,1],[2,2,2],[0,4,3],[4,0,3],[2,4,4],[4,2,4],[4,4,5], [0,6,6],[6,0,6],[2,6,7],[6,2,7],[4,6,8],[6,4,8],[6,6,9]] if big : ixtrip+=[[0,8,10],[8,0,10],[2,8,11],[8,2,11],[4,8,12],[8,4,12], [6,8,13],[8,6,13],[8,8,14]] if serie=='D' : # even even antisym ixtrip=[[0,2,1],[2,0,-1],[0,4,2],[4,0,-2],[2,4,3],[4,2,-3], [0,6,4],[6,0,-4],[2,6,5],[6,2,-5],[4,6,6],[6,4,-6]] if big : ixtrip+= [[0,8,7],[8,0,-7],[2,8,8],[8,2,-8],[4,8,9],[8,4,-9], [6,8,10],[8,6,-10]] if serie=='E' : # odd even ixtrip=[[1,2,1],[3,0,2],[3,2,3],[1,4,4],[5,0,5],[3,4,6], [5,2,7],[5,4,8]] if big : ixtrip+=[[1,6,9],[3,6,10],[5,6,11],[7,6,12], [7,0,13],[7,2,14],[7,4,15]] if (serie=='F')or(serie=='G') : # (odd even - even odd) ixtrip=[[1,2,1],[2,1,-1], [3,0,2],[0,3,-2], [3,2,3],[2,3,-3], [1,4,4],[4,1,-4], [5,0,5],[0,5,-5], [3,4,6],[4,3,-6], [5,2,7],[2,5,-7], [5,4,8],[4,5,-8]] if big : ixtrip+=[[1,6,9],[6,1,-9], [3,6,10],[6,3,-10], [5,6,11],[6,5,-11], [7,6,12],[6,7,-12], [7,0,13],[0,7,-13], [7,2,14],[2,7,-14], [7,4,15],[4,7,-15]] rowtrip= ixtrip; coltrip=ixtrip # row and column triplets ui,vj,itarget if (serie=='A')and(mode==1) : rowtrip=[[1,1,1],[1,3,2],[3,3,3],[1,5,4],[3,5,5],[5,5,6]] mcol=len(coltrip); mrow=len(rowtrip) v=[[]]*mrow; mmat=0 # mmat size of final matrix # ixpairs is finite-dim subspace in one of the symmetry classes for i in range(mrow) : v[i]=[0]*mcol; mi,ni,xi= tuple(rowtrip[i]); mmat=max(mmat,abs(xi)) for j in range(mcol) : mj,nj,xj= tuple(coltrip[j]); v[i][j]= vmatrix(mi,ni,mj,nj, mu,vpar) rm=[[]]*mmat; nm=[[]]*mmat # Ritz matrix and normalize count for h in range(mmat) : rm[h]=[0]*mmat; nm[h]=[0]*mmat for i in range(mrow) : # add to row i,xi mi,ni,xi= tuple(rowtrip[i]); (si,xi) =(1,xi-1) if (xi>0) else (-1,-xi-1) for j in range(mcol) : # addto column j,xj mj,nj,xj= tuple(coltrip[j]); (sj,xj) =(1,xj-1) if (xj>0) else (-1,-xj-1) rm[xi][xj]+= si*sj*v[i][j]; nm[xi][xj] +=1 if normalize : # divide rm by square-root of counts nm, for orthonormal for i in range(mmat) : for j in range(mmat) : if nm[i][j]>1 : rm[i][j]= rm[i][j]/sqrt(nm[i][j]) return rm, ixtrip, pars # pars= Parameter des VONS if __name__ == '__main__' : # do not export what follows def eigenwave(ev,ixt,x,y,pars) : # stehende Wellen, vektoren ev in Basis ixt u=basisfunc(9,x,pars); v=basisfunc(9,y,pars) # max Ordnung 8 bw=[0.0]*16; kmax=0; n=len(ixt) for i in range(n) : # Basis-Wellenwerte j,k,nd= tuple(ixt[i]); (sgn,ix)= (1,nd-1) if (nd>0) else (-1,-nd-1) bw[ix]+= sgn*u[j]*v[k]; kmax=max(kmax,ix) m=kmax+1; w=[0.0]*m # linearkombiniert zu Eigenwellen for i in range(m) : for j in range(m) : w[i]+= ev[i][j]*bw[j] return w # m Ergebnisse am Punkt (x,y) def dumpmodes(subset, ixt, ewert,evec,ref) : # Doku text output n=len(ixt); m=len(evec); bw=['']*m; count=[0]*m d='Serie '+subset+'. Basisfunktionen:'+str(m)+'. Faktor q= 1/sqrt(2)\n' for i in range(n) : # Basis-Wellenformeln j,k,nd= tuple(ixt[i]); (sgn,ix)= ('+',nd-1) if (nd>0) else ('-',-nd-1) bw[ix]+= sgn+'u'+str(j)+'*v'+str(k); count[ix]+=1 for j in range(m) : s=('('+bw[j]+')') if(count[j]==1) else ('('+bw[j]+')*q'); d+=(s+'\n') d+='Eigenwerte und Eigenvektor-Koeffizienten in der Basis\n' for j in range(m) : s=fe(ewert[j])+' : [' for k in range(m): s+=' '+ fe(evec[j][k]) d+=s+' ]\n' d+= '**** Ritz Computer (Eigenwert-Vergleich)\n'; nr=len(ref) for j in range(nr) : d+= ' '+fe(ref[j])+' '+fe(ewert[j])+'\n' print(d); return d def computedcase(subset, dbg=0, big=False) : # subsets: A B C D E F G # case F,G needs w on x=-100..100,y=0..100, later node[-x,-y]=node[x,y] def vscale(f,v) : # scale vector v n=len(v); u=[0]*n for i in range(n) : u[i]=f*v[i] return u nx=100; ny=100; w=[[]]*(nx+1) nodiag=('EFG'.find(subset)>=0); xs= (-1) if(subset=='G') else 1 sign=(-1) if('BD'.find(subset)>=0) else 1 # EFG no x=y mirror! rm,ixt,pars= ritzmatrix(subset,0,True,big) # rm= zu diagonalisierende Operatormatrix ## eval,evec,rank= eigenrun(0,rm,dbg=1) # obsolete, use eigenloop eval,evec= eigenloop(rm) print(fdump(' eigenvals',eval)) ref,z = platewave(subset, 0,0, pars) # reference eigenval spectrum if (subset!='G') and False : # deaktivierter Log s= dumpmodes(subset,ixt, eval,evec,ref) f=open('ritzmodes.txt','a'); f.write(s+'\n'); f.close() for ix in range(nx+1) : x= ix/(nx+0.0); w[ix]=[[]]*(ny+1); ymax= (nx+1) if nodiag else (ix+1) for iy in range(ymax) : y= iy/(ny+0.0) w[ix][iy] = eigenwave(evec,ixt, xs*x,y,pars) if not nodiag : # x=y mirror for ix in range(nx+1) : for iy in range(ix) : w[iy][ix]= vscale(sign,w[ix][iy]) # Symm-Achse x=y print('Wellenwerte: '+str([len(w),len(w[0]),len(w[0][0])])) if ('ABCDE'.find(subset)>=0) : curves=knotenbild(subset, w, debug=dbg, version='2') if (subset=='F')or(subset=='G') : curves=knotenbild(subset, w, debug=3, version='2') return curves def ritzplots3() : # text Resultate, subset A B C D E F f=open('ritzmodes.txt','w') for subset in ['A','B','C','D','E','F'] : rm,ixt,pars= ritzmatrix(subset,0,True,big=True) ref,z = platewave(subset, 0,0, pars) # reference eigenval spectrum eval,evec= eigenloop(rm); norm=eigentest(rm,eval,evec) print('Subset='+subset+' Quality Eigenvals='+str(norm)) s= dumpmodes(subset,ixt, eval,evec,ref); f.write(s+'\n') f.close() def chladniquadrat() : for c in ['A','B','C','D','E'] : simplecase(c, dbg=2) specialcase() # diagonale 'F'-Serie (E bis) from time import time def ritzplots() : # Urversion t0=time() #simplecase('A',dbg=2) chladniquadrat() t1=time() print('Laufzeit (sek)= '+str(int(t1-t0))) def ritzplots2() : # Neuberechnung t0=time() computedcase('A', dbg=2, big=True) computedcase('B', dbg=2, big=True) computedcase('C', dbg=2, big=True) computedcase('D', dbg=2, big=True) computedcase('E', dbg=2, big=True) specialcase(compute=2,version='2') # Serie 'F' t1=time() print('Laufzeit (sek)= '+str(int(t1-t0))) def startdialog() : try : s=input('Chladni-Figuren Urversion(1) Neurechnung(2) Eigenwerte(3)?') except : s='???' s= str(s)+'?' if s[0]=='1' : ritzplots() elif s[0]=='2' : ritzplots2() elif s[0]=='3' : ritzplots3() else : print('Eingabefehler.') startdialog()
Listing chladni.py
Bearbeiten# -*- coding: utf-8 -*- from math import sqrt from ritz import eigenloop, eigentest, knotenbild, ritzmatrix # def knotenbild(subset, w, debug=0, version='1') : # Figur aus Knotenlinien # debug=2 macht Kurven mit Namen 'single'+subset+version def fe(x) : return ('%11d' % x) if(type(x)==type(0)) else ('%+6.4e' % x) def fdump(s,m) : # vector or matrix debug dump n=len(m); ismat= (type(m[0])==type([])); t='' if not ismat : t='Vector '+s+' Dim='+str(n)+'\n' for k in range(n) : t+=' '+fe(m[k]) else : j=len(m[0]); t='Matrix '+s+' Dim='+str(n)+'*'+str(j)+'\n' for i in range(n) : for k in range(j) : t+=' '+fe(m[i][k]) if i<(n-1) : t+='\n' return t def norm(a) : n=len(a); z=0.0 for i in range(n) : z += a[i]*a[i] return sqrt(z) def wsum(a,b,f,g) : # weighted sum of 2 vectors n=len(a); c=[0]*n for i in range(n) : c[i]= f*a[i]+g*b[i] return c def dpoly(p) : # Polynom-Ableitung n=len(p); q=[0]*(n-1) for i in range(n-1) : q[i]=p[i+1]*(i+1) return q def evpoly(p,x) : # Polynom-Auswertung n=len(p); y=0; z=1 for i in range(n) : y+= z*p[i]; z *= x return y def tripleta(serie,max,dbg=0) : # serie=symmetry class. max= maximal order # get Index triplets for a basis of symmetric linear combs # i=k=0 excluded from function basis ? m=1; grow=False; t=[] # m=target index + 1 with sign, t=triplet list. if serie=='A' : i=1; k0=1; k=k0; sm=1 # sm= mirror symm if serie=='B' : i=1; k0=1; k=k0; sm=-1 if serie=='C' : i=0; k0=0; k=k0; sm=1 if serie=='D' : i=0; k0=0; k=k0; sm=-1 if serie=='E' : i=0; k0=1; k=k0; sm=-1 if serie=='F' : i=0; k0=1; k=k0; sm=0 while (i<=max)and(k<=max) : # Kombis (0,0) (01) (10) sind immer steril ? #if ((sm==1)and((i+k)>0)) or (i!=k) : t+= [[i,k,m]]; grow=True ## if ((i+k)>1) and ((sm==1) or (i!=k)) : t+= [[i,k,m]]; grow=True if (sm>=0) or (i!=k) : t+= [[i,k,m]]; grow=True if grow and (i!=k) and (sm!=0) : t+=[[k,i,sm*m]] if grow : m+=1; grow=False (i,k) = (i,k+2) if (k<i) else (i+2,k0) if dbg==1 : print(str(t)) return t,m-1 # m is dim of target matrix to fill ### Funktional-Extrem mit orthonormalen Polynomen def scalprod(p,q) : # Integral Polynome ueber -1...1 n=len(p); m=len(q); sp=0 for i in range(n) : for k in range(m) : j=i+k; z=(0 if(j%2>0) else 2.0/(j+1.0)); sp+= p[i]*q[k]*z return sp def spmatrix(p) : # debug n=len(p); m=[[]]*n for i in range(n) : m[i]=[0]*n for k in range(n) : m[i][k]= scalprod(p[i],p[k]) print(fdump('spmatrix',m)) def derivprod(p,q,np,nq) : # product of derivative (p,np) with (q,nq) for i in range(np) : p= dpoly(p) for i in range(nq): q= dpoly(q) return scalprod(p,q) # needed derivprod(p,q,1,1), (p,q,2,0), (p,q,2,2) def orthonormset(n,sprod,mode=0) : # make polynomials p[0] to p[n], wrt scalar product sprod() def normalize(p) : z=sprod(p,p); q= 1.0/sqrt(z) for j in range(len(p)) : p[j] *= q n1=n+1; p=[[]]*n1; sp=[0]*n1 for i in range(n1) : if (mode==0)or(i<2) : p[i]=[0]*(i+1); p[i][i]=1 elif mode==1 : # bigger polys with @boundary 2nd, 3rd deriv to vanish ni=i+4; p[i]=[0]*(ni+1); p[i][i]=1; z=i*(i-1) p[i][i+2]=-2*z/(i+1.0)/(i+2.0); p[i][i+4]= z/(i+3.0)/(i+4.0) normalize(p[0]) for i in range(1,n1) : # orthogonalize p[i] wrt to subset {0...i-1} for k in range(i) : sp[k]= sprod(p[i],p[k]) for k in range(i) : for j in range(len(p[k])) : p[i][j]-= sp[k]*p[k][j] normalize(p[i]) # for i in range(n1) : print(fdump('debug',p[i]))# are even/odd alternating return p def potentialmatrix(serie, max, nu, mode=0, dbg=0) : # matrices on ortho poly sets def auxmatrices(p) : n=len(p); dp00=[[]]*n; dp11=[[]]*n; dp20=[[]]*n; dp22=[[]]*n for i in range(n) : dp00[i]=[0]*n; dp11[i]=[0]*n; dp20[i]=[0]*n; dp22[i]=[0]*n for k in range(n) : dp00[i][k]= scalprod(p[i],p[k]) dp11[i][k]= derivprod(p[i],p[k],1,1) dp20[i][k]= derivprod(p[i],p[k],2,0) dp22[i][k]= derivprod(p[i],p[k],2,2) return dp00, dp11, dp20, dp22 # def vorthomatrix(n,m,p,q,nu,dp00,dp11,dp20,dp22) : # pot. on orthog (nm|pq) # V(f,g)=fxx*gxx+fyy*gyy+nu(fxx*gyy+fyy*gxx)+2(1-nu)(fxy*gxy) a= dp22[n][p]*dp00[m][q] # derivpr(p[n],p[p],2,2) b= dp22[m][q]*dp00[n][p] # derivpr(p[m],p[q],2,2) c= dp11[n][p]*dp11[m][q] # derivpr(p[n],p[p],1,1)*derivpr(p[m],p[q],1,1) d= dp20[n][p]*dp20[q][m] # derivpr(p[n],p[p],2,0)*derivpr(p[m],p[q],0,2) e= dp20[p][n]*dp20[m][q] # derivpr(p[n],p[p],0,2)*derivpr(p[m],p[q],2,0) f=1;g=2 #dbg v= (a+b) + f*nu*(d+e) + g*(1-nu)*c; s=dp00[n][p]*dp00[m][q] #s=scalprod return v,s # pol= orthonormset(max,scalprod,mode=mode) dp00, dp11, dp20, dp22 = auxmatrices(pol) ixtrip,mmat= tripleta(serie,max,dbg=dbg); nix=len(ixtrip) pm=[[]]*mmat; nm=[[]]*mmat; sm=[[]]*mmat; for h in range(mmat) : pm[h]=[0]*mmat; nm[h]=[0]*mmat; sm[h]=[0]*mmat for i in range(nix) : # add to row xi mi,ni,xi= tuple(ixtrip[i]); (si,xi) =(1,xi-1) if (xi>0) else (-1,-xi-1) for j in range(nix) : # addto column xj mj,nj,xj= tuple(ixtrip[j]); (sj,xj) =(1,xj-1) if (xj>0) else (-1,-xj-1) v,s= vorthomatrix(mi,ni, mj,nj, nu, dp00,dp11,dp20,dp22) pm[xi][xj]+= si*sj*v; sm[xi][xj]+= si*sj*s; nm[xi][xj]+=1 for i in range(mmat) : # normalize for j in range(mmat) : if nm[i][j]>1 : z=1.0/sqrt(nm[i][j]); pm[i][j]*=z; sm[i][j]*=z if dbg==1 : print(fdump('pm',pm)) # potential energy matrix, bug serie E? if dbg==1 : print(fdump('sm',sm)) # scalar prod matrix seems correct. return pm, ixtrip, pol def showsorted(ser,v,j) : # lowest positive values in vector v n=len(v); ix=[-1]*n; iy=[0]*n; ival=0; s='Serie '+ser+':' bound=1e-12; vsort=[0]*j for i in range(n) : vmin=1e33; kmin=-1 for k in range(n) : if (ix[k]<0) and (v[k]<vmin) and (v[k]>bound) : vmin=v[k]; kmin=k iy[i]=kmin; ix[kmin]=ival; ival+=1 for i in range(min(j,n)) : s+=' '+fe(v[iy[i]]); vsort[i]=v[iy[i]] return vsort,s def wellenbilder(subset,eval,evec,ixt,pol) : # Eigenkombinationen aus Polynomen # indizes der 5 kleinsten positiven Eigenwerte def auswahl(eva,nmax) : m=len(eva); nmax=min(nmax,m); ix=[-1]*nmax; use=[0]*m; bound=1e-12 for i in range(nmax) : imin=-1; emin=1e33 for k in range(m) : if (use[k]==0)and(eva[k]>bound)and(eva[k]<emin): (imin,emin)=(k,eva[k]) ix[i]=imin; bound=eva[imin]; use[imin]=1 print('Auswahl:'+str(ix)) return ix # def eigenwave(iew, ev, ixt,x,y,pol) : # Wellen aus Vektoren ev in Basis ixt np=len(pol); u=[0]*np; v=[0]*np; new=len(iew) for i in range(np) : u[i]= evpoly(pol[i],x); v[i]= evpoly(pol[i],y) bw=[0.0]*50; kmax=0; n=len(ixt) # bw=basiswellen, w=eigenwellen for i in range(n) : # Basis-Wellenwerte j,k,nd= tuple(ixt[i]); (sgn,ix)= (1,nd-1) if (nd>0) else (-1,-nd-1) bw[ix]+= sgn*u[j]*v[k]; kmax=max(kmax,ix) m=kmax+1; w=[0.0]*new # linearkombiniert zu Eigenwellen for h in range(new) : i=iew[h] for j in range(m) : w[h]+= ev[i][j]*bw[j] return w # m Ergebnisse am Punkt (x,y) # def vscale(f,v) : # scale vector v n=len(v); u=[0]*n for i in range(n) : u[i]=f*v[i] return u # iew= auswahl(eval,5); new=len(iew) nx=100; ny=100; w=[[]]*(nx+1); xs=1 for ix in range(nx+1) : x= ix/(nx+0.0); w[ix]=[[]]*(ny+1) for iy in range(ny+1) : y= iy/(ny+0.0); w[ix][iy] = eigenwave(iew, evec,ixt, xs*x,y,pol) print('Wellenwerte: '+str([len(w),len(w[0]),len(w[0][0])])) knotenbild(subset, w, debug=2, version='3') # ritz.knotenbild return w def tryorthopolyn(maxi, version, dbg=0) : print('Orthogonale Polynome maxi='+str(maxi)+' version='+str(version)) nu=0.225; for serie in ['A','B','C','D'] : ## ,'E','F'] : ma,ixt,pol= potentialmatrix(serie,maxi,nu, mode=version, dbg=dbg) eva,xa= eigenloop(ma) eigentest(ma,eva,xa, dbg=dbg) vsort, ssort= showsorted(serie,eva,5); print(ssort) wellenbilder(serie,eva,xa,ixt,pol) # knotenbilder def spektrumvergleich(maxi) : nu=0.225; version=0; print('Spektrum Balkenbasis Polynombasis') for serie in ['A','B','C','D'] : ma,ixt,pol= potentialmatrix(serie,maxi,nu, mode=version, dbg=0) eval,xa= eigenloop(ma) vsort,ssort = showsorted(serie,eval,5) rm,ixr,pars= ritzmatrix(serie,0,True,big=True) reval,revec= eigenloop(rm); # print(str(reval[:5])) for k in range(5) : s=serie+str(k+1)+' '+fe(reval[k])+' '+fe(vsort[k]); print(s) def startdialog() : s=str(input('Polynombasis: Chladni-Figuren(1) Eigenwert-Vergleich(2)?'))+'?' if s[0]=='1' : tryorthopolyn(15,0) # production run elif s[0]=='2' : spektrumvergleich(15) else : print('Eingabefehler.') startdialog()