Quantenmechanik/ Magnetfeld/ Skript
Skript zum Zeeman-Effekt. Schreibt die Datei zeeman.svg
from math import sqrt # computations for angular momentum def colsalign(s) : # align string array s columns, strings start with ' ' n=len(s); m=32; cols=[0]*m; kmax=0 for i in range(n) : t=s[i]; h=0; j=t.find(' ',h+1); k=0 while j>=0 : if ((j-h)>cols[k]) : cols[k]=j-h-1 h=j; j=t.find(' ',h+1); k+=1 j=len(t) if ((j-h)>cols[k]) : cols[k]=j-h-1 if (k+1)>kmax : kmax=k+1 # dbg print('Cols: '+str(cols[:kmax])) for i in range(n) : t=s[i]; h=0; j=t.find(' ',h+1); lt=len(t); k=0; v='' while j<=lt : u=t[h:j]+(' '*(cols[k]-(j-h-1))); v+=u h=j; j= (lt+10) if (h==lt) else t.find(' ',h+1) k+=1; j= lt if (j<0) else j s[i]= v return s def hasfact(x,z) : return (x>0) and ((x % z)==0) def havefact(x,y,z) : # x,y have common factor z? fx=hasfact(x,z); fy=hasfact(y,z) return (fx and fy) or (fx and (y==0)) or (fy and (x==0)) def normalize(x) : # rational-square root number x pn=[2,3,5,7,11,13,17,19,23]; ln= len(pn) # small prime nbrs ps=[0,1,4,9,16,25,36,49,64,81,100]; ls=len(ps) # small squares pr,pi,q,sp,sq = tuple(x) pr,sgr= (-pr,-1) if (pr<0) else (pr,1) pi,sgi= (-pi,-1) if (pi<0) else (pi,1) for i in range(2,len(ps)) : z=ps[i] while hasfact(sp,z) : sp=div(sp,z); pr *= i; pi *= i while hasfact(sq,z) : sq=div(sq,z); q *=i for i in range(ln) : z=pn[i] while hasfact(sp,z) and hasfact(sq,z) : sp=div(sp,z); sq=div(sq,z) while havefact(pr,pi,z) and hasfact(q,z) : pr=div(pr,z); pi=div(pi,z); q=div(q,z) if (pr==0)and(pi==0) : q=1;sp=1;sq=1 x[0],x[1],x[2],x[3],x[4] = (pr*sgr,pi*sgi,q,sp,sq) def real(x) : # rational square root number, get real part pr,pi,q,sp,sq = tuple(x); return sqrt(sp/(sq+0.0))*pr/(q+0.0) def encodenb(x) : pr,pi,q,sp,sq = tuple(x); s=''; w='' if (sp!=1)or(sq!=1) : w='\\sqrt{'; w += str(sp) if(sq==1) else ('\\frac{'+str(sp)+'}{'+str(sq)+'}') w +='}' if pr != 0 : u=str(pr); s += u if (q==1) else ('\\frac{'+u+'}{'+str(q)+'}') s = w if((s=='1')and(w!='')) else (s if (s=='1') else (s+w)) if pi != 0 : if (pr!=0) and (pi>0) : s +='+i' elif (pi<0) : s += '-i'; pi=-pi else : s += 'i' u=str(pi); u='' if ((pi==1)and(q==1)) else u s += u if (q==1) else ('\\frac{'+u+'}{'+str(q)+'}') s = s+w if (pr==0)and(pi==0) : s='0' return s def displaynb(x) : # simple readable, root in square brackets pr,pi,q,sp,sq = tuple(x); s=''; w='' if (sp!=1)or(sq!=1) : w='['; w += str(sp) if(sq==1) else (str(sp)+'/'+str(sq)) w +=']' if pr != 0 : u=str(pr); s += u if (q==1) else (u+'/'+str(q)) s = w if((s=='1')and(w!='')) else (s if (s=='1') else (s+w)) if pi != 0 : if (pr!=0) and (pi>0) : s +='+i' elif (pi<0) : s += '-i'; pi=-pi else : s += 'i' u=str(pi); u='' if ((pi==1)and(q==1)) else u s += u if (q==1) else (u+'/'+str(q)) s = s+w if (pr==0)and(pi==0) : s='0' return s def reformat(x) : # int, rational, rcomplex to root numbers if type(x)==type(1) : z=[x,0,1,1,1]; n=-1 elif type(x)==type([]) : n=len(x) if n==1 : z=[x[0],0,1,1,1] if n==2 : z=[x[0],0,x[1],1,1] if n==3 : z=[x[0],x[1],x[2],1,1] if n==5 : z=x if (n>5)or(n==0)or(n==4): print('reformat '+str(x)+' not supported.'); exit() return z def multip(x,y) : # format (u,v,w,p,q) = (u+iv)/w sqrt(p/q) xx=reformat(x); yy=reformat(y) xpr,xpi,xq,xsp,xsq= tuple(xx); ypr,ypi,yq,ysp,ysq= tuple(yy) pr= xpr*ypr-xpi*ypi; pi= xpr*ypi+ypr*xpi; q=xq*yq; sp=xsp*ysp;sq=xsq*ysq z= [pr,pi,q,sp,sq]; normalize(z); return z def addit(x,y) : xx=reformat(x); yy=reformat(y) return lincomb(xx,yy,1,1) def sqroot(x) : # input should be (p,0,q,1,1) pr,pi,q,sp,sq = tuple(x) if (pi!=0)or(sp!=1)or(sq!=1) : print('sqroot undefined.'); exit() sp=pr;sq=q;pr=1;q=1; z=[pr,pi,q,sp,sq]; normalize(z); return z def imagi(x) : pr,pi,q,sp,sq = tuple(x); return [-pi,pr,q,sp,sq] def scale(x,f) : pr,pi,q,sp,sq = tuple(x); return [pr*f,pi*f,q,sp,sq] def lincomb(x,y,f,g) : # f,g integer # a sqrt(r/s) + b sqrt(p/q) ?= sqrt(rp/qs) ? # can only be combined if r/s and p/q differ by square factor T/U ? # first write rq/qs, ps/qs and test if rq,ps have square factor ps=[0,1,4,9,16,25,36,49,64,81,100]; ls=len(ps) # small squares xpr,xpi,xq,xsp,xsq= tuple(x); xpr *= f; xpi *=f ypr,ypi,yq,ysp,ysq= tuple(y); ypr *= g; ypi *=g if (xpr==0)and(xpi==0) : z=[ypr,ypi,yq,ysp,ysq] elif (ypr==0)and(ypi==0) : z= [xpr,xpi,xq,xsp,xsq] else : sq=xsq*ysq; xp=xsp*ysq; yp=ysp*xsq for i in range(2,len(ps)) : z=ps[i] while hasfact(xp,z) : xp=div(xp,z); xpr *= i; xpi *= i while hasfact(yp,z) : yp=div(yp,z); ypr *= i; ypi *= i # here xp/sq new sqrt arg? if yp=n xp, rewrite x ? if xp != yp : print('lincomb:sqrt clash'+str([xp,yp])); exit() sp=xp; q=xq*yq; pr=xpr*yq+ypr*xq; pi=xpi*yq+ypi*xq z= [pr,pi,q,sp,sq] normalize(z); return z def matshow(s,x,new=0) : # new= 1 simplified, columns. new=0 raw. # new= 2 use encodenb, latex-like, check square hermitian n=len(x); m=len(x[0]); print(s); t=''; ok=True; tt=['']*n for i in range(n) : for k in range(m) : if (new==2) and (k>0) : t +=' &' if (new==1) : t +=' '+displaynb(x[i][k]) if (new==2) : t +=' '+encodenb(x[i][k]) if new==0 : t +=' '+str(x[i][k]) # beware about v, we need a copy! if new==2 : u=x[i][k]; v= [] + x[k][i]; v[1]= -v[1]; ok= ok and isequal(u,v) if (new==2) and (i<(n-1)) : t +=' \\\\'; tt[i]=t; t='' if new==1 : colsalign(tt) for i in range(n) : print(tt[i]) if new==2 : print('Test Hermitian: '+str(ok)) return tt def vecshow(s,x) : n=len(x); print(s); t='' for k in range(n) : t +=' '+displaynb(x[k]) print(t) def paulimats() : z=[0,0,1,1,1]; u=[1,0,1,1,1]; i=[0,1,1,1,1]; j=[0,-1,1,1,1]; v=[-1,0,1,1,1] sig=[[],[],[],[]] sig[0]= [[u,z],[z,u]] sig[1]= [[z,u],[u,z]] ; matshow('S1',sig[1]) sig[2]= [[z,j],[i,z]] ; matshow('S2',sig[2]) sig[3]= [[u,z],[z,v]] ; matshow('S3',sig[3]) for h in range(1,4) : for k in range(1,4) : a= matmul(sig[h],sig[k]); matshow('S'+str(h)+'*S'+str(k),a) def div(p,q) : if p>=0 : return int(p/q) else : return -int(-p/q) def getprimes(n) : # want n prime numbers p=[2]; i=1; plast=2 while i<=n : q=plast+1; found=False while not found: j=0 while ((q%p[j])!=0) and ((p[j]*p[j])<=q) : j +=1 if (q%p[j] != 0) : p += [q]; plast=q; found=True; i+=1 else : q+=1 return p def greatestdiv(x) : # greatest divisor, skip 0s in list n=len(x); y=[0]*n; w=[0]*n; h=0; ymin=-1; gcd=1 pn=[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47]; ln= len(pn) # small primes for i in range(n) : z=abs(x[i]) if z>0 : ymin= z if(ymin<0) else min(ymin,z); w[h]=z; h+=1 w=w[:h]; ip=0 while (ip<ln)and(pn[ip]<=ymin) : z=pn[ip]; ok=True while ok : for i in range(h) : ok= ok and ((w[i]%z)==0) if ok : for i in range(h) : w[i]= div(w[i],z) ymin= div(ymin,z); gcd *= z ip +=1 return gcd def smallestmult(x) : # smallest multiple of nonzero numbers n=len(x); y=abs(x[0]) for i in range(1,n) : z=abs(x[i]); y = y if (z==0) else div(y*z,greatestdiv([y,z])) return y def divide(p,q) : # improve integer fractions def hasfact(x,z) : return (x>0) and ((x % z)==0) pn=[2,3,5,7,11,13,17,19,23,29,31,37]; ln= len(pn) # small prime nbrs p,q,s = (abs(p),abs(q),-1) if ((p*q)<0) else (abs(p),abs(q),1) if p==0 : q=1 for i in range(ln) : z=pn[i] while hasfact(p,z) and hasfact(q,z) : p=div(p,z); q=div(q,z) return [s*p,q] ''' Basic fine-struct & zeeman effect model. Old basis: L3 and S3 diag. New: 2L*S=[j(j+1)-l(l+1)-s(s+1)] diag. S3 does not commute with J^2, but with J3,L3,S3,S^2,L^2. matrix elements of L*S, L3 and S3 in new basis Ci, from old basis Bk: (Ci,Op,Cj)= (sum k Mik, sum h Mjh) (Bk,Op,Bh) with matrix transform M matrices l3,s3 have same nonzero patterns scalar products <j,j3(L3,S3)j',j3'> wont stay in j-block, but j3-blocks. ''' def fullmatrix(diag,mat) : # diag + x * mat, latex-style t='\\begin{pmatrix}{llllll}\n'; n=len(diag) for i in range(n) : for k in range(n) : mik=mat[i][k]; zero= (mik[0]==0); dg=diag[i] v=encodenb(mik); neg=(v[0]=='-'); zero=(v[0]=='0') w= ('-x\cdot'+v[1:]) if neg else ('0' if zero else ('x\cdot'+v)) if i==k : u=encodenb(dg); u+= w if neg else ('+'+w) else : u=w if k>0 : t += ' & ' t+= u if (i<(n-1)) : t +=' \\\\'; t+='\n' t+='\\end{pmatrix}\n' print(t) def jj3(j,j3, l,l3, s,s3) : # get coeffs of vector (j,j3). numbers halfints j2=div(j[0]*2,j[1]); j32=div(j3[0]*2,j3[1]) l2=div(l[0]*2,l[1]); l32=div(l3[0]*2,l3[1]) s2=div(s[0]*2,s[1]); s32=div(s3[0]*2,s3[1]) ok=True; jmax=abs(l2)+abs(s2); jmin=abs(l2-s2); z=[0,1]; sign=0 if (s2 !=1) : print('spin s '+str(s)+' not supported'); ok=False if (j2>jmax)or(j2<jmin) : print('sum j '+str(j)+' out of range'); ok=False if (j32>j2)or(j32<-j2)or(l32>l2)or(l32<-l2)or(s32>s2)or(s32<-s2) : print('one of '+str([j3,l3,s3])+' out of range'); ok=False if (j2>l2) : # contribute l3,s3= (j3-0.5,+) and (j3+0.5,-) if (l32==(j32-1))and(s32==1) : z=[l2+j32+1,2*l2+2]; sign=1 if (l32==(j32+1))and(s32==-1) : z=[l2-j32+1,2*l2+2]; sign=1 else : # contribute l3,s3= (j3+0.5,-) and (j3-0.5,+) if (l32==(j32+1))and(s32==-1) : z=[l2+j32+1,2*l2+2]; sign=1 if (l32==(j32-1))and(s32==1) : z=[l2-j32+1,2*l2+2]; sign=-1 if (not ok)or(z[0]==0) : z= [0,0,1,1,1] else : z=[sign,0,1,z[0],z[1]] return z def testcleb(j,l) : # Clebsch-Gordan case spin 1/2 only # make a matrix of coeffs for (j,j3) in (l,l3)(x)(s,s3) noisy=False # example l=[1,1]; j=[3,2]; s fixed for spin 1/2 nl= div(2*l[0],l[1])+1 s=[1,2]; ns= div(2*s[0],s[1])+1 nj= div(2*j[0],j[1])+1; mx=[[]]*nj for ij in range(nj) : j3=j if (ij==0) else [j3[0]-j3[1],j3[1]]; hj=0; mx[ij]=[[]]*(nl*ns) if ij==0 : s3val=[[]]*(nl*ns); l3val=[[]]*(nl*ns) for il in range(nl) : l3=l if (il==0) else [l3[0]-l3[1],l3[1]] for ks in range(ns) : s3=s if (ks==0) else [s3[0]-s3[1],s3[1]] if ij==0 : s3val[hj]=s3; l3val[hj]=l3 z= jj3(j,j3, l,l3,s,s3); normalize(z); mx[ij][hj]=z; hj+=1 if noisy : print(str([ij,il,ks,z])) # matshow('',mx,1); return mx,s3val,l3val return mx,s3val,l3val def matpermute(m,s) : # matrix line-column permutation n=len(m); mp=[[]]*n; p=[0]*n for i in range(n) : p[i]=int(s[i]); mp[i]=[[]]*n for i in range(n) : for k in range(n) : mp[i][k]=m[p[i]][p[k]] return mp def vecpermute(v,s) : # vector permutation n=len(v); vp=[[]]*n for i in range(n) : p=int(s[i]); vp[i]= v[p] return vp def spectralcurve(dg,m) : # vary Dg+xM and compute 6 values for each # dg diagonal matrix, M 2x2-block matrix # wrong, should get 3 not 5 asymptotics ? 2 triplets with diff g-factors? nx=100; fx=5.0/nx; curve=[[]]*6; y=[0]*6 for j in range(6) : curve[j]=[0.0]*(2*nx+2) for ix in range(nx+1) : x=fx*ix; y[0]=real(dg[0])+real(m[0][0])*x y[1]=real(dg[1])+real(m[1][1])*x # 1st block trivial for j in range(2) : k=2+2*j; a=real(dg[k])+real(m[k][k])*x; b=real(m[k][k+1])*x; c=real(m[k+1][k])*x d=real(dg[k+1])+real(m[k+1][k+1])*x # solve (a-z)(d-z)=bc=zz-(a+d)z+ad; (z-p)^2=... q=b*c-a*d; p=0.5*(a+d); root=sqrt(q+p*p) y[k]=p+root; y[k+1]=p-root for j in range(6) : curve[j][2*ix]=x; curve[j][2*ix+1]=y[j] return curve def zeeman() : # use special multip and addit for square-root numbers l=[1,1]; s=[1,2]; ja=[3,2]; jb=[1,2] # combine ang-momenta l,s to ja,jb mx4,s3val,l3val= testcleb(ja,l) mx2,s3val,l3val= testcleb(jb,l) mx= mx4+mx2; n=len(mx); diag=[[]]*n; noisy=False # mx is 6x6 matrix print('Dimension of mx='+str(len(mx))+','+str(len(mx[0]))) # diag vector has (LS) = [j(j+1)-l(l+1)-s(s+1)]/2 entries z=addit(ja,1); ua=multip(ja,z) z=addit(jb,1); ub=multip(jb,z) z=addit(l,1); v=multip(l,z) z=addit(s,1); w=multip(s,z) x=lincomb(ua,v,1,-1); x=lincomb(x,w,1,-1); ua=multip(x,[1,2]) x=lincomb(ub,v,1,-1); x=lincomb(x,w,1,-1); ub=multip(x,[1,2]) for i in range(len(mx4)) : diag[i]= ua for i in range(len(mx4),n) : diag[i]= ub if noisy : print('ua,ub='+str(ua)+str(ub)) if noisy : matshow('Matrix mx',mx,1) s3=[[]]*n; l3=[[]]*n; l2s=[[]]*n for i in range(n) : s3[i]=[[]]*n; l3[i]=[[]]*n; l2s[i]=[[]]*n for j in range(n) : # compute op[i][j] s3sum=0; l3sum=0 for k in range(n) : u= s3val[k]; v=l3val[k] # the diagonal op(k,h) u1= multip(u,mx[i][k]); v1=multip(v,mx[i][k]) for h in (k,) : # not 'in range(n)' because diagonal u2=multip(u1,mx[j][h]); s3sum= addit(s3sum,u2) v2=multip(v1,mx[j][h]); l3sum= addit(l3sum,v2) s3[i][j]=s3sum; l3[i][j]=l3sum l2s[i][j]=lincomb(l3sum,s3sum,1,2) # L+2S matrix if noisy : matshow('Matrix s3',s3,1); matshow('Matrix l3',l3,1) if noisy : matshow('Matrix l2s',l2s,1) l2sp= matpermute(l2s,'031425'); diagp= vecpermute(diag,'031425') matshow('Matrix l2s permuted',l2sp,1) vecshow('Vector diag permuted', diagp) data= spectralcurve(diagp, l2sp); multiplot(data) # SVG plot print('\nPlot zeeman.svg written, for Perturbation Matrix\n') fullmatrix(diagp, l2sp) # Latex output # svg sketch 6 levels vs fieldstrength def multiplot(d) : n=len(d); xmin=1e12;xmax=-xmin;ymin=xmin;ymax=xmax txt=[]; fn='zeeman'; ix=[0,1,2,3,4,5,6,7,8,9] for i in range(n) : k=0; kmax=len(d[i]); #print('Curve '+str(i)+' length '+str(kmax)) while k<kmax : x=d[i][k]; y=d[i][k+1]; k+=2 xmin= x if(x<xmin) else xmin; xmax= x if (x>xmax) else xmax ymin= y if(y<ymin) else ymin; ymax= y if (y>ymax) else ymax #print('xmin,ymin, xmax,ymax'+str([xmin,ymin, xmax,ymax])) xyf=[ xmin,ymin, xmax,ymin, xmax,ymax, xmin,ymax, xmin,ymin] xys=[xyf]+d xs,fx,xpix= xmin, 750/(xmax-xmin),25 # scale user units, min in pixels ys,fy,ypix= ymin,-550/(ymax-ymin),575 ; scale=(xs,fx,xpix, ys,fy,ypix) colo=['#aaa','#00a','#077','#0a0','#770','#a00','#707','#0ff','#f0f'] sd=svgdump(); buf=sd.plotbegin(800,600,1); i=0; dy=(ymax-ymin)/20.0 for j in range(len(txt)) : buf += label(sd,scale, txt[j], 0.2*xmin+0.8*xmax,ymax-dy-j*dy) for t in xys : buf += curve(sd,scale, t, fill=colo[ix[i]]); i+=1 g=open(fn+'.svg','w'); g.write(buf+sd.plotend()); g.close() 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 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') : # path w=with lc=linecolor t='<path fill="none" 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) : (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) 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) zeeman()