/* metacoal.c - written by John Wakeley for Wakeley J and N Aliacar */ /* 2001 Gene genealogies in a metapopulation. Genetics 159:893-905 */ #include #include #include #include #include "Obaku:John:Cprograms:Headers:random.h" /* the line above includes a file with the random number generator I like; */ /* put your own or a system supplied one in unirandom()/sunirandom() below */ #define ANC_BASE 'A' #define MUT_BASE 'G' #define MAXN 11 /* maximum per-deme sample size */ struct node { /* the nodes in the tree */ int id; double time; struct node *desc1; struct node *desc2; }; struct tipset { int nprime; /* size of lineage entering collecting phase */ int tipids[MAXN]; /* labels of the lineages descendents in the sample */ }; void MyError(error_text) char error_text[]; { fprintf(stderr,"\nJW's run-time error...\n"); fprintf(stderr,"\n\t%s\n",error_text); fprintf(stderr,"\n...now exiting to system...\n\n"); exit(1); } /* TableSterlings() makes matrices of Stirling numbers of the second kind (s2) */ /* and the coefficients in the paper (s3) REMEMBER: s3[i][j][k] = S^{(k)}_{j,i} */ double s2[MAXN][MAXN],s3[MAXN][MAXN][MAXN]; void TableSterlings() { int x,y,z; for(x=0;x n || np < 1 || n < 1 || n >= MAXN ) MyError("Bad ScatterProbME()"); sum = 0.0; for(j=1;j<=n;j++) for(x=0;x<=n-j;x++) sum += PME(x,j,n,twoM,twoE)*BallBoxProb(j,np-x,k); return sum; } /* ES() is Watterson's (1975) expected number of segregating sites */ double ES(n,theta) int n; double theta; { int x; double a1; a1 = 0.0; for(x=1;x= MAXN ) MyError("Bad n in ESonedeme()"); sum = 0.0; for(np=2;np<=n;np++) sum += ScatterProbME(n,np,k,twoM,twoE)*ES(np,theta); return sum; } /* EStwodemes() is equation (25) in the paper, but for two demes only */ double EStwodemes(n1,n2,k1,k2,twoM1,twoM2,twoE1,twoE2,theta) int n1,n2,k1,k2; double twoM1,twoM2,twoE1,twoE2,theta; { int np1,np2; double sum; if( n1 < 1 || n1 >= MAXN ) MyError("Bad n1 in EStwodemes()"); if( n2 < 1 || n2 >= MAXN ) MyError("Bad n2 in EStwodemes()"); sum = 0.0; for(np1=1;np1<=n1;np1++) for(np2=1;np2<=n2;np2++) sum += ScatterProbME(n1,np1,k1,twoM1,twoE1)*ScatterProbME(n2,np2,k2,twoM2,twoE2)*ES(np1+np2,theta); return sum; } /* SUNIRANDOM - Seed your random number generator */ void sunirandom(seed) unsigned int seed; { /* put your own srandom here */ srandom(seed); } /* UNIRANDOM - Uniform [0,1) random deviates. */ #define IM 2147483648.0 double unirandom() { /* put your own random number generator here */ return (double)random()/IM; } #undef IM /* EXPONENTIALDEV - mean 1, deviates. For mean m, multiple by m. */ double exponentialdev() { double dum; do dum = unirandom(); while( dum == 0.0 ); return -log(dum); } /* LOCALGAMMLN - Natural log of the gamma function. */ double localgammln(xx) double xx; { double x,y,tmp,ser; static double cof[6]={76.18009172947146,-86.50532032941677, 24.01409824083091,-1.231739572450155, 0.1208650973866179e-2,-0.5395239384953e-5}; int j; y=x=xx; tmp=x+5.5; tmp -= (x+0.5)*log(tmp); ser=1.000000000190015; for (j=0;j<=5;j++) ser += cof[j]/++y; return -tmp+log(2.5066282746310005*ser/x); } /* POISSONDEV - Poisson deviates with mean xm. */ #define PI 3.141592653589793 double poissondev(xm) double xm; { double localgammln(); double unirandom(); static double sq,alxm,g,oldm=(-1.0); double em,t,y; if (xm < 12.0) { if (xm != oldm) { oldm=xm; g=exp(-xm); } em = -1; t=1.0; do { ++em; t *= unirandom(); } while (t > g); } else { if (xm != oldm) { oldm=xm; sq=sqrt(2.0*xm); alxm=log(xm); g=xm*alxm-localgammln(xm+1.0); } do { do { y=tan(PI*unirandom()); em=sq*y+xm; } while (em < 0.0); em=floor(em); t=0.9*(1.0+y*y)*exp(em*alxm-localgammln(em+1.0)-g); } while (unirandom() > t); } return em; } #undef PI /* MakeTipsOneDeme() simulates the scattering phase, returns nprime */ /* for the deme and stores the sizes of these lineages in sizes[] */ int MakeTipsOneDeme(ni,propagulesize,sizes,twoM,twoE) int ni,propagulesize,sizes[MAXN]; double twoM,twoE; { int x,y,n,nprime,numoccupied,pick1,pick2,counter,picks[MAXN],occupancies[MAXN],coalsizes[MAXN]; double prob,pcoal,pmig,denom; n = ni; if(n<1 || n>=MAXN) MyError("\n... bad n in MakeTipsOneDeme() ...\n\n"); if(n==1) { nprime = 1; sizes[0] = 1; } else { for(x=0;x 0) { denom = ((double)(n-1)) + twoM + twoE/((double)n); pcoal = ((double)(n-1))/denom; pmig = twoM/denom; prob = unirandom(); if(prob < pcoal) { pick1 = n*unirandom(); n -= 1; pick2 = n*unirandom(); if(pick2 >= pick1) pick2 += 1; coalsizes[pick1] += coalsizes[pick2]; for(x=pick2;x=0) { for(y=0;yid = x; (tree + x)->time = 0.0; (tree + x)->desc1 = NULL; (tree + x)->desc2 = NULL; } } /* MakeTree() standard coalescent tree building routine */ void MakeTree(numseqs,theta,tree) int numseqs; double theta; struct node *tree; { int x,pick,cnode; double t; struct node **list; list = (struct node **)malloc( (size_t)numseqs*sizeof(struct node *) ); if(list == NULL) MyError("problem with list memory allocation"); for(x=0;x1;x--) { cnode = 2*numseqs - x; pick = x*unirandom(); tree[cnode].desc1 = list[pick]; list[pick] = list[x-1]; pick = (x-1)*unirandom(); tree[cnode].desc2 = list[pick]; list[pick] = tree + cnode; t += exponentialdev()*theta/(double)(x*(x-1)); tree[cnode].time = t; } free( (void *)list ); } /* SizeChange() lineages before "time" become "factor" times longer */ void SizeChange(samplesize,time,factor,tree) int samplesize; double time,factor; struct node *tree; { int x; for(x=samplesize;x<(2*samplesize-1);x++) { if( tree[x].time > time ) tree[x].time = factor*(tree[x].time - time) + time; } } double TreeLength(numseqs,tree) int numseqs; struct node *tree; { int x; double Ttot; Ttot = 0.0; for(x=(2*numseqs-2);x>=numseqs;x--) { Ttot += (tree[x].time - (tree+x)->desc1->time); Ttot += (tree[x].time - (tree+x)->desc2->time); } return Ttot; } int PickBranch(numseqs,Ttot,tree) int numseqs; double Ttot; struct node *tree; { int x; double Tsum,Tpick; Tsum = 0.0; Tpick = Ttot*unirandom(); for(x=(2*numseqs-2);x>=numseqs;x--) { Tsum += (tree[x].time - (tree+x)->desc1->time); if( Tpick < Tsum ) return ( (tree+x)->desc1->id ); Tsum += (tree[x].time - (tree+x)->desc2->time); if( Tpick < Tsum ) return ( (tree+x)->desc2->id ); } } void MutateTips(numscat,site,datamatrix,thisnode,scattertips) int numscat,site; char **datamatrix; struct node *thisnode; struct tipset *scattertips; { int x; if( thisnode->id >= numscat ) { MutateTips(numscat,site,datamatrix,thisnode->desc1,scattertips); MutateTips(numscat,site,datamatrix,thisnode->desc2,scattertips); } else for(x=0;xid].nprime;x++) datamatrix[scattertips[thisnode->id].tipids[x]][site] = MUT_BASE; } void MakeDataTips(numscat,numseqs,S,datamatrix,Ttot,tree,scattertips) int numscat,numseqs,S; char **datamatrix; double Ttot; struct node *tree; struct tipset *scattertips; { int x,y,nodenum; for(x=0;x0) { datamatrix = (char **)malloc( (size_t)numseqs*sizeof(char *) ); if( datamatrix == NULL ) MyError("prob w/datamatrix in main()"); for(y=0;y