/* codeml.c  (aaml.c & codonml.c)

   Maximum likelihood parameter estimation for codon sequences (seqtype=1)
                    or amino-acid sequences (seqtype=2)
                Copyright, Ziheng YANG, 1993-2003

               cc -o codeml -fast codeml.c tools.o -lm
                         codeml <ControlFileName>
*/


/*
#define DSDN_MC  1
#define DSDN_MC_SITES  1
*/

#include "paml.h"

#define NS            5000
#define NBRANCH       (NS*2 - 2)
#define NNODE         (NS*2 - 1)
#define MAXNSONS      100
#define NGENE         2000
#define LSPNAME       96
#define NCODE         64
#define NCATG         40
#define NBTYPE        8

#define NP            (NBRANCH*2 + NGENE - 1 + 2 + NCODE + 2)
/*
#define NP            (NBRANCH+NGENE-1+189+2+NCODE+2)
*/
extern char BASEs[], AAs[];
extern int noisy, NFunCall, NEigenQ, NPMatUVRoot, *ancestor, GeneticCode[][64];
extern double *SeqDistance;
extern double SS, NN, Sd, Nd; /* kostas, SS=# of syn. sites, NN=# of non-syn. sites, Sd=# of syn. subs., Nd=# of non-syn. subs. as defined in DistanceMatNG86 in treesub.c */

int  Forestry(FILE *fout);
int  GetMemPUVR(int nc, int nUVR);
int  sortwM3(double x[]);
void DetailOutput(FILE *fout, double x[], double var[]);
int  GetOptions(char *ctlf);
int  testx(double x[], int np);
int  SetxBound(int np, double xb[][2]);
int  SetxInitials(int np, double x[], double xb[][2]);
int  GetInitials(double x[], int*fromfile);
double *PointKappa(double xcom[], int igene);
double *PointOmega(double xcom[], int igene, int inode, int isiteclass);
int  GetCodonFreqs(void);
int  SetParameters(double x[]);
int  SetParametersNSsites(double x[]);
int  Set_UVR_BranchSite(int iclass, int branchlabel);
int  SetPGene(int igene, int _pi, int _UVRoot, int _alpha, double x[]);
int  SetPSiteClass(int iclass, double x[]);
int  PMatJC69like(double P[], double t, int n);
int  printfcode(FILE *fout, double fb61[], double space[]);
int  InitializeCodon(FILE *fout, double space[]);
int  AA2Codonf(double faa[20], double fcodon[]);
int  DistanceMatAA(FILE *fout);
int  GetDaa(FILE *fout, double daa[]);
void getpcodonClass(double x[], double pcodonClass[]);
int  SelectionCoefficients(FILE* fout, double kappa[], double ppi[], double omega);
int  eigenQcodon(int mode, double blength, double *S, double *dS, double *dN,
   double Root[], double U[], double V[], double *meanrate, double kappa[], double omega, double Q[]);
int  eigenQaa(FILE *fout, double Root[], double U[], double V[], double rate[]);
int  Qcodon2aa(double Qc[], double pic[], double Qaa[], double piaa[]);
int  SetAA1STEP(void);
int  GetOmegaAA(int OmegaAA[]);
int  TestModelQc(FILE *fout, double x[]);
double lfun2dSdN(double x[], int np);
int  VariancedSdN(double t, double omega, double vtw[2 * 2], double vdSdN[2 * 2]);
int  GetCodonFreqs2(void);
int  PairwiseCodon(FILE *fout, FILE*fds, FILE*fdn, FILE*dt, double space[]);
int  PairwiseAA(FILE *fout, FILE *f2AA);
int  lfunNSsites_rate(FILE* fout, double x[], int np);
int  lfunNSsites_M2M8(FILE* frst, double x[], int np);
int  lfunNSsites_ACD(FILE* frst, double x[], int np);
double GetBranchRate(int igene, int ibrate, double x[], int *ix);
int  GetPMatBranch(double Pt[], double x[], double t, int inode);
int  ConditionalPNode(int inode, int igene, double x[]);
double CDFdN_dS(double x, double par[]);
int  DiscreteNSsites(double par[]);
char GetAASiteSpecies(int species, int sitepatt);
void finishup(void);
int  mergeSeqs(FILE*fout);
void Get4foldSites(void);
int  AdHocRateSmoothing(FILE*fout, double x[NS * 3], double xb[NS * 3][2], double space[]);
void DatingHeteroData(FILE* fout);

int SlidingWindow(FILE*fout, FILE* fpair[], double space[]);

void SimulateData2s61(void);
void Ina(void);
void d4dSdN(FILE*fout);

/* kostas functions */
double logprior(double t, double w, double par[]);
double logistic_transformation(double point, double logmean, double stdlogpar);
double loglikelihood(double Ptmatrix[]);
int EstVariances(double *var);
int BayesPairwise(int is, int js, double x[], double var[], double maxlogl,
   int npoints, double xb[][2], double space[]);
double logP(double x[], int np);
double CDFLogis(double x, double m, double s);
/* end of kostas functions */

struct common_info {
   unsigned char *z[NS];
   char *spname[NS], seqf[512], outf[512], treef[512], daafile[512], cleandata;
   char oldconP[NNODE];       /* update conP for nodes? to save computation */
   int seqtype, ns, ls, ngene, posG[NGENE + 1], lgene[NGENE], npatt, *pose, readpattern;
   int runmode, clock, verbose, print, codonf, aaDist, model, NSsites;
   int nOmega, nbtype, nOmegaType;  /* branch partition, AA pair (w) partition */
   int method, icode, ncode, Mgene, ndata, bootstrap;
   int fix_rgene, fix_kappa, fix_omega, fix_alpha, fix_rho, nparK, fix_blength, getSE;
   int np, ntime, nrgene, nkappa, npi, nrate, nalpha, ncatG, hkyREV;
   size_t sconP, sspace;
   double *fpatt, *space, kappa, omega, alpha, rho, rgene[NGENE], TipDate, TipDate_TimeUnit;
   double pi[NCODE], piG[NGENE][64], fb61[64];
   double f3x4[NGENE][12], *pf3x4, piAA[20];
   double freqK[NCATG], rK[NCATG], MK[NCATG*NCATG], daa[20 * 20], *conP, *fhK;
   double *blengths0;
   double(*plfun)(double x[], int np);
   double hyperpar[4]; /* kostas, the hyperparameters for the prior distribution of distance & omega */
   double omega_fix;  /* fix the last w in the NSbranchB, NSbranch2 models
          for lineages.  Useful for testing whether w>1 for some lineages. */
   int     conPSiteClass; /* conPSiteClass=0 if (method==0) and =1 if (method==1)?? */
   int     NnodeScale;
   char   *nodeScale;        /* nScale[ns-1] for interior nodes */
   double *nodeScaleF;       /* nScaleF[npatt] for scale factors */
  /* pomega & pkappa are used to communicate between SetParameters & ConditionalPNode
     & eigenQcodon.  Try to remove them? */
   double *pomega, pkappa[5], *ppi;
}  com;
struct TREEB {
   int  nbranch, nnode, root, branches[NBRANCH][2];
   double lnL;
}  tree;
struct TREEN {
   int father, nson, sons[MAXNSONS], ibranch, ipop;
   double branch, age, omega, *conP, label;
   char *nodeStr, fossil, usefossil;
}  *nodes, **gnodes, nodes_t[2 * NS - 1];


/* for stree.nodes[].fossil: lower, upper, bounds, gamma, inverse-gamma */
enum { LOWER_F = 1, UPPER_F, BOUND_F } FOSSIL_FLAGS;
char *fossils[] = { " ", "L", "U", "B" };

struct SPECIESTREE {
   int nbranch, nnode, root, nspecies, nfossil;
   struct TREESPN {
      char name[LSPNAME + 1], fossil, usefossil;  /* fossil: 0, 1, 2, 3 */
      int father, nson, sons[2];
      double age, pfossil[7];   /* lower and upper bounds or alpha & beta */
      double *lnrates;          /* log rates for loci */
   } nodes[2 * NS - 1];
}  stree;
/* all trees are binary & rooted, with ancestors unknown. */

struct DATA { /* locus-specific data and tree information */
   int ns[NGENE], ls[NGENE], npatt[NGENE], ngene, lgene[NGENE];
   int root[NGENE + 1], BlengthMethod, fix_nu, nbrate[NGENE], icode[NGENE];
   int datatype[1];
   char   *z[NGENE][NS], cleandata[NGENE];
   char   idaafile[NGENE], daafile[NGENE][40];
   double *fpatt[NGENE], lnpT, lnpR, lnpDi[NGENE];
   double Qfactor[NGENE], pi[NGENE][NCODE];
   double rgene[NGENE], kappa[NGENE], alpha[NGENE], omega[NGENE];
   int NnodeScale[NGENE];
   char *nodeScale[NGENE];    /* nScale[data.ns[locus]-1] for interior nodes */
}  data;

extern double Small_Diff;
int Nsensecodon, FROM61[64], FROM64[64], FourFold[4][4];
int ChangedInIteration;  /* 1: t changed, update P(t); 2: paras changed, update UVRoot */
double *PMat, *U, *V, *Root, *_UU[NBTYPE + 2], *_VV[NBTYPE + 2], *_Root[NBTYPE + 2];
/* 5 sets for branchsite models (YN2002); 6 sets for clade models */

double pcodon0[64], paa0[20], *pcodonClass;  /* for aaDist=FIT1 or FIT2 */

int BayesEB;  /* =1 for site models M2a & M8; =2 for branch-site models A & C */
int LASTROUND;
int IClass = -1;

int OmegaAA[190], AA1STEP[190];
enum { DNA, AA, CODON, MORPHC } DATATYPE;

double _rateSite = 1;
double Qfactor_NS, Qfactor_NS_branch[NBTYPE];
int KGaussLegendreRule = 16;

double AAchem[][20 + 1] = {  /* last element is the max */
{8.1, 10.5, 11.6, 13, 5.5, 10.5, 12.3, 9, 10.4, 5.2,
 4.9, 11.3,  5.7, 5.2,  8,  9.2,  8.6, 5.4, 6.2, 5.9,    13}, /* p */
{ 31, 124,  56,  54,   55, 85, 83,   3, 96, 111,
 111, 119, 105, 132, 32.5, 32, 61, 170, 136, 84,        170}, /* v */
{0, 0.65, 1.33, 1.38, 2.75, 0.89, 0.92, 0.74, 0.58,
 0, 0, 0.33, 0, 0, 0.39, 1.42, 0.71, 0.13, 0.2, 0,      -999},/* c */
{-0.11, 0.079, -0.136, -0.285, -0.184, -0.067, -0.246, -0.073, 0.32, 0.001,
 -0.008, 0.049, -0.041, 0.438, -0.016, -0.153, -0.208, 0.493, 0.381, -0.155} /* a */
};   /* in the order p, v, c, a */


FILE *fout, *frub, *flnf, *frst, *frst1, *frst2 = NULL, *finitials;
char *ratef = "rates";
enum { Fequal, F1x4, F3x4, Fcodon, F1x4MG, F3x4MG, FMutSel0, FMutSel } CodonFreqs;
char *codonfreqs[] = { "Fequal", "F1x4", "F3x4", "Fcodon", "F1x4MG", "F3x4MG", "FMutSel0", "FMutSel" };
enum { NSbranchB = 1, NSbranch2, NSbranch3 } NSBranchModels;
char *NSbranchmodels[] = { "One dN/dS ratio",
     "free dN/dS Ratios for branches", "several dN/dS ratios for branches",
     "NSbranch3" };
enum {
   Poisson, EqualInput, Empirical, Empirical_F,
   FromCodon0 = 5, FromCodon = 6, REVaa_0 = 8, REVaa = 9
} AAModel;

char *aamodels[] = { "Poisson", "EqualInput", "Empirical", "Empirical_F", "",
     "FromCodon0", "FromCodon", "", "REVaa_0", "REVaa" };
enum {
   NSnneutral = 1, NSpselection, NSdiscrete, NSfreqs, NSgamma, NS2gamma,
   NSbeta, NSbetaw, NSbetagamma, NSbeta1gamma, NSbeta1normal, NS02normal,
   NS3normal, NSM2aRel = 22
} NSsitesModels;
char *NSsitesmodels[] = { "one-ratio","NearlyNeutral", "PositiveSelection","discrete","freqs",
     "gamma","2gamma","beta","beta&w>1","beta&gamma", "beta&gamma+1",
     "beta&normal>1", "0&2normal>0", "3normal>0", "", "", "", "", "", "", "", "",
     "M2a_rel", "Tgamma", "Tinvgamma", "Tgamma+1", "Tinvgamma+1" };
int maxNSsitesModels = 27;
enum { FIT1 = 11, FIT2 = 12 } SiteClassModels;
enum { AAClasses = 7 } aaDistModels;
char *clockstr[] = { "", "Global clock", "Local clock", "ClockCombined" };
enum { GlobalClock = 1, LocalClock, ClockCombined } ClockModels;

#define CODEML 1
#include "treesub.c"
#include "treespace.c"


/* variables for batch run of site models */
int ncatG0 = 10, insmodel = 0, nnsmodels = 1, nsmodels[15] = { 0 };
/* used for sliding windows analysis */
int windowsize0 = 20, offset0 = 1, npositive = 0;
double lnLmodel;

int main(int argc, char *argv[])
{
   FILE *fseq = NULL, *fpair[6] = {NULL};
   char pairfs[6][32] = { "2NG.dS","2NG.dN","2NG.t", "2ML.dS","2ML.dN","2ML.t" };
   char ctlf[96] = "codeml.ctl", *pmodel, timestr[64];
   char *seqtypestr[3] = { "CODONML", "AAML", "CODON2AAML" };
   char *Mgenestr[] = { "diff. rate", "separate data", "diff. rate & pi",
                     "diff. rate & k&w", "diff. rate & pi & k&w" };
   int getdistance = 0, i,j, k, idata, nc, nUVR, cleandata0;
   size_t s2;

   starttimer();

   /*
   printf("KGaussLegendreRule? ");
   scanf("%d", &KGaussLegendreRule);
   */
   com.ndata = 1;
   noisy = 0;           com.runmode = 0;
   com.clock = 0;       com.fix_rgene = 0; /* 0: estimate rate factors for genes */
   com.cleandata = 0;  /* 1: delete; 0:use missing data */
   com.seqtype = AAseq;
   com.model = Empirical_F;
   strcpy(com.daafile, "jones.dat");
   com.icode = 0;       com.nrate = 0;
   com.fix_kappa = 0;   com.kappa = 1;    com.omega = 2.1;
   com.fix_alpha = 1;   com.alpha = 0.;   com.ncatG = 4;   /* alpha=0 := inf */
   com.fix_rho = 1;     com.rho = 0.;
   com.getSE = 0;       com.print = 0;    com.verbose = 1;  com.fix_blength = 0;
   com.method = 0;      com.space = NULL;

   frub = gfopen("rub", "w");
   frst = gfopen("rst", "w");
   frst1 = gfopen("rst1", "w");

   /*
      mergeSeqs(frst);  exit(0);
      Ina();
   */
   SetSeed(-1, 0);

#if (DSDN_MC || DSDN_MC_SITES)
   SimulateData2s61();
#endif

   if (argc > 2 && !strcmp(argv[argc - 1], "--stdout-no-buf"))
      setvbuf(stdout, NULL, _IONBF, 0);
   if (argc > 1) strncpy(ctlf, argv[1], 95);

   GetOptions(ctlf);
   cleandata0 = com.cleandata;
   if (com.runmode != -2 && com.runmode != -3)
      finitials = fopen("in.codeml", "r");
   else
      getdistance = 1;

   fprintf(frst, "Supplemental results for CODEML (seqf: %s  treef: %s)\n",
      com.seqf, com.treef);
   if (com.getSE == 2) frst2 = fopen("rst2", "w");

   printf("%s in %s\n", seqtypestr[com.seqtype - 1], pamlVerStr);

   fout = gfopen(com.outf, "w");

   if (noisy && (com.seqtype == CODONseq || com.model == FromCodon0 || com.model == FromCodon)) {
      printcu(F0, NULL, com.icode); puts("Nice code, uuh?");
   }

   /* space for P&U&V&Root */
   if (com.clock == 5 || com.clock == 6)
      DatingHeteroData(fout);

   nUVR = 1; nc = 20;
   if (com.seqtype == CODONseq) {
      nc = 64;
      if (com.model >= 1) nUVR = NBTYPE + 2;
   }
   else if (com.seqtype == CODONseq || com.model == FromCodon0 || com.model == FromCodon)
      nc = 64;

   GetMemPUVR(nc, nUVR);

   if ((fseq = fopen(com.seqf, "r")) == NULL || com.seqf[0] == '\0') {
      printf("\n\nSequence file %s not found!\n", com.seqf);
      exit(-1);
   }

   /* d4dSdN(fout); */
   if (com.aaDist == AAClasses) {
      SetAA1STEP();
      GetOmegaAA(OmegaAA);
   }
   else if (com.seqtype == AAseq && com.model == REVaa_0)
      SetAA1STEP();

   if (com.seqtype == 1) {
      for (i = 0; i < 3; i++)
         fpair[i] = (FILE*)gfopen(pairfs[i], "w");
      if (com.runmode == -2 || com.runmode == -3)
         for (; i < 6; i++) fpair[i] = (FILE*)gfopen(pairfs[i], "w");
   }
   else if (com.runmode == -2)
      fpair[0] = (FILE*)gfopen("2AA.t", "w");

   for (idata = 0; idata < com.ndata; idata++) {
      if (com.ndata > 1) {
         printf("\nData set %d ", idata + 1);
         fprintf(fout, "\n\nData set %d\n", idata + 1);
         fprintf(frst, "\t%d", idata + 1);
         fprintf(frst1, "%d", idata + 1);
         fprintf(frub, "\nData set %2d\n", idata + 1);
      }

      if (nnsmodels > 1) {
         if (com.seqtype != 1) error2("batch run of site models requires codon seqs.");
         if (com.fix_omega) error2("fix omega during batch run?");
         if (com.model) error2("model should be 0 in the batch run?");
         if (com.runmode) error2("runmode?");

         /* for allocating memory com.fhK[] */
         com.NSsites = NSbetaw;  com.ncatG = ncatG0 + 1;
         printf("NSsites batch run (ncatG as in YNGP2000): ");
         for (i = 0; i < nnsmodels; i++)
            printf(" %2d", nsmodels[i]);
         FPN(F0);
      }

      com.cleandata = cleandata0;

      /* ReadSeq may change seqtype*/
      ReadSeq((com.verbose ? fout : NULL), fseq, com.cleandata, 0);
      if (com.ngene > 1 && (com.fix_blength == 2 || com.fix_blength == 3))
         error2("fix_blength = 2 or 3 does not work for partitioned data or Mgene models");
      if (com.fix_blength == 3) {
         if ((com.blengths0 = (double*)malloc((com.ns * 2 - 2) * sizeof(double))) == NULL)
            error2("oom blengths0");
      }

      SetMapAmbiguity(com.seqtype, 0);

      fprintf(frst1, "\t%d\t%d\t%d", com.ns, com.ls, com.npatt);

      if (com.ngene == 1)
         com.Mgene = 0;
      if (com.ngene > 1) {
         if (com.seqtype == 1 && com.npi)
            error2("codon models (estFreq) not implemented for ngene > 1");
         if (com.runmode == -2 && com.Mgene != 1) error2("use Mgene=1 for runmode=-2?");
         if (com.runmode == -3 && com.Mgene != 1) error2("use Mgene=1 for runmode=-3?");
         if (com.model) error2("NSbranchsites with ngene.");
         if (com.NSsites) error2("NSsites with ngene.");
         if (com.aaDist >= FIT1)  /* because of pcodon0[] */
         {
            error2("ngene for amino acid fitness models");
         }
      }

      if (com.ndata == 1) fclose(fseq);

      i = (com.ns * 2 - 1) * sizeof(struct TREEN);
      if ((nodes = (struct TREEN*)malloc(i)) == NULL)
         error2("oom nodes");

      pmodel = (com.seqtype == CODONseq ? NSbranchmodels[com.model] : aamodels[com.model]);
      fprintf(fout, "%s (in %s)  %s\n", seqtypestr[com.seqtype - 1], pamlVerStr, com.seqf);
      fprintf(fout, "Model: %s, ", pmodel);
      if (com.clock) fprintf(fout, " %s ", clockstr[com.clock]);
      if (com.seqtype == CODONseq || com.model == FromCodon0 || com.model == FromCodon) {
         if (com.fix_kappa) fprintf(fout, " kappa = %.3f fixed\n", com.kappa);
         if (com.fix_omega) fprintf(fout, " omega = %.3f fixed\n", com.omega);
      }
      if (com.seqtype == AAseq && (com.model == Empirical || com.model == Empirical_F))
         fprintf(fout, " (%s) ", com.daafile);
      if (com.seqtype == AAseq && com.nrate) fprintf(fout, "(nrate:%d) ", com.nrate);
      if (com.alpha && com.rho) fprintf(fout, "Auto-");
      if (com.alpha) fprintf(fout, "dGamma (ncatG=%d) ", com.ncatG);
      if (com.ngene > 1)
         fprintf(fout, " (%d genes: %s)  ", com.ngene, Mgenestr[com.Mgene]);

      if (com.alpha == 0)  com.nalpha = 0;
      else                 com.nalpha = (com.nalpha ? com.ngene : !com.fix_alpha);
      if (com.Mgene == 1)  com.nalpha = !com.fix_alpha;
      if (com.nalpha > 1 && (!com.alpha || com.ngene == 1 || com.fix_alpha))
         error2("Malpha");
      if (com.nalpha > 1 && com.rho) error2("Malpha or rho");
      if (com.nalpha > 1) fprintf(fout, "(%d gamma)", com.nalpha);

      if (com.Mgene && com.ngene == 1) error2("Mgene for one gene.");
      if (com.seqtype == CODONseq) {
         fprintf(fout, "\nCodon frequency model: %s\n", codonfreqs[com.codonf]);
         if (com.alpha)
            fputs("Warning: Gamma model for codons.  See documentation.", fout);
      }
      if ((com.seqtype == CODONseq || com.model == FromCodon0 || com.model == FromCodon)
         && (com.aaDist && com.aaDist < 10 && com.aaDist != AAClasses))
         fprintf(fout, "%s, %s\n", com.daafile, (com.aaDist > 0 ? "geometric" : "linear"));

      if (com.NSsites) {
         fprintf(fout, "Site-class models: ");
         if (nnsmodels == 1) {
            fprintf(fout, " %s", NSsitesmodels[com.NSsites]);
            if (com.NSsites >= NSdiscrete)fprintf(fout, " (%d categories)", com.ncatG);
         }
         if (com.nparK) fprintf(fout, " & HMM");
         FPN(fout);
         if (com.aaDist)
            fprintf(fout, "\nFitness models: aaDist: %d\n", com.aaDist);
      }
      fprintf(fout, "ns = %3d  ls = %3d\n\n", com.ns, com.ls);

      if (getdistance) {
         k = com.ns*(com.ns - 1) / 2;
         SeqDistance = (double*)realloc(SeqDistance, k * sizeof(double));
         ancestor = (int*)realloc(ancestor, k * sizeof(int));
         if (SeqDistance == NULL || ancestor == NULL) error2("oom distance&ancestor");
         for (i = 0; i < k; i++) SeqDistance[i] = -1;
      }

      com.sspace = max2(5000000, 3 * com.ncode*com.ncode * sizeof(double));
      if (com.NSsites) {
         if (com.sspace < 2 * com.ncode*com.ncode + 4 * com.npatt * sizeof(double))
            com.sspace = 2 * com.ncode*com.ncode + 4 * com.npatt * sizeof(double);
      }
      if ((com.space = (double*)realloc(com.space, com.sspace)) == NULL) {
         printf("\nfailed to get %9zu bytes for space", com.sspace);
         error2("oom space");
      }

      if (com.seqtype == AAseq) {
         InitializeBaseAA(fout);
         if (com.model == FromCodon0 || com.model == FromCodon /* ||com.aaDist==AAClasses */) {
            AA2Codonf(com.pi, com.fb61);  /* get codon freqs from aa freqs */
            if (com.model == FromCodon0) {
               xtoy(com.fb61, com.pi, Nsensecodon);
            }
         }
      }
      else {  /* codon sequences */
         if (com.sspace < max2(com.ngene + 1, com.ns)*(64 + 12 + 4) * sizeof(double)) {
            com.sspace = max2(com.ngene + 1, com.ns)*(64 + 12 + 4) * sizeof(double);
            if ((com.space = (double*)realloc(com.space, com.sspace)) == NULL)
               error2("oom space for #c");
         }
         if (InitializeCodon(fout, com.space))
            error2("giving up on stop codons");

         if (com.Mgene == 3)
            for (i = 0; i < com.ngene; i++)
               xtoy(com.pi, com.piG[i], com.ncode);
      }

      if (getdistance) {
         if (com.seqtype == CODONseq)
            DistanceMatNG86(fout, fpair[0], fpair[1], fpair[2], 0);
         else
            DistanceMatAA(fout);
      }
      fflush(fout);

      if (com.seqtype == AAseq && com.model == Poisson && com.ngene <= 1 && !com.print) {
         PatternWeightJC69like();
         fprintf(fout, "\n\nPrinting out site pattern counts\n");
         printPatterns(fout);
      }
      if (com.alpha || com.NSsites) {
         s2 = com.npatt*com.ncatG * sizeof(double);
         if ((com.fhK = (double*)realloc(com.fhK, s2)) == NULL) error2("oom fhK");
      }

      if ((com.runmode == -2 || com.runmode == -3) && com.Mgene != 1) {
         if (com.seqtype == CODONseq)
            PairwiseCodon(fout, fpair[3], fpair[4], fpair[5], com.space);
         else
            PairwiseAA(fout, fpair[0]);
      }
      else {
         if (com.seqtype == AAseq && com.model == FromCodon0) {
            SetMapAmbiguity(com.seqtype, 1);
            com.seqtype = CODONseq;  
            /* com.model = 0; */
            com.cleandata = 0;
            com.ncode = Nsensecodon;
            for (i = 0; i < com.ns; i++) for (j = 0; j < com.npatt; j++)
               com.z[i][j] += 64;
            for (j = 64; j < 64 + 20; j++)
               getAAstr(CODONs[j], j - 64);
            CODONs[j][0] = CODONs[j][1] = CODONs[j][2] = '*';
            for (i = 0; i < com.ncode; i++)
               getcodon(CODONs[i], FROM61[i]);
         }

         com.sconP = 2L * com.ncode*com.npatt * sizeof(double);
         /* to be increased later in GetInitials() */
         /* com.sconP = (com.ns-1)*com.ncode*com.npatt*sizeof(double); */
         com.conP = (double*)realloc(com.conP, com.sconP);

         printf("\n%9zu bytes for distance", com.ns*(com.ns - 1) / 2 * sizeof(double));
         printf("\n%9zu bytes for conP\n", com.sconP);
         printf("%9zu bytes for fhK\n%9zu bytes for space\n", s2, com.sspace);
         if (com.conP == NULL)
            error2("oom conP");

         if (nnsmodels > 1) {
            for (insmodel = 0; insmodel < nnsmodels; insmodel++) {
               com.NSsites = nsmodels[insmodel];
               if (com.NSsites <= NSpselection)
                  com.ncatG = com.NSsites + 1;
               else if (com.NSsites == NSM2aRel || com.NSsites == NSdiscrete)
                  com.ncatG = 3;
               else if (com.NSsites == NSfreqs)
                  com.ncatG = 5;
               else if (com.NSsites == NSbetaw || com.NSsites == NS02normal)
                  com.ncatG = ncatG0 + 1;
               else
                  com.ncatG = ncatG0;

               com.nrate = com.nkappa = (com.hkyREV ? 5 : !com.fix_kappa);
               if (com.NSsites == 0 || com.NSsites == NSbetaw)  com.nrate += !com.fix_omega;
               else if (com.NSsites == NSnneutral)            com.nrate++;
               else if (com.NSsites == NSpselection || com.NSsites == NSM2aRel)
                  com.nrate += 1 + !com.fix_omega;
               else if (com.NSsites == NSdiscrete)
                  com.nrate += com.ncatG;

               printf("\n\nModel %d: %s\n", com.NSsites, NSsitesmodels[com.NSsites]);
               fprintf(fout, "\n\nModel %d: %s", com.NSsites, NSsitesmodels[com.NSsites]);
               fprintf(frst, "\n\nModel %d: %s", com.NSsites, NSsitesmodels[com.NSsites]);
               fprintf(frub, "\n\nModel %d: %s", com.NSsites, NSsitesmodels[com.NSsites]);
               if (com.NSsites) fprintf(fout, " (%d categories)", com.ncatG);
               FPN(fout);
               Forestry(fout);

               printf("\nTime used: %s\n", printtime(timestr));
               fprintf(fout, "\nTime used: %s\n", printtime(timestr));
            }
         }
         else {
            if (com.Mgene == 1)        MultipleGenes(fout, fpair, com.space);
            else if (com.runmode == 0) Forestry(fout);
            else if (com.runmode == 3) StepwiseAddition(fout, com.space);
            else if (com.runmode >= 4) Perturbation(fout, (com.runmode == 4), com.space);
            else                       StarDecomposition(fout, com.space);
            printf("\nTime used: %s\n", printtime(timestr));
            fprintf(fout, "\nTime used: %s\n", printtime(timestr));
         }
      }
      FPN(frst);  fflush(frst);
      FPN(frst1); fflush(frst1);
      free(nodes);
      if (com.fix_blength == 3)  free(com.blengths0);

   }  /* for (idata) */

   fclose(frst);
   for (i = 0; i < 6; i++) if(fpair[i]) fclose(fpair[i]);
   if (com.ndata > 1 && fseq) fclose(fseq);
   fclose(fout);  fclose(frub);
   if (finitials)  fclose(finitials);
   FreeMemPUVR();
   free(com.pose);
   for (i = 0; i < com.ns; i++) free(com.z[i]);

   return (0);
}


/* x[]: t[ntime]; rgene[ngene-1]; kappa; p[](NSsites); omega[];
        { alpha(for NSsites) !! alpha, rho || rK[], fK[] || rK[], MK[] }
*/

int Forestry(FILE *fout)
{
   static int ages = 0;
   FILE *ftree, *frate = NULL;
   int  status = 0, i, j = 0, k, itree, ntree, np, iteration = 1;
   int pauptree = 0, haslength;
   double x[NP], xb[NP][2], xcom[NP - NBRANCH], lnL = 0, lnL0 = 0, e = 1e-8, tl = 0, nchange = -1;
   double *g = NULL, *H = NULL;

   if ((ftree = fopen(com.treef, "r")) == NULL) {
      printf("\ntree file %s not found.\n", com.treef);
      exit(-1);
   }
   GetTreeFileType(ftree, &ntree, &pauptree, 0);
   if (com.alpha)
      frate = (FILE*)gfopen(ratef, "w");
   if (ntree > 10 && com.npatt > 10000 && com.print)
      puts("\nlnf file may be large");
   flnf = gfopen("lnf", "w+");
   fprintf(flnf, "%6d %6d %6d\n", ntree, com.ls, com.npatt);

   if (com.seqtype == 1 && com.aaDist >= FIT1) {
      xtoy(com.pi, pcodon0, 64);
      zero(paa0, 20);
      FOR(i, com.ncode) paa0[GeneticCode[com.icode][FROM61[i]]] += pcodon0[i];
      pcodonClass = (double*)malloc(com.ncatG * 64 * sizeof(double));
      if (pcodonClass == NULL) error2("oom pcodonClass");
   }

   for (itree = 0; ntree == -1 || itree < ntree; itree++, iteration = 1) {
      if (ReadTreeN(ftree, &haslength, &i, 0, 1)) {
         puts("end of tree file."); break;
      }

      printf("\nTREE # %2d\n", itree + 1);
      fprintf(fout, "\n\nTREE # %2d:  ", itree + 1);
      fprintf(flnf, "\n\n%2d\n", itree + 1);
      if (com.print) fprintf(frst, "\n\nTREE # %2d\n", itree + 1);
      fprintf(frub, "\n\nTREE #%2d\n", itree + 1);

      if ((com.fix_blength == 2 || com.fix_blength == 3) && !haslength)
         error2("We need branch lengths in tree");
      if (com.fix_blength > 0 && !haslength) com.fix_blength = 0;
      if (ages++ == 0 && com.fix_blength > 0 && haslength) {
         if (com.clock) puts("\nBranch lengths in tree are ignored");
         else {
            if (com.fix_blength == 2)
               puts("\nBranch lengths in tree are fixed.");
            else if (com.fix_blength == 1)
               puts("\nBranch lengths in tree used as initials.");
            if (com.fix_blength == 1) {
               FOR(i, tree.nnode)
                  if ((x[nodes[i].ibranch] = nodes[i].branch) < 0)
                     x[nodes[i].ibranch] = 1e-5;
            }
         }
      }
      LASTROUND = 0;
      if (com.cleandata)
         nchange = MPScore(com.space);
      if (com.ns < 40) { OutTreeN(F0, 0, 0); printf("   MP score: %.0f", nchange); }
      OutTreeN(fout, 0, 0); fprintf(fout, "   MP score: %.0f", nchange);

      if (!com.clock && nodes[tree.root].nson <= 2 && com.ns > 2) {
         puts("\nThis is a rooted tree, without clock.  Check.");
         fputs("\nThis is a rooted tree.  Please check!", fout);
      }
      GetInitials(x, &i);

      np = com.np;
      if (noisy >= 3 && np < 100) matout(F0, x, 1, np);
      if (i == -1) iteration = 0;
      if (np > NP || np - com.ntime > NP - NBRANCH) error2("raise NP");
      if (com.sspace < spaceming2(np)) {
         com.sspace = spaceming2(np);
         printf("\nspace adjusted to %9zu bytes\n", com.sspace);
         if ((com.space = (double*)realloc(com.space, com.sspace)) == NULL) {
            printf("\ntrying to get %zu bytes for ming2", com.sspace);
            error2("oom space");
         }
      }
      printf("\nntime & nrate & np:%6d%6d%6d\n", com.ntime, com.nrate, com.np);

      /*
            if(itree && !finitials)  for(i=0;i<np-com.ntime;i++) x[com.ntime+i] = xcom[i];
      */
      if (iteration && np) {
         SetxBound(np, xb);
         SetxInitials(np, x, xb); /* start within the feasible region */
      }
      PointconPnodes();
      /*
      for(i=0; i<com.npatt; i++)
      com.fpatt[i] /= (double)com.ls;
      */
      lnL = com.plfun(x, np);
      if (noisy) {
         printf("\nnp =%6d", np);
         printf("\nlnL0 = %12.6f\n", -lnL);
      }

      if (iteration && np) {
         if (com.method == 1)
            j = minB(noisy > 2 ? frub : NULL, &lnL, x, xb, e, com.space);
         else if (com.method == 3)
            j = minB2(noisy > 2 ? frub : NULL, &lnL, x, xb, e, com.space);
         else
            j = ming2(noisy > 2 ? frub : NULL, &lnL, com.plfun, NULL, x, xb, com.space, e, np);

         if (j == -1 || lnL <= 0 || lnL > 1e7) status = -1;
         else status = 0;
         if (status) fprintf(fout, "\ncheck convergence..");

      }
      printf("Out..\nlnL  = %12.6f\n", -lnL);

      printf("%d lfun, %d eigenQcodon, %d P(t)\n", NFunCall, NEigenQ, NPMatUVRoot);
      if (itree == 0)  {
         lnL0 = lnL;  
         for (i = 0; i < np - com.ntime; i++)   xcom[i] = x[com.ntime + i];
      }
      else if (!j)
         for (i = 0; i < np - com.ntime; i++) xcom[i] = xcom[i] * .2 + x[com.ntime + i] * 0.8;

      if (!LASTROUND && (com.NSsites == NSpselection || com.NSsites == NSM2aRel || com.NSsites == NSdiscrete
         || com.NSsites == NSfreqs || com.NSsites == NS3normal)) {
         /* transform back to p0, p1,... */
         k = com.ntime + com.nrgene + com.nkappa + com.npi;

         if (com.nparK) {   /* HMM model for w */
            k += com.ncatG;
            for (i = 0; i < com.ncatG; i++, k += com.ncatG - 1)
               f_and_x(x + k, x + k, com.ncatG, 0, 0);
         }
         else {
            j = (com.NSsites == NS3normal ? 3 : com.ncatG);
            if (com.model && com.model <= NSbranch2) j = 3;
            f_and_x(x + k, x + k, j, 0, 0);
         }
      }
      LASTROUND = 1;
      if (com.NSsites == NSdiscrete && com.aaDist == 0 && com.model == 0)
         sortwM3(x);
      if (com.clock) { /* move ages into x[] */
         for (i = 0, j = !nodes[tree.root].fossil; i < tree.nnode; i++)
            if (i != tree.root && nodes[i].nson && !nodes[i].fossil)
               x[j++] = nodes[i].age;
      }

      fprintf(fout, "\nlnL(ntime:%3d  np:%3d): %13.6f %+14.6f\n",
         com.ntime, np, -lnL, -lnL + lnL0);

      if (com.fix_blength < 2) {
         OutTreeB(fout);  FPN(fout);
      }
      /*
            OutTreeB(fout);  FPN(fout);
            if(com.fix_blength==2) {
               for(i=0; i<tree.nbranch; i++) fprintf(fout, " %8.5f", nodes[tree.branches[i][1]].branch);
               FPN(fout);
            }
      */
      for (i = 0; i < np; i++) fprintf(fout, " %8.6f", x[i]);
      FPN(fout); fflush(fout);

      if (com.getSE) {
         puts("Calculating SE's");
         if (com.sspace < np*(np + 1) * sizeof(double)) {
            com.sspace = np*(np + 1) * sizeof(double);
            if ((com.space = (double*)realloc(com.space, com.sspace)) == NULL)
               error2("oom space for SE");
         }

         g = com.space;
         H = g + com.np;
         HessianSKT2004(x, lnL, g, H);
         if (com.getSE >= 2 && com.clock == 0 && nodes[tree.root].nson == 3) {  /* g & H */
            fprintf(frst2, "\n %d\n\n", com.ns);
            OutTreeN(frst2, 1, 1);  fprintf(frst2, "\n\n");
            for (i = 0; i < com.ntime; i++)
               if (x[i] > 0.0004 && fabs(g[i]) < 0.005) g[i] = 0;
            for (i = 0; i < com.ntime; i++) fprintf(frst2, " %9.6f", x[i]);  fprintf(frst2, "\n\n");
            for (i = 0; i < com.ntime; i++) fprintf(frst2, " %9.6f", g[i]);  fprintf(frst2, "\n\n");
            fprintf(frst2, "\nHessian\n\n");
            for (i = 0; i < com.ntime; i++, FPN(frst2))
               for (j = 0; j < com.ntime; j++)
                  fprintf(frst2, " %10.4g", H[i*np + j]);
            fflush(frst2);
         }

         for (i = 0; i < np*np; i++)  H[i] *= -1;
         matinv(H, np, np, H + np*np);
         fprintf(fout, "SEs for parameters:\n");
         for (i = 0; i < np; i++)
            fprintf(fout, " %8.6f", (H[i*np + i] > 0. ? sqrt(H[i*np + i]) : -1));
         FPN(fout);
      }

      if (com.seqtype == 1 && com.ntime && com.clock == 0)
         fprintf(fout, "\nNote: Branch length is defined as number of nucleotide substitutions per codon (not per neucleotide site).\n");
      if (com.Mgene > 1) {
         fprintf(fout, "Note: Branch length is defined for the first gene (site partition).\n");
         fprintf(fout, "For other genes, look at \"rates for genes\".\n");
      }

      /* if (com.clock) SetBranch (x); */
      if (com.clock && com.nbtype > 1)
         fputs("\nWarning: branch rates are not yet applied in tree length and branch lengths", fout);
      if (AbsoluteRate)
         fputs("\nNote: mutation rate is not applied to tree length.  Tree has ages, for TreeView", fout);
      for (i = 0, tl = 0; i < tree.nnode; i++)
         if (i != tree.root) tl += nodes[i].branch;
      fprintf(fout, "\ntree length = %9.6f%s\n", tl, com.ngene > 1 ? " (1st gene)" : "");

      for (i = 0; i < com.np; i++) fprintf(frst1, "\t%.3f", x[i]);
      fprintf(frst1, "\t%.3f", -lnL);

      /*
            fprintf(frst1,"\t%.4f", (com.ns==2 ? x[0]*2 : 0));
            for(i=0; i<com.nkappa; i++) fprintf(frst1,"\t%.3f",x[com.ntime+i]);
            fprintf(frst1,"\t%.4f", com.omega);
            fprintf(frst1,"\t%.3f", -lnL);
      */
      FPN(fout); OutTreeN(fout, 0, 1);  FPN(fout);
      FPN(fout); OutTreeN(fout, 1, 1);  FPN(fout);
      if (com.clock) {
         FPN(fout); OutTreeN(fout, 1, PrNodeNum); FPN(fout);
      }

      if (com.np - com.ntime || com.clock)
         DetailOutput(fout, x, H);

      if (com.seqtype == AAseq && com.model >= REVaa_0)
         eigenQaa(fout, Root, U, V, x + com.ntime + com.nrgene);

      if (com.NSsites)
         lfunNSsites_rate(frst, x, np);
      if (com.print) {
         if (com.rho == 0 && com.nparK == 0 && com.clock <= 1)
            AncestralSeqs(frst, x);
         if (!com.NSsites && com.plfun != lfun)
            lfunRates(frate, x, np);
      }
      com.print -= 9;
      lnL = com.plfun(x, np);
      com.print += 9;

      fflush(fout);  fflush(flnf);  fflush(frst);  fflush(frst1);
   }     /* for(itree) */

   fclose(ftree);
   if (frate) fclose(frate);
   if (com.aaDist && com.aaDist < 10 && com.aaDist != AAClasses
      && (com.seqtype == CODONseq || com.model == FromCodon0 || com.model == FromCodon))
      printf("\n%s, %s.\n", com.daafile, (com.aaDist > 0 ? "geometric" : "linear"));
   if (com.seqtype == 1 && com.aaDist >= FIT1) free(pcodonClass);
   if (ntree == -1)  ntree = itree;

   if (ntree > 1) {
      rewind(flnf);
      rell(flnf, fout, ntree);
   }

   fclose(flnf);
   return (0);
}


double *PointKappa(double xcom[], int igene)
{
   /* This points to the kappa parameters in xcom[], by looking at com.model,
      igene, et&c.
   */
   int k = com.nrgene;
   int nka = (com.hkyREV ? 5 : 1), nw = (com.aaDist == AAClasses ? com.nOmegaType : 1);

   if (com.Mgene > 1 && com.Mgene >= 3)
      k += igene*(nka + nw);

   if (com.fix_kappa) return(&com.kappa);

   return(xcom + k);
}

double *PointOmega(double xcom[], int igene, int inode, int isiteclass)
{
   /* This points to the omega parameters in xcom[], by looking at com.model,
      com.NSsites and igene.  This sometimes points to com.omega or com.rK[].
      This is called by SetParameters(), DetailOutput(), etc.

      Difficulties in using this with lfunt() etc.

      Trying to remove global variables com.pomega and com.pkappa through
      PointOmega and PointKappa, but was unsuccessful when too many changes were
      made at the same time.  Perhaps look at this later.  Note that some
      variables are passed over the head from lfunt() etc. to eigenQcodon().

      Ziheng Notes: 8 August 2003.

   */
   int k = com.nrgene + com.nkappa, backfore;
   int nka = (com.hkyREV ? 5 : 1), nw = (com.aaDist == AAClasses ? com.nOmegaType : 1);

   if (com.seqtype != CODONseq && com.model != FromCodon0 && com.model != FromCodon)
      error2("should not be here.");

   if (com.NSsites == 0 && com.model == 0) { /* simple case: one ratio */
      if (com.ngene <= 1) {
         if (com.fix_omega) return (&com.omega_fix);  /* fix_omega */
         else;
      }
      else if (com.Mgene >= 3)
         k += igene*(nka + nw) + nka;
   }
   else if (com.NSsites == 0 && com.model) {  /* branch model */
      if (com.aaDist == 0) {
         if (com.fix_omega && nodes[inode].label == com.nbtype - 1)
            return (&com.omega_fix);
         else k += (int)nodes[inode].label;
      }
      else if (com.aaDist == AAClasses)
         k += (int)nodes[inode].label*com.nOmegaType;
   }
   else if (com.NSsites && com.model == 0) { /* site model */
      if (com.aaDist < 10)
         k += com.ncatG - 1 + 2 * isiteclass;
      else if (com.aaDist == FIT1)
         k += com.ncatG - 1 + 4 * isiteclass;
      else if (com.aaDist == FIT2)
         k += com.ncatG - 1 + 5 * isiteclass;
      else
         return (&com.rK[isiteclass]);
   }
   else if (com.NSsites && com.model <= NSbranch2) { /* branch&site models A&B */
      k += 2;   /* skip the frequencies. */
      backfore = (int)nodes[inode].label;
      if (isiteclass < 2)
         return(&com.rK[isiteclass]);
      else if (isiteclass == 2) {
         if (com.fix_omega && backfore)
            return(&com.omega_fix);
         else
            k += 2 + (com.NSsites == NSpselection ? 0 : 2) + backfore;
      }
   }
   else { /* NSbranch3: Clade models C and D */
      k += com.ncatG - 1;   /* skip the frequencies. */
      backfore = (int)nodes[inode].label;
      if (isiteclass < com.ncatG - 1)
         return(&com.rK[isiteclass]);
      else if (isiteclass == com.ncatG - 1) {
         if (com.fix_omega && backfore == com.nbtype - 1)
            return(&com.omega_fix);
         else
            k += 2 + (com.NSsites == NSpselection ? 0 : 2) + backfore;
      }
   }
   return (xcom + k);
}


int sortwM3(double x[])
{
   /* sort the w values for NSsites=NSdiscrete
      This assumes that com.freqK[] and com.rK[] have been initialized.
   */
   int i, k = com.ntime + com.nrgene + com.nkappa + com.npi, index[NCATG];
   double space[NCATG];

   if (com.NSsites != NSdiscrete) error2("sortwM3");
   if (fabs(1 - sum(com.freqK, com.ncatG)) > 1e-6) error2("sortwM3: freqK");

   if (com.nparK) { puts("\asortwM3 for HMM not implemented yet.."); return(-1); }

   indexing(com.rK, com.ncatG, index, 0, (int*)space);
   xtoy(com.rK, space, com.ncatG);
   FOR(i, com.ncatG) com.rK[i] = space[index[i]];
   xtoy(com.freqK, space, com.ncatG);
   FOR(i, com.ncatG) com.freqK[i] = space[index[i]];
   FOR(i, com.ncatG - 1) x[k + i] = com.freqK[i];
   FOR(i, com.ncatG)   x[k + com.ncatG - 1 + i] = com.rK[i];
   return(0);
}


void printParametersNSsites(FILE* fout, double x[])
{
   int i, j, k = com.ntime + com.nrgene + com.nkappa + com.npi;
   double w[NBTYPE][3];

   if (!com.NSsites) error2("should not be here");

   fprintf(fout, "\n\nMLEs of dN/dS (w) for site classes (K=%d)\n", com.ncatG);
   if (com.model == 0) {
      fputs("\np: ", fout);  for (i = 0; i < com.ncatG; i++) fprintf(fout, " %8.5f", com.freqK[i]);
      fputs("\nw: ", fout);  for (i = 0; i < com.ncatG; i++) fprintf(fout, " %8.5f", com.rK[i]);
      i = com.ncatG - 1;
      if (com.freqK[i] < 1e-5 && com.rK[i] > 1)
         fprintf(fout, "\n(note that p[%d] is zero)\n", i);
   }
   else if (com.model <= NSbranch2) {
      fprintf(fout, "\nsite class             0        1       2a       2b");
      fprintf(fout, "\nproportion     ");
      for (i = 0; i < com.ncatG; i++) fprintf(fout, " %8.5f", com.freqK[i]);
      fprintf(fout, "\nbackground w   ");
      for (i = 0; i < com.ncatG; i++) fprintf(fout, " %8.5f", com.rK[i % 2]);
      fprintf(fout, "\nforeground w   ");
      for (i = 0; i < com.ncatG - 2; i++) fprintf(fout, " %8.5f", com.rK[i % 2]);
      for (i = 0; i < 2; i++) fprintf(fout, " %8.5f", (com.fix_omega ? com.omega_fix : x[com.np - 1]));

      if (com.freqK[2] < 1e-5 && com.rK[2] > 1)
         fprintf(fout, "\n(note that p[2] is zero)\n");

   }
   else if (com.model == NSbranch3) {
      k += com.ncatG - 1 + (com.NSsites == 3 && com.ncatG > 2) + 1;  /* freqs & w0 & w1 */
      for (i = 0; i < com.nbtype; i++) {
         for (j = 0; j < com.ncatG - 1; j++)
            w[i][j] = com.rK[j];
         w[i][com.ncatG - 1] = (i == com.nbtype - 1 && com.fix_omega ? com.omega_fix : x[k++]);
      }

      fprintf(fout, "\nsite class    ");
      for (i = 0; i < com.ncatG; i++) fprintf(fout, " %9d", i);
      fprintf(fout, "\nproportion     ");
      for (i = 0; i < com.ncatG; i++) fprintf(fout, " %9.5f", com.freqK[i]);
      for (i = 0; i < com.nbtype; i++) {
         fprintf(fout, "\nbranch type %d: ", i);
         for (j = 0; j < com.ncatG; j++) fprintf(fout, " %9.5f", w[i][j]);
      }
      i = com.ncatG - 1;
      if (com.freqK[i] < 1e-5)  fprintf(fout, "\n(note that p[%d] is zero)\n", i);
   }
   fprintf(fout, "\n");
}

static int ijAAref = 19 * 20 + 9;
/* reference aa pair: VI (for REVaa, REVaa_0, AAClasses to estimate Grantham)
   The rate for this pair is set to 1, and other rates are relative to it.
*/
#define E1N(m,s) (s/sqrt(PI*2)*exp(-square((1-m)/s)/2)+m*(1-CDFNormal((1-m)/s)))


void DetailOutput(FILE *fout, double x[], double var[])
{
   /* var[] is used for codon models if com.getSE=1 to calculate the variances
      of dS and dN.
   */
   int i, j, k = com.ntime, np = com.np, npclass, ibtype;
   double om = -1, N = -1, S = 0, dN = 0, dS = 0, dSt, dNt, mr = 0, vtw[4], vSN[4], omclass[NCATG];
   double phi1 = 0, phi2 = 0, t, *tdSdNb = NULL, y;
   double mu[3] = { 0,1,2 }, sig[3] = { -1 }; /* 3normal: mu0=0 fixed. mu2 estimated */
   double fb3x4[12];

   fprintf(fout, "\nDetailed output identifying parameters\n");

   if (com.clock) OutputTimesRates(fout, x, var);
   k = com.ntime;
   if (com.nrgene) {
      fprintf(fout, "\nrates for %d genes:%6.0f", com.ngene, 1.);
      for (i = 0; i < com.nrgene; i++)
         fprintf(fout, " %8.5f", x[k++]);
      FPN(fout);
   }

   if (com.seqtype == CODONseq || com.model == FromCodon0 || com.model == FromCodon) {
      if (com.hkyREV) {
         fprintf(fout, "a (TC) & b (TA) & c (TG) & d (CA) & e (CG): ");
         FOR(i, 5) fprintf(fout, "%8.5f ", x[k++]);  FPN(fout);
      }
      else if (!com.fix_kappa && com.Mgene <= 2)
         fprintf(fout, "\nkappa (ts/tv) = %8.5f\n", x[k++]);

      if (com.npi) {
         if (com.codonf == F1x4 || com.codonf == F1x4MG || com.codonf >= FMutSel0) {
            for (j = 0, fb3x4[3] = 1; j < 3; j++) fb3x4[j] = x[k + j];
            abyx(1 / sum(fb3x4, 4), fb3x4, 4);
            fprintf(fout, "\nFrequency parameters:\n");
            for (j = 0; j < 4; j++)
               fprintf(fout, " %9.5f (%c)", fb3x4[j], BASEs[j]);

            if (com.codonf == FMutSel)
               for (j = 0; j < 4; j++)
                  fprintf(frst1, "\t%.4f", fb3x4[j]);
         }
         else if (com.codonf == F3x4 || com.codonf == F3x4MG) {
            for (j = 0; j < 3; j++) {
               xtoy(x + k + j * 3, fb3x4 + j * 4, 3);
               fb3x4[j * 4 + 3] = 1;
               abyx(1 / sum(fb3x4 + j * 4, 4), fb3x4 + j * 4, 4);
            }
            fprintf(fout, "\nCodon frequency model: %s", codonfreqs[com.codonf]);
            fprintf(fout, "\nFrequency parameters:\n");
            for (i = 0; i < 3; i++, FPN(fout)) {
               fprintf(fout, "Position %d:  ", i + 1);
               for (j = 0; j < 4; j++)
                  fprintf(fout, " %9.5f (%c)", fb3x4[i * 4 + j], BASEs[j]);
            }
         }
         if (com.npi > 3 || com.codonf != FMutSel) {
            fprintf(fout, "\nEquilibrium codon frequencies (evolver-style):\n");
            for (j = 0; j < 64; j++) {
               fprintf(fout, " %11.8f", GeneticCode[com.icode][j] == -1 ? 0 : com.pi[FROM64[j]]);
               if ((j + 1) % 4 == 0) FPN(fout);
            }
         }
         if (com.npi > 3 && com.codonf >= FMutSel0) {
            if (com.codonf == FMutSel0) {
               fprintf(fout, "\nEquilibrium amino acid frequencies:\n");
               for (j = 0; j < 20; j++) {
                  fprintf(fout, " %11.8f", com.piAA[j]);
                  if ((j + 1) % 10 == 0) FPN(fout);
               }
               i = GeneticCode[com.icode][FROM61[com.ncode - 1]];
               y = (i == 19 ? 0 : com.ppi[3 + i]);
               fprintf(fout, "\nfitness for %d codons (amino acid %c has fitness 0)\n", com.ncode, AAs[i]);
               for (j = 0; j < com.ncode; j++) {
                  i = GeneticCode[com.icode][FROM61[j]];
                  fprintf(fout, " %9.6f", (i == 19 ? 0 : com.ppi[3 + i]) - y);
               }
            }
            else {
               fprintf(fout, "\nfitness for %d codons (GGG has fitness 0)\n", com.ncode - 1);
               for (j = 0; j < com.ncode - 1; j++)
                  fprintf(fout, " %9.6f", com.ppi[3 + j]);
            }
            FPN(fout);
         }

         k += com.npi;

         if (com.codonf == FMutSel)
            SelectionCoefficients(frst, com.pkappa, com.ppi, com.omega);
      }

      /* dN/dS by averaging over site classes.
         Qfactor_NS was calculated during ML iteration and is used here..
      */
      if (com.NSsites && (com.model == 0 || com.model == FromCodon0)) {
         for (j = 0, dS = dN = 0; j < com.ncatG; j++) {
            if (com.aaDist) {
               if (com.aaDist < 10)
                  com.pomega = x + k + com.ncatG - 1 + 2 * j;
               else if (com.aaDist >= FIT1) {
                  com.pomega = x + k + com.ncatG - 1 + j*(4 + (com.aaDist == FIT2));
                  xtoy(pcodonClass + j * 64, com.pi, com.ncode);
               }
            }
            mr = -1;
            eigenQcodon(2, 1, &S, &dSt, &dNt, NULL, NULL, NULL, &mr, com.pkappa, com.rK[j], PMat);
            /* t=1 used here, and dS & dN used later for each branch */
            dS += com.freqK[j] * dSt;
            dN += com.freqK[j] * dNt;
            omclass[j] = dNt / dSt;
         }
         om = dN / dS;
         dS *= Qfactor_NS;
         dN *= Qfactor_NS;
         N = com.ls * 3 - S;
      }


      if (!com.fix_omega && com.NSsites == 0 && (com.model == 0 || com.model == FromCodon0) && com.aaDist != 7 && com.Mgene <= 2)
         fprintf(fout, "\nomega (dN/dS) = %8.5f\n", x[k++]);

      /* dN/dS rate ratios for classes */
      if (com.NSsites >= NSgamma) {
         fprintf(fout, "\nParameters in M%d (%s):\n ", com.NSsites, NSsitesmodels[com.NSsites]);
         if (com.NSsites == NSgamma)
            fprintf(fout, "  a=%9.5f  b=%9.5f\n", x[k], x[k + 1]);
         else if (com.NSsites == NS2gamma)
            fprintf(fout, " p0 = %9.5f  a0 = %9.5f  b0 = %9.5f\n(p1 = %9.5f) a1 = %9.5f (b1 = %9.5f)\n",
               x[k], x[k + 1], x[k + 2], 1 - x[k], x[k + 3], x[k + 3]);
         else if (com.NSsites == NSbeta)
            fprintf(fout, "p = %9.5f  q = %9.5f\n", x[k], x[k + 1]);
         else if (com.NSsites == NSbetaw)
            fprintf(fout, " p0 = %9.5f  p = %9.5f q = %9.5f\n (p1 = %9.5f) w = %9.5f\n",
               x[k], x[k + 1], x[k + 2], 1 - x[k], (com.fix_omega ? com.omega : x[k + 3]));
         else if (com.NSsites == NSbetagamma)
            fprintf(fout, " p0 = %9.5f  p = %9.5f  q = %9.5f\n(p1 = %9.5f) a = %9.5f  b = %9.5f\n",
               x[k], x[k + 1], x[k + 2], 1 - x[k], x[k + 3], x[k + 4]);
         else if (com.NSsites == NSbeta1gamma)
            fprintf(fout, " p0 = %9.5f  p = %9.5f  q = %9.5f\n(p1 = %9.5f) a = %9.5f  b = %9.5f\n",
               x[k], x[k + 1], x[k + 2], 1 - x[k], x[k + 3], x[k + 4]);
         else if (com.NSsites == NSbeta1normal)
            fprintf(fout, " p0 = %9.5f  p = %9.5f  q = %9.5f\n(p1 = %9.5f) u = %9.5f  s = %9.5f\n",
               x[k], x[k + 1], x[k + 2], 1 - x[k], x[k + 3], x[k + 4]);
         else if (com.NSsites == NS02normal)
            fprintf(fout, "p0 = %9.5f  p1 = %9.5f  u2 = %9.5f  s1 = %9.5f  s2 = %9.5f\n",
               x[k], x[k + 1], x[k + 2], x[k + 3], x[k + 4]);
         else if (com.NSsites == NS3normal)
            fprintf(fout, "p0 = %9.5f  p1 = %9.5f (p2 = %9.5f)\n u2 = %9.5f  s0 = %9.5f  s1 = %9.5f  s2 = %9.5f\n",
               x[k], x[k + 1], 1 - x[k] - x[k + 1], x[k + 2], x[k + 3], x[k + 4], x[k + 5]);
      }

      if (com.NSsites == NSdiscrete && com.aaDist) { /* structural site classes */
         npclass = (com.aaDist < 10 ? 2 : (com.aaDist == FIT1 ? 4 : 5));
         fprintf(fout, "\nParameters in each class (%d)", npclass);
         fprintf(fout, "%s:\n\n",
            (com.aaDist < 10 ? "(b, a)" : "(a_p, p*, a_v, v*, b)"));
         for (j = 0, k += com.ncatG - 1; j < com.ncatG; j++, FPN(fout)) {
            fprintf(fout, "%d: f=%8.5f, ", j + 1, com.freqK[j]);
            FOR(i, npclass) fprintf(fout, "%9.5f", x[k++]);
            fprintf(fout, " dN/dS = %7.5f", omclass[j]);
         }
      }
      else if (com.NSsites && com.aaDist == 0) {
         printParametersNSsites(fout, x);
         if (com.nparK) {
            fprintf(fout, "\nTransition matrix M in HMM: M_ij=Prob(i->j):\n");
            matout(fout, com.MK, com.ncatG, com.ncatG);
         }
      }
      else if (com.aaDist && com.aaDist <= 6) { /* one class (YNH98, Genetics) */
         k = com.ntime + com.nrgene + com.nkappa + com.npi;
         fprintf(fout, "\nb = %9.5f", x[k++]);
         if (com.seqtype == CODONseq)  fprintf(fout, "\na = %9.5f\n", x[k++]);
      }
      else if (com.aaDist && com.aaDist >= 11) { /* fitness, one class */
         fprintf(fout, "\nfitness model (a_p, p*, a_v, v*, (and w0 for FIT2):\n");
         k = com.ntime + com.nrgene + com.nkappa + com.npi;
         FOR(i, 4 + (com.aaDist == FIT2)) fprintf(fout, " %9.5f", x[k++]);  FPN(fout);
      }
      else if ((com.model == 0 || com.model == FromCodon0) && com.NSsites == 0 && !com.fix_omega && com.Mgene > 2) {
         if (!com.fix_kappa && !com.fix_omega) {
            for (i = 0; i < com.ngene; i++, k += 2)
               fprintf(fout, "\ngene #%2d: kappa = %9.5f omega = %9.5f", i + 1, x[k], x[k + 1]);
         }
         else if (com.fix_kappa) {
            for (i = 0; i < com.ngene; i++, k++)
               fprintf(fout, "\ngene #%2d: omega = %9.5f", i + 1, x[k]);
         }
         else if (com.fix_omega) {
            for (i = 0; i < com.ngene; i++, k++)
               fprintf(fout, "\ngene #%2d: kappa = %9.5f", i + 1, x[k]);
         }
      }
   }
   else
      k += com.nrate;

   for (j = 0; j < com.nalpha; j++) {
      if (!com.fix_alpha)
         fprintf(fout, "\nalpha (gamma, K = %d) = %8.5f", com.ncatG, (com.alpha = x[k++]));
      if (com.nalpha > 1)
         DiscreteGamma(com.freqK, com.rK, com.alpha, com.alpha, com.ncatG, DGammaUseMedian);

      fprintf(fout, "\nrate: "); FOR(i, com.ncatG) fprintf(fout, " %8.5f", com.rK[i]);
      fprintf(fout, "\nfreq: "); FOR(i, com.ncatG) fprintf(fout, " %8.5f", com.freqK[i]);
   }

   if (com.rho) {
      if (!com.fix_rho) fprintf(fout, "rho (correlation) = %8.5f\n", x[k]);
      fprintf(fout, "transition probabilities between rate categories:\n");
      for (i = 0; i < com.ncatG; i++, FPN(fout))  FOR(j, com.ncatG)
         fprintf(fout, " %8.5f", com.MK[i*com.ncatG + j]);
   }

   if (com.aaDist == AAClasses) {
      if (com.model == 0 || com.model == FromCodon0) {
         fprintf(fout, "\nw (dN/dS) classes for amino acid pairs:\n");
         for (k = 0; k < com.nOmegaType; k++) {
            fprintf(fout, " %9.5f: ", x[com.ntime + com.nrgene + com.nkappa + k]);
            for (i = 0; i < 20; i++) for (j = 0; j < i; j++)
               if (OmegaAA[i*(i - 1) / 2 + j] == k) fprintf(fout, " %c%c", AAs[i], AAs[j]);
            if (k == 0)  fprintf(fout, " (background ratio)");
            FPN(fout);
         }
         /* output for bubble plot */
         if (com.seqtype == 1) {
            for (i = 0; i < 20; i++) for (j = 0; j < i; j++) {
               y = 0;
               if (AA1STEP[i*(i - 1) / 2 + j])
                  y = x[com.ntime + com.nrgene + com.nkappa + OmegaAA[i*(i - 1) / 2 + j]];  /* omega */
               fprintf(frst, "%c%c %3d %3d %8.5f\n", AAs[i], AAs[j], i + 1, j + 1, y);
            }
         }
      }
      else {
         fprintf(fout, "\nw (dN/dS) for branch-type and amino acid class:\n");
         k = com.ntime + com.nrgene + com.nkappa + com.npi;
         for (i = 0; i < com.nbtype; i++) {
            fprintf(fout, "Branch type %d: ", i);
            for (j = 0; j < com.nOmegaType; j++) {
               fprintf(fout, " %9.5f", x[k++]);
            }
            FPN(fout);
         }
      }
   }

   /* dN & dS for each branch in the tree */
   if (com.seqtype == CODONseq && com.ngene == 1 && (com.model == 0 || com.model == FromCodon0 || com.NSsites == 0)) {
      tdSdNb = (double*)malloc(tree.nnode * 3 * sizeof(double));
      if (tdSdNb == NULL) error2("oom DetailOutput");
      if (com.model>=NSbranchB && com.model <= NSbranch3 && com.aaDist != AAClasses) {  /*  branch models */
         fprintf(fout, "\nw (dN/dS) for branches: ");
         k = com.ntime + com.nrgene + com.nkappa + com.npi;
         for (i = 0; i < com.nOmega - 1; i++)
            fprintf(fout, " %7.5f", x[k + i]);
         fprintf(fout, " %7.5f", (com.fix_omega ? com.omega : x[k + i]));
         FPN(fout);
      }
      fputs("\ndN & dS for each branch\n\n", fout);
      fprintf(fout, "%7s%11s%8s%8s%8s%8s%8s %5s %5s\n\n",
         "branch", "t", "N", "S", "dN/dS", "dN", "dS", "N*dN", "S*dS");
      for (i = 0, dNt = dSt = 0; i < tree.nbranch; i++) {
         fprintf(fout, "%4d..%-3d ", tree.branches[i][0] + 1, tree.branches[i][1] + 1);
         k = com.ntime + com.nrgene + com.nkappa + com.npi;
         /*       if(com.codonf >= FMutSel0)
                     com.ppi = x+com.ntime+com.nrgene+com.nkappa;
           */
         t = nodes[tree.branches[i][1]].branch;

         if (com.NSsites == 0) {
            if (com.aaDist) om = -1; /* not used in eigenQcodon() */
            else if (com.model == 0 || com.model == FromCodon0 || com.model == FromCodon)
               om = (com.fix_omega ? com.omega : x[k]);
            else if (com.model == NSbranchB) om = x[k + i];
            else if (com.model == NSbranch2) om = nodes[tree.branches[i][1]].omega;

            if (com.model == 0 || com.model == FromCodon0  && com.aaDist)
               com.pomega = x + com.ntime + com.nrgene + !com.fix_kappa + com.npi
               + (int)nodes[tree.branches[i][1]].label*com.nOmegaType;

            mr = 0;
            eigenQcodon(2, t, &S, &dS, &dN, NULL, NULL, NULL, &mr, com.pkappa, om, PMat); /* PMat destroyed! */
            dNt += dN;
            dSt += dS;
            if (com.aaDist) om = dN / dS;
            /*
                        if(dS<.01/com.ls) om = -1;
                        else if(om==-1)   om = dN/dS;
                        if(com.model==0)  om = com.omega;
            */
            N = com.ls * 3 - S;
            if (com.model >= NSbranchB &&com.model <= NSbranch3) {
               tdSdNb[i] = t;
               tdSdNb[tree.nnode + i] = dS;
               tdSdNb[tree.nnode * 2 + i] = dN;
            }

            fprintf(fout, " %7.3f %7.1f %7.1f %7.4f %7.4f %7.4f %5.1f %5.1f",
               t, N, S, om, dN, dS, N*dN, S*dS);
            /* fprintf(frst,"%8.1f%8.1f %9.5f%9.4f%9.4f",N,S,om,dN,dS); */

            /* om not used in AAClasses model */
            if (com.getSE > 1 && com.fix_blength < 2 && !com.clock&&com.aaDist != AAClasses) {
               vtw[0] = var[i*np + i];
               vtw[3] = var[k*np + k];
               vtw[1] = vtw[2] = var[i*np + k];
               VariancedSdN(t, om, vtw, vSN);
               fprintf(fout, "  dN = %7.4f +- %.4f dS = %7.4f +- %.4f",
                  dN, (vSN[3] > 0 ? sqrt(vSN[3]) : -0), dS, (vSN[0] > 0 ? sqrt(vSN[0]) : -0));
               fprintf(fout, " (method 2)");
            }
            FPN(fout);
         }
         else if (com.model == 0) {  /* NSsites & other site-class models */
            fprintf(fout, "%9.3f %8.1f %8.1f %8.4f %8.4f %8.4f %6.1f %6.1f\n",
               t, N, S, om, dN*t, dS*t, N*dN*t, S*dS*t);
         }
         else {  /* NSbranchsites models */
            ;
         }
      }  /* for (i) */
      if (com.NSsites == 0) {
         fprintf(fout, "\ntree length for dN: %12.4f\ntree length for dS: %12.4f\n", dNt, dSt);
         fprintf(frst1, "\t%.4f\t%.4f", dNt, dSt);
      }
      if (com.model >= NSbranchB &&com.model <= NSbranch3 && com.NSsites == 0) {
         fprintf(fout, "\ndS tree:\n");
         for (i = 0; i < tree.nbranch; i++)
            nodes[tree.branches[i][1]].branch = tdSdNb[tree.nnode + i];
         OutTreeN(fout, 1, 1);
         fprintf(fout, "\ndN tree:\n");
         for (i = 0; i < tree.nbranch; i++)
            nodes[tree.branches[i][1]].branch = tdSdNb[tree.nnode * 2 + i];
         OutTreeN(fout, 1, 1);  FPN(fout);
         /* revert branch lengths to the original values */
         for (i = 0; i < tree.nbranch; i++)
            nodes[tree.branches[i][1]].branch = tdSdNb[i];
         free(tdSdNb);

         /* the first label is the label assigned in the tree file.  The second is w ratio */
         if (com.aaDist == 0) {
            fprintf(fout, "\nw ratios as labels for TreeView:\n");
            OutTreeN(fout, 1, PrOmega);  FPN(fout);
         }
      }
   }  /* if codonseqs */

   FPN(fout); fflush(fout);
}



void ReadNSsitesModels(char *line)
{
   /* This reads the line  NSsites = 0 1 2 3 7 8  in codeml.ctl.
   */
   char *pline;
   int pop_digit;

   if ((pline = strstr(line, "=")) == NULL) error2(".ctl file error NSsites");
   pline++;
   for (nnsmodels = 0; nnsmodels < maxNSsitesModels; nnsmodels++) {
      if (sscanf(pline, "%d", &nsmodels[nnsmodels]) != 1) break;
      for (pop_digit = 0; ; ) {
         if (isdigit(*pline)) { pline++; pop_digit = 1; }
         else if (isspace(*pline)) {
            pline++;
            if (pop_digit) break;
         }
         else  error2(".ctl file NSsites line strange.");
      }
      if (nsmodels[nnsmodels] < 0 || nsmodels[nnsmodels] >= maxNSsitesModels)
         error2("NSsites model");
   }
   com.NSsites = nsmodels[0];
}


int ReadDaafiles(char *line)
{
   /* This reads the daa files and set up the eigen matrices U,V,Root for combined
      clock analyses of multiple protein data sets (clock = 5 or 6).
   */
   int  i, ng = (com.ndata > 1 ? com.ndata : NGENE), markgenes[NGENE];

   splitline(line, ng, markgenes);
   for (i = 0; i < ng; i++) {
      if (!isalnum(line[markgenes[i]])) break;
      sscanf(line + markgenes[i], "%s", data.daafile[i]);
      printf("protein %2d uses %s\n", i + 1, data.daafile[i]);
   }
   return(0);
}

int getnrate(int firsttime)
{
   int i, j;

   if (com.seqtype == AAseq || com.seqtype == CODON2AAseq) {
      if (com.NSsites) error2("use NSsites=0 for amino acids?");
      if (com.hkyREV && (com.model == FromCodon0 || com.model == FromCodon))  /*  REV & FromCodon not well-tested. */
         error2("use hkyREV=0 for amino acids?");
      com.ncode = 20;
      if (com.aaDist == AAClasses)
         com.nrate = com.nkappa = (com.hkyREV ? 5 : !com.fix_kappa);

      switch (com.model) {
      case (Poisson):  case (EqualInput): case (Empirical): case (Empirical_F):
         com.fix_kappa = 1; com.kappa = 0; com.nrate = 0;   break;
      case (FromCodon0):
         com.nrate = com.nkappa = (com.hkyREV ? 5 : !com.fix_kappa);
         if (com.aaDist) com.nrate++;
         if (!com.fix_omega)  com.nrate++;
         if (com.codonf) {
            com.codonf = 0;  puts("CodonFreq=0 reset for model=6.");
         }
         break;
      case (FromCodon):
         com.nrate = com.nkappa = (com.hkyREV ? 5 : !com.fix_kappa);
         if (com.aaDist) com.nrate++;
         if(com.fix_omega) error2("fix_omega = 1?  omega is inestimable!");
         com.omega = -1;
         if (com.codonf) {
            com.codonf = 0;  puts("CodonFreq=0 reset for model=6.");
         }
         break;
      case (REVaa_0): com.fix_kappa = 0; com.kappa = 0; break;
      case (REVaa):   com.fix_kappa = 0; com.kappa = 0; com.nrate = 189; break;
      default: error2("model unavailable");
      }
      if (com.Mgene > 2 || (com.Mgene == 2 && (com.model == Fequal || com.model == 2)))
         error2("Mgene && model");
      if (com.seqtype == 2 && com.model != FromCodon0 && com.model != FromCodon && com.model != AAClasses) {
         com.fix_kappa = com.fix_omega = 1; com.kappa = com.omega = 0;
      }
   }
   else if (com.seqtype == CODONseq) {
      if (com.nparK)
         if (com.model || com.aaDist || com.NSsites != NSdiscrete || com.alpha || com.rho)
            error2("HMM model option");
      if (com.Mgene > 1 && com.model) error2("Mgene & model?");
      if (com.fix_kappa) {
         if (com.hkyREV)
            error2("can't fix kappa for the codon model you selected.");
         else
            com.pkappa[0] = com.kappa;
      }
      if (com.codonf >= FMutSel0 && com.Mgene >= 2)
         error2("model FMutSel + Mgene not implemented");
      if (com.runmode == -2 && com.seqtype == 1 && com.npi)
         error2("runmode = -2 not implemented for codon models with frequencies");
      if (com.runmode == -3 && com.seqtype == 1 && com.npi)
         error2("runmode = -3 not implemented for codon models with frequencies");
      if (com.hkyREV && (com.aaDist || com.Mgene > 1))
         error2("hkyREV with aaDist or Mgene: check options?\a");
      if (com.NSsites<0 || com.NSsites>maxNSsitesModels || (com.NSsites > 13 && com.NSsites < 22))
         error2("option NSsites.");
      if (com.aaDist && com.NSsites)
         error2("aaDist & NSsites don't work together");
      if ((com.model && com.model != FromCodon0 && com.aaDist)
         && ((com.model > NSbranch2 && com.model != FromCodon0) || com.aaDist != AAClasses))
         error2("model & aaDist");
      if (com.model == NSbranch3 && com.NSsites != 2 && com.NSsites != 3)
         error2("clade model should have model = 3 NSsites = 2 or 3.");

      if (com.aaDist && com.fix_omega)
         error2("can't fix_omega for aaDist models");

      com.nrate = com.nkappa = (com.hkyREV ? 5 : !com.fix_kappa);

      /* pi_T, pi_C, pi_A are counted as frequency parameters pi. */
      if (com.codonf == 0)
         com.npi = 0;
      if (com.codonf == FMutSel0)     /* FMutSel0: pi_TCA plus 20 AA freqs. */
         com.npi = 3 + (com.npi ? 20 - 1 : 0);
      else if (com.codonf == FMutSel) /* FMutSel:  pi_TCA plus 60 codon freqs. */
         com.npi = 3 + (com.npi ? com.ncode - 1 : 0);
      else if (com.npi) {
         if (com.codonf == F1x4 || com.codonf == F1x4MG)  com.npi = 3;
         else if (com.codonf == F3x4 || com.codonf == F3x4MG)  com.npi = 9;
         else if (com.codonf == Fcodon)                        com.npi = com.ncode - 1;
      }
      com.nrate += com.npi;

      if (com.aaDist != AAClasses) {
         if (com.fix_kappa > 1) error2("fix_kappa>1, not tested.");  /** ???? */
         if (com.model > 0 && com.model!=FromCodon0 && (com.alpha || !com.fix_alpha))
            error2("dN/dS ratios among branches not implemented for gamma");
         if (com.model > 0 && com.clock)
            error2("model and clock don't work together");
         if (com.fix_omega) {
            com.omega_fix = com.omega;
            if ((com.model == 0 && com.NSsites == NSdiscrete)
               || (com.model && com.NSsites && com.NSsites != NSpselection
                  &&com.NSsites != NSdiscrete && com.NSsites != NSbetaw))
               error2("\afix_omega?");
         }
         if (com.model > NSbranch3 && com.model != FromCodon0)
            error2("seqtype or model.");
         if (com.model == NSbranch2 && com.clock == 2)
            error2("NSbranch & local clock.");
         if (com.model == NSbranch3 && (com.NSsites == NSpselection || com.NSsites == NSdiscrete) && com.ncatG != 3) {
            com.ncatG = 3; puts("ncatG = 3 reset.");
         }
         if (com.kappa < 0)  error2("kappa..");
         if (com.runmode)  com.fix_blength = 0;
         if ((com.runmode == -2 || com.runmode == -3) && (com.NSsites || com.alpha || com.aaDist))
            error2("wrong model for pairwise comparison.\ncheck NSsites, alpha, aaDist, model etc.");
         if (com.runmode > 0 && com.model == 2) error2("tree search & model");
         if (com.aaDist && com.NSsites != 0 && com.NSsites != NSdiscrete)
            error2("NSsites && aaDist.");

         if ((com.NSsites || nnsmodels > 1) && (com.alpha || com.fix_alpha == 0))
            error2("NSsites & Gamma");
         if (com.seqtype == 1 && (com.alpha || com.fix_alpha == 0))
            puts("\aGamma codon model: are you sure this is the model you want to use? ");

         if (com.aaDist == 0) {
            if ((!com.fix_omega || (com.Mgene && com.Mgene >= 3)) 
               && !com.NSsites && (com.model==0 || com.model == FromCodon0))
               com.nrate++;
         }
         else {
            if (com.aaDist <= 6)          com.nrate += 2;   /* a & b, PSB2000 */
            else if (com.aaDist == FIT1)  com.nrate += 4;   /* fitness models: */
            else if (com.aaDist == FIT2)  com.nrate += 5;   /* ap, p*, av, v*, b */
            if (com.aaDist >= FIT1)
               for (i = 0; i < 2; i++)
                  for (j = 0; j < 20; j++) AAchem[i][j] /= AAchem[i][20];
         }

         if (com.NSsites) {
            if (com.NSsites == NSfreqs && com.ncatG != 5)  {
               puts("\nncatG changed to 5."); com.ncatG = 5;
            }
            if (com.model && com.NSsites)
               if ((com.model != 2 && com.model != 3)
                  || (com.NSsites != NSpselection && com.NSsites != NSdiscrete))
                  error2("only NSsites=2,3 & model=2,3 are compatible.");
            switch (com.NSsites) {
            case (NSnneutral):   com.ncatG = 2;  break;
            case (NSpselection):
            case (NSM2aRel):
               com.ncatG = 3;  break;
            case (NSbetaw):      
            case (NS02normal):
               if (firsttime) com.ncatG++;  break;
            }

            if (com.model == 2) { /* branchsite models A & B */
               if (com.ncatG != 3) puts("\nbranch-site model: ncatG reset.");
               com.ncatG = 4;
               com.nrate += (com.NSsites == 2 ? 2 : 3);
            }
            else if (com.model == 3) { /* Clade models C & D */
               if (com.NSsites == NSpselection)  com.nrate += 3;
               else if (com.NSsites == NSdiscrete)    com.nrate += com.ncatG + 1;
            }
            else if (com.NSsites == NSnneutral) {
               if (!com.fix_omega) com.nrate++;
               else { com.nrate++; com.omega_fix = com.omega; }
            }
            else if (com.NSsites == NSpselection || com.NSsites == NSM2aRel) {
               if (!com.fix_omega) com.nrate += 2;
               else { com.nrate++; com.omega_fix = com.omega; }
            }
            else if (com.NSsites == NSbetaw)
            {
               if (!com.fix_omega) com.nrate++; else com.omega_fix = com.omega;
            }
            else if (com.NSsites == NSdiscrete && com.aaDist) {
               if (com.aaDist <= 6) com.nrate += com.ncatG;  /* a&b PSB2000 */
               else {  /* fitness models */
                  com.nrate = !com.fix_kappa + 4 * com.ncatG;
                  if (com.aaDist == FIT2) com.nrate += com.ncatG;
               }
            }
            else if (com.NSsites == NSdiscrete)
               com.nrate += com.ncatG;    /* omega's */
         }
      }
   }
   return(0);
}


int GetOptions(char *ctlf)
{
   int iopt, i, j, nopt = 37, lline = 255;
   char line[255], *pline, opt[99], *comment = "*#";
   char *optstr[] = { "seqfile", "outfile", "treefile", "seqtype", "noisy",
        "cleandata", "runmode", "method", "clock", "TipDate",
        "getSE", "RateAncestor", "CodonFreq", "estFreq", "verbose",
        "model", "hkyREV", "aaDist","aaRatefile", "NSsites",
        "NShmm", "icode", "Mgene", "fix_kappa", "kappa",
        "fix_omega", "omega", "fix_alpha", "alpha", "Malpha",
        "ncatG", "fix_rho", "rho", "ndata", "bootstrap", "Small_Diff", "fix_blength" };
   double t;
   FILE  *fctl;
   int ng = -1, markgenes[NGENE + 99];
   char *daafiles[] = { "", "grantham.dat", "miyata.dat",
                     "g1974c.dat","g1974p.dat","g1974v.dat","g1974a.dat" };

   /* kostas, default prior for t & w */
   com.hyperpar[0] = 1.1; com.hyperpar[1] = 1.1; com.hyperpar[2] = 1.1; com.hyperpar[3] = 2.2;

   fctl = gfopen(ctlf, "r");
   if (noisy) printf("\n\nReading options from %s..\n", ctlf);
   for (;;) {
      if (fgets(line, lline, fctl) == NULL) break;
      for (i = 0, t = 0, pline = line; i < lline&&line[i]; i++)
         if (isalnum(line[i])) { t = 1; break; }
         else if (strchr(comment, line[i])) break;
         if (t == 0) continue;
         sscanf(line, "%s%*s%lf", opt, &t);
         if ((pline = strstr(line, "=")) == NULL)
            error2("err: option file. add space around the equal sign?");
         for (iopt = 0; iopt < nopt; iopt++) {
            if (strncmp(opt, optstr[iopt], 8) == 0) {
               if (noisy >= 9)
                  printf("\n%3d %15s | %-20s %6.2f", iopt + 1, optstr[iopt], opt, t);
               switch (iopt) {
               case (0): sscanf(pline + 1, "%s", com.seqf);    break;
               case (1): sscanf(pline + 1, "%s", com.outf);    break;
               case (2): sscanf(pline + 1, "%s", com.treef);   break;
               case (3): com.seqtype = (int)t;     break;
               case (4): noisy = (int)t;           break;
               case (5): com.cleandata = (char)t;  break;
               case (6):
                  sscanf(pline + 1, "%d%lf%lf%lf%lf", &com.runmode, com.hyperpar, com.hyperpar + 1, com.hyperpar + 2, com.hyperpar + 3);
                  break;
               case (7): com.method = (int)t;      break;
               case (8): com.clock = (int)t;       break;
               case (9):
                  sscanf(pline + 1, "%lf%lf", &com.TipDate, &com.TipDate_TimeUnit);
                  break;
               case (10): com.getSE = (int)t;       break;
               case (11): com.print = (int)t;       break;
               case (12): com.codonf = (int)t;      break;
               case (13): com.npi = (int)t;         break;
               case (14): com.verbose = (int)t;     break;
               case (15): com.model = (int)t;       break;
               case (16): com.hkyREV = (int)t;      break;
               case (17): com.aaDist = (int)t;      break;
               case (18):
                  sscanf(pline + 2, "%s", com.daafile);
                  if (com.seqtype == 2 && com.ndata > 1 && (com.clock == 5 || com.clock == 6)) {
                     ReadDaafiles(pline + 2);
                     break;
                  }
                  break;
               case (19): ReadNSsitesModels(line); break;
               case (20): com.nparK = (int)t;       break;
               case (21):
                  com.icode = (int)t;
                  if (com.seqtype == 1 && (com.clock == 5 || com.clock == 6)) {
                     ng = splitline(++pline, min2(ng, com.ndata), markgenes);
                     for (j = 0; j < min2(ng, com.ndata); j++)
                        if (!sscanf(pline + markgenes[j], "%d", &data.icode[j])) break;

                     for (j = 0; j < min2(ng, com.ndata); j++) printf("%4d", data.icode[j]);  FPN(F0);

                  }
                  break;
               case (22): com.Mgene = (int)t;       break;
               case (23): com.fix_kappa = (int)t;   break;
               case (24):
                  com.kappa = t;
                  if (com.seqtype == 1 && com.fix_kappa && (com.clock == 5 || com.clock == 6)) {
                     ng = splitline(++pline, min2(ng, com.ndata), markgenes);
                     for (j = 0; j < min2(ng, com.ndata); j++)
                        if (!sscanf(pline + markgenes[j], "%lf", &data.kappa[j])) break;

                     matout(F0, data.kappa, 1, min2(ng, com.ndata));
                  }
                  break;
               case (25): com.fix_omega = (int)t;   break;
               case (26):
                  com.omega = t;
                  if (com.seqtype == 1 && com.fix_omega && (com.clock == 5 || com.clock == 6)) {
                     ng = splitline(++pline, min2(ng, com.ndata), markgenes);
                     for (j = 0; j < min2(ng, com.ndata); j++)
                        if (!sscanf(pline + markgenes[j], "%lf", &data.omega[j])) break;

                     matout(F0, data.omega, 1, min2(ng, com.ndata));
                  }

                  break;
               case (27): com.fix_alpha = (int)t;   break;
               case (28):
                  com.alpha = t;
                  if (com.fix_alpha && t && (com.clock == 5 || com.clock == 6)) {
                     ng = splitline(++pline, min2(ng, com.ndata), markgenes);
                     for (j = 0; j < min2(ng, com.ndata); j++)
                        if (!sscanf(pline + markgenes[j], "%lf", &data.alpha[j])) break;

                     matout(F0, data.alpha, 1, min2(ng, com.ndata));
                  }
                  break;
               case (29): com.nalpha = (int)t;      break;
               case (30): com.ncatG = (int)t;       break;
               case (31): com.fix_rho = (int)t;     break;
               case (32): com.rho = t;              break;
               case (33): com.ndata = (int)t;       break;
               case (34): com.bootstrap = (int)t;   break;
               case (35): Small_Diff = t;           break;
               case (36): com.fix_blength = (int)t; break;
               }
               break;
            }
         }
         if (iopt == nopt)
         {
            printf("\noption %s in %s not recognised\n", opt, ctlf); exit(-1);
         }
   }
   fclose(fctl);

   if ((com.fix_kappa || (com.fix_alpha&&com.alpha)) && (com.clock == 5 || com.clock == 6))
      printf("Using parameters from the control file.");

   if (noisy) FPN(F0);
   if (com.seqtype == 1 || com.model == FromCodon0 || com.model == FromCodon)
      setmark_61_64();

   if (com.seqtype != AAseq && com.seqtype == CODON2AAseq && com.seqtype == CODONseq)
      error2("seqtype..");
   getnrate(1);

   if ((com.runmode == -2 || com.runmode == -3) && com.cleandata == 0) {
      com.cleandata = 1;
      if (noisy) puts("gaps are removed for pairwise comparison.");
   }
   if (com.method && (com.clock || com.rho)) {
      com.method = 0; puts("Iteration method reset: method = 0");
   }
   if (com.method && com.seqtype == 2 && (com.model == FromCodon0 || com.model == FromCodon)) {
      com.method = 0; puts("\awork on method = 1 for model = 6");
   }

   if (com.clock && com.fix_blength == 2)
      error2("can't fix branch lengths under clock model.");
   if (com.runmode == 3 && (com.clock)) error2("runmode+clock");
   if (com.aaDist <= 6 && (com.seqtype == CODONseq || com.model == FromCodon0 || com.model == FromCodon))
      strcpy(com.daafile, daafiles[abs(com.aaDist)]);

   if (com.fix_alpha && com.alpha == 0) {
      if (com.rho) puts("rho set to 0.");  com.fix_rho = 1; com.rho = 0;
   }

   if (!com.fix_alpha && com.alpha <= 0)
      error2("initial value alpha <= 0 for fix_alpha = 0");
   if (!com.fix_rho && com.rho == 0) { com.rho = 0.001;  puts("init rho reset"); }
   if (com.alpha || com.NSsites)
   {
      if (com.ncatG<2 || com.ncatG>NCATG) error2("ncatG");
   }
   else if (com.ncatG > 1) com.ncatG = 1;

   if (com.ndata <= 0) com.ndata = 1;
   if (com.bootstrap && com.ndata != 1) error2("ndata=1 for bootstrap.");

   return(0);
}


int testx(double x[], int np)
{
   /* This is used for LS branch length estimation by nls2, called only if(clock==0)
   */
   int i;
   double tb[] = { .4e-6, 99 };

   for (i = 0; i < com.ntime; i++)
      if (x[i]<tb[0] || x[i]>tb[1])
         return (-1);
   return (0);
}



int SetxBound(int np, double xb[][2])
{
   int i = -1, j, k, K = com.ncatG;
   double tb[] = { 4e-6,50 }, tb0 = 1e-8, rgeneb[] = { 0.01,99 }, rateb[] = { 1e-4,999 };
   double alphab[] = { 0.02,49 }, betab[] = { 0.005,99 };
   double rhob[] = { 0.01,0.99 }, pb[] = { .00001,.99999 };
   double wb[] = { 0.0001,999 };
   double w0b[] = { 0.0001, 0.5 }, w1b[] = { 0.5, 1.5 };  /* clade model D */

   SetxBoundTimes(xb);
   for (i = com.ntime; i < np; i++) for (j = 0; j < 2; j++) xb[i][j] = rateb[j];

   for (i = com.ntime; i < np; i++) { xb[i][0] = rateb[0]; xb[i][1] = rateb[1]; }
   for (i = 0; i < com.nrgene; i++) for (j = 0; j < 2; j++) xb[com.ntime + i][j] = rgeneb[j];
   for (i = 0; i < com.nrate; i++)  for (j = 0; j < 2; j++) xb[com.ntime + com.nrgene + i][j] = rateb[j];
   k = com.ntime + com.nrgene + com.nkappa;

   /* codon frequency parameters */
   k += j = (com.seqtype == CODONseq && com.codonf >= FMutSel0 ? 3 : 0);
   if (com.seqtype == CODONseq && com.npi > 3
      && (com.codonf == Fcodon || com.codonf == FMutSel0 || com.codonf == FMutSel)) {
      for (; j < com.npi; j++) {
         xb[k][0] = -29; xb[k++][1] = 29;
      }
   }

   /* omega parameters or those in the w distribution */
   if (com.NSsites) { /* p's before w's in xb[] */
      wb[0] *= 0.01;

      switch (com.NSsites) {
      case(NSnneutral):
         xb[k][0] = pb[0]; xb[k++][1] = pb[1];    /* p0 */
         xb[k][0] = wb[0]; xb[k++][1] = 1;        /* w0 < 1 */
         break;
      case(NSpselection): /* for p0, p1, w2 */
      case(NSM2aRel):     /* for p0, p1, w2 */
         for (j = 0; j < 2; j++) { xb[k][0] = -99; xb[k++][1] = 99; }  /* transformed p */
         xb[k][0] = wb[0]; xb[k++][1] = 1;          /* w0 < 1 */
         if (!com.fix_omega && (com.model == 0 || com.model == 2)) { /* w2 > 1 */
            xb[k][0] = (com.NSsites == NSpselection ? 1 : wb[0]);
            xb[k++][1] = wb[1];
         }
         else if (com.model == 3)                                  /* clade model C */
            for (j = 0; j < 1 + !com.fix_omega; j++) {
               xb[k][0] = wb[0];  xb[k++][1] = wb[1];
            }
         break;
      case(NSdiscrete):  /* pK[] & rK[] */
         if (com.model == 3) {                                      /* Clade model D */
            if (com.nparK) error2("model & NSsites & nparK");
            for (j = 0; j < 2; j++) { xb[k][0] = -99; xb[k++][1] = 99; }  /* p0 & p1 */
            xb[k][0] = w0b[0];  xb[k++][1] = w0b[1];                 /* w0 */
            xb[k][0] = w1b[0];  xb[k++][1] = w1b[1];                 /* w1 */
            for (j = 0; j < com.nbtype; j++) { xb[k][0] = wb[0];  xb[k++][1] = wb[1]; } /* w2 w3 ...*/
         }
         else if (com.model == 2) {  /* branch-site model B */
            K = 3;
            if (com.nparK == 0)
               for (j = 0; j < K - 1; j++) { xb[k][0] = -99; xb[k++][1] = 99; }
            for (j = 0; j < K; j++) { xb[k][0] = wb[0];  xb[k++][1] = wb[1]; }
            if (com.nparK)
               for (j = 0; j < K*(K - 1); j++) { xb[k][0] = -99; xb[k++][1] = 99; }
         }
         else {                 /* NSsites models M3 */
            for (j = 0; j < K - 1; j++) { xb[k][0] = -99; xb[k++][1] = 99; }
            for (j = 0; j < K; j++) { xb[k][0] = wb[0];  xb[k++][1] = wb[1]; }
         }

         if (com.seqtype == CODONseq && com.aaDist)
            for (j = 0; j < K; j++) { xb[k][0] = wb[0];  xb[k++][1] = wb[1]; }
         break;
      case(NSfreqs):     /* p0...pK */
         for (j = 0; j < K - 1; j++) { xb[k][0] = -99; xb[k++][1] = 99; }
         break;
      case(NSgamma):
         for (j = 0; j < 2; j++) { xb[k][0] = alphab[0]; xb[k++][1] = alphab[1]; } break;
      case(NS2gamma):    /* p0, alpha1,beta1,alpha2=beta2 */
         xb[k][0] = pb[0]; xb[k++][1] = pb[1];
         for (j = 0; j < 3; j++) { xb[k][0] = alphab[0]; xb[k++][1] = alphab[1]; }
         break;
      case(NSbeta):       /* p_beta,q_beta */
         for (j = 0; j < 2; j++) { xb[k][0] = betab[0]; xb[k++][1] = betab[1]; }
         break;
      case(NSbetaw):
         /* p0, p_beta, q_beta, w */
         xb[k][0] = pb[0]; xb[k++][1] = pb[1]; /* p0 */
         for (j = 0; j < 2; j++) { xb[k][0] = betab[0]; xb[k++][1] = betab[1]; }  /* p & q */
         if (!com.fix_omega) { xb[k][0] = 1;  xb[k++][1] = wb[1]; }
         break;
      case(NSbetagamma):  /* p0, p_beta, q_beta, alpha, beta */
         xb[k][0] = pb[0]; xb[k++][1] = pb[1]; /* p0 */
         for (j = 0; j < 4; j++) { xb[k][0] = betab[0]; xb[k++][1] = betab[1]; }  /* p&q, a&b */
         break;
      case(NSbeta1gamma):  /* p0, p_beta, q_beta, alpha, beta */
         xb[k][0] = pb[0]; xb[k++][1] = pb[1]; /* p0 */
         for (j = 0; j < 4; j++) { xb[k][0] = betab[0]; xb[k++][1] = betab[1]; }  /* p&q, a&b */
         break;
      case(NSbeta1normal):  /* p0, p_beta, q_beta, mu, s */
         xb[k][0] = pb[0]; xb[k++][1] = pb[1]; /* p0 */
         for (j = 0; j < 4; j++) { xb[k][0] = betab[0]; xb[k++][1] = betab[1]; }  /* p&q, mu&s */
         xb[k - 2][0] = 1;  xb[k - 2][1] = 9;  /* mu */
         break;
      case(NS02normal):   /* p0, p1, mu2, s1, s2 */
         for (j = 0; j < 2; j++) { xb[k][0] = pb[0];  xb[k++][1] = pb[1]; }  /* p0 & p1, */
         for (j = 0; j < 3; j++) { xb[k][0] = .0001; xb[k++][1] = 29; }  /* mu2,s1,s2 */
         break;
      case(NS3normal):    /* p0, p1, mu2, s0, s1, s2 */
         for (j = 0; j < 2; j++) { xb[k][0] = -49;  xb[k++][1] = 49; }  /* p0 & p1, tranformed */
         for (j = 0; j < 4; j++) { xb[k][0] = .0001; xb[k++][1] = 29; }  /* mu2,s0,s1,s2 */
         break;
      }
   }
   else if ((com.seqtype == CODONseq || com.model == FromCodon0 || com.model == FromCodon) && com.aaDist != AAClasses)
   {
      if (!com.fix_omega) { xb[k][0] = wb[0]; xb[k][1] = wb[1]; }
   }

   if (com.seqtype == CODONseq && com.model)
      for (j = 0; j < com.nOmega - com.fix_omega; j++)
      {
         xb[k + j][0] = wb[0]; xb[k + j][1] = wb[1];
      }

   if (com.aaDist < 0 && (com.seqtype == 1 || com.model == FromCodon0 || com.model == FromCodon)) {
      /* linear relationship between d_ij and w_ij */
      if (com.nrate != !com.fix_kappa + 1 + (com.seqtype == 1)) error2("in Setxbound");
      xb[com.ntime + com.nrgene + !com.fix_kappa][1] = 1; /* 0<b<1 */
   }

   k = com.ntime + com.nrgene + com.nrate;
   for (i = 0; i < com.nalpha; i++, k++)  for (j = 0; j < 2; j++) xb[k][j] = alphab[j];
   if (!com.fix_rho)   for (j = 0; j < 2; j++) xb[np - 1][j] = rhob[j];

   if (noisy >= 3 && np < 100) {
      printf("\nBounds (np=%d):\n", np);
      for (i = 0; i < np; i++) printf(" %10.6f", xb[i][0]);  FPN(F0);
      for (i = 0; i < np; i++) printf(" %10.6f", xb[i][1]);  FPN(F0);
   }

   return(0);
}

void getpcodonClass(double x[], double pcodonClass[])
{
   /* This uses pcodon0[], paa0[], and x[] to calculate pcodonclass[] and
      com.pi[] for the fitness models.
      pcodon0[] has the codon frequencies observed (codonFreq=3) or expected
      (codonFreq=2 or 1 or 0) rootally.  Under the fitness models, the expected
      codon frequencies pcodonClass[] differs among site classes and from the
      rootal pi[] (pcodon0[]).
      This is called by SetParameters().
   */
   int i, iclass, iaa, k, nclass = (com.NSsites == 0 ? 1 : com.ncatG);
   double paaClass[20], *w, fit;

   if (com.seqtype != 1 || com.aaDist < FIT1) error2("getpcodonClass");
   k = com.ntime + com.nrgene + !com.fix_kappa + nclass - 1;
   FOR(iclass, nclass) {
      w = x + k + iclass*(4 + (com.aaDist == FIT2));
      FOR(iaa, 20) {
         fit = -w[0] * square(AAchem[0][iaa] - w[1])
            - w[2] * square(AAchem[1][iaa] - w[3]);
         paaClass[iaa] = exp(2 * fit);
      }
      abyx(1 / sum(paaClass, 20), paaClass, 20);
      FOR(i, com.ncode) {
         iaa = GeneticCode[com.icode][FROM61[i]];
         pcodonClass[iclass * 64 + i] = pcodon0[i] / paa0[iaa] * paaClass[iaa];
      }

      if (fabs(1 - sum(pcodonClass + iclass * 64, com.ncode)) > 1e-5) error2("pcodon!=1");
      /*
      fprintf(frst,"\nSite class %d: ",iclass+1);
      matout (frst,paaClass,2, 10);
      matout (frst,pcodonClass+iclass*64,16,4);
      */
   }
   if (nclass == 1) FOR(i, com.ncode) com.pi[i] = pcodonClass[i];
}



int GetInitialsCodon(double x[])
{
   /* This sets the initials and count com.np for codon models.
   */
   int k = com.ntime + com.nrgene, i, j, K = com.ncatG, nsyncodon[20];
   double mr = 0;

   getnrate(0);
   if (com.nrate) { /* either kappa, omega, or both for each gene */
      if (com.Mgene <= 2) {
         if (com.hkyREV) {
            x[k++] = .5 + rndu();
            for (i = 0; i < 4; i++) x[k++] = .1 + rndu();
         }
         else if (!com.fix_kappa)
            x[k++] = com.kappa;
         if (com.codonf == FMutSel0 || com.codonf == FMutSel) {
            for (i = 0; i < 3; i++)   /* pi_TCA */
               x[k++] = com.pf3x4[i] / (com.pf3x4[3] + .02*rndu());

            if (com.npi > 3 && com.codonf == FMutSel0) {
               for (i = 0; i < 20; i++) nsyncodon[i] = 0;
               for (i = 0; i < com.ncode; i++)
                  nsyncodon[GeneticCode[com.icode][FROM61[i]]] ++;
               for (i = 0; i < 20 - 1; i++)   /* amino acid fitness, ignoring nsyncodon */
                  x[k++] = log((com.piAA[i] / nsyncodon[i] + .001) / (com.piAA[19] / nsyncodon[19] + .002*rndu()));
            }
            else if (com.npi > 3 && com.codonf == FMutSel) {
               for (i = 0; i < com.ncode - 1; i++)   /* codon fitness */
                  x[k++] = log((com.pi[i] + .001) / (com.pi[com.ncode - 1] + .002*rndu()));
            }
         }
         else if (com.npi) {
            if (com.codonf == Fcodon)
               for (i = 0; i < com.ncode - 1; i++)   /* codon fitness */
                  x[k++] = log((com.pi[i] + .001) / (com.pi[com.ncode - 1] + .002*rndu()));
            else if (com.codonf == F1x4 || com.codonf == F1x4MG)
               for (i = 0; i < 3; i++)   /* pi_TCA */
                  x[k++] = com.pf3x4[i] / (com.pf3x4[3] + .02*rndu());
            else if (com.codonf == F3x4 || com.codonf == F3x4MG)
               for (j = 0; j < 3; j++)
                  for (i = 0; i < 3; i++)   /* pi_TCA */
                     x[k++] = com.pf3x4[j * 4 + i] / (com.pf3x4[j * 4 + 3] + .02*rndu());
         }
         if (com.NSsites == 0 && (com.model == 0 || com.model == FromCodon0)) {
            if (!com.aaDist)  {
               if (!com.fix_omega)    x[k++] = com.omega;
            }
            else if (com.aaDist == AAClasses)
               for (i = 0; i < com.nOmegaType; i++)
                  x[k++] = 0.11 + 0.1*rndu();
            else
            {
               x[k++] = 0.11 + 0.1*rndu(); x[k++] = 0.22 + 0.1*rndu();
            }
         }
      }
      else { /* com.Mgene==3,4 */
         if (com.Mgene >= 3) {
            com.nrate *= com.ngene;
            if (com.fix_omega) com.nrate--;
         }
         for (i = 0; i < com.ngene; i++) {
            if (com.hkyREV)
               error2("hkyREV for ngene>1.  Fix me.");
            if (!com.fix_kappa && !com.fix_omega)
            {
               x[k++] = com.kappa;  x[k++] = com.omega;
            }
            else if (com.fix_kappa)
               x[k++] = com.omega;
            else if (com.fix_omega) {
               x[k++] = com.kappa;
               if (i != com.ngene - 1) x[k++] = com.omega;
            }
         }
      }
   }

   if (com.model>=NSbranchB && com.model <= NSbranch3) {  /* branch models */
      if (com.model == NSbranchB) {
         com.nbtype = tree.nbranch;
         for (i = 0; i < tree.nbranch; i++)
            nodes[(int)tree.branches[i][1]].label = i;
      }
      if (com.NSsites == 0) {
         com.nOmega = com.nbtype;
         if (com.aaDist == AAClasses)
            com.nrate += com.nOmegaType*com.nbtype;
         else if (com.model == NSbranchB || com.model == NSbranch2)
            com.nrate += (com.model == NSbranchB ? tree.nbranch : com.nOmega - 1 + !com.fix_omega);
         else if (com.aaDist == 0)
            com.nrate += !com.fix_omega + com.nbtype - 1;
         k = com.ntime + com.nrgene;
         for (i = 0; i < com.nrate; i++)
            x[k++] = com.omega * (0.8 + 0.4*rndu());
      }
   }


   if (com.NSsites == 0 && com.nrate == 0)
      eigenQcodon(1, -1, NULL, NULL, NULL, Root, U, V, &mr, (com.nkappa > 1 ? x + com.ntime + com.nrgene : &com.kappa), com.omega, PMat);


   /* branch-site and clade models
      com.nOmega=2 different w's at a site (three w's in the model: w0,w1,w2) */
   if (com.model>=NSbranch2 && com.model <= NSbranch3 && com.NSsites) {
      if (com.model == NSbranch2) { /* branch-site models A & B */
         com.ncatG = 4;  K = 3;
         if (com.NSsites == NSdiscrete)
            com.nrate = com.nkappa + com.npi + 2 + !com.fix_omega + com.nbtype - 1 - 1; /* add w0 and w1 */
         else
            com.nrate = com.nkappa + com.npi + 1 + !com.fix_omega + com.nbtype - 1 - 1;
      }

      /* add p0 and p1.  check that this works for NSbranch2 */
      k = com.ntime + com.nrgene + com.nkappa + com.npi;

      if (com.model <= NSbranch2) { /* branch-site models A & B */
         /* p0 and p1:  x[0,1]=1,0, for p[]=0.6 0.2 */
         x[k++] = 1 + 0.5*rndu();
         if (K == 3) x[k++] = 0.2*rndu();
         if (com.NSsites == 2)        /* w0<1, w1=1 (if present) */
            x[k++] = 0.2 + 0.1*rndu();
         else if (com.NSsites == NSdiscrete) {   /* w0 and w1 for model B */
            x[k++] = 0.2*rndu();
            if (K == 3) x[k++] = 0.4 + .8*rndu();
         }
         if (!com.fix_omega)
            x[k++] = com.omega + 1 + rndu();  /* w2 */
      }
      else { /* NSbranch3: clade models C and D */
         x[k++] = 1 + rndu();   x[k++] = .5 + rndu();   /* p0 and p1, transformed. */
         if (com.NSsites == NSpselection)        /* w0<1, w1=1 */
            x[k++] = 0.2 + 0.2*rndu();
         else if (com.NSsites == NSdiscrete) {   /* w0 and w1 */
            x[k++] = 0.2 + 0.2*rndu();
            x[k++] = 0.5 + .5*rndu();
         }
         for (i = 0; i < com.nbtype - 1; i++)    /* additional w's */
            x[k++] = com.omega*(1 + 0.5*rndu());
         if (!com.fix_omega)
            x[k++] = com.omega*(1 + 0.5*rndu());
      }
   }
   else if (com.NSsites) {        /* w's are counted in com.nrate */
      switch (com.NSsites) {
      case(NSnneutral):
         x[k++] = 0.5 + 0.4*rndu();   /* p0 for w0<1 */
         x[k++] = 0.1 + 0.5*rndu();   /* w0<1 */
         break;
      case(NSpselection): /* for p0, p1.  w is counted in nrate.  */
      case(NSM2aRel):
         x[k++] = 0.8 + rndu(); x[k++] = .1 + .5*rndu();   /* p0, p1 */
         x[k++] = 0.1 + 0.4*rndu();                   /* w0<1 */
         if (!com.fix_omega) {
            x[k++] = com.omega*(1 + 0.2*rndu());                     /* w2 */
            if (com.omega < 1 && com.NSsites == NSpselection) {
               puts("\ninitial w for M2:NSpselection reset.");
               x[k - 1] = 2 + rndu();
            }
         }
         break;
      case(NSdiscrete):
         if (com.aaDist) {
            for (i = 0; i < com.ncatG - 1; i++) x[k++] = 0.;
            if (com.aaDist <= 6)
               for (i = 0; i < com.ncatG; i++) { x[k++] = 1.1; x[k++] = 1.2; }
            for (i = 0; i < com.ncatG; i++) /* ap,p*,av,v*, and b for each site class */
               FOR(j, 4 + (com.aaDist == FIT2)) x[k++] = rndu();
         }
         else if (com.nparK) { /* K*(K-1) paras in HMM of dN/dS over sites */
            zero(x + k, com.ncatG*(com.ncatG - 1));
            k += com.ncatG*(com.ncatG - 1);
         }
         else {   /* p0...pK.  Note that w's are counted in nrate  */
            for (i = 0; i < com.ncatG - 1; i++) x[k++] = rndu();
            for (i = 0; i < com.ncatG; i++)
               x[k++] = com.omega * (.5 + i*2. / com.ncatG*(0.8 + 0.4*rndu()));
         }
         break;
      case(NSfreqs):    /* p0...pK.  w's are fixed  */
         for (i = 0; i < com.ncatG - 1; i++) x[k++] = (com.ncatG - j) / 2.;
         break;
      case(NSgamma):  x[k++] = 1.1; x[k++] = 1.1; break;
      case(NS2gamma):    /* p0, alpha1,beta1,alpha2=beta2 */
         x[k++] = 0.5; FOR(j, 3) x[k++] = 2 * rndu() + j*0.1; break;
      case(NSbeta):       /* p_beta,q_beta */
         x[k++] = .2 + rndu(); x[k++] = 1 + rndu(); break;
      case(NSbetaw):
         /* p0, p_beta, q_beta.  w is counted in nrate. */
         x[k++] = .9; x[k++] = .2 + rndu(); x[k++] = 1 + rndu();
         if (!com.fix_omega) {
            x[k++] = com.omega;
            if (com.omega < 1) {
               puts("\ninitial w for M8:NSbetaw>1 reset.");
               x[k - 1] = 2 + rndu();
            }
         }
         break;
      case(NSbetagamma):  /* p0, p_beta, q_beta, alpha, beta */
         x[k++] = .9; x[k++] = .4; x[k++] = 1.2; x[k++] = 1.1; x[k++] = 1.1;
         break;
      case(NSbeta1gamma):  /* p0, p_beta, q_beta, alpha, beta */
         x[k++] = .9; x[k++] = .4; x[k++] = 1.2; x[k++] = .1; x[k++] = 1.1;
         break;
      case(NSbeta1normal):  /* p0, p_beta, q_beta, alpha, beta */
         x[k++] = .95; x[k++] = .4; x[k++] = 1.2; x[k++] = 1.1; x[k++] = 1.1;
         break;
      case(NS02normal):    /* p0, p1, mu2, s1, s2 */
         x[k++] = .8; x[k++] = 0.3;   /* p0 & p1, not transformed */
         x[k++] = .2; /* mu2 */
         x[k++] = 5; x[k++] = 1.1;  /* s1,s2 */
         break;
      case(NS3normal):    /* p0, p1, mu2, s0, s1, s2 */
         x[k++] = .77; x[k++] = 0.22;   /* p0 & p1, transformed */
         x[k++] = .2; /* mu2 */
         x[k++] = 0.5; x[k++] = 5; x[k++] = 1.1;  /* s0,s1,s2 */
         break;
      }
   }     /* if(com.NSsites) */

   com.np = k;
   return(0);
}


int GetInitials(double x[], int* fromfile)
{
   /* This caculates the number of parameters (com.np) and get initial values.
      This routine is too messy.  Perhaps try to restruct the code and make
      two sections for amino acids and codons?
      com.nrate is initialised in getoptions().
   */
   int i, j, k = 0, naa = 20;
   int K = (com.model == 2 && com.NSsites ? com.ncatG - 1 : com.ncatG);
   size_t sconP_new = (size_t)(tree.nnode - com.ns)*com.ncode*com.npatt * sizeof(double);
   double t;

   NFunCall = NPMatUVRoot = NEigenQ = 0;
   if (com.clock == ClockCombined && com.ngene <= 1)
      error2("Combined clock model requires mutliple genes.");
   GetInitialsTimes(x);

   com.plfun = (com.alpha == 0 ? lfun : (com.rho == 0 ? lfundG : lfunAdG));
   if (com.NSsites) com.plfun = lfundG;
   if (com.nparK) com.plfun = lfunAdG;

   if (com.plfun == lfun) com.conPSiteClass = 0;
   if (com.method && com.fix_blength != 2 && com.plfun == lfundG) {
      com.conPSiteClass = 1;
      sconP_new *= com.ncatG;
   }
   if (com.sconP < sconP_new) {
      com.sconP = sconP_new;
      printf("\n%9zu bytes for conP, adjusted\n", com.sconP);
      if ((com.conP = (double*)realloc(com.conP, com.sconP)) == NULL)
         error2("oom conP");
   }

   InitializeNodeScale();

   if ((com.aaDist && com.aaDist < 10 && com.aaDist != AAClasses &&
      (com.seqtype == CODONseq || com.model == FromCodon0 || com.model == FromCodon)) ||
      (com.seqtype == AAseq &&
      (com.model == Empirical || com.model == Empirical_F || com.model >= REVaa_0))) {
      GetDaa(NULL, com.daa);
   }

   com.nrgene = (!com.fix_rgene)*(com.ngene - 1);
   for (j = 0; j < com.nrgene; j++) x[com.ntime + j] = 1;


   if (com.seqtype == CODONseq)
      GetInitialsCodon(x);
   else {
      com.np = com.ntime + com.nrgene + com.nrate;

      k = com.ntime + com.nrgene;
      if (com.aaDist == AAClasses) {
         if (!com.fix_kappa) x[k++] = com.kappa;
         for (i = 0; i < com.nrate - !com.fix_kappa; i++)
            x[k++] = com.omega;
         if (com.nOmegaType > 65)
            puts("\a\nget better initial values for AAclasses?");
      }
      else {
         if (com.seqtype == AAseq) {   /* AAseq */
            if (com.nrate == 0)
               eigenQaa(NULL, Root, U, V, &t); /* once for all */
            if (com.model == REVaa_0) {
               for (i = 0; i < naa; i++) for (j = 0; j < i; j++)
                  if (AA1STEP[i*(i - 1) / 2 + j] && i*naa + j != ijAAref)
                     x[k++] = com.daa[i*naa + j];
            }
            else if (com.model == REVaa) {
               for (i = 1; i < naa; i++)  for (j = 0; j < i; j++)
                  if (i*naa + j != ijAAref) x[k++] = com.daa[i*naa + j];
            }
            else if (com.model == FromCodon0 || com.model == FromCodon) {
               for (j = 0; j < com.nkappa; j++)              x[k++] = com.kappa;
               for (j = 0; j < com.nrate - com.nkappa; j++)  x[k++] = com.omega;
            }
         }
      }
   }

   for (i = 0; i < com.nalpha; i++) x[com.np++] = com.alpha;

   if (!com.fix_rho) x[com.np++] = com.rho;
   if (com.rho)
      AutodGamma(com.MK, com.freqK, com.rK, &t, com.alpha, com.rho, com.ncatG);
   else if (com.alpha && com.fix_alpha && !com.NSsites)
      DiscreteGamma(com.freqK, com.rK, com.alpha, com.alpha, com.ncatG, DGammaUseMedian);

   if (com.fix_blength == -1)
      for (i = 0; i < com.np; i++)  x[i] = (i < com.ntime ? .1 + 0.5*rndu() : 0.5 + rndu());

   *fromfile = 0;
   if (finitials) {
      readx(x, fromfile);
      if (com.runmode > 0 && fromfile && com.NSsites)  LASTROUND = 1;
   }

   return (0);
}



int SetPGene(int igene, int _pi, int _UVRoot, int _alpha, double x[])
{
   /* xcom[] does not contain time parameters
      Note that com.piG[][] have been homogeneized if (com.Mgene==3)
      Note calculation of nr1 for (com.Mgene>=3 && com.fix_omega), as only the
      w for the last partition is fixed.
   */
   int nr1 = (com.nrate + 1) / com.ngene, k = com.nrgene + (com.Mgene >= 3)*igene*nr1;
   double *xcom = x + com.ntime, mr = 0;

   if (_pi) {
      xtoy(com.piG[igene], com.pi, com.ncode);
#if(defined(CODEML))
      if (com.codonf == F1x4MG || com.codonf == F3x4MG)
         com.pf3x4 = com.f3x4[igene];
#endif
   }
   if (_UVRoot) {
      if (com.seqtype == CODONseq) {
         if (!com.fix_kappa) com.kappa = xcom[k++];
         if (!com.fix_omega) com.omega = xcom[k++];
         else
            com.omega = (com.Mgene > 2 && igene < com.ngene - 1 ? xcom[k++] : com.omega_fix);
         if (!com.NSsites)
            eigenQcodon(1, -1, NULL, NULL, NULL, Root, U, V, &mr,
            (com.hkyREV || com.codonf == FMutSel ? &xcom[com.nrgene] : &com.kappa), com.omega, PMat);
      }
      else
         eigenQaa(NULL, Root, U, V, xcom + k);
   }
   if (_alpha) {
      com.alpha = xcom[com.nrgene + com.nrate + igene];
      DiscreteGamma(com.freqK, com.rK, com.alpha, com.alpha, com.ncatG, DGammaUseMedian);
   }
   return (0);
}


int SetParametersNSsites(double x[])
{
   /* for NSsites and NSbranchsite models including HMM, NSclade models
      p's are before w's in x[].
      w[2][3] holds omegas; w[i][j] for fore (i=0) or back (i=1) branches
      in site class j.

      A & B: branch-site models:  (model=2, NSsites=2 or 3)

                          iclass
                       0    1    2    3
            back      w0   w1   w0   w1
            fore      w0   w1   w2   w2

      C & D: clade-site models:   (model=3, NSsites=2 or 3)
      (D: nbtype = 2)

                          iclass
                       0    1    2
            b0        w0   w1   w2
            b1        w0   w1   w3
            b2        w0   w1   w4
            ......
   */
   int k0 = com.ntime + com.nrgene + com.nkappa + com.npi, k = k0;
   int K = com.ncatG, i, j, off;
   double w[NBTYPE][3], t, S, dS, dN, spaceP2PI[NCATG*(NCATG + 1)], small = 1e-4;
   double mr, f;
   double p0 = 1, c, e, eT, dwy, y, z, a, b, T, C, lnGa, ww, sign;
   const double *xI = NULL, *wI = NULL;  /* truncated NSsites models */

   if (com.NSsites == 0) error2("SetParametersNSsites : strange.");

   switch (com.NSsites) {
   case(NSnneutral):
      com.freqK[0] = x[k++];
      com.freqK[1] = 1 - com.freqK[0];
      com.rK[0] = x[k++];
      com.rK[1] = 1;
      break;
   case(NSpselection):
   case(NSM2aRel):
   case(NSdiscrete):
      if (com.model == NSbranch2)   /* branch-site A&B (Y&N2002) */
         K = com.ncatG - 1;
      if (com.nparK) {      /* HMM models, setting up p[] & w[] */
         for (j = 0; j < K; j++)   /* w's for site classes */
            com.rK[j] = x[k++];
         for (i = 0; i < K; i++, k += K - 1) {
            if (!LASTROUND) f_and_x(x + k, com.MK + i*K, K, 0, 0);   /* x->f */
            else            xtoy(x + k, com.MK + i*K, K - 1);
            com.MK[i*K + K - 1] = 1 - sum(com.MK + i*K, K - 1);
         }
         PtoPi(com.MK, com.freqK, K, spaceP2PI);
         break;
      }

      /* *** Note: Falling through.
         This sets up p[] for NSpselection, NSdiscrete, NSfreqs
      */
   case(NSfreqs):
      if (!LASTROUND) {
         f_and_x(x + k, com.freqK, K, 0, 1);   /* x->f */
         k += K - 1;
      }
      else {
         for (j = 0, com.freqK[K - 1] = 1; j < K - 1; j++)
            com.freqK[K - 1] -= (com.freqK[j] = x[k++]);
         if (com.freqK[K - 1] < -small || com.freqK[K - 1]>1 + small) {
            matout(F0, com.freqK, 1, K);
            error2("freqK[]");
         }
      }

      /* setting up w[] */
      if (com.NSsites == NSfreqs) {
         if (com.ncatG != 5) error2("NSfreqs, ncatG?");
         com.rK[0] = 0;
         com.rK[1] = 1. / 3;
         com.rK[2] = 2. / 3;
         com.rK[3] = 1;
         com.rK[4] = 3;
      }
      else if (com.NSsites == NSpselection || com.NSsites == NSM2aRel) {
         com.rK[0] = x[k++];
         com.rK[1] = 1;
         com.rK[2] = (com.fix_omega && com.model <= 2 ? com.omega_fix : x[k++]);
      }
      else if (com.NSsites == NSdiscrete && com.aaDist == 0) {
         for (j = 0; j < K; j++)
            com.rK[j] = x[k++];
      }
      if (com.model) {  /* branch-site and clade models */
         if (com.model == NSbranch2) { /* branch-site models */
            w[0][0] = w[1][0] = com.rK[0];  /* site class 0 */
            w[0][1] = w[1][1] = com.rK[1];  /* site class 1 */
            w[0][2] = -1;
            w[1][2] = com.rK[2];
         }
         else {                       /* clade models */
            k--;
            for (i = 0; i < com.nbtype; i++) {
               for (j = 0; j < K - 1; j++)
                  w[i][j] = com.rK[j];
               w[i][K - 1] = (i == com.nbtype - 1 && com.fix_omega ? com.omega_fix : x[k++]);
            }
         }
      }
      break;

   case(NSgamma):
   case(NS2gamma):
   case(NSbeta):
   case(NSbetaw):
   case(NSbetagamma):
   case(NSbeta1gamma):
   case(NSbeta1normal):
   case(NS02normal):
   case(NS3normal):
      DiscreteNSsites(x + k);
      break;
   }

   /* For NSsites models, calculates Qfactor_NS, to be used in eigenQcodon().
      For branch-site and clade models, calculate Qfactor_NS[] and also
      UVRoot for different omega's.
   */
   k = k0;
   if (com.model == 0) {  /* NSsites models */
      if (com.aaDist == 0) {
         for (j = 0, mr = 0; j < com.ncatG; j++)
            mr += com.freqK[j] * com.rK[j];
         Qfactor_NS = -1;
         eigenQcodon(0, -1, &S, &dS, &dN, NULL, NULL, NULL, &Qfactor_NS, com.pkappa, mr, PMat);
      }
      else {
         for (j = 0, Qfactor_NS = 0; j < com.ncatG; j++) {
            if (com.aaDist < 10)
               com.pomega = x + k + com.ncatG - 1 + 2 * j;
            else if (com.aaDist >= FIT1) {
               com.pomega = x + k + com.ncatG - 1 + j*(4 + (com.aaDist == FIT2));
               xtoy(pcodonClass + j * 64, com.pi, com.ncode);
            }
            mr = -1;
            eigenQcodon(0, -1, &S, &dS, &dN, NULL, NULL, NULL, &mr, com.pkappa, com.rK[j], PMat);
            Qfactor_NS += com.freqK[j] * mr;
         }
      }
      Qfactor_NS = 1 / Qfactor_NS;
      if (NFunCall == 1) printf("Qfactor_NS = %.6f\n", Qfactor_NS);
   }
   else if (com.model == NSbranch2) { /* branch&site models */
      t = com.freqK[0] + com.freqK[1];
      if (t < 1e-100)
         error2("p0 + p1 too small for branch&site model?");
      com.freqK[2] = (1 - t)*com.freqK[0] / t;
      com.freqK[3] = (1 - t)*com.freqK[1] / t;
      /* calculates scale factors: background branches has two site classes
         while foreground branches has 3 site classes */

      for (i = 0; i < 2; i++) {  /* i=0 back (2 site classes); i=1 fore (3 classes) */
         for (j = 0, mr = 0; j < (i == 0 ? 2 : 3); j++) {
            com.omega = w[i][j];
            f = com.freqK[j];
            if (i == 0)       f = com.freqK[j] / t;
            else if (j == 2)  f = 1 - t;
            if (NFunCall == 1) printf("branch=%d  freq=%.6f w%d = %.6f\n", i, f, j, com.omega);
            mr += f*com.omega;
         }
         Qfactor_NS_branch[i] = -1;
         eigenQcodon(0, -1, &S, &dS, &dN, NULL, NULL, NULL, &Qfactor_NS_branch[i], com.pkappa, mr, PMat);
         Qfactor_NS_branch[i] = 1 / Qfactor_NS_branch[i];
         if (NFunCall == 1) printf("\t\t\tQfactor for branch %d = %.6f\n", i, Qfactor_NS_branch[i]);
      }
      /* calculates 3 sets of U&V&Root vectors (w0,w1,w2), for GetPMatBranch().
         No eigenQcodon() calls are needed in ConditionalPNode() or minbranches().
      */
      for (i = 0; i < 3; i++) {  /* (w0,w1,w2) */
         if (NFunCall == 1) printf("w[%d] = %.6f\n", i, w[1][i]);
         mr = 1;
         eigenQcodon(1, -1, NULL, NULL, NULL, _Root[i], _UU[i], _VV[i], &mr, com.pkappa, w[1][i], PMat);
      }
   }
   else { /* NSbranch3: Clade models C and D */
      /* calculates Qfactor_NS_branch[nbtype]: each branch has K=com.ncatG site classes */
      for (i = 0; i < com.nbtype; i++) {
         for (j = 0, mr = 0; j < K; j++)
            mr += com.freqK[j] * w[i][j];
         Qfactor_NS_branch[i] = -1;
         eigenQcodon(0, -1, NULL, NULL, NULL, NULL, NULL, NULL, &Qfactor_NS_branch[i], com.pkappa, mr, PMat);
         Qfactor_NS_branch[i] = 1 / Qfactor_NS_branch[i];

         if (NFunCall == 1) printf("\t\t\tQfactor for branch=%d  = %.6f\n", i, Qfactor_NS_branch[i]);
      }
      /* calculates K-1+nbtype sets of U&V&Root vectors (w0,w1,w2, w3,...), for GetPMatBranch().
      */
      for (i = 0; i < K - 1 + com.nbtype; i++) {
         mr = 1;
         com.omega = (i < K - 1 ? w[0][i] : w[i - K + 1][K - 1]);
         eigenQcodon(1, -1, NULL, NULL, NULL, _Root[i], _UU[i], _VV[i], &mr, com.pkappa, com.omega, PMat);
      }
   }
   return(0);
}


int Set_UVR_BranchSite(int iclass, int branchlabel)
{
   /* There are 3 different w's in the branch-site models A & B, and nbtype+2
      different w's in the clade models C & B, so there are the same number of
      sets of U&V&Root.  This routine points out the right set.
   */
   int iUVR = 0;

   if (com.model == 0 || com.NSsites == 0) error2("should not be here.");

   if (com.model <= NSbranch2) { /* branch-site models A & B */
      if (branchlabel == 0) iUVR = iclass % 2;                  /* back, w0 w1 */
      else               iUVR = (iclass <= 1 ? iclass : 2);  /* fore, w0 w1 w2 */
   }
   else {                   /* clade models C & D */
      if (iclass < com.ncatG - 1) iUVR = iclass;
      else                   iUVR = com.ncatG - 1 + branchlabel;
   }
   U = _UU[iUVR];
   V = _VV[iUVR];
   Root = _Root[iUVR];

   return (iUVR);
}


int GetCodonFreqs(void)
{
   /* This is called by SetParameters() and calculates the expected base or codon frequencies
      (com.pf3x4[] & com.pi[]) using the parameters under the model com.codonf.
      This is used for models in which codon frequency parameters are estimated from
      the data by ML.  Modified from GetCodonFreqs2().
      com.pi[] is modified.
      The routine does not work if com.ngene>1.
   */
   int n = com.ncode, i, j, k, ic, iaa, b[3];
   double *ppi = com.ppi, mutbias[20], y;

   if (com.codonf == Fcodon) {
      for (i = 0; i < n; i++)
         com.pi[i] = (i == n - 1 ? 1 : exp(com.ppi[i]));
      abyx(1. / sum(com.pi, n), com.pi, n);
      return(0);
   }

   for (j = 0; j < 3; j++) {
      xtoy(ppi, com.pf3x4 + j * 4, 3);
      com.pf3x4[j * 4 + 3] = 1;
      abyx(1. / sum(com.pf3x4 + j * 4, 4), com.pf3x4 + j * 4, 4);
      if (com.codonf == F3x4 || com.codonf == F3x4MG)
         ppi += 3;
   }
   if (com.codonf == FMutSel && com.npi == 3)  return(0);

   if ((com.codonf >= F1x4 && com.codonf <= F3x4MG) || com.npi > 3) {
      for (i = 0; i < n; i++) {
         ic = FROM61[i];  b[0] = ic / 16; b[1] = (ic / 4) % 4; b[2] = ic % 4;
         com.pi[i] = com.pf3x4[b[0]] * com.pf3x4[4 + b[1]] * com.pf3x4[8 + b[2]];
      }
   }

   if (com.codonf == FMutSel && com.npi > 3) {
      for (i = 0; i < n - 1; i++)  /* last codon has fitness 0 */
         com.pi[i] *= exp(com.ppi[3 + i]);
   }
   else if (com.codonf == FMutSel0 && com.npi > 3) {
      for (i = 0; i < n; i++) {  /* last amino acid has fitness 0 */
         iaa = GeneticCode[com.icode][FROM61[i]];
         if (iaa < 19) com.pi[i] *= exp(com.ppi[3 + iaa]);
      }
      for (i = 0, zero(com.piAA, 20); i < n; i++)
         com.piAA[GeneticCode[com.icode][FROM61[i]]] += com.pi[i];
      abyx(1. / sum(com.piAA, 20), com.piAA, 20);
   }
   else if (com.codonf == FMutSel0 && com.npi == 3) {
      for (i = 0, zero(mutbias, 20); i < n; i++) {
         ic = FROM61[i];
         iaa = GeneticCode[com.icode][ic];
         b[0] = ic / 16; b[1] = (ic / 4) % 4; b[2] = ic % 4;
         mutbias[iaa] += com.pf3x4[b[0]] * com.pf3x4[b[1]] * com.pf3x4[b[2]];
      }
      for (i = 0; i < n; i++) {
         ic = FROM61[i];  iaa = GeneticCode[com.icode][ic];
         b[0] = ic / 16; b[1] = (ic / 4) % 4; b[2] = ic % 4;
         y = com.pf3x4[b[0]] * com.pf3x4[b[1]] * com.pf3x4[b[2]];
         com.pi[i] = y / mutbias[iaa] * com.piAA[iaa];
      }
      y = sum(com.pi, n);
   }
   abyx(1. / sum(com.pi, n), com.pi, n);
   return (0);
}


int SetParameters(double x[])
{
   /* Set com. variables and initialize U, V, Root etc. before each calculation
      of the likelihood function.
      Is it a good idea to restruct this and/or Getinitials into two parts,
      one for aa's and another for codons?
      When (com.NSsites==NS02normal || NS3normal), p's are before w's in x[];
      see CDFdN_dS().
   */
   int i, j, k, ik = 0, nUVR = NBTYPE + 2;
   double t, w0 = -1, mr = 0;

   if (com.clock >= 5) return(0);
   if (com.fix_blength != 2) SetBranch(x);
   if (com.np <= com.ntime) return(0);

   if (com.seqtype == 1 || com.model == FromCodon0 || com.model == FromCodon || com.aaDist == AAClasses) {
      k = com.ntime + com.nrgene;
      if (com.hkyREV == 0) {
         if (com.fix_kappa == 1) { com.pkappa[0] = com.kappa; ik = 1; }
         else                   com.kappa = x[k];
      }
      for (i = 0; i < com.nkappa; i++)
         com.pkappa[ik++] = x[k++];

      if (com.npi) {
         com.ppi = x + com.ntime + com.nrgene + com.nkappa;
         GetCodonFreqs();
      }
      com.pomega = x + com.ntime + com.nrgene + com.nkappa + com.npi;
   }
   for (j = 0; j < com.nrgene; j++)
      com.rgene[j + 1] = x[com.ntime + j];
   if (com.clock && AbsoluteRate) com.rgene[0] = x[0]; /* so that rgene are abs rates */

   if (com.seqtype == 1 && com.aaDist >= FIT1)
      getpcodonClass(x, pcodonClass);

   k = com.ntime + com.nrgene + com.nkappa + com.npi;

   if (com.nrate) {
      if ((com.model==0 || com.model == FromCodon0) && !com.aaDist && !com.fix_omega && !com.NSsites)
         com.omega = x[k];
      if (com.seqtype == AAseq)
         eigenQaa(NULL, Root, U, V, x + com.ntime + com.nrgene);
      else if ((com.model == 0 || com.model == FromCodon0) && com.NSsites == 0 && com.Mgene <= 1)
         eigenQcodon(1, -1, NULL, NULL, NULL, Root, U, V, &mr, com.pkappa, com.omega, PMat);
      else if ((com.model == NSbranchB || com.model == NSbranch2)
         && com.NSsites == 0 && com.nbtype <= nUVR) {
         for (i = 0; i < com.nbtype; i++) {
            if (com.aaDist == AAClasses)
               com.pomega = x + com.ntime + com.nrgene + com.nkappa + com.npi + i*com.nOmegaType;
            else
               w0 = (i == com.nOmega - 1 && com.fix_omega ? com.omega_fix : com.pomega[i]);
            eigenQcodon(1, -1, NULL, NULL, NULL, _Root[i], _UU[i], _VV[i], &mr, com.pkappa, w0, PMat);
         }
      }
      k = com.ntime + com.nrgene + com.nrate;
   }
   if (com.seqtype == CODONseq && com.NSsites)
      SetParametersNSsites(x);

   /* to force crash in case or error
   if(com.model) com.omega=-1;
   */

   /* branch models */
   if (com.seqtype == CODONseq && com.model>=NSbranchB &&  com.model <= NSbranch3 && com.NSsites == 0 && com.aaDist == 0) {
      for (j = 0; j < tree.nnode; j++) {
         if (j == tree.root) continue;
         if (com.fix_omega && (int)nodes[j].label == com.nOmega - 1)
            nodes[j].omega = com.omega_fix;
         else
            nodes[j].omega = com.pomega[(int)nodes[j].label];
      }
   }
   if (!com.fix_alpha && com.NSsites == 0) {
      com.alpha = x[k++];
      if (com.fix_rho)
         DiscreteGamma(com.freqK, com.rK, com.alpha, com.alpha, com.ncatG, DGammaUseMedian);
   }
   if (!com.fix_rho) {
      com.rho = x[k++];
      AutodGamma(com.MK, com.freqK, com.rK, &t, com.alpha, com.rho, com.ncatG);
   }
   return (0);
}


int DiscreteNSsites(double par[])
{
   /* This discretizes the continuous distribution for dN/dS ratios among sites
      and calculates freqK[] and rK[], using the median method.
      par[] contains all paras in the w distribution.  par[0] is the
      proportion of beta if (com.NSsites==betaw), or the proportion of w=0 if
      (com.NSsites=NS02normal).
      This routine uses com.NSsites, com.ncatG, com.freqK, com.rK.
      betaw has com.ncatG-1 site classes in the beta distribution, and 02normal
      has com.ncatG-1 site classes in the mixed normal distribution.
      See the function CDFdN_dS() for definitions of parameters.
   */
   int status = 0, i, j, off, K = com.ncatG - (com.NSsites == NSbetaw || com.NSsites == NS02normal);
   double xb[2] = { 1e-7,99 };  /* bounds for omega.  */
   double p01 = 0, p, w0, lnbeta;

   if (com.NSsites == NSbeta || com.NSsites == NSbetaw) xb[1] = 1;

   if (com.NSsites == NSbeta || com.NSsites == NSbetaw) {
      off = (com.NSsites == NSbetaw);  /* par[0] is proportion for beta for M8 */
      lnbeta = LnGamma(par[off]) + LnGamma(par[off + 1]) - LnGamma(par[off] + par[off + 1]);
      for (j = 0; j < K; j++) {
         p = (j*2. + 1) / (2.*K);
         com.rK[j] = QuantileBeta(p, par[off], par[off + 1], lnbeta);
      }
   }
   else {
      for (j = 0; j < K; j++) {
         p = (j*2. + 1) / (2.*K);
         w0 = 0.01 + j / K;
         if (com.rK[j]) w0 = (w0 + com.rK[j]) / 2;
         com.rK[j] = Quantile(CDFdN_dS, p, w0, par, xb);  /* median */
      }
   }
   for (j = 0; j < K; j++) com.freqK[j] = 1.0 / K;

   if (com.NSsites == NSbetaw) {
      if (!com.fix_omega) com.rK[com.ncatG - 1] = par[3];
      else               com.rK[com.ncatG - 1] = com.omega_fix;
      com.freqK[K] = 1 - par[0];
      for (j = 0; j < K; j++) com.freqK[j] *= par[0];
   }
   if (com.NSsites == NS02normal) {
      for (j = K - 1; j >= 0; j--) /* shift to right by 1 to make room for spike at 0*/
      {
         com.rK[j + 1] = com.rK[j]; com.freqK[j + 1] = com.freqK[j];
      }
      com.rK[0] = 0;  com.freqK[0] = par[0];
      for (j = 1; j < K + 1; j++) com.freqK[j] *= (1 - par[0]);
   }

   if (com.NSsites >= NSgamma) {
      if (!status && com.NSsites == NSbeta)
         for (j = 1; j < com.ncatG; j++) if (com.rK[j] + 1e-7 < com.rK[j - 1]) status = 1;

      if (status) {
         printf("\nwarning: DiscreteNSsites\nparameters: ");
         FOR(j, (com.NSsites == 7 ? 2 : 4)) printf(" %12.6f", par[j]);  FPN(F0);
         FOR(j, com.ncatG)            printf("%13.5f", com.freqK[j]);  FPN(F0);
         FOR(j, com.ncatG)            printf("%13.5e", com.rK[j]);  FPN(F0);
      }
   }
   return(0);
}


double CDFdN_dS(double x, double p[])
{
   /* This calculates the CDF of the continuous dN/dS distribution over sites,
      to be used as argument to the routine Quantile().  When the distribution
      has spikes, the spikes are ignored in this routine, and the scaling
      is done outside this routine, for example, in DiscreteNSsites().
      All parameters (par) for the w distribution are passed to this routine,
      although some (p0 for the spike at 0) are not used in this routine.
      Parameters are arranged in the following order:

         NSgamma (2):       alpha, beta
         NS2gamma (4):      p0, alpha1, beta1, alpha2 (=beta2)
         NSbeta (2):        p_beta, q_beta
         NSbetaw (4):       p0, p_beta, q_beta, w (if !com.fix_omega, not used here)
         NSbetagamma (5):   p0, p_beta, q_beta, alpha, beta
         NSbeta1gamma (5):  p0, p_beta, q_beta, alpha, beta (1+gamma)
         NSbeta1normal (5): p0, p_beta, q_beta, mu, s (normal>1)
         NS02normal (5):    p0, p1, mu2, s1, s2 (s are sigma's)
         NS3normal (6):     p0, p1, mu2, s0, s1, s2 (s are sigma's)

      Parameters p0 & p1 are transformed if (!LASTROUND)

   */
   double cdf = -1;
   double z, f[3], mu[3] = { 0,1,2 }, sig[3]; /* 3normal: mu0=0 fixed. mu2 estimated */

   switch (com.NSsites) {
   case(NSgamma):  cdf = CDFGamma(x, p[0], p[1]);   break;
   case(NS2gamma):
      cdf = p[0] * CDFGamma(x, p[1], p[2]) + (1 - p[0])*CDFGamma(x, p[3], p[3]);  break;
   case(NSbeta):   cdf = CDFBeta(x, p[0], p[1], 0);  break;
   case(NSbetaw):  cdf = CDFBeta(x, p[1], p[2], 0);  break;
   case(NSbetagamma):
      cdf = p[0] * CDFBeta(x, p[1], p[2], 0) + (1 - p[0])*CDFGamma(x, p[3], p[4]);  break;

   case(NSbeta1gamma):
      if (x <= 1) cdf = p[0] * CDFBeta(x, p[1], p[2], 0);
      else     cdf = p[0] + (1 - p[0])*CDFGamma(x - 1, p[3], p[4]);
      break;
   case(NSbeta1normal):
      if (x <= 1) cdf = p[0] * CDFBeta(x, p[1], p[2], 0);
      else {
         cdf = CDFNormal((p[3] - 1) / p[4]);
         if (cdf < 1e-9) {
            matout(F0, p, 1, 5);;
            printf("PHI(%.6f)=%.6f\n", (p[3] - 1) / p[4], cdf);  getchar();
         }
         cdf = p[0] + (1 - p[0])*(1 - CDFNormal((p[3] - x) / p[4]) / cdf);
      }
      break;
   case(NS02normal):
      mu[2] = p[2]; sig[1] = p[3]; sig[2] = p[4];
      f[1] = p[1];  f[2] = 1 - f[1];
      cdf = 1 - f[1] * CDFNormal(-(x - mu[1]) / sig[1]) / CDFNormal(mu[1] / sig[1])
         - f[2] * CDFNormal(-(x - mu[2]) / sig[2]) / CDFNormal(mu[2] / sig[2]);
      break;
   case(NS3normal):
      mu[2] = p[2]; sig[0] = p[3]; sig[1] = p[4]; sig[2] = p[5];

      if (LASTROUND) { f[0] = p[0]; f[1] = p[1]; }
      else { z = (f[0] = exp(p[0])) + (f[1] = exp(p[1])) + 1; f[0] /= z; f[1] /= z; }
      f[2] = 1 - f[0] - f[1];
      cdf = 1 - f[0] * 2 * CDFNormal(-x / sig[0])
         - f[1] * CDFNormal(-(x - mu[1]) / sig[1]) / CDFNormal(mu[1] / sig[1])
         - f[2] * CDFNormal(-(x - mu[2]) / sig[2]) / CDFNormal(mu[2] / sig[2]);
      break;
   }
   return(cdf);
}


void GetSNphysical(double pi[], double *Sphysical, double *Nphysical, double *S4)
{
   /* this calculates the synonymous and nonsynonymous sites according to the
      physical-site definition (Yang 2006 Computational Molecular Evolution, Section 2.5.4).
      S and N are sites per codon.
      It is not clear how to deal with stop codons.
   */
   int i, j, k, ic, b[3], aa0, aa1, *code = GeneticCode[com.icode];
   int by[3] = { 16,4,1 }, nstop, s, n;
   double y;

   for (i = 0, *Sphysical = *Nphysical = *S4 = 0; i < com.ncode; i++) {
      ic = FROM61[i]; b[0] = ic / 16; b[1] = (ic / 4) % 4; b[2] = ic % 4;
      /* no need to check the first and second positions here */
      if (FourFold[b[0]][b[1]]) *S4 += pi[i];
      aa0 = code[ic];

      for (j = 0, s = n = nstop = 0; j < 3; j++) FOR(k, 3) {
         aa1 = code[ic + ((b[j] + k + 1) % 4 - b[j])*by[j]];
         if (aa1 == -1)        nstop++;
         else if (aa0 == aa1)  s++;
         else               n++;
      }
      /* s + n ~= 9 */
      *Sphysical += pi[i] * s / 9.*3.;
      *Nphysical += pi[i] * n / 9.*3.;
   }
   y = (*Sphysical + *Nphysical) / 3;
   *Sphysical /= y;  *Nphysical /= y;
}


double GetOmega(int aa1, int aa2, double omega, double pomega[])
{
   /* this gets the omega (w) value under different models for eigenQcodon().
   */
   double w = 1, fit1, fit2;
   int k;

   if (com.aaDist == AAClasses) {
      if (aa1 < aa2) { k = aa2; aa2 = aa1; aa1 = k; }
      k = aa1*(aa1 - 1) / 2 + aa2;
      if (pomega[OmegaAA[k]] < 0) {
         if (noisy)  printf("aa1 & aa2 & iw & w: %d %d %d %.5f\n",
            aa1, aa2, OmegaAA[k], pomega[OmegaAA[k]]);
         pomega[OmegaAA[k]] = 0;
      }
      if (com.seqtype == AAseq && com.nrate > 65 && aa1 * 20 + aa2 == ijAAref)
         ;     /* if estimating grantham's matrix with aa sequences */
      else  w = pomega[OmegaAA[k]];
   }
   else if (com.aaDist == 0)  w = omega; /* NSsites==0 or >0 */
   else if (com.aaDist <= 6) {          /* chemical properties: a & b */
      w = pomega[0] * com.daa[aa1 * 20 + aa2];
      if (com.aaDist > 0)           w = exp(-w);  /* geometric */
      else                       w = 1 - w;      /* linear */
      if (com.seqtype == CODONseq) w *= pomega[1];
   }
   else if (com.aaDist >= FIT1) {   /* ap,p*,av,v* (and w0 for FIT2) */
      fit1 = -pomega[0] * square(AAchem[0][aa1] - pomega[1])
         - pomega[2] * square(AAchem[1][aa1] - pomega[3]);
      fit2 = -pomega[0] * square(AAchem[0][aa2] - pomega[1])
         - pomega[2] * square(AAchem[1][aa2] - pomega[3]);

      w = exp(-fit1 - fit2);
      if (com.aaDist == FIT2) w *= pomega[4];
   }

   return(w);
}


double GetMutationMultiplier(int i, int j, int pos, int from[3], int to[3])
{
   /* This sets the mutation-bias multipliers for F1x4MG, F3x4MG, FMutSel0, FMutSel.
      com.pi[], com.pf3x4[], and com.piAA[] are set correctly before this routine is called.
   */
   int n = com.ncode, b1, b2;
   double q, eFit1, eFit2, small = min2(1e-6, 1. / com.ls);

   /* b1 and b2 are the 2 unchanged positions */
   if (pos == 0) { b1 = 1; b2 = 2; }
   else if (pos == 1) { b1 = 2; b2 = 0; }
   else { b1 = 0; b2 = 1; }
   q = 1 / (com.pf3x4[b1 * 4 + to[b1]] * com.pf3x4[b2 * 4 + to[b2]]);

   if (com.npi && (com.codonf == FMutSel || com.codonf == FMutSel0)) {
      eFit1 = max2(com.pi[i], small);
      eFit2 = max2(com.pi[j], small);
      eFit1 /= com.pf3x4[from[0]] * com.pf3x4[from[1]] * com.pf3x4[from[2]];
      eFit2 /= com.pf3x4[to[0]] * com.pf3x4[to[1]] * com.pf3x4[to[2]];

      if (fabs(eFit2 - eFit1) > 1e-10)
         q *= (log(eFit2) - log(eFit1)) / (eFit2 - eFit1);
      else
         q /= eFit2;
   }
   return(q);
}


int SelectionCoefficients(FILE* fout, double kappa[], double ppi[], double omega)
{
   /* This calculates the distribution of S or 2Ns under the FMutSel or FMutSel0 models.
      Qsubw[] is not correct if (com.NSsites) and the results are not printed.
   */
   int n = Nsensecodon, i, j, k, ic1, ic2, b1, b2;
   int ndiff, pos = 0, from[3], to[3];
   double q, summut = 0, summutp = 0, sumsub = 0, sumsubw = 0, eF1, eF2, fb[4];
   double bigS = 2, sumbadmut = 0, sumgoodmut = 0;
   double Qmut[NCODE*NCODE], Qsub[NCODE*NCODE], Qsubw[NCODE*NCODE], Ns[NCODE*NCODE], mNs = 0, mNsp = 0, mNsn = 0;
   double maxNs = 0, fNsMut[50] = { 0 }, fNsSub[50] = { 0 }, fNsSubw[50] = { 0 }, small = min2(1e-6, 1. / com.ls);
   int ncat = 21;

   if (com.codonf < FMutSel0)
      error2("codonf incorrect");

   fprintf(fout, "\nI\tJ\tij\t2Ns_IJ\tpMut_IJ\tpSub_IJ\t2Ns_JI\tpMut_JI\tpSub_JI\n\n");
   fb[0] = ppi[0]; fb[1] = ppi[1]; fb[2] = ppi[2]; fb[3] = 1;
   for (i = 0; i < n*n; i++) Qmut[i] = Qsub[i] = Qsubw[i] = 0;
   for (i = 1; i < n; i++) {
      ic1 = FROM61[i]; from[0] = ic1 / 16; from[1] = (ic1 / 4) % 4; from[2] = ic1 % 4;
      for (j = 0; j < i; j++) {
         ic2 = FROM61[j]; to[0] = ic2 / 16; to[1] = (ic2 / 4) % 4; to[2] = ic2 % 4;
         for (k = 0, ndiff = 0; k < 3; k++)
            if (from[k] != to[k]) { ndiff++; pos = k; }
         if (ndiff != 1)  continue;
         q = 1;
         if (com.hkyREV) { /* REV-GTR model */
            b1 = min2(from[pos], to[pos]); /* b1 and b2 are changed nucleotides */
            b2 = max2(from[pos], to[pos]);
            if (b1 == 0 && b2 == 1)  q = kappa[0]; /* TC or CT, relative to AG */
            else if (b1 == 0 && b2 == 2)  q = kappa[1]; /* TA or AT */
            else if (b1 == 0 && b2 == 3)  q = kappa[2]; /* TG or GT */
            else if (b1 == 1 && b2 == 2)  q = kappa[3]; /* CA or AC */
            else if (b1 == 1 && b2 == 3)  q = kappa[4]; /* CG or GC */
         }
         else {           /* HKY model */
            if (from[pos] + to[pos] == 1 || from[pos] + to[pos] == 5)
               q = kappa[0];
         }

         eF1 = max2(com.pi[i], small) / (fb[from[0]] * fb[from[1]] * fb[from[2]]);
         eF2 = max2(com.pi[j], small) / (fb[to[0]] * fb[to[1]] * fb[to[2]]);

         Ns[i*n + j] = log(eF2 / eF1);
         Ns[j*n + i] = -Ns[i*n + j];

         if (maxNs < fabs(Ns[i*n + j])) maxNs = fabs(Ns[i*n + j]);

         Qmut[i*n + j] = Qsub[i*n + j] = com.pi[i] * q * fb[to[pos]];
         Qmut[j*n + i] = Qsub[j*n + i] = com.pi[j] * q * fb[from[pos]];

         if (fabs(Ns[i*n + j]) > 1e-20) {  /* non-neutral mutations */
            Qsub[i*n + j] *= Ns[i*n + j] / (1 - exp(-Ns[i*n + j]));
            Qsub[j*n + i] *= Ns[j*n + i] / (1 - exp(-Ns[j*n + i]));
         }
         Qsubw[i*n + j] = Qsub[i*n + j];
         Qsubw[j*n + i] = Qsub[j*n + i];
         if (!com.NSsites && GeneticCode[com.icode][ic1] != GeneticCode[com.icode][ic2]) {
            Qsubw[i*n + j] *= com.omega;
            Qsubw[j*n + i] *= com.omega;
         }

         summut += Qmut[i*n + j] + Qmut[j*n + i];
         sumsub += Qsub[i*n + j] + Qsub[j*n + i];
         sumsubw += Qsubw[i*n + j] + Qsubw[j*n + i];

         if (fabs(Ns[i*n + j]) > 1e-20) {  /* non-neutral mutations */
            summutp += (Ns[i*n + j] > 0 ? Qmut[i*n + j] : Qmut[j*n + i]);
            mNsp += (Ns[i*n + j] > 0 ? Qmut[i*n + j] * Ns[i*n + j] : Qmut[j*n + i] * Ns[j*n + i]);
            mNsn += (Ns[i*n + j] < 0 ? Qmut[i*n + j] * Ns[i*n + j] : Qmut[j*n + i] * Ns[j*n + i]);
         }
         else {  /* neutral mutation.  Ns = 0 makes no contribution to mNsp & mNsn */
            summutp += (Qmut[i*n + j] + Qmut[j*n + i]) / 2;
         }
         mNs += (Qmut[i*n + j] + Qmut[j*n + i])*fabs(Ns[i*n + j]);

         if (fabs(Ns[i*n + j]) > bigS) {
            if (Ns[i*n + j] > 0) {
               sumgoodmut += Qmut[i*n + j];
               sumbadmut += Qmut[j*n + i];
            }
            else {
               sumgoodmut += Qmut[j*n + i];
               sumbadmut += Qmut[i*n + j];
            }
         }

         fprintf(fout, "%c%c%c\t", BASEs[from[0]], BASEs[from[1]], BASEs[from[2]]);
         fprintf(fout, "%c%c%c\t", BASEs[to[0]], BASEs[to[1]], BASEs[to[2]]);
         fprintf(fout, "%c%c", BASEs[from[pos]], BASEs[to[pos]]);
         fprintf(fout, "\t%.5f\t%.5f\t%.5f", Ns[i*n + j], Qmut[i*n + j], Qsub[i*n + j]);
         fprintf(fout, "\t%.5f\t%.5f\t%.5f", Ns[j*n + i], Qmut[j*n + i], Qsub[j*n + i]);

         if (!com.NSsites)
            fprintf(fout, "\t%.5f\t%.5f", Qsubw[i*n + j], Qsubw[j*n + i]);

         FPN(fout);

      } /* for (j) */
   }    /* for (i) */

   sumgoodmut /= summut;
   sumbadmut /= summut;
   mNs /= summut;
   mNsp /= summutp;
   mNsn /= summut - summutp;

   fprintf(fout, "\n\nHistograms\n2Ns\tFMut\tFSub(CodonUsage)\tFSubw(after w)\n\n");

   for (i = 0; i < n; i++) {
      for (j = 0; j < n; j++) {
         if (Qmut[i*n + j] == 0) continue;
         for (k = 0; k < ncat - 1; k++) {
            if (Ns[i*n + j] < (-1 + (k + 1.) * 2 / ncat)*maxNs) break;
         }
         fNsMut[k] += Qmut[i*n + j] / summut;
         fNsSub[k] += Qsub[i*n + j] / sumsub;
         fNsSubw[k] += Qsubw[i*n + j] / sumsubw;
      }
   }
   for (k = 0; k < ncat; k++) {
      fprintf(fout, "%.5f\t%.5f\t%.5f", (-1 + (k + 0.5) * 2 / ncat)*maxNs, fNsMut[k], fNsSub[k]);
      if (!com.NSsites)
         fprintf(fout, "\t%.5f", fNsSubw[k]);
      FPN(fout);
   }

   fprintf(fout, "\nProportion of advantageous (S > 0) mutations:\n %.5f\n", summutp / summut);
   fprintf(fout, "\nProportions of good & bad mutations (|S| > %.4f) among mutations:\n%.5f  %.5f\n",
      bigS, sumgoodmut, sumbadmut);
   fprintf(fout, "\nmean |Ns| = %.5f\tmean Ns+ = %.5f\tmean Ns- = %.5f\n", mNs, mNsp, mNsn);

   fprintf(frst1, "\t%.4f\t%.4f\t%.4f", mNs, mNsp, mNsn);

   return(0);
}


int eigenQcodon(int mode, double blength, double *S, double *dS, double *dN,
   double Root[], double U[], double V[], double *meanrate, double kappa[], double omega, double Q[])
{
   /* This contructs the rate matrix Q for codon substitution and gets the eigen
      values and vectors if getstats==0, or get statistics (dS & dN etc.) if
      getstats==1.
      The routine is also called by Qcodon2aa for mechanistic amino acid
      substitution models.
      Input parameters are kappa, omega and com.pi (or com.fb61).

      Statistics calculated include S, dS & dN.
      c0[0,1,2] and c[0,1,2] are rates for the 3 codon positions before and after
      selection.  c4 is for 4-fold rates.  ts[3] and tv[3] are transition/
      transversion rates for the three codon positions, not calculated.

      mode=0: construct Q;  1: calculate UVRoot; 2:calculate statistics

      *Qfactor or *meanrate:
         =0 means that Q is scaled as usual;
         <0 means that the scale factor will be calculated and returned
         >0 the given scale factor is applied (1 means no scaling).

      Note that under NSsites or branch&site models, scaling is done for all Q
      matrices for the whole branch.

      aaDist=FIT1 & FIT2:  ap,p*,av,v*, (and w0 for FIT2)
      The argument omega is used only if the model assumes one omega.  For
      AAClasses, com.pomega is used instead.
   */
   int n = Nsensecodon, i, j, k, ic1, ic2, aa1, aa2, b1, b2;
   int ndiff, pos = 0, from[3], to[3];
   double q, mr, rs0, ra0, rs, ra, y;
   double Sphysical, Nphysical, S4, dSnew, dNnew;
   double d4 = 0, d0[3], d[3], ts[3], tv[3];  /* rates at positions and 4-fold sites */
   double *pi = (com.seqtype == AAseq ? com.fb61 : com.pi), w = -1, piQij;
   double space[NCODE*(NCODE + 1)];

   /* Delete this after the MutSel project. */
   static int times = 0;
   if (mode == 1) times = 0;
   else times++;

   NEigenQ++;
   if (blength >= 0 && (S == NULL || dS == NULL || dN == NULL)) error2("eigenQcodon");
   memset(Q, 0, n*n*sizeof(double));
   for (i = 1; i < n; i++) {
      ic1 = FROM61[i]; from[0] = ic1 / 16; from[1] = (ic1 / 4) % 4; from[2] = ic1 % 4;
      for (j = 0; j < i; j++) {
         ic2 = FROM61[j]; to[0] = ic2 / 16; to[1] = (ic2 / 4) % 4; to[2] = ic2 % 4;
         for (k = 0, ndiff = 0; k < 3; k++)
            if (from[k] != to[k]) { ndiff++; pos = k; }
         if (ndiff != 1)  continue;
         q = 1;
         if (com.hkyREV) { /* REV-GTR model */
            b1 = min2(from[pos], to[pos]); /* b1 and b2 are changed nucleotides */
            b2 = max2(from[pos], to[pos]);
            if (b1 == 0 && b2 == 1)  q = kappa[0]; /* TC or CT, relative to AG */
            else if (b1 == 0 && b2 == 2)  q = kappa[1]; /* TA or AT */
            else if (b1 == 0 && b2 == 3)  q = kappa[2]; /* TG or GT */
            else if (b1 == 1 && b2 == 2)  q = kappa[3]; /* CA or AC */
            else if (b1 == 1 && b2 == 3)  q = kappa[4]; /* CG or GC */
         }
         else {            /* HKY model */
            if (from[pos] + to[pos] == 1 || from[pos] + to[pos] == 5)
               q = kappa[0];
         }
         if (com.codonf >= F1x4MG && com.codonf <= FMutSel && com.codonf != Fcodon)
            q *= GetMutationMultiplier(i, j, pos, from, to);

         aa1 = GeneticCode[com.icode][ic1];
         aa2 = GeneticCode[com.icode][ic2];
         if (aa1 != aa2)
            q *= GetOmega(aa1, aa2, omega, com.pomega);
         Q[j*n + i] = Q[i*n + j] = q;
      } /* for (j) */
   }    /* for (i) */
   if (com.seqtype == AAseq && com.model == FromCodon) return (0);  /* the FromCodon model */
   for (i = 0; i < n; i++) for (j = 0; j < n; j++)
      Q[i*n + j] *= pi[j];

   for (i = 0; i < n; i++)
      Q[i*n + i] = -sum(Q + i*n, n);
   for (i = 0, mr = 0; i < n; i++)
      mr -= pi[i] * Q[i*n + i];

   if (mode == 1) {  /* get Root, U, & V */
      eigenQREV(Q, pi, n, Root, U, V, space);
      if (*meanrate >= 0) {    /* apply scaling if meanrate>0 */
         if (*meanrate > 0)
            mr = *meanrate;
         for (i = 0; i < n; i++)
            Root[i] /= mr;
      }
   }
   else if (mode == 2) {  /* get statistics */
      for (i = 0; i < 3; i++) d[i] = d0[i] = ts[i] = tv[i] = 0;
      rs0 = ra0 = rs = ra = 0;
      for (i = 0; i < n; i++) {
         ic1 = FROM61[i]; from[0] = ic1 / 16; from[1] = (ic1 / 4) % 4; from[2] = ic1 % 4;
         for (j = 0; j < n; j++) {
            if (i == j || Q[i*n + j] == 0) continue;
            ic2 = FROM61[j]; to[0] = ic2 / 16; to[1] = (ic2 / 4) % 4; to[2] = ic2 % 4;
            aa1 = GeneticCode[com.icode][ic1];
            aa2 = GeneticCode[com.icode][ic2];
            for (k = 0, ndiff = 0; k < 3; k++)
               if (from[k] != to[k]) { ndiff++; pos = k; }
            if (ndiff != 1) error2("jgl");

            piQij = pi[i] * Q[i*n + j];
            if (pos == 2 && FourFold[to[0]][to[1]])
               d4 += piQij;

            if (aa1 == aa2) {
               rs += piQij;
               d0[pos] += piQij;
            }
            else {
               ra += piQij;
               w = GetOmega(aa1, aa2, omega, com.pomega);
               ra0 += piQij / w;
               d0[pos] += piQij / w;
            }
            d[pos] += piQij;
         } /* for (j) */
      }    /* for (i) */

      if (fabs(mr - (rs + ra)) > 1e-6)
         error2("mr should be = rs+ra");

      rs0 = rs;
      w = (rs0 + ra0);  rs0 /= w;  ra0 /= w;   *S = rs0 * 3 * com.ls;
      if (com.NSsites == 0 && blength >= 0) {  /* calculates dS & dN */
         if (blength == 0) *dS = *dN = 0;
         rs /= mr;
         ra /= mr;
         *dS = blength*rs / (3 * rs0);
         *dN = blength*ra / (3 * ra0);
         w = (*dS > 0 ? *dN / *dS : -1);
         GetSNphysical(com.pi, &Sphysical, &Nphysical, &S4);
         for (i = 0; i < 3; i++) {
            d[i] *= blength / mr;
            d0[i] *= blength / mr;
         }
         d4 *= blength / mr / S4;
         dNnew = blength*ra / Nphysical;
         dSnew = blength*rs / Sphysical;

         if (noisy >= 9) {
            printf("\nd123[*] =%9.5f%9.5f%9.5f  average%9.5f\n", d[0], d[1], d[2], (d[0] + d[1] + d[2]) / 3);
            printf("    [B] =%9.5f%9.5f%9.5f  average%9.5f\n", d0[0], d0[1], d0[2], (d0[0] + d0[1] + d0[2]) / 3);
            printf("accept  =%9.5f%9.5f%9.5f\n\n", d[0] / d0[0], d[1] / d0[1], d[2] / d0[2]);
            printf("w =%9.5f dN =%9.5f dS =%9.5f d4 =%9.5f (%.1f four-fold sites)\n", w, *dN, *dS, d4, S4*com.ls);
            printf("%12s dN*=%9.5f dS*=%9.5f S* =%7.2f N* =%7.2f\n", "", dNnew, dSnew, Sphysical*com.ls, Nphysical*com.ls);
         }

         /* print out dN* dS* d4 d3B */
         if (com.verbose && times == 1 && com.ns == 2)
            fprintf(frst1, "\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f",
               *dN * 2, *dS * 2, dNnew * 2, dSnew * 2, d0[2] * 2, d4 * 2);
      }
      else if (com.NSsites) {
         *dS = rs / (rs0 * 3);
         *dN = ra / (ra0 * 3);
      }
   }

   if (*meanrate < 0) *meanrate = mr;
   return(0);
}


int eigenQaa(FILE *fout, double Root[], double U[], double V[], double rate[])
{
   /*  Codon-based AA model must use FromCodon, even if com.aaDist==AAClasses.
   */
   int naa = 20, i, j, k;
   double Q[20 * 20], mr = 0, t = 0;
   double space[NCODE*NCODE * 2 + NCODE], *Qc = space + NCODE*NCODE, *space_pisqrt = Qc + NCODE*NCODE;
   char aa3[4] = "", AAratefile[96] = "AAratefile.dat";
   FILE *fAArate;

   for (i = 0; i < naa*naa; i++) Q[i] = 0;
   switch (com.model) {
   case (Poisson): case (EqualInput):
      fillxc(Q, 1., naa*naa);  break;
   case (Empirical): case (Empirical_F):
      for (i = 0; i < naa; i++) for (j = 0; j < i; j++)
         Q[i*naa + j] = Q[j*naa + i] = com.daa[i*naa + j];
      break;
   case (FromCodon): /* eigenQcodon check mode value */
      eigenQcodon(0, -1, NULL, NULL, NULL, Root, U, V, &mr,
         (com.hkyREV || com.codonf == FMutSel ? rate : &com.kappa), com.omega, Qc);
      Qcodon2aa(Qc, com.fb61, Q, space);
      break;
   case (REVaa_0):
      for (i = 1, k = 0; i < naa; i++)
         for (j = 0; j < i; j++)
            if (AA1STEP[i*(i - 1) / 2 + j] && i*naa + j != ijAAref)
               Q[i*naa + j] = Q[j*naa + i] = rate[k++];
      k = ijAAref;
      Q[(k / naa)*naa + k%naa] = Q[(k%naa)*naa + k / naa] = 1;
      break;
   case (REVaa):
      for (i = 0, k = 0; i < naa; i++)
         for (j = 0; j < i; j++)
            if (i*naa + j != ijAAref) Q[i*naa + j] = Q[j*naa + i] = rate[k++];
      Q[ijAAref] = Q[(ijAAref%naa)*naa + (ijAAref / naa)] = 1;
      break;
   }
   for (i = 0; i < naa; i++) for (j = 0; j < naa; j++)
      Q[i*naa + j] *= com.pi[j];
   for (i = 0, mr = 0; i < naa; i++) {
      Q[i*naa + i] = 0;
      Q[i*naa + i] = -sum(Q + i*naa, naa);
      mr -= com.pi[i] * Q[i*naa + i];
   }

   if (fout && com.model >= REVaa_0) {
      printf("\nAA substitution rate matrix printed into %s\n", AAratefile);
      fAArate = (FILE*)gfopen(AAratefile, "w");
      fprintf(fout, "\n\nRate matrix (symmetrical part, Sij)\n");
      for (i = 0, t = 0; i < naa; i++) {
         if (com.pi[i] == 0) error2("eigenQaa: do this now");
         for (j = 0; j < i; j++)
            t += Q[i*naa + j] / com.pi[j] / (naa*(naa - 1) / 2.);
      }
      for (i = 0; i < naa; i++) {
         fprintf(fout, "\n%-5s", getAAstr(aa3, i));
         for (j = 0; j < i; j++) fprintf(fout, " %8.2f", Q[i*naa + j] / t / com.pi[j] * 100);
         for (j = 0; j < i; j++) fprintf(fAArate, " %8.2f", Q[i*naa + j] / t / com.pi[j] * 100);
         FPN(fAArate);
      }
      fputs("\n     ", fout);
      for (i = 0; i < naa; i++)
         fprintf(fout, "%5s", getAAstr(aa3, i));
      FPN(fout);
      fflush(fout);
      matout(fAArate, com.pi, 1, naa);
      for (i = 0; i < naa; i++)
         fprintf(fAArate, "%12s", getAAstr(aa3, i));
      FPN(fAArate);
      fprintf(fAArate, "\n\nNote: Amino acid rate matrix estimated from %s\n", com.seqf);
      fclose(fAArate);
   }

   if (fout && frst1 && com.model >= REVaa_0) {
      fprintf(frst1, "\nRate matrix (symmetrical part, Sij) for bubble plot\n");
      for (i = 0; i < naa; i++)  for (j = 0; j < i; j++)
         fprintf(frst1, "\t%d\t%d\t%.2f\n", i + 1, j + 1, Q[i*naa + j] / t / com.pi[j] * 100);
   }

   eigenQREV(Q, com.pi, naa, Root, U, V, space_pisqrt);
   for (i = 0; i < naa; i++)
      Root[i] = Root[i] / mr;
   return (0);
}


int Qcodon2aa(double Qc[], double pic[], double Qaa[], double piaa[])
{
/* Qc -> Qaa

   This routine constructs the rate matrix for amino acid replacement from
   the rate matrix for codon substitution, by congregating states in the
   Markov chain.  Both processes are time reversible, and only the
   symmetrical part of the rate matrix are constructed.  Codon frequencies
   pic[] are used.  They are constructed by assigning equal frequencies for
   synonymous codons in the routine AA2Codonf().
   Qaa(a_i, a_j) = sum_i sum_j (piC[i]*piC[j]]*Qc[i][j]) / (piAA[i]*piAA[j])
*/
   int i, j, aai, aaj, nc = Nsensecodon, naa = 20;
   double ti, tij;

   zero(piaa, naa);
   zero(Qaa, naa*naa);
   for (i = 0; i < nc; i++)
      piaa[GeneticCode[com.icode][FROM61[i]]] += pic[i];
   for (i = 0; i < nc; i++) {
      aai = GeneticCode[com.icode][FROM61[i]];
      if (piaa[aai] == 0)   ti = 0;
      else                  ti = pic[i] / piaa[aai];
      for (j = 0; j < i; j++) {
         aaj = GeneticCode[com.icode][FROM61[j]];
         if (Qc[i*nc + j] == 0 || aai == aaj) continue;
         if (piaa[aaj] == 0)
            tij = 0;
         else
            tij = ti*pic[j] * Qc[i*nc + j] / piaa[aaj];
         Qaa[aai*naa + aaj] += tij;
         Qaa[aaj*naa + aai] += tij;
      }
   }

   return (0);
}



int ConditionalPNode(int inode, int igene, double x[])
{
   int n = com.ncode, i, j, k, h, ison, pos0 = com.posG[igene], pos1 = com.posG[igene + 1];
   double t;

   for (i = 0; i < nodes[inode].nson; i++)
      if (nodes[nodes[inode].sons[i]].nson > 0 && !com.oldconP[nodes[inode].sons[i]])
         ConditionalPNode(nodes[inode].sons[i], igene, x);

   if (inode < com.ns)
      for (h = pos0*n; h < pos1*n; h++)
         nodes[inode].conP[h] = 0; /* young ancestor */
   else
      for (h = pos0*n; h < pos1*n; h++)
         nodes[inode].conP[h] = 1;
   if (com.cleandata && inode < com.ns)
      for (h = pos0; h < pos1; h++)
         nodes[inode].conP[h*n + com.z[inode][h]] = 1;

   for (i = 0; i < nodes[inode].nson; i++) {
      ison = nodes[inode].sons[i];
      t = nodes[ison].branch * _rateSite;
      if (com.clock < 5) {
         if (com.clock)  t *= GetBranchRate(igene, (int)nodes[ison].label, x, NULL);
         else            t *= com.rgene[igene];
      }

      GetPMatBranch(PMat, x, t, ison);

      if (nodes[ison].nson < 1 && com.cleandata) {        /* tip && clean */
         for (h = pos0; h < pos1; h++)
            for (j = 0; j < n; j++)
               nodes[inode].conP[h*n + j] *= PMat[j*n + com.z[ison][h]];
      }
      else if (nodes[ison].nson < 1 && !com.cleandata) {  /* tip & unclean */
         for (h = pos0; h < pos1; h++)
            for (j = 0; j < n; j++) {
               for (k = 0, t = 0; k < nChara[com.z[ison][h]]; k++)
                  t += PMat[j*n + CharaMap[com.z[ison][h]][k]];
               nodes[inode].conP[h*n + j] *= t;
            }
      }
      else {                                            /* internal node */
         for (h = pos0; h < pos1; h++)
            for (j = 0; j < n; j++) {
               for (k = 0, t = 0; k < n; k++)
                  t += PMat[j*n + k] * nodes[ison].conP[h*n + k];
               nodes[inode].conP[h*n + j] *= t;
            }
      }

   }        /*  for (ison)  */
   if (com.NnodeScale && com.nodeScale[inode])
      NodeScale(inode, pos0, pos1);

   return (0);
}


int PMatJC69like(double P[], double t, int n)
{
   int i;
   double pii = 1. / n + (1. - 1. / n)*exp(-n / (n - 1.)*t), pij = (1. - pii) / (n - 1.);
   for (i = 0; i < n*n; i++) P[i] = pij;
   for (i = 0; i < n; i++)   P[i*n + i] = pii;
   return (0);
}


int Fcodon_3x4(double fcodon[], double fb3x4[]);
void OutFb3x4(FILE*fout, double fb3x4[]);
void CountCodons(FILE *fout, double fcodonsg[], double fb3x4sg[], double fb4g[]);

int Fcodon_3x4(double fcodon[], double fb3x4[])
{
   /* this converts the codon frequencies into a fb3x4 table. fcodon has 64 codons.
   */
   int b[3], k, j, nc = 64, status = 0;
   double t;

   zero(fb3x4, 12);
   for (k = 0; k < nc; k++) {
      b[0] = k / 16; b[1] = (k % 16) / 4; b[2] = k % 4;
      for (j = 0; j < 3; j++) {
         fb3x4[j * 4 + b[j]] += fcodon[k];
      }
   }
   for (j = 0; j < 3; j++) {
      t = sum(fb3x4 + j * 4, 4);
      if (t < 1e-20) status = -1;
      abyx(1 / t, fb3x4 + j * 4, 4);
   }
   return(status);
}

void OutFb3x4(FILE*fout, double fb3x4[])
{
   int j, k;
   for (j = 0; j < 3; j++) {
      fprintf(fout, "\nposition %2d:", j + 1);
      for (k = 0; k < 4; k++)
         fprintf(fout, "%5c:%7.5f", BASEs[k], fb3x4[j * 4 + k]);
   }
   fprintf(fout, "\nAverage     ");
   for (k = 0; k < 4; k++)
      fprintf(fout, "%5c:%7.5f", BASEs[k], (fb3x4[0 * 4 + k] + fb3x4[1 * 4 + k] + fb3x4[2 * 4 + k]) / 3);
}


void CountCodons(FILE *fout, double fcodonsg[], double fb3x4sg[], double fb4g[])
{
   /* Outputs codon counts and f3x4 tables, called from InitializeCodon(), where
      more notes are found.
   */
   int h, j, k, nc = NCODE, ig, wname = 15, nb[3], ib[3][4], ic, nempty, status = 0;

   /* counts codons for output, species first, genes next */
   fputs("Codon usage in sequences\n", fout);
   zero(fcodonsg, com.ns*nc);
   for (j = 0; j < com.ns; j++) {
      for (h = 0; h < com.npatt; h++) {
         for (k = 0; k < 3; k++)
            NucListall(CODONs[com.z[j][h]][k], &nb[k], ib[k]);
         k = nb[0] * nb[1] * nb[2];
         if (k > 1)  continue;
         ic = ib[0][0] * 16 + ib[1][0] * 4 + ib[2][0];
         fcodonsg[j*nc + ic] += com.fpatt[h];
      }
      status += Fcodon_3x4(fcodonsg + j*nc, fb3x4sg + j * 12);
   }
   if (-status / (double)com.ns > 0.9) {
      printf("\n%d out of %d sequences do not have any resolved nucleotides. Giving up.\n", -status, com.ns);
      exit(1);
   }
   printcums(fout, com.ns, fcodonsg, com.icode);
   fputs("Codon position x base (3x4) table for each sequence.", fout);
   for (j = 0; j < com.ns; j++) {
      fprintf(fout, "\n\n#%d: %-*s", j + 1, wname, com.spname[j]);
      OutFb3x4(fout, fb3x4sg + j * 12);
   }

   zero(fcodonsg, (com.ngene + 1)*nc);
   zero(fb4g, (com.ngene + 1) * 4);
   for (ig = 0; ig < com.ngene; ig++) {
      for (j = 0; j < com.ns; j++) {
         for (h = com.posG[ig]; h < com.posG[ig + 1]; h++) {
            for (k = 0; k < 3; k++)
               NucListall(CODONs[com.z[j][h]][k], &nb[k], ib[k]);

            k = nb[0] * nb[1] * nb[2];
            if (k > 1) continue;
            ic = ib[0][0] * 16 + ib[1][0] * 4 + ib[2][0];
            fcodonsg[ig*nc + ic] += com.fpatt[h];
         }
      }
      if (Fcodon_3x4(fcodonsg + ig*nc, fb3x4sg + ig * 12)) {
         printf("All sequences are empty? ");
         if (com.ngene > 1) printf(" in Gene %d\n", ig + 1);
         exit(-1);
      }
   }
   if (com.ngene > 1) {
      fputs("\n\nCodon usage in genes\n", fout);
      printcums(fout, com.ngene, fcodonsg, com.icode);
      fputs("Codon position x base (3x4) table for each gene.\n", fout);
      for (ig = 0; ig < com.ngene; ig++) {
         fprintf(fout, "\n\nGene #%d", ig + 1);
         OutFb3x4(fout, fb3x4sg + ig * 12);
      }
   }

   for (ig = 0; ig < com.ngene; ig++)
      for (k = 0; k < nc; k++) fcodonsg[com.ngene*nc + k] += fcodonsg[ig*nc + k];
   Fcodon_3x4(fcodonsg + com.ngene*nc, fb3x4sg + com.ngene * 12);
   for (ig = 0; ig < com.ngene + 1; ig++)
      for (j = 0; j < 3; j++) for (k = 0; k < 4; k++) fb4g[ig * 4 + k] += fb3x4sg[ig * 12 + j * 4 + k] / 3;

   fputs("\n\nSums of codon usage counts", fout);
   printcu(fout, fcodonsg + com.ngene*nc, com.icode);
   if (!com.cleandata) fputs("\n(Ambiguity data are not used in the counts.)\n", fout);
   fputs("\n\nCodon position x base (3x4) table, overall\n", fout);
   OutFb3x4(fout, fb3x4sg + com.ngene * 12);


   {
      double *fb3x4 = fb3x4sg + com.ngene * 12, GC3;
      GC3 = (fb3x4[0 * 4 + 1] + fb3x4[1 * 4 + 1] + fb3x4[2 * 4 + 1]) / 3
         + (fb3x4[0 * 4 + 3] + fb3x4[1 * 4 + 3] + fb3x4[2 * 4 + 3]) / 3;
      fprintf(frst1, "\t%.4f", GC3);
   }

}


void AddCodonFreqSeqGene(int js, int ig, double fcodon0[], double fcodon[],
   double fb3x40[], double fb3x4[],
   double fb40[], double fb4[]);

void AddCodonFreqSeqGene(int js, int ig, double fcodon0[], double fcodon[],
   double fb3x40[], double fb3x4[],
   double fb40[], double fb4[])
{
   /* This adds codon and nucleotide counts in sequence js in gene ig to fcodon,
      fb3x4, and fb4, using fcodon0, fb3x40, and fb40 to resolve ambiguities
      Similar to AddFreqSeqGene().
   */
   int h, k, i0, i1, i2, nc = NCODE;
   int nb[3], ib[3][4], ic = -1;
   double t, t1;
   char str[4] = "   ", codon[4] = " ", ft[64];

   for (h = com.posG[ig]; h < com.posG[ig + 1]; h++) {
      for (k = 0; k < 3; k++)
         NucListall(CODONs[com.z[js][h]][k], &nb[k], ib[k]);
      k = nb[0] * nb[1] * nb[2];
      for (k = 0; k < 3; k++) {  /* f3x4 & f1x4, no regard for stop codons */
         for (i0 = 0, t = t1 = 0; i0 < nb[k]; i0++) {
            t += fb3x40[k * 4 + ib[k][i0]];
            t1 += fb40[ib[k][i0]];
         }
         for (i0 = 0; i0 < nb[k]; i0++) {
            fb3x4[k * 4 + ib[k][i0]] += com.fpatt[h] * fb3x40[k * 4 + ib[k][i0]] / t;
            fb4[ib[k][i0]] += com.fpatt[h] * fb40[ib[k][i0]] / t1;
         }
      }
      for (i0 = 0; i0 < 64; i0++) ft[i0] = 0;
      for (i0 = k = 0, t = 0; i0 < nb[0]; i0++) FOR(i1, nb[1]) FOR(i2, nb[2]) {
         ic = ib[0][i0] * 16 + ib[1][i1] * 4 + ib[2][i2];
         if (FROM64[ic] == -1) continue;
         ft[ic] = 1;  k++;
         t += fcodon0[ic];
      }
      if (k == 0) printf("%s in seq. %d is stop (icode=%d)\n",
         getcodon(str, ic), js + 1, com.icode);
      if (t < 1e-100)
         printf("difficulty in resolving codon %s.\n", codon);
      for (ic = 0; ic < nc; ic++)  if (ft[ic])
         fcodon[ic] += (t > 0 ? com.fpatt[h] * fcodon0[ic] / t : com.fpatt[h] / k);
   }
}


int InitializeCodon(FILE *fout, double space[])
{
   /* Count codons for genes, calculate site patterns and fpatt.
      Sequences com.z[] are not coded and may contain ambiguity characters
      Space requirement for fcodonsg & fb3x4sg: max(ngene+1,ns)*(64+12+4).
      First we count codons for output, with ambiguity characters ignored.
      Then we recount to resolve ambiguity characters, to be used for ML
      calculation later on.
      set up com.pi[NCODE], com.piG[NGENE][64], according to com.codonf
      com.pi[] has freqs for all codon sites in the seqs if ngene>1.
      Space use is not economical as com.piG and fcodonsg are separate and
      duplicated.
   */
   int j, k, nc = NCODE, ig, ic[3], wrongorder[4] = { 2,1,3,0 };
   int irf, nrf = 20;
   double *fcodonsg = space, *fb3x4sg = space + max2((com.ngene + 1), com.ns)*nc;
   double *fb4g = space + (com.ngene + 1)*(64 + 12);
   double *ppi, fcodon0[64], fb3x40[12], fb40[4], d1, d2, d3;

   /* counts codons for output, species first, genes next */
   if (noisy) puts("Counting codons..");
   CountCodons(fout, fcodonsg, fb3x4sg, fb4g);

   /* Now to count fcodonsg, fb3x4sg, fb4g, to set up pi's for ML calculation.
      Three iterations are going on at the same time.
   */
   if (com.codonf != Fequal && !com.cleandata) { /* iteration to resolve ambiguities */
      for (ig = 0; ig < com.ngene; ig++) {    /* calculate com.piG[] */
         axtoy(1 / sum(fcodonsg + ig*nc, nc), fcodonsg + ig*nc, fcodon0, nc);
         xtoy(fb3x4sg + ig * 12, fb3x40, 12);
         xtoy(fb4g + ig * 4, fb40, 4);

         for (irf = 0; irf < nrf; irf++) {
            zero(fcodonsg + ig*nc, nc);
            zero(fb3x4sg + ig * 12, 12);
            zero(fb4g + ig * 4, 4);
            for (j = 0; j < com.ns; j++) {
               AddCodonFreqSeqGene(j, ig, fcodon0, fcodonsg + ig*nc,
                  fb3x40, fb3x4sg + ig * 12, fb40, fb4g + ig * 4);
            }
            abyx(1 / sum(fcodonsg + ig*nc, nc), fcodonsg + ig*nc, nc);
            for (k = 0; k < 3; k++)
               abyx(1 / sum(fb3x4sg + ig * 12 + k * 4, 4), fb3x4sg + ig * 12 + k * 4, 4);
            abyx(1 / sum(fb4g + ig * 4, 4), fb4g + ig * 4, 4);
            d1 = distance(fcodonsg + ig*nc, fcodon0, nc);
            d2 = distance(fb3x4sg + ig * 12, fb3x40, 12);
            d3 = distance(fb4g + ig * 4, fb40, 4);
            if (d1 < 1e-8 && d2 < 1e-8 && d3 < 1e-8)
               break;
            xtoy(fcodonsg + ig*nc, fcodon0, nc);
            xtoy(fb3x4sg + ig * 12, fb3x40, 12);
            xtoy(fb4g + ig * 4, fb40, 4);
         } /* for(irf) */
      }   /* for(ig) */

      axtoy(1 / sum(fcodonsg + com.ngene*nc, nc), fcodonsg + com.ngene*nc, fcodon0, nc);
      xtoy(fb3x4sg + com.ngene * 12, fb3x40, 12);
      xtoy(fb4g + com.ngene * 4, fb40, 4);
      for (irf = 0; irf < nrf; irf++) {  /* calculate com.pi[] */
         zero(fcodonsg + com.ngene*nc, nc);
         zero(fb3x4sg + com.ngene * 12, 12);
         zero(fb4g + com.ngene * 4, 4);
         for (ig = 0; ig < com.ngene; ig++)
            for (j = 0; j < com.ns; j++) {
               AddCodonFreqSeqGene(j, ig, fcodon0, fcodonsg + com.ngene*nc,
                  fb3x40, fb3x4sg + com.ngene * 12, fb40, fb4g + com.ngene * 4);
            }
         abyx(1 / sum(fcodonsg + com.ngene*nc, nc), fcodonsg + com.ngene*nc, nc);
         for (k = 0; k < 3; k++)
            abyx(1 / sum(fb3x4sg + com.ngene * 12 + k * 4, 4), fb3x4sg + com.ngene * 12 + k * 4, 4);
         abyx(1 / sum(fb4g + com.ngene * 4, 4), fb4g + com.ngene * 4, 4);
         d1 = distance(fcodonsg + com.ngene*nc, fcodon0, nc);
         d2 = distance(fb3x4sg + com.ngene * 12, fb3x40, 12);
         d3 = distance(fb4g + com.ngene * 4, fb40, 4);
         if (d1 < 1e-8 && d2 < 1e-8 && d3 < 1e-8)  break;
         xtoy(fcodonsg + com.ngene*nc, fcodon0, nc);
         xtoy(fb3x4sg + com.ngene * 12, fb3x40, 12);
         xtoy(fb4g + com.ngene * 4, fb40, 4);
      } /* for(irf) */
   }

   /* edit com.pi & com.piG according to com.codonf */
   for (ig = 0; ig < com.ngene + 1; ig++) {
      ppi = (ig < com.ngene ? com.piG[ig] : com.pi);
      zero(ppi, nc);
      if (com.codonf == Fequal)
         fillxc(ppi, 1, com.ncode);
      else if (com.codonf == Fcodon || com.codonf == FMutSel0 || com.codonf == FMutSel) {
         for (k = 0; k < nc; k++)
            if (FROM64[k] > -1)  ppi[FROM64[k]] = fcodonsg[ig*nc + k];
      }
      else if (com.codonf == F3x4 || com.codonf == F3x4MG) {
         for (k = 0; k < nc; k++)
            if (FROM64[k] > -1)
               ppi[FROM64[k]] = fb3x4sg[ig * 12 + k / 16] * fb3x4sg[ig * 12 + 4 + (k / 4) % 4] * fb3x4sg[ig * 12 + 8 + k % 4];
      }
      else if (com.codonf == F1x4 || com.codonf == F1x4MG) {
         for (k = 0; k < nc; k++)
            if (FROM64[k] > -1)
               ppi[FROM64[k]] = fb4g[ig * 4 + k / 16] * fb4g[ig * 4 + (k / 4) % 4] * fb4g[ig * 4 + k % 4];
      }
      abyx(1 / sum(ppi, com.ncode), ppi, com.ncode);  /* ncode != nc */

      if (ig < com.ngene) {
         if (com.codonf >= F1x4 && com.codonf <= FMutSel)
            xtoy(fb3x4sg + ig * 12, com.f3x4[ig], 12);
         /* write 1x4 tables into 3x4 tables */
         if (com.codonf == FMutSel0 || com.codonf == FMutSel || com.codonf == F1x4 || com.codonf == F1x4MG) {
            for (k = 0; k < 4; k++) {
               d1 = com.f3x4[ig][0 * 4 + k] + com.f3x4[ig][1 * 4 + k] + com.f3x4[ig][2 * 4 + k];
               for (j = 0; j < 3; j++)
                  com.f3x4[ig][j * 4 + k] = d1 / 3;
            }
         }
      }
   }

   if (com.codonf == FMutSel0) {
      for (j = 0, zero(com.piAA, 20); j < com.ncode; j++)
         com.piAA[GeneticCode[com.icode][FROM61[j]]] += com.pi[j];
      matout(F0, com.piAA, 1, 20);
   }

   if (com.codonf >= F1x4 && com.codonf <= FMutSel)
      com.pf3x4 = com.f3x4[0];

   if (com.verbose && com.ngene == 1) {
      fprintf(fout, "\n\nCodon frequencies under model, for use in evolver (TTT TTC TTA TTG ... GGG):\n");
      for (k = 0; k < 64; k++) {
         fprintf(fout, "%12.8f", GeneticCode[com.icode][k] == -1 ? 0 : com.pi[FROM64[k]]);
         if ((k + 1) % 4 == 0) FPN(fout);
      }
      /*
      fprintf(fout, "\nWrong order: AAA AAC AAG AAT ... TTT\n");
      for(k=0; k<64; k++) {
         ic[0] = wrongorder[k/16];
         ic[1] = wrongorder[(k/4)%4];
         ic[2] = wrongorder[k%4];
         j = ic[0]*16+ic[1]*4+ic[2];
         if(GeneticCode[com.icode][j]!=-1)
            fprintf(fout,"%.8f, ", com.pi[FROM64[j]]);
      }
      exit(0);
      */
   }
   return(0);
}


int AA2Codonf(double faa[20], double fcodon[])
{
   /* get codon freqs from amino acid freqs, assuming equal freq. for each syn
      codon.  Used in codon-based amino acid substitution models.
   */
   int ic, iaa, i, NCsyn[20];

   for (iaa = 0; iaa < 20; iaa++) 
      NCsyn[iaa] = 0;
   for (ic = 0; ic < 64; ic++) {
      iaa = GeneticCode[com.icode][ic];
      if (iaa != -1) NCsyn[iaa]++;
   }
   zero(fcodon, 64);
   for (ic = 0; ic < Nsensecodon; ic++) {
      iaa = GeneticCode[com.icode][FROM61[ic]];
      fcodon[ic] += faa[iaa] / NCsyn[iaa];
   }
   if (fabs(1 - sum(fcodon, 64)) > 1e-6) printf("\n1 == %12.7f\n", sum(fcodon, 64));
   return (0);
}


int DistanceMatAA(FILE *fout)
{
   int i, j, h;
   double p, lst;

   if (fout) fprintf(fout, "\nAA distances (raw proportions of different sites)\n");
   for (h = 0, lst = 0; h < com.npatt; h++)  lst += com.fpatt[h];
   for (i = 0; i < com.ns; i++) {
      if (fout) fprintf(fout, "\n%-15s", com.spname[i]);
      for (j = 0; j < i; j++) {
         for (h = 0, p = 0; h < com.npatt; h++)
            if (com.z[i][h] != com.z[j][h]) p += com.fpatt[h];
         p /= lst;
         SeqDistance[i*(i - 1) / 2 + j] = p;
         if (fout) fprintf(fout, " %7.4f", p);
      }
   }
   if (fout) FPN(fout);
   return (0);
}


int GetDaa(FILE* fout, double daa[])
{
   /* Get the amino acid distance (or substitution rate) matrix
      (grantham, dayhoff, jones, etc).
   */
   FILE * fdaa;
   char aa3[4] = "";
   int i, j, naa = 20;
   double dmax = 0, dmin = 1e40;

   if (noisy > 3) printf("\n\nReading matrix from %s", com.daafile);
   if (com.model == REVaa_0 || com.model == REVaa) puts(", to get initial values.");
   fdaa = gfopen(com.daafile, "r");

   for (i = 0; i < naa; i++)
      for (j = 0, daa[i*naa + i] = 0; j < i; j++) {
         fscanf(fdaa, "%lf", &daa[i*naa + j]);
         daa[j*naa + i] = daa[i*naa + j];
         if (dmax < daa[i*naa + j]) dmax = daa[i*naa + j];
         if (dmin > daa[i*naa + j]) dmin = daa[i*naa + j];
      }
   if (com.aaDist && (com.seqtype == 1 || com.model == FromCodon)) { /* codon model */
      if (noisy) printf("\ndistance: %.2f --- %.2f\n", dmin, dmax);
      for (i = 0; i < naa; i++)
         for (j = 0; j < naa; j++)
            com.daa[i*naa + j] /= dmax;
   }
   else if (com.seqtype == AAseq) {
      for (i = 0; i < naa; i++)
         for (j = 0; j < i; j++)
            if (i*naa + j != ijAAref)
               daa[j*naa + i] = daa[i*naa + j] /= com.daa[ijAAref];
      daa[ijAAref] = daa[(ijAAref%naa)*naa + (ijAAref / naa)] = 1;

      if (com.model == Empirical) {
         for (i = 0; i < naa; i++)
            if (fscanf(fdaa, "%lf", &com.pi[i]) != 1)
               error2("aaRatefile");
         if (fabs(1 - sum(com.pi, 20)) > 1e-5) {
            printf("\nSum of freq. = %.6f != 1 in aaRateFile\n", sum(com.pi, naa));
            exit(-1);
         }
      }
   }
   fclose(fdaa);

   if (fout) {
      fprintf(fout, "\n%s\n", com.daafile);
      for (i = 0; i < naa; i++) {
         fprintf(fout, "\n%4s", getAAstr(aa3, i));
         for (j = 0; j < i; j++)
            fprintf(fout, "%5.0f", daa[i*naa + j]);
      }
      FPN(fout);
   }

   /*
   SetAA1STEP();
   for(i=0,FPN(frst);i<naa;i++,FPN(frst))
      FOR(j,i) fprintf(frst,"%3d",AA1STEP[i*(i-1)/2+j]);

   for(i=0,k=0;i<naa;i++)
      FOR(j,i) if(AA1STEP[i*(i-1)/2+j]) {
         fprintf(frst,"%c%c\t%.2f\n",AAs[i],AAs[j],com.daa[i*naa+j]);
         k++;
      }
   fprintf(frst,"\n%d one-step amino acid pairs\n", k);
   exit (0);
   */

   return (0);
}


int SetAA1STEP(void)
{
   /* Sets the global variable AA1STEP[19*20/2].
      Sets com.nrate for models like AAClasses and REVaa_0.
      AA1STEP[k] marks the k_th pair of amino acids that differ at one position,
      Q[i*naa+j] is the k_th nonzero element if AA1STEP[k]=i*naa+j;
      Lower diagonal of Q is visited, with i>j.
   */
   int ncode0 = com.ncode, nc, naa = 20, i, j, k, ic1, ic2, ndiff, from[3], to[3];
   int *Q = (int*)PMat;

   setmark_61_64();
   nc = Nsensecodon;  com.ncode = ncode0;
   for (i = 0; i < naa*naa; i++) Q[i] = 0;
   for (i = 0; i < nc; i++)
      for (j = 0; j < i; j++) {
         ic1 = FROM61[i]; from[0] = ic1 / 16; from[1] = (ic1 / 4) % 4; from[2] = ic1 % 4;
         ic2 = FROM61[j];   to[0] = ic2 / 16;   to[1] = (ic2 / 4) % 4;   to[2] = ic2 % 4;
         for (k = 0, ndiff = 0; k < 3; k++)  if (from[k] != to[k]) ndiff++;
         if (ndiff != 1)  continue;
         ic1 = GeneticCode[com.icode][ic1];
         ic2 = GeneticCode[com.icode][ic2];
         Q[ic1*naa + ic2]++;
         Q[ic2*naa + ic1]++;
      }
   /*
   #if DEBUG
         for (i=0,FPN(F0); i<naa; i++,FPN(F0)) FOR(j,i)printf("%3d",Q[i*naa+j]);
   #endif
   */
   for (i = 0, k = 0; i < naa; i++)
      for (j = 0; j < i; j++) {
         if (Q[i*naa + j] > 0) { AA1STEP[i*(i - 1) / 2 + j] = 1;  k++; }
         else                AA1STEP[i*(i - 1) / 2 + j] = 0;
      }
   /*
   for(i=0,FPN(F0);i<naa;i++,FPN(F0)) FOR(j,i)printf("%3d",AA1STEP[i*(i-1)/2+j]);
   */
   if (com.seqtype == 2) com.nrate = k - 1;     /* one element (ijAAref) is fixed */

   return(0);
}

int GetOmegaAA(int OmegaAA[])
{
   /* This routine reads the file OmegaAA.dat to initialize the
      lower diagonal matrix OmegaAA, which specifies the aa substituion
      rate classes.  To be used with the codon substitution model
      AAClasses, which specifies several classes of the dN/dS ratio.

      OmegaAA[iaa*(iaa-1)/2+jaa]= -1 if no one-step change is possible;
                                = 0 for the first, background, class
                                = i (1,..,nclass) if iaa and jaa are in class i
   */
   char *OmegaAAf = "OmegaAA.dat", line[1024];
   FILE *fin = NULL;
   int iomega, n1step = 0, i, j, k, iaa, jaa, npair, naa = 20, nline = 1024;

   for (i = 0, n1step = 0; i < naa; i++) for (j = 0; j < i; j++)
      if (AA1STEP[i*(i - 1) / 2 + j]) { OmegaAA[i*(i - 1) / 2 + j] = 0;  n1step++; }
      else                        OmegaAA[i*(i - 1) / 2 + j] = -1;
      if (noisy) {
         printf("\n\n%d one-step aa pairs.\n", n1step);
         printf("Reading omega class from %s.\n", OmegaAAf);
      }
      com.nOmegaType = -1;
      fin = fopen(OmegaAAf, "r");
      if (fin) fscanf(fin, "%d", &com.nOmegaType);
      if (com.nOmegaType < 1 || com.nOmegaType>65 - 1) {
         if (com.seqtype != CODONseq) puts("\nTo be tested.\a");
         com.nOmegaType = 0;
         if (com.seqtype == AAseq) {
            for (i = 0; i < naa; i++) for (j = 0; j < i; j++) if (i*naa + j != ijAAref && AA1STEP[i*(i - 1) / 2 + j])
               OmegaAA[i*(i - 1) / 2 + j] = com.nOmegaType++;
         }
         else
            for (i = 0; i < naa; i++) for (j = 0; j < i; j++)
               if (AA1STEP[i*(i - 1) / 2 + j]) OmegaAA[i*(i - 1) / 2 + j] = com.nOmegaType++;
         printf("%d dN/dS ratios estimated from data.\n", com.nOmegaType);
      }
      else {
         printf("%d dN/dS ratios estimated from data.\n", com.nOmegaType);
         for (iomega = 0; iomega < com.nOmegaType - 1; iomega++) {
            fscanf(fin, "%d", &j);
            if (j != iomega + 1) { printf("err data file %s.", OmegaAAf); exit(-1); }
            printf("\nClass #%d: ", j);
            j = fgetc(fin);  if (j != ':') error2("err expecting :");
            fgets(line, nline, fin);

            printf("%s\n", line);
            for (j = 0, npair = 0; j < nline - 1 && line[j] && line[j] != '\n'; j++) {
               iaa = line[j];
               if (!isalpha(iaa)) continue;
               jaa = line[++j];  if (!isalpha(jaa)) error2("err jaa");
               npair++;

               printf("\npair %2d: |%c%c| ", npair, iaa, jaa);
               iaa = CodeChara((char)iaa, AAseq); jaa = CodeChara((char)jaa, AAseq);
               if (iaa < 0 || iaa>19 || jaa < 0 || jaa>19) error2("aa not found");
               if (iaa < jaa) { k = jaa, jaa = iaa; iaa = k; }

               printf("|%c%c (%2d,%2d)| ", AAs[iaa], AAs[jaa], iaa, jaa);
               if (iaa == jaa) puts("This pair has no effect.");
               if (OmegaAA[iaa*(iaa - 1) / 2 + jaa] == -1) {
                  puts("\nThis pair cannot change in one step and is ignored!");
                  continue;
               }
               else if (OmegaAA[iaa*(iaa - 1) / 2 + jaa])
                  error2("This pair has already been specified?");
               OmegaAA[iaa*(iaa - 1) / 2 + jaa] = iomega + 1;
               printf(" in class %d ", iomega + 1);
            }
         }
      }
      if (fin) fclose(fin);
      com.nrate = com.nkappa = (com.hkyREV ? 5 : !com.fix_kappa);
      com.nrate += (com.nOmega = com.nOmegaType);
      /*
         for (i=0; i<naa; i++,FPN(F0))
             for(j=0; j<i; j++) printf ("%3d", OmegaAA[i*(i-1)/2+j]);
      */
      return (0);
}



int GetCodonFreqs2(void)
{
   /* Recalcualte the expected codon frequencies (com.pi[]) using the control
      variable com.codonf, and the observed codon frequencies in com.pi[].
      com.pi[] is both input (observed codon frequencies) and output (expected
      frequencies under the model codonf).
      This is used by PairwiseCodon().
   */
   int n = com.ncode, i, j, ic, b[3];
   double *pi = com.pi, fb3x4[12], fb4[4], GC[3] = { 0 };

   if (com.codonf == Fequal)
   {
      fillxc(pi, 1. / n, n); return 0;
   }
   if (com.codonf != Fcodon && com.codonf != FMutSel) {
      for (i = 0, zero(fb3x4, 12), zero(fb4, 4); i < n; i++) {
         ic = FROM61[i];  b[0] = ic / 16; b[1] = (ic / 4) % 4; b[2] = ic % 4;
         for (j = 0; j < 3; j++)
         {
            fb3x4[j * 4 + b[j]] += pi[i];  fb4[b[j]] += pi[i] / 3.;
         }
      }
      for (i = 0; i < n; i++) {
         ic = FROM61[i];  b[0] = ic / 16; b[1] = (ic / 4) % 4; b[2] = ic % 4;
         if (com.codonf == F3x4 || com.codonf == F3x4MG)
            pi[i] = fb3x4[b[0]] * fb3x4[4 + b[1]] * fb3x4[8 + b[2]];
         else
            pi[i] = fb4[b[0]] * fb4[b[1]] * fb4[b[2]];
      }

      if (com.codonf == F1x4MG)
         for (j = 0; j < 3; j++)
            xtoy(fb4, com.pf3x4 + j * 4, 4);
      else if (com.codonf == F3x4MG)
         xtoy(fb3x4, com.pf3x4, 12);

      abyx(1. / sum(pi, n), pi, n);

      GC[0] = (fb3x4[0 + 1] + fb3x4[0 + 3]) * 100;
      GC[1] = (fb3x4[4 + 1] + fb3x4[4 + 3]) * 100;
      GC[2] = (fb3x4[8 + 1] + fb3x4[8 + 3]) * 100;
      /*  fprintf(frst1, "\tGC123\t%.1f\t%.1f\t%.1f", GC[0],GC[1],GC[2]);  */
   }
   return 0;
}


double lfun2dSdN(double x[], int np)
{
   /* likelihood function for calculating dS and dN between 2 sequences,
      com.z[0] & com.z[1:
            f(i,j) = \pi_i * p_{ij}(t)

      Data are clean and coded.
      Transition probability pijt is calculated for observed patterns only.
   */
   int n = com.ncode, h, i, k, ik, z0, z1;
   double lnL = 0, fh, expt[NCODE], mr = 0;

   NFunCall++;
   k = 1, ik = 0;
   if (com.hkyREV == 0) {
      if (com.fix_kappa == 1) { com.pkappa[0] = com.kappa;  ik = 1; }
      else                   com.kappa = x[k]; /* Is this necessary? */
   }
   for (i = 0; i < (com.hkyREV ? 5 : !com.fix_kappa); i++)
      com.pkappa[ik++] = x[k++];
   if (com.codonf == FMutSel)
      for (i = 0; i < 3; i++)
         com.pkappa[ik++] = x[k++];

   if (!com.fix_omega) com.omega = x[1 + com.nkappa];
   if (!com.fix_kappa || !com.fix_omega)
      eigenQcodon(1, -1, NULL, NULL, NULL, Root, U, V, &mr, com.pkappa, com.omega, PMat);

   for (k = 0; k < n; k++)
      expt[k] = exp(x[0] * Root[k]);
   for (h = 0; h < com.npatt; h++) {
      if (com.fpatt[h] < 1e-20) continue;
      z0 = com.z[0][h];
      z1 = com.z[1][h];
      for (k = 0, fh = 0; k < n; k++)
         fh += U[z0*n + k] * expt[k] * V[k*n + z1];
      fh *= com.pi[z0];
      if (fh <= 0) {
         matout(F0, x, 1, np);
         printf("lfun2dSdN: fh = %.9f\n", fh);
         fh = 1e-70;
      }
      lnL -= log(fh) * com.fpatt[h];
   }
   return (lnL);
}


int VariancedSdN(double t, double omega, double vtw[2 * 2], double vdSdN[2 * 2])
{
   /* This calculates the covariance matrix of dS & dN, using the
      difference approximation, from the covariance matrix of t and
      omega (vtw).  com.kappa and com.pi are used.  Sampling errors
      in parameters other than t and omega, such as kappa and pi[],
      are ignored.
            JacobiSN = {{dS/dt, dS/dw}, {dN/dt,dN/dw}}
   */
   int np = 2;
   double JacobiSN[2 * 2], T1[2 * 3], T2[2 * 3], S, dS, dN, dS1, dN1, dS2, dN2, eh, mr = 0;

   if (vtw[0] <= 0 || vtw[3] <= 0) {
      puts("var(dS,dN) not calculable.");
      zero(vdSdN, 4);
      return(-1);
   }

   /* printf("\nt & w: %.5f %.5f\n", t, omega);
      matout(F0,vtw, 2,2); */
   eigenQcodon(2, t, &S, &dS, &dN, NULL, NULL, NULL, &mr, com.pkappa, omega, PMat);

   eh = (t + 1)*Small_Diff;
   eigenQcodon(2, t + eh, &S, &dS1, &dN1, NULL, NULL, NULL, &mr, com.pkappa, omega, PMat);
   eigenQcodon(2, t - eh, &S, &dS2, &dN2, NULL, NULL, NULL, &mr, com.pkappa, omega, PMat);
   JacobiSN[0 * np + 0] = (dS1 - dS2) / (2 * eh);
   JacobiSN[1 * np + 0] = (dN1 - dN2) / (2 * eh);

   eh = (omega + 1)*Small_Diff;
   eigenQcodon(2, t, &S, &dS1, &dN1, NULL, NULL, NULL, &mr, com.pkappa, omega + eh, PMat);
   eigenQcodon(2, t, &S, &dS2, &dN2, NULL, NULL, NULL, &mr, com.pkappa, omega - eh, PMat);
   JacobiSN[0 * np + 1] = (dS1 - dS2) / (2 * eh);
   JacobiSN[1 * np + 1] = (dN1 - dN2) / (2 * eh);

   matby(JacobiSN, vtw, T1, 2, 2, 2);
   mattransp2(JacobiSN, T2, 2, 2);
   matby(T1, T2, vdSdN, 2, 2, 2);

   /* matout(F0,vdSdN, 2,2); */

   return (0);
}

double distanceHKY85(double x[], double *kappa, double alpha);
int distance3pos(double dHKY[], double kHKY[], int *sites4, char *z1, char *z2);

int distance3pos(double dHKY[], double kHKY[], int *sites4, char *z1, char *z2)
{
   /* This calculates nucleotide-based distances between two protein-coding
      DNA sequences z1 and z2, both of which are coded.  com.cleandata = 1 is
      assumed.
   */
   int i, j, h, k, ic1, ic2, from[3], to[3];
   double fij[4][16] = { {0} }, pi4[4] = { 0 };
   /* [0,1,2] are for 3 positions, [3] is for 4-fold */

   for (h = 0; h < com.npatt; h++) {
      ic1 = FROM61[(int)z1[h]]; from[0] = ic1 / 16; from[1] = (ic1 / 4) % 4; from[2] = ic1 % 4;
      ic2 = FROM61[(int)z2[h]];   to[0] = ic2 / 16;   to[1] = (ic2 / 4) % 4;   to[2] = ic2 % 4;
      for (k = 0; k < 3; k++)
         fij[k][from[k] * 4 + to[k]] += com.fpatt[h] / com.ls;
      if (from[0] == to[0] && from[1] == to[1] && FourFold[to[0]][to[1]])
         fij[3][from[2] * 4 + to[2]] += com.fpatt[h];
   }
   *sites4 = (int)sum(fij[3], 16);

   if (*sites4)
      FOR(k, 16) fij[3][k] /= *sites4;
   FOR(i, 4) FOR(j, 4) pi4[i] += fij[3][i * 4 + j] / 2;
   FOR(i, 4) FOR(j, 4) pi4[j] += fij[3][i * 4 + j] / 2;

   for (k = 0; k < 4; k++)
      dHKY[k] = distanceHKY85(fij[k], &kHKY[k], 0);
   return(0);
}


int PairwiseCodon(FILE *fout, FILE*fds, FILE*fdn, FILE*ft, double space[])
{
   /* Calculates ds & dn for all pairwise codon sequence comparisons.
      It uses different npatt for different pairs.
      The data com.z[] should be encoded clean data, with ambiguity characters
      removed.  Think of what to do with raw unclean data.
      JacobiSN has two columns, the 1st are deratives of dS (dS/dt, dS/dk, dS/dw)
      and the second of dN.
   */
   char *pz0[NS], codon[2][3];   /* pz0, npatt0, & fpatt0 hold the old information */
   int npatt0 = com.npatt;
   double *fpatt0, ls0 = com.ls;
   float fp[NCODE*NCODE];
   int n = com.ncode, is, js, j, k, h, i0, np, wname = 15;
   int nb[3], ib[3][4], ic[2], missing = 0, sites4;
   double x[10] = { .9,1,.5,.5,.5,.5,.3 }, xb[10][2] = { {1e-5,50} }, large = 50;
   double kappab[2] = { .01,999 }, wb[2] = { .001,99 };
   double lnL, e = 1e-7, *var = space + NP, S, dS, dN, mr = 0;
   double JacobiSN[2 * 3], T1[2 * 3], T2[2 * 3], vSN[2 * 2], dS1, dN1, dS2, dN2, y[3], eh;
   /* for calculating SEs of dS & dN */
   double dHKY[4], kHKY[4];

   fpatt0 = (double*)malloc(npatt0 * 3 * sizeof(double));
   FOR(k, com.ns) pz0[k] = com.z[k];
   com.z[0] = (char*)(fpatt0 + npatt0);
   com.z[1] = com.z[0] + npatt0;
   FOR(k, npatt0) fpatt0[k] = (float)com.fpatt[k];

   if (!com.cleandata) puts("\nPairwiseCodon: pairwise deletion.");
   if (com.ngene > 1 && com.Mgene == 1) puts("ngene>1 to be tested.");
   if (noisy > 1) printf("\npairwise comparison (Goldman & Yang 1994).\n");
   fprintf(fout, "\npairwise comparison, codon frequencies: %s.\n",
      codonfreqs[com.codonf]);

   FOR(j, com.nkappa) { xb[1 + j][0] = kappab[0]; xb[1 + j][1] = kappab[1]; }
   if (!com.fix_omega) { k = 1 + com.nkappa; xb[k][0] = wb[0]; xb[k][1] = wb[1]; }

   fprintf(fds, "%6d\n", com.ns);  fprintf(fdn, "%6d\n", com.ns);
   fprintf(ft, "%6d\n", com.ns);
   fprintf(frst, "\n\npairwise comparison (Goldman & Yang 1994)");
   fprintf(frst,
      "\nseq seq        N       S       dN       dS     dN/dS   Paras.\n");

   for (is = 0; is < com.ns; is++) {
      fprintf(fds, "%-*s ", wname, com.spname[is]);
      fprintf(fdn, "%-*s ", wname, com.spname[is]);
      fprintf(ft, "%-*s ", wname, com.spname[is]);
      for (js = 0; js < is; js++) {
         if (noisy > 9) {
            puts("\nInput the pair i & j (i>j) for dN-dS calculation? ");
            scanf("%d%d", &is, &js);
            is--; js--;
            if (is > com.ns || js < 0 || is < js) error2("invalid pair");
         }
         if (noisy > 1) printf("\n%4d vs. %3d", is + 1, js + 1);
         fprintf(fout, "\n\n%d (%s) ... %d (%s)",
            is + 1, com.spname[is], js + 1, com.spname[js]);
         fprintf(frst, "%3d %3d ", is + 1, js + 1);
         if (noisy > 2) fprintf(frub, "\n\n%d (%s) ... %d (%s)",
            is + 1, com.spname[is], js + 1, com.spname[js]);
         for (k = 0; k < n*n; k++) fp[k] = 0;
         if (com.cleandata) {
            for (h = 0; h < npatt0; h++) {
               j = max2(pz0[is][h], pz0[js][h]);
               k = min2(pz0[is][h], pz0[js][h]);
               fp[j*n + k] += (float)fpatt0[h];
            }
         }
         else {
            for (h = 0, com.ls = 0; h < npatt0; h++) {
               FOR(i0, 2) FOR(k, 3) codon[i0][k] = pz0[i0 == 0 ? is : js][h * 3 + k];
               for (i0 = 0, missing = 0; i0 < 2; i0++) {
                  for (k = 0; k < 3; k++)
                     NucListall(codon[i0][k], &nb[k], ib[k]);
                  if (nb[0] * nb[1] * nb[2] != 1)
                  {
                     missing = 1; break;
                  }
                  else
                     ic[i0] = FROM64[ib[0][0] * 16 + ib[1][0] * 4 + ib[2][0]];
               }
               if (missing) continue;
               com.ls += (int)fpatt0[h];

               j = max2(ic[0], ic[1]);
               k = min2(ic[0], ic[1]);
               fp[j*n + k] += (float)fpatt0[h];
            }
         }

         for (j = 0, com.npatt = 0; j < n; j++) {
            for (k = 0; k < j + 1; k++)
               if (fp[j*n + k]) {
                  com.z[0][com.npatt] = (char)j;
                  com.z[1][com.npatt] = (char)k;
                  com.fpatt[com.npatt++] = fp[j*n + k];
               }
         }
         if (noisy > 2) printf("\n  npatt=%d ", com.npatt);
         for (j = 0, zero(com.pi, n); j < com.npatt; j++) {
            com.pi[(int)com.z[0][j]] += com.fpatt[j] / (2.*com.ls);
            com.pi[(int)com.z[1][j]] += com.fpatt[j] / (2.*com.ls);

         }
         GetCodonFreqs2();

         distance3pos(dHKY, kHKY, &sites4, com.z[0], com.z[1]);

         np = com.np = (com.ntime = 1) + com.nkappa + !com.fix_omega;
         NFunCall = 0;

         /* initial values and bounds */
         x[0] = SeqDistance[is*(is - 1) / 2 + js] * (0.8 + 0.3*rndu());
         if (x[0] > 3) x[0] = 1.5 + rndu();
         if (x[0] < 1e-6) x[0] = .5*rndu();
         if (com.nkappa == 1) { /* HKY type model */
            if (is == 0 && js == 1)  x[1] = (com.icode == 1 ? 4 : 1.5) + rndu();
            else                x[1] = (x[1] * 2 + 2 + rndu()) / 3;
            if (x[1] > 10) x[1] = 5;
            xb[1][0] = 0.4;
         }
         else         /* REV or FMutSel models, do something later */
            for (j = 1, x[1] = .8 + .4*rndu(); j < com.nkappa; j++)
               x[1 + j] = .2 + .4*rndu();

         if (!com.fix_omega) {
            k = 1 + com.nkappa;
            if (is == 0 && js == 0) x[k] = 0.2 + 0.2*rndu();
            else               x[k] = (3 * x[k] + 0.6*rndu()) / 4;
            x[k] = max2(x[k], 0.01);
            x[k] = min2(x[k], 2);
         }

         if (noisy >= 9) {
            FPN(F0);  FOR(k, np) printf(" %12.6f", x[k]); FPN(F0);
            FOR(k, np) printf(" %12.6f", xb[k][0]); FPN(F0);
            FOR(k, np) printf(" %12.6f", xb[k][1]); FPN(F0);
         }

         if (com.fix_kappa && com.fix_omega)
            eigenQcodon(1, -1, NULL, NULL, NULL, Root, U, V, &mr, com.pkappa, com.omega, PMat);


         if (com.runmode == -3) { //kostas, save values 
            x[4] = x[0];
            x[5] = x[2];
         }


         if (np)
            ming2(noisy > 3 ? frub : NULL, &lnL, lfun2dSdN, NULL, x, xb, space, e, np);
         else { x[1] = x[2] = com.kappa = com.omega = 0; lnL = 0; }

         lnLmodel = lnL;
         fprintf(fout, "\nlnL =%12.6f\n", -lnL);
         FOR(k, np) fprintf(fout, " %8.5f", x[k]);  FPN(fout);

         if (noisy > 2) {
            printf("\n\nt_NG = %.5f\tMLEs: ", SeqDistance[is*(is - 1) / 2 + js]);
            for (k = 0; k < np; k++) printf(" %.5f", x[k]);
         }

         if (np && com.getSE) {
            Hessian(np, x, lnL, space, var, lfun2dSdN, var + np*np);
            matinv(var, np, np, var + np*np);
            fprintf(fout, "SEs for parameters:\n");
            FOR(k, np) fprintf(fout, " %8.5f", (var[k*np + k] > 0. ? sqrt(var[k*np + k]) : -0));
            FPN(fout);
         }
         FPN(fout);
         eigenQcodon(2, x[0], &S, &dS, &dN, NULL, NULL, NULL, &mr, com.pkappa, com.omega, PMat);

         if (noisy >= 3) {
            puts("\nNucleotide-based analysis (approximate MLEs; use baseml to get proper MLEs):");
            printf("\ndHKY (123-4):");  FOR(k, 4) printf(" %8.5f", dHKY[k]);
            printf("\nkHKY (123-4):");  FOR(k, 4) printf(" %8.5f", kHKY[k]);
            printf(" (%d four-fold sites)\n", sites4);
         }

         fprintf(fds, " %7.4f", dS);   fprintf(fdn, " %7.4f", dN);
         fprintf(ft, " %7.4f", x[0]);

         fprintf(fout,
            "t= %6.4f  S= %7.1f  N= %7.1f  dN/dS= %7.4f  dN =%7.4f  dS =%7.4f\n",
            x[0], S, com.ls * 3 - S, com.omega, dN, dS);

         fprintf(frst, "%8.1f %8.1f %8.4f %8.4f %8.4f", com.ls * 3 - S, S, dN, dS, com.omega);
         for (k = 0; k < np; k++) fprintf(frst, " %8.4f", x[k]);

         for (k = 0; k < np; k++) fprintf(frst1, "\t%.4f", x[k]);
         fprintf(frst1, "\t%.3f", -lnL);
         fprintf(frst1, "\t%.4f\t%.4f", dN, dS);

         k = np - 1;
         if (com.getSE)
            fprintf(frst, " +-%6.4f", (var[k*np + k] > 0. ? sqrt(var[k*np + k]) : -1));
         fprintf(frst, " %9.3f\n", -lnL);
         if (com.getSE && !com.fix_omega) {
            FOR(k, np) {
               FOR(j, np) y[j] = x[j];
               y[k] += (eh = (x[k] + 1)*Small_Diff);
               if (!com.fix_kappa) com.kappa = y[1];
               com.omega = y[1 + !com.fix_kappa];
               eigenQcodon(2, y[0], &S, &dS1, &dN1, NULL, NULL, NULL, &mr, com.pkappa, com.omega, PMat);
               y[k] -= 2 * eh;
               if (!com.fix_kappa) com.kappa = y[1];
               com.omega = y[1 + !com.fix_kappa];
               eigenQcodon(2, y[0], &S, &dS2, &dN2, NULL, NULL, NULL, &mr, com.pkappa, com.omega, PMat);

               JacobiSN[0 * np + k] = (dS1 - dS2) / (2 * eh);
               JacobiSN[1 * np + k] = (dN1 - dN2) / (2 * eh);
            }

            matby(JacobiSN, var, T1, 2, np, np);
            mattransp2(JacobiSN, T2, 2, np);
            matby(T1, T2, vSN, 2, np, 2);
            /*
                        fputs("\nvar(dS,dN):\n", fout);
                        matout(fout,vSN,2,2);
            */
            fprintf(fout, "dN = %7.5f +- %.5f   dS = %7.5f +- %.5f",
               dN, (vSN[3] > 0 ? sqrt(vSN[3]) : -0), dS, (vSN[0] > 0 ? sqrt(vSN[0]) : -0));
            fprintf(fout, " (by method 1)\n");

            T1[0] = var[0];
            T1[1] = T1[2] = var[0 * np + np - 1];
            T1[3] = var[(np - 1)*np + (np - 1)];
            if (com.getSE && !com.fix_omega)
               VariancedSdN(x[0], x[np - 1], T1, vSN);

            fprintf(fout, "dN = %7.5f +- %.5f   dS = %7.5f +- %.5f",
               dN, (vSN[3] > 0 ? sqrt(vSN[3]) : -0), dS, (vSN[0] > 0 ? sqrt(vSN[0]) : -0));
            fprintf(fout, " (by method 2)\n");

         }


         if (com.runmode == -3)  BayesPairwise(is, js, x, var, lnL, 32, xb, space); //kostas

         fflush(frst);  fflush(fout);
      }  /* for (js) */
      FPN(fds); FPN(fdn); FPN(ft);
      fflush(fds); fflush(fdn); fflush(ft);
   }     /* for (is) */

   com.ls = (int)ls0;   FOR(k, com.ns) com.z[k] = pz0[k];
   com.npatt = npatt0;  FOR(h, npatt0) com.fpatt[h] = fpatt0[h];  free(fpatt0);
   return (0);
}






//kostas
int BayesPairwise(int is, int js, double x[], double var[], double maxlogl,
   int npoints, double xb[][2], double space[])
{
   /*This function returns estimates of E[ t | x ], E[ w | x ], Var[ t | x ], Var[ w | x ],
   Cov[ w,t | x ], Corr[ w,t | x], P[ w>1 | x ]
   */
   const double *nodes = NULL, *weights = NULL;  //contain the points and weights
   double interm_results[7] = { 0,0,0,0,0,0,0 }; //contain the normalizing_constant, E[w|x], E[t|x], E[w^2|x], E[t^2|x], E[w*t|x], P[w>1|x]  
   register int i = 0, j = 0;
   int w_index = 0, t_index = 0, way = 0, setp = 0;
   double w_value, t_value, w_weight, t_weight, sign, scalefactor = 0, Qmatrix[64 * 64],
      z1, z2, logl, logposterior, hvalue, m1, m2, s1, s2, rvalue,
      bayes_est[7], maxlogP, e = 1e-7, xp[2], kappa[1], pS, pN, sdiff[3] = { 1e-7, 1e-8, 1e-9 };
   double FL, alpha, u, w_p, Rp[64 * 64], Up[64 * 64], Vp[64 * 64], PMatp[64 * 64], logl_p, logposterior_p,
      hvalue_p, qvalue;  //For calculation of P(w>1|x)
   char ch1[] = "E[t]", ch2[] = "E[w]", ch3[] = "SE[t]", ch4[] = "SE[w]",
      ch5[] = "Cov[t,w]", ch6[] = "Corr[t,w]", ch7[] = "P[w > 1]";


   if (com.fix_kappa == 1 && com.fix_omega == 0) {
      x[2] = x[1];
      x[1] = com.kappa;
   }
   if (com.fix_omega == 1)
      return (1);

   pS = Sd / SS; pN = Nd / NN;
   if (pS == 0 && pN == 0) { x[1] = 2; }      //fix value of k at 2 when sequences are identical

   if (com.codonf == 3) {
      for (i = 0; i < 61; i++) {
         if (com.pi[i] < 1e-15) com.pi[i] = 1e-15;
      }
   }

   if ((pS > 0 && pS < 0.74) && (pN > 0 && pN < 0.74) && x[0] > 0.001 && x[0] < 10 && x[2] > 0.005 && x[2] < 5) {
      // Choice of 0.001, 0.005, 5 and 10 is arbitrary. We just need to exclude extreme 
      // values because extreme values are shrinked and if we use the MLES to define
      // the location parameters of logistic distributions the transformation won't be proper  
      way = 0;
      EstVariances(var);
   }
   else {
      way = 1;

      if (x[0] < 10) xp[0] = x[0]; else xp[0] = x[4]; //initial t value for ming2. MAP is usually far from an extreme ML value for a prior mean   ~1.
      if (x[2] < 10) xp[1] = x[2]; else xp[1] = x[5]; //initial w value for ming2. MAP is usually far from an extreme ML value for a prior mean ~0.5.

      if (pS == 0 && pN == 0)    xp[1] = com.hyperpar[2] / com.hyperpar[3];  //in case of identical sequences posterior mean would be close to the prior mean
      //Set the boundaries for minimization 
      xb[0][0] = 1e-5;   xb[0][1] = 100;
      xb[1][0] = 1e-5;   xb[1][1] = 200;

      if (com.fix_kappa == 0) {
         com.fix_kappa = 1;  com.kappa = x[1]; com.nkappa = 0, com.np = 2;
      }

      x[5] = Small_Diff;   //Store the value of Small_Diff. I return the initial value back below.   
      Small_Diff = 1e-9;

      ming2(NULL, &maxlogP, logP, NULL, xp, xb, space, e, 2);
      printf("\nMAPs:  %.5f  %.5f\n", xp[0], xp[1]);

      Small_Diff = 1e-6;

      Hessian(2, xp, maxlogP, space, var, logP, var + 2 * 2);
      //Explores whether different values 1e-9 <= Small_Diff <= 1e-7 give appropriate Hessian matrix (No negative or zero variance after Hessian inversion)
      if ((var[0] * var[3] - var[1] * var[2]) < 0 || var[0] < 0) {  //check condition for local minimum
         for (i = 0; i < 3; i++) {
            Small_Diff = sdiff[i];
            Hessian(2, xp, maxlogP, space, var, logP, var + 2 * 2);
            if ((var[0] * var[3] - var[1] * var[2]) > 0 && var[0] > 0) break;
            if (i == 2) {
               fprintf(fout, "MAPs:\n  %.5f  %.5f\n", xp[0], xp[1]);
               printf("Can't estimate Hessian");
               return (1);
            }
         }
      }//end of if

      Small_Diff = x[5];   //Restore the initial value of Small_Diff    
      matinv(var, 2, 2, var + 2 * 2);
      x[0] = xp[0]; x[2] = xp[1]; var[1] = var[3];
   }  // end of else

   m1 = log(x[0]);  //location parameter of logistic distribution for transformation of t
   m2 = log(x[2]);  //location parameter of logistic distribution for transformation of w
   s1 = (1 / x[0]) * sqrt(var[0]);  //scale parameter of logistic distribution for transformation of t
   s2 = (1 / x[2]) * sqrt(var[1]);  //scale parameter of logistic distribution for transformation of w    
   kappa[0] = x[1];
   GaussLegendreRule(&nodes, &weights, npoints);

   //For P(w>1|x) calculation
   FL = CDFLogis(0, m2, s2);
   if (FL > 1 - 1e-5) { bayes_est[6] = 0, setp = 1; }  //If all the mass of posterior density is below 1, set P(w>1|x)=0
   if (FL < 1e-5) { bayes_est[6] = 1, setp = 1; }  //If all the mass of posterior density is above 1, set P(w>1|x)=1
   if (setp == 0)   alpha = 2 * FL - 1;

   for (i = 0; i < npoints; i++) {  //count for omega
      if (i < npoints / 2) { w_index = npoints / 2 - 1 - i; sign = -1; }
      else { w_index = i - npoints / 2;     sign = 1; }
      z2 = sign*nodes[w_index];
      w_weight = weights[w_index];  //weight for omega value                            
      w_value = logistic_transformation(z2, m2, s2); //value of omega after logistic transformation

      eigenQcodon(1, -1, NULL, NULL, NULL, Root, U, V, &scalefactor, kappa, w_value, Qmatrix);  //estimate Root,U,V for the scaled Qmatrix

     //For P(w>1|x) calculation
      if (setp == 0) {
         u = ((1 - alpha) * z2 + 1 + alpha) / 2;
         w_p = logistic_transformation(u, m2, s2);
         eigenQcodon(1, -1, NULL, NULL, NULL, Rp, Up, Vp, &scalefactor, kappa, w_p, Qmatrix);  //estimate Rp,Up,Vp for the scaled Qmatrix for the calculation of P(w>1|x)
      }

      for (j = 0; j < npoints; j++) {  //count for distance
         if (j < npoints / 2) { t_index = npoints / 2 - 1 - j; sign = -1; }
         else { t_index = j - npoints / 2;     sign = 1; }
         z1 = sign * nodes[t_index];
         t_weight = weights[t_index];
         t_value = logistic_transformation(z1, m1, s1); //value of distance after logistic transformation

         PMatUVRoot(PMat, t_value, com.ncode, U, V, Root);  //calculate Ptmatrix

         logl = loglikelihood(PMat);
         logposterior = logl + logprior(t_value, w_value, com.hyperpar);

         if (way == 0) hvalue = exp(logposterior + maxlogl);  //way is 0 or 1
         else			  hvalue = exp(logposterior + maxlogP);

         rvalue = (hvalue * 2 * t_value * s1 * 2 * w_value * s2) / ((1 - square(z1)) * (1 - square(z2)));


         // For P(w>1|x) calculation
         if (setp == 0) {
            PMatUVRoot(PMatp, t_value, com.ncode, Up, Vp, Rp);
            logl_p = loglikelihood(PMatp);
            logposterior_p = logl_p + logprior(t_value, w_p, com.hyperpar);

            if (way == 0) hvalue_p = exp(logposterior_p + maxlogl);  //way is 0 or 1
            else          hvalue_p = exp(logposterior_p + maxlogP);

            qvalue = (hvalue_p * 2 * t_value * s1 * 2 * w_p  * s2 * (1 - alpha)) / ((1 - square(z1)) * (1 - square(u)) * 2);
         }

         interm_results[0] += w_weight * t_weight *                     rvalue; //normalizing constant
         interm_results[1] += w_weight * t_weight * w_value *           rvalue; //unscaled post. mean omega
         interm_results[2] += w_weight * t_weight *           t_value * rvalue; //unscaled post. mean time
         interm_results[3] += w_weight * t_weight * w_value * w_value * rvalue; //unscaled post. mean omega^2
         interm_results[4] += w_weight * t_weight * t_value * t_value * rvalue; //unscaled post. mean time^2
         interm_results[5] += w_weight * t_weight * w_value * t_value * rvalue; //unscaled post. mean omega*time
         if (setp == 0) interm_results[6] += w_weight * t_weight *     qvalue; //for P[w>1|x] calculation

      }  //2nd for closes     
   }  //1st for closes 

   for (i = 1; i <= 6; i++)
      interm_results[i] /= interm_results[0];  //divide everything by the normalizing constant

   bayes_est[0] = interm_results[2]; //posterior mean distance
   bayes_est[1] = interm_results[1]; //posterior mean omega
   bayes_est[2] = interm_results[4] - square(interm_results[2]); //posterior Var distance
   if (bayes_est[2] < 0)  bayes_est[2] = 0;

   bayes_est[3] = interm_results[3] - square(interm_results[1]); //posterior Var omega
   if (bayes_est[3] < 0)  bayes_est[3] = 0;

   bayes_est[4] = interm_results[5] - interm_results[1] * interm_results[2]; //posterior Cov[t,w]

   if (bayes_est[2] != 0 && bayes_est[3] != 0) {
      bayes_est[5] = bayes_est[4] / sqrt(bayes_est[2] * bayes_est[3]);  //posterior Corr[t,w]
   }
   if (setp == 0)   bayes_est[6] = interm_results[6];   // P[w>1|x]

   //print results
   fprintf(fout, "\n\nBayesian estimates of distance and omega\n");
   fprintf(fout, "%14s%14s%14s%14s%15s", ch1, ch2, ch3, ch4, ch5);

   if (bayes_est[2] != 0 && bayes_est[3] != 0) {
      fprintf(fout, "%15s%15s", ch6, ch7);
   }
   else {
      fprintf(fout, "%15s", ch7);
   }

   fprintf(fout, "\n%14.6g%14.6g%14.6g%14.6g%15.6g", bayes_est[0],
      bayes_est[1], sqrt(bayes_est[2]), sqrt(bayes_est[3]), bayes_est[4]);

   if (bayes_est[2] != 0 && bayes_est[3] != 0) {
      fprintf(fout, "%15.6g%15.3g", bayes_est[5], bayes_est[6]);
   }
   else {
      fprintf(fout, "%15.3g", bayes_est[6]);
   }

   return (0);
} //end of function



double loglikelihood(double Ptmatrix[])
{  /*This function returns the logl for 2 sequences given the number of different site patterns (com.npatt),
the number of possible different codons (com.ncode), the positions of codons of the site patterns
into the genetic code (*com.z[]), the frequences of site patterns (com.fpatt[]), the probabilities
of codons in equilibrium (com.pi[]) and the Pt matrix(Ptmatrix[])*/
   int i;
   double logl = 0;
   for (i = 0; i < com.npatt; i++)
      logl += com.fpatt[i] * log(com.pi[(int)com.z[0][i]] * Ptmatrix[com.ncode * (int)com.z[0][i] + (int)com.z[1][i]]);
   return logl;
}


double logistic_transformation(double point, double logmean, double stdlogpar)
{
   double result;
   result = exp(logmean + stdlogpar * log((1 + point) / (1 - point)));
   return result;
}

double logprior(double t, double w, double par[])
{  /*This function returns the log prior function of time and omega(dN/dS)
   par vector contains the shape & scale parameters for time for omega.*/
   double logtprior = -par[1] * t + (par[0] - 1) * log(t) + par[0] * log(par[1]) - LnGamma(par[0]);
   double logwprior = -par[3] * w + (par[2] - 1) * log(w) + par[2] * log(par[3]) - LnGamma(par[2]);
   return logtprior + logwprior;
}

double logP(double x[], int np)
{   /*This function returns the log-posterior. It is used to find the
    mode of the log-posterior. x[0] is for distance and x[1] for w.*/
   return lfun2dSdN(x, np) - logprior(x[0], x[1], com.hyperpar);
}

int EstVariances(double *var) {
   /*This function estimates Var(t) & Var(w) using the
   Nei-Gojobori counting method and stores them in the 1st
   and 2nd place of *var vector respectively*/
   double pS, pN, VarpS, VarpN, hN, hS, VardS, VardN, dS, dN;

   pS = Sd / SS;
   pN = Nd / NN;

   hN = 1 - ((double)4 / 3) * pN;
   hS = 1 - ((double)4 / 3) * pS;

   dS = -0.75 * log(hS);
   dN = -0.75 * log(hN);

   VarpS = (pS * (1 - pS)) / SS;
   VarpN = (pN * (1 - pN)) / NN;

   VardS = square(1 / hS) * VarpS;
   VardN = square(1 / hN) * VarpN;

   var[0] = square((3 * SS) / (SS + NN)) * VardS + square((3 * NN) / (SS + NN)) * VardN;
   var[1] = VardN / square(dS) + (square(dN) * VardS) / square(square(dS));

   return (0);
}

double CDFLogis(double x, double m, double s) {
   return 1 / (1 + exp(-(x - m) / s));
}
//End of kostas code





double lfun2AA(double t)
{
   /* likelihood function for two amino acid sequences
            prob(i,j) = PI_i * p(i,j,t)

      The data are clean & coded (com.z[0] & com.z[1]).
      Transition probability pijt is calculated for observed patterns only.
   */
   int n = 20, h, k, aa0, aa1;
   double lnL = 0, pijt, expt[20], al = com.alpha;

   if (al == 0)  FOR(k, n) expt[k] = exp(t*Root[k]);
   else       FOR(k, n) expt[k] = pow(al / (al - t*Root[k]), al);
   for (h = 0; h < com.npatt; h++) {
      aa0 = com.z[0][h]; aa1 = com.z[1][h];
      for (k = 0, pijt = 0; k < n; k++)
         pijt += U[aa0*n + k] * expt[k] * V[k*n + aa1];
      lnL -= log(com.pi[aa0] * pijt)*com.fpatt[h];
   }
   return(lnL);
}


int _nestS = 0;   /* 189= estimate the S elements, 0= use those from com.daa[] */
static double *_Fij;

double lfun2AArev(double x[], int np)
{
   /* np = _nestS + 19*3 + (1 or 2);
      x[]: Q matrix, 3*pi, 1 or 2 blength
      pi[0] is for the root, pi[1] & pi[2] are for Q[1] & Q[2] for the 2 branches.
      See notes in PairwiseAArev().
   */
   int i, j, k, n = 20;
   double pi[3][20], *p, Q[3][400], *T = Q[0], *Fe = Q[0], t, t1, t2, m1, m2, lnL = 0;
   double space[20 * 20 * 2 + 20 * 2];

   NFunCall++;
   for (k = 0; k < 3; k++) {
      for (i = 0, p = pi[k], p[19] = 1; i < n - 1; i++) p[i] = x[_nestS + k * 19 + i];
      for (i = 0, t = 0; i < n; i++) t += p[i];
      for (i = 0; i < n; i++) p[i] /= t;
   }

   if (_nestS) {
      for (i = 0, k = 0; i < n; i++) {
         for (j = 0, Q[1][i*n + i] = 0; j < i; j++)
            if (i*n + j != ijAAref)
               Q[1][i*n + j] = Q[1][j*n + i] = x[k++];
      }
      Q[1][ijAAref] = Q[1][(ijAAref%n)*n + (ijAAref / n)] = 1;
   }
   else {
      for (i = 0; i < n; i++)
         for (j = 0, Q[1][i*n + i] = 0; j <= i; j++)
            Q[1][i*n + j] = Q[1][j*n + i] = com.daa[i*n + j];
   }

   for (i = 0, m1 = m2 = 0; i < n; i++) {
      for (j = 0, t1 = t2 = 0; j < n; j++) {
         Q[2][i*n + j] = Q[1][i*n + j] * pi[2][j];
         Q[1][i*n + j] *= pi[1][j];
         t1 += Q[1][i*n + j];
         t2 += Q[2][i*n + j];
      }
      Q[1][i*n + i] = -t1;
      Q[2][i*n + i] = -t2;
      m1 += pi[1][i] * t1;
      m2 += pi[2][i] * t2;
   }

   if (com.ntime == 1) { t1 = x[np - 1] / 2 / m1;  t2 = x[np - 1] / 2 / m2; }
   else { t1 = x[np - 2] / m1;    t2 = x[np - 1] / m2; }
   PMatQRev(Q[1], pi[1], t1, n, space);
   PMatQRev(Q[2], pi[2], t2, n, space);

   for (i = 0; i < n*n; i++)  Fe[i] = 0;
   for (k = 0; k < n; k++)
      for (i = 0; i < n; i++)
         for (j = 0, t = pi[0][k] * Q[1][k*n + i]; j < n; j++)
            Fe[i*n + j] += t*Q[2][k*n + j];

   /* if(fabs((t=sum(Fe,n*n))-1)>1e-6) printf("Fe = %.9f != 1\n", t); */

   for (i = 0; i < n*n; i++) {
      if (_Fij[i] <= 1e-15) continue;
      if (Fe[i] > 1e-200)
         lnL -= _Fij[i] * log(Fe[i]);
      else
         printf("Fij_exp = %.10f < 0\n", Fe[i]);
   }
   return(lnL);
}

double PairwiseAArev(int is, int js)
{
   /* This calculates pairwise distance under a nonstationary model.  It assumes
      three sets of amino acid frequencies: pi[0] for the root, pi[1] and pi[2]
      are for the Q matrices for branches 1 and 2.
      It estimate the symmetrical part of the rate matrix if _nestS==189.
      If _nestS==0, it uses the symmetrical part read from the com.daa file.
      It can estimate 1 or 2 distances depending on com.ntime=1 or 2.

      np = 189 + 19*3 + (1 or 2);
      x[]: Q matrix, 3*pi, 1 or 2 blength
   */
   int n = com.ncode, h, i, j, k, np = _nestS + 19 * 3 + 1;
   double Fij[400], x[248], xb[248][2], lnL, e = 1e-9, t = 0, p[20];

   com.ntime = 1;  /* 1: t1=t2; 2: t1 and t2 */
   if (com.ntime == 2) np++;
   _Fij = Fij;
   if (com.cleandata != 1) error2("cleandata");

   if (com.sspace < spaceming2(np)) {
      com.sspace = spaceming2(np);
      printf("\nspace adjusted to %9zu bytes\n", com.sspace);
      if ((com.space = (double*)realloc(com.space, com.sspace)) == NULL)
         error2("oom space");
   }

   for (h = 0, zero(Fij, n*n); h < com.npatt; h++) {
      Fij[com.z[is][h] * n + com.z[js][h]] += com.fpatt[h] / com.ls;
   }

   if (_nestS) {
      for (i = 1, k = 0; i < n; i++)  FOR(j, i)
         if (i*n + j != ijAAref) x[k++] = (com.daa[i*n + j] + .001)*(0.8 + 0.4*rndu());
   }
   for (i = 0; i < np; i++) {
      x[i] = rndu();  xb[i][0] = 1e-5;  xb[i][1] = 100;
   }
   lnL = lfun2AArev(x, np);
   printf("\nlnL0 = %12.6f\n", -lnL);

   ming2(noisy > 2 ? frub : NULL, &lnL, lfun2AArev, NULL, x, xb, com.space, e, np);



   for (k = 0; k < 3; k++) {
      for (i = 0, p[19] = 1; i < n - 1; i++) p[i] = x[_nestS + k * 19 + i];
      for (i = 0, t = 0; i < n; i++) t += p[i];
      for (i = 0; i < n; i++) p[i] /= t;
      matout2(F0, p, 1, n, 7, 4);
   }

   return (x[_nestS + 19 * 3]);
}


int PairwiseAA(FILE *fout, FILE*f2AA)
{
   /* Calculates pairwise distances using amino acid seqs.
      Data (com.z[]) are clean and coded.
      com.npatt for the whole data set is used which may be greater than
      the number of patterns for each pair.
      SE is not calculated.
   */
   char *pz0[NS];
   int n = com.ncode, j, is, js;
   double x, xb[2] = { 0,19 }, lnL, step;

   if (com.ngene > 1 && com.Mgene == 1) error2("ngene>1 to be tested.");
   if (noisy) printf("\npairwise ML distances of AA seqs.\n\n");
   /*
      if(com.model>Empirical_F)  error2("PairwiseAA: model wrong");
   */
   if (com.model == 0)  fillxc(com.pi, 1. / n, n);
   if (com.model >= Empirical)  GetDaa(NULL, com.daa);
   if (com.model == 0 || com.model == Empirical)
      eigenQaa(NULL, Root, U, V, NULL);

   FOR(j, com.ns) pz0[j] = com.z[j];
   fprintf(fout, "\nML distances of aa seqs.\n");
   if (com.alpha)
      fprintf(fout, "\nContinuous gamma with alpha = %.3f is used (ncatG is ignored).\n\n", com.alpha);

   fprintf(f2AA, "%6d\n", com.ns);
   for (is = 0; is < com.ns; is++, FPN(F0), FPN(fout), FPN(f2AA)) {
      printf("%4d vs", is + 1);
      fprintf(f2AA, "%-14s ", com.spname[is]);
      fprintf(fout, "%-14s ", com.spname[is]);
      for (js = 0; js < is; js++) {

         if (com.model == REVaa) {
            x = PairwiseAArev(is, js);
            fprintf(f2AA, " %7.4f", x); fprintf(fout, " %7.4f", x);
            continue;
         }

         com.z[0] = pz0[is]; com.z[1] = pz0[js];
         printf(" %2d", js + 1);
         if (com.model == 1 || com.model == Empirical_F) {
            for (j = 0, zero(com.pi, n); j < com.npatt; j++) {
               com.pi[(int)com.z[0][j]] += com.fpatt[j];
               com.pi[(int)com.z[1][j]] += com.fpatt[j];
            }
            abyx(1. / sum(com.pi, n), com.pi, n);
            eigenQaa(NULL, Root, U, V, NULL);
         }
         /* com.posG[1]=com.npatt; */

         xb[0] = SeqDistance[is*(is - 1) / 2 + js];  x = xb[0] * 1.5;  step = xb[0];
         LineSearch(lfun2AA, &lnL, &x, xb, step, 1e-7);
         fprintf(f2AA, " %7.4f", x); fprintf(fout, " %7.4f", x);
         if (com.getSE);
      }  /* for (js) */
   }     /* for (is) */

   FOR(j, com.ns) com.z[j] = pz0[j];
   return (0);
}


char GetAASiteSpecies(int species, int sitepatt)
{
/* this returns the amino acid encoded by the codon at sitepatt in species.
   Returns '*' if more than two amino acids or '-' if codon is --- or ***.
*/
   int n = com.ncode, c, naa, k;
   char aa = 0, newaa = 0;

   if (com.seqtype != 1)
      error2("GetAASiteSpecies() right now works for codon seqs only.  Check.");
   c = com.z[species][sitepatt];
   if (c < n) {
      aa = AAs[GeneticCode[com.icode][FROM61[c]]];
   }
   else { /* naa is = 1 or >1, precise value being incorrect. */
      for (k = 0, aa = -1; k < nChara[c]; k++) {
         newaa = GeneticCode[com.icode][FROM61[CharaMap[c][k]]];
         if (newaa == -1) continue;
         newaa = AAs[newaa];
         if (aa == -1) {
            naa = 1;
            aa = newaa;
         }
         else
            if (newaa != aa) naa++;
      }
      if (nChara[c] == n)  aa = '-';
      else if (naa > 1)    aa = '*';
   }
   return (aa);
}



int PrintProbNSsites(FILE* frst, double prob[], double meanw[], double varw[], int ncat, int refsp)
{
   /*  This prints out posterior probabilities that each site is from a site class
       under the NSsites mdoels (model=0).
       This is called by both the old empirical Bayes routine (NEB) and also the new
       Bayes empirical Bayes (BEB) routine.
   */
   int h, hp, it, ir, lst = (com.readpattern ? com.npatt : com.ls);
   double psel = 0, wpos = 1, cutoff = 0.5;
   double mpostp[NCATG];
   char  *sig, aa;

   char codons[2][4];
   double St, Nt, ns, na, ndiff;

   if (com.model == 0) {
      fprintf(frst, " & postmean_w");
      if (!BayesEB && com.rK[ncat - 1] > 1)  fprintf(frst, " & P(w>1)");
   }
   fprintf(frst, "\n(amino acids refer to 1st sequence: %s)\n\n", com.spname[refsp]);
   zero(mpostp, com.ncatG);
   for (h = 0; h < lst; h++, FPN(frst)) {
      hp = (!com.readpattern ? com.pose[h] : h);
      aa = GetAASiteSpecies(refsp, hp);
      fprintf(frst, "%4d %c  ", h + 1, aa);
      for (ir = 0, it = 0, psel = 0; ir < ncat; ir++) {
         fprintf(frst, " %5.5f", prob[ir*com.npatt + hp]);
         if (prob[ir*com.npatt + hp] > prob[it*com.npatt + hp])
            it = ir;
         if (!BayesEB && com.model == 0)
            if (com.rK[ir] > 1) psel += prob[ir*com.npatt + hp];
         mpostp[ir] += prob[ir*com.npatt + hp] / com.ls;

      }
      fprintf(frst, " (%2d)", it + 1);
      if (com.model == 0) {
         fprintf(frst, " %6.3f", meanw[hp]);
         if (!BayesEB && psel) fprintf(frst, " %6.3f", psel);
         if (BayesEB == 1 && com.model == 0)
            fprintf(frst, " +- %6.3f", varw[hp]);
      }
   }

   /*
   if(!BayesEB) {
      printf("\nmean posterior probabilities for site classes");
      matout(F0, mpostp, 1, com.ncatG);
      matout(F0, com.freqK, 1, com.ncatG);
   }
   */

   /* list of positively selected sites */
   if (com.model == 0) { /* NSsites models */
      if (com.NSsites != 1 && com.NSsites != 7)
         fprintf(frst, "\nPositively selected sites\n\n\tProb(w>1)  mean w\n\n");

      for (ir = 0, it = 0; ir < ncat; ir++)
         if (BayesEB == 1 || (com.freqK[ir] > .1 / com.ls && com.rK[ir] > wpos)) it = 1;
      if (!com.aaDist && it) {
         fprintf(fout, "\nPositively selected sites (*: P>95%%; **: P>99%%)\n");
         fprintf(fout, "(amino acids refer to 1st sequence: %s)\n\n", com.spname[refsp]);
         fprintf(fout, "            Pr(w>1) %25s\n\n", "post mean +- SE for w");
         for (h = 0; h < lst; h++) {
            hp = (!com.readpattern ? com.pose[h] : h);
            if (BayesEB == 1)
               psel = prob[(ncat - 1)*com.npatt + hp];
            else
               for (ir = 0, psel = 0; ir < ncat; ir++)
                  if (com.rK[ir] > wpos) psel += prob[ir*com.npatt + hp];

            if (psel > cutoff) {
               sig = "  ";
               if (psel > .95) sig = "* ";
               if (psel > .99) sig = "**";
               aa = GetAASiteSpecies(refsp, hp);
               fprintf(fout, "%6d %c %10.3f%-8s %.3f", h + 1, aa, psel, sig, meanw[hp]);
               fprintf(frst, "%6d %c %10.3f%-8s %.3f", h + 1, aa, psel, sig, meanw[hp]);

               if (BayesEB == 1 && com.model == 0) {
                  fprintf(fout, " +- %5.3f", varw[hp]);
                  fprintf(frst, " +- %5.3f", varw[hp]);
               }

               /*********** print out both codons if 2 sequences ******/
               /*
               if(com.ns==2) {
                  codons[0] = CODONs[com.z[0][hp]]);
                  codons[1] = CODONs[com.z[1][hp]]);
                  ndiff=difcodonNG(codons[0], codons[1], &St,&Nt,&ns,&na,0,com.icode);
                  fprintf(fout,"\t%3s %3s  %2.0f diff (ps pn: %5.3f %5.3f)", codons[0], codons[1], ndiff, ns/St, na/Nt);
               }
               */

               FPN(fout);  FPN(frst);
            }
         }
         FPN(fout);
         if (!BayesEB == 1 && com.rK[ncat - 2] > wpos)
            fputs("\nNote: more than one w>1.  Check rst for details\n", fout);
      }
   }
   return(0);
}

int lfunNSsites_rate(FILE* frst, double x[], int np)
{
   /* This calculates the dN/dS rates for sites under models with variabel dN/dS
      ratios among sites (Nielsen and Yang 1998).  Modified from lfundG()
      com.fhK[] holds the posterior probabilities.
   */
   int  h, hp, ir, it = 0, refsp = 0, k = com.ntime + com.nrgene + com.nkappa;
   double lnL = 0, fh;
   double w2 = x[com.np - 1], psel = 0, *meanw, maxmw, minmw, wpos = 1.1, cutoff = 0.5;
   char  *sig, aa;

   FILE *fsites, *fras;
   int  continuous = 0, R, G, B;
   int  lst = (com.readpattern ? com.npatt : com.ls);
   int  ncolors = 5;  /* continuous = 0 uses the specified colors */
   char sitelabel[96], *colors[5] = { "darkblue", "lightblue", "purple", "pinkred", "red" };
   char *colorvalues[5] = { "[2,2,120]", "[133,57,240]", "[186,60,200]", "[200,60,160]", "[250,5,5]" };


   if (com.nparK) error2("lfunNSsites_rate to be done for HMM.");

   if ((meanw = (double*)malloc(com.npatt * sizeof(double))) == NULL)
      error2("oom lfunNSsites_rate");  /* meanw useful for NSsites only */
   if (com.aaDist == 0)
      printParametersNSsites(frst, x);
   else
      fputs("\nCheck main result file for parameter estimates\n", frst);

   fx_r(x, np);
   if (com.NnodeScale)
      FOR(h, com.npatt) {
      for (ir = 1, fh = com.fhK[h]; ir < com.ncatG; ir++)
         if (com.fhK[ir*com.npatt + h] > fh) fh = com.fhK[ir*com.npatt + h];
      for (ir = 0; ir < com.ncatG; ir++)
         com.fhK[ir*com.npatt + h] = exp(com.fhK[ir*com.npatt + h] - fh);
      lnL -= fh*com.fpatt[h];
   }

   for (h = 0; h < com.npatt; h++) {
      for (ir = 0, fh = meanw[h] = 0; ir < com.ncatG; ir++) {
         fh += (com.fhK[ir*com.npatt + h] *= com.freqK[ir]);  /* prior=>posterior */
         meanw[h] += com.fhK[ir*com.npatt + h] * com.rK[ir];
      }
      for (ir = 0, meanw[h] /= fh; ir < com.ncatG; ir++) com.fhK[ir*com.npatt + h] /= fh;
      lnL -= com.fpatt[h] * log(fh);
   }

   fprintf(frst, "\nNaive Empirical Bayes (NEB) probabilities for %d classes", com.ncatG);
   if (com.model == 0 && com.NSsites && com.NSsites != 1 && com.NSsites != 7)
      fprintf(fout, "\nNaive Empirical Bayes (NEB) analysis");
   PrintProbNSsites(frst, com.fhK, meanw, NULL, com.ncatG, refsp);

   if (com.model && com.model <= NSbranch2) {  /* branch&site models */
      if (com.rK[0] > wpos || com.rK[1] > wpos) {  /* positive sites for all lineages */
         fputs("\n\nPositive sites for all lineages Prob(w>1):\n", fout);
         for (h = 0; h < lst; h++) {
            hp = (!com.readpattern ? com.pose[h] : h);
            aa = GetAASiteSpecies(refsp, hp);
            psel = 0;
            if (com.rK[0] > wpos) psel = com.fhK[0 * com.npatt + hp];
            if (com.rK[1] > wpos) psel += com.fhK[1 * com.npatt + hp];
            if (psel > cutoff) {
               sig = "";
               if (psel > .95) sig = "*";
               if (psel > .99) sig = "**";
               fprintf(fout, "%6d %c %.3f%s\n", h + 1, aa, psel, sig);
            }
         }
      }
      if (w2 > wpos && (com.freqK[com.ncatG - 1] > 1e-6)) {  /* for foreground branches */
         fprintf(fout, "\nNaive Empirical Bayes (NEB) analysis (please use the BEB results.)");
         fprintf(fout, "\nPositive sites for foreground lineages Prob(w>1):\n\n");
         for (h = 0; h < lst; h++) {
            hp = (!com.readpattern ? com.pose[h] : h);
            aa = GetAASiteSpecies(refsp, hp);
            psel = com.fhK[2 * com.npatt + hp] + com.fhK[3 * com.npatt + hp];
            if (psel > cutoff) {
               sig = "";
               if (psel > .95) sig = "*";
               if (psel > .99) sig = "**";
               fprintf(fout, "%6d %c %.3f%s\n", h + 1, aa, psel, sig);
            }
         }
      }
   }
   fprintf(frst, "\n\nlnL = %12.6f\n", -lnL);

   /* RasMol script for coloring structure */
   if (com.verbose && com.model == 0) {
      fsites = (FILE*)fopen("SiteNumbering.txt", "r");
      if (fsites) {
         puts("\nCollecting RasMol commands for coloring structure into RasMol.txt");

         printf("Choose color scheme (0: %d colors, 1: white->red, 2: rainbow) ", ncolors);
         scanf("%d", &continuous);

         fras = (FILE*)gfopen("RasMol.txt", "w");
         for (h = 0, maxmw = 0, minmw = 99; h < com.npatt; h++) {
            if (maxmw < meanw[h]) maxmw = meanw[h];
            if (minmw > meanw[h]) minmw = meanw[h];
         }
         if (continuous == 0)
            for (it = 0; it < ncolors; it++)
               printf("\t%-10s %-20s mean_w < %7.5f\n",
                  colors[it], colorvalues[it], (it + 1)*(maxmw - minmw) / ncolors);
         fprintf(fras, "cartoon\nset background white\n");
         for (h = 0; h < lst; h++) {
            fscanf(fsites, "%d%s", &it, sitelabel);
            if (it - 1 != h) { puts("Site number wrong.  Giving up."); break; }
            if (strchr(sitelabel, '?')) continue;
            hp = (!com.readpattern ? com.pose[h] : h);

            if (continuous == 0) {
               for (it = 0; it < ncolors; it++)
                  if (meanw[hp] < minmw + (it + 1.)*(maxmw - minmw) / ncolors + 1e-9) break;
               fprintf(fras, "select %s\n\t\tcolor %s\n", sitelabel, colorvalues[it]);
            }
            else if (continuous == 1) {
               it = 5 + (int)(245 * (meanw[hp] - minmw) / (maxmw - minmw + 1e-9));
               fprintf(fras, "select %s\n\t\tcolor [250, %d, %d]\n", sitelabel, 255 - it, 255 - it);
            }
            else {
               rainbowRGB((meanw[hp] - minmw) / (maxmw - minmw + 1e-9), &R, &G, &B);
               fprintf(fras, "select %s\n\t\tcolor [%d, %d, %d]\n", sitelabel, R, G, B);
            }
         }
         fclose(fsites);  fclose(fras);
      }
   }
   free(meanw);

   if (com.model == 0 && (com.NSsites == NSpselection || com.NSsites == NSbetaw)
      && (com.fix_omega != 1 || com.omega != 1))   /* BEB for M2 & M8 */
      lfunNSsites_M2M8(frst, x, com.np);

   /* BEB for branchsite A, clade C & D */
   if (!com.fix_omega && (com.model == 2 || com.model == 3) && (com.NSsites == 2 || com.NSsites == 3))
      lfunNSsites_ACD(frst, x, com.np);

   return (0);
}

/*

(*) Codon models for variable dN/dS ratios among sites
    (com.nrate includes kappa & omega) (see also CDFdN_dS)

    NSsites          npara

    0  one-ratio     0:    one ratio for all sites
    1  neutral       1:    p0 (w0=0, w1=1)
    2  selection     3:    p0, p1, w2 (w0=0, w1=1)
    3  discrete      2K-1: p0,p1,..., and w0,w1,...
    4  freqs         K:    p's (w's are fixed)
    5  gamma         2:    alpha, beta
    6  2gamma        4:    p0, alpha1,beta1, alpha2=beta2
    7  beta          2:    p_beta, q_beta
    8  beta&w        4:    p0, p_beta, q_beta, w estimated
    9  beta&gamma    5:    p0, p_beta, q_beta, alpha, beta
   10  beta&1+gamma  5:    p0, p_beta, q_beta, alpha, beta (1+gamma used)
   11  beta&1>normal 5:    p0, p_beta, q_beta, mu, s    (normal truncated w>1)
   12  0&2normal     5:    p0, p1, mu2, s1, s2
   13  3normal       6:    p0, p1, mu2, s0, s1, s2
   14  M8a:beta&w=1  3:    p0, p_beta, q_beta, w=1 fixed
   15  M8a:beta&w>=1 4:    p0, p_beta, q_beta, w>=1 estimated

NSsites = 14 forces change to fix_omega so we can't have 2 models in one run.
NSsites = 15 would not set wb[0] correctly for the next tree.


(*) Codon models for variable dN/dS ratios among both branches and sites
    (model=2, NSsites=3 or 2)
    (com.nrate includes kappa & omega)
    Parameters include branchlens, kappa, p0, p1, w0, w1, w2

    method = 0: SetPSiteClass copies w's to nodes[].omega and PMat is calculated
    in ConditionalPNode().
    method = 1: PMat for branch of interest is calulated in lfuntdd_SiteClass().
    The two types of branches have different Qfactor_NS: Qfactor_NS_branch[2].
    August 2000.


(*) Codon (perhaps aa as well) site-class models

    NSsites=3, ncatG=3 or 2 etc

    aaDist:
       1-6 for G1974,Miyata,c,p,v,a
       FIT1 & FIT2 (11, 12): fitness model F_j = a_p*(p-p*)^2+a_v*(v-v*)^2
       FIT1:   w_ij = exp(F_j - F_i)
       FIT2:   w_ij = b*exp(F_j - F_i)

       FIT1 & FIT2 are also implemented for NSsites=0


(*) Amino acid models

    REVaa: The symmetrical part (S) of the rate matrix Q=S*PI are estimated,
           making up 19*20/2-1=189 rate parameters for the matrix.  The aa
           frequencies are estimated using the observed ones.  The Sij for
           ijAAref=19*naa+9 (I-V) is set to one and others are relative rates;
    REVaa_0: AA1STEP[i*(i+1)+j] marks the aa pair i & j that are
            interchangeable.  Sij for ijAAref=19*naa+9 (I-V) is set to one
            and others are relative rates;


(*)
    Codon & amino acid models

    AAClasses: OmegaAA[i*(i-1)/2+j] marks the dN/dS ratio class for the pair
            i & j.  Note kappa is before omega's in x[].
            OmegaAA[i*(i-1)/2+j]=-1, if AAs i & j are not interchangeable
                       =0,  for the background ratio
                       =1,...,nclass for AAs i & j specified in OmegaAA.dat.
            The total number of classes (com.nOmega) is one plus the number
            specified in the file OmegaAAf.

   com.nOmega is the number of different dN/dS ratios in the NSbranchB, NSbranch2 models
      and in AAClasses.
   nodes[].label marks the dN/dS ratio for the node in the NSbranchB NSbranch2 models
   AA1STEP[i*(i-1)/2+j] =1 if AAs i & j differ at one codon position;
                        =0 otherwise.

(*) Codon and amino acid models

    aaDist = -5,-4,-3,-2,-1,1,2,3,4,5:
    Geometric and linear relationships between amino acid distance and
    substitution rate:
       wij = a*(1-b*dij/dmax)
       wij = a*exp(-b*dij/dmax)
    aaDist = 0:equal, +:geometric; -:linear, {1-5:Grantham,Miyata,c,p,v}

    aaDist = 11, 12: fitness models, see above.
*/





#if 0  /* routines for testing codon-models */

int GetCategoryQc(char z[NS])
{
   /* the category ID for a codon site with z[NS], transformed
      classified into 19 categories
   */
   int i, j, icat, ncat = 19, it, b[NS][3], nbase[3], markb[4];

   puts("\nDo not work with missing data, GetCategoryQc.");
   for (j = 0; j < com.ns; j++) {
      it = FROM61[(int)z[j]];  b[j][0] = it / 16; b[j][1] = (it / 4) % 4; b[j][2] = it % 4;
   }
   FOR(i, 3) {
      FOR(j, 4) markb[j] = 0;
      FOR(j, com.ns) markb[b[j][i]] = 1;
      nbase[i] = markb[0] + markb[1] + markb[2] + markb[3] - 1;
   }
   if (nbase[1] >= 2) icat = ncat - 1;
   else {
      if (nbase[0] > 2) nbase[0] = 2;  if (nbase[2] > 2) nbase[2] = 2;
      icat = nbase[1] * 9 + nbase[0] * 3 + nbase[2];
   }
   return (icat);
}

int TestModelQc(FILE * fout, double x[])
{
   /* Test the Qc model, slower than simulations
   */
   char z[NS];
   int h, npatt, it, icat, j, nodeb[NS], imposs;
   int n = Nsensecodon, isum, nsum, ncat = 19;
   double  fh, y, nobs[19], pexp[19], Pt[8][NCODE*NCODE];

   puts("\nDo not work with missing data, GetCategoryQc.");
   puts("\ntest Qc..\n");
   for (h = 0, zero(nobs, ncat); h < com.npatt; h++) {
      for (j = 0; j < com.ns; j++) z[j] = com.z[j][h] - 1;
      icat = GetCategoryQc(z);
      nobs[icat] += com.fpatt[h];
   }
   FOR(j, ncat)
      printf("cat #%4d: %4d%4d%4d%6.0f\n", j + 1, j / 9 + 1, (j / 3) % 3 + 1, j % 3 + 1, nobs[j]);

   if (com.ns > 5 || com.alpha || com.ngene > 1)
      error2("TestModelQc: ns>5 || alpha>0.");
   if (SetParameters(x)) puts("\npar err..");
   for (j = 0, npatt = 1; j < com.ns; j++)  npatt *= n;
   for (isum = 0, nsum = 1; isum < tree.nnode - com.ns; nsum *= n, isum++);
   printf("\nTest Qc: npatt = %d\n", npatt);
   FOR(j, tree.nbranch)
      PMatUVRoot(Pt[j], nodes[tree.branches[j][1]].branch, n, U, V, Root);

   for (h = 0, zero(pexp, ncat); h < npatt; h++) {
      for (j = 0, it = h; j < com.ns; nodeb[com.ns - 1 - j] = it%n, it /= n, j++);
      for (j = 0, imposs = 0; j < com.ns; j++)
      {
         z[j] = nodeb[j];  if (com.pi[(int)z[j]] == 0) imposs = 1;
      }
      if (imposs) continue;

      if ((icat = GetCategoryQc(z)) == ncat - 1) continue;
      if ((h + 1) % 100 == 0)
         printf("\rTest Qc:%9d%4d%9.2f%%", h + 1, icat, 100.*(h + 1.) / npatt);

      for (isum = 0, fh = 0; isum < nsum; isum++) {
         for (j = 0, it = isum; j < tree.nbranch - com.ns + 1; j++)
         {
            nodeb[com.ns + j] = it%n; it /= n;
         }
         for (j = 0, y = com.pi[nodeb[tree.root]]; j < tree.nbranch; j++)
            y *= Pt[j][nodeb[tree.branches[j][0]] * n + nodeb[tree.branches[j][1]]];
         fh += y;
      }
      if (fh <= 0) {
         matout(F0, x, 1, com.np);
         printf("\a\ntest Qc: h=%4d  fh=%9.4f \n", h, fh);
      }
      pexp[icat] += fh;
   }
   pexp[ncat - 1] = 1 - sum(pexp, ncat - 1);

   FOR(j, ncat)
      fprintf(fout, "\ncat # %4d%4d%4d%4d%6.0f%10.5f%10.2f",
         j + 1, j / 9 + 1, (j / 3) % 3 + 1, j % 3 + 1, nobs[j], pexp[j], com.ls*pexp[j]);
   return (0);
}

#endif

#if (DSDN_MC || DSDN_MC_SITES)

void SimulateData2s61(void)
{
   /* This simulates two codon sequences and analyze using ML (GY94).
      It generates site pattern freqs and then samples from them
      to generate the seq data.  Codons are coded as 0,1,...,60.  There
      is another routine of a similar name in the file dsdn.c where the
      codons are coded as 0,1,...,63.  The two routines should not be
      mixed.
      Note that com.pi[] is changed in the analysis but not reused to
      calculate Efij[]
      Ifdef (DSDN_MC_SITES), the data will be simulated with the NSsites models
      but analysed assuming one omega for all sites, so the model is wrong.
   */
   char infile[32] = "in.codon2s", seqfile[32] = "codonseq.tmp", str[4] = "";
   FILE *fseq, *fin;
   int ir, nr = 100, ip, i, j, k, h, n = Nsensecodon;
   int npatt0 = n*(n + 1) / 2, nobs[NCODE*NCODE];
   int il, nil, ls[50] = { 0,200,500 };
   double y, x[6] = { 1,1,1 }, xb[6][2], S, dN, dS, dNt, dSt, om, lnL, mr = 0;
   double t0, kappa0, omega0 = .5, pi0[NCODE], mx[6], vx[6], mse[6]; /* t,k,w,dS,dN */
   double Efij[NCODE*(NCODE + 1) / 2], space[50000];

   com.icode = 0; com.seqtype = 1; com.ns = 2;
   com.ncode = n; com.cleandata = 1; setmark_61_64();
   for (j = 0; j < com.ns; j++)
      com.z[j] = (char*)malloc(npatt0 * sizeof(char));
   if (com.z[com.ns - 1] == NULL) error2("oom z");
   if ((com.fpatt = (double*)malloc(npatt0 * sizeof(double))) == NULL)
      error2("oom fpatt");
   for (j = 0; j < 3; j++) { xb[j][0] = .0001; xb[j][1] = 99; }

#if (DSDN_MC_SITES)
   strcpy(infile, "in.codon2sSites");
#endif
   printf("\nTwo codon seq. simulation for ML (GY94), input from %s\n", infile);
   fin = gfopen(infile, "r");

   fscanf(fin, "%d%d%d%d", &k, &nr, &com.codonf, &nil);
   printf("\n%d replicates, %s model for analysis\nLc:",
      nr, codonfreqs[com.codonf]);
   for (il = 0; il < nil; il++)
      fscanf(fin, "%d", &ls[il + 1]);
   matIout(F0, ls + 1, 1, nil);
   for (i = 0, k = 0; i < NCODE; i++) {
      fscanf(fin, "%lf", &y);
      if (GeneticCode[com.icode][i] > -1) pi0[k++] = y;
      else if (y != 0)
         error2("stop codon freq !=0");
   }
   printf("sum pi = 1 = %.6f\n", sum(pi0, n));

   for (ip = 0; ip < 99; ip++) {
      fscanf(fin, "%lf%lf", &t0, &kappa0);
      if (t0 < 0) exit(0);
      printf("\n\nParameter set %d\nt0 =%.2f  kappa0 =%.2f\n", ip + 1, t0, kappa0);
      fprintf(frst, "\n\nParameter set %d\nt0 =%.2f  kappa0 =%.2f\n", ip + 1, t0, kappa0);

      for (j = 0; j < n; j++) com.pi[j] = pi0[j];
      com.ls = 1;
#if (DSDN_MC_SITES)
      com.NSsites = 3;
      fscanf(fin, "%d", &com.ncatG);
      for (i = 0; i < com.ncatG; i++) fscanf(fin, "%lf", &com.freqK[i]);
      for (i = 0; i < com.ncatG; i++) fscanf(fin, "%lf", &com.rK[i]);

      printf("\nSite classe model (K=%d)\np: ", com.ncatG);
      for (i = 0; i < com.ncatG; i++)
         printf("%7.4f", com.freqK[i]);
      printf("\nw: "); FOR(i, com.ncatG) printf("%7.4f", com.rK[i]); FPN(F0);
      fprintf(frst, "\nSite classe model (K=%d)\np: ", com.ncatG);
      for (i = 0; i < com.ncatG; i++)
         fprintf(frst, "%7.4f", com.freqK[i]);
      fputs("\nw: ", frst); FOR(i, com.ncatG) fprintf(frst, "%7.4f", com.rK[i]); FPN(frst);

      if (1 - sum(com.freqK, com.ncatG))
         error2("freqs do not sum to 1");
      for (j = 0, Qfactor_NS = 0, dS = dN = 0; j < com.ncatG; j++) {
         freqK_NS = com.freqK[j];
         eigenQcodon(2, 1, &S, &dSt, &dNt, NULL, NULL, NULL, &mr, &kappa0, com.rK[j], PMat);
         dS += freqK_NS*dSt;
         dN += freqK_NS*dNt;
      }
      Qfactor_NS = 1 / Qfactor_NS;
      om = (dS > 0 ? dN / dS : -1);
      dS *= t0*Qfactor_NS;
      dN *= t0*Qfactor_NS;

#else
      fscanf(fin, "%lf", &omega0);
      eigenQcodon(2, t0, &S, &dS, &dN, NULL, NULL, NULL, &mr, &kappa0, omega0, space);
      om = omega0;
#endif
      printf("\nCorrect values");
      printf("\nS%%=%7.4f  dS=%7.4f  dN=%7.4f  w=%7.4f\n", S / 3, dS, dN, om);
      fprintf(frst, "\nCorrect values");
      fprintf(frst, "\nS%%=%7.4f  dS=%7.4f  dN=%7.4f  w=%7.4f\n", S / 3, dS, dN, om);

      /* calculate Efij[], the site pattern probabilities */
      FOR(j, n) com.pi[j] = pi0[j];
#if (DSDN_MC_SITES)
      com.NSsites = 3;
      for (k = 0, zero(Efij, npatt0); k < com.ncatG; k++) {
         eigenQcodon(1, -1, NULL, NULL, NULL, Root, U, V, &mr, &kappa0, com.rK[k], PMat);
         PMatUVRoot(PMat, t0, n, U, V, Root);
         for (i = 0, h = 0; i < n; i++) for (j = 0; j <= i; j++) {
            y = com.pi[i] * PMat[i*n + j];
            Efij[h++] += (i == j ? y : 2 * y) * com.freqK[k];
         }
      }
      com.NSsites = 0;
#else
      eigenQcodon(1, -1, NULL, NULL, NULL, Root, U, V, &mr, &kappa0, omega0, PMat);
      PMatUVRoot(PMat, t0, n, U, V, Root);
      for (i = 0, h = 0; i < n; i++) for (j = 0; j <= i; j++) { /* why for each il? */
         y = com.pi[i] * PMat[i*n + j];
         Efij[h++] = (i == j ? y : 2 * y);
      }
#endif
      for (i = h = 0, com.ls = 1, com.npatt = npatt0; i < n; i++) for (j = 0; j <= i; j++) {
         com.z[0][h] = (char)i; com.z[1][h] = (char)j;
         com.fpatt[h] = Efij[h];  h++;
      }
      if (fabs(1 - sum(Efij, npatt0)) > 1e-6) error2("sum Efij != 1");

      for (il = 0; il < nil + 1; il++) {
         com.ls = ls[il];
         if (com.ls == 0) {
            puts("\nML estimates from infinite data");
            com.ls = 1;
            x[0] = t0*rndu(); x[1] = kappa0; x[2] = omega0*rndu();
            GetCodonFreqs2();
            ming2(NULL, &lnL, lfun2dSdN, NULL, x, xb, space, 1e-10, 3);
            printf("lnL = %.6f\n", -lnL);
            eigenQcodon(2, x[0], &S, &dS, &dN, NULL, NULL, NULL, &mr, &x[1], x[2], space);
            printf("S%%=%7.4f  dS=%7.4f  dN=%7.4f  w=%7.4f\n", S / 3, dS, dN, x[2]);
            fprintf(frst, "ML estimates from infinite data\nt=%7.4f  k=%7.4f", x[0], x[1]);
            fprintf(frst, "  S%%=%7.4f  dS=%7.4f  dN=%7.4f  w=%7.4f\n", S / 3, dS, dN, x[2]);

            for (h = 1; h < npatt0; h++) Efij[h] += Efij[h - 1];
            puts("\nt & k & w & dS & dN");
            fputs("\nLc & t & k & w & dS & dN\n", frst);  fflush(frst);
            continue;
         }

         printf("\nls = %d\n", com.ls);
         for (ir = 0, zero(mx, 6), zero(vx, 6), zero(mse, 6); ir < nr; ir++) {
            MultiNomial(com.ls, npatt0, Efij, nobs, NULL);
            for (i = 0, com.npatt = 0, zero(com.pi, n); i < n; i++) for (j = 0; j <= i; j++)
               if (nobs[k = i*(i + 1) / 2 + j]) {
                  com.z[0][com.npatt] = i; com.z[1][com.npatt] = j;
                  com.fpatt[com.npatt++] = nobs[k];
               }
            for (i = 0, zero(com.pi, n); i < com.npatt; i++) {
               com.pi[com.z[0][i]] += com.fpatt[i] / (2.*com.ls);
               com.pi[com.z[1][i]] += com.fpatt[i] / (2.*com.ls);
            }
            GetCodonFreqs2();

            x[0] = t0;  x[1] = kappa0; x[2] = omega0;
            /* printf("\nlnL=%9.6f\n",-lfun2dSdN(x,3)); */
            ming2((noisy ? F0 : NULL), &lnL, lfun2dSdN, NULL, x, xb, space, 1e-7, 3);
            eigenQcodon(2, x[0], &S, &x[3], &x[4], NULL, NULL, NULL, &mr, &x[1], x[2], space);
            FOR(j, 5) {
               vx[j] += (x[j] - mx[j])*(x[j] - mx[j]);
               mx[j] = (mx[j] * ir + x[j]) / (ir + 1.);
            }
            mse[0] += square(x[2] - omega0);
            printf("\r%4d%8.4f%8.4f%8.4f  %8.4f%8.4f%8.4f%8.4f%8.4f",
               ir + 1, x[0], x[1], x[2], mx[0], mx[1], mx[2], mx[3], mx[4]);
#if 0
            if (ir == 9) {
               fseq = gfopen(seqfile, "w");
               fprintf(fseq, "%6d %6d\n", com.ns, com.ls * 3);
               for (i = 0; i < 2; i++, FPN(fseq), fflush(fseq)) {
                  fprintf(fseq, "seq.%-5d  ", i + 1);
                  FOR(h, com.npatt) FOR(k, (int)com.fpatt[h])
                     fprintf(fseq, "%s", getcodon(str, FROM61[com.z[i][h]]));
               }
               fclose(fseq); exit(0);
            }
#endif
         }
         if (nr > 1) { FOR(j, 5) vx[j] = sqrt(vx[j] / (nr - 1.) / nr); mse[0] = sqrt(mse[0] / nr); }
         fprintf(frst, "%4d ", com.ls);
         FOR(i, 5) fprintf(frst, "%7.4f +%7.4f", mx[i], vx[i]);  FPN(frst);
      }  /* for (ii) */
   }   /* for(ip) */
   exit(0);
}


void Ina(void)
{
   /* This simulates two codon sequences and analyze them using Ina's method.
      Ina's program is modified to output result in Ina1.tmp.  Consistency
      analysis is done by generating long sequences.
      Note that com.pi[] is not changed in the analysis, which is done outside
      the program.
   */
   char seqfile[32] = "codonseq.tmp", tmpfile[32] = "Ina1.tmp", str[4] = "";
   FILE *fseq, *ftmp;
   int ip, ir, nr = 500, i, j, k, h, n = Nsensecodon;
   int npatt0 = n*(n + 1) / 2, nobs[NCODE*NCODE];
   int il, nil = 1, ls[] = { 500,100,200,300,400,500,600,800,1000 }, fcodon = 1;
   double y, t = .5, f3x4[12], x[3] = { 1,1,1 }, S, dS, dN, mr = 0;
   double t0 = 1, kappa0 = 1, omega0 = 1, mx[6], vx[6], mse[6]; /* t,k,w,dS,dN */
   double Efij[NCODE*NCODE], space[50000];
   double f3x4_data[][3 * 4] = {
                            {0.25, 0.25, 0.25, 0.25,
                             0.25, 0.25, 0.25, 0.25,
                             0.25, 0.25, 0.25, 0.25},

                            {0.20517, 0.28293, 0.30784, 0.20406, /* mt pri */
                             0.40979, 0.27911, 0.18995, 0.12116,
                             0.15105, 0.43290, 0.37123, 0.04482},

                            {0.19020, 0.16201, 0.36655, 0.28124, /* hiv */
                             0.28889, 0.18805, 0.30179, 0.22127,
                             0.24875, 0.16894, 0.36822, 0.21410},

                            {0.14568, 0.24519, 0.33827, 0.27086,
                             0.35556, 0.18765, 0.24049, 0.21630,
                             0.26444, 0.25728, 0.21012, 0.26815} /* lysinNew*/
   };

   puts("\nThis simulates data and analyses them using Ina95.");

   printf("fcodon? ");
   scanf("%d", &fcodon);

   FOR(j, 12) f3x4[j] = f3x4_data[fcodon][j];
   for (j = 0, h = 0, y = 0; j < 64; j++) {
      if (GeneticCode[com.icode][j] == -1) continue;
      com.pi[h] = f3x4[j / 16] * f3x4[4 + (j % 16) / 4] * f3x4[8 + j % 4];
      y += com.pi[h++];
   }
   FOR(j, n) com.pi[j] /= y;
   printf("fcodon: %d\n", fcodon);
   matout(frst, f3x4, 3, 4);
   com.icode = 0; com.seqtype = 1; com.ns = 2; com.ls = 1; npatt0 = n*(n + 1) / 2;
   com.ncode = n; setmark_61_64();
   FOR(j, com.ns) com.z[j] = (char*)malloc(npatt0 * sizeof(char));
   if (com.z[com.ns - 1] == NULL) error2("oom z");
   if ((com.fpatt = (double*)malloc(npatt0 * sizeof(double))) == NULL)
      error2("oom fpatt");

   printf("\nInfinite sequences.\nsum pi=1=%.6f\n", sum(com.pi, NCODE));
   noisy = 0;  FOR(i, 6) x[i] = 0;

   FOR(ip, 99) {
      printf("\nt0 & kappa0 & omega0? ");
      scanf("%lf%lf%lf", &t0, &kappa0, &omega0);
      if (t0 < 0) exit(0);
      printf("t0 =%.2f & kappa0 =%.2f & omega0 =%.2f\n", t0, kappa0, omega0);
      fprintf(frst, "\nt & k & w: %8.2f%8.2f%8.2f\n\n", t0, kappa0, omega0);
      eigenQcodon(2, t0, &S, &dS, &dN, NULL, NULL, NULL, &mr, &kappa0, omega0, space);
      fprintf(frst, "\nS/(S+N)=%7.4f  dS=%7.4f  dN=%7.4f\n", S / 3, dS, dN);
      fputs("Lc & t & k & w & dS & dN\n", frst);

      eigenQcodon(1, -1, NULL, NULL, NULL, Root, U, V, &mr, &kappa0, omega0, PMat);
      PMatUVRoot(PMat, t0, n, U, V, Root);
      for (i = 0, h = 0; i < n; i++) for (j = 0; j <= i; j++) {
         y = com.pi[i] * PMat[i*n + j];
         Efij[h++] = (i == j ? y : 2 * y);
      }
      for (i = h = 0, com.ls = 1, com.npatt = npatt0; i < n; i++) for (j = 0; j <= i; j++) {
         com.z[0][h] = (char)i; com.z[1][h] = (char)j;
         com.fpatt[h] = Efij[h];  h++;
      }
      for (h = 1; h < npatt0; h++) Efij[h] += Efij[h - 1];
      if (fabs(1 - Efij[npatt0 - 1]) > 1e-6) puts("Sum p_ij != 1.");
      for (il = 0; il < nil; il++) {

         com.ls = ls[il];
         printf("\nls = %d\n", com.ls);
         for (ir = 0, zero(mx, 6), zero(vx, 6), zero(mse, 6); ir < nr; ir++) {
            printf("\r%4d", ir + 1);
            MultiNomial(com.ls, npatt0, Efij, nobs, NULL);
            for (i = 0, com.npatt = 0; i < n; i++) for (j = 0; j <= i; j++)
               if (nobs[k = i*(i + 1) / 2 + j]) {
                  com.z[0][com.npatt] = i; com.z[1][com.npatt] = j;
                  com.fpatt[com.npatt++] = nobs[k];
               }
            fseq = gfopen(seqfile, "w");
            fprintf(fseq, "> %6d %6d\n", com.ns, com.ls * 3);
            for (i = 0; i < 2; i++, FPN(fseq), fflush(fseq)) {
               fprintf(fseq, "seq.%-5d  ", i + 1);
               FOR(h, com.npatt) FOR(k, (int)com.fpatt[h])
                  fprintf(fseq, "%s", getcodon(str, FROM61[com.z[i][h]]));
            }
            fclose(fseq);
            if (com.ls > 2000) system("Ina1Large codonseq.tmp >t");
            else            system("Ina1 codonseq.tmp >t");
            ftmp = gfopen(tmpfile, "r");
            if (fscanf(ftmp, "%lf%lf%lf", &x[0], &x[1], &x[2]) != 3)
               error2("reading tmpf");
            fclose(ftmp);
            FOR(j, 5) {
               vx[j] += (x[j] - mx[j])*(x[j] - mx[j]);
               mx[j] = (mx[j] * ir + x[j]) / (ir + 1.);
            }
            mse[0] += square(x[0] - omega0);

            printf("%7.4f%7.4f%7.4f  %7.4f%7.4f%7.4f%7.4f%7.4f",
               x[0], x[1], x[2], mx[0], mx[1], mx[2], mx[3], mx[4]);

            /*            fprintf(frst1,"%7.4f%7.4f%7.4f  %7.4f%7.4f%7.4f%7.4f%7.4f\n",
                               x[0],x[1],x[2],mx[0],mx[1],mx[2],mx[3],mx[4]);
            */
         }
         if (nr > 1) { FOR(j, 5) vx[j] = sqrt(vx[j] / (nr - 1.) / nr); mse[0] = sqrt(mse[0] / nr); }
         fprintf(frst, "%4d ", com.ls);
         FOR(i, 5) fprintf(frst, "%7.3f +%7.4f", mx[i], vx[i]);
         FPN(frst); fflush(frst);

         fprintf(frst1, "%6d%6d %7.2f%7.2f%7.2f: %8.3f +%7.3f\n",
            com.ls, nr, t0, kappa0, omega0, mx[0], mse[0]);
         fflush(frst1);
      }    /* for (il) */
   }       /* for (ip) */
   exit(0);
}

#endif

#if 0

int mergeSeqs(FILE*fout)
{
   /* This concatenates multiple genes (data sets) for the same set of species
      into one file of a long gene.  Used to process Anne Yoders' alignment.
   */

   char *filenames[12] = { "NADH1.fin","NADH2.fin","COI.fin","COII.fin","ATPase8.fin",
        "ATPase6.fin","COIII.fin","NADH3.fin","NADH4L.fin","NADH4.fin",
        "NADH5.fin", "Cytb.fin" };

   int ns0 = 32, nfile = 12, ifile, ls0, lswhole = 20000, i, h, lgene0[32];
   char *z0[32], *spname0[32] = { "Artibeus", "B.musculus", "B.physalus", "Bos",
      "Canis", "Cavia", "Ceratother", "Dasypus", "Didelphis", "E.asinus",
      "E.caballus","Erinaceus", "Felis", "Glis", "Gorilla", "Halichoeru", "Homo",
      "Hylobates", "Macropus", "Mus", "Ornithorhy", "Oryctolagu", "Ovis",
      "P.paniscus", "P.troglody", "Papio", "Phoca", "P.abelii",
      "P.pygmaeus", "Rattus", "Rhinoceros", "Sus" };
   FILE *fseq;

   noisy = 0;
   FOR(i, ns0) if ((z0[i] = (char*)malloc(lswhole * sizeof(char))) == NULL)
      error2("oom z");
   for (ifile = 0, ls0 = 0; ifile < nfile; ifile++) {
      printf("Reading data set %2d/%2d (%s)", ifile + 1, nfile, filenames[ifile]);
      fseq = gfopen(filenames[ifile], "r");
      ReadSeq(NULL, fseq, 1);
      lgene0[ifile] = com.ls;  com.ls *= 3;
      FOR(i, ns0) if (strcmp(spname0[i], com.spname[i])) error2("spname different");
      FOR(i, ns0)  FOR(h, com.ls) z0[i][ls0 + h] = com.z[i][h];
      ls0 += com.ls;
      printf(" + %5d = %5d\n", com.ls, ls0);
   }
   fprintf(fout, "%6d %6d  G\nG %4d ", ns0, ls0, nfile);
   FOR(ifile, nfile) fprintf(fout, " %4d", lgene0[ifile]);  FPN(fout);

   for (i = 0; i < ns0; i++, FPN(fout)) {
      fprintf(fout, "%-12s  ", spname0[i]);
      FOR(h, ls0) {
         fprintf(fout, "%c", z0[i][h]);
         if ((h + 1) % 3 == 0) fprintf(fout, " ");
      }
   }
   return(0);
}

#endif


int SlidingWindow(FILE*fout, FILE* fpair[], double space[])
{
   /* sliding window analysis, clean data, 2 sequences only */
   int wlen = windowsize0, offset = offset0, wstart, n = com.ncode, j, h, positive = 0;
   int ls0 = com.ls, npatt0 = com.npatt;
   char *z0[NS];
   double *fpatt0, pi0[NCODE], lnL0 = 0, lnL1 = 0;

   if (com.seqtype != 1) error2("implemented for codon sequences only.");
   if (com.runmode != -2) error2("this version of sliding windows requires runmode=-2");
   if (!com.cleandata || com.ngene > 1)
      error2("clean data & one gene only for sliding window analysis");
   if (com.print)
      error2("Choose RateAncestor=0 for sliding window analysis");
   for (j = 0; j < com.ns; j++)
      z0[j] = com.z[j];
   for (j = 0; j < com.ns; j++)
      if ((com.z[j] = malloc(npatt0 * sizeof(char))) == NULL) error2("oom z");
   if ((fpatt0 = (double*)malloc(npatt0 * sizeof(double))) == NULL) error2("oom fp");
   for (h = 0; h < com.npatt; h++)
      fpatt0[h] = com.fpatt[h];
   for (j = 0; j < n; j++)
      pi0[j] = com.pi[j];

   for (wstart = 0; wstart + wlen <= ls0; wstart += offset) {
      for (h = 0; h < npatt0; h++)
         com.fpatt[h] = 0;
      for (h = wstart; h < wstart + wlen; h++)
         com.fpatt[com.pose[h]]++;

      for (h = 0, com.npatt = 0, zero(com.pi, n); h < npatt0; h++) if (com.fpatt[h] > 0) {
         for (j = 0; j < com.ns; j++)
            com.z[j][com.npatt] = z0[j][h];
         com.fpatt[com.npatt] = com.fpatt[h];
         com.npatt++;
      }
      com.ls = wlen;
      com.posG[0] = 0; com.posG[1] = com.npatt;

      com.fix_omega = 1; com.omega = 1;
      PairwiseCodon(fout, fpair[3], fpair[4], fpair[5], com.space);
      lnL0 = -lnLmodel; /* lnLmodel passed overhead from PairwiseCodon() */

      com.fix_omega = 0; com.omega = 0.5;
      PairwiseCodon(fout, fpair[3], fpair[4], fpair[5], com.space);
      lnL1 = -lnLmodel;

      if (com.omega > 1 && (lnL1 - lnL0) > 2.71 / 2) {
         positive = 1;
         break;
      }

      if (noisy)
         printf("sites %3d -- %3d  (%d) npatt:%4d w=%.4f\n", wstart + 1, wstart + wlen, ls0, com.npatt, com.omega);
      fprintf(fout, "\nsites %3d -- %3d  %4d", wstart + 1, wstart + wlen, com.npatt);

      /* Forestry(fout); */
   }
   fprintf(frst1, " %2d", positive);
   printf("     %2d", positive);

   com.ls = ls0;  com.posG[1] = com.npatt = npatt0;
   for (h = 0; h < com.npatt; h++)
      com.fpatt[h] = fpatt0[h];
   xtoy(pi0, com.pi, n);
   free(fpatt0);
   for (j = 0; j < com.ns; j++) {
      free(com.z[j]);
      com.z[j] = z0[j];
   }
   return(positive);
}



void Get4foldSites(void)
{
   /* This collects the four-fold degerate sites into a file named 4fold.nuc.
      The data are not coded yet, and the routine is called from ReadSeq().
   */
   int ls4, j, k, h, ib[3][4], nb[3];
   char file4[12] = "4fold.nuc", *mark4;
   FILE *f4;

   f4 = gfopen(file4, "w");
   if ((mark4 = (char*)malloc(com.ls * sizeof(char))) == NULL) error2("oom mark");
   FOR(h, com.ls) mark4[h] = 0;

   for (h = 0, ls4 = 0; h < com.ls; h++) {
      for (k = 0; k < 3; k++)
         NucListall(com.z[0][h * 3 + k], &nb[k], ib[k]);
      if (nb[0] == 1 && nb[2] == 1 && FourFold[ib[0][0]][ib[1][0]]) {
         for (j = 1; j < com.ns; j++)
            for (k = 0; k < 2; k++) if (com.z[j][h * 3 + k] != com.z[0][h * 3 + k]) goto nextsite;
         mark4[h] = 1;  ls4++;
      }
   nextsite:;
   }     /* for(h) */

   fprintf(f4, "%6d  %6d\n", com.ns, ls4);
   for (j = 0; j < com.ns; j++) {
      fprintf(f4, "\n%s\n", com.spname[j]);
      for (h = 0; h < com.ls; h++)
         if (mark4[h]) fprintf(f4, "%c", com.z[j][h * 3 + 2]);
      FPN(f4);
   }
   fprintf(f4, "\n\ncodons included\n");
   for (h = 0; h < com.ls; h++)
      if (mark4[h]) fprintf(f4, " %2d", h + 1);
   FPN(f4);

   fclose(f4);  free(mark4);
}


double distanceHKY85(double x[], double *kappa, double alpha);

void d4dSdN(FILE* fout)
{
   /* This looks at the 4-fold degerenate sites.
   */
   char str1[4] = "   ", str2[4] = "   ";
   int i, j, k, n = com.ncode, b[2][3], ic1, ic2, iaa;
   double pS4, d4, kappa4fold;
   double fij, fij4f[4 * 4], pi4f[4], pstop, t, S, dS, dN, dN_dS, mr = 0;
   double fb3x4[12] = { .25, .25, .25, .25,
                     .25, .25, .25, .25,
                     .25, .25, .25, .25 };

   int nii = 18, ii;
   double t0[] = { 0.001, 0.01,0.05, .1, .2, .3, .4, .5, .6, .7, .8, .9, 1, 1.2, 1.5, 2,2.5,3 };


   com.ls = 1; com.kappa = 3; com.omega = 1;

   fb3x4[0 * 4 + 0] = 0.35;
   fb3x4[0 * 4 + 1] = 0.15;
   fb3x4[0 * 4 + 2] = 0.35;
   fb3x4[0 * 4 + 3] = 0.15;
   /*
      fb3x4[1*4+0]=0.35;
      fb3x4[1*4+1]=0.15;
      fb3x4[1*4+2]=0.35;
      fb3x4[1*4+3]=0.15;
   */
   fb3x4[2 * 4 + 0] = 0.35;
   fb3x4[2 * 4 + 1] = 0.15;
   fb3x4[2 * 4 + 2] = 0.35;
   fb3x4[2 * 4 + 3] = 0.15;


   printf("\tt\tS\tdS\tdN\tdN/dS\tS4\td4\tk_4f\tpT_4f\n");

   zero(com.pi, 64);
   FOR(k, 64)  if (FROM64[k] > -1)
      com.pi[FROM64[k]] = fb3x4[k / 16] * fb3x4[4 + (k / 4) % 4] * fb3x4[8 + k % 4];
   pstop = 1 - sum(com.pi, n);
   abyx(1 / (1 - pstop), com.pi, n);

   eigenQcodon(1, -1, NULL, NULL, NULL, Root, U, V, &mr, &com.kappa, com.omega, PMat);

   matout(frst, com.pi, 16, 4);

   FOR(ii, nii) {
      t = t0[ii];
      eigenQcodon(2, t, &S, &dS, &dN, NULL, NULL, NULL, &mr, &com.kappa, com.omega, PMat);
      PMatUVRoot(PMat, t, n, U, V, Root);
      if (testTransP(PMat, n)) error2("testP");

      matout(frst, PMat, n, n);

      for (i = 0, zero(fij4f, 16); i < n; i++) {
         ic1 = FROM61[i]; b[0][0] = ic1 / 16; b[0][1] = (ic1 / 4) % 4; b[0][2] = ic1 % 4;
         iaa = GeneticCode[com.icode][ic1];
         ic1 -= b[0][2];
         FOR(k, 4)  if (GeneticCode[com.icode][ic1 + k] != iaa)  break;
         if (k < 4) continue;
         FOR(j, n) {
            fij = com.pi[i] * PMat[i*n + j];
            ic2 = FROM61[j]; b[1][0] = ic2 / 16; b[1][1] = (ic2 / 4) % 4; b[1][2] = ic2 % 4;

            if (b[0][0] != b[1][0] || b[0][1] != b[1][1]) continue;
            fij4f[b[0][2] * 4 + b[1][2]] += fij;

            /* printf("%c %s %s  %.8f\n",AAs[iaa],getcodon(str1,ic1+b[0][2]),getcodon(str2,ic2),fij);
            */

         }
      }

      pS4 = sum(fij4f, 16) / 3;
      abyx(1 / sum(fij4f, 16), fij4f, 16);
      FOR(k, 4) pi4f[k] = sum(fij4f + k * 4, 4);

      /* matout(F0,fij4f,4,4); */

      d4 = distanceHKY85(fij4f, &kappa4fold, 0);
      dN_dS = (dS > 0 ? dN / dS : -1);
      printf("\t%.4f\t%.5f\t%.5f\t%.5f\t%.5f\t%.3f\t%.5f\t%.3f\t%.4f\n",
         t, S / 3, dS, dN, dN_dS, pS4, d4, kappa4fold, pi4f[0]);

   }

   printf("\nproportion of stop codons: %.4f\n", pstop);

   exit(0);
}


double distanceHKY85(double x[], double *kappa, double alpha)
{
   /* This is from SeqDivergence(), copied here to avoid linking to SeqDivergence.
   */
   int i, j;
   double p[4], Y, R, a1, a2, b, P1, P2, Q, tc, ag;
   double largek = 999, larged = 9;

   if (testXMat(x) && noisy) {
      matout(F0, x, 4, 4);
      puts("X err..  Perhaps no sites to compare?");
   }
   *kappa = 0;
   for (i = 0, zero(p, 4); i < 4; i++) {
      FOR(j, 4) { p[i] += x[i * 4 + j] / 2;  p[j] += x[i * 4 + j] / 2; }
   }
   P1 = x[0 * 4 + 1] + x[1 * 4 + 0];
   P2 = x[2 * 4 + 3] + x[3 * 4 + 2];
   Q = x[0 * 4 + 2] + x[0 * 4 + 3] + x[1 * 4 + 2] + x[1 * 4 + 3] + x[2 * 4 + 0] + x[2 * 4 + 1] + x[3 * 4 + 0] + x[3 * 4 + 1];
   Y = p[0] + p[1];
   R = p[2] + p[3];

   if (P1 + P2 + Q < 1e-100) {
      *kappa = -1; return(0);
   }

   tc = p[0] * p[1];
   ag = p[2] * p[3];

   a1 = 1 - Y*P1 / (2 * tc) - Q / (2 * Y);
   a2 = 1 - R*P2 / (2 * ag) - Q / (2 * R);
   b = 1 - Q / (2 * Y*R);
   if (a1 <= 0 || a2 <= 0 || b <= 0) return (larged);
   if (alpha <= 0) { a1 = -log(a1); a2 = -log(a2); b = -log(b); }
   else { a1 = -gammap(a1, alpha); a2 = -gammap(a2, alpha); b = -gammap(b, alpha); }
   a1 = -R / Y*b + a1 / Y;
   a2 = -Y / R*b + a2 / R;
   if (b > 0) *kappa = min2((a1 + a2) / (2 * b), largek);
   return 2 * (p[0] * p[1] + p[2] * p[3])*(a1 + a2) / 2 + 2 * Y*R*b;
}



void get_pclassM_iw_M2M8(int iw[], double pclassM[], double para[][100], int n1d, int M2a, int ternary);
void get_grid_para_like_M2M8(double para[4][100], int n1d, int dim, int M2a, int ternary,
   double p0b[], double p1b[], double w0b[], double wsb[],
   double p_beta_b[], double q_beta_b[], double x[], double *S);
void GetIndexTernary(int *ix, int *iy, double *x, double *y, int itriangle, int K);



void get_grid_para_like_M2M8(double para[4][100], int n1d, int dim, int M2a, int ternary,
   double p0b[], double p1b[], double w0b[], double wsb[],
   double p_beta_b[], double q_beta_b[], double x[], double *S)
{
   /* This sets up the grid (para[][]) according to the priors.  It also copies all
      possible w values into com.rK[].
      The bounds on parameters are used to set up the uniform priors for parameters.
   */
   int i, k, h, site = 10;
   double fh;

   if (com.NSsites == NSbetaw)  /* can't control the range of w from the beta */
   {
      w0b[0] = 0; w0b[1] = 1;
   }

   for (i = 0; i < n1d; i++) {
      para[0][i] = p0b[0] + (i + 0.5)*(p0b[1] - p0b[0]) / n1d;                   /* p0 */
      if (com.NSsites == 2) {  /* M2 & M2a */
         para[1][i] = p1b[0] + (i + 0.5)*(p1b[1] - p1b[0]) / n1d;                /* p1 */
         if (ternary) para[0][i] = para[1][i] = -1;
         if (M2a)
            para[2][i] = w0b[0] + (i + 0.5)*(w0b[1] - w0b[0]) / n1d;             /* w0 */
         para[2 + M2a][i] = wsb[0] + (i + 0.5)*(wsb[1] - wsb[0]) / n1d;            /* w2 */
      }
      else {                 /* M8 */
         para[1][i] = p_beta_b[0] + (i + 0.5)*(p_beta_b[1] - p_beta_b[0]) / n1d; /* p */
         para[2][i] = q_beta_b[0] + (i + 0.5)*(q_beta_b[1] - q_beta_b[0]) / n1d; /* q */
         para[3][i] = wsb[0] + (i + 0.5)*(wsb[1] - wsb[0]) / n1d;                /* ws */
      }
   }

   k = 0;
   if (com.NSsites == 2 && M2a == 0)
      com.rK[k++] = 0;
   else   /* w0 in M2a or w0 from beta in M8 */
      for (i = 0; i < n1d; i++)
         com.rK[k++] = w0b[0] + (i + 0.5)*(w0b[1] - w0b[0]) / n1d;
   if (com.NSsites == 2)
      com.rK[k++] = 1;  /* w1 for M2 & M2a */
   for (i = 0; i < n1d; i++)
      com.rK[k++] = wsb[0] + (i + 0.5)*(wsb[1] - wsb[0]) / n1d; /* w2 in M2 or ws */

   /* calculates the likelihood com.fhK[] */
   printf("\nCalculating f(x_h|w): %d categories %d w sets.\n", n1d, com.ncatG);
   com.conPSiteClass = 0;  *S = 0;
   fx_r(x, -1);

   if (noisy > 3)
      for (k = 0; k < com.ncatG; k++)
         printf("S%d w log{f(x|w)}: %9.4f  %12.6f\n",
            site, com.rK[k], (com.NnodeScale ? com.fhK[k*com.npatt + site] : log(com.fhK[k*com.npatt + site])));

   if (com.NnodeScale)
      for (h = 0; h < com.npatt; h++) {
         for (k = 1, fh = com.fhK[h]; k < com.ncatG; k++)
            fh = max2(fh, com.fhK[k*com.npatt + h]);
         for (k = 0; k < com.ncatG; k++)
            com.fhK[k*com.npatt + h] = exp(com.fhK[k*com.npatt + h] - fh);
         *S += fh*com.fpatt[h];
      }
   else
      for (h = 0; h < com.npatt; h++) {
         for (k = 1, fh = com.fhK[h]; k < com.ncatG; k++)
            fh = max2(fh, com.fhK[k*com.npatt + h]);
         for (k = 0; k < com.ncatG; k++)
            com.fhK[k*com.npatt + h] /= fh;
         *S += log(fh)*com.fpatt[h];
      }

}


void get_pclassM_iw_M2M8(int iw[], double pclassM[], double para[][100], int n1d, int M2a, int ternary)
{
   /* This sets up iw[ngrid*nclassM] and pclassM[ngrid*nclassM], where iw
      locates the w ratio in com.rK[] and f(x_h|w) stored in com.fhK[],
      and pclassM is the proportion of the site class under the model.
      Look at get_grid_para_like() for more info about the setup of com.rK[], which
      accounts for the setup of iw here in this function.

      M8 used to use 10 categories to approximate the beta, each of probability 0.1.
      Here we use n1d categories, equally spaced, and the probabilities for categories
      are calculated using CDFBeta.

      Parameters for grid integration:

                      Parameters         Parameter dependence
         Model     0    1    2    3          iw            pclassM
      -------------------------------------------------------------------
         M2       p0   p1   w2          iclassM w0 w2     iclassM p0 p1
         M2a      p0   p1   w0   w2     iclassM w2        iclassM p0 p1
         M8       p0    p    q   ws     iclassM p q ws    iclassM p0 p q
      -------------------------------------------------------------------

      If M2 or M2a and ternary, the n1d*n1d grid for p0-p1 is mapped onto the
      triangle specified by p0-p1-p2.  First the index i and j are retrieved
      from the label for the point (ip[0]*n1d+ip[1]).  Then the coordinates
      p0 and p1 at the point is worked out.  With this scheme, p0 and p1 each
      takes on 2*n1d-1 possible values.
   */
   int dim = (com.NSsites == 8 || M2a ? 4 : 3), ngrid, igrid, i, j, k, it, ip[4] = { 0 };
   int nclassM = (com.NSsites == NSpselection ? 3 : n1d + 1);
   double p0, p1, p, q, cdf0, cdf1;

   ngrid = n1d*n1d*n1d*(dim == 4 ? n1d : 1);
   for (igrid = 0; igrid < ngrid; igrid++) {
      for (j = dim - 1, it = igrid; j >= 0; j--) { ip[j] = it%n1d; it /= n1d; }
      if (com.NSsites == 2 && !ternary && para[0][ip[0]] + para[1][ip[1]] > 1) continue;
      for (k = 0; k < nclassM; k++) {
         if (com.NSsites == NSpselection) {    /* M2 & M2a */
            if (ternary) {
               GetIndexTernary(&i, &j, &p0, &p1, ip[0] * n1d + ip[1], n1d);
               pclassM[igrid*nclassM + k] = (k == 0 ? p0 : (k == 1 ? p1 : 1 - p0 - p1));
            }
            else {
               if (k < 2)  pclassM[igrid*nclassM + k] = para[k][ip[k]];  /* p0 or p1 */
               else     pclassM[igrid*nclassM + k] = 1 - para[0][ip[0]] - para[1][ip[1]];   /* p2 */
               pclassM[igrid*nclassM + k] = max2(pclassM[igrid*nclassM + k], 0);
            }

            if (M2a == 0) {     /*M2 */
               if (k < 2) iw[igrid*nclassM + k] = k;                /* w0 or w1 */
               else    iw[igrid*nclassM + k] = 2 + ip[2];           /* w2 */
            }
            else {  /* M2a */
               if (k == 0)      iw[igrid*nclassM + k] = ip[2];       /* w0 */
               else if (k == 1) iw[igrid*nclassM + k] = n1d;         /* w1 */
               else          iw[igrid*nclassM + k] = n1d + 1 + ip[3]; /* w2 */
            }
         }
         else {   /* M8 */
            p0 = para[0][ip[0]];
            if (k < n1d) {  /* w from beta */
               p = para[1][ip[1]];
               q = para[2][ip[2]];
               cdf0 = 0;  cdf1 = 1;
               if (k > 0)       cdf0 = CDFBeta(k / (double)n1d, p, q, 0);
               if (k < n1d - 1) cdf1 = CDFBeta((k + 1.0) / n1d, p, q, 0);
               pclassM[igrid*nclassM + k] = p0*(cdf1 - cdf0);
               iw[igrid*nclassM + k] = k;
            }
            else {             /* ws */
               pclassM[igrid*nclassM + k] = 1 - p0;
               iw[igrid*nclassM + k] = n1d + ip[3];
            }
         }
      }
   }
}



int lfunNSsites_M2M8(FILE* frst, double x[], int np)
{
   /* Bayes empirical Bayes (BEB) correction for the posterior of w for each site
      under M2 or M8.  The integral is 3-d for M2, and 4-d for M2a or M8,
      approximated using n1d=10 categories in each dimension.  The ngrid=n1d^dim
      points make up the grid.

      com.ncatG is the number of all possible w's ever needed.  They are copied
      into com.rK[], to be used to calculate f(x_h|w), stored in com.fhK[], before
      entering the grid of 4-d integration.  iw[ngrid*nclassM] identifies the
      position of w in com.rK[], and pclassM[ngrid*nclassM] is the proportion
      of sites under the model.  Those are set up in get_pclassM_iw().

      The priors are set up in get_pclassM_iw_M2M8().  See notes there.
      Some control variables:
         M2a=1 for M2a=0 for M2.
         ternary=1: use ternary triangles to specify prior for p0-p1 under M2 or M2a
                =0: break p0 and p1 into 10 bins and skip the unfeasible points

      Parameters and their priors are as follows:
         M2 (p0 p1 w2)   : p0,p1~U(0,1),              w2~U(1,11)
         M2a(p0 p1 w0 w2): p0,p1~U(0,1), w0~U(0,1),   w2~U(1,11)
         M8 (p0 p  q  ws): p0~U(0,1),    p,q~U(0,2),  ws~U(1,11)

      Ziheng, Copenhagen, 17 May 2004.
   */
   int n1d = 10, M2a = 1, ternary = 1, trianglePriorM8 = 0, ip[4] = { 0 };
   double p0b[] = { 0,1 }, p1b[] = { 0,1 }, w0b[] = { 0,1 };  /* w0b for M2a only. */
   double wsb[] = { 1,11 };           /* for w2 in M2 & M2a, or for ws in M8 */
   double p_beta_b[] = { 0,2 }, q_beta_b[] = { 0,2 };

   int dim = (com.NSsites == 8 || M2a ? 4 : 3), ngrid, igrid, j, k, h, it;
   int refsp = 0, ncatG0 = com.ncatG;
   /* # of site classes under model and index for site class */
   int nclassM = (com.NSsites == NSpselection ? 3 : n1d + 1), iclassM, *iw;
   double para[4][100] = { {0} }, postpara[4][100];  /* paras on grid for 4-d integral: n1d<=100! */
   /* lnfXs is log of term in equation 5 in YWN05, which sums over those terms. */
   double fh, fX, *lnfXs, S1, S2, *lnprior, *pclassM, *meanw, *varw, *postSite, *postp0p1 = NULL;
   double fh1site, t, v;
   char timestr[32], *paras[4];

   printf("\nBEBing (dim = %d).  This may take several minutes.", dim);

   if (com.NSsites == 8)  {
      paras[0] = "p0"; paras[1] = "p"; paras[2] = "q"; paras[3] = "ws";
   }
   else if (!M2a)   {
      paras[0] = "p0"; paras[1] = "p1";  paras[2] = "w2";
   }
   else {
      paras[0] = "p0"; paras[1] = "p1";  paras[2] = "w0"; paras[3] = "w2";
   }

   ngrid = n1d*n1d*n1d*(dim == 4 ? n1d : 1);
   if (com.NSsites == 8) com.ncatG = n1d + n1d;  /* w from beta & ws */
   else               com.ncatG = (M2a ? n1d + 1 + n1d : 2 + n1d);  /* w0, w1=1, w2 */
   if ((meanw = (double*)malloc(com.npatt*(2 + nclassM) * sizeof(double))) == NULL)
      error2("oom meanw");
   varw = meanw + com.npatt;  postSite = varw + com.npatt;
   ternary = (com.NSsites == 2 && ternary);

   if (ternary && (postp0p1 = (double*)malloc(n1d*n1d * sizeof(double))) == NULL)
      error2("oom postp0p1");
   if ((lnfXs = (double*)malloc(ngrid * sizeof(double))) == NULL)
      error2("oom lnfXs");
   if ((pclassM = (double*)malloc(ngrid*nclassM*(sizeof(double) + sizeof(int)))) == NULL)
      error2("oom pclassM");  /* this wastes space */
   iw = (int*)(pclassM + ngrid*nclassM);
   if ((lnprior = (double*)malloc(n1d*n1d * sizeof(double))) == NULL)
      error2("oom lnprior");  /* this wastes space */

   k = com.npatt*com.ncatG * sizeof(double);
   if ((com.fhK = (double*)realloc(com.fhK, k)) == NULL) error2("oom fhK");

   for (j = 0; j < n1d*n1d; j++) lnprior[j] = 0;
   if (com.NSsites == 8 && trianglePriorM8) {
      /* for(j=0; j<n1d; j++) lnprior[j]=(2-1./n1d-j*2./n1d)/n1d; */
      for (j = 0; j < n1d; j++) lnprior[j] = (2 * j + 1.) / (n1d*n1d);
      printf("triangular prior for p0 under M8\n");
      for (j = 0; j < n1d; j++) printf("%9.4f", (2 * j + 1.) / (2 * n1d));  FPN(F0);
      for (j = 0; j < n1d; j++) printf("%9.4f", lnprior[j]);  FPN(F0);
   }

   BayesEB = 1;
   get_grid_para_like_M2M8(para, n1d, dim, M2a, ternary, p0b, p1b, w0b, wsb, p_beta_b, q_beta_b, x, &S1);
   get_pclassM_iw_M2M8(iw, pclassM, para, n1d, M2a, ternary);

   /* calculate log{fX}, the marginal likelihood,
      and posterior of parameters postpara[].  S2 is the scale factor. */
   printf("Calculating f(X), the marginal likelihood.\n");
   fX = 1;  S2 = -1e300;
   for (j = 0; j < dim; j++) for (k = 0; k < n1d; k++) postpara[j][k] = 1;
   if (ternary) for (k = 0; k < n1d*n1d; k++) postp0p1[k] = 1;
   for (igrid = 0; igrid < ngrid; igrid++) {
      for (j = dim - 1, it = igrid; j >= 0; j--) { ip[j] = it%n1d; it /= n1d; }
      if (com.NSsites == 2 && !ternary && para[0][ip[0]] + para[1][ip[1]] > 1)
         continue;
      lnfXs[igrid] = 0;
      for (h = 0; h < com.npatt; h++) {
         fh = 0;
         for (k = 0; k < nclassM; k++)
            fh += pclassM[igrid*nclassM + k] * com.fhK[iw[igrid*nclassM + k] * com.npatt + h];
         if (fh < 1e-300) {
            printf("strange: f[%3d] = %12.6g very small.\n", h, fh);
            continue;
         }
         lnfXs[igrid] += log(fh)*com.fpatt[h];
      }
      lnfXs[igrid] += (com.NSsites == 8 ? lnprior[ip[0]] : lnprior[ip[0] * n1d + ip[1]]);
      t = lnfXs[igrid] - S2;
      if (t > 50) {    /* reset scale factor S2 to lnfXs[igrid] */
         t = (t < 200 ? exp(-t) : 0);
         fX = fX*t + 1;
         for (j = 0; j < dim; j++)
            for (k = 0; k < n1d; k++)
               postpara[j][k] *= t;
         for (j = 0; j < dim; j++)
            postpara[j][ip[j]] ++;
         if (ternary) {
            for (k = 0; k < n1d*n1d; k++) postp0p1[k] *= t;
            postp0p1[ip[0] * n1d + ip[1]] ++;
         }
         S2 = lnfXs[igrid];
      }
      else if (t > -200) {
         t = exp(t);
         fX += t;
         for (j = 0; j < dim; j++)
            postpara[j][ip[j]] += t;
         if (ternary) postp0p1[ip[0] * n1d + ip[1]] += t;
      }
   }
   for (j = 0; j < dim; j++)
      for (k = 0; k < n1d; k++)
         postpara[j][k] /= fX;
   if (ternary)
      for (k = 0; k < n1d*n1d; k++)
         postp0p1[k] /= fX;

   fX = log(fX) + S2;
   printf("\tlog(fX) = %12.6f  S = %12.6f %12.6f\n", fX + S1 - dim*log(n1d*1.), S1, S2);

   /* calculate posterior probabilities and mean w for each site pattern.
      S1 and S2 are scale factors for probabilities and for w. */
   printf("Calculating f(w|X), posterior probabilities of site classes.\n");
   for (h = 0; h < com.npatt; h++) {
      S1 = -1e300;  FOR(j, nclassM) postSite[j*com.npatt + h] = 1;
      S2 = -1e300;  meanw[h] = varw[h] = 1;
      for (iclassM = 0; iclassM < nclassM; iclassM++) {
         for (igrid = 0; igrid < ngrid; igrid++) {
            for (j = dim - 1, it = igrid; j >= 0; j--) { ip[j] = it%n1d; it /= n1d; }
            if (com.NSsites == 2 && !ternary && para[0][ip[0]] + para[1][ip[1]] > 1)
               continue;
            for (k = 0, fh = 0; k < nclassM; k++) /* duplicated calculation */
               fh += pclassM[igrid*nclassM + k] * com.fhK[iw[igrid*nclassM + k] * com.npatt + h];
            it = igrid*nclassM + iclassM;
            fh1site = pclassM[it] * com.fhK[iw[it] * com.npatt + h];

            if (fh1site < 1e-300) continue;

            fh1site /= fh;
            t = log(fh1site) + lnfXs[igrid]; /* t is log of term on grid */
            if (t > S1) {  /* change scale factor S1 */
               for (j = 0; j < nclassM; j++)
                  postSite[j*com.npatt + h] = postSite[j*com.npatt + h] * exp(S1 - t);
               S1 = t;
            }
            postSite[iclassM*com.npatt + h] += exp(t - S1);

            t = fh1site*com.rK[iw[it]];
            v = fh1site*square(com.rK[iw[it]]);
            if (t < 1e-300) continue;
            t = log(t) + lnfXs[igrid]; /* t is log of mean */
            v = log(v) + lnfXs[igrid];
            if (t > S2) {  /* change scale factor S2 */
               meanw[h] = meanw[h] * exp(S2 - t);
               varw[h] = varw[h] * exp(S2 - t);
               S2 = t;
            }
            meanw[h] += exp(t - S2);
            varw[h] += exp(v - S2);
         }
      }

      for (j = 0; j < nclassM; j++)
         postSite[j*com.npatt + h] *= exp(S1 - fX);
      meanw[h] *= exp(S2 - fX);
      varw[h] *= exp(S2 - fX);
      varw[h] -= meanw[h] * meanw[h];
      varw[h] = (varw[h] > 0 ? sqrt(varw[h]) : 0);

      if ((h + 1) % 10 == 0 || h == com.npatt - 1)
         printf("\r\tdid %3d / %3d patterns  %s", h + 1, com.npatt, printtime(timestr));
   }  /* for(h) */

   /* print out posterior probabilities */
   fprintf(frst, "\nBayes Empirical Bayes (BEB) probabilities for %d classes (class)", nclassM);
   fprintf(fout, "\nBayes Empirical Bayes (BEB) analysis");
   fprintf(fout, " (Yang, Wong & Nielsen 2005. Mol. Biol. Evol. 22:1107-1118)");

   com.ncatG = ncatG0;
   PrintProbNSsites(frst, postSite, meanw, varw, nclassM, refsp);

   fprintf(fout, "\n\nThe grid %s\n\n", (ternary ? "(see ternary graph for p0-p1)" : ""));
   for (j = (ternary ? 2 : 0); j < dim; j++, FPN(fout)) {
      fprintf(fout, "%-2s: ", paras[j]);
      for (k = 0; k < n1d; k++)
         fprintf(fout, " %6.3f", para[j][k]);
   }
   if (ternary)  for (k = 0; k < n1d; k++) postpara[0][k] = postpara[1][k] = -1;
   fprintf(fout, "\n\nPosterior on the grid\n\n");
   for (j = (ternary ? 2 : 0); j < dim; j++, FPN(fout)) {
      fprintf(fout, "%-2s: ", paras[j]);
      for (k = 0; k < n1d; k++)
         fprintf(fout, " %6.3f", postpara[j][k]);
   }
   if (ternary) {
      fprintf(fout, "\nPosterior for p0-p1 (see the ternary graph) (YWN2015, fig. 1)\n\n");
      for (k = 0; k < n1d*n1d; k++) {
         fprintf(fout, " %5.3f", postp0p1[k]);
         if (fabs(square((int)sqrt(k + 1.)) - (k + 1)) < 1e-5) FPN(fout);
      }
      fprintf(fout, "\nsum of density on p0-p1 = %10.6f\n", sum(postp0p1, n1d*n1d));
   }

   BayesEB = 0;
   free(meanw);  free(lnfXs);  free(pclassM);  free(lnprior);
   if (ternary) free(postp0p1);
   return(0);
}



void get_grid_para_like_ACD(double para[][40], int n1d, int dim, double w0b[], double w1b[], double w2b[], double x[], double *S)
{
   /* This sets up the grid (para[][]) according to the uniform priors.
      It calculates the probability of data at each site given w: f(x_h|w), using the
      branch model (NSsites = 0 model = 2), with BayesEB=2 to force the use of the
      correct scale factors in GetPMatBranch().

      Order of site classes for iw or f(x_h|w):
                           back    fore     #sets
      Branchsite A (121 sets)
         site class 0:      w0     w0        10
         site class 1:      w1=1   w1=1       1
         site class 2a:     w0     w2       100
         site class 2b:     w1=1   w2        10

      Clade C      (111 sets if nbtype=2 or 1011 sets if nbtype=3)
         site class 0:      w0     w0        10
         site class 1:      w1=1   w1=1       1
         site class 2:      w2     w3        10*10*10... (d^nbtype)

      Clade D      (120 sets if nbtype=2 or 1020 sets if nbtype=3)
         site class 0:      w0     w0        10
         site class 1:      w1     w1        10
         site class 2:      w2     w3        10*10*10... (d^nbtype)
   */
   enum ModelsACD { mA, mC, mD };
   int modelACD = (com.model == 2 ? mA : (com.NSsites == 2 ? mC : mD));
   int i, k, h, iw;
   double fh, wbranches[NBTYPE];  /* w for back and fore branches, for each site class */
   int NSsites0 = com.NSsites, model0 = com.model;

   /* setting up parameter values (p0 p1 w0 w2 w3 ...) at the d=10 points */
   if (modelACD == mA) {
      for (i = 0; i < n1d; i++) {
         para[0][i] = para[1][i] = -1;                       /* p0 & p1 */
         para[2][i] = (i + 0.5) / n1d;                           /* w0 (0, 1) */
         para[3][i] = w2b[0] + (i + 0.5)*(w2b[1] - w2b[0]) / n1d;  /* w2 */
      }
   }
   else if (modelACD == mC) {
      for (i = 0; i < n1d; i++) {
         para[0][i] = para[1][i] = -1;                       /* p0 & p1 */
         para[2][i] = (i + 0.5) / n1d;                           /* w0 (0, 1) */
         for (k = 0; k < com.nbtype; k++)                         /* w2 w3 w4... */
            para[3 + k][i] = w2b[0] + (i + 0.5)*(w2b[1] - w2b[0]) / n1d;;
      }
   }
   else {             /* clade model D */
      for (i = 0; i < n1d; i++) {
         para[0][i] = para[1][i] = -1;                       /* p0 & p1 */
         para[2][i] = w0b[0] + (i + 0.5)*(w0b[1] - w0b[0]) / n1d;  /* w0 */
         para[3][i] = w1b[0] + (i + 0.5)*(w1b[1] - w1b[0]) / n1d;  /* w1 */
         for (k = 0; k < com.nbtype; k++)                         /* w2 w3 w4... */
            para[4 + k][i] = w2b[0] + (i + 0.5)*(w2b[1] - w2b[0]) / n1d;
      }
   }

   /* calculates the prob for each site pattern, com.fhK[] */
   printf("\nCalculating f(x_h|w) for %d w's\n", com.ncatG);
   com.conPSiteClass = 0;
   *S = 0;
   com.model = 2;
   com.NSsites = 0;
   com.pomega = wbranches;
   for (iw = 0; iw < com.ncatG; iw++) {  /* com.ncatG has the number of w values for each site */
      if (modelACD == mA) {                            /* model A:  10 + 1 + 100 + 10 */
         if (iw < n1d)        wbranches[0] = wbranches[1] = para[2][iw]; /* class 0:  w0 */
         else if (iw == n1d)  wbranches[0] = wbranches[1] = 1;           /* class 1:  w1 */
         else if (iw < n1d + 1 + n1d*n1d) {                                  /* class 2a: w0 w2 */
            wbranches[0] = para[2][(iw - n1d - 1) / n1d];
            wbranches[1] = para[3][(iw - n1d - 1) % n1d];
         }
         else {                                                       /* class 2b: w1 w2 */
            wbranches[0] = 1;
            wbranches[1] = para[3][iw - n1d - 1 - n1d*n1d];
         }
      }
      else if (modelACD == mC) {                       /* model C:  10 + 1 + 10*10*... */
         if (iw < n1d)                                                   /* class 0: w0 */
            for (i = 0; i < com.nbtype; i++) wbranches[i] = para[2][iw];
         else if (iw == n1d)                                             /* class 1: w1 */
            for (i = 0; i < com.nbtype; i++) wbranches[i] = 1;
         else {                                                       /* class 2: w2 w3... */
            for (i = com.nbtype - 1, k = iw - n1d - 1; i >= 0; i--) {
               wbranches[i] = para[3 + i][k%n1d];
               k /= n1d;
            }
         }
      }
      else if (modelACD == mD) {                        /* model D:  10 + 10 + 10*10*... */
         if (iw < n1d)                                                   /* class 0: w0 */
            for (i = 0; i < com.nbtype; i++) wbranches[i] = para[2][iw];
         else if (iw < n1d * 2)                                            /* class 1: w1 */
            for (i = 0; i < com.nbtype; i++) wbranches[i] = para[3][iw - n1d];
         else {                                                       /* class 2: w2 w3... */
            for (i = com.nbtype - 1, k = iw - n1d * 2; i >= 0; i--) {
               wbranches[i] = para[4 + i][k%n1d];
               k /= n1d;
            }
         }
         /*
         printf("\nw set %3d: ", iw+1);
         for(i=0; i<com.nbtype; i++) printf(" %10.6f", wbranches[i]);
         */
      }
      ConditionalPNode(tree.root, 0, x);
      for (h = 0; h < com.npatt; h++) {
         for (i = 0, fh = 0; i < com.ncode; i++)
            fh += com.pi[i] * nodes[tree.root].conP[h*com.ncode + i];
         if (fh <= 0) {
            if (fh < -1e-5) printf("\nfh = %.6f negative\n", fh);
            fh = 1e-300;
         }
         fh = log(fh);
         for (k = 0; k < com.NnodeScale; k++)
            fh += com.nodeScaleF[k*com.npatt + h];
         com.fhK[iw*com.npatt + h] = fh;
      }
      if ((iw + 1) % 10 == 0 || iw == com.ncatG - 1) {
         printf("\r\t %4d / %d sets.  w for branches: ", iw + 1, com.ncatG);
         for (i = 0; i < com.nbtype; i++) printf(" %6.4f", wbranches[i]);
         for (h = 0, fh = 0; h < com.npatt; h++)
            fh += com.fpatt[h] * com.fhK[iw*com.npatt + h];
         printf(" lnfX = %8.4f", fh);
      }
   }
   printf("\n");

   for (h = 0, *S = 0; h < com.npatt; h++) {
      for (k = 1, fh = com.fhK[h]; k < com.ncatG; k++)
         fh = max2(fh, com.fhK[k*com.npatt + h]);
      for (k = 0; k < com.ncatG; k++)
         com.fhK[k*com.npatt + h] = exp(com.fhK[k*com.npatt + h] - fh);
      *S += fh*com.fpatt[h];
   }
   com.NSsites = NSsites0;  com.model = model0;
}

void get_pclassM_iw_ACD(int iw[], double pclassM[], double para[][40], int n1d)
{
   /* This sets up iw[mgrid*nclassM] and iclassM[mgrid*nclassM], where iw locates the
      correct f(x_h|w) stored in com.fhK[], and pclassM has the proportion for the site
      class and the prior.
      The n1d*n1d grid for p0-p1 is mapped onto the ternary graph for p0-p1-p2.

      See get_grid_para_like_ACD() for order of iw or site classes.

      Parameters are model A: (p0 p1 w0 w2)
                     model C: (p0 p1 w0 w2 w3 ...)
                     model D: (p0 p1 w0 w1 w2 w3 ...)
   */
   enum ModelsACD { mA, mC, mD };
   int modelACD = (com.model == 2 ? mA : (com.NSsites == 2 ? mC : mD));
   double p[3];        /* p0 p1 p2 for site classes */
   int nclassM = (modelACD == mA ? 4 : 3), dim, ngrid, igrid, ip[4 + NBTYPE], i, j, k, it;

   if (modelACD == mA)  dim = 4;
   else              dim = 3 + (modelACD == mD) + com.nbtype;
   for (i = 0, ngrid = 1; i < dim; i++) ngrid *= n1d;

   for (igrid = 0; igrid < ngrid; igrid++) {
      for (j = dim - 1, it = igrid; j >= 0; j--) { ip[j] = it%n1d; it /= n1d; }
      for (k = 0; k < nclassM; k++) {
         GetIndexTernary(&i, &j, &p[0], &p[1], ip[0] * n1d + ip[1], n1d);
         p[2] = 1 - p[0] - p[1];
         pclassM[igrid*nclassM + k] = p[k <= 2 ? k : 2];
         if (modelACD == mA && k >= 2)  pclassM[igrid*nclassM + k] = p[2] * p[k - 2] / (1 - p[2]);

         switch (modelACD) {
         case(mA):
            if (k == 0)       iw[igrid*nclassM + k] = ip[2];                 /* class 0: w0 */
            else if (k == 1)  iw[igrid*nclassM + k] = n1d;                   /* class 1: w1=1 */
            else if (k == 2)  iw[igrid*nclassM + k] = n1d + 1 + ip[2] * n1d + ip[3]; /* class 2a model A: w0 & w2 */
            else           iw[igrid*nclassM + k] = n1d + 1 + n1d*n1d + ip[3];   /* class 2b model A: w1=1 & w2 */
            break;
         case(mC):
            if (k == 0)       iw[igrid*nclassM + k] = ip[2];     /* class 0: w0 */
            else if (k == 1)  iw[igrid*nclassM + k] = n1d;       /* class 1: w1=1 */
            else {                                          /* class 2: w2 w3 w4 ... */
               for (i = 0, j = 0; i < com.nbtype; i++)
                  j = j*n1d + ip[3 + i];
               iw[igrid*nclassM + k] = n1d + 1 + j;
            }
            break;
         case(mD):
            if (k == 0)       iw[igrid*nclassM + k] = ip[2];     /* class 0: w0 */
            else if (k == 1)  iw[igrid*nclassM + k] = n1d + ip[3]; /* class 1: w1 */
            else {                                          /* class 2: w2 w3 w4 ... */
               for (i = 0, j = 0; i < com.nbtype; i++)
                  j = j*n1d + ip[4 + i];
               iw[igrid*nclassM + k] = n1d * 2 + j;
            }
         }
      }
   }
}


int lfunNSsites_ACD(FILE* frst, double x[], int np)
{
   /* Bayes empirical Bayes (BEB) calculation of posterior probabilities for site
      classes under the branch-site model A, and clade models C and D.
      The dimension of integral is
         4 for A (p0 p1 w0 w2),
         3 + nbtype for C (p0 p1 w0 w2 w3...), and
         4 + nbtype for D (p0 p1 w0 w1 w2 w3...).
      Each dimension is approximated using d=n1d=10 bins, and the grid is made up of
      ngrid=d^dim points.

      For branch-site model A, the probability of data at any site f(x_h|w) needs to
      be calculated for 121=(d+1+d*d+d) sets of w's (w0, w1=1, w0*w2, w1*w2).
      For clade model C, it needs to be calculated for 111 (d+1+d^nbtype) sets (for w0, w1=1, w2*w3*w4...).
      For clade model D, it needs to be calculated for 120 (d+d+d^nbtype) sets (for w0, w1, w2*w3*w4...).
      The f(x_h|w) values are calculated and stored in com.fhK[], before entering the grid.
      iw[ngrid*nclassM] identifies the right f(x_h|w), and pclassM[ngrid*nclassM]
      is the proportion of sites under the model, f(w).  Those are set up in
      get_pclassM_iw_ACD().

      The priors are set up in get_pclassM_iw_ACD().  See notes there.

      Parameters and priors are as follows:
         model A (p0 p1 w0 w2):       p0,p1~Dir(1,1,1), w0~U(0,1), w2~U(1,11)
         model C (p0 p1 w0 w2 w3):    p0,p1~Dir(1,1,1), w0~U(0,1), w2,w3~U(0,3)
         model D (p0 p1 w0 w1 w2 w3): p0,p1~Dir(1,1,1), w0,w1~U(0,1), w2,w3~U(0,3)

      22 September 2004, for YWN2005.
      Nov 2008, modified to use more than 2 branch types under clade model C.
      8 March 2016, added BEB for clade model D.  deleted ncatG=2 for D so that ncatG=3 for A C D.
   */
   int n1d = 10, debug = 0, site = 0;
   double w0b[] = { 0.0, 0.5 };  /* bounds for w0 */
   double w1b[] = { 0.5, 1.5 };  /* bounds for w1 (for model D only) */
   double wsb[] = { 1, 11 };     /* bounds for w2 in model A */
   double w2b[] = { 0, 3 };      /* bounds for w2 w3 w4... in clade models C & D */
   enum ModelsACD { mA, mC, mD };
   int modelACD = (com.model == 2 ? mA : (com.NSsites == 2 ? mC : mD));
   int dim, ngrid, igrid, ip[4 + NBTYPE], j, k, h, hp, it;
   int refsp = 0, ncatG0 = com.ncatG, lst = (com.readpattern ? com.npatt : com.ls);
   /* # of site classes under model and index for site class */
   int nclassM = (modelACD == mA ? 4 : 3), *iw, i;
   double para[4 + NBTYPE][40] = { {0} }, postpara[4 + NBTYPE][40];  /* paras on grid : n1d<=40 */
   double fh, fX, *lnfXs, S1, S2, *pclassM, *postSite, *postp0p1;
   double fhk[4], t, cutoff = 0.5;
   char timestr[32], paras[4 + NBTYPE][4] = { "p0","p1","w0","w2","w3","w4","w5","w6","w7" }, *sig, aa;

   if (modelACD == mA)  dim = 4;
   else              dim = 3 + (modelACD == mD) + com.nbtype;
   printf("\nBEBing (dim = %d).  This may take many minutes.", dim);

   if (modelACD == mD) { /* "p0","p1","w0","w1","w2","w3"... */
      for (i = 0; i < com.nbtype + 1; i++) sprintf(paras[3 + i], "w%d", i + 1);
   }

   for (i = 0, ngrid = 1; i < dim; i++) ngrid *= n1d;
   if (modelACD == mA)
      com.ncatG = n1d + 1 + n1d*n1d + n1d;  /* branch-site model A: table 1 YWN05 */
   else if (modelACD == mC) {                  /* clade model C: table 2 YWN05 */
      for (i = 0, com.ncatG = 1; i < com.nbtype; i++) com.ncatG *= n1d;  /* w2 w3 w4 ... */
      com.ncatG += n1d + 1;                 /* w0 & w1=1 */
   }
   else {                                   /* clade model D */
      for (i = 0, com.ncatG = 1; i < com.nbtype; i++) com.ncatG *= n1d;  /* w2 w3 w4 ... */
      com.ncatG += n1d * 2;                 /* w0 & w1 */
   }

   k = (n1d*n1d + com.npatt*nclassM + ngrid + ngrid*nclassM) * sizeof(double)
      + ngrid*nclassM * sizeof(int);
   if (noisy) printf("\nTrying to get %.1fM memory in lfunNSsites_ACD\n", k / 1000000.0);
   if ((postp0p1 = (double*)malloc(k)) == NULL)
      error2("oom in lfunNSsites_ACD");
   postSite = postp0p1 + n1d*n1d;
   lnfXs = postSite + com.npatt*nclassM;
   pclassM = lnfXs + ngrid;
   iw = (int*)(pclassM + ngrid*nclassM);

   k = com.npatt*com.ncatG * sizeof(double);
   if ((com.fhK = (double*)realloc(com.fhK, k)) == NULL) error2("oom fhK");

   BayesEB = 2;
   get_grid_para_like_ACD(para, n1d, dim, w0b, w1b, (modelACD == mA ? wsb : w2b), x, &S1);
   get_pclassM_iw_ACD(iw, pclassM, para, n1d);

   /* calculate the marginal likelihood f(X), and postpara[].  S2 is scale. */
   printf("Time: %s\n", printtime(timestr));
   printf("Calculating the marginal likelihood f(X).\n");
   fX = 1;  S2 = -1e300;
   for (j = 0; j < dim; j++)  /* postpara[0-1] for p0p1 ignored */
      for (k = 0; k < n1d; k++)
         postpara[j][k] = 0;
   for (k = 0; k < n1d*n1d; k++)
      postp0p1[k] = 0;
   for (igrid = 0; igrid < ngrid; igrid++) {
      for (j = dim - 1, it = igrid; j >= 0; j--) { ip[j] = it%n1d;  it /= n1d; }
      lnfXs[igrid] = 0; /* log likelihood value for whole data at igrid */
      for (h = 0; h < com.npatt; h++) {
         fh = 0;
         for (k = 0; k < nclassM; k++)
            fh += pclassM[igrid*nclassM + k] * com.fhK[iw[igrid*nclassM + k] * com.npatt + h];
         if (fh < 1e-300) {
            printf("strange: f[%3d] = %12.6g very small.\n", h, fh);
            continue;
         }
         lnfXs[igrid] += log(fh)*com.fpatt[h];
      }
      t = lnfXs[igrid] - S2;
      if (t > 10) {    /* change scale factor S2 */
         t = (t < 200 ? exp(-t) : 0);
         fX = fX*t + 1;
         for (j = 0; j < dim; j++)
            for (k = 0; k < n1d; k++)
               postpara[j][k] *= t;
         for (k = 0; k < n1d*n1d; k++)
            postp0p1[k] *= t;

         for (j = 0; j < dim; j++)
            postpara[j][ip[j]] ++;
         postp0p1[ip[0] * n1d + ip[1]] ++;
         S2 = lnfXs[igrid];
      }
      else if (t > -200) {
         t = exp(t);
         fX += t;
         for (j = 0; j < dim; j++)
            postpara[j][ip[j]] += t;
         postp0p1[ip[0] * n1d + ip[1]] += t;
      }
      if ((igrid + 1) % 1000 == 0 || igrid == ngrid - 1)
         printf("\t%3d / %3d grid points, %s\r", igrid + 1, ngrid, printtime(timestr));

      if (debug) {
         printf("\n\nigrid %5d, fX=%8.5f  S2=%8.5f  fXigrid=%9.5f", igrid, fX, S2, lnfXs[igrid]);
         printf("  w%2d%2d%2d%2d ", ip[2], ip[3], ip[4], ip[5]);
      }
   }
   for (j = 0; j < dim; j++) for (k = 0; k < n1d; k++)
      postpara[j][k] /= fX;
   for (k = 0; k < n1d*n1d; k++)
      postp0p1[k] /= fX;

   fX = log(fX) + S2;
   printf("\tlog(fX) = %12.6f  S = %12.6f %12.6f\n", fX + S1 - dim*log((double)n1d), S1, S2);

   /* calculate posterior prob for site classes at each site.  S1 is scale factor */
   printf("Calculating f(w_k|X), posterior for site classes for each site.  Slow!\n");
   for (h = 0; h < com.npatt; h++) {
      for (j = 0; j < nclassM; j++)
         postSite[j*com.npatt + h] = 0;
      for (igrid = 0; igrid < ngrid; igrid++) {
         for (j = dim - 1, it = igrid; j >= 0; j--) { ip[j] = it%n1d; it /= n1d; }
         for (k = 0, fh = 0; k < nclassM; k++) /* duplicated calculation */
            fh += fhk[k] = pclassM[igrid*nclassM + k] * com.fhK[iw[igrid*nclassM + k] * com.npatt + h];
         for (k = 0; k < nclassM; k++) {    /* log & exp in this loop is expensive  */
            t = log(fhk[k] / fh) + lnfXs[igrid] - fX;
            if (t > -300) postSite[k*com.npatt + h] += exp(t);
         }
      }
      if ((h + 1) % 10 == 0 || h == com.npatt - 1)
         printf("\r\tdid %3d / %3d site patterns  %s", h + 1, com.npatt, printtime(timestr));
   }  /* for(h) */

   if (debug)
      for (k = 0, printf("\nS%d: ", site); k < nclassM; k++) printf("%7.4f", postSite[k*com.npatt + site]);

   /* print out posterior probabilities */
   fprintf(frst, "\nBayes Empirical Bayes (BEB) probabilities for %d classes (class)", nclassM);
   fprintf(fout, "\nBayes Empirical Bayes (BEB) analysis");
   fprintf(fout, " (Yang, Wong & Nielsen 2005. Mol. Biol. Evol. 22:1107-1118)");

   com.ncatG = ncatG0;

   PrintProbNSsites(frst, postSite, NULL, NULL, nclassM, refsp);
   if (modelACD == mA) {  /* branch&site model A */
      fprintf(fout, "\nPositive sites for foreground lineages Prob(w>1):\n");
      for (h = 0; h < lst; h++) {
         hp = (!com.readpattern ? com.pose[h] : h);
         aa = GetAASiteSpecies(refsp, hp);
         t = postSite[2 * com.npatt + hp] + postSite[3 * com.npatt + hp]; /* class 2A or 2B */
         if (t > cutoff) {
            sig = "";  if (t > .95) sig = "*";  if (t > .99) sig = "**";
            fprintf(fout, "%6d %c %.3f%s\n", h + 1, aa, t, sig);
         }
      }
   }

   fprintf(fout, "\n\nThe grid (see ternary graph for p0-p1)\n\n");
   for (j = 2; j < dim; j++, FPN(fout)) {
      fprintf(fout, "%-2s: ", paras[j]);
      for (k = 0; k < n1d; k++)
         fprintf(fout, " %6.3f", para[j][k]);
   }
   for (k = 0; k < n1d; k++)
      postpara[0][k] = postpara[1][k] = -1;
   fprintf(fout, "\n\nPosterior on the grid\n\n");
   for (j = 2; j < dim; j++, FPN(fout)) {
      fprintf(fout, "%-2s: ", paras[j]);
      for (k = 0; k < n1d; k++)
         fprintf(fout, " %6.3f", postpara[j][k]);
   }
   fprintf(fout, "\nPosterior for p0-p1 (see the ternary graph) (YWN2015, fig. 1)\n\n");
   for (k = 0; k < n1d*n1d; k++) {
      fprintf(fout, " %5.3f", postp0p1[k]);
      if (fabs(square((int)sqrt(k + 1.)) - (k + 1)) < 1e-5) FPN(fout);
   }
   fprintf(fout, "\nsum of density on p0-p1 = %10.6f\n", sum(postp0p1, n1d*n1d));

   free(postp0p1);
   BayesEB = 0;
   return(0);
}
