/* Schrodinger equation laboratory */ /* From an ideaa of Michael Creutz */ /* creutz@wind.phy.bnl.gov */ /* to compile: */ /* cc -O -L/usr/X11R6/lib schrodlab.c -lX11 -lm */ /* Version May 3, 1998. /* by Claudio Destri, destri@mi.infn.it, with many changes and */ /* additions with respect to the original by Creutz. */ /* !!!!!! FFT CHANGED TOO !!!!!!!!!!!!!!!!!!!!!! */ /* this solves the Schrodinger equation in a potential */ /* displays amplitude squared and the potential superposed */ /* the left mouse button perturbs the wave function */ /* the right mouse button perturbs the potential */ /* the damp button evolves system towards the ground state */ /* the t -> -t button implements time reversal */ /* the show E button lets the avarage energy be shown as a line */ /* the rotate V button rotates through few preset potentials */ /* the kick button varies the average momentum */ /* the hbar button varies Plank's constant */ /* the speed button varies the speed of the evolution */ /* the fourier button shows the amplitude squared in fourier space */ /* the project button projects out the psi's captured in the */ /* register buttons 0 to 5 which are pressed */ # include # include # include # include # include # include # include # include # include # include # include #ifndef _COMPLEX_DEFINED typedef struct { double re; double im; } complex; #define _COMPLEX_DEFINED #endif /* NSITES=number of lattice sites fft (as implemented here) REQUIRES a power of two */ # define NSITES 512 # define NPOINTS 512 /* dimensions for buttons */ # define BUTTONWIDTH 78 # define BUTTONHEIGHT 18 /* some important constants */ # define SIZE 128 # define DT .05 # define DX (SIZE/(1.*NSITES)) # define MASS 0.1 # define DAMPFACTOR 1.0 /* how many preset potentials? */ # define NPOT 7 complex xpsi[NSITES]; /* wave function in x space */ complex kpsi[NSITES]; /* wave function in k space */ complex inpsi[NSITES]; /* to monitor norm change when damped */ complex gpsi[NSITES][6]; /* to store intersting psi's */ complex pfactor[NSITES]; /* for updating potential term */ complex kfactor[NSITES]; /* for updating kinetic term */ double potential[NSITES]; /* potential in Schrodinger equation */ double kenergy[NSITES+1]; /* array with kinetic energy */ double ene; /* average energy */ double sn[NSITES]; int ik[NSITES/4]; /* relabels k space */ int iamp[NPOINTS+1],ipot[NPOINTS+1]; /* X-plottable discrete counterparts */ XPoint xpoints[2*NPOINTS]; /* for drawing waves */ struct timeval timeout; /* timer for speed control */ char getstr[1+1]; /* to repaint capture buttons */ char commstr[24+1]; /* to show norm change when damped */ short int ifgot[6]={0,0,0,0,0,0}; /* needed by the capture routines */ short int paused=1; /* is the system paused? */ short int damped=0; /* is the system damped? */ short int trevd=1; /* time grows (1) or decreases (-1)? */ short int kickversor=0;/* direction of kicks */ short int kicked=0; /* signed number of kicks */ short int hbar=5; /* between 1 and 10 */ short int speed=1; /* updating delay proportional to speed; between 0 and 10 */ short int delay=0; /* counter for implementing speed control */ short int potident=1; /* initialize the rotation of the potential */ short int show=0; /* do not show energy at startup */ short int fourier=0; /* fourier=1 to show psi in momentum space */ short int project=0; /* when 1 project out low lying states stored in gpsi */ short int fixedbc=0; /* fixedbc=1 to change to Dirichlet bc's */ int ncalls=0; /* init counter of fft calls */ double enscale=0.3; /* energy scale on graph (max=1) */ void drawbutton(),openwindow(),makebuttons(),update(),repaint(), setmom(),rotpot(),cleanup(),drawit(),renorm(),energy(), resetbutt(),convert(),makefactor(),doproject(),fastf(); # define line(x1,y1,x2,y2) XDrawLine(display,window,gc,x1,y1,x2,y2) # define color(i) XSetForeground(display,gc,translate[i]) /* various window stuff */ Display *display; int screen; static char *progname; Window window,quitbutton,pausebutton,potbutton,bcbutton,dampbutton, projbutton,trevbutton,enebutton,foubutton,speedbutton, getbutton,hbarbutton,kickbutton,commbutton,makebutton(); XColor xcolor,colorcell; Colormap cmap; GC gc; int windowwidth,windowheight,playwidth,playheight; XFontStruct *font=NULL; int font_height,font_width; XSizeHints size_hints; int darkcolor,lightcolor,black,white; long translate[256]; /* for converting colors */ int main(argc,argv) int argc; char **argv; {int i,j,k,p,cget; double psipeg,w; unsigned int width, height; XEvent report; progname=argv[0]; openwindow(argc,argv); makebuttons(); /* init ik */ for (i=0;i -t",2*trevd); } else if (report.xbutton.window==dampbutton) {damped=1-damped; if (damped) commbutton=makebutton(0,0,2*BUTTONWIDTH,BUTTONHEIGHT); drawbutton(dampbutton,0,0,BUTTONWIDTH,BUTTONHEIGHT, "damp",2-4*damped); makefactor(); if (1-damped) XDestroyWindow(display, commbutton); } else if (report.xbutton.window==getbutton) {cget=report.xbutton.x/26; ifgot[cget]=1-ifgot[cget]; if (ifgot[cget]) for (i=0;iNPOT) potident=1; rotpot(); resetbutt(); } else if (report.xbutton.window==bcbutton) {fixedbc=1-fixedbc; makefactor(); energy(); resetbutt(); drawit(); } else if (report.xbutton.window==speedbutton) { /* reset speed */ speed=10-(11*report.xbutton.x)/BUTTONWIDTH; if (speed<0) speed=0; if (speed>10) speed=10; delay=speed; drawbutton(speedbutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"speed",-2); drawbutton(speedbutton,1+((10-speed)*(BUTTONWIDTH-2))/11,1, (BUTTONWIDTH-2)/11,BUTTONHEIGHT-2,"",2); } else if (report.xbutton.window==hbarbutton) { /* reset hbar */ hbar=1+(10*report.xbutton.x)/BUTTONWIDTH; if (hbar<1) hbar=1; if (hbar>10) hbar=10; makefactor(); if (show) energy(); drawbutton(hbarbutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"hbar",-2); drawbutton(hbarbutton,1+((hbar-1)*(BUTTONWIDTH-2))/10,1, (BUTTONWIDTH-2)/11,BUTTONHEIGHT-2,"",2); } else if (report.xbutton.window==kickbutton) {/* kick the wavefunction */ i=report.xbutton.x; if (i3*BUTTONWIDTH/4) {kickversor=1; kicked+=kickversor;} else kickversor=0; setmom(); } else /* button one changes wave function, two updates, and three modifies potential */ {i=report.xbutton.x; j=report.xbutton.y; if (jb)? b : a) #define max(a,b) ((a>b)? a : b) void drawit() /* draws the wave function */ {int i,k1,k2,iene; if (fourier) convert(kpsi); else convert(xpsi); /* now draw it */ /* first the red part */ for (i=0;i -t", 2*trevd); drawbutton(dampbutton, 0,0,BUTTONWIDTH,BUTTONHEIGHT,"damp", 2-4*damped); for (j=0;j<6;j++) {sprintf(getstr,"%d",j); drawbutton(getbutton,j*BUTTONWIDTH/3,0,BUTTONWIDTH/3, BUTTONHEIGHT, getstr,2-4*ifgot[j]); } drawbutton(projbutton, 0,0,BUTTONWIDTH,BUTTONHEIGHT,"project", 2-4*project); drawbutton(pausebutton, 0,0,BUTTONWIDTH,BUTTONHEIGHT,"pause", 2-4*paused); drawbutton(quitbutton, 0,0,BUTTONWIDTH,BUTTONHEIGHT,"quit", 2); drawbutton(potbutton, 0,0,5*BUTTONWIDTH/4,BUTTONHEIGHT,"rotate V", 2); drawbutton(bcbutton, 0,0,5*BUTTONWIDTH/4,BUTTONHEIGHT,"change bc", 2); drawbutton(speedbutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"speed",-2); drawbutton(speedbutton,1+((10-speed)*(BUTTONWIDTH-2))/11,1, (BUTTONWIDTH-2)/11,BUTTONHEIGHT-2,"",2); drawbutton(hbarbutton,0,0,BUTTONWIDTH,BUTTONHEIGHT,"hbar",-2); drawbutton(hbarbutton,1+((hbar-1)*(BUTTONWIDTH-2))/10,1, (BUTTONWIDTH-2)/11,BUTTONHEIGHT-2,"",2); drawbutton(kickbutton,3*BUTTONWIDTH/4,0,BUTTONWIDTH/4,BUTTONHEIGHT,">",2); drawbutton(kickbutton,BUTTONWIDTH/4,0, BUTTONWIDTH/2,BUTTONHEIGHT,"kick",2); drawbutton(kickbutton,0,0,BUTTONWIDTH/4-1,BUTTONHEIGHT,"<",2); drawbutton(window,4*BUTTONWIDTH+1,playheight+BUTTONHEIGHT, playwidth-4*BUTTONWIDTH-1,BUTTONHEIGHT, "left mouse button perturbs psi^2 (magenta)",0); drawbutton(window,4*BUTTONWIDTH+1,playheight+2*BUTTONHEIGHT, playwidth-4*BUTTONWIDTH-1,BUTTONHEIGHT, "right mouse button perturbs potential V (green)",0); if (damped) drawbutton(commbutton,0,0,2*BUTTONWIDTH,BUTTONHEIGHT,commstr,2); resetbutt(); color(4); XFillRectangle(display,window,gc,0,playheight,windowwidth,BUTTONHEIGHT); drawit(); return; } void resetbutt() /* fixes potential and boundary conditions buttons */ { if (potident==1) {drawbutton(window,0,playheight+BUTTONHEIGHT,7*BUTTONWIDTH/4, BUTTONHEIGHT,"V=constant",0); } if (potident==2) {drawbutton(window,0,playheight+BUTTONHEIGHT,7*BUTTONWIDTH/4, BUTTONHEIGHT,"V=harmonic",0); } if (potident==3) {drawbutton(window,0,playheight+BUTTONHEIGHT,7*BUTTONWIDTH/4, BUTTONHEIGHT,"V=quartic",0); } if (potident==4) {drawbutton(window,0,playheight+BUTTONHEIGHT,7*BUTTONWIDTH/4, BUTTONHEIGHT,"V=square well",0); } if (potident==5) {drawbutton(window,0,playheight+BUTTONHEIGHT,7*BUTTONWIDTH/4, BUTTONHEIGHT,"V=double well",0); } if (potident==6) {drawbutton(window,0,playheight+BUTTONHEIGHT,7*BUTTONWIDTH/4, BUTTONHEIGHT,"V=periodic",0); } if (potident==7) {drawbutton(window,0,playheight+BUTTONHEIGHT,7*BUTTONWIDTH/4, BUTTONHEIGHT,"V=random",0); } if (fixedbc) drawbutton(window,0,playheight+2*BUTTONHEIGHT, 7*BUTTONWIDTH/4,BUTTONHEIGHT,"bc=dirichlet",0); else drawbutton(window,0,playheight+2*BUTTONHEIGHT, 7*BUTTONWIDTH/4,BUTTONHEIGHT,"bc=periodic",0); return; } void openwindow(argc,argv) /* a lot of this is taken from basicwin in the Xlib Programming Manual */ int argc; char **argv; {char *window_name="Schrodinger"; char *icon_name="waves"; long event_mask; Pixmap icon_pixmap; char *display_name=NULL; int i; # define icon_bitmap_width 16 # define icon_bitmap_height 16 static unsigned char icon_bitmap_bits[] = { 0x1f, 0xf8, 0x1f, 0x88, 0x1f, 0x88, 0x1f, 0x88, 0x1f, 0x88, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; /* open up the display */ if ((display=XOpenDisplay(display_name))==NULL) {fprintf(stderr,"%s: cannot connect to X server %s\n", progname,XDisplayName(display_name)); exit(-1); } screen=DefaultScreen(display); cmap=DefaultColormap(display,screen); darkcolor=black=BlackPixel(display,screen); lightcolor=white=WhitePixel(display,screen); translate[0]=white; translate[1]=black; translate[2]=lightcolor; translate[3]=darkcolor; for(i=4;i<256;i++) translate[i]=translate[i%4]; /* a bunch of colors to play with */ if (XAllocNamedColor(display,cmap,"salmon",&colorcell,&xcolor)) darkcolor=colorcell.pixel; if (XAllocNamedColor(display,cmap,"wheat",&colorcell,&xcolor)) lightcolor=colorcell.pixel; if (XAllocNamedColor(display,cmap,"red",&colorcell,&xcolor)) translate[0]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"blue",&colorcell,&xcolor)) translate[1]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"green",&colorcell,&xcolor)) translate[2]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"cyan",&colorcell,&xcolor)) translate[3]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"orange",&colorcell,&xcolor)) translate[4]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"purple",&colorcell,&xcolor)) translate[5]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"yellow",&colorcell,&xcolor)) translate[6]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"pink",&colorcell,&xcolor)) translate[7]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"brown",&colorcell,&xcolor)) translate[8]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"grey",&colorcell,&xcolor)) translate[9]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"turquoise",&colorcell,&xcolor)) translate[10]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"gold",&colorcell,&xcolor)) translate[11]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"magenta",&colorcell,&xcolor)) translate[12]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"navy",&colorcell,&xcolor)) translate[13]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"tan",&colorcell,&xcolor)) translate[14]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"violet",&colorcell,&xcolor)) translate[15]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"white",&colorcell,&xcolor)) translate[16]=colorcell.pixel; if (XAllocNamedColor(display,cmap,"black",&colorcell,&xcolor)) translate[17]=colorcell.pixel; /* feel free to type in more colors, I got bored */ for(i=18;i<256;i++) translate[i]=translate[i%18]; /* make the main window */ windowwidth=10*BUTTONWIDTH; windowheight=500; playwidth=windowwidth; playheight=(windowheight-3*BUTTONHEIGHT); window=XCreateSimpleWindow(display,RootWindow(display,screen), 0,0,windowwidth,windowheight,4,translate[14],lightcolor); /* make the icon */ icon_pixmap=XCreateBitmapFromData(display,window, icon_bitmap_bits,icon_bitmap_width,icon_bitmap_height); size_hints.flags=PPosition | PSize | PMinSize; size_hints.min_width=windowwidth; size_hints.min_height=300; /* this is probably silly, and not really tested, but here goes */ #ifdef X11R3 size_hints.x=x; size_hints.y=y; size_hints.width=windowwidth; size_hints.height=windowheight; XSetStandardProperties(display,window,window_name,icon_name, icon_pixmap,argv,argc,&size_hints); #else {XWMHints wm_hints; XClassHint class_hints; XTextProperty windowName, iconName; if (XStringListToTextProperty(&window_name,1,&windowName)==0) {fprintf(stderr,"%s: structure allocation for windowName failed.\n" ,progname); exit(-1); } if (XStringListToTextProperty(&icon_name,1,&iconName)==0) {fprintf(stderr,"%s: structure allocation for iconName failed.\n" ,progname); exit(-1); } wm_hints.initial_state=NormalState; wm_hints.input=True; wm_hints.icon_pixmap=icon_pixmap; wm_hints.flags=StateHint|IconPixmapHint|InputHint; class_hints.res_name=progname; class_hints.res_class="Basicwin"; XSetWMProperties(display,window,&windowName,&iconName, argv,argc,&size_hints,&wm_hints,&class_hints); } #endif /* pick the events to look for */ event_mask=ExposureMask|ButtonPressMask|StructureNotifyMask; XSelectInput(display,window,event_mask); /* pick font: 9x15 is supposed to almost always be there */ if ((font=XLoadQueryFont(display,"9x15"))==NULL) if ((font=XLoadQueryFont(display,"fixed"))==NULL) {fprintf(stderr,"%s: Sorry, having font problems.\n",progname); exit(-1); } font_height=font->ascent+font->descent; font_width=font->max_bounds.width; /* make graphics context: */ gc=XCreateGC(display,window,0,NULL); XSetFont(display,gc,font->fid); XSetForeground(display,gc,black); XSetBackground(display,gc,lightcolor); /* show the window */ XMapWindow(display,window); return; } void makebuttons() { /* first destroy any old buttons */ XDestroySubwindows(display,window); /* now make the new buttons */ quitbutton=makebutton(3*BUTTONWIDTH, windowheight-BUTTONHEIGHT,BUTTONWIDTH,BUTTONHEIGHT); pausebutton=makebutton(3*BUTTONWIDTH, windowheight-2*BUTTONHEIGHT,BUTTONWIDTH,BUTTONHEIGHT); enebutton=makebutton(0,windowheight-3*BUTTONHEIGHT, BUTTONWIDTH,BUTTONHEIGHT); foubutton=makebutton(BUTTONWIDTH,windowheight-3*BUTTONHEIGHT, BUTTONWIDTH,BUTTONHEIGHT); trevbutton=makebutton(2*BUTTONWIDTH,windowheight-3*BUTTONHEIGHT, BUTTONWIDTH,BUTTONHEIGHT); dampbutton=makebutton(3*BUTTONWIDTH,windowheight-3*BUTTONHEIGHT, BUTTONWIDTH,BUTTONHEIGHT); getbutton=makebutton(4*BUTTONWIDTH,windowheight-3*BUTTONHEIGHT, 2*BUTTONWIDTH,BUTTONHEIGHT); projbutton=makebutton(6*BUTTONWIDTH,windowheight-3*BUTTONHEIGHT, BUTTONWIDTH,BUTTONHEIGHT); potbutton=makebutton(7*BUTTONWIDTH/4,windowheight-2*BUTTONHEIGHT, 5*BUTTONWIDTH/4,BUTTONHEIGHT); bcbutton=makebutton(7*BUTTONWIDTH/4,windowheight-BUTTONHEIGHT, 5*BUTTONWIDTH/4,BUTTONHEIGHT); speedbutton=makebutton(windowwidth-BUTTONWIDTH, windowheight-3*BUTTONHEIGHT,BUTTONWIDTH,BUTTONHEIGHT); hbarbutton=makebutton(windowwidth-2*BUTTONWIDTH, windowheight-3*BUTTONHEIGHT,BUTTONWIDTH,BUTTONHEIGHT); kickbutton=makebutton(windowwidth-3*BUTTONWIDTH, windowheight-3*BUTTONHEIGHT,BUTTONWIDTH,BUTTONHEIGHT); return; } void cleanup() {XUnloadFont(display,font->fid); XFreeGC(display,gc); XCloseDisplay(display); exit(0); } Window makebutton(xoffset,yoffset,xsize,ysize) int xoffset,yoffset,xsize,ysize; /* Puts button of specified dimensions on window. Nothing is drawn. */ {Window buttonwindow; long event_mask; buttonwindow=XCreateSimpleWindow(display,window,xoffset,yoffset, xsize,ysize,0,black,lightcolor); event_mask=ButtonPressMask|ExposureMask; /* look for mouse-button presses */ XSelectInput(display,buttonwindow,event_mask); XMapWindow(display,buttonwindow); return buttonwindow; } void drawbutton(buttonwindow,xoffset,yoffset,xsize,ysize,text,state) Window buttonwindow; int xoffset,yoffset,xsize,ysize,state; char * text; /* Draw a button in buttonwindow of specified dimensions with text centered. Color of button determined by sign of "state", size of border determined by magnitude. I don't need no stinking tookit. */ {int textlength,i,j; int cdark,clight,cup,cdown; int cleft,cright,cbutton,ctext; cup=lightcolor; cdown=darkcolor; cdark=black; clight=white; if (state<0) {cbutton=cdown; ctext=clight; cleft=cdark; cright=clight; } else {cbutton=cup; ctext=cdark; cleft=clight; cright=cdark; } j=abs(state); /* width for button borders */ XSetForeground(display,gc,cbutton); XFillRectangle(display,buttonwindow,gc,xoffset+j,yoffset+j, xsize-2*j,ysize-2*j); XSetForeground(display,gc,cleft); XFillRectangle(display,buttonwindow,gc,xoffset,yoffset,xsize,j); XFillRectangle(display,buttonwindow,gc,xoffset,yoffset,j,ysize); XSetForeground(display,gc,cright); for (i=0;i> 1; N4 = N2 >> 1; x = fft_malloc(N2); A = fft_malloc(N2); wp1 = x; wp2 = data; wp3 = data + N2; for (m = 0; m < N2; ++m, ++wp1, ++wp2, ++wp3) { wp1->re = wp2->re + wp3->re; wp1->im = wp2->im + wp3->im; } w = cosi[Nd - 4] + 1; wp1 = A + 1; wp2 = data + 1; wp3 = data + 1 + N2; for (m = 1; m < N4; ++m, ++wp1, ++wp2, ++wp3, ++w) { wp1->re = (wp2->re - wp3->re) * (*w); wp1->im = (wp2->im - wp3->im) * (*w); } ++m, ++wp1, ++wp2, ++wp3, ++w; for (; m < N2; ++m, ++wp1, ++wp2, ++wp3, ++w) { wp1->re = (wp2->re - wp3->re) * (*w); wp1->im = (wp2->im - wp3->im) * (*w); } A[0].re = 0.0; A[0].im = 0.0; A[N4].re = 0.0; A[N4].im = 0.0; RBfft(A, Nd-1, sign); RBfft(x, Nd-1, sign); if(sign < 0) { v0.re = data[0].re - data[N2].re + data[N4].im - data[N - N4].im; v0.im = data[0].im - data[N2].im - data[N4].re + data[N - N4].re; v1.re = data[0].re - data[N2].re - data[N4].im + data[N - N4].im; v1.im = data[0].im - data[N2].im + data[N4].re - data[N - N4].re; } else { v0.re = data[0].re - data[N2].re - data[N4].im + data[N - N4].im; v0.im = data[0].im - data[N2].im + data[N4].re - data[N - N4].re; v1.re = data[0].re - data[N2].re + data[N4].im - data[N - N4].im; v1.im = data[0].im - data[N2].im - data[N4].re + data[N - N4].re; } wp1 = data; wp2 = x; for (m = 0; m < N2; ++m, wp1 += 2, ++wp2) *wp1 = *wp2; wp1 = data + 1; wp2 = A; for (m = 1; m < N4; ++m, wp1 += 2, ++wp2) { wp1->re = wp2->re + (wp2 + 1)->re + v0.re; wp1->im = wp2->im + (wp2 + 1)->im + v0.im; wp1 += 2; ++wp2; wp1->re = wp2->re + (wp2 + 1)->re + v1.re; wp1->im = wp2->im + (wp2 + 1)->im + v1.im; } wp1->re = wp2->re + (wp2 + 1)->re + v0.re; wp1->im = wp2->im + (wp2 + 1)->im + v0.im; data[N - 1].re = A[N2 - 1].re + A[0].re + v1.re; data[N - 1].im = A[N2 - 1].im + A[0].im + v1.im; fft_free(A, N2); fft_free(x, N2); } fft(data, n, sign) complex *data; int n, sign; { int i; int j = 0; if (n != ndata) { ndata = n; i = 1; while (n > i) { i <<= 1; ++j; } fft_init(j); ndigit = j; } RBfft(data, ndigit, sign); }