The program is more general than the discussion as the
program implements two models,
The program is less general than the discussion as only a quadratic lattice is implemented.
#include <stdio.h> #include <math.h> #include <stdlib.h> #include <assert.h> #define NBRNUM 4 #define gascon 8.314 static struct SITE { struct SITE *nbr[NBRNUM]; int id; int env; int seq; int flag; } *site; static struct QUEUE { double rate; struct SITE *target; int action; } *queue; static int count; static double eqLimit; static double omega; static double desene; static double difene; static double preFacDif; static double preFacDes; static int size; #define SQRT3 1.732050808 static double ran2(int offset) { unsigned int a = 16807; unsigned int c = 0; unsigned int m = 2147483647; static int state = 1; static int ready = 0; if (offset > 0) { assert(ready == 0); state = offset; return 0.; } ready = 1; state = (a * state + c) % m; return ((double) state / m); } static void setEnvAtm(struct SITE * c) { int i; c->env = 0; for (i = 0; i < NBRNUM; i++) if (c->nbr[i]->id > 0) c->env++; } static void swapAtm(struct SITE * c, struct SITE * n) { int i, t; if (c->id == 0) { if (n->id > 0) { for (i = 0; i < NBRNUM; i++) c->nbr[i]->env++; for (i = 0; i < NBRNUM; i++) n->nbr[i]->env--; } } else { if (n->id == 0) { for (i = 0; i < NBRNUM; i++) c->nbr[i]->env--; for (i = 0; i < NBRNUM; i++) n->nbr[i]->env++; } } t = c->id; c->id = n->id; n->id = t; t = c->seq; c->seq = n->seq; n->seq = t; } static void swapNbr(struct SITE *c, int n) { swapAtm(c,c->nbr[n]); } static double calcene(void) { double e; int i; e = 0.; for (i = 0; i < size * size; i++) if (site[i].id > 0) e += desene + omega * site[i].env; return e; } static void walk(struct SITE * s, int difEq[], double *emin) { double e; int i; s->flag = s->env; e = desene + 2. * omega * s->env; if (e < *emin) *emin = e; if (difEq[s->env]) for (i = 0; i < NBRNUM; i++) if (s->nbr[i]->id == 0 && s->nbr[i]->flag < 0) { swapAtm(s, s->nbr[i]); walk(s->nbr[i], difEq, emin); swapAtm(s, s->nbr[i]); } } static void jump(struct SITE * s, int difEq[], double t) { double emin; int i, i1, i2; int last; double level; double sum; double wghtSurf[NBRNUM + 1]; for (i = 0; i < size * size; i++) site[i].flag = -1; emin = desene + 2. * omega * s->env; walk(s, difEq, &emin); for (i = 0; i <= NBRNUM; i++) if (desene + i * omega < emin - 5. * gascon * t) wghtSurf[i] = 1.; else if (desene + i * omega < emin + 5. * gascon * t) wghtSurf[i] = exp(-(desene + 2. * i * omega - emin) / gascon / t); else wghtSurf[i] = 0.; last = 0;sum=0.; for (i = 0; i < size * size; i++) if (site[i].flag >= 0) { queue[last].target = s; queue[last].action = i; assert(site[i].env >= 0 && site[i].env <= NBRNUM); sum + =wghtSurf[site[i].flag]; queue[last].rate = sum; last++; } if (last == 0) return; level = sum * ran2(0); /* search by bisection */ i1 = -1; i2 = last - 1; while (i1+1 < i2) { i = (i1 + i2) / 2; assert(i>=0 && i<last); if (level < queue[i].rate) i2 = i; else i1 = i; assert((i1 == -1 || queue[i1].rate <= level) && level < queue[i2].rate); } assert(i1+1 == i2 && (i2 == 0 || queue[i2 - 1].rate <= level) && level < queue[i2].rate); swapAtm(s, &site[queue[i2].action]); } static void desOne(struct SITE * c) { int i; c->id = 0; count--; for (i = 0; i < NBRNUM; i++) setEnvAtm(c->nbr[i]); } static void desTwo(struct SITE * c, int n) { desOne(c); desOne(c->nbr[n]); } static void output(int moves, int im) { int ia, is, ix, iy; struct LIST { int id; double x; double y; } *list; if ((list = (struct LIST *) malloc((unsigned) size * size * sizeof(struct LIST))) == NULL) { (void) fprintf(stderr, "Not enough memory\n"); exit(1); } for (iy = 0; iy < size; iy++) for (ix = 0; ix < size; ix++) { is = site[ix + size * iy].seq; list[is].id = site[ix + size * iy].id; list[is].x = (double) ix / (double) size; list[is].y = (double) iy / (double) size; } if (im == 0) { (void) printf("\n"); (void) printf("2 %d 0 0 1\n", moves); (void) printf("%d 0 0\n0 %d 0\n0 0 1\n", size, size); (void) printf("%d %d\n", size * size); for (ia = 0; ia < size * size; ia++) { (void) printf("%d", list[ia].id); (void) printf(" X"); (void) printf(" %.3f %.3f %.3f", list[ia].x, list[ia].y, 0.); (void) printf("\n"); } } else { (void) printf("%d 0 0\n0 %d 0\n0 0 1\n", size, size); for (ia = 0; ia < size * size; ia++) { (void) printf("%d", list[ia].id); (void) printf(" %.3f %.3f %.3f", list[ia].x, list[ia].y, 0.); (void) printf("\n"); } } (void) free((char *) list); } static void equil(double temp,int moves) { double delene; double oldene; double newene; int im, is, io; oldene = calcene(); for (im = 0; im < moves; im++) { for (is = 0; is < size * size; is++) if (site[is].id > 0) { io = NBRNUM * ran2(0); if (site[is].nbr[io]->id == 0) { swapNbr(&site[is], io); newene = calcene(); delene = newene - oldene; if (delene < 0. || delene < 15. * gascon * temp && exp(-delene / gascon / temp) > ran2(0)) { oldene = newene; } else { /* reject : swap id's back */ swapNbr(&site[is], io); } } } } } #define P(x,y) (x+y*size) static void setup(void) { int j; int i, ix, iy; int xm, ym; int xp, yp; int t; for (iy = 0; iy < size; iy++) for (ix = 0; ix < size; ix++) { xm = (ix == 0) ? size - 1 : ix - 1; ym = (iy == 0) ? size - 1 : iy - 1; xp = (ix == size - 1) ? 0 : ix + 1; yp = (iy == size - 1) ? 0 : iy + 1; site[P(ix, iy)].seq = P(ix, iy); site[P(ix, iy)].nbr[0] = &site[P(xp, iy)]; site[P(ix, iy)].nbr[1] = &site[P(ix, yp)]; site[P(ix, iy)].nbr[2] = &site[P(xm, iy)]; site[P(ix, iy)].nbr[3] = &site[P(ix, ym)]; } for (i = 0; i < count; i++) site[i].id = 1; for (; i < size * size; i++) site[i].id = 0; for (i = 0; i < size * size; i++) { j = size * size * ran2(0); if (site[i].id != site[j].id && ran2(0) > 0.5) { t = site[i].id; site[i].id = site[j].id; site[j].id = t; } } for (i = 0; i < size * size; i++) setEnvAtm(&site[i]); } static double rate1(double t) { int i, is; double r; double desRate[NBRNUM + 1]; r = 0.; for (i = 0; i < NBRNUM; i++) desRate[i] = preFacDes * exp(-(-desene - i * omega) / gascon / t); for (is = 0; is < size * size; is++) if (site[is].id > 0) r += desRate[site[is].env]; return r; } static void model1(double tstart, double htrate, double tstep) { double difRate[NBRNUM + 1]; double desRate[NBRNUM + 1]; int difEq[NBRNUM + 1]; double dt; int i, i1,i2,is; int last; double level; double sum; double t, tsum; tsum = 0.; for (;;) { t = tstart + htrate * tsum; for (i = 0; i < NBRNUM; i++) { difRate[i] = preFacDif * exp(-(difene - i * omega) / gascon / t); difEq[i] = (difRate[i] * tstep > eqLimit); } for (i = 0; i < NBRNUM; i++) desRate[i] = preFacDes * exp(-(-desene - i * omega) / gascon / t); for (is = 0; is < size * size; is++) if (site[is].id > 0 && difEq[site[is].env]) jump(&site[is], difEq, t); last = 0; sum=0.; for (is = 0; is < size * size; is++) if (site[is].id > 0) { if (!difEq[site[is].env]) for (i = 0; i < NBRNUM; i++) if (site[is].nbr[i]->id == 0) { queue[last].action = i; queue[last].target = &site[is]; assert(site[is].env >= 0 && site[is].env < NBRNUM); sum += difRate[site[is].env]; queue[last].rate = sum; last++; } queue[last].action = NBRNUM + 1; queue[last].target = &site[is]; sum += desRate[site[is].env]; queue[last].rate = sum; last++; } if (last == 0) return; dt = -log(ran2(0)) / sum; if (tsum + dt * ran2(0) > tstep) return; level = sum * ran2(0); /* search by bisection */ i1 = -1; i2 = last - 1; while (i1+1 < i2) { i = (i1 + i2) / 2; assert(i>=0 && i<last); if (level < queue[i].rate) i2 = i; else i1 = i; assert((i1 == -1 || queue[i1].rate <= level) && level < queue[i2].rate); } assert(i1+1 == i2 && (i2 == 0 || queue[i2 - 1].rate <= level) && level < queue[i2].rate); assert(queue[i2].target->id > 0); if (queue[i2].action < NBRNUM) swapNbr(queue[i2].target, queue[i2].action); else desOne(queue[i2].target); tsum += dt; } } static double rate2(double t) { int i, is; double r; double desRate[2 * NBRNUM + 1]; for (i = 0; i <= 2 * NBRNUM; i++) desRate[i] = preFacDes * exp(-(2. * desene - i * omega) / gascon / t); r = 0.; for (is = 0; is < size * size; is++) if (site[is].id > 0) for (i = 0; i < NBRNUM / 2; i++) if (site[is].nbr[i]->id == 1) r += desRate[site[i].env + site[is].env]; return r; } static void model2(double tstart, double htrate, double tstep) { double difRate[NBRNUM + 1]; double desRate[2 * NBRNUM + 1]; int difEq[NBRNUM + 1]; double dt; int i, i1,i2,is; int last; double rate; double sum; double t, tsum; for (tsum = 0; tsum <= tstep; tsum += dt) { t = tstart + htrate * tsum; for (i = 0; i <= NBRNUM; i++) { difRate[i] = preFacDif * exp(-(difene - i * omega) / gascon / t); difEq[i] = (difRate[i] * tstep > eqLimit); } for (i = 0; i <= 2 * NBRNUM; i++) desRate[i] = preFacDes * exp(-(2. * desene - i * omega) / gascon / t); for (is = 0; is < size * size; is++) if (site[is].id > 0 && difEq[site[is].env]) jump(&site[is], difEq, t); last = 0; sum=0.; for (is = 0; is < size * size; is++) if (site[is].id > 0) { if (!difEq[site[is].env]) for (i = 0; i < NBRNUM; i++) if (site[is].nbr[i]->id == 0) { queue[last].action = i; queue[last].target = &site[is]; assert(site[is].env >= 0 && site[is].env < NBRNUM); sum += difRate[site[is].env]; queue[last].rate = sum; last++; } for (i = 0; i < NBRNUM / 2; i++) if (site[is].nbr[i]->id == 1) { queue[last].action = NBRNUM + i; queue[last].target = &site[is]; assert(site[is].env >= 0 && site[is].env <= NBRNUM); sum += desRate[site[i].env + site[is].env]; queue[last].rate = sum; last++; } } if (last == 0) return; dt = -log(ran2(0)) / sum; if (tsum + dt * ran2(0) <= tstep) { rate = sum * ran2(0); /* search by bisection */ i1 = -1; i2 = last - 1; while (i1+1 < i2) { i = (i1 + i2) / 2; assert(i>=0 && i<last); if (rate < queue[i].rate) i2 = i; else i1 = i; assert((i1 == -1 || queue[i1].rate <= rate) && rate < queue[i2].rate); } assert(i1+1 == i2 && (i2 == 0 || queue[i2 - 1].rate <= rate) && rate < queue[i2].rate); assert(queue[i2].target->id > 0); if (queue[i2].action < NBRNUM) swapNbr(queue[i2].target, queue[i2].action); else desTwo(queue[i2].target, queue[i2].action - NBRNUM); } } } int main(int argc, char *argv[]) { int i; int im; int c; void (*m) (double, double, double) = model1; double (*r) (double) = rate1; double tstep = 1.; double htrate = 2.; double conc = 0.95; double tstart = 300.; static int moves[2] = {0,500}; int seed = 0; eqLimit = 10.; omega = 0.; preFacDif = 1.0e11; preFacDes = 1.0e11; desene = -60000.; difene = 50000.; size = 32; while (--argc > 0 && (*++argv)[0] == '-') { c = *(++argv[0]); switch (c) { case 'c': if (--argc == 0 || sscanf(*(++argv), "%lf", &conc) != 1 || conc < 0. || conc > 1.) { (void) fprintf(stderr, "Could not read argument of option -%c\n", c); return 1; } break; case 'd': if (--argc == 0 || sscanf(*(++argv), "%lf", &preFacDif) != 1 || preFacDif <= 0. || --argc == 0 || sscanf(*(++argv), "%lf", &difene) != 1) { (void) fprintf(stderr, "Could not read argument of option -%c\n", c); return 1; } break; case 'e': if (--argc == 0 || sscanf(*(++argv), "%lf", &preFacDes) != 1 || preFacDes <= 0. || --argc == 0 || sscanf(*(++argv), "%lf", &desene) != 1) { (void) fprintf(stderr, "Could not read argument of option -%c\n", c); return 1; } break; case 'f': if (--argc == 0 || sscanf(*(++argv), "%lf", &eqLimit) != 1 ||eqLimit < 1.) { (void) fprintf(stderr, "Could not read argument of option -%c\n", c); return 1; } break; case 'h': if (--argc == 0 || sscanf(*(++argv), "%lf", &tstep) != 1 || tstep <= 0.) { (void) fprintf(stderr, "Could not read argument of option -%c\n", c); return 1; } break; case 'M': if (--argc == 0 || sscanf(*(++argv), "%d", &i) != 1 || i < 1 || i > 2) { (void) fprintf(stderr, "Could not read argument of option -%c\n", c); return 1; } if (i == 1) { m = model1; r = rate1; } else { m = model2; r = rate2; } break; case 'm': if (--argc == 0 || sscanf(*(++argv), "%d", &moves[0]) != 1 || moves[0] < 0 ||--argc == 0 || sscanf(*(++argv), "%d", &moves[1]) != 1 || moves[1] < 1) { (void) fprintf(stderr, "Could not read argument of option -%c\n", c); return 1; } break; case 'o': if (--argc == 0 || sscanf(*(++argv), "%lf", &omega) != 1) { (void) fprintf(stderr, "Could not read argument of option -%c\n", c); return 1; } break; case 'r': if (--argc == 0 || sscanf(*(++argv), "%d", &seed) != 1 || seed < 1) { (void) fprintf(stderr, "Could not read argument of option -%c\n", c); return 1; } break; case 's': if (--argc == 0 || sscanf(*(++argv), "%d", &size) != 1 || size < 4) { (void) fprintf(stderr, "Could not read argument of option -%c\n", c); return 1; } break; case 't': if (--argc == 0 || sscanf(*(++argv), "%lf", &tstart) != 1 || tstart <= 0. || --argc == 0 || sscanf(*(++argv), "%lf", &htrate) != 1 || htrate < 0.) { (void) fprintf(stderr, "Could not read argument of option -%c\n", c); return 1; } break; case '?': (void) fprintf(stderr, "Usage: a.out [arguments]\n"); (void) fprintf(stderr, "\t-c <float> : start concentration\n"); (void) fprintf(stderr, "\t-d <float> <float> : preexponential factor and act energy for diffusion\n"); (void) fprintf(stderr, "\t-e <float> <float> : preexponential factor and act energy for desorption\n"); (void) fprintf(stderr, "\t-h <float> : timestep\n"); (void) fprintf(stderr, "\t-m <int> : number of timesteps\n"); (void) fprintf(stderr, "\t-M <int> : model\n"); (void) fprintf(stderr, "\t-o <int> : interaction between occupied sites\n"); (void) fprintf(stderr, "\t-r <int> : seed for RNG\n"); (void) fprintf(stderr, "\t-s <int> : size\n"); (void) fprintf(stderr, "\t-t <float> <float> : start temperature and heating rate\n"); default: (void) fprintf(stderr, "-%c ?\n", c); return 1; } } if (seed > 0) (void) ran2(seed); count = conc * size * size; if ((site = (struct SITE *) malloc((unsigned) size * size * sizeof(struct SITE))) == NULL || (queue = (struct QUEUE *) malloc((unsigned) (2 * NBRNUM) * count * sizeof(struct QUEUE))) == NULL) { (void) fprintf(stderr, "Not enough memory\n"); return 1; } setup(); for(im=0; im<moves[1]; im++) { equil(tstart,1); (void) fprintf(stderr, "%d %.3f %.3f %.3f %.5f", im, tstep * im, tstart, count / (double) (size * size), 0.); if (count > 0) (void) fprintf(stderr, " %.3f", calcene() / (count)); (void) fprintf(stderr, "\n"); } output(moves[1],0); for (im = 0; im < moves[1]; im++) { m(tstart + im * tstep * htrate, htrate, tstep); (void) fprintf(stderr, "%d %.3f %.3f %.3f %.5f", im, tstep * im, tstart + htrate * tstep * im, count / (double) (size * size), r(tstart + (im + 1) * tstep * htrate) / (size * size)); if (count > 0) (void) fprintf(stderr, " %.3f", calcene() / (count)); (void) fprintf(stderr, "\n"); output(moves[1],im + 1); } (void) free((char *) site); (void) free((char *) queue); return 0; }