The source

This is the complete source for a KMC program for TPD.

The program is more general than the discussion as the program implements two models,

A* A + *

and
2A* A2 + 2*

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;
}


Start

Author Per Stoltze stoltze@fysik.dtu.dk