/* This file contains the source for my experimental simulator for the Schroedinger wave equation of quantum mechanics. It currently simulates the behavior of a single electron confined to a 1-dimensional, 1-angstrom long space under the influence of a time-independent potential energy function which can be changed by editing the energy() function and recompiling. The display shows the real and imaginary components of the wave function, as a function of the position of the electron, superimposed in two different colors, on the top half of the display, and the derived probability distribution over the electron's position along the bottom of the display superimposed over the potential energy function. A key press shows some stats and a mouse button exits. I first wrote this program in the summer of '95 on Jody's Gateway Pentium under Linux. I've run it on RS6000s at IBM, and on HP Snakes and various Suns at the AI lab. Speed helps a lot! -mpf 8/28/96 */ #include #include #include #include #include #include "icon.bitmap" #define BITMAPDEPTH 1 static Display *display; static int screen; /*----------------------------------------------------------------------*/ #include /* Physical constants. */ #define h (6.626e-34) /* Planck's constant in J-sec */ #define hbar (h/(2*M_PI)) /* in J-sec */ #define me (9.109e-31) /* Electron rest mass in kg */ /* Parameters of simulation. npts=50, dt=5e-23 makes a nice fast display, but a little jaggedy. Smoother and slower is npts=200, dt=5e-24. */ static const int npts = 50; /* Number of points of spatial resolution */ static const double dt = 5e-23; /* time step, in seconds */ static const double wm = 1e-10; /* width of sim space in meters = 1 angstrom */ /* Parameters of normal distribution for wavefunction at time t=0. */ static const double mu = .25; /* How far across the window is the hump. */ static const double sigma = .05; /* How wide is the hump compared to the window. */ /* Some constants derived at init time and cached for efficiency. */ static double dx, /* Dist. in meters btw. neighboring points. */ oodx, /* One over dx. */ ho2mdt; /* hbar over (2*mass) times dt */ /* Various arrays for keeping up with the wavefunction state. */ static double *real,*imag; /* State at current time. */ static double *r2,*i2; /* State being calc'ed for next time. */ static double *pr,*pi; /* State at prev. time (for erasing). */ static double *dtvoh; /* Energy of points times dt over hbar. */ /* For tracking our progress. */ static int cycles = 0; /* Number of iterations done so far. */ static double t = 0; /* Total simulated time so far. */ /* Computes a normal (Gaussian) distribution over x, given the standard parameters mu (mean) and sigma (sqrt of std. dev.). This is used for setting up the electron's initial position distribution. */ double normal(x,mu,sigma) double x,mu,sigma; { double s2p = sqrt(2*M_PI); double d = (x-mu)/sigma; return (1/(sigma*s2p))*exp(-0.5*d*d); } /* Compute the potential energy, in Joules, as a function of position, in meters. This whole function is just an input parameter to the simulation, not part of the simulation itself. */ double energy(double x){ double dx = x-(wm/2); /* Below are some of the different energy functions I have played with. All but one of these should be commented out at any given time. */ /* Negative Gaussian potential well. */ /*return 5e-15 * (1.0 - 0.25 * normal(x/wm,0.5,0.1));*/ /* Positive Gaussian potential bump. */ /*return 5e-15 * 0.25 * normal(x/wm,0.8,0.1);*/ /* Well where energy drops with inverse distance from center, down to a cutoff threshold. */ /*double adx = (dx<0?-dx:dx); double p = 4e-15 - (1e-25 / adx); if (p > 0) { return p; } else { return 0; }*/ /* Parabolic well for harmonic oscillator. */ return dx*dx*1e+6; /* Constant, nonzero energy. Apparent wave rotation rate differs from zero-energy case.*/ /*return -24e-15;*/ /* Constant, zero energy. */ /*return 0;*/ /* A step barrier through which to tunnel. */ /*if (x < wm/2) { return 0; } else if (x < wm*.6) { return 1.5e-15; } else { return 0; }*/ } /* Initialize the simulation. */ void init_physics() { int i; dx = wm/npts; /* Calc dist. btw. pts. in meters. */ oodx = 1/dx; /* Cache this calculation to avoid many divides later. */ ho2mdt = (hbar/(2*me))*dt; /* Similarly. */ /* Allocate the various arrays. */ real = (double *)malloc(npts*sizeof(double)); imag = (double *)malloc(npts*sizeof(double)); r2 = (double *)malloc(npts*sizeof(double)); i2 = (double *)malloc(npts*sizeof(double)); pr = (double *)malloc(npts*sizeof(double)); pi = (double *)malloc(npts*sizeof(double)); dtvoh = (double *)malloc(npts*sizeof(double)); /* Initialize the wavefunction & cache the values of the energy function. */ for(i=0;i maxr) {maxr=real[i]; amr = i; } if (-real[i] > maxr) {maxr=-real[i]; amr = i; } if (imag[i] > maxi) {maxi=imag[i]; ami = i; } if (-imag[i] > maxi) {maxi=-imag[i]; ami = i; } if (pd > maxpd) {maxpd = pd; amp = -1;} } printf("Cycle = %d, t = %g.\n",cycles,t); printf(" Max R = %g@%d, Max I = %g@%d, Max P = %g\n", maxr,amr,maxi,ami,maxpd); /*draw_graphics(win, gc, width, height); for(i=0;i<64;i++) cycle(); break;*/ } break; case ButtonPress: XUnloadFont(display,font_info->fid); XFreeGC(display,gc); XFreeGC(display,gce); XFreeGC(display,gcred); XFreeGC(display,gcblue); XCloseDisplay(display); exit(1); default: /* all events selected by StructureNotifyMask except */ /* ConfigureNotify are thrown away here, since nothing is done */ /* with them */ break; } /* end switch */ } /* end while */ } get_GC(Window win, GC *gc, XFontStruct *font_info, int foo) { unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */ XGCValues values; unsigned int line_width = 1; int line_style = LineSolid; int cap_style = CapButt; int join_style = JoinRound; int dash_offset = 0; static char dash_list[] = { 12, 24 }; int list_length = 2; /* Create default graphics context */ *gc = XCreateGC(display,win,valuemask,&values); /* specify font */ XSetFont(display,*gc,font_info->fid); { XColor sdr,edr; if (foo == 1) { /* specify black foreground since default may be white on white */ XSetForeground(display,*gc,WhitePixel(display,screen)); } else if (foo == 0) { XSetForeground(display,*gc,BlackPixel(display,screen)); } else if (foo == 2) { XAllocNamedColor(display,DefaultColormap(display,screen),"cyan", &sdr,&edr); XSetForeground(display,*gc,edr.pixel); } else if (foo == 3) { XAllocNamedColor(display,DefaultColormap(display,screen),"yellow", &sdr,&edr); XSetForeground(display,*gc,edr.pixel); }} /* set line attributes */ XSetLineAttributes(display,*gc,line_width,line_style,cap_style, join_style); /* set dashes to be line_width in length */ XSetDashes(display,*gc,dash_offset,dash_list,list_length); } load_font(XFontStruct **font_info) { char *fontname = "9x15"; /* Access font */ if ((*font_info = XLoadQueryFont(display,fontname)) == NULL) { fprintf(stderr,"Basic: Cannot open 9x15 font\n"); exit(-1); } } draw_graphics(win,gc,window_width,window_height,gce,gcred,gcblue) Window win; GC gc; unsigned window_width, window_height; GC gce,gcred,gcblue; { double ght = window_height/2; unsigned c1 = ght/2; unsigned c2 = window_height; int i; double maxv = 6.0; double mv2 = 15; for(i=0;i