/* SCHII2B: Like SCHII2, except that I went from ints back to using doubles in the delta calculations, to avoid some overflow problems, and also I added a pretty complex-plane projection of the wavefunction in the center of the display. Also, can redisplay wavefunction after each half-step, to make it easier to see how artifacts form. (They arise if epsilon exceeds 0.5.) */ #include #include #include #include #include /* Physical constants. We'll use MKS (m,kg,s,nt,J,coul...) units. */ #define planck_h (6.626e-34) /* Planck's constant, in Joule-seconds */ #define light_c (2.998e8) /* Speed of light in meters/second */ static const double hbar = planck_h/(2*M_PI), /* h/2*pi, also in J-sec */ elec_m = 9.109e-31, /* Electron rest mass, in kg */ elec_q = 1.602e-19, /* Electron charge (abs.value) in Coulombs */ coul_const = 8.988e9; /* 1/4*pi*epsilon_0 (Coulomb's law constant) in nt-m^2/coul^2. */ /* Parameters of simulation. o */ #define space_width (1e-10) /* Width of sim space in meters: 1 A. */ #define num_pts (300) /* Number of discrete space points in sim. */ static const double sim_dx = space_width/num_pts, /* delta btw. pts, in meters. */ //sim_dt = 26.3682e-22, /* Simulated time per step, in secs. */ // above or larger blows up //sim_dt = 25.03e-22, //sim_dt = 10e-22, //sim_dt = 6.590e-22, /* Simulated time per step, in secs. */ // just on the verge of blowing up //sim_dt = 4.8e-22, sim_dt = 4.7e-22, /* Simulated time per step, in secs. */ // This one seems safe and still fairly fast. init_vel = light_c*0.4, /* Initial velocity in m/s */ initial_mu = -space_width/4, /* initial mean electron pos, rel. to ctr. */ initial_sigma = space_width/30; /* width of initial hump. */ /* For holding some arrays of size num_pts, in real/imaginary pairs. */ static double *energies, /* Real potential energies at points. */ *on_real,*on_imag, *off_real,*off_imag, /* On/off diagonal matrix elements, real/imag */ *Psi_real,*Psi_imag; /* Real at t, imag at t+1/2. */ static double *Feyn; /* Now, we will use Psi_real and Psi_imag only for translation between the internal, integer form, and how it is used externally. Here is the real wave function: */ static int *psiR,*psiI; /* Real and imaginary integer wave function. */ static long long int *FeynQuant; static double totFeyn; /* Total Feynman quantity */ static double initFeyn; /* initial total Feynman quant */ static double totProb; /* Total normal probability */ static double minProb; /* smallest value of it so far */ static double scaleFactor; /* The value, in the integer range, that a real value of 1.0 translates to. */ static int n_steps = 0; /* Number of iterations done so far. */ static double total_t = 0; /* Total simulated time so far. */ static int max_steps = 10000; /* go a million iterations before reversing */ static int direction = 0; /* forwards */ #define STEPS_PER_SHOT 30 typedef enum energ_funcs { neg_gaus=0, pos_gaus, inv_cutoff, parabolic, half_para, const_nonzero, const_zero, step_barrier } energ_func_id; static energ_func_id which_potential = const_zero; static const char *energ_func_strs[] = { "Negative Gaussian potential well", "Positive Gaussian potential bump", "Inverse distance well with cutoff", "Parabolic well for harmonic oscillator", "Half of a parabolic well", "Constant, non-zero energy level", "Constant, zero energy", "A step barrier to tunnel through" }; void print_sim_params() { printf("\n"); printf("SCHROEDINGER SIMULATOR PARAMETERS\n"); printf("---------------------------------\n"); printf("\n"); printf("Width of simulated space is %g meters (%g light-seconds).\n", space_width, space_width/light_c); printf("Simulating %d discrete points in space.\n", num_pts); printf("Distance between points: %g m (%g ls).\n",sim_dx, sim_dx/light_c); printf("Time per simulation step: %g secs (light dist: %g m)\n", sim_dt, sim_dt*light_c); printf("Initial electron position: mu=%g m, sigma=%g m.\n", initial_mu, initial_sigma); printf("Using potential energy function %d: %s.\n", which_potential, energ_func_strs[which_potential]); printf("Initial electron velocity = %g m/s (%g c).\n", init_vel, init_vel/light_c); printf("Number of steps to go before reversing: %d.\n",max_steps); printf("\n"); } static double *init_real,*init_imag; void print_stats() { /* Calculate and print some stats of the wavefunction. */ int this = n_steps&1; int i; double total_p = 0; double mom_real = 0, mom_imag = 0, potential = 0, kin_real = 0, kin_imag = 0, energ_real = 0, energ_imag = 0; double dPsi2_real, dPsi2_imag; double diff=0; for(i=0;i -4e-14) { return p; } else { return -4e-14; } } case parabolic: /* Parabolic well for harmonic oscillator. */ return x*x*5e+6; case half_para: if (x < 0) { return x*x*2e+6; } else { return 0; } case const_nonzero: /* Constant, nonzero energy. Apparent wave rotation rate differs from zero-energy case.*/ return 24e-17; case const_zero: /* Constant, zero energy. */ return 0; case step_barrier: /* A step barrier through which to tunnel. */ { double v; if (x < space_width * 0.0) { v=0; } else if (x < space_width * 0.1) { v=5e-15; } else { v=0; } //v-=7e-15; return v; } } return 0; } static double epsilon; static double *alphas; static int *alphasi; static int epsiloni; void cache_energies() { int i; /* epsilon: an angle that roughly indicates how much of a point's amplitude gets spread to its neighboring points per time step. A function of sim dt and dx parameters only. */ epsilon = hbar*sim_dt/(elec_m*sim_dx*sim_dx); //epsilon = 0.5000001; epsiloni = (int)((unsigned)(0x80000000) * epsilon); printf("Sim epsilon angle: %g radians (%g of a circle).\n", epsilon, epsilon/(2*M_PI)); printf("Integer epsilon: %d\n",epsiloni); energies = malloc_doubles(); on_real = malloc_doubles(); on_imag = malloc_doubles(); off_real = malloc_doubles(); off_imag = malloc_doubles(); alphas = malloc_doubles(); alphasi = malloc_ints(); printf("Alphas:\n"); for(i=0;imaxval) maxval=absval; absval = Psi_imag[i]; absval = (absval<0)?-absval:absval; if (absval>maxval) maxval=absval; } printf("The maximum absolute value initially is: %g.\n",maxval); /* We'll scale our integers so that they can hold values up to almost twice the largest initial value before they incur an overflow. */ scaleFactor = (1<<30)/maxval; printf("Therefore the scale factor will be: %g.\n",scaleFactor); } /* Convert to integers. */ printf("Integer psis:\n"); for(i=0;i>= 1; if (m1p&mask) prod += m2p>>pos; } if (m1<0) prod = -prod; if (m2<0) prod = -prod; return prod; } int function(int *vec,int i){ int j,k; double result; j = i+1; if (j==-1) j=num_pts-1; else if (j==num_pts) j=0; k = i-1; if (k==-1) k=num_pts-1; else if (k==num_pts) k=0; result = 2*alphas[i]*vec[i] - epsilon*vec[j] - epsilon*vec[k]; if (result > 0x80000000u || -result > 0x80000000u) { printf("Function value at point %d, %lf, does not fit in an int!\n", i,result); printf("vec[i] = %d\n",vec[i]); printf("vec[j] = %d\n",vec[j]); printf("vec[k] = %d\n",vec[k]); sleep(1000000); exit(1); } return result; /* The following doesn't work too well b/c if epsilon>0.5 then 2*alphas will generally be >1 and so alphasi will overflow */ /*return signed_mult_frac(alphasi[i],vec[i]) - signed_mult_frac(epsiloni,vec[j]) - signed_mult_frac(epsiloni,vec[k]);*/ } void update_feyn_quant() { int i; // Feynman's exactly conserved probability-squared-like quantity // P = R[s]^2 + I[s+1]*I[s-1] totFeyn = 0; totProb = 0; for(i=0;i %lf\n",i,FeynQuant[i]); } if (totProb < minProb || minProb == 0) { minProb = totProb; //printf("New minimum PP: %.0lf\n",minProb); } if (initFeyn == 0) { initFeyn = totFeyn; } if (n_steps % 100 == 0) { printf("Feynman quantity: %.16lf\n",totFeyn/initFeyn); } for(i=0;i #include #include #include "icon.bitmap" #define BITMAPDEPTH 1 static Display *display; static int screen; static double *prev_real, *prev_imag; static double *prev_feyn; static double maxv; static double maxp; void init_graphics() { int i; int this = n_steps&1; prev_real = malloc_doubles(); prev_imag = malloc_doubles(); prev_feyn = malloc_doubles(); maxv = 0; maxp = 0; for(i=0;i maxv) maxv = absv; absv = Psi_imag[i]; absv = (absv<0)?-absv:absv; if (absv > maxv) maxv = absv; absv = Psi_real[i]*Psi_real[i] + Psi_imag[i]*Psi_imag[i]; if (absv > maxp) maxp = absv; } } void draw_graphics(win,gc,window_width,window_height,gce,gcreal,gcimag) Window win; GC gc; unsigned window_width, window_height; GC gce,gcreal,gcimag; { double ght = window_height/2; /* How much Y space per graph */ unsigned c1 = ght/2; /* origin y for top graph */ unsigned c2 = window_height/2; /* origin y for circle graph */ unsigned c3 = window_height; /* origin y for Feynman graph */ int this = n_steps&1; /* which Psi is current */ int i; for(i=0;i 0) && ((i-(num_pts/2)) < 0.1*num_pts)) { XDrawLine(display,win,gcreal, cx+tX,c2-tY, cx+RtX,c2-RtY); } else { /*if ((i&7) != 0)*/ { XDrawLine(display,win,gcimag, cx+tX,c2-tY, cx+RtX,c2-RtY); } } XFillRectangle(display,win,gc, cx+tX-1,c2-tY-1, 3,3); /* Erase old Feynman quant and draw new. */ XDrawLine(display,win,gce,x,c3-pfY,xj,c3-RpfY); XDrawLine(display,win,gc,x,c3-tfY,xj,c3-RtfY); /* Draw energy function. */ XDrawLine(display,win,gc, x,(int)(c3-(ght*0.5)-ght*energies[i]*1e14), xj,(int)(c3-(ght*0.5)-ght*energies[j]*1e14) ); XDrawPoint(display,win,gc,x,(int)(c3-(ght*0.5))); } for(i=0;ifid); { XColor sdr,edr; XSetBackground(display,*gc,BlackPixel(display,screen)); if (foo == 1) { 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); } } int main(argc,argv) int argc; char **argv; { Window win; unsigned width, height; /* window size */ int x = 0, y = 0; /* window position */ unsigned border_width = 4; /* border four pixels wide */ unsigned display_width, display_height; char *window_name = "Schroedinger Wave Simulator"; char *icon_name = "schroed"; Pixmap icon_pixmap; XSizeHints size_hints; XEvent report; GC gc,gce,gcreal,gcimag; XFontStruct *font_info; char *display_name = NULL; int i; printf("Size of (long long int) = %d\n",sizeof(long long int)); /* connect to X server */ if ( (display=XOpenDisplay(display_name)) == NULL ) { fprintf(stderr, "cannot connect to X server %s\n", XDisplayName(display_name)); exit(-1); } sim_init(); init_graphics(); /* get screen size from display structure macro */ screen = DefaultScreen(display); display_width = DisplayWidth(display,screen); display_height = DisplayHeight(display,screen); /* size window with enough room for text */ width = display_width/3, height = display_height/3; /* create opaque window */ win = XCreateSimpleWindow(display,RootWindow(display,screen), x,y,width,height,border_width, WhitePixel(display,screen), BlackPixel(display,screen)); /* Create pixmap of depth 1 (bitmap) for icon */ icon_pixmap = XCreateBitmapFromData(display, win, icon_bitmap_bits, icon_bitmap_width, icon_bitmap_height); /* initialize size hint property for window manager */ size_hints.flags = PPosition | PSize | PMinSize; size_hints.x = x; size_hints.y = y; size_hints.width = width; size_hints.height = height; size_hints.min_width = 175; size_hints.min_height = 125; /* set properties for window manager (always before mapping) */ XSetStandardProperties(display,win,window_name,icon_name, icon_pixmap,argv,argc,&size_hints); /* Select event types wanted */ XSelectInput(display,win, ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask); load_font(&font_info); /* create GC for text and drawing */ get_GC(win, &gc, font_info, 1); get_GC(win, &gce, font_info, 0); get_GC(win, &gcreal, font_info, 2); get_GC(win, &gcimag, font_info, 3); /* Display window */ XMapWindow(display,win); while (1) { /* Event loop. */ int i; XNextEvent(display,&report); switch(report.type) { case Expose: /* get rid of all other Expose events on the queue */ while (XCheckTypedEvent(display, Expose, &report)); draw_graphics(win, gc, width, height, gce, gcreal, gcimag); //if (n_steps == 0) sleep(1); for(i=0;ifid); XFreeGC(display,gc); XFreeGC(display,gce); XFreeGC(display,gcreal); XFreeGC(display,gcimag); XCloseDisplay(display); exit(1); default: break; } } return 0; }