/*
 * puzzle1.c
 *
 *
 * Part of TREE-PUZZLE 5.2 (February 2005)
 *
 * (c) 2003-2005 by Heiko A. Schmidt, Korbinian Strimmer, and Arndt von Haeseler
 * (c) 1999-2003 by Heiko A. Schmidt, Korbinian Strimmer,
 *                  M. Vingron, and Arndt von Haeseler
 * (c) 1995-1999 by Korbinian Strimmer and Arndt von Haeseler
 *
 * All parts of the source except where indicated are distributed under
 * the GNU public licence.  See http://www.opensource.org for details.
 *
 * ($Id$)
 *
 */
#define USE_GTR 1

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#if !PARALLEL
#  ifdef USE_CONSOLE_H
#    include <console.h>
#  endif
#endif

#define EXTERN

#include "puzzle.h"
#include "gamma.h"
#include "treetest.h"

#if PARALLEL
#	include "ppuzzle.h"
#endif

/*epe*/
#ifdef VT
#	include <VT.h>
#endif



/******* debugging stuff - HAS ;-) ********/

int PPP1=0;
/* fprintf(stderr, "PPP1: %d (%s:%d)\n", PPP1++, __FILE__, __LINE__); */
/* fputid(stderr, 65); fprintf(stderr, " = 65 (%s:%d - 666)\n", __FILE__, __LINE__); */


void fprintftimespan(FILE *ofp, time_t start, time_t stop, time_t allstart, char *comment)
{
	double timespan;
	timespan = difftime(stop, start);
	fprintf(ofp, "TTT: %-25s took %.0f seconds (= %.1f minutes = %.1f hours)\n",
			comment, timespan, timespan/60., timespan/3600.);
	timespan = difftime(stop, allstart);
	fprintf(ofp, "TTT:                from beginning: %.0f seconds (= %.1f minutes = %.1f hours)\n",
			timespan, timespan/60., timespan/3600.);
	fflush(ofp);
}

/******* end of debugging stuff - HAS ;-) ********/


void tp_exit(int exitcode, char *exitstr, int printline, char *fname, int fline, int dowait)
{
	if(exitstr != NULL) {
        	fprintf(stderr, "%s", exitstr);
		if(printline) fprintf(stderr, " (%s:%d)", fname, fline);
        	fprintf(stderr, "\n");
	}
#	if PARALLEL
		PP_Finalize();
#	endif
	
	if(dowait) {
		printf("\npress [return] to finish: ");
		fflush(stdout);
		while (getchar() != '\n');
	}
	exit(exitcode);
} /* tp_exit */

void num2quart(uli qnum, int *a, int *b, int *c, int *d)
{
        double temp;
        uli aa, bb, cc, dd;
        uli lowval=0, highval=0;

        aa=0; bb=1; cc=2; dd=3;

        temp = (double)(24 * qnum);
        temp = sqrt(temp);
        temp = sqrt(temp);
        /* temp = pow(temp, (double)(1/4)); */
        dd = (uli) floor(temp) + 1;
        if (dd < 3) dd = 3;
        lowval =  (uli) dd*(dd-1)*(dd-2)*(dd-3)/24;
        highval = (uli) (dd+1)*dd*(dd-1)*(dd-2)/24;
        if (lowval >= qnum)
            while ((lowval > qnum)) {
                dd -= 1; lowval = (uli) dd*(dd-1)*(dd-2)*(dd-3)/24;
            }
        else {
            while (highval <= qnum) {
                dd += 1; highval = (uli) (dd+1)*dd*(dd-1)*(dd-2)/24;
            }
            lowval = (uli) dd*(dd-1)*(dd-2)*(dd-3)/24;
        }
        qnum -= lowval;
        if (qnum > 0) {
            temp = (double)(6 * qnum);
            temp = pow(temp, (double)(1/3));
            cc = (uli) floor(temp);
            if (cc < 2) cc= 2;
            lowval =  (uli) cc*(cc-1)*(cc-2)/6;
            highval = (uli) (cc+1)*cc*(cc-1)/6;
            if (lowval >= qnum)
                while ((lowval > qnum)) {
                   cc -= 1; lowval = (uli) cc*(cc-1)*(cc-2)/6;
                }
            else {
                while (highval <= qnum) {
                   cc += 1; highval = (uli) (cc+1)*cc*(cc-1)/6;
                }
                lowval = (uli) cc*(cc-1)*(cc-2)/6;
            }
            qnum -= lowval;
            if (qnum > 0) {
                temp = (double)(2 * qnum);
                temp = sqrt(temp);
                bb = (uli) floor(temp);
                if (bb < 1) bb= 1;
                lowval =  (uli) bb*(bb-1)/2;
                highval = (uli) (bb+1)*bb/2;
                if (lowval >= qnum)
                    while ((lowval > qnum)) {
                        bb -= 1; lowval = (uli) bb*(bb-1)/2;
                    }
                else {
                    while (highval <= qnum) {
                       bb += 1; highval = (uli) (bb+1)*bb/2;
                    }
                    lowval = (uli) bb*(bb-1)/2;
                }
                qnum -= lowval;
                if (qnum > 0) {
                   aa = (uli) qnum;
                   /* if (aa < 0) aa= 0; */ /* obsolete, because unsigned integers cannot be < 0 - HAS ;^) */
                }
            }
        }
        *d = (int)dd;
        *c = (int)cc;
        *b = (int)bb;
        *a = (int)aa;
}  /* num2quart */

/******************/

uli numquarts(int maxspc)
{
   uli tmp;
   int a, b, c, d;

   if (maxspc < 4)
     return (uli)0;
   else {
      maxspc--;
      a = maxspc-3;
      b = maxspc-2;
      c = maxspc-1;
      d = maxspc;

      tmp = (uli) 1 + a +
            (uli) b * (b-1) / 2 +
            (uli) c * (c-1) * (c-2) / 6 +
            (uli) d * (d-1) * (d-2) * (d-3) / 24;
      return (tmp);
   }
}  /* numquarts */

/******************/

uli quart2num (int a, int b, int c, int d)
{
      uli tmp;
      if ((a>b) || (b>c) || (c>d)) {
         fprintf(stderr, "Error PP5 not (%d <= %d <= %d <= %d) !!!\n", a, b, c,
d);
#	 if 0
#	 if PARALLEL
		PP_Finalize();
#	 endif
         exit (1);
#	 endif
         tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
      }
      tmp = (uli) a +
            (uli) b * (b-1) / 2 +
            (uli) c * (c-1) * (c-2) / 6 +
            (uli) d * (d-1) * (d-2) * (d-3) / 24;
      return (tmp);
}  /* quart2num */

/******************/



/*  flag=0	old allquart binary  */
/*  flag=1	allquart         binary  */
/*  flag=2	allquart         ACSII   */
/*  flag=3	quartlh          binary  */
/*  flag=4	quartlh          ASCII   */
/*  flag=5	quartlh + brlen  binary  */
/*  flag=6	quartlh + brlen  ASCII   */
/*  flag=7	quartlh          binary, no check double */
/*  flag=8	quartlh + brlen  binary, no check double */

void writetpqfheader(int            nspec,
                     FILE          *ofp,
                     int            flag)
{ int            currspec;

  if (flag == 0) {
     unsigned long  nquart;
     unsigned long  blocklen;

     nquart = numquarts(nspec);
     /* compute number of bytes */
     if (nquart % 2 == 0) { /* even number */
        blocklen = (nquart)/2;
     } else { /* odd number */
        blocklen = (nquart + 1)/2;
     }
     /* fprintf(STDOUT, "Writing quartet file: %s\n", filename); */
     fprintf(ofp, "TREE-PUZZLE\n%s\n\n", VERSION);
     fprintf(ofp, "species: %d\n",       nspec);
     fprintf(ofp, "quartets: %lu\n",     nquart);
     fprintf(ofp, "bytes: %lu\n\n",      blocklen);


     /* fwrite(&(quartetinfo[0]), sizeof(char), blocklen, ofp); */
  }

  if (flag == 1) fprintf(ofp, "##TPQF-BB (TREE-PUZZLE %s)\n%d\n", VERSION, nspec); /* with check-double */
  if (flag == 2) fprintf(ofp, "##TPQF-BA (TREE-PUZZLE %s)\n%d\n", VERSION, nspec);
  if (flag == 3) fprintf(ofp, "##TPQF-LB (TREE-PUZZLE %s)\n%d\n", VERSION, nspec); /* with check-double */
  if (flag == 4) fprintf(ofp, "##TPQF-LA (TREE-PUZZLE %s)\n%d\n", VERSION, nspec);
  if (flag == 5) fprintf(ofp, "##TPQF-EB (TREE-PUZZLE %s)\n%d\n", VERSION, nspec); /* with check-double */
  if (flag == 6) fprintf(ofp, "##TPQF-EA (TREE-PUZZLE %s)\n%d\n", VERSION, nspec);
  if (flag == 7) fprintf(ofp, "##TPQF-LN (TREE-PUZZLE %s)\n%d\n", VERSION, nspec); /* no check-double */
  if (flag == 8) fprintf(ofp, "##TPQF-EN (TREE-PUZZLE %s)\n%d\n", VERSION, nspec); /* no check-double */

  for (currspec=0; currspec<nspec; currspec++) {
     fputid(ofp, currspec);
     fprintf(ofp, "\n");
  } /* for each species */
  fprintf(ofp, "\n");

  if ((flag == 0)||(flag == 1)||(flag == 3)||(flag == 5)) {
	double ttt;
	((unsigned char*)(&ttt))[0]=(unsigned char)0xaf;
	((unsigned char*)(&ttt))[1]=(unsigned char)0xfe;
	((unsigned char*)(&ttt))[2]=(unsigned char)0xaf;
	((unsigned char*)(&ttt))[3]=(unsigned char)0xfe;
	((unsigned char*)(&ttt))[4]=(unsigned char)0xab;
	((unsigned char*)(&ttt))[5]=(unsigned char)0xcc;
	((unsigned char*)(&ttt))[6]=(unsigned char)0xab;
	((unsigned char*)(&ttt))[7]=(unsigned char)0xcc;
  	fwrite(&ttt, sizeof(double), 1, ofp);
  }

} /* writetpqfheader */



void writeallquarts(int            nspec,
                    char          *filename,
                    unsigned char *quartetinfo)
{ unsigned long  nquart;
  unsigned long  blocklen;
  FILE          *ofp;

  nquart = numquarts(nspec);

  /* compute number of bytes */
  if (nquart % 2 == 0) { /* even number */
     blocklen = (nquart)/2;
  } else { /* odd number */
     blocklen = (nquart + 1)/2;
  }

  fprintf(STDOUT, "Writing quartet file: %s\n", filename);

  openfiletowrite(&ofp, filename, "all quartets", stdinput_fp);

  writetpqfheader(nspec, ofp, 0);

  fwrite(&(quartetinfo[0]), sizeof(char), blocklen, ofp);

  /* if ((flag == 1)||(flag == 3)||(flag == 5)) { */
  {
	double ttt;
	((unsigned char*)(&ttt))[0]=(unsigned char)0xaf;
	((unsigned char*)(&ttt))[1]=(unsigned char)0xfe;
	((unsigned char*)(&ttt))[2]=(unsigned char)0xaf;
	((unsigned char*)(&ttt))[3]=(unsigned char)0xfe;
	((unsigned char*)(&ttt))[4]=(unsigned char)0xab;
	((unsigned char*)(&ttt))[5]=(unsigned char)0xcc;
	((unsigned char*)(&ttt))[6]=(unsigned char)0xab;
	((unsigned char*)(&ttt))[7]=(unsigned char)0xcc;
  	fwrite(&ttt, sizeof(double), 1, ofp);
  }
  fclose(ofp);

} /* writeallquart */



void readallquarts(int            nspec,
                   char          *filename,
                   unsigned char *quartetinfo)
{ unsigned long  nquart;
  unsigned long  blocklen;
  int            currspec;
  unsigned long  dummynquart;
  unsigned long  dummyblocklen;
  int            dummynspec;
  char           dummyversion[128];
  char           dummyname[128];
  FILE          *ifp;

  nquart = numquarts(nspec);

  /* compute number of bytes */
  if (nquart % 2 == 0) { /* even number */
     blocklen = (nquart)/2;
  } else { /* odd number */
     blocklen = (nquart + 1)/2;
  }

/*  &(quartetinfo[0] */

  openfiletoread(&ifp, filename, "all quartets", stdinput_fp);

  fscanf(ifp, "TREE-PUZZLE\n");
  fscanf(ifp, "%s\n\n", dummyversion);
  
  fscanf(ifp, "species: %d\n",   &dummynspec);
  fscanf(ifp, "quartets: %lu\n", &dummynquart);
  fscanf(ifp, "bytes: %lu\n\n",  &dummyblocklen);

  if ((nspec != dummynspec) ||
      (nquart != dummynquart) ||
      (blocklen != dummyblocklen)) {
     fprintf(STDOUT, "ERROR: Parameters in quartet file %s do not match!!!\n",
                     filename);
#    if 0
#    if PARALLEL
         PP_SendDone();
         MPI_Finalize();
#    endif /* PARALLEL */
     exit(1);
#    endif
#    if PARALLEL
         PP_SendDone();
#    endif /* PARALLEL */
     tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
  }

  fprintf(STDOUT, "Reading quartet file: %s\n", filename);
  fprintf(STDOUT, "   generated by: TREE-PUZZLE %s\n", dummyversion);
  fprintf(STDOUT, "   current:      TREE-PUZZLE %s\n", VERSION);

  fprintf(STDOUT, "   %d species, %lu quartets, %lu bytes\n", 
                   dummynspec, dummynquart, dummyblocklen);

  for (currspec=0; currspec<nspec; currspec++) {

     fscanf(ifp, "%s\n", dummyname);
     if (0 != strcmp(dummyname, Namestr[currspec])) {
         fprintf(STDOUT, "\n\n\nUnable to proceed (species in quartet file does not match: '%s' != '%s')\n\n", dummyname, Namestr[currspec]);
#	 if 0
#	 if PARALLEL
		PP_Finalize();
#	 endif
	 exit (1);
#	 endif
	 tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
     }
     fprintf(STDOUT, "   %3d. %s\n", currspec+1, dummyname);

  } /* for each species */
  fprintf(STDOUT, "\n");

  /* if ((flag == 1)||(flag == 3)||(flag == 5)) { */
  {
	double ttt, iii;
	((unsigned char*)(&ttt))[0]=(unsigned char)0xaf;
	((unsigned char*)(&ttt))[1]=(unsigned char)0xfe;
	((unsigned char*)(&ttt))[2]=(unsigned char)0xaf;
	((unsigned char*)(&ttt))[3]=(unsigned char)0xfe;
	((unsigned char*)(&ttt))[4]=(unsigned char)0xab;
	((unsigned char*)(&ttt))[5]=(unsigned char)0xcc;
	((unsigned char*)(&ttt))[6]=(unsigned char)0xab;
	((unsigned char*)(&ttt))[7]=(unsigned char)0xcc;
  	fread(&iii, sizeof(double), 1, ifp);
	if (ttt != iii) {
         	fprintf(STDOUT, "\n\n\nUnable to proceed (starting check double in quartet file does not match: '%f' != '%f')\n\n", ttt, iii);
#		if 0
#		    if PARALLEL
			PP_Finalize();
#		    endif
		    exit (1);
#	 	endif
	 	tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
	} else {
         	fprintf(STDOUT, "start check double: OK\n");
	}
  }

  fread(&(quartetinfo[0]), sizeof(char), blocklen, ifp);

  /* if ((flag == 1)||(flag == 3)||(flag == 5)) { */
  {
	double ttt, iii;
	((unsigned char*)(&ttt))[0]=(unsigned char)0xaf;
	((unsigned char*)(&ttt))[1]=(unsigned char)0xfe;
	((unsigned char*)(&ttt))[2]=(unsigned char)0xaf;
	((unsigned char*)(&ttt))[3]=(unsigned char)0xfe;
	((unsigned char*)(&ttt))[4]=(unsigned char)0xab;
	((unsigned char*)(&ttt))[5]=(unsigned char)0xcc;
	((unsigned char*)(&ttt))[6]=(unsigned char)0xab;
	((unsigned char*)(&ttt))[7]=(unsigned char)0xcc;
  	fread(&iii, sizeof(double), 1, ifp);
	if (ttt != iii) {
         	fprintf(STDOUT, "\n\n\nUnable to proceed (starting check double in quartet file does not match: '%f' != '%f')\n\n", ttt, iii);
#		if 0
#		    if PARALLEL
			PP_Finalize();
#		    endif
		    exit (1);
#	 	endif
	 	tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
	} else {
         	fprintf(STDOUT, "final check double: OK\n");
	}
  }

  fclose(ifp);

} /* readallquart */




/******************************************************************************/
/* options - file I/O - output                                                */
/******************************************************************************/

/* compute TN parameters according to F84 Ts/Tv ratio */
void makeF84model()
{
	double rho, piA, piC, piG, piT, piR, piY, ts, yr;
	
	piA = Freqtpm[0];
	piC = Freqtpm[1];
	piG = Freqtpm[2];
	piT = Freqtpm[3];
	piR = piA + piG;
	piY = piC + piT;
	if (piC*piT*piR + piA*piG*piY == 0.0) {		
		fprintf(STDOUT, "\n\n\nF84 model not possible ");
		fprintf(STDOUT, "(bad combination of base frequencies)\n");
		tstvf84 = 0.0;
		return;
	}
	rho = (piR*piY*(piR*piY*tstvf84 - (piA*piG + piC*piT)))/
		(piC*piT*piR + piA*piG*piY);
	
	if(piR == 0.0 || piY == 0.0 || (piR + rho) == 0.0) {
		fprintf(STDOUT, "\n\n\nF84 model not possible ");
		fprintf(STDOUT, "(bad combination of base frequencies)\n");
		tstvf84 = 0.0;
		return;
	}
	ts = 0.5 + 0.25*rho*(1.0/piR + 1.0/piY);
	yr = (piY + rho)/piY * piR/(piR + rho);
	if (ts < MINTS || ts > MAXTS) {
		fprintf(STDOUT, "\n\n\nF84 model not possible ");
		fprintf(STDOUT, "(bad Ts/Tv parameter)\n");
		tstvf84 = 0.0;
		return;
	}
	if (yr < MINYR || yr > MAXYR) {
		fprintf(STDOUT, "\n\n\nF84 model not possible ");
		fprintf(STDOUT, "(bad Y/R transition parameter)\n");
		tstvf84 = 0.0;
		return;
	}
	TSparam = ts;
	YRparam = yr;
	optim_optn = FALSE;
} /* makeF84model */

/* compute number of quartets used in LM analysis */
void compnumqts()
{
	if (lmqts == 0) {
		if (numclust == 4)
			Numquartets = (uli) clustA*clustB*clustC*clustD;
		if (numclust == 3)
			Numquartets = (uli) clustA*clustB*clustC*(clustC-1)/2;
		if (numclust == 2)
			Numquartets = (uli) clustA*(clustA-1)/2 * clustB*(clustB-1)/2;
		if (numclust == 1)	
			Numquartets = (uli) Maxspc*(Maxspc-1)*(Maxspc-2)*(Maxspc-3)/24;
	} else {
		Numquartets = lmqts;
	}
} /* compnumqts */

/* set options interactively */
void setoptions(FILE *param_in)
{	
	int i, valid;
	double sumfreq;
	char ch;

	/* defaults */
	rhetmode = UNIFORMRATE;          /* assume rate homogeneity               */
	numcats = 1;
	Geta = 0.05;
	grate_optim = FALSE;
	fracinv = 0.0;
	fracinv_optim = FALSE;

	compclock = FALSE;           /* compute clocklike branch lengths      */
	locroot = -1;                /* search for optimal place of root      */ 
	qcalg_optn = FALSE;          /* don't use sampling of quartets        */
	approxp_optn = TRUE;         /* approximate parameter estimates       */
	listqptrees_optn = PSTOUT_NONE;   /* list puzzling step trees              */
	
	/* approximate ML QP quartets? */
	if (Maxspc <= 6) {
		approxqp_optn = QUART_EXACT;
		quartcrit_optn = QUART_MLEXACT;
	} else {
		approxqp_optn = QUART_APPROX;
		quartcrit_optn = QUART_MLAPPROX;
	}
	
	codon_optn = 0;        /* use all positions in a codon          */
	
	/* number of puzzling steps */
	if (Maxspc <= 25) Numtrial = 1000;
	else if (Maxspc <= 50) Numtrial = 10000;
	else if (Maxspc <= 75) Numtrial = 25000;
	else Numtrial = 50000;
	    
	utree_optn = TRUE;     /* use first user tree for estimation    */
	outgroup = 0;          /* use first taxon as outgroup           */
	sym_optn = FALSE;      /* symmetrize doublet frequencies        */
	tstvf84 = 0.0;         /* disable F84 model                     */
	show_optn = FALSE;     /* show unresolved quartets              */
	typ_optn = TREERECON_OPTN;          /* tree reconstruction                   */
	numclust = 1;          /* one clusters in LM analysis           */
	lmqts = 0;             /* all quartets in LM analysis           */
	compnumqts();
	if (Numquartets > 10000) {
		lmqts = 10000;     /* 10000 quartets in LM analysis         */
		compnumqts();
	}

	/* correct default analysis types if too few/many sequences*/
	if ((seqnumcheck!=SEQNUM_OK) && (puzzlemode==QUARTPUZ))
		puzzlemode = (puzzlemode + 1) % NUMPUZZLEMODES;
	/* correct default analysis types if too fewy sequences*/
	if ((seqnumcheck==SEQNUM_TOOFEW) && (typ_optn==LIKMAPING_OPTN))
		typ_optn = (typ_optn + 1) % NUMTYPES;
	
 	do {
		fprintf(STDOUT, "\n\n\nGENERAL OPTIONS");
		if (seqnumcheck==SEQNUM_OK) fprintf(STDOUT, "\n");
		if (seqnumcheck==SEQNUM_TOOFEW) fprintf(STDOUT, " (no quartet methods available - too few sequences)\n");
		if (seqnumcheck==SEQNUM_TOOMANY) fprintf(STDOUT, " (no quartet puzzling available - too many sequences)\n");
		fprintf(STDOUT, " b                     Type of analysis?  ");
		if (typ_optn == TREERECON_OPTN) {
			if (seqnumcheck==SEQNUM_TOOFEW) 
				fprintf(STDOUT, "Tree reconstruction (only possible)\n");
			else fprintf(STDOUT, "Tree reconstruction\n");
		}
		/* not possible for |seqs| < 4 */
		if (typ_optn == LIKMAPING_OPTN) fprintf(STDOUT, "Likelihood mapping\n");
		if (typ_optn == TREERECON_OPTN) {
			fprintf(STDOUT, " k                Tree search procedure?  ");
			/* not possible for |seqs| < 4 and for |seqs| > 257 */
			if (puzzlemode == QUARTPUZ) fprintf(STDOUT, "Quartet puzzling\n");
			if (puzzlemode == USERTREE) fprintf(STDOUT, "Evaluate user defined trees\n");
			if (puzzlemode == CONSENSUS) fprintf(STDOUT, "Consensus of user defined trees\n");
			if (puzzlemode == PAIRDIST) fprintf(STDOUT, "Pairwise distances only (no tree)\n");
		}
		if ((typ_optn == LIKMAPING_OPTN) || ((typ_optn == TREERECON_OPTN) && (puzzlemode == QUARTPUZ))) {
		fprintf(STDOUT, " v         Quartet evaluation criterion?  ");
			switch (quartcrit_optn) {
				case QUART_MLAPPROX: fprintf(STDOUT, "Approximate maximum likelihood (ML)\n"); break;
				case QUART_MLEXACT:  fprintf(STDOUT, "Exact maximum likelihood (ML)\n"); break;
				case QUART_MP:       fprintf(STDOUT, "Maximum parsimony (MP)\n"); break;
				case QUART_ME:       fprintf(STDOUT, "Minimum evolution (ME)\n"); break;
				case QUART_NJ:       fprintf(STDOUT, "Neighbor Joining (NJ)\n"); break;
			}
#if 0
			fprintf(STDOUT, " v       Approximate quartet likelihood?  %s\n",
				((approxqp_optn == QUART_APPROX) ? "Yes" : "No"));
#endif
		}
		if (typ_optn == TREERECON_OPTN) {
			if (puzzlemode == QUARTPUZ) {
				fprintf(STDOUT, " n             Number of puzzling steps?  %lu\n",
						Numtrial);
			}
			if ((puzzlemode == QUARTPUZ) || (puzzlemode == CONSENSUS)) {
				fprintf(STDOUT, " o                  Display as outgroup?  ");
				fputid(STDOUT, outgroup);
				fprintf(STDOUT, " (%d)\n", outgroup + 1);
			}
			if (puzzlemode == QUARTPUZ || puzzlemode == USERTREE || puzzlemode == CONSENSUS) {
				fprintf(STDOUT, " z     Compute clocklike branch lengths?  ");
				if (compclock) fprintf(STDOUT, "Yes\n");
				else fprintf(STDOUT, "No\n");
			}
			if (compclock)
				if (puzzlemode == QUARTPUZ || puzzlemode == USERTREE || puzzlemode == CONSENSUS) {
					fprintf(STDOUT, " l                     Location of root?  ");
					if (locroot < 0) fprintf(STDOUT, "Best place (automatic search)\n");
					else if (locroot < Maxspc) {
						fprintf(STDOUT, "Branch %d (", locroot + 1);
						fputid(STDOUT, locroot);
						fprintf(STDOUT, ")\n");
					} else fprintf(STDOUT, "Branch %d (internal branch)\n", locroot + 1);
				}
		}
		if (typ_optn == LIKMAPING_OPTN) {
			  fprintf(STDOUT, " g          Group sequences in clusters?  ");
			  if (numclust == 1) fprintf(STDOUT, "No\n");
			  else fprintf(STDOUT, "Yes (%d clusters as specified)\n", numclust);
			  fprintf(STDOUT, " n                   Number of quartets?  ");
			  if (lmqts == 0) fprintf(STDOUT, "%lu (all possible)\n", Numquartets);
			  else fprintf(STDOUT, "%lu (random choice)\n", lmqts);
		}
		fprintf(STDOUT, " e                  Parameter estimates?  ");
		if (approxp_optn) fprintf(STDOUT, "Approximate (faster)\n");
		else fprintf(STDOUT, "Exact (slow)\n");
		if (!((puzzlemode == USERTREE || puzzlemode == CONSENSUS) && typ_optn == TREERECON_OPTN)) {	
			fprintf(STDOUT, " x            Parameter estimation uses?  ");
			if (qcalg_optn) fprintf(STDOUT, "Quartet sampling + NJ tree\n");
			else fprintf(STDOUT, "Neighbor-joining tree\n");
			
		} else {
			fprintf(STDOUT, " x            Parameter estimation uses?  ");
			if (utree_optn)
				fprintf(STDOUT, "1st input tree\n");
			else if (qcalg_optn) fprintf(STDOUT, "Quartet sampling + NJ tree\n");
			else fprintf(STDOUT, "Neighbor-joining tree\n");
		}


		if ((typ_optn == TREERECON_OPTN) && (puzzlemode != PAIRDIST)) {
			fprintf(STDOUT, "OUTPUT OPTIONS\n");
			if (puzzlemode == QUARTPUZ || puzzlemode == USERTREE || puzzlemode == CONSENSUS) {
				fprintf(STDOUT, " 9   List puzzling trees/splits (NEXUS)?  ");
				switch (savenexus_optn) {
					case FALSE:	fprintf(STDOUT, "No\n"); break;
					case TRUE:
					default:
							fprintf(STDOUT, "yes\n"); break;
				}
			}
			if (puzzlemode == QUARTPUZ) {
				fprintf(STDOUT, " u             List unresolved quartets?  %s\n",
					(show_optn ? "Yes" : "No"));
				fprintf(STDOUT, " j             List puzzling step trees?  ");
				switch (listqptrees_optn) {
					case PSTOUT_NONE:      fprintf(STDOUT, "No\n"); break;
					case PSTOUT_ORDER:     fprintf(STDOUT, "Unique topologies\n"); break;
					case PSTOUT_LISTORDER: fprintf(STDOUT, "Unique topologies & Chronological list\n"); break;
					case PSTOUT_LIST:      fprintf(STDOUT, "Chronological list only\n"); break;
				}
			}
		}


		fprintf(STDOUT, "SUBSTITUTION PROCESS\n");
		fprintf(STDOUT, " d          Type of sequence input data?  ");
		if (auto_datatype == AUTO_GUESS) fprintf(STDOUT, "Auto: ");
		if (data_optn == NUCLEOTIDE) fprintf(STDOUT, "Nucleotides\n");
		if (data_optn == AMINOACID) fprintf(STDOUT, "Amino acids\n");
		if (data_optn == BINARY) fprintf(STDOUT, "Binary states\n");
		if (data_optn == NUCLEOTIDE && (Maxseqc % 3) == 0  && !SH_optn) {
			fprintf(STDOUT, " h             Codon positions selected?  ");
			if (codon_optn == 0) fprintf(STDOUT, "Use all positions\n");
			if (codon_optn == 1) fprintf(STDOUT, "Use only 1st positions\n");
			if (codon_optn == 2) fprintf(STDOUT, "Use only 2nd positions\n");
			if (codon_optn == 3) fprintf(STDOUT, "Use only 3rd positions\n");
			if (codon_optn == 4) fprintf(STDOUT, "Use 1st and 2nd positions\n");
		}
		fprintf(STDOUT, " m                Model of substitution?  ");
		if (data_optn == NUCLEOTIDE) { /* nucleotides */
			if (nuc_optn) {
				if(HKY_optn)
					fprintf(STDOUT, "HKY (Hasegawa et al. 1985)\n");	
				if(TN_optn) {
					fprintf(STDOUT, "TN (Tamura-Nei 1993)\n");
					fprintf(STDOUT, " p      Constrain TN model to F84 model?  ");
					if (tstvf84 == 0.0)
						fprintf(STDOUT, "No\n");
					else fprintf(STDOUT, "Yes (Ts/Tv ratio = %.2f)\n", tstvf84);
				}
				if(GTR_optn)
					fprintf(STDOUT, "GTR (e.g. Lanave et al. 1980)\n");	
				if((HKY_optn) || (TN_optn)) {
					fprintf(STDOUT, " t    Transition/transversion parameter?  ");
					if (optim_optn)
						fprintf(STDOUT, "Estimate from data set\n");
					else
						fprintf(STDOUT, "%.2f\n", TSparam);	
				}
				if (TN_optn) {
					fprintf(STDOUT, " r             Y/R transition parameter?  ");
					if (optim_optn)
						fprintf(STDOUT, "Estimate from data set\n");
					else
						fprintf(STDOUT, "%.2f\n", YRparam);		
 				}			
				if (GTR_optn) {
					fprintf(STDOUT, " 1  A-C rate?  ");
					fprintf(STDOUT, "%-23.2f", GTR_ACrate);		
					fprintf(STDOUT, " 2  A-G rate?  ");
					fprintf(STDOUT, "%-23.2f\n", GTR_AGrate);		
					fprintf(STDOUT, " 3  A-T rate?  ");
					fprintf(STDOUT, "%-23.2f", GTR_ATrate);		
					fprintf(STDOUT, " 4  C-G rate?  ");
					fprintf(STDOUT, "%-23.2f\n", GTR_CGrate);		
					fprintf(STDOUT, " 5  C-T rate?  ");
					fprintf(STDOUT, "%-23.2f", GTR_CTrate);		
					fprintf(STDOUT, " 6  G-T rate?  ");
					fprintf(STDOUT, "%-23.2f\n", GTR_GTrate);		
#if 0
					fprintf(STDOUT, " 1                A <-> C mutation rate?  ");
					fprintf(STDOUT, "%.2f\n", GTR_ACrate);		
					fprintf(STDOUT, " 2                A <-> G mutation rate?  ");
					fprintf(STDOUT, "%.2f\n", GTR_AGrate);		
					fprintf(STDOUT, " 3                A <-> T mutation rate?  ");
					fprintf(STDOUT, "%.2f\n", GTR_ATrate);		
					fprintf(STDOUT, " 4                C <-> G mutation rate?  ");
					fprintf(STDOUT, "%.2f\n", GTR_CGrate);		
					fprintf(STDOUT, " 5                C <-> T mutation rate?  ");
					fprintf(STDOUT, "%.2f\n", GTR_CTrate);		
					fprintf(STDOUT, " 6                G <-> T mutation rate?  ");
					fprintf(STDOUT, "%.2f\n", GTR_GTrate);		
#endif
 				}			
			}
			if (SH_optn) {
					fprintf(STDOUT, "SH (Schoeniger-von Haeseler 1994)\n");
					fprintf(STDOUT, " t    Transition/transversion parameter?  ");
					if (optim_optn)
						fprintf(STDOUT, "Estimate from data set\n");
					else
						fprintf(STDOUT, "%.2f\n", TSparam);
			}	
		}
		if (data_optn == NUCLEOTIDE && SH_optn) {
			fprintf(STDOUT, " h                  Doublets defined by?  ");
			if (SHcodon)
				fprintf(STDOUT, "1st and 2nd codon positions\n");
			else
				fprintf(STDOUT, "1st+2nd, 3rd+4th, etc. site\n");
		}
		if (data_optn == AMINOACID) { /* amino acids */
			switch (auto_aamodel) {
				case AUTO_GUESS:
					fprintf(STDOUT, "Auto: ");
					break;
				case AUTO_DEFAULT:
					fprintf(STDOUT, "Def.: ");
					break;
			}
			if (Dayhf_optn) fprintf(STDOUT, "Dayhoff (Dayhoff et al. 1978)\n");	
			if (Jtt_optn) fprintf(STDOUT, "JTT (Jones et al. 1992)\n");
			if (mtrev_optn) fprintf(STDOUT, "mtREV24 (Adachi-Hasegawa 1996)\n");
			if (cprev_optn) fprintf(STDOUT, "cpREV45 (Adachi et al. 2000)\n");
			if (blosum62_optn) fprintf(STDOUT, "BLOSUM62 (Henikoff-Henikoff 92)\n");
			if (vtmv_optn) fprintf(STDOUT, "VT (Mueller-Vingron 2000)\n");
			if (wag_optn) fprintf(STDOUT, "WAG (Whelan-Goldman 2000)\n");
			if (lg_optn) fprintf(STDOUT, "LG (Le-Gascuel 2008)\n");
			/* if (poisson_optn) fprintf(STDOUT, "Poisson (JC model for proteins)\n"); */
			/* if (equalin_optn) fprintf(STDOUT, "Equalin (XXX, TODO)\n"); */
			/* if (mtmam_optn) fprintf(STDOUT, "mtMAM (XXX, TODO)\n"); */
			/* if (rtrev_optn) fprintf(STDOUT, "rtREV (XXX, TODO)\n"); */
		}
		if (data_optn == BINARY) { /* binary states */
			fprintf(STDOUT, "Two-state model (Felsenstein 1981)\n");
		}
		if (data_optn == AMINOACID)
			fprintf(STDOUT, " f               Amino acid frequencies?  ");
		else if (data_optn == NUCLEOTIDE && SH_optn)
			fprintf(STDOUT, " f                  Doublet frequencies?  ");
		else if (data_optn == NUCLEOTIDE && nuc_optn)
			fprintf(STDOUT, " f               Nucleotide frequencies?  ");
		else if (data_optn == BINARY)
			fprintf(STDOUT, " f             Binary state frequencies?  ");
		fprintf(STDOUT, "%s\n", (Frequ_optn ? "Estimate from data set" :
			"Use specified values"));
		if (data_optn == NUCLEOTIDE && SH_optn)
			fprintf(STDOUT, " s       Symmetrize doublet frequencies?  %s\n",
				(sym_optn ? "Yes" : "No"));
				
		fprintf(STDOUT, "RATE HETEROGENEITY\n");
		fprintf(STDOUT, " w          Model of rate heterogeneity?  ");
		if (rhetmode == UNIFORMRATE) fprintf(STDOUT, "Uniform rate\n");
		if (rhetmode == GAMMARATE  ) fprintf(STDOUT, "Gamma distributed rates\n");
		if (rhetmode == TWORATE    ) fprintf(STDOUT, "Two rates (1 invariable + 1 variable)\n");
		if (rhetmode == MIXEDRATE  ) fprintf(STDOUT, "Mixed (1 invariable + %d Gamma rates)\n", numcats);
		
		if (rhetmode == TWORATE || rhetmode == MIXEDRATE) {
			fprintf(STDOUT, " i         Fraction of invariable sites?  ");
			if (fracinv_optim) fprintf(STDOUT, "Estimate from data set");
			else fprintf(STDOUT, "%.2f", fracinv);
			if (fracinv == 0.0 && !fracinv_optim) fprintf(STDOUT, " (all sites variable)");
			fprintf(STDOUT, "\n");
		}
		if (rhetmode == GAMMARATE || rhetmode == MIXEDRATE) {
			fprintf(STDOUT, " a   Gamma distribution parameter alpha?  ");
			if (grate_optim)
				fprintf(STDOUT, "Estimate from data set\n");
			else if (Geta > 0.5)
				fprintf(STDOUT, "%.2f (strong rate heterogeneity)\n", (1.0-Geta)/Geta);
			else fprintf(STDOUT, "%.2f (weak rate heterogeneity)\n", (1.0-Geta)/Geta);
			fprintf(STDOUT, " c      Number of Gamma rate categories?  %d\n", numcats);
		}
	
		fprintf(STDOUT, "\nQuit [q], confirm [y], or change [menu] settings: ");
		fflush(STDOUT);
		
		/* read one char */
		ch = getc(param_in);
		/* ch = getchar(); */
		if (ch != '\n') {
			do ;
			while (getc(param_in) != '\n');
			/* while (getchar() != '\n'); */
		}
		ch = (char) tolower((int) ch);
		
		/* letters in use: a b c d e f g h i j k l m n o p q r s t u v w y x z */
		/* letters not in use:  */

		switch (ch) {

			case '\n':	break;
			
			case 'z':	if (typ_optn == TREERECON_OPTN && (puzzlemode == QUARTPUZ || puzzlemode == USERTREE || puzzlemode == CONSENSUS)) {
						compclock = compclock + 1;
						if (compclock == 2) compclock = 0;
					} else {
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					}
					break;

			case 'l':	if (compclock && typ_optn == TREERECON_OPTN && (puzzlemode == QUARTPUZ || puzzlemode == USERTREE || puzzlemode == CONSENSUS)) {
						fprintf(STDOUT, "\n\n\nEnter an invalid branch number to search ");
						fprintf(STDOUT, "for the best location!\n");
						fprintf(STDOUT, "\nPlace root at branch (1-%d, 0=automatic): ",
							2*Maxspc-3);
						fflush(STDOUT);
						fscanf(param_in, "%d", &locroot);
						/* scanf("%d", &locroot); */
						do ;
						while (getc(param_in) != '\n');
						/* while (getchar() != '\n'); */
						if (locroot < 1 || locroot > 2*Maxspc-3) locroot = 0;
						locroot = locroot - 1; 
					} else {
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					}
					break;
			
			case 'e':	if ((rhetmode == TWORATE || rhetmode == MIXEDRATE) && fracinv_optim) {
						fprintf(STDOUT, "\n\n\nInvariable sites estimation needs to be exact!\n");
					} else {
						approxp_optn = approxp_optn + 1;
						if (approxp_optn == 2) approxp_optn = 0;						
					}
					break;
						
			case 'w':	rhetmode = rhetmode + 1;
					if (rhetmode == 4) rhetmode = UNIFORMRATE;
					if (rhetmode == UNIFORMRATE) { /* uniform rate */
						numcats = 1;
						Geta = 0.05;
						grate_optim = FALSE;
						fracinv = 0.0;
						fracinv_optim = FALSE;
					}
					if (rhetmode == GAMMARATE  ) { /* Gamma distributed rates */
						numcats = 4;
						Geta = 0.05;
						grate_optim = TRUE;
						fracinv = 0.0;
						fracinv_optim = FALSE;
					}
					if (rhetmode == TWORATE    ) { /* two rates (1 invariable + 1 variable) */
						approxp_optn = FALSE;
						numcats = 1;
						Geta = 0.05;
						grate_optim = FALSE;
						fracinv = 0.0;
						fracinv_optim = TRUE;
					}
					if (rhetmode == MIXEDRATE  ) { /* mixed (1 invariable + Gamma rates) */
						approxp_optn = FALSE;
						numcats = 4;
						Geta = 0.05;
						grate_optim = TRUE;
						fracinv = 0.0;
						fracinv_optim = TRUE;
					}
					break;

			case 'i':	if (rhetmode == TWORATE || rhetmode == MIXEDRATE) {
						fprintf(STDOUT, "\n\n\nEnter an invalid value for ");
						fprintf(STDOUT, "estimation from data set!\n");
						fprintf(STDOUT, "\nFraction of invariable sites among all sites (%.2f-%.2f): ",
							MINFI, MAXFI);
						fflush(STDOUT);
						fscanf(param_in, "%lf", &fracinv);
						/* scanf("%lf", &fracinv); */
						do ;
						while (getc(param_in) != '\n');
						/* while (getchar() != '\n'); */
						if (fracinv < MINFI || fracinv > MAXFI) {
								fracinv_optim = TRUE;
								fracinv = 0.0;
						} else {
							fracinv_optim = FALSE;
						}
					} else {
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					}
					break;

			case 'a':	if (rhetmode == GAMMARATE || rhetmode == MIXEDRATE) {
						fprintf(STDOUT, "\n\n\nEnter an invalid value for estimation from data set!\n");
						fprintf(STDOUT, "\nGamma distribution parameter alpha (%.2f-%.2f): ",
							(1.0-MAXGE)/MAXGE, (1.0-MINGE)/MINGE);
						fflush(STDOUT);
						fscanf(param_in, "%lf", &Geta);
						/* scanf("%lf", &Geta); */
						do ;
						while (getc(param_in) != '\n');
						/* while (getchar() != '\n'); */
						if (Geta < (1.0-MAXGE)/MAXGE || Geta > (1.0-MINGE)/MINGE) {
							grate_optim = TRUE;
							Geta = 0.05;
						} else {
							grate_optim = FALSE;
							Geta = 1.0/(1.0 + Geta);
						}
					} else 
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					break;

			case 'c':	if (rhetmode == GAMMARATE || rhetmode == MIXEDRATE) {
						fprintf(STDOUT, "\n\n\nNumber of Gamma rate categories (%d-%d): ",
							MINCAT, MAXCAT);
						fflush(STDOUT);
						fscanf(param_in, "%d", &numcats);
						/* scanf("%d", &numcats); */
						do ;
						while (getc(param_in) != '\n');
						/* while (getchar() != '\n'); */
						if (numcats < MINCAT || numcats > MAXCAT) {
							fprintf(STDOUT, "\n\n\nThis number of categories is not available!\n");
							numcats = 4;
						}
					} else {
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					}	
					break;
			
			case 'h':	if (data_optn == NUCLEOTIDE && (Maxseqc % 3) == 0  && !SH_optn) {
						codon_optn = codon_optn + 1;
						if (codon_optn == 5) codon_optn = 0;
						translatedataset(Maxspc, Maxseqc, &Maxsite, Seqchars, &Seqchar, &Seqgapchar, &Seqotherchar);

						/* reestimate nucleotide frequencies only 
						   if user did not specify other values */
						if (Frequ_optn) estimatebasefreqs();

					} else if (data_optn == NUCLEOTIDE && SH_optn) { 
						if (Maxseqc % 2 != 0 && Maxseqc % 3 == 0) {
							SHcodon = TRUE;
							fprintf(STDOUT, "\n\n\nThis is the only possible option for the data set!\n");
						}
						if (Maxseqc % 3 != 0 && Maxseqc % 2 == 0) {
							SHcodon = FALSE;
							fprintf(STDOUT, "\n\n\nThis is the only possible option for the data set!\n");
						}
						if (Maxseqc % 2 == 0 && Maxseqc % 3 == 0) {
							if (SHcodon)
								SHcodon = FALSE;
							else
								SHcodon = TRUE;	
							translatedataset(Maxspc, Maxseqc, &Maxsite, Seqchars, &Seqchar, &Seqgapchar, &Seqotherchar);
							/* reestimate nucleotide frequencies only 
						   	   if user did not specify other values */
							if (Frequ_optn) estimatebasefreqs();
						}
					} else {
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					}
					break;

			case 'x':	if (typ_optn == TREERECON_OPTN && (puzzlemode == USERTREE || puzzlemode == CONSENSUS)) {
						/* use of usertree for parameter estimation set? */
						/* utree_optn==TRUE  && qcalg_optn==?     - 1st user tree (for substitution process and rate variation) */
						/* utree_optn==FALSE && qcalg_optn==TRUE  - quartet sampling (for substitution process) + NJ tree (for rate variation) */
						/* utree_optn==FALSE && qcalg_optn==FALSE - neighbor-joining tree (for substitution process and rate variation) */

						if (utree_optn) {
							/* menu point 1 (1st utree) -> 2 (NJ) */
							utree_optn = FALSE;	/* no 1st usertree */
							qcalg_optn = FALSE;	/* no quartets */
						} else {
							/* menu point 2 (NJ) -> 3 (NJ+Q) */
							qcalg_optn = qcalg_optn + 1;

							/* seq-num < 4: only 1' (NJ) possible */
							if ((seqnumcheck==SEQNUM_TOOFEW) && (qcalg_optn==1)) 
								qcalg_optn = qcalg_optn + 1;

							if (qcalg_optn == 2) {
								/* menu point 3 (NJ+Q) -> 1 (1st utree) */
								qcalg_optn = 0;
								utree_optn = TRUE;
							}
						}
					} else {
						/* menu point 1' (NJ) -> 2' (NJ+Q) */
						qcalg_optn = qcalg_optn + 1;

						/* menu point 2' (NJ+Q) -> 1' (NJ) */
						if (qcalg_optn == 2) qcalg_optn = 0;

						/* seq-num < 4: only 1' (NJ) possible */
						if ((seqnumcheck==SEQNUM_TOOFEW) && (qcalg_optn==1)) qcalg_optn=0;
					}
					break;
						
			case 'k':	if (typ_optn == TREERECON_OPTN) {
						puzzlemode = (puzzlemode + 1) % NUMPUZZLEMODES;
						if ((seqnumcheck!=SEQNUM_OK) && (puzzlemode==QUARTPUZ))
							puzzlemode = (puzzlemode + 1) % NUMPUZZLEMODES;
					} else {
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					}
					break;

			case 'b':	typ_optn = (typ_optn + 1) % NUMTYPES;
					if ((seqnumcheck==SEQNUM_TOOFEW) && (typ_optn==LIKMAPING_OPTN))
						typ_optn = (typ_optn + 1) % NUMTYPES;
					break;

			case 'g':	if (typ_optn == LIKMAPING_OPTN) {
						char backtomenu = FALSE;
						clustA = clustB = clustC = clustD = 0;
						if (numclust != 1) {
							numclust = 1;
						} else {
							fprintf(STDOUT, "\n\n\nNumber of clusters (2-4): ");
							fflush(STDOUT);
							fscanf(param_in, "%d", &numclust);
							/* scanf("%d", &numclust); */
							do ;
							while (getc(param_in) != '\n');
							/* while (getchar() != '\n'); */
							if (numclust < 2 || numclust > 4) {
								numclust = 1;
								fprintf(STDOUT, "\n\n\nOnly 2, 3, or 4 ");
								fprintf(STDOUT, "clusters possible\n");
							} else {
								fprintf(STDOUT, "\nDistribute all sequences over the ");
								if (numclust == 2) {
									fprintf(STDOUT, "two clusters [a] and [b] (at least two\n");
									fprintf(STDOUT, "sequences per cluster are necessary), ");
									fprintf(STDOUT, "type [x] to exclude a sequence\n");
								}
								if (numclust == 3) {
									fprintf(STDOUT, "three clusters [a], [b], and [c]\n");
									fprintf(STDOUT, "(at least one sequence in cluster [a] and [b], and at least two\n");
									fprintf(STDOUT, "sequences in [c] are necessary), ");
									fprintf(STDOUT, "type [x] to exclude a sequence\n");
								}
								if (numclust == 4) {
									fprintf(STDOUT, "four [c]lusters [a], [b], [c], and [d]\n");
									fprintf(STDOUT, "(at least one sequence per cluster is necessary),\n");
									fprintf(STDOUT, "type [x] to exclude a sequence ");
								}
								fprintf(STDOUT, "and [q] to get back to the menu:\n\n");
															
								for (i = 0; ((i < Maxspc) && (! backtomenu)); i++) {
									valid = FALSE;
									do {
										fputid10(STDOUT, i);
										fprintf(STDOUT, ": ");
										fflush(STDOUT);
										/* read one char */
										ch = getc(param_in);
										/* ch = getchar(); */
										if (ch != '\n') {
										do ;
										while (getc(param_in) != '\n');
										/* while (getchar() != '\n'); */
										}	
										ch = (char) tolower((int) ch);
										if (ch == 'q') {
											clustA = clustB = clustC = clustD = 0;
											numclust = 1;
											backtomenu = TRUE;
											valid = TRUE;
#if 0
#											if PARALLEL
												PP_SendDone();
#											endif /* PARALLEL */
	 										tp_exit(0, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
#endif
											break;
										}

										if (ch == 'a' || ch == 'b' || ch == 'x')
											valid = TRUE;
										if (numclust == 3 || numclust == 4)
											if (ch == 'c') valid = TRUE;
										if (numclust == 4)
											if (ch == 'd') valid = TRUE;
									} while (!valid);
									if (ch == 'a') {
										clusterA[clustA] = i;
										clustA++;
									}
									if (ch == 'b') {
										clusterB[clustB] = i;
										clustB++;
									}
									if (ch == 'c') {
										clusterC[clustC] = i;
										clustC++;
									}
									if (ch == 'd') {
										clusterD[clustD] = i;
										clustD++;
									}
								}
								/* check clusters */
								if (! backtomenu) {
									valid = TRUE;
									if (numclust == 4) {
										if (clustA == 0) {
											valid = FALSE;
											numclust = 1;
											fprintf(STDOUT, "\n\n\nNo sequence in cluster a\n");
										}
										if (clustB == 0) {
											valid = FALSE;
											numclust = 1;
											fprintf(STDOUT, "\n\n\nNo sequence in cluster b\n");
										}
										if (clustC == 0) {
											valid = FALSE;
											numclust = 1;
											fprintf(STDOUT, "\n\n\nNo sequence in cluster c\n");
										}
										if (clustD == 0) {
											valid = FALSE;
											numclust = 1;
											fprintf(STDOUT, "\n\n\nNo sequence in cluster d\n");
										}
									}
									if (numclust == 3) {
										if (clustA == 0) {
											valid = FALSE;
											numclust = 1;
											fprintf(STDOUT, "\n\n\nNo sequence in cluster a\n");
										}
										if (clustB == 0) {
											valid = FALSE;
											numclust = 1;
											fprintf(STDOUT, "\n\n\nNo sequence in cluster b\n");
										}
										if (clustC < 2) {
											valid = FALSE;
											numclust = 1;
											if (clustC == 0)
												fprintf(STDOUT, "\n\n\nNo sequence in cluster c\n");
											else
												fprintf(STDOUT, "\n\n\nOnly one sequence in cluster c\n");
										}
									}
									if (numclust == 2) {
										if (clustA < 2) {
											valid = FALSE;
											numclust = 1;
											if (clustA == 0)
												fprintf(STDOUT, "\n\n\nNo sequence in cluster a\n");
											else
												fprintf(STDOUT, "\n\n\nOnly one sequence in cluster a\n");
										}
										if (clustB < 2) {
											valid = FALSE;
											numclust = 1;
											if (clustB == 0)
												fprintf(STDOUT, "\n\n\nNo sequence in cluster b\n");
											else
												fprintf(STDOUT, "\n\n\nOnly one sequence in cluster b\n");
										}	
									}
									if (valid) {
										fprintf(STDOUT, "\nNumber of sequences in each cluster:\n\n");
										fprintf(STDOUT, "Cluster a: %d\n", clustA);
										fprintf(STDOUT, "Cluster b: %d\n", clustB);
										if (numclust > 2)
											fprintf(STDOUT, "Cluster c: %d\n", clustC);
										if (numclust == 4)
											fprintf(STDOUT, "Cluster d: %d\n", clustD);
										fprintf(STDOUT, "\nExcluded sequences: ");
										if (numclust == 2) fprintf(STDOUT, "%d\n",
											Maxspc-clustA-clustB);
										if (numclust == 3) fprintf(STDOUT, "%d\n",
											Maxspc-clustA-clustB-clustC);
										if (numclust == 4) fprintf(STDOUT, "%d\n",
											Maxspc-clustA-clustB-clustC-clustD);
								
									}
								} /* if not back-to-menu */
							}
						}
						/* number of resulting quartets */
						compnumqts();

					} else {
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					}
					break;

			case 'd':	if (auto_datatype == AUTO_GUESS) {
						auto_datatype = AUTO_OFF;
						guessdata_optn = data_optn;
						data_optn = 0;
					} else {
						data_optn = data_optn + 1;
						if (data_optn == 3) {
							auto_datatype = AUTO_GUESS;
							data_optn = guessdata_optn;
						}
					}
					/* translate characters into format used by ML engine */
					translatedataset(Maxspc, Maxseqc, &Maxsite, Seqchars, &Seqchar, &Seqgapchar, &Seqotherchar);
	                    		estimatebasefreqs();
					break;

			case 'u':	if (puzzlemode == QUARTPUZ && typ_optn == TREERECON_OPTN)
						show_optn = 1 - show_optn;
					else
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					break;

			case 'j':	if (puzzlemode == QUARTPUZ && typ_optn == TREERECON_OPTN)
						listqptrees_optn = (listqptrees_optn + 1) % 4;
					else
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					break;
							
			case 'v':	if ((puzzlemode == QUARTPUZ && typ_optn == TREERECON_OPTN) || (typ_optn == LIKMAPING_OPTN)) {
						quartcrit_optn = (quartcrit_optn + 1);
						if(quartcrit_optn == QUART_MAX) quartcrit_optn = 0;
						if (quartcrit_optn == QUART_MLAPPROX)
							approxqp_optn = QUART_APPROX;
						else
							approxqp_optn = QUART_EXACT;
					} else
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					break;

			case 'f':	if (Frequ_optn) {
						tstvf84 = 0.0;
						Frequ_optn = FALSE;
						sumfreq = 0.0;
						if (data_optn == AMINOACID)
							fprintf(STDOUT, "\n\n\nAmino acid");
						else if (data_optn == NUCLEOTIDE && SH_optn)
							fprintf(STDOUT, "\n\n\nDoublet");
						else if (data_optn == NUCLEOTIDE && nuc_optn)
							fprintf(STDOUT, "\n\n\nNucleotide");
						else if (data_optn == BINARY)
							fprintf(STDOUT, "\n\n\nBinary state");
						fprintf(STDOUT, " frequencies (in %%):\n\n");
						for (i = 0; i < gettpmradix() - 1; i++) {
							fprintf(STDOUT, "pi(%s) = ", int2code(i));
							fflush(STDOUT);
							fscanf(param_in, "%lf", &(Freqtpm[i]));
							/* scanf("%lf", &(Freqtpm[i])); */
							do ;
							while (getc(param_in) != '\n');
							/* while (getchar() != '\n'); */
							Freqtpm[i] = Freqtpm[i]/100.0;
							if (Freqtpm[i] < 0.0) {
								fprintf(STDOUT, "\n\n\nNegative frequency not possible\n");
								estimatebasefreqs();
								break;
							}
							sumfreq = sumfreq + Freqtpm[i];
							if (sumfreq > 1.0) {
								fprintf(STDOUT, "\n\n\nThe sum of ");
								fprintf(STDOUT, "all frequencies exceeds");
								fprintf(STDOUT, " 100%%\n");
								estimatebasefreqs();
								break;
							}
							if (i == gettpmradix() - 2)
								Freqtpm[i+1] = 1.0 - sumfreq;
						}
					} else estimatebasefreqs();
					break;
			
			case 's':	if (data_optn == NUCLEOTIDE && SH_optn) {
						sym_optn = 1 - sym_optn;
					} else {
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					}
					break;

			case 'n':	if (puzzlemode == QUARTPUZ && typ_optn == TREERECON_OPTN) {
						fprintf(STDOUT, "\n\n\nNumber of puzzling steps: ");
						fflush(STDOUT);
						fscanf(param_in, "%lu", &Numtrial);
						/* scanf("%lu", &Numtrial); */
						do ;
						while (getc(param_in) != '\n');
						/* while (getchar() != '\n'); */
						if (Numtrial < 1) {
							fprintf(STDOUT, "\n\n\nThe number of puzzling");
							fprintf(STDOUT, " steps can't be smaller than one\n");
							Numtrial = 1000;
						}
					} else {
						if (typ_optn == LIKMAPING_OPTN) {
							fprintf(STDOUT, "\n\nEnter zero to use all possible");
							fprintf(STDOUT, " quartets in the analysis!\n");
							fprintf(STDOUT, "\nNumber of random quartets: ");
							fflush(STDOUT);
							fscanf(param_in, "%lu", &lmqts);
							/* scanf("%lu", &lmqts); */
							do ;
							while (getc(param_in) != '\n');
							/* while (getchar() != '\n'); */
							
							/* compute number of quartets used */
							compnumqts();
						} else {
							fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
						}
					}
					break;
						
			case 'o':	if (((puzzlemode == QUARTPUZ) || (puzzlemode == CONSENSUS)) && typ_optn == TREERECON_OPTN) {
						fprintf(STDOUT, "\n\n\nSequence to be displayed as outgroup (1-%d, or 0 for last): ",
								Maxspc);
						fflush(STDOUT);
						fscanf(param_in, "%d", &outgroup);
						/* scanf("%d", &outgroup); */
						do ;
						while (getc(param_in) != '\n');
						/* while (getchar() != '\n'); */
						if (outgroup < 0 || outgroup > Maxspc) {
							fprintf(STDOUT, "\n\n\nSequences are numbered ");
							fprintf(STDOUT, "from 1 to %d\n",
									Maxspc);
							outgroup = 1;
						} 
						if (outgroup == 0) outgroup = Maxspc;
						outgroup = outgroup - 1;
					} else {
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					}
					break;
	
			case 'm':	if (data_optn == NUCLEOTIDE) { /* nucleotide data */
#ifndef USE_GTR
						if(HKY_optn && nuc_optn) {
							/* HKY -> TN */
							tstvf84       = 0.0;
							TSparam       = 2.0;
							YRparam       = 0.9;
							HKY_optn      = FALSE;
							TN_optn       = TRUE;
							GTR_optn      = FALSE;
							optim_optn    = TRUE;
							nuc_optn      = TRUE;
							SH_optn       = FALSE;
							break;
						}
#else
						if(HKY_optn && nuc_optn) {
							/* HKY -> TN */
							tstvf84       = 0.0;
							TSparam       = 2.0;
							YRparam       = 0.9;
							HKY_optn      = FALSE;
							TN_optn       = TRUE;
							GTR_optn      = FALSE;
							optim_optn    = TRUE;
							nuc_optn      = TRUE;
							SH_optn       = FALSE;
							break;
						}
						if(TN_optn && nuc_optn) {
							/* TN -> GTR */
							tstvf84       = 0.0;
							TSparam       = 2.0;
							YRparam       = 0.9;
							GTR_ACrate    = 1.0;
							GTR_AGrate    = 1.0;
							GTR_ATrate    = 1.0;
							GTR_CGrate    = 1.0;
							GTR_CTrate    = 1.0;
							GTR_GTrate    = 1.0;
							HKY_optn      = FALSE;
							TN_optn       = FALSE;
							GTR_optn      = TRUE;
							optim_optn    = FALSE;
							nuc_optn      = TRUE;
							SH_optn       = FALSE;
							break;
						}
#if 0
						if(GTR_optn && nuc_optn) {
							/* GTR -> TN */
							tstvf84       = 0.0;
							TSparam       = 2.0;
							YRparam       = 0.9;
							HKY_optn      = FALSE;
							TN_optn       = TRUE;
							GTR_optn      = FALSE;
							optim_optn    = TRUE;
							nuc_optn      = TRUE;
							SH_optn       = FALSE;
							break;
						}
#endif
#endif
						if(GTR_optn && nuc_optn) {
						/* if(TN_optn && nuc_optn) { */
							if (Maxseqc % 2 == 0 || Maxseqc % 3 == 0) {
								/* number of chars needs to be a multiple 2 or 3 */
								/* TN -> SH */		
								if (Maxseqc % 2 != 0 && Maxseqc % 3 == 0)
									SHcodon = TRUE;
								else
									SHcodon = FALSE;								
								tstvf84       = 0.0;
								TSparam       = 2.0;
								YRparam       = 1.0;
								HKY_optn      = TRUE;
								TN_optn       = FALSE;
								GTR_optn      = FALSE;
								optim_optn    = TRUE;
								nuc_optn      = FALSE;
								SH_optn       = TRUE;
								/* translate characters into format */
								/* used by ML engine */
								translatedataset(Maxspc, Maxseqc, &Maxsite, Seqchars, &Seqchar, &Seqgapchar, &Seqotherchar);
								estimatebasefreqs();
							} else {
								fprintf(STDOUT, "\n\n\nSH model not ");
								fprintf(STDOUT, "available for the data set!\n");
								/* TN -> HKY */
								tstvf84       = 0.0;
								TSparam       = 2.0;
								YRparam       = 1.0;
								HKY_optn      = TRUE;
								TN_optn       = FALSE;
								GTR_optn      = FALSE;
								optim_optn    = TRUE;
								nuc_optn      = TRUE;
								SH_optn       = FALSE;
							}
							break;
						}
						if(SH_optn) {
							/* SH -> HKY */
							tstvf84       = 0.0;
							TSparam       = 2.0;
							YRparam       = 1.0;
							HKY_optn      = TRUE;
							TN_optn       = FALSE;
							GTR_optn      = FALSE;
							optim_optn    = TRUE;
							nuc_optn      = TRUE;
							SH_optn       = FALSE;
							/* translate characters into format */
							/* used by ML engine */
							translatedataset(Maxspc, Maxseqc, &Maxsite, Seqchars, &Seqchar, &Seqgapchar, &Seqotherchar);
							estimatebasefreqs();
							break;
						}
						break;
					}
					if (data_optn == AMINOACID) { /* amino acid data */
						if (auto_aamodel) {
							/* AUTO -> Dayhoff */
							Dayhf_optn    = TRUE;
							Jtt_optn      = FALSE;
							mtrev_optn    = FALSE;
							cprev_optn    = FALSE;
							blosum62_optn = FALSE;
							vtmv_optn     = FALSE;
							wag_optn      = FALSE;
							lg_optn       = FALSE;
							auto_aamodel  = AUTO_OFF;
							break;
						}
						if (Dayhf_optn) {
							/* Dayhoff -> JTT */
							Dayhf_optn    = FALSE;
							Jtt_optn      = TRUE;
							mtrev_optn    = FALSE;
							cprev_optn    = FALSE;
							blosum62_optn = FALSE;
							vtmv_optn     = FALSE;
							wag_optn      = FALSE;
							lg_optn       = FALSE;
							auto_aamodel  = AUTO_OFF;
							break;
						}
						if (Jtt_optn) {
							/* JTT -> mtREV */
							Dayhf_optn    = FALSE;
							Jtt_optn      = FALSE;
							mtrev_optn    = TRUE;
							cprev_optn    = FALSE;
							blosum62_optn = FALSE;
							vtmv_optn     = FALSE;
							wag_optn      = FALSE;
							lg_optn       = FALSE;
							auto_aamodel  = AUTO_OFF;
							break;
						}
#ifdef CPREV
						if (mtrev_optn) {
							/* mtREV -> cpREV */
							Dayhf_optn    = FALSE;
							Jtt_optn      = FALSE;
							mtrev_optn    = FALSE;
							cprev_optn    = TRUE;
							blosum62_optn = FALSE;
							vtmv_optn     = FALSE;
							wag_optn      = FALSE;
							lg_optn       = FALSE;
							auto_aamodel  = AUTO_OFF;
							break;
						}
#else /* ! CPREV */
						if (mtrev_optn) {
							/* mtREV -> BLOSUM 62 */
							Dayhf_optn    = FALSE;
							Jtt_optn      = FALSE;
							mtrev_optn    = FALSE;
							cprev_optn    = FALSE;
							blosum62_optn = TRUE;
							vtmv_optn     = FALSE;
							wag_optn      = FALSE;
							lg_optn       = FALSE;
							auto_aamodel  = AUTO_OFF;
							break;
						}
#endif /* ! CPREV */

#ifdef CPREV
						if (cprev_optn) {
							/* cpREV -> BLOSUM 62 */
							Dayhf_optn    = FALSE;
							Jtt_optn      = FALSE;
							mtrev_optn    = FALSE;
							cprev_optn    = FALSE;
							blosum62_optn = TRUE;
							vtmv_optn     = FALSE;
							wag_optn      = FALSE;
							lg_optn       = FALSE;
							auto_aamodel  = AUTO_OFF;
							break;
						}
#endif
						if (blosum62_optn) {
							/* BLOSUM 62 -> VT model */
							Dayhf_optn    = FALSE;
							Jtt_optn      = FALSE;
							mtrev_optn    = FALSE;
							cprev_optn    = FALSE;
							blosum62_optn = FALSE;
							vtmv_optn     = TRUE;
							wag_optn      = FALSE;
							lg_optn       = FALSE;
							auto_aamodel  = AUTO_OFF;
							break;
						}
						if (vtmv_optn) {
							/* VT model -> WAG model */
							Dayhf_optn    = FALSE;
							Jtt_optn      = FALSE;
							mtrev_optn    = FALSE;
							cprev_optn    = FALSE;
							blosum62_optn = FALSE;
							vtmv_optn     = FALSE;
							wag_optn      = TRUE;
							lg_optn       = FALSE;
							auto_aamodel  = AUTO_OFF;
							break;
						}
						if (wag_optn) {
							/* WAG model -> LG model */
							Dayhf_optn    = FALSE;
							Jtt_optn      = FALSE;
							mtrev_optn    = FALSE;
							cprev_optn    = FALSE;
							blosum62_optn = FALSE;
							vtmv_optn     = FALSE;
							wag_optn      = FALSE;
							lg_optn       = TRUE;
							auto_aamodel  = AUTO_OFF;
							break;
						}
						if (lg_optn) {
							/* LG model -> AUTO */
							Dayhf_optn    = guessDayhf_optn;
							Jtt_optn      = guessJtt_optn;
							mtrev_optn    = guessmtrev_optn;
							cprev_optn    = guesscprev_optn;
							blosum62_optn = guessblosum62_optn;
							vtmv_optn     = guessvtmv_optn;
							wag_optn      = guesswag_optn;
							lg_optn       = guesslg_optn;
							auto_aamodel  = guessauto_aamodel;
							break;
						}
						/* TODO: poisson_optn equalin_optn mtmam_optn rtrev_optn - HAS ;^) */
						break;
					}
					if (data_optn == BINARY) {
						fprintf(STDOUT, "\n\n\nNo other model available!\n");
					}
					break;
					
			case 't':	if (data_optn != NUCLEOTIDE) {
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					} else {
						tstvf84 = 0.0;
						fprintf(STDOUT, "\n\n\nEnter an invalid value for ");
						fprintf(STDOUT, "estimation from data set! (0.5 for JC69/F81)\n");
						fprintf(STDOUT, "\nTransition/transversion parameter (%.2f-%.2f): ",
								MINTS, MAXTS);
						fflush(STDOUT);
						fscanf(param_in, "%lf", &TSparam);
						/* scanf("%lf", &TSparam); */
						do ;
						while (getc(param_in) != '\n');
						/* while (getchar() != '\n'); */
						if (TSparam < MINTS || TSparam > MAXTS) {
							optim_optn = TRUE;
							TSparam = 2.0;
						} else {
							optim_optn = FALSE;
						}
					}
					break;

			case 'q':	fprintf(STDOUT, "\n\n\n");
#					if PARALLEL
						PP_SendDone();
#					endif /* PARALLEL */
#	 if 0
					exit(0);
#	 endif
	 				tp_exit(0, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);

					break;

			case 'r':	if (!(TN_optn && nuc_optn)){
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					} else {
						tstvf84 = 0.0;
						fprintf(STDOUT, "\n\n\nEnter an invalid value ");
						fprintf(STDOUT, "for estimation from data set!\n");
						fprintf(STDOUT, "\nY/R transition parameter (%.2f-%.2f): ", MINYR, MAXYR);
						fflush(STDOUT);
						fscanf(param_in, "%lf", &YRparam);
						/* scanf("%lf", &YRparam); */
						do ;
						while (getc(param_in) != '\n');
						/* while (getchar() != '\n'); */
						if (YRparam < MINYR || YRparam > MAXYR) {
							optim_optn = TRUE;
							YRparam = 0.9;
						} else if (YRparam == 1.0) {
							TN_optn = FALSE;
							HKY_optn = TRUE;
							if (optim_optn) TSparam = 2.0;
						} else {
							optim_optn = FALSE;
						}
					}
					break;
						
			case 'p':	if (!(TN_optn && nuc_optn)){
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					} else {
						fprintf(STDOUT, "\n\n\nThe F84 model (Felsenstein 1984) is a restricted");
						fprintf(STDOUT, " TN model, and the one\nF84 parameter uniquely");
						fprintf(STDOUT, " determines the two corresponding TN parameters!\n\n");
						fprintf(STDOUT, "F84 expected transition/transversion ratio: ");
						fflush(STDOUT);
						fscanf(param_in, "%lf", &tstvf84);
						/* scanf("%lf", &tstvf84); */
						do ;
						while (getc(param_in) != '\n');
						/* while (getchar() != '\n'); */
						if (tstvf84 <= 0.0) tstvf84 = 0.0;
						else makeF84model();
					}
					break;

			case '1':	if (!(GTR_optn && nuc_optn)){
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					} else {
						fprintf(STDOUT, "\nA-C substitution rate: ");
						fflush(STDOUT);
						fscanf(param_in, "%lf", &GTR_ACrate);
						/* scanf("%lf", &GTR_ACrate); */
						do ; while (getc(param_in) != '\n');
						/* do ; while (getchar() != '\n'); */
					}
					break;
			case '2':	if (!(GTR_optn && nuc_optn)){
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					} else {
						fprintf(STDOUT, "\nA-G substitution rate: ");
						fflush(STDOUT);
						fscanf(param_in, "%lf", &GTR_AGrate);
						/* scanf("%lf", &GTR_AGrate); */
						do ; while (getc(param_in) != '\n');
						/* do ; while (getchar() != '\n'); */
					}
					break;
			case '3':	if (!(GTR_optn && nuc_optn)){
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					} else {
						fprintf(STDOUT, "\nA-T substitution rate: ");
						fflush(STDOUT);
						fscanf(param_in, "%lf", &GTR_ATrate);
						/* scanf("%lf", &GTR_ATrate); */
						do ; while (getc(param_in) != '\n');
						/* do ; while (getchar() != '\n'); */
					}
					break;
			case '4':	if (!(GTR_optn && nuc_optn)){
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					} else {
						fprintf(STDOUT, "\nC-G substitution rate: ");
						fflush(STDOUT);
						fscanf(param_in, "%lf", &GTR_CGrate);
						/* scanf("%lf", &GTR_CGrate); */
						do ; while (getc(param_in) != '\n');
						/* do ; while (getchar() != '\n'); */
					}
					break;
			case '5':	if (!(GTR_optn && nuc_optn)){
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					} else {
						fprintf(STDOUT, "\nC-T substitution rate: ");
						fflush(STDOUT);
						fscanf(param_in, "%lf", &GTR_CTrate);
						/* scanf("%lf", &GTR_CTrate); */
						do ; while (getc(param_in) != '\n');
						/* do ; while (getchar() != '\n'); */
					}
					break;
			case '6':	if (!(GTR_optn && nuc_optn)){
						fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					} else {
						fprintf(STDOUT, "\nG-T substitution rate: ");
						fflush(STDOUT);
						fscanf(param_in, "%lf", &GTR_GTrate);
						/* scanf("%lf", &GTR_GTrate); */
						do ; while (getc(param_in) != '\n');
						/* do ; while (getchar() != '\n'); */
					}
					break;
						
			case '9':	fprintf(STDOUT, "\n");
					if (savenexus_optn) {
						savenexus_optn         = FALSE;
					} else {
						savenexusptorder_optn  = TRUE;
						savenexusptsplits_optn = TRUE;
						savenexus_optn         = TRUE;
						savenexusjoin_optn     = TRUE;
					}
					break;

			case 'y':	fprintf(STDOUT, "\n");
					break;

			default:	fprintf(STDOUT, "\n\n\nThis is not a possible option!\n");
					break;
		}
	} while (ch != 'y');

	{
        int gaperror = 0;
	int notu;
	for (notu = 0; notu < Maxspc; notu++) {
#ifndef USE_WINDOWS
                if ((Seqgapchar[notu] + Seqotherchar[notu]) == Maxsite) {
#else
                if ((Seqgapchar[notu] + Seqotherchar[notu]) == alimaxsite) {
#endif
			if (gaperror == 0) {
				fprintf(STDOUT, "\n\n\n");
				fprintf(STDOUT, "\n\n\nUnable to proceed (only ambiguous characters ('-', '?', 'X', ...) \nin sequence(s) '");
			} else {
				fprintf(STDOUT, "', '");
			}
			fputid(STDOUT, notu);
			gaperror++;
                }

		if (gaperror > 0) {
			fprintf(STDOUT, "')\n\n\n");
#			if 0
#				if PARALLEL
					PP_Finalize();
#				endif
				exit(1);
#			endif
	 		tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
		}
	} /* for */
	}
} /* setoptions */


/* open file for reading */
int openfiletoread(FILE **fp, char name[], char descr[], FILE *infp)
{
	int count = 0;
	int reset = 0;
	cvector str;

	if ((*fp = fopen(name, "r")) == NULL) {
		fprintf(STDOUT, "\n\n\nPlease enter a file name for the %s: ", descr);
		fflush(STDOUT);
		/* str = mygets(); */
		str = myfgets(infp);
		reset = 1;
		while ((*fp = fopen(str, "r")) == NULL)
		{
			count++;
			if (count > 10)
			{
				fprintf(STDOUT, "\n\n\nToo many trials - quitting ...\n");
#				if 0
#					if PARALLEL
						PP_Finalize();
#					endif
					exit(1);
#				endif
	 			tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
			}
   			fprintf(STDOUT, "File '%s' not found, ", str);
			fprintf(STDOUT, "please enter alternative name: ");
			free_cvector(str);
			fflush(STDOUT);
			str = myfgets(infp);
			/* str = mygets(); */
			reset = 1;
		}
		fprintf(STDOUT, "\n");
		strcpy(name, str);
		free_cvector(str);
	}
	return(reset);
} /* openfiletoread */


/* open file for writing */
int openfiletowrite(FILE **fp, char name[], char descr[], FILE *infp)
{
	int count = 0;
	int reset = 0;
	cvector str;

	if ((*fp = fopen(name, "w")) == NULL) {
   		fprintf(STDOUT, "\n\n\nPlease enter a file name for the %s: ", descr);
		fflush(STDOUT);
		/* str = mygets(); */
		str = myfgets(infp);
		while ((*fp = fopen(str, "w")) == NULL)
		{
			count++;
			if (count > 10)
			{
				fprintf(STDOUT, "\n\n\nToo many trials - quitting ...\n");
#				if 0
#					if PARALLEL
						PP_Finalize();
#					endif
					exit(1);
#				endif
	 			tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
			}
   			fprintf(STDOUT, "File '%s' not created, ", str);
			fprintf(STDOUT, "please enter other name: ");
			free_cvector(str);
			fflush(STDOUT);
			/* str = mygets(); */
			str = myfgets(infp);
			reset = 1;
		}
		fprintf(STDOUT, "\n");
		strcpy(name, str);
		free_cvector(str);
	}
	return(reset);
} /* openfiletowrite */


/* open file for appending */
int openfiletoappend(FILE **fp, char name[], char descr[], FILE *infp)
{
	int count = 0;
	int reset = 0;
	cvector str;

	if ((*fp = fopen(name, "a")) == NULL) {
   		fprintf(STDOUT, "\n\n\nPlease enter a file name for the %s: ", descr);
		fflush(STDOUT);
		/* str = mygets(); */
		str = myfgets(infp);
		while ((*fp = fopen(str, "a")) == NULL)
		{
			count++;
			if (count > 10)
			{
				fprintf(STDOUT, "\n\n\nToo many trials - quitting ...\n");
#				if 0
#					if PARALLEL
						PP_Finalize();
#					endif
					exit(1);
#				endif
	 			tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
			}
   			fprintf(STDOUT, "File '%s' not created, ", str);
			fprintf(STDOUT, "please enter other name: ");
			free_cvector(str);
			fflush(STDOUT);
			/* str = mygets(); */
			str = myfgets(infp);
			reset = 1;
		}
		fprintf(STDOUT, "\n");
		strcpy(name, str);
		free_cvector(str);
	}
	return(reset);
} /* openfiletoappend */


/* close file */
void closefile(FILE *fp)
{	
	fclose(fp);
} /* closefile */

/* symmetrize doublet frequencies */
void symdoublets()
{
	int i, imean;
	double mean;
	
	if (data_optn == NUCLEOTIDE && SH_optn && sym_optn) {
		/* ML frequencies */
		mean = (Freqtpm[1] + Freqtpm[4])/2.0; /* AC CA */
		Freqtpm[1] = mean;
		Freqtpm[4] = mean;
		mean = (Freqtpm[2] + Freqtpm[8])/2.0; /* AG GA */
		Freqtpm[2] = mean;
		Freqtpm[8] = mean;
		mean = (Freqtpm[3] + Freqtpm[12])/2.0; /* AT TA */
		Freqtpm[3] = mean;
		Freqtpm[12] = mean;
		mean = (Freqtpm[6] + Freqtpm[9])/2.0; /* CG GC */
		Freqtpm[6] = mean;
		Freqtpm[9] = mean;
		mean = (Freqtpm[7] + Freqtpm[13])/2.0; /* CT TC */
		Freqtpm[7] = mean;
		Freqtpm[13] = mean;
		mean = (Freqtpm[11] + Freqtpm[14])/2.0; /* GT TG */
		Freqtpm[11] = mean;
		Freqtpm[14] = mean;
		
		/* base composition of each taxon */
		for (i = 0; i < Maxspc; i++) {
			imean = (Basecomp[i][1] + Basecomp[i][4])/2; /* AC CA */
			Basecomp[i][1] = imean;
			Basecomp[i][4] = imean;
			imean = (Basecomp[i][2] + Basecomp[i][8])/2; /* AG GA */
			Basecomp[i][2] = imean;
			Basecomp[i][8] = imean;
			imean = (Basecomp[i][3] + Basecomp[i][12])/2; /* AT TA */
			Basecomp[i][3] = imean;
			Basecomp[i][12] = imean;
			imean = (Basecomp[i][6] + Basecomp[i][9])/2; /* CG GC */
			Basecomp[i][6] = imean;
			Basecomp[i][9] = imean;
			imean = (Basecomp[i][7] + Basecomp[i][13])/2; /* CT TC */
			Basecomp[i][7] = imean;
			Basecomp[i][13] = imean;
			imean = (Basecomp[i][11] + Basecomp[i][14])/2; /* GT TG */
			Basecomp[i][11] = imean;
			Basecomp[i][14] = imean;
		}
	}
} /* symdoublets */

/* show Ts/Tv ratio and Ts Y/R ratio */
void computeexpectations()
{
	double AlphaYBeta, AlphaRBeta, piR, piY, num, denom, pyr, pur;
	
	if (nuc_optn == TRUE) { /* 4x4 nucs */
		piR = Freqtpm[0] + Freqtpm[2];
		piY = Freqtpm[1] + Freqtpm[3];
		AlphaRBeta = 4.0*TSparam / (1 + YRparam);
		AlphaYBeta = AlphaRBeta * YRparam;
		tstvratio = (AlphaRBeta*Freqtpm[0]*Freqtpm[2] +
					 AlphaYBeta*Freqtpm[1]*Freqtpm[3])/(piR * piY);
		yrtsratio = (AlphaYBeta*Freqtpm[1]*Freqtpm[3]) /
					(AlphaRBeta*Freqtpm[0]*Freqtpm[2]);
	} else { /* 16x16 nucs */
		pyr = Freqtpm[1]*Freqtpm[3] + Freqtpm[5]*Freqtpm[7] +
			Freqtpm[9]*Freqtpm[11] + Freqtpm[4]*Freqtpm[12] +
			Freqtpm[5]*Freqtpm[13] + Freqtpm[6]*Freqtpm[14] +
			Freqtpm[7]*Freqtpm[15] + Freqtpm[13]*Freqtpm[15];
		pur = Freqtpm[0]*Freqtpm[2] + Freqtpm[4]*Freqtpm[6] +
			Freqtpm[0]*Freqtpm[8] + Freqtpm[1]*Freqtpm[9] +
			Freqtpm[2]*Freqtpm[10] + Freqtpm[8]*Freqtpm[10] +
			Freqtpm[3]*Freqtpm[11] + Freqtpm[12]*Freqtpm[14];
		num = pyr + pur;
		denom = Freqtpm[0]*Freqtpm[1] + Freqtpm[1]*Freqtpm[2] +
			Freqtpm[0]*Freqtpm[3] + Freqtpm[2]*Freqtpm[3] +
			Freqtpm[0]*Freqtpm[4] + Freqtpm[1]*Freqtpm[5] +
			Freqtpm[4]*Freqtpm[5] + Freqtpm[2]*Freqtpm[6] +
			Freqtpm[5]*Freqtpm[6] + Freqtpm[3]*Freqtpm[7] +
			Freqtpm[4]*Freqtpm[7] + Freqtpm[6]*Freqtpm[7] +
			Freqtpm[4]*Freqtpm[8] + Freqtpm[5]*Freqtpm[9] +
			Freqtpm[8]*Freqtpm[9] + Freqtpm[6]*Freqtpm[10] +
			Freqtpm[9]*Freqtpm[10] + Freqtpm[7]*Freqtpm[11] +
			Freqtpm[8]*Freqtpm[11] + Freqtpm[10]*Freqtpm[11] +
			Freqtpm[0]*Freqtpm[12] + Freqtpm[8]*Freqtpm[12] +
			Freqtpm[1]*Freqtpm[13] + Freqtpm[9]*Freqtpm[13] +
			Freqtpm[12]*Freqtpm[13] + Freqtpm[2]*Freqtpm[14] +
			Freqtpm[10]*Freqtpm[14] + Freqtpm[13]*Freqtpm[14] +
			Freqtpm[3]*Freqtpm[15] + Freqtpm[11]*Freqtpm[15] +
			Freqtpm[12]*Freqtpm[15] + Freqtpm[14]*Freqtpm[15];
		tstvratio = 2.0*TSparam * num/denom;
		yrtsratio = pyr/pur;
	}
} /* computeexpectations */

/* write ML distance matrix to file */
void putdistance(FILE *fp)
{
	int i, j;
	
	fprintf(fp, "  %d\n", Maxspc);
	for (i = 0; i < Maxspc; i++) {
		fputid10(fp, i);
		for (j = 0; j < Maxspc; j++) {
			fprintf(fp, "  %.5f", Distanmat[i][j]/100.0);
			/* seven in one row */
			if ((j + 1) % 7 == 0 && j+1 != Maxspc)
				fprintf(fp, "\n          ");
		}
		fprintf(fp, "\n");
	}
} /* putdistance */

/* write tstv to file */
void puttstv()
{
	int maxchar;
	FILE *fp;
	int seq1, seq2, x, i, j;
	uli ts_counts = 0;
	uli tv_counts = 0;
	ulimatrix countmatr;
	uli validpairs = 0;	/* number of valid pair sites, i.e. excluding those with gaps+wildcards like X */
	uli editdist = 0;	/* edit distance on the valid pair sites, i.e. excluding those with gaps+wildcards like X */
	
	maxchar=1 + gettpmradix(); /* number of residues + 1 for gap/unknown */

	/**** if (data_optn == NUCLEOTIDE) { ****/ /* nucleotides */

		countmatr = new_ulimatrix(maxchar,maxchar);
#if 0
		if (data_optn == NUCLEOTIDE) { /* nucleotides */
			ts_counts = new_ulimatrix(Maxspc,Maxspc);
			tv_counts = new_ulimatrix(Maxspc,Maxspc);
		}
#endif


		/* write distance matrix */
		fprintf(STDOUT, "Writing tstv to file %s\n", TSTV);
		openfiletowrite(&fp, TSTV, "tstv", fp);

		if (data_optn == NUCLEOTIDE) { /* nucleotides */
			fprintf(fp, "pair\tdistance\tts\ttv");
		} else {
			fprintf(fp, "pair\tdistance");
		}

		for (i = 0; i < maxchar-2; i++) {		/* print tstv header line */
			for (j = i+1; j < maxchar-1; j++) {
				fprintf(fp, "\t%s%s", int2code(i), int2code(j));
			}
		}
		fprintf(fp, "\teditdist\tpairsites");
		fprintf(fp, "\n");


		for (seq1 = 0; seq1 < Maxspc; seq1++) {
			for (seq2 = seq1+1; seq2 < Maxspc; seq2++) {
				for (i = 0; i < maxchar; i++) {		/* init count array with 0 */
					for (j = 0; j < maxchar; j++) {
						countmatr[i][j]=0;
					}
				}

				for (x = 0; x < Maxsite; x++) {	/* count all sustitutions */
					countmatr[ (int) Seqchar[seq1][x] ][ (int) Seqchar[seq2][x] ]++;
				}


				if (data_optn == NUCLEOTIDE) { /* nucleotides */
					ts_counts = countmatr[0][2] + countmatr[2][0] + 
						    countmatr[1][3] + countmatr[3][1];
					tv_counts = countmatr[0][1] + countmatr[1][0] + 
						    countmatr[0][3] + countmatr[3][0] + 
						    countmatr[2][1] + countmatr[1][2] + 
						    countmatr[2][3] + countmatr[3][2];
#if 0
					validpairs = ts_counts + tv_counts + 
						     countmatr[0][0] + countmatr[1][1] + 
						     countmatr[2][2] + countmatr[3][3];
#endif
				}

	
				/* calculate the number of valid pairs between the sequences, i.e., */
				/* i.e. all pairs without gaps or wildcards  */
				validpairs = countmatr[maxchar-1][maxchar-1]; /* last diag to init */
				editdist   = 0; /* init num diff counter */
				for (i = 0; i < maxchar-2; i++) {	/* all counts w/o gaps */
					validpairs += countmatr[i][i];	/* add diag elements */
					for (j = i+1; j < maxchar-1; j++) {
						editdist += countmatr[i][j] + countmatr[j][i]; /* add off-diags = substitutions */
					}
				}
				validpairs += editdist; /* add off-diags to the valid pairs */

	
				fprintf(fp, "%d-%d", seq1+1, seq2+1);
				fprintf(fp, "\t%.6f", Distanmat[seq1][seq2]/100.0);
				if (data_optn == NUCLEOTIDE) { /* nucleotides */
					fprintf(fp, "\t%lu", ts_counts);
					fprintf(fp, "\t%lu", tv_counts);
				}
				for (i = 0; i < maxchar-2; i++) {	/* output counts w/o gaps */
					for (j = i+1; j < maxchar-1; j++) {
						fprintf(fp, "\t%lu", countmatr[i][j] + countmatr[j][i]);
					}
				}

				fprintf(fp, "\t%lu\t%lu", editdist, validpairs);
				fprintf(fp, "\n");
			}
		}

		closefile(fp);
		free_ulimatrix(countmatr);
	/* } */
} /* puttstv */


/* write editdist to file */
void puteditdist()
{
	int maxchar;
	FILE *fp;
	int seq1, seq2, x;
	ulimatrix distmatr;
	ulimatrix obsdistmatr;

	
	maxchar=1 + gettpmradix(); /* number of residues + 1 for gap/unknown */

	distmatr    = new_ulimatrix(Maxspc,Maxspc);
	obsdistmatr = new_ulimatrix(Maxspc,Maxspc);

	/* write distance matrix */
	fprintf(STDOUT, "Writing edit distances to file %s\n", EDITDIST);
	openfiletowrite(&fp, EDITDIST, "edit distances", fp);

	/* initialize count matrices */
	for (seq1 = 0; seq1 < Maxspc; seq1++) {
		distmatr[seq1][seq1]    = 0;
		obsdistmatr[seq1][seq1] = 0;
		for (seq2 = seq1+1; seq2 < Maxspc; seq2++) {
			distmatr[seq1][seq2]    = 0;
			obsdistmatr[seq1][seq2] = 0;
			distmatr[seq2][seq1]    = 0;
			obsdistmatr[seq2][seq1] = 0;
		}
	}
		

	/* count edit distance */
	for (seq1 = 0; seq1 < Maxspc; seq1++) {
		for (seq2 = seq1+1; seq2 < Maxspc; seq2++) {

			for (x = 0; x < Maxsite; x++) {	
				if(Seqchar[seq1][x] != Seqchar[seq2][x]) {
					distmatr[seq1][seq2]++; /* count edit distance including s:[x-] and [-x]:s */
					if((Seqchar[seq1][x] < maxchar-1) && (Seqchar[seq2][x] < maxchar-1)) { 
						obsdistmatr[seq1][seq2]++; /* count edit distance excluding s:[x-] and [-x]:s */
					}
				}
			}
		}
	}

	/* symmetrize edit distance matrices */
	for (seq1 = 0; seq1 < Maxspc; seq1++) {
		for (seq2 = seq1+1; seq2 < Maxspc; seq2++) {
			distmatr[seq2][seq1]    = distmatr[seq1][seq2];
			obsdistmatr[seq2][seq1] = obsdistmatr[seq1][seq2];
		}
	}

	/*****************/

	fprintf(fp, "\n\nObserved pairwise edit distance (excl. columns with gaps+wildcards):\n");
	fprintf(fp, "  %d\n", Maxspc);
	for (seq1 = 0; seq1 < Maxspc; seq1++) {
		fputid10(fp, seq1);
		for (seq2 = 0; seq2 < Maxspc; seq2++) {
			fprintf(fp, "  %7lu", obsdistmatr[seq1][seq2]);

			/* seven in one row */
			if ((seq2 + 1) % 7 == 0 && seq2+1 != Maxspc)
				fprintf(fp, "\n          ");
		}
		fprintf(fp, "\n");
	}

	/*****************/

	fprintf(fp, "Pairwise edit distance (incl. gaps+wildcards as separate state):\n");
	fprintf(fp, "  %d\n", Maxspc);
	for (seq1 = 0; seq1 < Maxspc; seq1++) {
		fputid10(fp, seq1);
		for (seq2 = 0; seq2 < Maxspc; seq2++) {
			fprintf(fp, "  %7lu", distmatr[seq1][seq2]);

			/* seven in one row */
			if ((seq2 + 1) % 7 == 0 && seq2+1 != Maxspc)
				fprintf(fp, "\n          ");
		}
		fprintf(fp, "\n");
	}

	/* close file and cleanup */
	closefile(fp);

	free_ulimatrix(distmatr);
	free_ulimatrix(obsdistmatr);
} /* puteditdist */

#define DEBUG_INFORM 1
#undef DEBUG_INFORM
/* determine number of [non-/partly] informative and constant sites */
/* - informative:        at least 2 states with at least 2 occurrences (includes partly informative) */
/* - partly informative: informative, but contains states with only 1 occurrence or gaps/wildcards */
/* - non-informative:    no 2 states with >=2 occurrences, excl. gaps/wildcards (includes constant sites) */
/* - constant+gaps:      only one character state plus gaps/wildcards */
/* - constant:           only one character state */

/* reminder for siteinform: */
/*    informative sites are FULLINFO + PARTINFO */
/*      - FULLINFO    1 */
/*      - PARTINFO    2 */
/* all non-informative sites are VARNONINFO + CONSTSITE + COSTSGAPS */
/*      - VARNONINFO  3 */
/*      - CONSTSITE   4 */
/*      - CONSTGAPS   5 */
void countinformativesites(uli       *inform, 		/* number of informative sites in the whole alignment, containing */
			   uli       *fullinform, 	/* - number of fully informative (no singletons/wildcards) sites */
			   uli       *partinform, 	/* - number of partly informative (may have singletons/wildcards) sites */
			   uli       *noninform, 	/* number of non-informative sites in the whole alignment, containing: */
			   uli       *varnoninform, 	/* - number of variable, non-informative sites in the whole alignment */
			   uli       *constantgaps, 	/* - number of constant (with gaps/wildcards) sites */
			   uli       *constant,		/* - number of constant (no gaps/wildcards) sites */
			   ivector   *siteinform, 	/* vector of informative site types for each position */
			   ulivector *gapvec,		/* vector of gap (+ wildcard) counts for each position */
			   ulivector *taxinform,	/* vector of informative-site counts for each taxon */
			   ulivector *taxnoninform)	/* vector of non-informative-site counts for each taxon */
{
	int maxchar;
	int pos, tax, i, t;
	ulivector countvec;

	uli onetime;
	uli twotime;

	*inform       = 0;
	*fullinform   = 0;
	*partinform   = 0;
	*noninform    = 0;
	*varnoninform = 0;
	*constantgaps = 0;
	*constant     = 0;

	maxchar = gettpmradix(); /* number of residues + 1 for gap/unknown */

	countvec           = new_ulivector(maxchar+1);
	(*siteinform)      = new_ivector(Maxsite);
	(*gapvec)          = new_ulivector(Maxsite);
	(*taxinform)       = new_ulivector(Maxspc);
	(*taxnoninform)    = new_ulivector(Maxspc);
	

	for (t = 0; t < Maxspc; t++) {		
		/* init count taxon array with 0 */
		(*taxinform)[t]       = 0;
		(*taxnoninform)[t]    = 0;
 	}


	/* for each alignment column */
	for (pos = 0; pos < Maxsite; pos++) {

		/* reset position for debugging */
		(*siteinform)[pos] = UNKNOWN;

		/* store number of gaps/wildcards */
		(*gapvec)[pos] = countvec[maxchar];

		/* reset count vector */
		for (i = 0; i <= maxchar; i++) {		
			/* init count array with 0 */
			countvec[i] = 0;
 		}
		onetime = 0;
		twotime = 0;

		for (tax = 0; tax < Maxspc; tax++) {
			/* count states */
			countvec[(int) Seqchar[tax][pos]]++;
		}

		for (i = 0; i < maxchar; i++) {	/* check all except gap/wildcards (=maxchar) */
			if(countvec[i]>0){
				if(countvec[i]>1){
					twotime++;
				} else {
					onetime++;
				}
			}
 		}

		if (twotime>1) { /* informative */
			(*inform)++;
#ifdef DEBUG_INFORM
			fprintf(stderr, "III site %d: I   (1x=%lu, 2x=%lu, gaps+X=%lu - informative, %lu)\n", pos+1, onetime, twotime, countvec[maxchar], *inform);
#endif
			if ((onetime==0) && (countvec[maxchar]==0)) { 
				/* fully informative (no single states/gaps/wildcards exist) */
				(*fullinform)++;
				(*siteinform)[pos] = FULLINFO;
				for (t = 0; t < Maxspc; t++) { 
					/* count as informative sites per taxon */
					(*taxinform)[t]++;
				}
#ifdef DEBUG_INFORM
				fprintf(stderr, "III site %d: - f (1x=%lu, 2x=%lu, gaps+X=%lu - fully informative, %lu)\n", pos+1, onetime, twotime, countvec[maxchar], *fullinform);
#endif
			} else { 
				/* partly informative (single states/gaps exist) */
				(*partinform)++;
				(*siteinform)[pos] = PARTINFO;

				for (t = 0; t < Maxspc; t++) { /* count (un)informative sites per taxon */
					if(countvec[(int)Seqchar[t][pos]]>1) {
						(*taxinform)[t]++;
					} else {
						(*taxnoninform)[t]++;
					}
 				}

#ifdef DEBUG_INFORM
				fprintf(stderr, "III site %d: - p (1x=%lu, 2x=%lu, gaps+X=%lu - partly informative, %lu)\n", pos+1, onetime, twotime, countvec[maxchar], *partinform);
#endif
			}
		} else { /* uninformative */
			(*noninform)++;
			for (t = 0; t < Maxspc; t++) {
				(*taxnoninform)[t]++;
 			}

#ifdef DEBUG_INFORM
			fprintf(stderr, "III site %d: N   (1x=%lu, 2x=%lu, gaps+X=%lu - uninformative, %lu)\n", pos+1, onetime, twotime, countvec[maxchar], *noninform);
#endif

			if ((onetime==0) && (twotime==1) && (countvec[maxchar]==0)) { 
				/* constant */
				(*constant)++;
				(*siteinform)[pos] = CONSTSITE;
#ifdef DEBUG_INFORM
				fprintf(stderr, "III site %d: - C (1x=%lu, 2x=%lu, gaps+X=%lu - completely constant, %lu)\n", pos+1, onetime, twotime, countvec[maxchar], *constant);
#endif
			} else {
				if ((onetime==0) && (twotime==1) && (countvec[maxchar]>0)) { 
					/* constant incl. gaps/wildcards */
					(*constantgaps)++;
					(*siteinform)[pos] = CONSTGAPS;
#ifdef DEBUG_INFORM
					fprintf(stderr, "III site %d: - c (1x=%lu, 2x=%lu, gaps+X=%lu - contains gaps+wildcards, but otherwise constant, %lu)\n", pos+1, onetime, twotime, countvec[maxchar], *constantgaps);
#endif
				} else {
					/* variable, but non-informative */
					(*varnoninform)++;
					(*siteinform)[pos] = VARNONINFO;
#ifdef DEBUG_INFORM
					fprintf(stderr, "III site %d: - v (1x=%lu, 2x=%lu, gaps+X=%lu - variable but uninformative, %lu)\n", pos+1, onetime, twotime, countvec[maxchar], *varnoninform);
#endif
				}
			}
		}
	} /* END for each alignment column */

	free_ulivector(countvec);

#if 0
	for (pos = 0; pos < Maxsite; pos++) 
		fprintf(stderr, "XXX\tpos:%d\t%d\n",pos,(*siteinform)[pos]);
#endif
} /* countinformativesites */


/****************************/
/***      for VisRec      ***/
/****************************/

/* reminder for siteinform: */
/*    informative sites are FULLINFO + PARTINFO */
/*      - FULLINFO    1 */
/*      - PARTINFO    2 */
/* all non-informative sites are VARNONINFO + CONSTSITE + COSTSGAPS */
/*      - VARNONINFO  3 */
/*      - CONSTSITE   4 */
/*      - CONSTGAPS   5 */
/*      - GAPS        6 */
void writealivisrecinformativesites(FILE      *ofp,
			      FILE      *nofp,
			      ivector    siteinform, 
			      ulivector  gapvec, 
			      uli        stepsize, 
			      uli        winsize) 
{
	long int startpos, midpos, endpos;
	long int startposold, endposold;
	long int winlen, leftwin, rightwin;

	/* uli offset, count, max, len, wincenter; */
	long int maxinfotype = 7, count;
	long int countarr[maxinfotype];

	if (ofp!=NULL) {
		fprintf(ofp, "BEGIN INFSITES;\n");
		fprintf(ofp, "   [ center  fullinf partlyinf  varnoninf complconst constgap  gaps ]\n");
	}

#if 0
	if (ofp!=NULL) {
		fprintf(ofp, "center\tstart\tend\tinformative\tpartlyinformative\tnoninformative\tcompletelyconstant\tconstant\n");
	}
#endif

	if (nofp!=NULL) {
		fprintf(nofp, "center\tstart\tend\tinformative\tpartlyinformative\tnoninformative\tcompletelyconstant\tconstant\tgaps\tnumspec\tlength\n");
	}

	/* reset count array */
	for (count=0; count<=maxinfotype; count++) {
		countarr[count] = 0;
	}

	leftwin=(long int)((winsize)/2);
	rightwin=(long int)((winsize-1)/2);
	midpos=1;

#if 0
/* some debug output */
for (count=0; count<Maxsite; count++) {
fprintf(stderr, "YYY pos: %lu/gaps: %lu\n", count, gapvec[count]);
/* fprintf(stderr, "XXX %lu %lu\n", wincenter, countarr[GAPS]); */
}
#endif
	
	startpos    = midpos-leftwin;
	endpos      = midpos+rightwin;
	startposold = 1;
	endposold   = 0;
	winlen      = 0;

	while(midpos <= Maxsite) {
		startpos = midpos-leftwin;
		endpos   = midpos+rightwin;
		if(startpos<1)     startpos=1;
		if(endpos>Maxsite) endpos=Maxsite;
		winlen=endpos - startpos + 1;

		/* substract old values [startpos_old..startpos-1] */
		while (startposold<startpos){
			countarr[maxinfotype] -= gapvec[startposold]; /* substract site gaps */
			countarr[siteinform[startposold++]]--;        /* substract site type */
		}

		/* add new values [endpos_old+1..endpos] */
		endposold++;
		while (endposold<=endpos){
			countarr[maxinfotype] += gapvec[endposold]; /* add site gaps */
			countarr[siteinform[endposold++]]++;        /* add site type */
		}

		/* printf("%5ld / %5ld / %5ld = %5ld\n", startpos, midpos, endpos, winlen); */
#if 0
#endif
#if 0
fprintf(stderr, "XXX %5ld / %5ld / %5ld = %5ld\n", startpos, midpos, endpos, winlen);
#endif

		if (ofp!=NULL) { /* save percentages */
			fprintf(ofp, "INFORM %ld  %.3f %.3f  %.3f %.3f %.3f  %.3f;\n",
				midpos, 
				/* startpos, */
				/* endpos, */
				(double)(100.0*((double)countarr[FULLINFO])/(double)winlen),
				(double)(100.0*((double)countarr[PARTINFO])/(double)winlen),
				/* (double)(100.0*((double)countarr[FULLINFO]+(double)countarr[PARTINFO])/(double)winlen), */
				/* (double)(100.0*((double)countarr[VARNONINFO]+(double)countarr[CONSTSITE]+(double)countarr[CONSTGAPS])/(double)winlen), */
				(double)(100.0*((double)countarr[VARNONINFO])/(double)winlen),
				(double)(100.0*((double)countarr[CONSTSITE])/(double)winlen),
				(double)(100.0*((double)countarr[CONSTGAPS])/(double)winlen),
				(double)(100.0*((double)countarr[maxinfotype])/(double)(winlen*Maxspc)));

#if 0
fprintf(stderr, "ZZZ %.2f\n", (double)(100.0*((double)countarr[FULLINFO])/(double)winlen)
				+(double)(100.0*((double)countarr[PARTINFO])/(double)winlen)
				+(double)(100.0*((double)countarr[VARNONINFO])/(double)winlen)
				+(double)(100.0*((double)countarr[CONSTSITE])/(double)winlen)
				+(double)(100.0*((double)countarr[CONSTGAPS])/(double)winlen));
#endif
		}

#if 0
		if (ofp!=NULL) { /* save percentages */
			fprintf(ofp, "%lu\t%lu\t%lu\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f\n",
				midpos, startpos, endpos, 
				(double)(100.0*((double)countarr[FULLINFO]+(double)countarr[PARTINFO])/(double)winlen),
				(double)(100.0*((double)countarr[PARTINFO])/(double)winlen),
				(double)(100.0*((double)countarr[VARNONINFO]+(double)countarr[CONSTSITE]+(double)countarr[CONSTGAPS])/(double)winlen),
				(double)(100.0*((double)countarr[CONSTSITE])/(double)winlen),
				(double)(100.0*((double)countarr[CONSTGAPS])/(double)winlen));
		}
#endif

		/* output counts of informative sites */
		if (nofp!=NULL) {
			fprintf(nofp, "%lu\t%lu\t%lu\t%lu\t%lu\t%lu\t%lu\t%lu\t%lu\t%d\t%lu\n",
				midpos, startpos, endpos, 
				(countarr[FULLINFO]+countarr[PARTINFO]),
				(countarr[PARTINFO]),
				(countarr[VARNONINFO]+countarr[CONSTSITE]+countarr[CONSTGAPS]),
				(countarr[CONSTSITE]),
				(countarr[CONSTGAPS]),
				(countarr[GAPS]),
				Maxspc,
				winlen);
		}

		midpos += stepsize;
		endposold = endpos;
		startposold = startpos;
	}


	if (ofp!=NULL) {
		fprintf(ofp, "END; [INFSITES]\n");
	}



/* 
fprintf(stderr, "RRR c%lu cg%lu cm%lu G%d m%lu\n", midpos, countarr[GAPS], countarr[maxinfotype], GAPS, maxinfotype);
*/ 

} /* writealivisrecinformativesites */

/****************************/



/* reminder for siteinform: */
/*    informative sites are FULLINFO + PARTINFO */
/*      - FULLINFO    1 */
/*      - PARTINFO    2 */
/* all non-informative sites are VARNONINFO + CONSTSITE + COSTSGAPS */
/*      - VARNONINFO  3 */
/*      - CONSTSITE   4 */
/*      - CONSTGAPS   5 */
/*      - GAPS        6 */
void writealiinformativesites(FILE      *ofp,
			      FILE      *nofp,
			      ivector    siteinform, 
			      ulivector  gapvec, 
			      uli        stepsize, 
			      uli        winsize) 
{
	uli pos1, pos2;
	uli end1, end2;
	uli offset, count, max, len, wincenter;
	uli maxinfotype = 7;
	uli countarr[maxinfotype];

	/* reset count arrar */
	for (count=0; count<=maxinfotype; count++) {
		countarr[count] = 0;
	}

	max=winsize;
	if (max>Maxsite) max=Maxsite;

	offset=(uli)((winsize+1)/2); /* offset to window center */

for (count=0; count<Maxsite; count++) {
fprintf(stderr, "YYY %lu %lu\n", count, gapvec[count]);
/* fprintf(stderr, "XXX %lu %lu\n", wincenter, countarr[GAPS]); */
}
	
	/* init count array for the 1st window */
	for (count=0; count<max; count++) {
		countarr[siteinform[count]]++;
		countarr[maxinfotype] += gapvec[count];
	}
/* fprintf(stderr, "ZZZ %lu %lu\n", (uli)0, countarr[maxinfotype]); */

	pos1=0;
	pos2=count;

	count=0;
	wincenter=count*stepsize + offset;

	if (ofp!=NULL) {
		fprintf(ofp, "center\tstart\tend\tinformative\tpartlyinformative\tnoninformative\tcompletelyconstant\tconstant\n");
	}

	if (nofp!=NULL) {
		fprintf(nofp, "center\tstart\tend\tinformative\tpartlyinformative\tnoninformative\tcompletelyconstant\tconstant\tgaps\tnumspec\tlength\n");
	}

fprintf(stderr, "Maxsite: %d\n", Maxsite);
	while(wincenter<Maxsite) {
		/* fprintf(ofp, "center\tstart\tend\tinformative\tpartlyinformative\tnoninformative\tcompletelyconstant\tconstant\n"); */
		/* compute window length - differs at the end of the alignment */
		len=pos2-pos1;
		/* output fractions of informative sites */
		if (ofp!=NULL) {
			fprintf(ofp, "%lu\t%lu\t%lu\t%.6f\t%.6f\t%.6f\t%.6f\t%.6f\n",
				wincenter, pos1+1, pos2, 
				(double)(100.0*((double)countarr[FULLINFO]+(double)countarr[PARTINFO])/(double)len),
				(double)(100.0*((double)countarr[PARTINFO])/(double)len),
				(double)(100.0*((double)countarr[VARNONINFO]+(double)countarr[CONSTSITE]+(double)countarr[CONSTGAPS])/(double)len),
				(double)(100.0*((double)countarr[CONSTSITE])/(double)len),
				(double)(100.0*((double)countarr[CONSTGAPS])/(double)len));
		}
fprintf(stderr, "RRR c%lu cg%lu cm%lu G%d m%lu\n", wincenter, countarr[GAPS], countarr[maxinfotype], GAPS, maxinfotype);
		/* output counts of informative sites */
		if (nofp!=NULL) {
			fprintf(nofp, "%lu\t%lu\t%lu\t%lu\t%lu\t%lu\t%lu\t%lu\t%lu\t%d\t%lu\n",
				wincenter, pos1+1, pos2, 
				(countarr[FULLINFO]+countarr[PARTINFO]),
				(countarr[PARTINFO]),
				(countarr[VARNONINFO]+countarr[CONSTSITE]+countarr[CONSTGAPS]),
				(countarr[CONSTSITE]),
				(countarr[CONSTGAPS]),
				(countarr[GAPS]),
				Maxspc,
				len);
		}

		/* substract old values */
		end1=pos1+stepsize;
		if (end1>Maxsite) end1=Maxsite;
		while (pos1<end1){
			countarr[maxinfotype] -= gapvec[pos1];
			countarr[siteinform[pos1++]]--;
		}

		/* add new values */
		end2=pos2+stepsize;
		if (end2>Maxsite) end2=Maxsite;
		while (pos2<end2){
			countarr[maxinfotype] += gapvec[pos2];
			countarr[siteinform[pos2++]]++;
		}

		/* fprintf(ofp, "ZZZ %lu - c%lu - p1:%lu - p2:%lu - e1:%lu - e2:%lu - max:%d - len:%lu\n",
			count, wincenter, pos1, pos2, end1, end2, Maxsite, len); */

		/* new window and wincenter */
		count++; 
		wincenter=count*stepsize + offset;
	}

} /* writealiinformativesites */


/* find identical sequences */
/* write ML distance matrix to file */
void putdistancenexus(FILE *nfp)
{
	int i, j;

	fprintf(nfp, "BEGIN Distances;\n");
	fprintf(nfp, "  DIMENSIONS NTAX=%d;\n", Maxspc);
	fprintf(nfp, "  FORMAT TRIANGLE=BOTH DIAGONAL LABELS;\n");
	fprintf(nfp, "  MATRIX\n");

	
	/* fprintf(nfp, "  %d\n", Maxspc); */

	for (i = 0; i < Maxspc; i++) {
		/* if (i>0) fprintf(nfp, ",\n"); */
		fprintf(nfp, "\t'");
		fputid(nfp, i);
		fprintf(nfp, "'\t");

		for (j = 0; j < Maxspc; j++) {
			fprintf(nfp, "  %.5f", Distanmat[i][j]/100.0);
		}
		fprintf(nfp, "\n");
	}
	fprintf(nfp, "  ;\n");
	fprintf(nfp, "  END; [Distances]\n");
} /* putdistance */


/* find identical sequences */
void findidenticals(FILE *fp)
{
	int i, j, noids;
	cvector useqs;
	
	useqs = new_cvector(Maxspc);
	
	for (i = 0; i < Maxspc; i++)
		useqs[i] = 0;
	
	noids = TRUE;
	for (i = 0; i < Maxspc && noids; i++)
		for (j = i + 1; j < Maxspc && noids; j++)
			if (Distanmat[i][j] == 0.0) noids = FALSE;
	
	if (noids)
		fprintf(fp, " All sequences are unique.\n");
	else {
		for (i = 0; i < Maxspc; i++) {	
			noids = TRUE;
			for (j = i + 1; j < Maxspc && noids; j++)
				if (Distanmat[i][j] == 0.0) noids = FALSE;
				
			if (!noids && useqs[i] == 0) {
				fputid(fp, i);
				useqs[i] = 1;	
				for (j = i + 1; j < Maxspc; j++)
					if (Distanmat[i][j] == 0.0) {
						fprintf(fp, ", ");
						fputid(fp, j);
						useqs[j] = 1;
					}				
				fprintf(fp, ".\n");
			}
		}
		fprintf(fp, "\nNote: Identical sequences are identified by zero distance.\n");
		fprintf(fp, "Hence, two 'identical' sequences might differ by gaps or\n");
		fprintf(fp, "ambiguous characters.\n");
	}
	free_cvector(useqs);
} /* findidenticals */

/* compute average distance */
double averagedist(int maxspc, dmatrix  distanmat, double *meandist, double *mindist, double *maxdist, double *stddevdist, double *vardist)
{	
	int i, j;
	double sum;
	double avg;
	double min;
	double max;
	double var;
	double stddev;
	double temp;
	double numofdists;
	
	numofdists = ((double) (maxspc * (maxspc - 1)) / 2.0);
	sum = 0.0;
	for (i = 0; i < maxspc; i++)
		for (j = i + 1; j < maxspc; j++)
			sum = sum + distanmat[i][j];
	
	/* avg = sum / (double) maxspc / ((double) maxspc - 1.0) * 2.0; */
	/* avg = sum / ((double) (maxspc * (maxspc - 1)) / 2.0); */
	avg = sum / numofdists;


/*
	fprintf(stderr, "\nXXXX: old %f, new %f\n",
	1 / (double) maxspc / ((double) maxspc - 1.0) * 2.0,
	1 / ((double) (maxspc * (maxspc - 1)) / 2.0));
*/
	
	sum = 0.0;
	min = distanmat[0][1];
	max = distanmat[0][1];
	for (i = 0; i < maxspc; i++)
		for (j = i + 1; j < maxspc; j++) {
			temp = avg/100 - distanmat[i][j]/100;
			sum += temp * temp;
			if (min > distanmat[i][j]) min = distanmat[i][j];
			if (max < distanmat[i][j]) max = distanmat[i][j];
		}
	var = sum / (numofdists - 1);
	stddev = sqrt(var);

#if 0
	fprintf(stderr, "\nXXXX: mean=%f, min=%f max=%f variance=%f, std-deviation=%f\n",
		avg/100, min/100, max/100, var, stddev);
#endif
	*meandist   = avg/100;
	*mindist    = min/100;
	*maxdist    = max/100;
	*vardist    = var;
	*stddevdist = stddev;
	return avg;
} /* averagedist */


/**********************************************************/
/*  Likelihood mapping routines (TODO: move to lmap.c/h)  */
/**********************************************************/

/*
                   (a,b)-(c,d)   => numclust == 4
                   (a,b)-(c,c)   => numclust == 3
                   (a,a)-(b,b)   => numclust == 2

                     1l/\1r
                      /  \
                     /  1 \
                 6u / \  / \ 4u
                   /   \/   \
               6d /    /\    \ 4d
                 / 6  /  \  4 \
                /\   /  7 \   /\
             3u/  \ /______\ /  \2u
              / 3  |    5   |  2 \
             /_____|________|_____\
	        3d   5l  5r   2d
    (a,d)-(b,c)                  (a,c)-(b,d)   => numclust == 4
    (a,c)-(b,c)                  (a,c)-(b,c)   => numclust == 3
    (a,b)-(a,b)                  (a,b)-(a,b)   => numclust == 2

*/

/***********************************
*  Likelihood mapping to SVG file  *
***********************************/

/* first lines of SVG likelihood mapping file */
void initsvg(FILE *ofp)
{
	/* SVG preamble */
	fprintf(ofp,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
	fprintf(ofp,"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
	fprintf(ofp,"<svg\n");
	fprintf(ofp,"   xmlns:svg=\"http://www.w3.org/2000/svg\"\n");
	fprintf(ofp,"   xmlns=\"http://www.w3.org/2000/svg\"\n");
	fprintf(ofp,"   xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
	fprintf(ofp,"   version=\"1.1\"\n");
	fprintf(ofp,"   baseProfile=\"full\"\n");
	fprintf(ofp,"   id=\"body\"\n");
	fprintf(ofp,"   width=\"800px\"\n");
	fprintf(ofp,"   height=\"800px\"\n");
	fprintf(ofp,"   viewBox=\"0 0 1000 1000\"\n");
	fprintf(ofp,"   preserveAspectRatio=\"none\">\n");
	fprintf(ofp,"  <defs>\n");
	fprintf(ofp,"    <style type=\"text/css\"><![CDATA[\n");
	/* fprintf(ofp,"      #result circle{ fill: black; stroke: none; }\n"); */
	fprintf(ofp,"      circle{ stroke: none; }\n");
	fprintf(ofp,"      polygon{ stroke: black; stroke-width: 2px; fill: none; }\n");
	fprintf(ofp,"      line{ stroke: black; stroke-width: 2px; }\n");
	fprintf(ofp,"      text{ font-size:50px; }\n");
	fprintf(ofp,"    ]]></style>\n");
	fprintf(ofp,"  </defs>\n");
	fprintf(ofp,"  <title\n");
	fprintf(ofp,"     id=\"title1\">SVG drawing</title>\n");
	/* end SVG preamble */

	/* triangle 1 (top) */
	fprintf(ofp,"<g transform=\"scale(0.45)\"><g transform=\"translate(600,1050)\">\n");
	fprintf(ofp,"  <g id=\"fig1\">\n");
	fprintf(ofp,"	<polygon points=\"0.0,-0.0 1000.0,-0.0 500,-866.0254038\" />\n");


	if (numclust == 4) { /* four cluster analysis */
		fprintf(ofp,"	<text\n");
		fprintf(ofp,"	   x=\"500.0\"\n");
		fprintf(ofp,"	   y=\"-896.0254038\"\n");
		fprintf(ofp,"	   text-anchor=\"middle\"\n");
		fprintf(ofp,"	   id=\"label_top_1\">(a,b)-(c,d)</text> <!-- CHANGE HERE IF NECESSARY -->\n");
		fprintf(ofp,"	<text\n");
		fprintf(ofp,"	   x=\"-30.0\"\n");
		fprintf(ofp,"	   y=\"60.0\"\n");
		fprintf(ofp,"	   text-anchor=\"middle\"\n");
		fprintf(ofp,"	   id=\"label_left_1\">(a,d)-(b,c)</text> <!-- CHANGE HERE IF NECESSARY -->\n");
		fprintf(ofp,"	<text\n");
		fprintf(ofp,"	   x=\"1030.0\"\n");
		fprintf(ofp,"	   y=\"60.0\"\n");
		fprintf(ofp,"	   text-anchor=\"middle\"\n");
		fprintf(ofp,"	   id=\"label_right_1\">(a,c)-(b,d)</text> <!-- CHANGE HERE IF NECESSARY -->\n");

		// fprintf(ofp, "%% label corners\n");
		// fprintf(ofp, "0.5 tl 0.9 tl moveto\n"); /* old: 0.375 0.9 */
		// fprintf(ofp, "((a,b)-(c,d)) centershow %% CHANGE HERE IF NECESSARY\n");
		// fprintf(ofp, "-0.045 tl -0.08 tl moveto\n"); /* old: -0.16 -0.08 */
		// fprintf(ofp, "((a,d)-(b,c)) centershow %% CHANGE HERE IF NECESSARY\n");
		// fprintf(ofp, "1.045 tl -0.08 tl moveto\n"); /* old: -0.92 -0.08 */
		// fprintf(ofp, "((a,c)-(b,d)) centershow %% CHANGE HERE IF NECESSARY\n");
	}
	if (numclust == 3) { /* three cluster analysis */
		fprintf(ofp,"	<text\n");
		fprintf(ofp,"	   x=\"500.0\"\n");
		fprintf(ofp,"	   y=\"-896.0254038\"\n");
		fprintf(ofp,"	   text-anchor=\"middle\"\n");
		fprintf(ofp,"	   id=\"label_top_1\">(a,b)-(c,c)</text> <!-- CHANGE HERE IF NECESSARY -->\n");
		fprintf(ofp,"	<text\n");
		fprintf(ofp,"	   x=\"-30.0\"\n");
		fprintf(ofp,"	   y=\"60.0\"\n");
		fprintf(ofp,"	   text-anchor=\"middle\"\n");
		fprintf(ofp,"	   id=\"label_left_1\">(a,c)-(b,c)</text> <!-- CHANGE HERE IF NECESSARY -->\n");
		fprintf(ofp,"	<text\n");
		fprintf(ofp,"	   x=\"1030.0\"\n");
		fprintf(ofp,"	   y=\"60.0\"\n");
		fprintf(ofp,"	   text-anchor=\"middle\"\n");
		fprintf(ofp,"	   id=\"label_right_1\">(a,c)-(b,c)</text> <!-- CHANGE HERE IF NECESSARY -->\n");

		// fprintf(ofp, "%% label corners\n");
		// fprintf(ofp, "0.5 tl 0.9 tl moveto\n"); /* old: 0.375 0.9 */
		// fprintf(ofp, "((a,b)-(c,c)) centershow %% CHANGE HERE IF NECESSARY\n");
		// fprintf(ofp, "-0.045 tl -0.08 tl moveto\n"); /* old: -0.16 -0.08 */
		// fprintf(ofp, "((a,c)-(b,c)) centershow %% CHANGE HERE IF NECESSARY\n");
		// fprintf(ofp, "1.045 tl -0.08 tl moveto\n"); /* old: -0.92 -0.08 */
		// fprintf(ofp, "((a,c)-(b,c)) centershow %% CHANGE HERE IF NECESSARY\n");
	}
	if (numclust == 2) { /* two cluster analysis */
		fprintf(ofp,"	<text\n");
		fprintf(ofp,"	   x=\"500.0\"\n");
		fprintf(ofp,"	   y=\"-896.0254038\"\n");
		fprintf(ofp,"	   text-anchor=\"middle\"\n");
		fprintf(ofp,"	   id=\"label_top_1\">(a,a)-(b,b)</text> <!-- CHANGE HERE IF NECESSARY -->\n");
		fprintf(ofp,"	<text\n");
		fprintf(ofp,"	   x=\"-30.0\"\n");
		fprintf(ofp,"	   y=\"60.0\"\n");
		fprintf(ofp,"	   text-anchor=\"middle\"\n");
		fprintf(ofp,"	   id=\"label_left_1\">(a,b)-(a,b)</text> <!-- CHANGE HERE IF NECESSARY -->\n");
		fprintf(ofp,"	<text\n");
		fprintf(ofp,"	   x=\"1030.0\"\n");
		fprintf(ofp,"	   y=\"60.0\"\n");
		fprintf(ofp,"	   y=\"60.0\"\n");
		fprintf(ofp,"	   text-anchor=\"middle\"\n");
		fprintf(ofp,"	   id=\"label_right_1\">(a,b)-(a,b)</text> <!-- CHANGE HERE IF NECESSARY -->\n");

		// fprintf(ofp, "%% label corners\n");
		// fprintf(ofp, "0.5 tl 0.9 tl moveto\n"); /* old: 0.375 0.9 */
		// fprintf(ofp, "((a,a)-(b,b)) centershow %% CHANGE HERE IF NECESSARY\n");
		// fprintf(ofp, "-0.045 tl -0.08 tl moveto\n"); /* old: -0.16 -0.08 */
		// fprintf(ofp, "((a,b)-(a,b)) centershow %% CHANGE HERE IF NECESSARY\n");
		// fprintf(ofp, "1.045 tl -0.08 tl moveto\n"); /* old: -0.92 -0.08 */
		// fprintf(ofp, "((a,b)-(a,b)) centershow %% CHANGE HERE IF NECESSARY\n");
	}

} /* initsvg */


void plotlmpointsvg(FILE *ofp, double w1, double w2)
{
	/* plot dots into triangle 1 (top) */
	fprintf(ofp,"	<circle xxx cx=\"%.10f\" cy=\"%.10f\" r=\"2\" />\n", (0.5*w1 + w2)*1000, -(w1*866.0254038));
} /* plotlmpointsvg */

void finishsvg(FILE *ofp, uli **countarr)
{
	fprintf(ofp,"  </g>\n");
	/* end triangle 1 (top) */

	/* triangle 2 (bottom left) */
	fprintf(ofp,"  <g id=\"fig2\" transform=\"translate(-550.0,1000)\">\n");
	fprintf(ofp,"	<polygon points=\"0.0,-0.0 1000.0,-0.0 500.0,-866.0254038\" />\n");
	fprintf(ofp,"	<line\n");
	fprintf(ofp,"	   id=\"line2-1\"\n");
	fprintf(ofp,"	   y2=\"-0.0\"\n");
	fprintf(ofp,"	   x2=\"500\"\n");
	fprintf(ofp,"	   y1=\"-288.6751346\"\n");
	fprintf(ofp,"	   x1=\"500\" />\n");
	fprintf(ofp,"	<line\n");
	fprintf(ofp,"	   id=\"line2-2\"\n");
	fprintf(ofp,"	   y2=\"-433.0127019\"\n");
	fprintf(ofp,"	   x2=\"250\"\n");
	fprintf(ofp,"	   y1=\"-288.6751346\"\n");
	fprintf(ofp,"	   x1=\"500\" />\n");
	fprintf(ofp,"	<line\n");
	fprintf(ofp,"	   id=\"line2-3\"\n");
	fprintf(ofp,"	   y2=\"-433.0127019\"\n");
	fprintf(ofp,"	   x2=\"750\"\n");
	fprintf(ofp,"	   y1=\"-288.6751346\"\n");
	fprintf(ofp,"	   x1=\"500\" />\n");
	fprintf(ofp,"	<text\n");
	fprintf(ofp,"	   x=\"440\"\n");
	fprintf(ofp,"	   y=\"-500\"\n");
	fprintf(ofp,"	   id=\"up_2\">%.1f%%</text>\n", (double)countarr[Maxspc][LM_AR1]*100.0/Numquartets);
	fprintf(ofp,"	<text\n");
	fprintf(ofp,"	   x=\"250\"\n");
	fprintf(ofp,"	   y=\"-150\"\n");
	fprintf(ofp,"	   id=\"down_left_2\">%.1f%%</text>\n", (double)countarr[Maxspc][LM_AR3]*100.0/Numquartets);
	fprintf(ofp,"	<text\n");
	fprintf(ofp,"	   x=\"630\"\n");
	fprintf(ofp,"	   y=\"-150\"\n");
	fprintf(ofp,"	   id=\"down_right_2\">%.1f%%</text>\n", (double)countarr[Maxspc][LM_AR2]*100.0/Numquartets);
	fprintf(ofp,"  </g>\n");
	/* end triangle 2 (bottom left) */

	/* triangle 3 (bottom right) */
	fprintf(ofp,"  <g id=\"fig3\" transform=\"translate(550,1000)\">\n");
	fprintf(ofp,"	<polygon points=\"0.0,-0.0 1000.0,-0.0 500.0,-866.0254038\" />\n");
	fprintf(ofp,"	<polygon id=\"triangle3b\" points=\"250,-144.3375673 750,-144.3375673 500,-577.3502692\" />\n");
	fprintf(ofp,"	<line\n");
	fprintf(ofp,"	   id=\"line3-1\"\n");
	fprintf(ofp,"	   x1=\"125\"\n");
	fprintf(ofp,"	   y1=\"-216.5063509\"\n");
	fprintf(ofp,"	   x2=\"250\"\n");
	fprintf(ofp,"	   y2=\"-144.3375673\" />\n");
	fprintf(ofp,"	<line\n");
	fprintf(ofp,"	   id=\"line3-2\"\n");
	fprintf(ofp,"	   x1=\"375\"\n");
	fprintf(ofp,"	   y1=\"-649.5190528\"\n");
	fprintf(ofp,"	   x2=\"500\"\n");
	fprintf(ofp,"	   y2=\"-577.3502692\" />\n");
	fprintf(ofp,"	<line\n");
	fprintf(ofp,"	   id=\"line3-3\"\n");
	fprintf(ofp,"	   x1=\"625\"\n");
	fprintf(ofp,"	   y1=\"-649.5190528\"\n");
	fprintf(ofp,"	   x2=\"500\"\n");
	fprintf(ofp,"	   y2=\"-577.3502692\" />\n");
	fprintf(ofp,"	<line\n");
	fprintf(ofp,"	   id=\"line3-4\"\n");
	fprintf(ofp,"	   x1=\"875\"\n");
	fprintf(ofp,"	   y1=\"-216.5063509\"\n");
	fprintf(ofp,"	   x2=\"750\"\n");
	fprintf(ofp,"	   y2=\"-144.3375673\" />\n");
	fprintf(ofp,"	<line\n");
	fprintf(ofp,"	   id=\"line3-5\"\n");
	fprintf(ofp,"	   x1=\"750\"\n");
	fprintf(ofp,"	   y1=\"-0.0\"\n");
	fprintf(ofp,"	   x2=\"750\"\n");
	fprintf(ofp,"	   y2=\"-144.3375673\" />\n");
	fprintf(ofp,"	<line\n");
	fprintf(ofp,"	   id=\"line3-6\"\n");
	fprintf(ofp,"	   x1=\"250\"\n");
	fprintf(ofp,"	   y1=\"-0.0\"\n");
	fprintf(ofp,"	   x2=\"250\"\n");
	fprintf(ofp,"	   y2=\"-144.3375673\" />\n");

	/* number of resolved quartets, top */
	fprintf(ofp,"	<text\n");
	fprintf(ofp,"	   x=\"500\"\n");
	fprintf(ofp,"	   y=\"-660\"\n");
	fprintf(ofp,"	   text-anchor=\"middle\"\n");
	fprintf(ofp,"	   id=\"up_3\">%.1f%%</text>\n", (double)countarr[Maxspc][LM_REG1]*100.0/Numquartets);

	/* number of resolved quartets, bottom left */
	fprintf(ofp,"	<text\n");
	fprintf(ofp,"	   y=\"-50\"\n");
	fprintf(ofp,"	   x=\"70\"\n");
	fprintf(ofp,"	   id=\"down_left_3\">%.1f%%</text>\n", (double)countarr[Maxspc][LM_REG3]*100.0/Numquartets);

	/* number of resolved quartets, bottom right */
	fprintf(ofp,"	<text\n");
	fprintf(ofp,"	   y=\"-50\"\n");
	fprintf(ofp,"	   x=\"770\"\n");
	fprintf(ofp,"	   id=\"down_right_3\">%.1f%%</text>\n", (double)countarr[Maxspc][LM_REG2]*100.0/Numquartets);

	/* number of partly resolved quartets, bottom */
	fprintf(ofp,"	<text\n");
	fprintf(ofp,"	   x=\"500\"\n");
	fprintf(ofp,"	   y=\"-50\"\n");
	fprintf(ofp,"	   text-anchor=\"middle\"\n");
	fprintf(ofp,"	   id=\"down_side_3\">%.1f%%</text>\n", (double)countarr[Maxspc][LM_REG5]*100.0/Numquartets);

	/* number of unresolved quartets, center */
	fprintf(ofp,"	<text\n");
	fprintf(ofp,"	   x=\"500\"\n");
	fprintf(ofp,"	   y=\"-280\"\n");
	fprintf(ofp,"	   text-anchor=\"middle\"\n");
	fprintf(ofp,"	   id=\"center_3\">%.1f%%</text>\n", (double)countarr[Maxspc][LM_REG7]*100.0/Numquartets);

	/* number of partly resolved quartets, top right */
	/* fprintf(ofp,"<circle cx=\"685.0\" cy=\"-390.8439\" r=\"20\" />\n"); */ /* ro */
	fprintf(ofp,"	<text\n");
	fprintf(ofp,"	   x=\"685.0\"\n");
	fprintf(ofp,"	   y=\"-390.8439\"\n");
	fprintf(ofp,"	   text-anchor=\"middle\"\n");
	fprintf(ofp,"	   transform=\"rotate(60,665.0,-380.8439)\"\n");
	fprintf(ofp,"	   id=\"right_side_3\">%.1f%%</text>\n", (double)countarr[Maxspc][LM_REG4]*100.0/Numquartets);

	/* number of partly resolved quartets, top left */
	/* fprintf(ofp,"<circle cx=\"315.0\" cy=\"-390.8439\" r=\"20\" />\n"); */  /* lo */
	fprintf(ofp,"	<text\n");
	fprintf(ofp,"	   x=\"315.0\"\n");
	fprintf(ofp,"	   y=\"-390.8439\"\n");
	fprintf(ofp,"	   text-anchor=\"middle\"\n");
	fprintf(ofp,"	   transform=\"rotate(-60,335.0,-380.8439)\"\n");
	fprintf(ofp,"	   id=\"left_side_3\">%.1f%%</text>\n", (double)countarr[Maxspc][LM_REG6]*100.0/Numquartets);

	fprintf(ofp,"  </g>\n");
	/* end triangle 3 (bottom right) */

	fprintf(ofp,"</g></g>\n");
	fprintf(ofp,"</svg>\n");
} /* finishsvg */

/* end - Likelihood mapping to SVG file  */


/***********************************
*  Likelihood mapping to EPS file  *
***********************************/

/* first lines of EPSF likelihood mapping file */
void initeps(FILE *ofp)
{
	fprintf(ofp, "%%!PS-Adobe-3.0 EPSF-3.0\n");
	fprintf(ofp, "%%%%BoundingBox: 60 210 550 650\n");
	fprintf(ofp, "%%%%Pages: 1\n");
#	ifndef ALPHA
		fprintf(ofp, "%%%%Creator: %s (version %s)\n", PACKAGE, VERSION);
#	else
		fprintf(ofp, "%%%%Creator: %s (version %s%s)\n", PACKAGE, VERSION, ALPHA);
#	endif
	fprintf(ofp, "%%%%Title: Likelihood Mapping Analysis\n");
	fprintf(ofp, "%%%%CreationDate: %s", asctime(localtime(&Starttime)) );
	fprintf(ofp, "%%%%DocumentFonts: Helvetica\n");
	fprintf(ofp, "%%%%DocumentNeededFonts: Helvetica\n");
	fprintf(ofp, "%%%%EndComments\n");
	fprintf(ofp, "%% use inch as unit\n");
	fprintf(ofp, "/inch {72 mul} def\n");
	fprintf(ofp, "%% triangle side length (3 inch)\n");
	fprintf(ofp, "/tl {3 inch mul} def\n");
	fprintf(ofp, "%% plot one dot (x-y coordinates on stack)\n");
	fprintf(ofp, "/dot {\n");
	fprintf(ofp, "newpath\n");
	fprintf(ofp, "0.002 tl 0 360 arc  %% radius is 0.002 of the triangle length\n");
	fprintf(ofp, "closepath\n");
	fprintf(ofp, "fill\n");
	fprintf(ofp, "} def\n");

	/* PS definition of a flush right print */
	fprintf(ofp, "\n%% flush right show\n");
	fprintf(ofp, "/centershow {\n");
	fprintf(ofp, "   dup stringwidth pop  %% get length of string\n");
	fprintf(ofp, "   neg 0 rmoveto        %% move width to left\n");
	fprintf(ofp, "   show\n");
	fprintf(ofp, "} def\n");
	fprintf(ofp, "\n%% centered show\n");

	/* PS definition of a centered print */
	fprintf(ofp, "/centershow {\n");
	fprintf(ofp, "   dup stringwidth pop %% get length of string\n");
	fprintf(ofp, "   -2 div              %% devide length by -2\n");
	fprintf(ofp, "   0 rmoveto           %% move half width to left\n");
	fprintf(ofp, "   show\n");
	fprintf(ofp, "} def\n");


	fprintf(ofp, "%% preamble\n");
	fprintf(ofp, "/Helvetica findfont\n");
	fprintf(ofp, "12 scalefont\n");
	fprintf(ofp, "setfont\n");
	fprintf(ofp, "%% 0/0 for triangle of triangles\n");
	fprintf(ofp, "0.9 inch 3 inch translate\n");
	fprintf(ofp, "%% first triangle (the one with dots)\n");
	fprintf(ofp, "0.6 tl 1.2 tl 0.8660254038 mul translate\n");
	fprintf(ofp, "newpath\n");
	fprintf(ofp, " 0.0 tl 0.0 tl moveto\n");
	fprintf(ofp, " 1.0 tl 0.0 tl lineto\n");
	fprintf(ofp, " 0.5 tl 0.8660254038 tl lineto\n");
	fprintf(ofp, "closepath\n");
	fprintf(ofp, "stroke\n");

	if (numclust == 4) { /* four cluster analysis */
		fprintf(ofp, "%% label corners\n");
		fprintf(ofp, "0.5 tl 0.9 tl moveto\n"); /* old: 0.375 0.9 */
		fprintf(ofp, "((a,b)-(c,d)) centershow %% CHANGE HERE IF NECESSARY\n");
		fprintf(ofp, "-0.045 tl -0.08 tl moveto\n"); /* old: -0.16 -0.08 */
		fprintf(ofp, "((a,d)-(b,c)) centershow %% CHANGE HERE IF NECESSARY\n");
		fprintf(ofp, "1.045 tl -0.08 tl moveto\n"); /* old: -0.92 -0.08 */
		fprintf(ofp, "((a,c)-(b,d)) centershow %% CHANGE HERE IF NECESSARY\n");
	}
	if (numclust == 3) { /* three cluster analysis */
		fprintf(ofp, "%% label corners\n");
		fprintf(ofp, "0.5 tl 0.9 tl moveto\n"); /* old: 0.375 0.9 */
		fprintf(ofp, "((a,b)-(c,c)) centershow %% CHANGE HERE IF NECESSARY\n");
		fprintf(ofp, "-0.045 tl -0.08 tl moveto\n"); /* old: -0.16 -0.08 */
		fprintf(ofp, "((a,c)-(b,c)) centershow %% CHANGE HERE IF NECESSARY\n");
		fprintf(ofp, "1.045 tl -0.08 tl moveto\n"); /* old: -0.92 -0.08 */
		fprintf(ofp, "((a,c)-(b,c)) centershow %% CHANGE HERE IF NECESSARY\n");
	}
	if (numclust == 2) { /* two cluster analysis */
		fprintf(ofp, "%% label corners\n");
		fprintf(ofp, "0.5 tl 0.9 tl moveto\n"); /* old: 0.375 0.9 */
		fprintf(ofp, "((a,a)-(b,b)) centershow %% CHANGE HERE IF NECESSARY\n");
		fprintf(ofp, "-0.045 tl -0.08 tl moveto\n"); /* old: -0.16 -0.08 */
		fprintf(ofp, "((a,b)-(a,b)) centershow %% CHANGE HERE IF NECESSARY\n");
		fprintf(ofp, "1.045 tl -0.08 tl moveto\n"); /* old: -0.92 -0.08 */
		fprintf(ofp, "((a,b)-(a,b)) centershow %% CHANGE HERE IF NECESSARY\n");
	}

} /* initeps */

/* plot one point of likelihood mapping analysis */
void plotlmpoint(FILE *epsofp, FILE *svgofp, double w1, double w2)
{
	if (lmapeps_optn) {
		fprintf(epsofp,"%.10f tl %.10f tl dot\n",
			0.5*w1 + w2, w1*0.8660254038);
	}
	if (lmapsvg_optn) {
		//fprintf(svgofp,"    <use x=\"%.10f\" y=\"%.10f\" xlink:href=\"#result\" />\n", (0.5*w1 + w2), -(w1*0.8660254038));
		fprintf(svgofp,"    <circle cx=\"%.10f\" cy=\"%.10f\" r=\"2\" />\n", 
			(0.5*w1 + w2)*1000, -(w1*866.0254038));
	}
} /* plotlmpoint */

/* plot one point of likelihood mapping analysis */
void plotlmpointcolor(FILE *epsofp, FILE *svgofp, double w1, double w2, int red, int green, int blue)
{
	if (lmapeps_optn) {
		fprintf(epsofp,"currentrgbcolor %d %d %d setrgbcolor\n", red, green, blue);
		fprintf(epsofp,"%.10f tl %.10f tl dot\n",
			0.5*w1 + w2, w1*0.8660254038);
		fprintf(epsofp,"setrgbcolor\n");
	}
	if (lmapsvg_optn) {
/*
	stijn imbrechts:
		Adding colour to elements is pretty easy, if you are familiar with
		CSS, it works almost exactly the same.
		The dots are represented by a <circle> element, if you want all of
		them to be, for example, red, add this to the <style> area:
			circle{ fill: red; stroke: red }
		
		If you just want a certain group of dots coloured, you can group them
		by adding a "class"-attribute like this:
			<circle cx="500" cy="100" r="2" class="reddot" />
		And add the following rule to the <style> area:
			circle.reddot{ fill: red; stroke: red; }
		Only the circles who belong to the "reddot" class will turn red 

		you can use rgb values as well: fill: rgb(255,0,0);

*/
		fprintf(svgofp,"    <circle cx=\"%.10f\" cy=\"%.10f\" r=\"2\" ", 
			(0.5*w1 + w2)*1000, -(w1*866.0254038));
		fprintf(svgofp,"fill=\"rgb(%d%%, %d%%, %d%%)\" />\n", (int)(100*red), (int)(100*green), (int)(100*blue));
	}
} /* plotlmpointcolor */

/* last lines of EPSF likelihood mapping file */
void finisheps(FILE *ofp, uli **countarr)
{
	fprintf(ofp, "stroke\n");
	fprintf(ofp, "%% second triangle (the one with 3 basins)\n");
	fprintf(ofp, "/secondtriangle {\n");
	fprintf(ofp, "newpath\n");
	fprintf(ofp, " 0.0 tl 0.0 tl moveto\n");
	fprintf(ofp, " 1.0 tl 0.0 tl lineto\n");
	fprintf(ofp, " 0.5 tl 0.8660254038 tl lineto\n");
	fprintf(ofp, "closepath\n");
	fprintf(ofp, "stroke\n");
	fprintf(ofp, "newpath\n");
	fprintf(ofp, " 0.50 tl 0.2886751346 tl moveto\n");
	fprintf(ofp, " 0.50 tl 0.0000000000 tl lineto\n");
	fprintf(ofp, "stroke\n");
	fprintf(ofp, "newpath\n");
	fprintf(ofp, " 0.50 tl 0.2886751346 tl moveto\n");
	fprintf(ofp, " 0.25 tl 0.4330127019 tl lineto\n");
	fprintf(ofp, "stroke\n");
	fprintf(ofp, "newpath\n");
	fprintf(ofp, " 0.50 tl 0.2886751346 tl moveto\n");
	fprintf(ofp, " 0.75 tl 0.4330127019 tl lineto\n");
	fprintf(ofp, "stroke\n");
	fprintf(ofp, "0.44 tl 0.5 tl moveto %% up\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) countarr[Maxspc][LM_AR1]*100.0/Numquartets);
	fprintf(ofp, "0.25 tl 0.15 tl moveto %% down left\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) countarr[Maxspc][LM_AR3]*100.0/Numquartets);
	fprintf(ofp, "0.63 tl 0.15 tl moveto %% down right\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) countarr[Maxspc][LM_AR2]*100.0/Numquartets);
#if 0
	fprintf(ofp, "0.44 tl 0.5 tl moveto %% up\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) ar1*100.0/Numquartets);
	fprintf(ofp, "0.25 tl 0.15 tl moveto %% down left\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) ar3*100.0/Numquartets);
	fprintf(ofp, "0.63 tl 0.15 tl moveto %% down right\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) ar2*100.0/Numquartets);
#endif
	fprintf(ofp, "} def\n");
	fprintf(ofp, "%% third triangle (the one with 7 basins)\n");
	fprintf(ofp, "/thirdtriangle {\n");
	fprintf(ofp, "newpath\n");
	fprintf(ofp, " 0.0 tl 0.0 tl moveto\n");
	fprintf(ofp, " 1.0 tl 0.0 tl lineto\n");
	fprintf(ofp, " 0.5 tl 0.8660254038 tl lineto\n");
	fprintf(ofp, "closepath\n");
	fprintf(ofp, "stroke\n");
	fprintf(ofp, "newpath\n");
	fprintf(ofp, " 0.25 tl 0.1443375673 tl moveto\n");
	fprintf(ofp, " 0.75 tl 0.1443375673 tl lineto\n");
	fprintf(ofp, " 0.50 tl 0.5773502692 tl lineto\n");
	fprintf(ofp, "closepath\n");
	fprintf(ofp, "stroke\n");
	fprintf(ofp, "newpath\n");
	fprintf(ofp, " 0.125 tl 0.2165063509 tl moveto\n");
	fprintf(ofp, " 0.250 tl 0.1443375673 tl lineto\n");
	fprintf(ofp, "stroke\n");
	fprintf(ofp, "newpath\n");
	fprintf(ofp, " 0.375 tl 0.6495190528 tl moveto\n");
	fprintf(ofp, " 0.500 tl 0.5773502692 tl lineto\n");
	fprintf(ofp, "stroke\n");
	fprintf(ofp, "newpath\n");
	fprintf(ofp, " 0.625 tl 0.6495190528 tl moveto\n");
	fprintf(ofp, " 0.500 tl 0.5773502692 tl lineto\n");
	fprintf(ofp, "stroke\n");
	fprintf(ofp, "newpath\n");
	fprintf(ofp, " 0.875 tl 0.2165063509 tl moveto\n");
	fprintf(ofp, " 0.750 tl 0.1443375673 tl lineto\n");
	fprintf(ofp, "stroke\n");
	fprintf(ofp, "newpath\n");
	fprintf(ofp, " 0.750 tl 0.00 tl moveto\n");
	fprintf(ofp, " 0.750 tl 0.1443375673 tl lineto\n");
	fprintf(ofp, "stroke\n");
	fprintf(ofp, "newpath\n");
	fprintf(ofp, " 0.250 tl 0.00 tl moveto\n");
	fprintf(ofp, " 0.250 tl 0.1443375673 tl lineto\n");
	fprintf(ofp, "stroke\n");
#if 0
	fprintf(ofp, "0.42 tl 0.66 tl moveto %% up\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) reg1*100.0/Numquartets);
	fprintf(ofp, "0.07 tl 0.05 tl moveto %% down left\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) reg3*100.0/Numquartets);
	fprintf(ofp, "0.77 tl 0.05 tl moveto %% down right\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) reg2*100.0/Numquartets);
	fprintf(ofp, "0.43 tl 0.05 tl moveto %% down side\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) reg5*100.0/Numquartets);
	fprintf(ofp, "0.43 tl 0.28 tl moveto %% center\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) reg7*100.0/Numquartets);
	fprintf(ofp, "gsave\n");
	fprintf(ofp, "-60 rotate\n");
	fprintf(ofp, "-0.07 tl 0.77 tl moveto %% right side\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) reg4*100.0/Numquartets);
	fprintf(ofp, "grestore\n");
	fprintf(ofp, "gsave\n");
	fprintf(ofp, "60 rotate\n");
	fprintf(ofp, "0.4 tl -0.09 tl moveto %% left side\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) reg6*100.0/Numquartets);
#endif
	/* resolved quartets, top */
	fprintf(ofp, "0.42 tl 0.66 tl moveto %% up\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) countarr[Maxspc][LM_REG1]*100.0/Numquartets);
	/* resolved quartets, bottom left */
	fprintf(ofp, "0.07 tl 0.05 tl moveto %% down left\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) countarr[Maxspc][LM_REG3]*100.0/Numquartets);
	/* resolved quartets, bottom right */
	fprintf(ofp, "0.77 tl 0.05 tl moveto %% down right\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) countarr[Maxspc][LM_REG2]*100.0/Numquartets);
	/* partly resolved quartets, bottom */
	fprintf(ofp, "0.43 tl 0.05 tl moveto %% down side\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) countarr[Maxspc][LM_REG5]*100.0/Numquartets);
	/* unresolved quartets */
	fprintf(ofp, "0.43 tl 0.28 tl moveto %% center\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) countarr[Maxspc][LM_REG7]*100.0/Numquartets);
	/* partly resolved quartets, top right */
	fprintf(ofp, "gsave\n");
	fprintf(ofp, "-60 rotate\n");
	fprintf(ofp, "-0.07 tl 0.77 tl moveto %% right side\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) countarr[Maxspc][LM_REG4]*100.0/Numquartets);
	fprintf(ofp, "grestore\n");
	/* partly resolved quartets, top left */
	fprintf(ofp, "gsave\n");
	fprintf(ofp, "60 rotate\n");
	fprintf(ofp, "0.4 tl -0.09 tl moveto %% left side\n");
	fprintf(ofp, "(%.1f%%) show\n", (double) countarr[Maxspc][LM_REG6]*100.0/Numquartets);
	fprintf(ofp, "grestore\n");
	fprintf(ofp, "} def\n");
	fprintf(ofp, "%% print the other two triangles\n");
	fprintf(ofp, "-0.6 tl -1.2 tl 0.8660254038 mul translate\n");
	fprintf(ofp, "secondtriangle\n");
	fprintf(ofp, "1.2 tl 0 translate\n");
	fprintf(ofp, "thirdtriangle\n");	
	fprintf(ofp, "showpage\n");
	fprintf(ofp, "%%%%EOF\n");
} /* finisheps */

/*  Likelihood mapping to EPS file  */



/* switching on different color for each simplex area */
#define COL_TEST
#undef COL_TEST

/* computes LM point from the three log-likelihood values,
   plots the point, and does some statistics */
/*
			&reg1, &reg2, &reg3, &reg4, &reg5, &reg6, &reg7, 
			&ar1, &ar2, &ar3, &reg1l, &reg1r, &reg2u, &reg2d, &reg3u, &reg3d, 
			&reg4u, &reg4d, &reg5l, &reg5r, &reg6u, &reg6d, 
			&ar, &reg, 
			t1, t2, t3, t4, countarr, 
*/
/* input: log-likelihoods=b1/b2/b3, internal quartet edge length=bl1/bl2/bl3 */
/*        min edgelen=minlen, max edgelen=maxlen, how to color=coltype */
void makelmpoint(
	FILE *fpeps, 				/* output file pointer */
	FILE *fpsvg, 				/* output file pointer */
	double  b1, 				/* log-likelihood: ab|cd */
	double  b2, 				/* log-likelihood: ac|bd */
	double  b3, 				/* log-likelihood: ad|bc */
#if 0
	uli *reg1, uli *reg2, uli *reg3, 	/* simplex reagions for counting */
	uli *reg4, uli *reg5, uli *reg6, 
	uli *reg7, 
	uli *ar1, uli *ar2, uli *ar3, 
	uli *reg1l, uli *reg1r, 
	uli *reg2u, uli *reg2d, 
	uli *reg3u, uli *reg3d, 
	uli *reg4u, uli *reg4d, 
	uli *reg5l, uli *reg5r, 
	uli *reg6u, uli *reg6d,
	int *ar, int *reg, 
#endif
	int t1, int t2, int t3, int t4,		/* four taxa in the quartet */
	uli **countarr,				/* taxon-specific  */
	double  bl1, 				/* internal branchlength: ab|cd */
	double  bl2, 				/* internal branchlength: ac|bd */
	double  bl3, 				/* internal branchlength: ad|bc */
	double  minlen, 			/* lower branch-length bound */
	double  maxlen, 			/* upper branch-length bound */
	int     coltype				/* color to plot points on the branch-length bound */
)
{
	double w1, w2, w3, temp;
	unsigned char qpbranching;
	double temp1, temp2, temp3, onethird;
	double templog;
	unsigned char discreteweight[3], treebits[3];
	int nummin, nummax;
	
	onethird = 1.0/3.0;
	treebits[0] = (unsigned char) 1;
	treebits[1] = (unsigned char) 2;
	treebits[2] = (unsigned char) 4;

	/* sort in descending order */
	qweight[0] = b1;
	qweight[1] = b2;
	qweight[2] = b3;
	sort3doubles(qweight, qworder);

	/* compute Bayesian weights */
	templog = qweight[qworder[1]]-qweight[qworder[0]];
	if(templog < -TP_MAX_EXP_DIFF)	/* possible, since 1.0+exp(>36) == 1.0 */
	   qweight[qworder[1]] = 0.0;
	else
	   qweight[qworder[1]] = exp(templog);

        templog = qweight[qworder[2]]-qweight[qworder[0]];
	if(templog < -TP_MAX_EXP_DIFF)	/* possible, since 1.0+exp(>36) == 1.0 */
	   qweight[qworder[2]] = 0.0;
	else
	   qweight[qworder[2]] = exp(templog);

	qweight[qworder[0]] = 1.0;

	temp = qweight[0] + qweight[1] + qweight[2];
	qweight[0] = qweight[0]/temp;
	qweight[1] = qweight[1]/temp;
	qweight[2] = qweight[2]/temp;

	/* plot one point in likelihood mapping triangle */
	w1 = qweight[0];
	w2 = qweight[1];
	w3 = qweight[2];

#if 0
#ifndef COL_TEST
	plotlmpoint(fpeps, fpsvg, w1, w2);
	/* plotlmpointcolor(fpeps, fpsvg, w1, w2, red, green, blue); */
#endif
#endif

#if 0
	/* check areas 1,2,3 */	
	if (treebits[qworder[0]] == 1) ar1++;
	else if (treebits[qworder[0]] == 2) ar2++;
	else ar3++;
#endif

	/* check areas 1,2,3 */
	if (treebits[qworder[0]] == 1) {
		countarr[Maxspc][LM_AR1]++;
		countarr[t1][LM_AR1]++;
		countarr[t2][LM_AR1]++;
		countarr[t3][LM_AR1]++;
		countarr[t4][LM_AR1]++;
	} else {
		if (treebits[qworder[0]] == 2) {
			countarr[Maxspc][LM_AR2]++;
			countarr[t1][LM_AR2]++;
			countarr[t2][LM_AR2]++;
			countarr[t3][LM_AR2]++;
			countarr[t4][LM_AR2]++;
		} else {
			countarr[Maxspc][LM_AR3]++;
			countarr[t1][LM_AR3]++;
			countarr[t2][LM_AR3]++;
			countarr[t3][LM_AR3]++;
			countarr[t4][LM_AR3]++;
		}
	}

	/* check out regions 1,2,3,4,5,6,7 */

	/* 100 distribution */
	temp1 = 1.0 - qweight[qworder[0]];
	sqdiff[0] = temp1*temp1 +
		qweight[qworder[1]]*qweight[qworder[1]] +
		qweight[qworder[2]]*qweight[qworder[2]];
	discreteweight[0] = treebits[qworder[0]];

	/* 110 distribution */
	temp1 = 0.5 - qweight[qworder[0]];
	temp2 = 0.5 - qweight[qworder[1]];
	sqdiff[1] = temp1*temp1 + temp2*temp2 +
		qweight[qworder[2]]*qweight[qworder[2]];
	discreteweight[1] = treebits[qworder[0]] + treebits[qworder[1]];

	/* 111 distribution */
	temp1 = onethird - qweight[qworder[0]];
	temp2 = onethird - qweight[qworder[1]];
	temp3 = onethird - qweight[qworder[2]];
	sqdiff[2] = temp1 * temp1 + temp2 * temp2 + temp3 * temp3;
	discreteweight[2] = (unsigned char) 7;

	/* sort in descending order */
	sort3doubles(sqdiff, sqorder);
			
	qpbranching = (unsigned char) discreteweight[sqorder[2]];
							
/*
                   (a,b)-(c,d)   => numclust == 4
                   (a,b)-(c,c)   => numclust == 3
                   (a,a)-(b,b)   => numclust == 2

                     1l/\1r
                      /  \
                     /  1 \
                 6u / \  / \ 4u
                   /   \/   \
               6d /    /\    \ 4d
                 / 6  /  \  4 \
                /\   /  7 \   /\
             3u/  \ /______\ /  \2u
              / 3  |    5   |  2 \
             /_____|________|_____\
	        3d   5l  5r   2d
    (a,d)-(b,c)                  (a,c)-(b,d)   => numclust == 4
    (a,c)-(b,c)                  (a,c)-(b,c)   => numclust == 3
    (a,b)-(a,b)                  (a,b)-(a,b)   => numclust == 2

*/

	if (qpbranching == 1) {
		countarr[Maxspc][LM_REG1]++;
		countarr[t1][LM_REG1]++;
		countarr[t2][LM_REG1]++;
		countarr[t3][LM_REG1]++;
		countarr[t4][LM_REG1]++;
#if 0
		reg1++;
		if (w2 < w3) reg1l++;
		else reg1r++;
#endif
#		ifdef COL_TEST
			/* plotlmpoint(fpeps, fpsvg, w1, w2); */
			plotlmpointcolor(fpeps, fpsvg, w1, w2, 0, 0, 1);
#		endif
	
	}
	if (qpbranching == 2) {
		countarr[Maxspc][LM_REG2]++;
		countarr[t1][LM_REG2]++;
		countarr[t2][LM_REG2]++;
		countarr[t3][LM_REG2]++;
		countarr[t4][LM_REG2]++;
#if 0
		reg2++;
		if (w1 < w3) reg2d++;
		else reg2u++;
#endif
#		ifdef COL_TEST
			/* plotlmpoint(fpeps, fpsvg, w1, w2); */
			plotlmpointcolor(fpeps, fpsvg, w1, w2, 0, 1, 0);
#		endif
	}
	if (qpbranching == 4) {
		countarr[Maxspc][LM_REG3]++;
		countarr[t1][LM_REG3]++;
		countarr[t2][LM_REG3]++;
		countarr[t3][LM_REG3]++;
		countarr[t4][LM_REG3]++;
#if 0
		reg3++;
		if (w1 < w2) reg3d++;
		else reg3u++;
#endif
#		ifdef COL_TEST
			/* plotlmpoint(fpeps, fpsvg, w1, w2); */
			plotlmpointcolor(fpeps, fpsvg, w1, w2, 1, 0, 0);
#		endif
	}
	if (qpbranching == 3) {
		countarr[Maxspc][LM_REG4]++;
		countarr[t1][LM_REG4]++;
		countarr[t2][LM_REG4]++;
		countarr[t3][LM_REG4]++;
		countarr[t4][LM_REG4]++;
#if 0
		reg4++;
		if (w1 < w2) reg4d++;
		else reg4u++;
#endif
#		ifdef COL_TEST
			/* plotlmpoint(fpeps, fpsvg, w1, w2); */
			plotlmpointcolor(fpeps, fpsvg, w1, w2, 0, 1, 1);
#		endif
	}
	if (qpbranching == 6) {
		countarr[Maxspc][LM_REG5]++;
		countarr[t1][LM_REG5]++;
		countarr[t2][LM_REG5]++;
		countarr[t3][LM_REG5]++;
		countarr[t4][LM_REG5]++;
#if 0
		reg5++;
		if (w2 < w3) reg5l++;
		else reg5r++;
#endif
#		ifdef COL_TEST
			/* plotlmpoint(fpeps, fpsvg, w1, w2); */
			plotlmpointcolor(fpeps, fpsvg, w1, w2, 1, 1, 0);
#		endif
	}
	if (qpbranching == 5) {
		countarr[Maxspc][LM_REG6]++;
		countarr[t1][LM_REG6]++;
		countarr[t2][LM_REG6]++;
		countarr[t3][LM_REG6]++;
		countarr[t4][LM_REG6]++;
#if 0
		reg6++;
		if (w1 < w3) reg6d++;
		else reg6u++;
#endif
#		ifdef COL_TEST
			/* plotlmpoint(fpeps, fpsvg, w1, w2); */
			plotlmpointcolor(fpeps, fpsvg, w1, w2, 1, 0, 1);
#		endif
	}
	if (qpbranching == 7) {
		countarr[Maxspc][LM_REG7]++;
		countarr[t1][LM_REG7]++;
		countarr[t2][LM_REG7]++;
		countarr[t3][LM_REG7]++;
		countarr[t4][LM_REG7]++;
#if 0
		reg7++;
#endif
#		ifdef COL_TEST
			plotlmpoint(fpeps, fpsvg, w1, w2);
			/* plotlmpointcolor(fpeps, fpsvg, w1, w2, 1, 1, 1); */
#		endif
	}

	switch (coltype) {
		case LMAP_AREA:
			switch (qpbranching) {
				case 1: /* 001 */
					plotlmpointcolor(fpeps, fpsvg, w1, w2, 0, 0, 1);
					break;
				case 2: /* 010 */
					plotlmpointcolor(fpeps, fpsvg, w1, w2, 0, 1, 0);
					break;
				case 4: /* 100 */
					plotlmpointcolor(fpeps, fpsvg, w1, w2, 1, 0, 0);
					break;
				case 3: /* 011 */
					plotlmpointcolor(fpeps, fpsvg, w1, w2, 0, 1, 1);
					break;
				case 5: /* 101 */
					plotlmpointcolor(fpeps, fpsvg, w1, w2, 1, 0, 1);
					break;
				case 6: /* 110 */
					plotlmpointcolor(fpeps, fpsvg, w1, w2, 1, 1, 0);
					break;
				case 7: /* 111 */
					plotlmpoint(fpeps, fpsvg, w1, w2);
					break;
			}
			break;
		case LMAP_MINMAXLEN:
			nummin = nummax = 0;
			if (bl1 <= minlen) nummin++;
			if (bl2 <= minlen) nummin++;
			if (bl3 <= minlen) nummin++;
#if 0
			if (bl1 >= maxlen) nummax++;
			if (bl2 >= maxlen) nummax++;
			if (bl3 >= maxlen) nummax++;
#endif
			if (nummin == 2) {
				plotlmpointcolor(fpeps, fpsvg, w1, w2, 1, 0, 0);
			} else { 
				if (nummin == 1) {
					plotlmpointcolor(fpeps, fpsvg, w1, w2, 0, 0, 1);
				} else {
					plotlmpoint(fpeps, fpsvg, w1, w2);
				}
			}
			break;
		case LMAP_NORMAL:
		default:
			plotlmpoint(fpeps, fpsvg, w1, w2);
			break;
	}
} /* makelmpoint */

/****************************************/
/*  end of Likelihood mapping routines  */
/****************************************/



/********************************************************/

/* time stamp */
void timestamp(FILE* ofp)
{
	double timespan;
	double cpuspan;
	timespan = difftime(Stoptime, Starttime);
	cpuspan  = ((double) (Stopcpu - Startcpu) / CLOCKS_PER_SEC);
	fprintf(ofp, "\n\nTIME STAMP\n\n");
	fprintf(ofp, "Date and time: %s", asctime(localtime(&Starttime)) );
	fprintf(ofp, "Runtime (excl. input) : %.0f seconds (= %.1f minutes = %.1f hours)\n",
		timespan, timespan/60., timespan/3600.);
	fprintf(ofp, "Runtime (incl. input) : %.0f seconds (= %.1f minutes = %.1f hours)\n",
		fulltime, fulltime/60., fulltime/3600.);
#ifdef TIMEDEBUG
	fprintf(ofp, "CPU time (incl. input): %.0f seconds (= %.1f minutes = %.1f hours)\n\n",
		fullcpu, fullcpu/60., fullcpu/3600.);
#endif /* TIMEDEBUG */

} /* timestamp */

/* SONJA #include "sonja.c" */
/***************************************************************************/
/***                                                                     ***/
/***    Sonja's distance problem ;-)                                     ***/
/***                                                                     ***/
/***************************************************************************/
#ifdef SONJA
        /* routines to compute the distances in the tree */
        /* # include "sonja.c"                           */

/* collect distances from the subtree rooted by np */
void subtree2dist(Node   *np,           /* subtree root */
                  ivector nodefound,    /* leaves in this subtree */
                  dvector nodedist,     /* distances leaf <-> np */
                  dmatrix distmat,      /* dist matrix between leaves */
                  imatrix distdone)     /* done flags */
{
        int      n, m;
        ivector  foundbelow;
        Node    *tp;

        /* external node = leaf */
        if (np->isop == NULL) {
#               ifdef DEBUGTREEDIST
                   fprintf(stderr, "e%d: len=%.6f\n", np->number, np->length);
#               endif
                /* nodedist[np->number] = np->length; */
                nodefound[np->number]    = 1;
                return;
        } else { /* if not external node */
#               ifdef DEBUGTREEDIST
                   fprintf(stderr, "i%d: len=%.6f\n", np->number, np->length);
#               endif
                foundbelow = new_ivector(Maxspc);

                /* for every branch at the inner node */
                tp = np->isop;
                while (tp != np) {
                        for (n = 0; n < Maxspc; n++)
                          foundbelow[n] = 0;

                        subtree2dist(tp->kinp, foundbelow, nodedist, distmat, distdone);

                        for (n = 0; n < Maxspc; n++) {
                           if (foundbelow[n] == 1) {
#                             ifdef DEBUGTREEDIST
                                 fprintf(stderr, "  +++i%d: nd%d=%.5f+%.5f=%.5f\n", np->number, n, nodedist[n], tp->length, nodedist[n]+tp->length);
#                             endif
                              nodefound[n] = 1;
                              nodedist[n] += tp->length;
                           }
                        }
                        tp = tp->isop;
                } /* while tp != np */

                for (n = 0; n < Maxspc; n++) {
                   for (m = n+1; m < Maxspc; m++) {
                      if ((distdone[n][m]!=1) && (nodefound[n]==1) && (nodefound[m]==1)) {
                         distmat[n][m] = nodedist[n] + nodedist[m];
                         distmat[m][n] = distmat[n][m];
                         distdone[n][m] = 1;
                         distdone[m][n] = 1;
                      } /* if */
                   } /* for m */
                } /* for n */ 

                free (foundbelow);

        } /* if not external node */
}

/***************************************************************************/



/* collect all distances from the current tree */
void tree2dist(dmatrix distmat)
{
        ivector nodefound;
        imatrix distdone;
        dvector nodedist;
        int n, m;

        nodefound = new_ivector(Maxspc);
        distdone  = new_imatrix(Maxspc,Maxspc);
        nodedist  = new_dvector(Maxspc);

        for (n = 0; n < Maxspc; n++) {
           nodedist[n] = 0.0;
           nodefound[n] = 0;
           for (m = n+1; m < Maxspc; m++) {
              if (n==m) {
                 distmat[n][m]  = 0.0;
                 distdone[n][m] = 1;
              } else {
                 distmat[n][m]  = 0.0;
                 distmat[m][n]  = 0.0;
                 distdone[n][m] = 0;
                 distdone[m][n] = 0;
              }
           } /* for m */
        } /* for n */

        /* we are NOT on a leaf, because root -> collect  */
        subtree2dist(Ctree->ebrnchp[outgroup]->kinp, nodefound, nodedist, distmat, distdone);

        /* compute distances to the root */
        m = outgroup;
        for (n = 0; n < Maxspc; n++) {
           if ((distdone[n][m]!=1) && (nodefound[n]==1)) {
              distmat[n][m] = nodedist[n] + Ctree->ebrnchp[outgroup]->length;
              distmat[m][n] = distmat[n][m];
              distdone[n][m] = 1;
              distdone[m][n] = 1;
           } /* if */
        } /* for n */

        free(nodefound);
        free(distdone);
        free(nodedist);
}



#endif /* SONJA */
/***************************************************************************/
/* end of SONJA                                                            */
/***************************************************************************/

/* write output file */
void writeoutputfile(FILE *ofp, int part, int clockmode)
{
	int i, fail, df;
	uli li;
	uli sum;
#if 0
#endif
	uli res_all, partres_all, unres_all;
	uli res, partres, unres;
	double pval, delta;

   if ((part == WRITEPARAMS) || (part == WRITEALL)) {
#	ifndef ALPHA
		fprintf(ofp, "TREE-PUZZLE %s\n\n", VERSION);
#	else
		fprintf(ofp, "TREE-PUZZLE %s%s\n\n", VERSION, ALPHA);
#	endif

	fprintf(ofp, "Input file name: %s\n",INFILE);
	if (puzzlemode == USERTREE || puzzlemode == CONSENSUS) fprintf(ofp, "User tree file name: %s\n",INTREE);


	fprintf(ofp, "Type of analysis: ");
	switch(typ_optn) {
		case TREERECON_OPTN:	switch(puzzlemode) {
						case CONSENSUS:	fprintf(ofp, "consensus construction\n");
								break;
						case USERTREE:	fprintf(ofp, "user tree evaluation\n");
								break;
						default:	fprintf(ofp, "tree reconstruction\n");
								break;
					}
					break;
		case LIKMAPING_OPTN:	fprintf(ofp, "likelihood mapping\n");
					break;
	}

	fprintf(ofp, "Parameter estimation: ");
	if (approxp_optn) fprintf(ofp, "approximate (faster)\n");
	else fprintf(ofp, "accurate (slow)\n");
	if (!((puzzlemode == USERTREE || puzzlemode == CONSENSUS) && typ_optn == TREERECON_OPTN)) {
		fprintf(ofp, "Parameter estimation uses: ");
		if (qcalg_optn)
			fprintf(ofp, "quartet sampling (for substitution process) + NJ tree (for rate variation)\n");
		else
			fprintf(ofp, "neighbor-joining tree (for substitution process and rate variation)\n");
	} else {
		fprintf(ofp, "Parameter estimation uses: ");
		if (utree_optn)
			fprintf(ofp, "1st user tree (for substitution process and rate variation)\n");
		else if (qcalg_optn)
			fprintf(ofp, "quartet sampling (for substitution process) + NJ tree (for rate variation)\n");
		else
			fprintf(ofp, "neighbor-joining tree (for substitution process and rate variation)\n");
	}
	fprintf(ofp, "\nStandard errors (S.E.) are obtained by the curvature method.\n");
	fprintf(ofp, "The upper and lower bounds of an approximate 95%% confidence interval\n");
	fprintf(ofp, "for parameter or branch length x are x-1.96*S.E. and x+1.96*S.E.\n");
	fprintf(ofp, "\n\n");

	/***************************************************************************/
	/*  SEQUENCE ALIGNMENT                                                     */
	/***************************************************************************/

	fprintf(ofp, "SEQUENCE ALIGNMENT\n\n");
#ifndef USE_WINDOWS
	fprintf(ofp, "Input data: %d sequences with %d ", Maxspc, Maxsite);
#else
	fprintf(ofp, "Input data: %d sequences with %d ", Maxspc, alimaxsite);
#endif
	if (data_optn == AMINOACID)
		fprintf(ofp, "amino acid");
	else if (data_optn == NUCLEOTIDE && SH_optn)
#ifndef USE_WINDOWS
		fprintf(ofp, "doublet (%d nucleotide)", Maxsite*2);
#else
		fprintf(ofp, "doublet (%d nucleotide)", alimaxsite*2);
#endif
	else if (data_optn == NUCLEOTIDE && nuc_optn)
		fprintf(ofp, "nucleotide");
	else if (data_optn == BINARY)
		fprintf(ofp, "binary state");
	fprintf(ofp, " sites");
	if (data_optn == NUCLEOTIDE && (Maxseqc % 3) == 0  && !SH_optn) {
		if (codon_optn == 1) fprintf(ofp, " (1st codon positions)");
		if (codon_optn == 2) fprintf(ofp, " (2nd codon positions)");
		if (codon_optn == 3) fprintf(ofp, " (3rd codon positions)");
		if (codon_optn == 4) fprintf(ofp, " (1st and 2nd codon positions)");
	}
	if (data_optn == NUCLEOTIDE && SH_optn) {
		if (SHcodon)
			fprintf(ofp, " (1st and 2nd codon positions)");
		else
			fprintf(ofp, " (1st+2nd, 3rd+4th, etc. site)");
	}	
	fprintf(ofp, "\n");
	fprintf(ofp, "Number of constant sites: %d (= %.1f%% of all sites)\n",
		Numconst, 100.0*fracconst);
	fprintf(ofp, "\n");
	fprintf(ofp, "Number of site patterns: %d\n",
		Numptrn);
	fprintf(ofp, "Number of constant site patterns: %d (= %.1f%% of all site patterns)\n\n",
		Numconstpat, 100.0*fracconstpat);


	/* compute informative site statistics (overall and per site) */
	countinformativesites(&inform, &fullinform, &partinform, &noninform, &varnoninform, &constantgaps, &constant, &siteinform, &gapvec, &taxinform, &taxnoninform);

	if (savealiinfofile_optn) {
		openfiletowrite(&aliinfofp, ALIINFO, "Alignment information file", stdinput_fp);
	} else {
		aliinfofp=NULL;
	}
	if (savealiinfonumfile_optn) {
		openfiletowrite(&aliinfonumfp, ALIINFONUM, "Alignment information file (counts)", stdinput_fp);
	} else {
		aliinfonumfp=NULL;
	}
	if (savealiinfofile_optn || savealiinfonumfile_optn) {
		/* compute and save informative sites in sliding windows along the alignment */
#		if USE_RECDETEC
			writealiinformativesites(aliinfofp, aliinfonumfp, siteinform, gapvec, aliinfo_ss, aliinfo_ws);
#		else
			writealivisrecinformativesites(aliinfofp, aliinfonumfp, siteinform, gapvec, aliinfo_ss, aliinfo_ws);
#		endif
	}
	if (savealiinfofile_optn) fclose(aliinfofp);
	if (savealiinfonumfile_optn) fclose(aliinfonumfp);


	fprintf(ofp, "\nConcering parsimony informative sites there are:\n\n");

#if 0
fprintf(stderr, "TEST: %lu informative + %lu non-informative sites = %lu (= %lu maxsites?)\n",
		inform, noninform, inform+noninform, (long int)Maxsite);
#endif
	fprintf(ofp, "Number of parsimony informative sites: %lu (= %.1f%% of all sites)\n",
		inform, 100.0*((double)inform/Maxsite));
	fprintf(ofp, "  - fully informative sites:  %lu (= %.1f%% of all sites)\n",
		fullinform, 100.0*((double)fullinform/Maxsite));
	fprintf(ofp, "  - partly informative sites: %lu (= %.1f%% of all sites)\n",
		partinform, 100.0*((double)partinform/Maxsite));
	fprintf(ofp, "Number of parsimony uninformative sites: %lu (= %.1f%% of all sites)\n",
		noninform, 100.0*((double)noninform/Maxsite));
	fprintf(ofp, "  - variable, but uninformative sites: %lu (= %.1f%% of all sites)\n",
		varnoninform, 100.0*((double)varnoninform/Maxsite));
	fprintf(ofp, "  - completely constant sites: %lu (= %.1f%% of all sites)\n",
		constant, 100.0*((double)constant/Maxsite));
	fprintf(ofp, "  - constant sites (but with gaps/wildcards): %lu (= %.1f%% of all sites)\n",
		constantgaps, 100.0*((double)constantgaps/Maxsite));


	fprintf(ofp, "\n\nFor each sequence there are following numbers of parsimony (non-)informative site:\n\n");
	fprintf(ofp, "                    informative sites   non-informative sites\n");
	for (i = 0; i < Maxspc; i++) {
           fprintf(ofp, " %-3d ", i+1);
           fputid10(ofp, i);
           fprintf(ofp, "  ");
           fprintf(ofp, "%10lu (%6.2f%%)    %10lu (%6.2f%%)\n", 
		taxinform[i],    100.0*((double)taxinform[i]/Maxsite), 
		taxnoninform[i], 100.0*((double)taxnoninform[i]/Maxsite));
        }
        fprintf(ofp, "\nNote: partially informative sites are informative only for some sequences. Hence, the number of informative sites for each sequence can differ.\n\n\n");


	/***********/
	if (saverdstatsfile_optn) {
		openfiletowrite(&rdsfp, RDSTATS, "RecDetec Statistics file", stdinput_fp);
		/* openfiletoappend(&rdsfp, RDSTATS, "RecDetec Statistics file", stdinput_fp); */
		fprintf(rdsfp, "ALI sequences: %d\n", Maxspc);
		fprintf(rdsfp, "ALI sites: %d\n", Maxsite);
		fprintf(rdsfp, "ALI constant sites: %d (%.1f%%)\n",
			Numconst, 100.0*fracconst);
		fprintf(rdsfp, "ALI site patterns: %d\n",
			Numptrn);
		fprintf(rdsfp, "ALI constant site patterns: %d (%.1f%%)\n",
			Numconstpat, 100.0*fracconstpat);
		fprintf(rdsfp, "ALI informative sites: %lu (%.1f%%)\n",
			inform, 100.0*((double)inform/Maxsite));
		fprintf(rdsfp, "ALI   fully informative sites: %lu (%.1f%%)\n",
			fullinform, 100.0*((double)fullinform/Maxsite));
		fprintf(rdsfp, "ALI   partly informative sites: %lu (%.1f%%)\n",
			partinform, 100.0*((double)partinform/Maxsite));
		fprintf(rdsfp, "ALI non-informative sites: %lu (%.1f%%)\n",
			noninform, 100.0*((double)noninform/Maxsite));
		fprintf(rdsfp, "ALI   variable but uninformative sites: %lu (%.1f%%)\n",
			varnoninform, 100.0*((double)varnoninform/Maxsite));
		fprintf(rdsfp, "ALI   completely constant sites: %lu (%.1f%%)\n",
			constant, 100.0*((double)constant/Maxsite));
		fprintf(rdsfp, "ALI   constant sites (plus gaps/wildcards): %lu (%.1f%%)\n",
			constantgaps, 100.0*((double)constantgaps/Maxsite));
		fprintf(rdsfp, "\n");
		fprintf(rdsfp, "ALI TAX                    informative sites   non-informative sites\n");
		for (i = 0; i < Maxspc; i++) {
           		fprintf(rdsfp, "ALI TAX %-3d ", i+1);
           		fputid10(rdsfp, i);
           		fprintf(rdsfp, "  ");
           		fprintf(rdsfp, "%10lu (%6.2f%%)    %10lu (%6.2f%%)\n", 
				taxinform[i],    100.0*((double)taxinform[i]/Maxsite), 
				taxnoninform[i], 100.0*((double)taxnoninform[i]/Maxsite));
        	}
		fflush(rdsfp);
		fclose(rdsfp);
	} /* if saverdstatsfile_optn */

	free_ivector(siteinform);
	free_ulivector(taxnoninform);
	free_ulivector(taxinform);
	free_ulivector(gapvec);

	if (stopafteralistats_optn) {
		tp_exit(0, NULL, TRUE, __FILE__, __LINE__, exit_wait_optn);
	}

	/***************************************************************************/
	/*  SUBSTITUTION PROCESS                                                   */
	/***************************************************************************/

	fprintf(ofp, "SUBSTITUTION PROCESS\n\n");
	fprintf(ofp, "Model of substitution: ");
	if (data_optn == NUCLEOTIDE) { /* nucleotides */
		if (nuc_optn) {
			if(HKY_optn) fprintf(ofp, "HKY (Hasegawa et al. 1985)\n");	
			if(TN_optn)  fprintf(ofp, "TN (Tamura-Nei 1993)\n");
			if(GTR_optn) fprintf(ofp, "GTR (e.g. Lanave et al. 1980)\n");

			if((HKY_optn) || (TN_optn)) {
				fprintf(ofp, "Transition/transversion parameter");
				if (optim_optn)
					fprintf(ofp, " (estimated from data set)");
				fprintf(ofp, ": %.2f", TSparam);
				if (optim_optn)
					fprintf(ofp, " (S.E. %.2f)", tserr);
				fprintf(ofp, "\n");
			
				if (optim_optn && TSparam > MAXTS - 1.0)
					fprintf(ofp, "WARNING --- parameter estimate close to internal upper bound!\n");
				if (optim_optn && TSparam < MINTS + 0.1)
					fprintf(ofp, "WARNING --- parameter estimate close to internal lower bound!\n");		
			}
			
			if (TN_optn) {
				fprintf(ofp, "Y/R transition parameter");
				if (optim_optn)
					fprintf(ofp, " (estimated from data set)");
				fprintf(ofp, ": %.2f", YRparam);
				if (optim_optn)
					fprintf(ofp, " (S.E. %.2f)", yrerr);
				fprintf(ofp, "\n");
				
				if (optim_optn && YRparam > MAXYR - 0.5)
					fprintf(ofp, "WARNING --- parameter estimate close to internal upper bound!\n");
				if (optim_optn && YRparam < MINYR + 0.1)
					fprintf(ofp, "WARNING --- parameter estimate close to internal lower bound!\n");		
			}

			if (GTR_optn || print_GTR_optn) {
				if((HKY_optn) || (TN_optn)) fprintf(ofp, "\n");
				fprintf(ofp, "Rate matrix R (parameters %s):\n\n", GTR_optn ? "set by user" : "restricted to selected model");
				fprintf(ofp, " A-C rate: ");
				fprintf(ofp, "%.5f\n", GTR_ACrate);		
				fprintf(ofp, " A-G rate: ");
				fprintf(ofp, "%.5f\n", GTR_AGrate);		
				fprintf(ofp, " A-T rate: ");
				fprintf(ofp, "%.5f\n", GTR_ATrate);		
				fprintf(ofp, " C-G rate: ");
				fprintf(ofp, "%.5f\n", GTR_CGrate);		
				fprintf(ofp, " C-T rate: ");
				fprintf(ofp, "%.5f\n", GTR_CTrate);		
				fprintf(ofp, " G-T rate: ");
				fprintf(ofp, "%.5f\n", GTR_GTrate);		
				fprintf(ofp, "\n");
			}
		}
		if (SH_optn) {
			fprintf(ofp, "SH (Schoeniger-von Haeseler 1994)\n");
			fprintf(ofp, "Transition/transversion parameter");
			if (optim_optn) fprintf(ofp, " (estimated from data set)");
			fprintf(ofp, ": %.2f\n", TSparam);
			if (optim_optn)
				fprintf(ofp, " (S.E. %.2f)", tserr);
			fprintf(ofp, "\n");
						
			if (optim_optn && TSparam > MAXTS - 1.0)
				fprintf(ofp, "WARNING --- parameter estimate close to internal upper bound!\n");
			if (optim_optn && TSparam < MINTS + 0.1)
				fprintf(ofp, "WARNING --- parameter estimate close to internal lower bound!\n");		

		}	
	}
	if (data_optn == AMINOACID) { /* amino acids */
		if (Dayhf_optn) fprintf(ofp, "Dayhoff (Dayhoff et al. 1978)\n");	
		if (Jtt_optn) fprintf(ofp, "JTT (Jones et al. 1992)\n");
		if (mtrev_optn) fprintf(ofp, "mtREV24 (Adachi-Hasegawa 1996)\n");
		if (cprev_optn) fprintf(ofp, "cpREV45 (Adachi et al. 2000)\n");
		if (blosum62_optn) fprintf(ofp, "BLOSUM 62 (Henikoff-Henikoff 1992)\n");
		if (vtmv_optn) fprintf(ofp, "VT (Mueller-Vingron 2000)\n");
		if (wag_optn) fprintf(ofp, "WAG (Whelan-Goldman 2000)\n");
		/* if (poisson_optn) fprintf(STDOUT, "Poisson (JC model for proteins)\n"); */
		/* if (equalin_optn) fprintf(STDOUT, "Equalin (XXX, TODO)\n"); */
		/* if (mtmam_optn) fprintf(STDOUT, "mtMAM (XXX, TODO)\n"); */
		/* if (rtrev_optn) fprintf(STDOUT, "rtREV (XXX, TODO)\n"); */
	}
	if (data_optn == BINARY) { /* binary states */
		fprintf(ofp, "Two-state model (Felsenstein 1981)\n");
	}
	if (data_optn == AMINOACID)
			fprintf(ofp, "Amino acid ");
		else if (data_optn == NUCLEOTIDE && SH_optn)
			fprintf(ofp, "Doublet ");
		else if (data_optn == NUCLEOTIDE && nuc_optn)
			fprintf(ofp, "Nucleotide ");
		else if (data_optn == BINARY)
			fprintf(ofp, "Binary state ");
	fprintf(ofp, "frequencies (");
	if (Frequ_optn) fprintf(ofp, "estimated from data set");
	else fprintf(ofp, "user specified");
	if (data_optn == NUCLEOTIDE && SH_optn && sym_optn)
		fprintf(ofp, " and symmetrized");
	fprintf(ofp, "):\n\n");
	for (i = 0; i < gettpmradix(); i++)
		fprintf(ofp, " pi(%s) = %5.1f%%\n",
			int2code(i), Freqtpm[i]*100);
	if (data_optn == NUCLEOTIDE) {
		if (!GTR_optn) {
			fprintf(ofp, "\nExpected transition/transversion ratio: %.2f",
				tstvratio);
			if (tstvf84 == 0.0) fprintf(ofp, "\n");
			else fprintf(ofp, " (= F84 parameter)\n");
			fprintf(ofp, "Expected pyrimidine transition/purine transition");
			fprintf(ofp, " ratio: %.2f\n", yrtsratio);
			if (tstvf84 != 0.0 && TN_optn)
				fprintf(ofp,
					"This TN model is equivalent to a F84 model (Felsenstein 1984).\n");
		}
	}


	/***************************************************************************/
	/*  SEQUENCE COMPOSITION (SEQUENCES IN INPUT ORDER)                        */
	/***************************************************************************/

	fprintf(ofp, "\n\nAMBIGUOUS CHARACTERS IN THE SEQUENCE (SEQUENCES IN INPUT ORDER)\n\n");


        {
        double fract;
	int sumgapchar=0;
	int sumotherchar=0;

	fprintf(ofp, "                   gaps  wildcards        sum   %% sequence\n");
	for (i = 0; i < Maxspc; i++) {
           fprintf(ofp, " %-3d ", i+1);
           fputid10(ofp, i);
           fprintf(ofp, "  ");
#ifndef USE_WINDOWS
           fract = (Seqgapchar[i] + Seqotherchar[i]) / (double) Maxsite;
#else
           fract = (Seqgapchar[i] + Seqotherchar[i]) / (double) alimaxsite;
#endif
	   sumgapchar+=Seqgapchar[i];
	   sumotherchar+=Seqotherchar[i];
           fprintf(ofp, "%6d     %6d     %6d      %6.2f%%  %c\n", 
                         Seqgapchar[i], Seqotherchar[i], 
                         (Seqgapchar[i] + Seqotherchar[i]),
                         100.0 * fract, ((fract > 0.5) ? '!' : ' '));
        }
        fprintf(ofp, " -----------------------------------------------------------\n");
        fprintf(ofp, " Sum             ");
#ifndef USE_WINDOWS
        fract = (sumgapchar + sumotherchar) / (double) (Maxsite * Maxspc);
#else
        fract = (sumgapchar + sumotherchar) / (double) (alimaxsite * Maxspc);
#endif
        fprintf(ofp, "%6d     %6d     %6d      %6.2f%%  %c\n", 
                      sumgapchar, sumotherchar, 
                      (sumgapchar + sumotherchar),
                      100.0 * fract, ((fract > 0.5) ? '!' : ' '));
	fprintf(ofp, "\n\n");
	fprintf(ofp, "The table above shows the amount of gaps ('-') and other 'wildcard'\n");
#ifndef USE_WINDOWS
        fprintf(ofp, "characters ('X', '?', etc.) and their percentage of the %d columns\n", Maxsite);
#else
        fprintf(ofp, "characters ('X', '?', etc.) and their percentage of the %d columns\n", alimaxsite);
#endif
        fprintf(ofp, "in the alignment.\n");
        fprintf(ofp, "Sequences with more than 50%% ambiguous characters are marked with a '!' and \n");
        fprintf(ofp, "should be checked, whether they have sufficient overlap to other sequences.\n");
        fprintf(ofp, "Sequences with 100%% ambiguous characters do not hold any phylogenetic\n");
        fprintf(ofp, "information and had to be discarded from the analysis.\n\n");
        }


	/***************************************************************************/
	/*  SEQUENCE COMPOSITION (SEQUENCES IN INPUT ORDER)                        */
	/***************************************************************************/

	fprintf(ofp, "\n\nSEQUENCE COMPOSITION (SEQUENCES IN INPUT ORDER)\n\n");

	fail = FALSE;
	/* fprintf(ofp, "              5%% chi-square test  p-value\n"); */
	fprintf(ofp, "                  5%% chi-square test  p-value   chi2-value\n");
	for (i = 0; i < Maxspc; i++) {
		double chi2val;
		fprintf(ofp, " %-3d ", i+1);
		fputid10(ofp, i);
		pval = chi2test(Freqtpm, Basecomp[i], gettpmradix(), &chi2val, &chi2fail);
#if 0
		pval = homogentest(i);
		/* HAS ;-) */
		if (pval != chi2test(Freqtpm, Basecomp[i], gettpmradix(), &chi2val, &chi2fail))
			fprintf(stderr, "XXXXXXXXXXX: chi2 != chi2\n");
		else
			fprintf(stderr, "XXXXXXXXXXX: OK\n");
#endif

		if ( pval < 0.05 ) fprintf(ofp, "        failed       ");
		else               fprintf(ofp, "        passed       ");
		if (chi2fail) fail = TRUE;
		fprintf(ofp, "  %6.2f%%  ", pval*100.0);
		fprintf(ofp, "   (%.2f)  ", chi2val);
		fprintf(ofp, "\n");	

#if 0
		fprintf(stderr, "  %6.2f%%  ", pval*100.0);
		fprintf(stderr, "   (%.2f)  ", chi2val);
		fprintf(stderr, "\n");	
#endif
	}
	fprintf(ofp, "\n");
	fprintf(ofp, "The chi-square tests with %d degrees of freedom compares the\n", gettpmradix()-1);
	if (data_optn == AMINOACID)
		fprintf(ofp, "amino acid");
	else if (data_optn == NUCLEOTIDE && SH_optn)
		fprintf(ofp, "doublet");
	else if (data_optn == NUCLEOTIDE && nuc_optn)
		fprintf(ofp, "nucleotide");
	else if (data_optn == BINARY)
		fprintf(ofp, "binary state");
	fprintf(ofp," composition of each sequence to the frequency\n");
	fprintf(ofp, "distribution assumed in the maximum likelihood model.\n");	
	if (fail) {
		fprintf(ofp, "\nWARNING: Result of chi-square test may not be valid");
		fprintf(ofp, " because of\nsmall maximum likelihood frequencies and");
		fprintf(ofp, " short sequence length!\n");
	}

	/***************************************************************************/
	/*  IDENTICAL SEQUENCE                                                     */
	/***************************************************************************/

	fprintf(ofp, "\n\nIDENTICAL SEQUENCES\n\n");
	fprintf(ofp, "The sequences in each of the following groups are all identical. To speed\n");
	fprintf(ofp, "up computation please remove all but one of each group from the data set.\n\n");
	findidenticals(ofp);
	fprintf(ofp, "\n\nMAXIMUM LIKELIHOOD DISTANCES\n\n");
	fprintf(ofp, "Maximum likelihood distances are computed using the ");
	fprintf(ofp, "selected model of\nsubstitution and rate heterogeneity.\n\n");
	putdistance(ofp);
	{
	double avgdist, meandist, mindist, maxdist, stddevdist, vardist;
	avgdist = averagedist(Maxspc, Distanmat, &meandist, &mindist, &maxdist, &stddevdist, &vardist);
	fprintf(ofp, "\nAverage distance (over all possible pairs of sequences):  %.5f\n",
		meandist);
	fprintf(ofp, "                  minimum  : %.5f,  maximum  : %.5f\n", mindist, maxdist);
	fprintf(ofp, "                  variance : %.5f,  std.dev. : %.5f\n", vardist, stddevdist);
	}


	/***************************************************************************/
	/*  RATE HETEROGENEITY (PART 1)                                            */
	/***************************************************************************/

	fprintf(ofp, "\n\nRATE HETEROGENEITY\n\n");
	fprintf(ofp, "Model of rate heterogeneity: ");
	if (rhetmode == UNIFORMRATE) fprintf(ofp, "uniform rate\n");
	if (rhetmode == GAMMARATE  ) fprintf(ofp, "Gamma distributed rates\n");
	if (rhetmode == TWORATE    ) fprintf(ofp, "two rates (1 invariable + 1 variable)\n");
	if (rhetmode == MIXEDRATE  ) fprintf(ofp, "mixed (1 invariable + %d Gamma rates)\n", numcats);
	if (rhetmode == TWORATE || rhetmode == MIXEDRATE) {
		fprintf(ofp, "Fraction of invariable sites");
		if (fracinv_optim) fprintf(ofp, " (estimated from data set)");
		fprintf(ofp, ": %.2f", fracinv);
		if (fracinv_optim) fprintf(ofp, " (S.E. %.2f)", fierr);
		fprintf(ofp, "\n");
			
		if (fracinv_optim && fracinv > MAXFI - 0.05)
			fprintf(ofp, "WARNING --- parameter estimate close to internal upper bound!\n");
		
#ifndef USE_WINDOWS
		fprintf(ofp, "Number of invariable sites: %.0f\n", floor(fracinv*Maxsite));
#else
		fprintf(ofp, "Number of invariable sites: %.0f\n", floor(fracinv*alimaxsite));
#endif
	}
	if (rhetmode == GAMMARATE || rhetmode == MIXEDRATE) {
		fprintf(ofp, "Gamma distribution parameter alpha");
		if (grate_optim) fprintf(ofp, " (estimated from data set)");
		fprintf(ofp, ": %.2f", (1.0-Geta)/Geta);
		if (grate_optim) fprintf(ofp, " (S.E. %.2f)",
			geerr/(Geta*Geta)); /* first order approximation */
		fprintf(ofp, "\n");
		
		if (grate_optim && Geta > MAXGE - 0.02)
			fprintf(ofp, "WARNING --- parameter estimate close to internal upper bound!\n");
		if (grate_optim && Geta < MINGE + 0.01)
			fprintf(ofp, "WARNING --- parameter estimate close to internal lower bound!\n");		

		fprintf(ofp, "Number of Gamma rate categories: %d\n", numcats);
	}
	if (rhetmode == MIXEDRATE) {
		fprintf(ofp, "Total rate heterogeneity (invariable sites + Gamma model): ");
		fprintf(ofp, "%.2f", fracinv + Geta - fracinv*Geta);
		if (grate_optim && fracinv_optim)
			fprintf(ofp, " (S.E. %.2f)", geerr + fierr); /* first order approximation */
		else if (grate_optim && !fracinv_optim)
			fprintf(ofp, " (S.E. %.2f)", geerr);
		else if (!grate_optim && fracinv_optim)
			fprintf(ofp, " (S.E. %.2f)", fierr);
		fprintf(ofp, "\n");
	}
	if (rhetmode != UNIFORMRATE) {
		fprintf(ofp, "\nRates and their respective probabilities used in the likelihood function:\n");
		fprintf(ofp, "\n Category  Relative rate  Probability\n");
		if (rhetmode == TWORATE || rhetmode == MIXEDRATE)
			fprintf(ofp, "  0         0.0000         %.4f\n", fracinv);
		for (i = 0; i < numcats; i++)
			fprintf(ofp, "  %d         %.4f         %.4f\n",
				i+1, Rates[i], (1.0-fracinv)/(double) numcats);	
	}
	if (rhetmode == GAMMARATE || rhetmode == MIXEDRATE) {
		fprintf(ofp, "\nCategories 1-%d approximate a continous ", numcats);
		fprintf(ofp, "Gamma-distribution with expectation 1\n"); 
		fprintf(ofp, "and variance ");
		if (Geta == 1.0) fprintf(ofp, "infinity");
		else fprintf(ofp, "%.2f", Geta/(1.0-Geta));
		fprintf(ofp, ".\n");
	}

		
   } /* if WRITEPARAMS) || WRITEALL */

   if ((part == WRITEREST) || (part == WRITEALL)) {


	/***************************************************************************/
	/*  RATE HETEROGENEITY (PART 2)                                            */
	/***************************************************************************/

#if 0
	if (typ_optn == TREERECON_OPTN && (puzzlemode == QUARTPUZ || puzzlemode == USERTREE  || puzzlemode == CONSENSUS) && !skipmlbranch_optn) {
#endif

#if 0
if(typ_optn == TREERECON_OPTN) fprintf(stderr, "typ_optn == TREERECON_OPTN\n");
if(puzzlemode == QUARTPUZ)     fprintf(stderr, "puzzlemode == QUARTPUZZ\n");
if(puzzlemode == USERTREE)     fprintf(stderr, "puzzlemode == USERTREE\n");
if(puzzlemode == CONSENSUS)    fprintf(stderr, "puzzlemode == CONSENSUS\n");
if(dotreelh_optn)              fprintf(stderr, "dotreelh_optn\n");
#endif

	if (typ_optn == TREERECON_OPTN 
            && (puzzlemode == QUARTPUZ 
	        || puzzlemode == USERTREE  
	        || puzzlemode == CONSENSUS) 
	    && dotreelh_optn) {           /* if likelihood has been computed */
		if (rhetmode != UNIFORMRATE) {
			fprintf(ofp, "\nCombination of categories that contributes");
			fprintf(ofp, " the most to the likelihood\n");
			fprintf(ofp, "(computation done without clock assumption assuming ");
			if (puzzlemode == QUARTPUZ) fprintf(ofp, "quartet-puzzling tree");
			if (puzzlemode == USERTREE || puzzlemode == CONSENSUS) {
		        	if (utree_optn) fprintf(ofp, "1st user tree");
		        	else            fprintf(ofp, "NJ tree");
			}
			fprintf(ofp, "):\n\n");
			if (bestratefound==0) {
                             fprintf(STDOUT, "ERROR: no rate combination computed before output!!!\n");
			     findbestratecombination(); 
			}
			printbestratecombination(ofp);
		} /* rhetmode != UNIFORMRATE */

		if (savesiterate_optn) {
			FILE *ratefp;

			openfiletowrite(&ratefp, SITERATE, "site rates", stdinput_fp);
			printbestratecombinationtofile(ratefp, rhetmode);
			fclose(ratefp);
		} /* if savesiterate_optn */
	} /* if likelihood has been computed */
		
	/***************************************************************************/
	/*  BAD QUARTET STATISTICS (SEQUENCES IN INPUT ORDER)                      */
	/***************************************************************************/

	if (puzzlemode == QUARTPUZ &&typ_optn == TREERECON_OPTN) {
		fprintf(ofp, "\n\nQUARTET STATISTICS (SEQUENCES IN INPUT ORDER)\n\n");
		
		
		fprintf(ofp, "\n");
		fprintf(ofp, "     name       | resolved        | partly resolved | unresolved      | sum\n");
		fprintf(ofp, " ------------------------------------------------------------------------------\n");
		for (i = 0; i < Maxspc; i++) {
			/* fprintf(ofp, " %3d. %-10s  %6.2f%% [%7ld] %6.2f%% [%7ld] %6.2f%% [%7ld] %7ld\n", */
			/* fprintf(ofp, " %3d. %-10s  (%6.2f%%) %7ld (%6.2f%%) %7ld (%6.2f%%) %7ld %7ld\n", */
			fprintf(ofp, " %-3d %-10s  %7ld [%6.2f%%] %7ld [%6.2f%%] %7ld [%6.2f%%] %7ld\n", 
				i+1, Namestr[i],
				(qinfomatr[1][i]+qinfomatr[2][i]+qinfomatr[4][i]),
				(100.0 * (qinfomatr[1][i]+qinfomatr[2][i]+qinfomatr[4][i])/qinfomatr[8][i]),
				(qinfomatr[3][i]+qinfomatr[5][i]+qinfomatr[6][i]),
				(100.0 * (qinfomatr[3][i]+qinfomatr[5][i]+qinfomatr[6][i])/qinfomatr[8][i]),
				qinfomatr[7][i],
				(100.0 * (qinfomatr[7][i])/qinfomatr[8][i]),
				qinfomatr[8][i]);
/* MISSING QUARTETS (HAS ;-) */
		}
		fprintf(ofp, " --------------------------------------------------------------------------\n");
		fprintf(ofp, "     #quartets : ");
		{
		uli allqs;
		allqs = fullresqs + partresqs + unresqs + missingqs;
		fprintf(ofp, "%7ld [%6.2f%%] ", fullresqs, 100.0 * fullresqs / allqs);
		fprintf(ofp, "%7ld [%6.2f%%] ", partresqs, 100.0 * partresqs / allqs);
		fprintf(ofp, "%7ld [%6.2f%%] ", unresqs,   100.0 * unresqs   / allqs);
/* MISSING QUARTETS (HAS ;-) */
		/* fprintf(ofp, "%7ld [%6.2f%%] ", missingqs,   100.0 * missingqs   / allqs); */
		fprintf(ofp, "%7ld",  allqs);
		}
		fprintf(ofp, "\n\n");
		fprintf(ofp, "The table shows the occurrences of fully resolved, partially, and\n");
		fprintf(ofp, "completely unresolved quartets for each sequence and their percentage\n");
		fprintf(ofp, "relative to the number of times the sequence occurs in the list of \n");
		fprintf(ofp, "quartets (i.e. %ld quartets out of %ld in total).\n", (4 * Numquartets)/Maxspc, Numquartets);
		fprintf(ofp, "In fully resolved quartet one single topology is supported, while for\n");
		fprintf(ofp, "partially resolved quartets two and for completely unresolved quartets\n");
		fprintf(ofp, "none of the topologies (AB||CD, AC||BD, AD||BC) are favoured.\n");
		fprintf(ofp, "Note: Because 4 sequences are involved in one quartet numbers add up\n");
		fprintf(ofp, "to a four-fold of the existing quartets.\n");
		fprintf(ofp, "\n");
		fprintf(ofp, "Hint: The overall numbers in the last row give information about the\n");
		fprintf(ofp, "phylogenetic content of the dataset. The higher the percentage of partially\n");
		fprintf(ofp, "and unresolved quartets, the lower the content of phylogenetic information.\n");
		fprintf(ofp, "This can be visualized in more detail by likelihood mapping analysis.\n");
		fprintf(ofp, "\n");
		
		if (saverdstatsfile_optn) {
			openfiletoappend(&rdsfp, RDSTATS, "RecDetec Statistics file", stdinput_fp);
			fprintf(rdsfp, "\n");
			fprintf(rdsfp, "QUART TAX      name       | resolved        | partly resolved | unresolved      | sum\n");
			for (i = 0; i < Maxspc; i++) {
				/* fprintf(rdsfp, " %3d. %-10s  %6.2f%% [%7ld] %6.2f%% [%7ld] %6.2f%% [%7ld] %7ld\n", */
				/* fprintf(rdsfp, " %3d. %-10s  (%6.2f%%) %7ld (%6.2f%%) %7ld (%6.2f%%) %7ld %7ld\n", */
				fprintf(rdsfp, "QUART TAX  %-3d %-10s  %7ld [%6.2f%%] %7ld [%6.2f%%] %7ld [%6.2f%%] %7ld\n", 
					i+1, Namestr[i],
					(qinfomatr[1][i]+qinfomatr[2][i]+qinfomatr[4][i]),
					(100.0 * (qinfomatr[1][i]+qinfomatr[2][i]+qinfomatr[4][i])/qinfomatr[8][i]),
					(qinfomatr[3][i]+qinfomatr[5][i]+qinfomatr[6][i]),
					(100.0 * (qinfomatr[3][i]+qinfomatr[5][i]+qinfomatr[6][i])/qinfomatr[8][i]),
					qinfomatr[7][i],
					(100.0 * (qinfomatr[7][i])/qinfomatr[8][i]),
					qinfomatr[8][i]);
					/* MISSING QUARTETS (HAS ;-) */
			}
			fprintf(rdsfp, "QUART TAX      #quartets : ");
			{
				uli allqs;
				allqs = fullresqs + partresqs + unresqs + missingqs;
				fprintf(rdsfp, "%7ld [%6.2f%%] ", fullresqs, 100.0 * fullresqs / allqs);
				fprintf(rdsfp, "%7ld [%6.2f%%] ", partresqs, 100.0 * partresqs / allqs);
				fprintf(rdsfp, "%7ld [%6.2f%%] ", unresqs,   100.0 * unresqs   / allqs);
				/* MISSING QUARTETS (HAS ;-) */
				/* fprintf(rdsfp, "%7ld [%6.2f%%] ", missingqs,   100.0 * missingqs   / allqs); */
				fprintf(rdsfp, "%7ld",  allqs);
			}
			fprintf(rdsfp, "\n");
			fflush(rdsfp);
			fclose(rdsfp);
		} /* if saverdstatsfile_optn */

		if (savelmaptab_optn) {
#if 0
int LMAP=1;
fprintf(stderr, "LMAP: %d (%s:%d)\n", LMAP++, __FILE__, __LINE__);
#endif
			openfiletowrite(&lmaptabfp, LMAPTAB, "likelihood mapping table", stdinput_fp);
			for (i=0; i<Maxspc; i++){
				/* fprintf(ofp, " %3d. %-10s  %6.2f%% [%7ld] %6.2f%% [%7ld] %6.2f%% [%7ld] %7ld\n", */
				/* fprintf(ofp, " %3d. %-10s  (%6.2f%%) %7ld (%6.2f%%) %7ld (%6.2f%%) %7ld %7ld\n", */
				fprintf(lmaptabfp, "%s\t%ld\t%.4f\t%.4f\t%.4f\n", 
					Namestr[i],
					qinfomatr[8][i],
					(100.0 * (qinfomatr[1][i]+qinfomatr[2][i]+qinfomatr[4][i])/qinfomatr[8][i]),
					(100.0 * (qinfomatr[3][i]+qinfomatr[5][i]+qinfomatr[6][i])/qinfomatr[8][i]),
					(100.0 * (qinfomatr[7][i])/qinfomatr[8][i]));
/* MISSING QUARTETS (HAS ;-) */
			}
#if 0
			sum = res_all + partres_all + unres_all;
#endif
			fprintf(lmaptabfp, "Overall");
			{
				uli allqs;
				allqs = fullresqs + partresqs + unresqs + missingqs;
				fprintf(lmaptabfp, "\t%ld",  allqs);
				fprintf(lmaptabfp, "\t%.4f", 100.0 * fullresqs / allqs);
				fprintf(lmaptabfp, "\t%.4f", 100.0 * partresqs / allqs);
				fprintf(lmaptabfp, "\t%.4f", 100.0 * unresqs   / allqs);
			}
			closefile(lmaptabfp);
		} /* if savelmaptab_optn */


	} /* if puzzlemode == QUARTPUZ && typ_optn == TREERECON_OPTN */

	if (typ_optn == TREERECON_OPTN) {
	
		
	/***************************************************************************/
	/*  TREE SEARCH                                                            */
	/***************************************************************************/

		fprintf(ofp, "\n\nTREE SEARCH\n\n");
		if (puzzlemode == QUARTPUZ) {
			fprintf(ofp, "Quartet puzzling is used to choose from the possible tree topologies\n");
			fprintf(ofp, "and to simultaneously infer support values for internal branches.\n\n");
			fprintf(ofp, "Number of puzzling steps: %lu\n", Numtrial);
			fprintf(ofp, "Analysed quartets: %lu\n", Numquartets);
			fprintf(ofp, "Fully resolved quartets:  %lu (= %.1f%%)\n",
				fullresqs, (double) fullresqs / (double) Numquartets * 100.0);	
			fprintf(ofp, "Partly resolved quartets: %lu (= %.1f%%)\n",
				partresqs, (double) partresqs / (double) Numquartets * 100.0);	
			fprintf(ofp, "Unresolved quartets:      %lu (= %.1f%%)\n",
				unresqs, (double) unresqs / (double) Numquartets * 100.0);	
/* MISSING QUARTETS (HAS ;-) */
/*
			fprintf(ofp, "Missing quartets:          %lu (= %.1f%%)\n",
				missingqs, (double) missingqs / (double) Numquartets * 100.0);	
*/

			if (saverdstatsfile_optn) {
				openfiletoappend(&rdsfp, RDSTATS, "RecDetec Statistics file", stdinput_fp);
				fprintf(rdsfp, "\n");
				fprintf(rdsfp, "QUART Analysed quartets: %lu\n", Numquartets);
				fprintf(rdsfp, "QUART Fully resolved quartets: %lu (%.1f%%)\n",
					fullresqs, (double) fullresqs / (double) Numquartets * 100.0);	
				fprintf(rdsfp, "QUART Partly resolved quartets: %lu (%.1f%%)\n",
					partresqs, (double) partresqs / (double) Numquartets * 100.0);	
				fprintf(rdsfp, "QUART Unresolved quartets: %lu (%.1f%%)\n",
				unresqs, (double) unresqs / (double) Numquartets * 100.0);	
				fflush(rdsfp);
				fclose(rdsfp);
			} /* if saverdstatsfile_optn */

			fprintf(ofp, "\nQuartet trees are based on %s maximum likelihood values\n",
				(approxqp_optn ? "approximate" : "exact"));
			fprintf(ofp, "using the selected model of substitution and rate heterogeneity.\n");
		}
		if (puzzlemode == USERTREE || puzzlemode == CONSENSUS) {
			fprintf(ofp, "%d tree topologies were specified by the user.\n", numutrees);		
		}
		if (puzzlemode == PAIRDIST) {
			fprintf(ofp, "No tree search performed (maximum likelihood distances only).\n");
		}

		
	/***************************************************************************/
	/*  QUARTET PUZZLING TREE / CONSENSUS TREE                                 */
	/***************************************************************************/

		if ((puzzlemode == QUARTPUZ) || (puzzlemode == CONSENSUS)) {
			if (puzzlemode == QUARTPUZ) {
				fprintf(ofp, "\n\nQUARTET PUZZLING TREE\n\n");
				fprintf(ofp, "Support for the internal branches of the unrooted quartet puzzling\n");
				fprintf(ofp, "tree topology is shown in percent.\n");
				if (consincluded == (Maxspc - 3))
					fprintf(ofp,"\nThis quartet puzzling tree is completely resolved.\n");
				else
					fprintf(ofp,"\nThis quartet puzzling tree is not completely resolved!\n");
			} else {
				fprintf(ofp, "\n\nCONSENSUS TREE\n\n");
				fprintf(ofp, "Support for the internal branches of the unrooted consensus tree\n");
				fprintf(ofp, "topology is shown in percent.\n");
				if (consincluded == (Maxspc - 3))
					fprintf(ofp,"\nThis consensus tree is completely resolved.\n");
				else
					fprintf(ofp,"\nThis consensus tree is not completely resolved!\n");
			}
			fprintf(ofp, "\n\n");
			plotconsensustree(ofp);
			if (puzzlemode == QUARTPUZ) fprintf(ofp, "\n\nQuartet puzzling tree (in CLUSTAL W notation):\n\n");
			else                        fprintf(ofp, "\n\nConsensus tree (in CLUSTAL W notation):\n\n");
			writeconsensustree(ofp, FALSE, qsupportarr);
			if (qsupport_optn)
				writeconsensustree(ofp, TRUE, qsupportarr);
			if (puzzlemode == QUARTPUZ) {
				fprintf(ofp, "\n\nBIPARTITIONS\n\n");
				fprintf(ofp, "The following bipartitions occured at least once");
				fprintf(ofp, " in all intermediate\ntrees that have been generated ");
				fprintf(ofp, "in the %lu puzzling steps.\n", Numtrial);
				fprintf(ofp, "Bipartitions included in the quartet puzzling tree:\n");
			} else {
				fprintf(ofp, "\n\nBIPARTITIONS\n\n");
				fprintf(ofp, "The following bipartitions occured at least once");
				fprintf(ofp, " in the specified set\n of %d usertrees tree topologies.\n", numutrees);
				fprintf(ofp, "Bipartitions included in the consensus tree:\n");
			}
			fprintf(ofp,
				"(bipartition with sequences in input order : number of times seen (and ratio))\n\n");
			for (li = 0; li < (uli)consfifty; li++) {
				fprintf(ofp, " ");
				fprintfsplit(ofp, splitfreqs[2*li+1], splitpatterns, splitlength, Maxspc, TRUE);

				if (puzzlemode == QUARTPUZ) { /* QP */
					fprintf(ofp, " : %5lu (%.3f)", splitfreqs[2*li], (double)splitfreqs[2*li]/(double)Numtrial);
				} else { /* consensus */
					fprintf(ofp, " : %5lu (%.3f)", splitfreqs[2*li], (double)splitfreqs[2*li]/(double)numutrees);
				}

/* MISSING QUARTETS (HAS ;-) */
/* todo (HAS) */
				if (qsupport_optn) {
					fprintf(ofp, "   f+=%.0f|", (100.0*qsupportarr[li].fullres_pro/qsupportarr[li].qsum));
					fprintf(ofp, "p+=%.0f|", (100.0*qsupportarr[li].partres_pro/qsupportarr[li].qsum));
					fprintf(ofp, "f-=%.0f|", (100.0*qsupportarr[li].fullres_con/qsupportarr[li].qsum));
					fprintf(ofp, "p-=%.0f|", (100.0*qsupportarr[li].partres_con/qsupportarr[li].qsum));
					fprintf(ofp, "ur=%.0f", (100.0*qsupportarr[li].unres/qsupportarr[li].qsum));
					if (qsupportarr[li].missing > 0) {
						fprintf(ofp, "|md=%.0f", (100.0*qsupportarr[li].missing/qsupportarr[li].qsum));
					}
					fprintf(ofp, "/%ld\n", qsupportarr[li].qsum);
				} else {
					fprintf(ofp, "\n");
				}
#if 0
#endif
			}
			if (consincluded == 0) fprintf(ofp, " None (no bipartition included)\n");
			if (conssub50_optn) {
				if (! puzzlemode == CONSENSUS) 
					fprintf(ofp, "\nCongruent bipartitions occurred in 50%% or less, included in \nthe quartet puzzling tree:\n");
				else
					fprintf(ofp, "\nCongruent bipartitions occurred in 50%% or less, included in \nthe consensus tree:\n");
			} else {
				if (! puzzlemode == CONSENSUS) 
					fprintf(ofp, "\nCongruent bipartitions occurred in 50%% or less, not included in \nthe quartet puzzling tree:\n");
				else
					fprintf(ofp, "\nCongruent bipartitions occurred in 50%% or less, not included in \nthe consensus tree:\n");
			}
			fprintf(ofp,
				"(bipartition with sequences in input order : number of times seen (and ratio))\n\n");
						
			if ((uli)consfifty == numbiparts) {
				fprintf(ofp, " None (all bipartitions are included)\n");
			} else {
				if (consfifty < conscongruent) {
					for (li = (uli)consfifty; (li < (uli)numbiparts) && (li < (uli)conscongruent); li++) {
						fprintf(ofp, " ");
						fprintfsplit(ofp, splitfreqs[2*li+1], splitpatterns, splitlength, Maxspc, TRUE);

						if (puzzlemode == QUARTPUZ) { /* QP */
							fprintf(ofp, " : %5lu (%.3f)", splitfreqs[2*li], (double)splitfreqs[2*li]/(double)Numtrial);
						} else { /* consensus */
							fprintf(ofp, " : %5lu (%.3f)", splitfreqs[2*li], (double)splitfreqs[2*li]/(double)numutrees);
						}
/* MISSING QUARTETS (HAS ;-) */
/* todo (HAS) */
						if (qsupport_optn) {
							fprintf(ofp, "f+=%.0f|", (100.0*qsupportarr[li].fullres_pro/qsupportarr[li].qsum));
							fprintf(ofp, "p+=%.0f|", (100.0*qsupportarr[li].partres_pro/qsupportarr[li].qsum));
							fprintf(ofp, "f-=%.0f|", (100.0*qsupportarr[li].fullres_con/qsupportarr[li].qsum));
							fprintf(ofp, "p-=%.0f|", (100.0*qsupportarr[li].partres_con/qsupportarr[li].qsum));
							fprintf(ofp, "ur=%.0f", (100.0*qsupportarr[li].unres/qsupportarr[li].qsum));
							if (qsupportarr[li].missing > 0) {
								fprintf(ofp, "|md=%.0f", (100.0*qsupportarr[li].missing/qsupportarr[li].qsum));
							}
							fprintf(ofp, "/%ld\n", qsupportarr[li].qsum);
						} else {
							fprintf(ofp, "\n");
						}
#if 0
#endif
					}
				} else {
					fprintf(ofp, " None (No congruent split not included)\n");
				}

				if (! puzzlemode == CONSENSUS) 
					fprintf(ofp, "\nIncongruent bipartitions not included in the quartet puzzling tree:\n");
				else
					fprintf(ofp, "\nIncongruent bipartitions not included in the consensus tree:\n");
				fprintf(ofp,
					"(bipartition with sequences in input order : number of times seen (and ratio))\n\n");

				/* print next 20 bipartions not included */				
				for (li = conscongruent; (li < numbiparts) && (li < conscongruent + 20UL); li++) {
					fprintf(ofp, " ");
					fprintfsplit(ofp, splitfreqs[2*li+1], splitpatterns, splitlength, Maxspc, TRUE);

					if (puzzlemode == QUARTPUZ) { /* QP */
						fprintf(ofp, " : %5lu (%.3f)\n", splitfreqs[2*li], (double)splitfreqs[2*li]/(double)Numtrial);
					} else { /* consensus */
						fprintf(ofp, " : %5lu (%.3f)\n", splitfreqs[2*li], (double)splitfreqs[2*li]/(double)numutrees);
					}
				}
				if ((li == conscongruent + 20UL) && (li != numbiparts)) 
					fprintf(ofp, "\n(%lu other less frequent bipartitions not shown)\n",
						numbiparts - conscongruent - 20UL);			

			}	

			if ((saveptsplitsfile_optn) && ((puzzlemode == QUARTPUZ) || (puzzlemode == CONSENSUS))) {
				FILE *splitsfp;
				openfiletowrite(&splitsfp, PTSPLITS, "splits file", stdinput_fp);
				for (li = 0; li < numbiparts; li++) {
					fprintfsplit(splitsfp, splitfreqs[2*li+1], splitpatterns, splitlength, Maxspc, FALSE);
					if (puzzlemode == QUARTPUZ) { /* QP */
						fprintf(splitsfp, "\t%.4f\n", (double)splitfreqs[2*li]/(double)Numtrial);
					} else { /* consensus */
						fprintf(splitsfp, "\t%.4f\n", (double)splitfreqs[2*li]/(double)numutrees);
					}
				}
				fclose(splitsfp);
			} /* if savesplitfile_optn */

			if (! puzzlemode == CONSENSUS) {
				fprintfsortedpstrees(ofp, psteptreelist, psteptreenum, psteptreesum, PT_FTYPE_REPORT, 5.0);
				/* fprintfsortedpstrees(ofp, psteptreelist, psteptreenum, psteptreesum, 0, 5.0); changed for NEXUS output (HAS) ;-) */
			}
			if (savenexusptsplits_optn) {
				FILE *nexfp;
	
				openfiletoappend(&nexfp, NEXPTSPLITS, "nexus splits file", stdinput_fp);
				if (puzzlemode == QUARTPUZ) {
					fprintfsplitblocknexus(nexfp, numbiparts, Numtrial, 0.0 /* cutoff */, splitfreqs, splitpatterns, splitlength, consfifty, conscongruent, consincluded, Maxspc);
				} else {
					fprintfsplitblocknexus(nexfp, numbiparts, numutrees, 0.0 /* cutoff */, splitfreqs, splitpatterns, splitlength, consfifty, conscongruent, consincluded, Maxspc);
				}
				fclose(nexfp);
			} /* if savenexusptsplits_optn */
			
		}
	
		
	/***************************************************************************/
	/*  MAXIMUM LIKELIHOOD BRANCH LENGTHS ON QUARTET  PUZZLING TREE (NO CLOCK) */
	/***************************************************************************/

#if 0
		if (((puzzlemode == QUARTPUZ) || (puzzlemode == CONSENSUS)) && !skipmlbranch_optn) {
#endif
		if (((puzzlemode == QUARTPUZ) || (puzzlemode == CONSENSUS)) && dotreelh_optn) {

			if (! puzzlemode == CONSENSUS) {
				fprintf(ofp, "\n\nMAXIMUM LIKELIHOOD BRANCH LENGTHS ON QUARTET");
				fprintf(ofp, " PUZZLING TREE (NO CLOCK)\n\nBranch lengths are computed using");
				fprintf(ofp, " the selected model of\nsubstitution and rate heterogeneity.\n\n\n");
			} else {
				fprintf(ofp, "\n\nMAXIMUM LIKELIHOOD BRANCH LENGTHS ON CONSENSUS");
				fprintf(ofp, " TREE (NO CLOCK)\n\nBranch lengths are computed using");
				fprintf(ofp, " the selected model of\nsubstitution and rate heterogeneity.\n\n\n");
			}
			clockmode = 0; /* nonclocklike branch lengths */
			prtopology(ofp, clockmode);
			fprintf(ofp, "\n");
			resulttree(ofp, FALSE, clockmode); /* branch lengths cannot be set by user in this case */
			if (! puzzlemode == CONSENSUS) {
				fprintf(ofp, "\n\nQuartet puzzling tree with maximum likelihood branch lengths");
				fprintf(ofp, "\n(in CLUSTAL W notation):\n\n");
			} else {
				fprintf(ofp, "\n\nConsensus tree with maximum likelihood branch lengths");
				fprintf(ofp, "\n(in CLUSTAL W notation):\n\n");
			}
			fputphylogeny(ofp, clockmode, TRUE); /* TRUE => fold lines longer 60 chars */
		
/* SONJA */
#ifdef SONJA
        /* computes the distances in the tree and writes them to file/stderr */
        tree2dist(Distanmat);
        putdistance(ofp);
        putdistance(stderr);
#endif

	/*****************************************************************************/
	/*  MAXIMUM LIKELIHOOD BRANCH LENGTHS ON QUARTET  PUZZLING TREE (WITH CLOCK) */
	/*****************************************************************************/

			if (compclock) {
				if (! puzzlemode == CONSENSUS) {
					fprintf(ofp, "\n\nMAXIMUM LIKELIHOOD BRANCH LENGTHS OF QUARTET");
					fprintf(ofp, " PUZZLING TREE (WITH CLOCK)\n\nBranch lengths are computed using");
				} else {
					fprintf(ofp, "\n\nMAXIMUM LIKELIHOOD BRANCH LENGTHS OF CONSENSUS");
					fprintf(ofp, " TREE (WITH CLOCK)\n\nBranch lengths are computed using");
				}
				fprintf(ofp, " the selected model of\nsubstitution and rate heterogeneity.\n");
				fprintf(ofp, "\nRoot located at branch: %d ", locroot+1);
				if (locroot<Maxspc) {
					fprintf(ofp, "\""); fputid(ofp,locroot); fprintf(ofp, "\"  ");
				} else	fprintf(ofp, "\"internal branch\"  ");

				if (rootsearch == ROOT_USER) fprintf(ofp, "(user specified)\n\n\n");
				if (rootsearch == ROOT_AUTO) {
					fprintf(ofp, "(automatic search)");
					if (numbestroot > 1) fprintf(ofp, "- WARNING: %d best locations found! -", numbestroot);
					fprintf(ofp, "\n\n");	
					fprintf(ofp, "If the automatic search misplaces the root please rerun the analysis\n");
					fprintf(ofp, "(rename \"outtree\" to \"intree\") and select location of root manually!");
					fprintf(ofp, "\n\n\n");
				}
				if (rootsearch == ROOT_DISPLAYED) fprintf(ofp, "(displayed outgroup)\n\n\n");
				clockmode = 1; /* clocklike branch lengths */
				prtopology(ofp, clockmode);
				fprintf(ofp, "\n");
				fprintf(ofp, "\nTree drawn as unrooted tree for better ");
				fprintf(ofp, "comparison with non-clock tree!\n");
				resulttree(ofp, usebranch_optn, clockmode);
				fprintf(ofp, "\n");
				resultheights(ofp);
				if (! puzzlemode == CONSENSUS) {
					fprintf(ofp, "\n\nRooted quartet puzzling tree with clocklike");
				} else {
					fprintf(ofp, "\n\nRooted consensus tree with clocklike");
				}
				fprintf(ofp, " maximum likelihood branch lengths\n");
				fprintf(ofp, "(in CLUSTAL W notation):\n\n");
				fputrooted(ofp, locroot, TRUE);
			}
			
		
	/***************************************************************************/
	/*  MOLECULAR CLOCK LIKELIHOOD RATIO TEST                                  */
	/***************************************************************************/

			if (compclock) {
				fprintf(ofp, "\n\nMOLECULAR CLOCK LIKELIHOOD RATIO TEST\n\n");
				fprintf(ofp, "log L without clock: %.2f (independent branch parameters: %d)\n",
					Ctree->lklhd, Numspc + Numibrnch);
				fprintf(ofp, "log L with clock:    %.2f (independent branch parameters: %d)\n\n",
					Ctree->lklhdc, Numhts + 1);
				delta = fabs(2.0*((Ctree->lklhd) - (Ctree->lklhdc)));
				fprintf(ofp, "Likelihood ratio test statistic delta: %.2f\n", delta);	
				df = Numspc + Numibrnch - Numhts - 1;
				fprintf(ofp, "Degress of freedom of chi-square distribution: %d\n", df);
				
				pval = IncompleteGammaQ(df*0.5, delta*0.5);
				
				fprintf(ofp, "Critical significance level: %.2f%%\n\n", pval*100.0);
				if (pval >= 0.05) {
					fprintf(ofp, "The simpler (clocklike) tree can not be rejected on a significance\n");
					fprintf(ofp, "level of 5%%. The log-likelihood of the more complex (no clock) tree\n");
					fprintf(ofp, "is not significantly increased.\n");
				} else {
					fprintf(ofp, "The simpler (clocklike) tree is rejected on a significance level\n");
					fprintf(ofp, "of 5%%. The log-likelihood of the more complex (no clock) tree is\n");
					fprintf(ofp, "significantly increased.\n");
				}
				fprintf(ofp, "\nPlease take care that the correct root is used!\n");
			}
				
		}
	}
	
		
	/***************************************************************************/
	/*  LIKELIHOOD MAPPING ANALYSIS                                            */
	/***************************************************************************/

	if (typ_optn == LIKMAPING_OPTN) {
	
			fprintf(ofp, "\n\nLIKELIHOOD MAPPING ANALYSIS\n\n");
			fprintf(ofp, "Number of quartets: %lu", Numquartets);
			if (lmqts == 0) fprintf(ofp, " (all possible)\n");
			else fprintf(ofp, " (random choice)\n");
			fprintf(ofp, "\nQuartet trees are based on approximate maximum likelihood values\n");
			fprintf(ofp, "using the selected model of substitution and rate heterogeneity.\n\n\n");
			if (numclust == 1) {
				fprintf(ofp, "Sequences are not grouped in clusters.\n");
			} else {
				fprintf(ofp, "Sequences are grouped in %d clusters.\n", numclust);
				fprintf(ofp, "\nCluster a: %d sequences\n\n", clustA);
				for (i = 0; i < clustA; i++) {
					fprintf(ofp, " ");
					fputid(ofp, clusterA[i]);
					fprintf(ofp, "\n");
				}
				fprintf(ofp, "\nCluster b: %d sequences\n\n", clustB);
				for (i = 0; i < clustB; i++) {
					fprintf(ofp, " ");
					fputid(ofp, clusterB[i]);
					fprintf(ofp, "\n");
				}
				if (numclust > 2) {
					fprintf(ofp, "\nCluster c: %d sequences\n\n", clustC);
					for (i = 0; i < clustC; i++) {
						fprintf(ofp, " ");
						fputid(ofp, clusterC[i]);
						fprintf(ofp, "\n");
					}
				}
				if (numclust == 4) {
					fprintf(ofp, "\nCluster d: %d sequences\n\n", clustD);
					for (i = 0; i < clustD; i++) {
						fprintf(ofp, " ");
						fputid(ofp, clusterD[i]);
						fprintf(ofp, "\n");
					}
				}
				fprintf(ofp, "\nQuartets of sequences used in the likelihood");
				fprintf(ofp, " mapping analysis are generated\n");
				if (numclust == 2)
					fprintf(ofp, "by drawing two sequences from cluster a and two from cluster b.");
				if (numclust == 3)
					fprintf(ofp, "by drawing one sequence from clusters a and b and two from cluster c.");
				if (numclust == 4)
					fprintf(ofp, "by drawing one sequence from each of the clusters a, b, c, and d.");
			}

		
	/***************************************************************************/
	/*  LIKELIHOOD MAPPING STATISTICS                                          */
	/***************************************************************************/

			fprintf(ofp, "\n\nLIKELIHOOD MAPPING STATISTICS\n\n");
#if 0
			fprintf(ofp, "Occupancies of the three areas 1, 2, 3:\n\n");
			if (numclust == 4)
				fprintf(ofp, "                    (a,b)-(c,d)\n");
			if (numclust == 3)
				fprintf(ofp, "                    (a,b)-(c,c)\n");
			if (numclust == 2)
				fprintf(ofp, "                    (a,a)-(b,b)\n");
			fprintf(ofp, "                        /\\\n");
			fprintf(ofp, "                       /  \\\n");
			fprintf(ofp, "                      /    \\\n");
			fprintf(ofp, "                     /   1  \\\n");
			fprintf(ofp, "                    / \\    / \\\n");
			fprintf(ofp, "                   /   \\  /   \\\n");
			fprintf(ofp, "                  /     \\/     \\\n");
			fprintf(ofp, "                 /  3    :   2  \\\n");
			fprintf(ofp, "                /        :       \\\n");
			fprintf(ofp, "               /__________________\\\n");
			if (numclust == 4)
				fprintf(ofp, "     (a,d)-(b,c)                  (a,c)-(b,d)\n");
			if (numclust == 3)
				fprintf(ofp, "     (a,c)-(b,c)                  (a,c)-(b,c)\n");
			if (numclust == 2)
				fprintf(ofp, "     (a,b)-(a,b)                  (a,b)-(a,b)\n");
			fprintf(ofp, "\n");
#if 0
			fprintf(ofp, "Number of quartets in region 1: %lu (= %.1f%%)\n",
			 	ar1, (double) ar1*100.0/Numquartets);
			fprintf(ofp, "Number of quartets in region 2: %lu (= %.1f%%)\n",
				ar2, (double) ar2*100.0/Numquartets);
			fprintf(ofp, "Number of quartets in region 3: %lu (= %.1f%%)\n\n",
				ar3, (double) ar3*100.0/Numquartets);
#endif
			fprintf(ofp, "Number of quartets in region 1: %lu (= %.1f%%)\n",
			 	qcountarray[Maxspc][LM_AR1], (double) qcountarray[Maxspc][LM_AR1]*100.0/Numquartets);
			fprintf(ofp, "Number of quartets in region 2: %lu (= %.1f%%)\n",
				qcountarray[Maxspc][LM_AR2], (double) qcountarray[Maxspc][LM_AR2]*100.0/Numquartets);
			fprintf(ofp, "Number of quartets in region 3: %lu (= %.1f%%)\n\n",
				qcountarray[Maxspc][LM_AR3], (double) qcountarray[Maxspc][LM_AR3]*100.0/Numquartets);
			fprintf(ofp, "Occupancies of the seven areas 1, 2, 3, 4, 5, 6, 7:\n\n");
			if (numclust == 4)
				fprintf(ofp, "                    (a,b)-(c,d)\n");
			if (numclust == 3)
				fprintf(ofp, "                    (a,b)-(c,c)\n");
			if (numclust == 2)
				fprintf(ofp, "                    (a,a)-(b,b)\n");
			fprintf(ofp, "                        /\\\n");
			fprintf(ofp, "                       /  \\\n");
			fprintf(ofp, "                      /  1 \\\n");
			fprintf(ofp, "                     / \\  / \\\n");
			fprintf(ofp, "                    /   /\\   \\\n");
			fprintf(ofp, "                   / 6 /  \\ 4 \\\n");
			fprintf(ofp, "                  /   /  7 \\   \\\n");
			fprintf(ofp, "                 / \\ /______\\ / \\\n");
			fprintf(ofp, "                / 3  :   5  :  2 \\\n");
			fprintf(ofp, "               /__________________\\\n");
			if (numclust == 4)
				fprintf(ofp, "     (a,d)-(b,c)                  (a,c)-(b,d)\n");
			if (numclust == 3)
				fprintf(ofp, "     (a,c)-(b,c)                  (a,c)-(b,c)\n");
			if (numclust == 2)
				fprintf(ofp, "     (a,b)-(a,b)                  (a,b)-(a,b)\n");
			fprintf(ofp, "\n");
#if 0
			fprintf(ofp, "Number of quartets in region 1: %lu (= %.1f%%)    left:   %lu   right: %lu\n",
				reg1, (double) reg1*100.0/Numquartets, reg1l, reg1r);
			fprintf(ofp, "Number of quartets in region 2: %lu (= %.1f%%)    bottom: %lu   top:   %lu\n",
				reg2, (double) reg2*100.0/Numquartets, reg2d, reg2u);
			fprintf(ofp, "Number of quartets in region 3: %lu (= %.1f%%)    bottom: %lu   top:   %lu\n",
				reg3, (double) reg3*100.0/Numquartets, reg3d, reg3u);
			fprintf(ofp, "Number of quartets in region 4: %lu (= %.1f%%)    bottom: %lu   top:   %lu\n",
				reg4, (double) reg4*100.0/Numquartets, reg4d, reg4u);
			fprintf(ofp, "Number of quartets in region 5: %lu (= %.1f%%)    left:   %lu   right: %lu\n",
				reg5, (double) reg5*100.0/Numquartets, reg5l, reg5r);
			fprintf(ofp, "Number of quartets in region 6: %lu (= %.1f%%)    bottom: %lu   top:   %lu\n",
				reg6, (double) reg6*100.0/Numquartets, reg6d, reg6u);
			fprintf(ofp, "Number of quartets in region 7: %lu (= %.1f%%)\n",
				reg7, (double) reg7*100.0/Numquartets);
#endif
			fprintf(ofp, "Number of quartets in region 1: %lu (= %.1f%%)\n",
				qcountarray[Maxspc][LM_REG1], (double) qcountarray[Maxspc][LM_REG1]*100.0/Numquartets);
			fprintf(ofp, "Number of quartets in region 2: %lu (= %.1f%%)\n",
				qcountarray[Maxspc][LM_REG2], (double) qcountarray[Maxspc][LM_REG2]*100.0/Numquartets);
			fprintf(ofp, "Number of quartets in region 3: %lu (= %.1f%%)\n",
				qcountarray[Maxspc][LM_REG3], (double) qcountarray[Maxspc][LM_REG3]*100.0/Numquartets);
			fprintf(ofp, "Number of quartets in region 4: %lu (= %.1f%%)\n",
				qcountarray[Maxspc][LM_REG4], (double) qcountarray[Maxspc][LM_REG4]*100.0/Numquartets);
			fprintf(ofp, "Number of quartets in region 5: %lu (= %.1f%%)\n",
				qcountarray[Maxspc][LM_REG5], (double) qcountarray[Maxspc][LM_REG5]*100.0/Numquartets);
			fprintf(ofp, "Number of quartets in region 6: %lu (= %.1f%%)\n",
				qcountarray[Maxspc][LM_REG6], (double) qcountarray[Maxspc][LM_REG6]*100.0/Numquartets);
			fprintf(ofp, "Number of quartets in region 7: %lu (= %.1f%%)\n",
				qcountarray[Maxspc][LM_REG7], (double) qcountarray[Maxspc][LM_REG7]*100.0/Numquartets);
			fprintf(ofp, "\n");
			fprintf(ofp, "Number of resolved        quartets (regions 1,2,3): %lu (= %.1f%%)\n",
				(qcountarray[Maxspc][LM_REG1]+qcountarray[Maxspc][LM_REG2]+qcountarray[Maxspc][LM_REG3]),
				(double)(qcountarray[Maxspc][LM_REG1]+qcountarray[Maxspc][LM_REG2]+qcountarray[Maxspc][LM_REG3])*100.0/Numquartets);
			fprintf(ofp, "Number of partly resolved quartets (regions 4,5,6): %lu (= %.1f%%)\n",
				(qcountarray[Maxspc][LM_REG4]+qcountarray[Maxspc][LM_REG5]+qcountarray[Maxspc][LM_REG6]),
				(double)(qcountarray[Maxspc][LM_REG4]+qcountarray[Maxspc][LM_REG5]+qcountarray[Maxspc][LM_REG6])*100.0/Numquartets);
			fprintf(ofp, "Number of unresolved      quartets (region 7):      %lu (= %.1f%%)\n",
				qcountarray[Maxspc][LM_REG7], (double) qcountarray[Maxspc][LM_REG7]*100.0/Numquartets);

#endif


		if ((numclust == 1) || (numclust == 4))
			fprintf(ofp, "           (a,b)-(c,d)                             (a,b)-(c,d)       \n");
		if (numclust == 3)
			fprintf(ofp, "           (a,b)-(c,c')                            (a,b)-(c,c')      \n");
		if (numclust == 2)
			fprintf(ofp, "          (a,a')-(b,b')                           (a,a')-(b,b')      \n");
		fprintf(ofp, "                /\\                                      /\\           \n");
		fprintf(ofp, "               /  \\                                    /  \\          \n");
		fprintf(ofp, "              /    \\                                  /  1 \\         \n");
		fprintf(ofp, "             /  a1  \\                                / \\  / \\        \n");
		fprintf(ofp, "            /\\      /\\                              /   \\/   \\       \n");
		fprintf(ofp, "           /  \\    /  \\                            /    /\\    \\      \n");
		fprintf(ofp, "          /    \\  /    \\                          / 6  /  \\  4 \\     \n");
		fprintf(ofp, "         /      \\/      \\                        /\\   /  7 \\   /\\    \n");
		fprintf(ofp, "        /        |       \\                      /  \\ /______\\ /  \\   \n");
		fprintf(ofp, "       /   a3    |    a2  \\                    / 3  |    5   |  2 \\  \n");
		fprintf(ofp, "      /__________|_________\\                  /_____|________|_____\\ \n");
		if ((numclust == 1) || (numclust == 4))
			fprintf(ofp, "(a,d)-(b,c)            (a,c)-(b,d)      (a,b)-(c,d)            (a,c)-(b,d)\n");
		if (numclust == 3)
			fprintf(ofp, "(a,c')-(b,c)          (a,c)-(b,c')      (a,c')-(b,c)          (a,c)-(b,c')\n");
		if (numclust == 2)
			fprintf(ofp, "(a,b')-(a',b)        (a,b)-(a',b')      (a,b')-(a',b)        (a,b)-(a',b')\n");
		fprintf(ofp, "\n");
		fprintf(ofp, "\n");
		fprintf(ofp, "For more information about likelihood-mapping refer to\n");
		fprintf(ofp, "   Strimmer and von Haeseler (1997) PNAS 94:6815-6819\n");
		fprintf(ofp, "and/or\n");
		fprintf(ofp, "   Schmidt and von Haeseler (2003) Current Protocols in Bioinformatics\n");
		fprintf(ofp, "   (by Baxevanis et al., Eds.), Unit 6, Wiley&Sons, New York.\n");
		fprintf(ofp, "\n");
		fprintf(ofp, "\n");
		fprintf(ofp, "\n");
		fflush(ofp);

		fprintf(ofp, "\n");
		fprintf(ofp, "Quartet support of regions a1, a2, a3:\n");
		fprintf(ofp, "\n");
		qcountarray[Maxspc][LM_AR1] = 0;
		qcountarray[Maxspc][LM_AR2] = 0;
		qcountarray[Maxspc][LM_AR3] = 0;
		fprintf(ofp, "     name       ");
		fprintf(ofp, "#quartets ");
		fprintf(ofp, "   a1 (%% a1)    ");
		fprintf(ofp, "   a2 (%% a2)    ");
		fprintf(ofp, "   a3 (%% a3)  \n");
		fprintf(ofp, "-----------------------------------------------------------------------------\n");
		for (i=0; i<Maxspc; i++){
			sum=qcountarray[i][LM_AR1] + qcountarray[i][LM_AR2] + qcountarray[i][LM_AR3];
			fprintf(ofp, "%3d %10s ", i+1, Namestr[i]);
			fprintf(ofp, "%9lu ", sum);
			fprintf(ofp, "%6lu (%6.2f) ", qcountarray[i][LM_AR1],  100.0*(double)qcountarray[i][LM_AR1]/(double)sum);
			fprintf(ofp, "%6lu (%6.2f) ", qcountarray[i][LM_AR2],  100.0*(double)qcountarray[i][LM_AR2]/(double)sum);
			fprintf(ofp, "%6lu (%6.2f) ", qcountarray[i][LM_AR3],  100.0*(double)qcountarray[i][LM_AR3]/(double)sum);
			qcountarray[Maxspc][LM_AR1] += qcountarray[i][LM_AR1];
			qcountarray[Maxspc][LM_AR2] += qcountarray[i][LM_AR2];
			qcountarray[Maxspc][LM_AR3] += qcountarray[i][LM_AR3];
			fprintf(ofp, "\n");
		}
		fprintf(ofp, "-----------------------------------------------------------------------------\n");
		sum=(qcountarray[Maxspc][LM_AR1] + qcountarray[Maxspc][LM_AR2] + qcountarray[Maxspc][LM_AR3]) / 4;
		fprintf(ofp, "               ");
		fprintf(ofp, "%9lu ", sum);
		fprintf(ofp, "%6lu (%6.2f) ", qcountarray[Maxspc][LM_AR1] / 4, 25.0*(double)qcountarray[Maxspc][LM_AR1]/(double)sum);
		fprintf(ofp, "%6lu (%6.2f) ", qcountarray[Maxspc][LM_AR2] / 4, 25.0*(double)qcountarray[Maxspc][LM_AR2]/(double)sum);
		fprintf(ofp, "%6lu (%6.2f) ", qcountarray[Maxspc][LM_AR3] / 4, 25.0*(double)qcountarray[Maxspc][LM_AR3]/(double)sum);
		fprintf(ofp, "\n");
		fprintf(ofp, "\n");
		fprintf(ofp, "\n");
		fflush(ofp);

		fprintf(ofp, "\n");
		fprintf(ofp, "Quartet support of areas 1-7:\n");
		fprintf(ofp, "\n");
		qcountarray[Maxspc][LM_REG1] = 0;
		qcountarray[Maxspc][LM_REG2] = 0;
		qcountarray[Maxspc][LM_REG3] = 0;
		qcountarray[Maxspc][LM_REG4] = 0;
		qcountarray[Maxspc][LM_REG5] = 0;
		qcountarray[Maxspc][LM_REG6] = 0;
		qcountarray[Maxspc][LM_REG7] = 0;
		fprintf(ofp, "                ");
		fprintf(ofp, "          ");
		fprintf(ofp, "    resolved    ");
		fprintf(ofp, "                ");
		fprintf(ofp, "                ");
		fprintf(ofp, "    partly      ");
		fprintf(ofp, "                ");
		fprintf(ofp, "                ");
		fprintf(ofp, "    unresolved  \n");

		fprintf(ofp, "     name       ");
		fprintf(ofp, "#quartets ");
		fprintf(ofp, "    1 (%% 1)     ");
		fprintf(ofp, "    2 (%% 2)     ");
		fprintf(ofp, "    3 (%% 3)     ");
		fprintf(ofp, "    4 (%% 4)     ");
		fprintf(ofp, "    5 (%% 5)     ");
		fprintf(ofp, "    6 (%% 6)     ");
		fprintf(ofp, "    7 (%% 7)   \n");
		fprintf(ofp, "-------------------------------------------------------------------------------------------------------------------------------------------------\n");
		for (i=0; i<Maxspc; i++){
			sum=qcountarray[i][LM_AR1] + qcountarray[i][LM_AR2] + qcountarray[i][LM_AR3];
			fprintf(ofp, "%3d %10s ", i+1, Namestr[i]);
			fprintf(ofp, "%9lu ", sum);
			fprintf(ofp, "%6lu (%6.2f) ", qcountarray[i][LM_REG1], 100.0*(double)qcountarray[i][LM_REG1]/(double)sum);
			fprintf(ofp, "%6lu (%6.2f) ", qcountarray[i][LM_REG2], 100.0*(double)qcountarray[i][LM_REG2]/(double)sum);
			fprintf(ofp, "%6lu (%6.2f) ", qcountarray[i][LM_REG3], 100.0*(double)qcountarray[i][LM_REG3]/(double)sum);
			fprintf(ofp, "%6lu (%6.2f) ", qcountarray[i][LM_REG4], 100.0*(double)qcountarray[i][LM_REG4]/(double)sum);
			fprintf(ofp, "%6lu (%6.2f) ", qcountarray[i][LM_REG5], 100.0*(double)qcountarray[i][LM_REG5]/(double)sum);
			fprintf(ofp, "%6lu (%6.2f) ", qcountarray[i][LM_REG6], 100.0*(double)qcountarray[i][LM_REG6]/(double)sum);
			fprintf(ofp, "%6lu (%6.2f) ", qcountarray[i][LM_REG7], 100.0*(double)qcountarray[i][LM_REG7]/(double)sum);
			qcountarray[Maxspc][LM_REG1] += qcountarray[i][LM_REG1];
			qcountarray[Maxspc][LM_REG2] += qcountarray[i][LM_REG2];
			qcountarray[Maxspc][LM_REG3] += qcountarray[i][LM_REG3];
			qcountarray[Maxspc][LM_REG4] += qcountarray[i][LM_REG4];
			qcountarray[Maxspc][LM_REG5] += qcountarray[i][LM_REG5];
			qcountarray[Maxspc][LM_REG6] += qcountarray[i][LM_REG6];
			qcountarray[Maxspc][LM_REG7] += qcountarray[i][LM_REG7];
			fprintf(ofp, "\n");
		}
		fprintf(ofp, "-------------------------------------------------------------------------------------------------------------------------------------------------\n");
		sum=(qcountarray[Maxspc][LM_AR1] + qcountarray[Maxspc][LM_AR2] + qcountarray[Maxspc][LM_AR3]) / 4;
		fprintf(ofp, "               ");
		fprintf(ofp, "%9lu ", sum);
		fprintf(ofp, "%6lu (%6.2f) ", qcountarray[Maxspc][LM_REG1] / 4, 25.0*(double)qcountarray[Maxspc][LM_REG1]/(double)sum);
		fprintf(ofp, "%6lu (%6.2f) ", qcountarray[Maxspc][LM_REG2] / 4, 25.0*(double)qcountarray[Maxspc][LM_REG2]/(double)sum);
		fprintf(ofp, "%6lu (%6.2f) ", qcountarray[Maxspc][LM_REG3] / 4, 25.0*(double)qcountarray[Maxspc][LM_REG3]/(double)sum);
		fprintf(ofp, "%6lu (%6.2f) ", qcountarray[Maxspc][LM_REG4] / 4, 25.0*(double)qcountarray[Maxspc][LM_REG4]/(double)sum);
		fprintf(ofp, "%6lu (%6.2f) ", qcountarray[Maxspc][LM_REG5] / 4, 25.0*(double)qcountarray[Maxspc][LM_REG5]/(double)sum);
		fprintf(ofp, "%6lu (%6.2f) ", qcountarray[Maxspc][LM_REG6] / 4, 25.0*(double)qcountarray[Maxspc][LM_REG6]/(double)sum);
		fprintf(ofp, "%6lu (%6.2f) ", qcountarray[Maxspc][LM_REG7] / 4, 25.0*(double)qcountarray[Maxspc][LM_REG7]/(double)sum);
		fprintf(ofp, "\n");
		fprintf(ofp, "\n");
		fprintf(ofp, "\n");
		fflush(ofp);

		fprintf(ofp, "\n");
		fprintf(ofp, "Quartet resolution per sequence:\n");
		fprintf(ofp, "\n");
		res    =partres    =unres    =0;
		res_all=partres_all=unres_all=0;
		fprintf(ofp, "\n");
		fprintf(ofp, "\n");
		fprintf(ofp, "     name       ");
		fprintf(ofp, "#quartets ");
		fprintf(ofp, "   resolved      ");
		fprintf(ofp, "   partly        ");
		fprintf(ofp, "   unresolved    \n");
		fprintf(ofp, "-----------------------------------------------------------------------------\n");
		for (i=0; i<Maxspc; i++){
			res    =qcountarray[i][LM_REG1] + qcountarray[i][LM_REG2] + qcountarray[i][LM_REG3];
			partres=qcountarray[i][LM_REG4] + qcountarray[i][LM_REG5] + qcountarray[i][LM_REG6];
			unres  =qcountarray[i][LM_REG7];
			sum = res + partres + unres;
			fprintf(ofp, "%3d %10s ", i+1, Namestr[i]);
			fprintf(ofp, "%9lu ", sum);
			fprintf(ofp, "%6lu (%6.2f) ", res,     100.0*(double)res    /(double)sum);
			fprintf(ofp, "%6lu (%6.2f) ", partres, 100.0*(double)partres/(double)sum);
			fprintf(ofp, "%6lu (%6.2f) ", unres,   100.0*(double)unres  /(double)sum);
			res_all     += res;
			partres_all += partres;
			unres_all   += unres;
			fprintf(ofp, "\n");
		}
		fprintf(ofp, "-----------------------------------------------------------------------------\n");
		sum = res_all + partres_all + unres_all;
		fprintf(ofp, "               ");
		fprintf(ofp, "%9lu ", sum / 4);
		fprintf(ofp, "%6lu (%6.2f) ", res_all     / 4, 100.0*(double)res_all     /(double)sum);
		fprintf(ofp, "%6lu (%6.2f) ", partres_all / 4, 100.0*(double)partres_all /(double)sum);
		fprintf(ofp, "%6lu (%6.2f) ", unres_all   / 4, 100.0*(double)unres_all   /(double)sum);
		fprintf(ofp, "\n");
		fprintf(ofp, "\n");
		fprintf(ofp, "\n");
		fflush(ofp);

		fprintf(ofp, "\n");
		fprintf(ofp, "Overall quartet resolution:\n");
		fprintf(ofp, "\n");
		fprintf(ofp, "Number of resolved        quartets (regions 1+2+3): %6lu (= %6.2f%%)\n", res_all     / 4, 100.0*(double)res_all     /(double)sum);
		fprintf(ofp, "Number of partly resolved quartets (regions 4+5+6): %6lu (= %6.2f%%)\n", partres_all / 4, 100.0*(double)partres_all /(double)sum);
		fprintf(ofp, "Number of unresolved      quartets (region 7):      %6lu (= %6.2f%%)\n", unres_all   / 4, 100.0*(double)unres_all   /(double)sum);


		if (savelmaptab_optn) {
			res_all     = 0;
			partres_all = 0;
			unres_all   = 0;
			openfiletowrite(&lmaptabfp, LMAPTAB, "likelihood mapping table", stdinput_fp);
			for (i=0; i<Maxspc; i++){
				res    =qcountarray[i][LM_REG1] + qcountarray[i][LM_REG2] + qcountarray[i][LM_REG3];
				partres=qcountarray[i][LM_REG4] + qcountarray[i][LM_REG5] + qcountarray[i][LM_REG6];
				unres  =qcountarray[i][LM_REG7];
				sum = res + partres + unres;
				fprintf(lmaptabfp, "%s", Namestr[i]);
				fprintf(lmaptabfp, "\t%lu", sum);
				fprintf(lmaptabfp, "\t%.4f", 100.0*(double)res    /(double)sum);
				fprintf(lmaptabfp, "\t%.4f", 100.0*(double)partres/(double)sum);
				fprintf(lmaptabfp, "\t%.4f", 100.0*(double)unres  /(double)sum);
				res_all     += res;
				partres_all += partres;
				unres_all   += unres;
				fprintf(lmaptabfp, "\n");
			}
			sum = res_all + partres_all + unres_all;
			fprintf(lmaptabfp, "Overall");
			fprintf(lmaptabfp, "\t%lu", sum / 4);
			fprintf(lmaptabfp, "\t%.4f", 100.0*(double)res_all    /(double)sum);
			fprintf(lmaptabfp, "\t%.4f", 100.0*(double)partres_all/(double)sum);
			fprintf(lmaptabfp, "\t%.4f", 100.0*(double)unres_all  /(double)sum);
			closefile(lmaptabfp);
		} /* if savelmaptab_optn */

	} /* if typ_optn == LIKMAPING_OPTN */

    
   } /* if WRITEREST || WRITEALL */
} /* writeoutputfile */


#if PARALLEL
void writetimesstat(FILE *ofp)
{
	int n;
	double cpusum = 0.0;
	double wallmax = 0.0;
	cputimes[0]      = ((double)(cputimestop - cputimestart) / CLOCKS_PER_SEC);
	walltimes[0]     = difftime(walltimestop, walltimestart);
	fullcpu          = tarr.fullcpu;
	fulltime         = tarr.fulltime;
	fullcputimes[0]  = tarr.fullcpu;
	fullwalltimes[0] = tarr.fulltime;
	altcputimes[0]   = tarr.cpu;
	altwalltimes[0]  = tarr.time;
   	fprintf(ofp, "\n\n\nPARALLEL LOAD STATISTICS\n\n");
	
	fprintf(ofp, "The analysis was performed with %d parallel processes (1 master and \n", PP_NumProcs);
	fprintf(ofp, "%d worker processes).\n\n", PP_NumProcs-1);
	fprintf(ofp, "The following table the distribution of computation to the processes.\n");
	fprintf(ofp, "The first column gives the process number, where 0 is the master process.\n");
	fprintf(ofp, "The second and third column show the number of quartets computed (3 topologies \n");
	fprintf(ofp, "each) and the the number of scheduling blocks the came in. The last two columns \n");
	fprintf(ofp, "state the number of puzzling steps done by a process and number of scheduling \n");
	fprintf(ofp, "blocks.\n\n");
   	fprintf(ofp, "process  #quartets #chunks  #puzzlings #chunks \n");
   	fprintf(ofp, "-----------------------------------------------\n");
	for (n=0; n<PP_NumProcs; n++) {
   		fprintf(ofp, "%6d  %9d %7d  %10d %7d \n", n,
			quartsent[n], quartsentn[n],
			splitsent[n], splitsentn[n]);
	} /* for */
   	fprintf(ofp, "-----------------------------------------------\n");
   	fprintf(ofp, " Sums:  %9d %7d  %10d %7d \n",
		PP_quartrecved, PP_quartrecvedn,
		PP_splitrecved, PP_splitrecvedn);

#ifdef TIMEDEBUG
	fprintf(ofp, "\n\nBelow the distribution of computing times (CPU and wallclock) per host is shown.\n");
	fprintf(ofp, "The times are shown in seconds, minutes, and hours. At the bottom of the table the\n");
	fprintf(ofp, "sum of CPU times and the maximum wallclock time is shown.\n\n");
   	fprintf(ofp, "process   CPU-time[s]     [min]   [hours] | wallclock[s]     [min]   [hours] \n");
   	fprintf(ofp, "----------------------------------------------------------------------------\n");
	for (n=0; n<PP_NumProcs; n++) {

#		ifdef TIMEDEBUG
   		fprintf(ofp, "%6d   %11.1f %9.1f %9.1f  | %11.1f %9.1f %9.1f\n", n,
			cputimes[n],  cputimes[n] /60, cputimes[n] /3600,
			walltimes[n], walltimes[n]/60, walltimes[n]/3600);
#		endif /* TIMEDEBUG */

   		fprintf(ofp, "%6d   %11.1f %9.1f %9.1f  | %11.1f %9.1f %9.1f\n", n,
			fullcputimes[n],  fullcputimes[n] /60, fullcputimes[n] /3600,
			fullwalltimes[n], fullwalltimes[n]/60, fullwalltimes[n]/3600);

#		ifdef TIMEDEBUG
   		fprintf(ofp, "%6d   %11.1f %9.1f %9.1f  | %11.1f %9.1f %9.1f alt\n", n,
			altcputimes[n],  altcputimes[n] /60, altcputimes[n] /3600,
			altwalltimes[n], altwalltimes[n]/60, altwalltimes[n]/3600);
#		endif /* TIMEDEBUG */

		if (fullwalltimes[n] > wallmax) wallmax=fullwalltimes[n];
		cpusum += fullcputimes[n];
	} /* for */
   	fprintf(ofp, "----------------------------------------------------------------------------\n");
   	fprintf(ofp, "Sum/Max: %11.1f %9.1f %9.1f  | %11.1f %9.1f %9.1f \n",
		cpusum, cpusum/60, cpusum/3600, wallmax, wallmax/60, wallmax/3600);
#else /* TIMEDEBUG */
	fprintf(ofp, "\n\nBelow the distribution of computing times (wallclock) per host is shown.\n");
	fprintf(ofp, "The times are shown in seconds, minutes, and hours. At the bottom of the table the\n");
	fprintf(ofp, "the maximum wallclock times is shown.\n\n");
   	fprintf(ofp, "process   wallclock[s]     [min]   [hours] \n");
   	fprintf(ofp, "----------------------------------------------------------------------------\n");
	for (n=0; n<PP_NumProcs; n++) {

#		ifdef TIMEDEBUG
   		fprintf(ofp, "%6d   %11.1f %9.1f %9.1f\n", n,
			walltimes[n], walltimes[n]/60, walltimes[n]/3600);
#		endif /* TIMEDEBUG */

   		fprintf(ofp, "%6d   %11.1f %9.1f %9.1f\n", n,
			fullwalltimes[n], fullwalltimes[n]/60, fullwalltimes[n]/3600);

#		ifdef TIMEDEBUG
   		fprintf(ofp, "%6d   %11.1f %9.1f %9.1f alt\n", n,
			altwalltimes[n], altwalltimes[n]/60, altwalltimes[n]/3600);
#		endif /* TIMEDEBUG */

		if (fullwalltimes[n] > wallmax) wallmax=fullwalltimes[n];
		cpusum += fullcputimes[n];
	} /* for */
   	fprintf(ofp, "----------------------------------------------------------------------------\n");
   	fprintf(ofp, "Sum/Max: %11.1f %9.1f %9.1f \n",
		wallmax, wallmax/60, wallmax/3600);
#endif /* TIMEDEBUG */

	fullcpu          = cpusum;
	fulltime         = wallmax;

} /* writetimesstat */
#endif


/* write current user tree to file */
void writecutree(FILE *ofp, int num, int clockmode)
{
	int df;
	double pval, delta;


	if (typ_optn == TREERECON_OPTN) {
	
		
	/***************************************************************************/
	/*  MAXIMUM LIKELIHOOD BRANCH LENGTHS OF USER DEFINED TREE #xxx (NO CLOCK) */
	/***************************************************************************/

		if (puzzlemode == USERTREE) {
			fprintf(ofp, "\n\nMAXIMUM LIKELIHOOD BRANCH LENGTHS OF USER");
			fprintf(ofp, " DEFINED TREE # %d (NO CLOCK)\n\nBranch lengths are computed using", num);
			fprintf(ofp, " the selected model of\nsubstitution and rate heterogeneity.\n\n\n");
			clockmode = 0; /* nonclocklike branch lengths */
			prtopology(ofp, clockmode);
			fprintf(ofp, "\n");
			resulttree(ofp, usebranch_optn, clockmode);
			fprintf(ofp, "\n\nUnrooted user defined tree with maximum likelihood branch lengths");
			fprintf(ofp, "\n(in CLUSTAL W notation):\n\n");
			fputphylogeny(ofp, clockmode, TRUE); /* TRUE => fold lines longer 60 chars */
			fflush(ofp);
		
	/*****************************************************************************/
	/*  MAXIMUM LIKELIHOOD BRANCH LENGTHS OF USER DEFINED TREE #xxx (WITH CLOCK) */
	/*****************************************************************************/

			if (compclock) {
				fprintf(ofp, "\n\nMAXIMUM LIKELIHOOD BRANCH LENGTHS OF USER");
				fprintf(ofp, " DEFINED TREE # %d (WITH CLOCK)\n\nBranch lengths are computed using", num);
				fprintf(ofp, " the selected model of\nsubstitution and rate heterogeneity.\n");
				fprintf(ofp, "\nRoot located at branch: %d ", locroot+1);
				if (locroot<Maxspc) {
					fprintf(ofp, "\""); fputid(ofp,locroot); fprintf(ofp, "\"  ");
				} else	fprintf(ofp, "\"internal branch\"  ");
				if (rootsearch == ROOT_USER) fprintf(ofp, "(user specified)\n\n\n");
				if (rootsearch == ROOT_AUTO) {
					fprintf(ofp, "(automatic search)");
					if (numbestroot > 1) fprintf(ofp, "- WARNING: %d best locations found! -", numbestroot);
					fprintf(ofp, "\n\n");
					fprintf(ofp, "If the automatic search misplaces the root please rerun the analysis\n");
					fprintf(ofp, "and select location of root manually!");
					fprintf(ofp, "\n\n\n");

				}
				if (rootsearch == ROOT_DISPLAYED) fprintf(ofp, "(displayed outgroup)\n\n\n");
				clockmode = 1; /* clocklike branch lengths */
				prtopology(ofp, clockmode);
				fprintf(ofp, "\n");
				resulttree(ofp, usebranch_optn, clockmode);
				fprintf(ofp, "\n");
				resultheights(ofp);
				fprintf(ofp, "\n\nRooted user defined tree with clocklike ");
				fprintf(ofp, "maximum likelihood branch lengths\n");
				fprintf(ofp, "(in CLUSTAL W notation):\n\n");
				fputrooted(ofp, locroot, TRUE);
				fflush(ofp);
			}
			
		
	/*****************************************************************************/
	/*  MOLECULAR CLOCK LIKELIHOOD RATIO TEST FOR USER TREE #xxx                 */
	/*****************************************************************************/

			if (compclock) {
				fprintf(ofp, "\n\nMOLECULAR CLOCK LIKELIHOOD RATIO TEST FOR USER TREE # %d\n\n", num);
				fprintf(ofp, "log L without clock: %.2f (independent branch parameters: %d)\n",
					Ctree->lklhd, Numspc + Numibrnch);
				fprintf(ofp, "log L with clock:    %.2f (independent branch parameters: %d)\n\n",
					Ctree->lklhdc, Numhts + 1);
				delta = fabs(2.0*((Ctree->lklhd) - (Ctree->lklhdc)));
				fprintf(ofp, "Likelihood ratio test statistic delta: %.2f\n", delta);	
				df = Numspc + Numibrnch - Numhts - 1;
				fprintf(ofp, "Degrees of freedom of chi-square distribution: %d\n", df);
				
				pval = IncompleteGammaQ (df*0.5, delta*0.5);
				
				fprintf(ofp, "Critical significance level: %.2f%%\n\n", pval*100.0);
				if (pval >= 0.05) {
					fprintf(ofp, "The simpler (clocklike) tree can not be rejected on a significance\n");
					fprintf(ofp, "level of 5%%. The log-likelihood of the more complex (no clock) tree\n");
					fprintf(ofp, "is not significantly increased.\n");
				} else {
					fprintf(ofp, "The simpler (clocklike) tree is rejected on a significance level\n");
					fprintf(ofp, "of 5%%. The log-likelihood of the more complex (no clock) tree is\n");
					fprintf(ofp, "significantly increased.\n");
				}
				fprintf(ofp, "\nPlease take care that the correct root is used!\n");
			}			
		}	
	}
} /* writecutree */


/******************************************************************************/
/* timer routines                                                             */
/******************************************************************************/

void resetqblocktime(timearray_t *ta)
{
	ta->quartcpu += ta->quartblockcpu;
	ta->quartblockcpu = 0.0;
	ta->quarttime += ta->quartblocktime;
	ta->quartblocktime = 0.0;
} /* resetqblocktime */


void resetpblocktime(timearray_t *ta)
{
	ta->puzzcpu += ta->puzzblockcpu;
	ta->puzzblockcpu = 0.0;
	ta->puzztime += ta->puzzblocktime;
	ta->puzzblocktime = 0.0;
} /* resetpblocktime */


#ifdef TIMEDEBUG
void printtimearr(timearray_t *ta)
{
#	if ! PARALLEL
	  int PP_Myid;
	  PP_Myid = -1;
#	endif
	printf("(%2d) MMCPU: %11ld  /  %11ld \n", PP_Myid, ta->maxcpu, ta->mincpu);
	printf("(%2d) CTick: %11.6f [tks]  /  %11.6f [s] \n", PP_Myid, ta->mincputick, ta->mincputicktime);

	printf("(%2d) MMTIM: %11ld  /  %11ld \n", PP_Myid, ta->maxtime, ta->mintime);

	printf("(%2d) Mxblk: %11.6e  /  %11.6e \n", PP_Myid, ta->maxcpublock, ta->maxtimeblock);
	printf("(%2d) Mnblk: %11.6e  /  %11.6e \n", PP_Myid, ta->mincpublock, ta->mintimeblock);

	printf("(%2d) Gnrl: %11.6e  /  %11.6e \n", PP_Myid, ta->generalcpu, ta->generaltime);
	printf("(%2d) Optn: %11.6e  /  %11.6e \n", PP_Myid, ta->optionscpu, ta->optionstime);
	printf("(%2d) Estm: %11.6e  /  %11.6e \n", PP_Myid, ta->paramestcpu, ta->paramesttime);
	printf("(%2d) Qurt: %11.6e  /  %11.6e \n", PP_Myid, ta->quartcpu, ta->quarttime);
	printf("(%2d) QBlk: %11.6e  /  %11.6e \n", PP_Myid, ta->quartblockcpu, ta->quartblocktime);
	printf("(%2d) QMax: %11.6e  /  %11.6e \n", PP_Myid, ta->quartmaxcpu, ta->quartmaxtime);
	printf("(%2d) QMin: %11.6e  /  %11.6e \n", PP_Myid, ta->quartmincpu, ta->quartmintime);

	printf("(%2d) Puzz: %11.6e  /  %11.6e \n", PP_Myid, ta->puzzcpu, ta->puzztime);
	printf("(%2d) PBlk: %11.6e  /  %11.6e \n", PP_Myid, ta->puzzblockcpu, ta->puzzblocktime);
	printf("(%2d) PMax: %11.6e  /  %11.6e \n", PP_Myid, ta->puzzmaxcpu, ta->puzzmaxtime);
	printf("(%2d) PMin: %11.6e  /  %11.6e \n", PP_Myid, ta->puzzmincpu, ta->puzzmintime);

	printf("(%2d) Tree: %11.6e  /  %11.6e \n", PP_Myid, ta->treecpu, ta->treetime);
	printf("(%2d) TBlk: %11.6e  /  %11.6e \n", PP_Myid, ta->treeblockcpu, ta->treeblocktime);
	printf("(%2d) TMax: %11.6e  /  %11.6e \n", PP_Myid, ta->treemaxcpu, ta->treemaxtime);
	printf("(%2d) TMin: %11.6e  /  %11.6e \n", PP_Myid, ta->treemincpu, ta->treemintime);

	printf("(%2d) C/T : %11.6e / %11.6e \n", PP_Myid, 
		(ta->generalcpu + ta->optionscpu + ta->paramestcpu + ta->quartblockcpu + ta->puzzblockcpu + ta->treeblockcpu),
		(ta->generaltime + ta->optionstime + ta->paramesttime + ta->quartblocktime + ta->puzzblocktime + ta->treeblocktime));
	printf("(%2d)  CPU: %11.6e /  Time: %11.6e \n", PP_Myid, ta->cpu, ta->time);
	printf("(%2d) aCPU: %11.6e / aTime: %11.6e \n", PP_Myid, ta->fullcpu, ta->fulltime);

} /* printtimearr */
#endif /* TIMEDEBUG */

char *jtype [7];

void inittimearr(timearray_t *ta)
{
	clock_t c0, c1, c2; 

	jtype[OVERALL]  = "OVERALL";
	jtype[GENERAL]  = "GENERAL";
	jtype[OPTIONS]  = "OPTIONS";
	jtype[PARAMEST] = "PARAMeter ESTimation";
	jtype[QUARTETS] = "QUARTETS";
	jtype[PUZZLING] = "PUZZLING steps";
	jtype[TREEEVAL] = "TREE EVALuation";
	ta->currentjob = GENERAL;

	c1 = clock();
	c2 = clock();
	while (c1 == c2)
	   c2 = clock(); 
	ta->mincputick = (double)(c2 - c1);
	ta->mincputicktime = ((double)(c2 - c1))/CLOCKS_PER_SEC;

	ta->tempcpu = clock();
	ta->tempcpustart = ta->tempcpu;
	ta->tempfullcpu  = ta->tempcpu;
	time(&(ta->temptime));
	ta->temptimestart = ta->temptime;
        ta->tempfulltime  = ta->temptime;

	c0=0; c1=0; c2=(clock_t)((2 * c1) + 1);;
	while (c1 < c2) {
	   c0 = c1;
	   c1 = c2;
	   c2 = (clock_t)((2 * c1) + 1);
	}
	if (c1 == c2) ta->maxcpu=c0;
	if (c1  > c2) ta->maxcpu=c1;

	c0=0; c1=0; c2=(clock_t)((2 * c1) - 1);
	while (c1 > c2) {
	   c0 = c1;
	   c1 = c2;
	   c2 = (clock_t)((2 * c1) - 1);
	}
	if (c1 == c2) ta->mincpu=c0;
	if (c1  < c2) ta->mincpu=c1;



	ta->maxtime        = 0;
	ta->mintime        = 0;

	ta->maxcpublock    = 0;
	ta->mincpublock    = DBL_MAX;
	ta->maxtimeblock   = 0;
	ta->mintimeblock   = DBL_MAX;

	ta->cpu            = 0.0;
	ta->time           = 0.0;

	ta->fullcpu        = 0.0;
	ta->fulltime       = 0.0;

	ta->generalcpu     = 0.0;
	ta->optionscpu     = 0.0;
	ta->paramestcpu    = 0.0;
	ta->quartcpu       = 0.0;
	ta->quartblockcpu  = 0.0;
	ta->quartmaxcpu    = 0.0;
	ta->quartmincpu    = ((double) ta->maxcpu)/CLOCKS_PER_SEC;
	ta->puzzcpu        = 0.0;
	ta->puzzblockcpu   = 0.0;
	ta->puzzmaxcpu     = 0.0;
	ta->puzzmincpu     = ((double) ta->maxcpu)/CLOCKS_PER_SEC;
	ta->treecpu        = 0.0;
	ta->treeblockcpu   = 0.0;
	ta->treemaxcpu     = 0.0;
	ta->treemincpu     = ((double) ta->maxcpu)/CLOCKS_PER_SEC;

	ta->generaltime    = 0.0;
	ta->optionstime    = 0.0;
	ta->paramesttime   = 0.0;
	ta->quarttime      = 0.0;
	ta->quartblocktime = 0.0;
	ta->quartmaxtime   = 0.0;
	ta->quartmintime   = DBL_MAX;
	ta->puzztime       = 0.0;
	ta->puzzblocktime  = 0.0;
	ta->puzzmaxtime    = 0.0;
	ta->puzzmintime    = DBL_MAX;
	ta->treetime       = 0.0;
	ta->treeblocktime  = 0.0;
	ta->treemaxtime    = 0.0;
	ta->treemintime    = DBL_MAX;
} /* inittimearr */


/***************/

void addup(int jobtype, clock_t c1, clock_t c2, time_t t1, time_t t2, timearray_t *ta)
{
   double  c,
           t;

   if (t2 != t1) t = difftime(t2, t1); 
   else          t = 0.0;

   if (c2 < c1)
      c = ((double)(c2 - ta->mincpu))/CLOCKS_PER_SEC +
          ((double)(ta->maxcpu - c1))/CLOCKS_PER_SEC;
   else
      c = ((double)(c2 - c1))/CLOCKS_PER_SEC;

   if (jobtype != OVERALL) {

      if (ta->mincpublock  > c) ta->mincpublock = c;
      if (ta->maxcpublock  < c) ta->maxcpublock = c;
      if (ta->mintimeblock > t) ta->mintimeblock = t;
      if (ta->maxtimeblock < t) ta->maxtimeblock = t;

      switch (jobtype) {
         case GENERAL: ta->generalcpu  += c;
                       ta->generaltime += t;
                       break;
         case OPTIONS: ta->optionscpu  += c;
                       ta->optionstime += t;
                       break;
         case PARAMEST: ta->paramestcpu  += c;
                        ta->paramesttime += t;
                        break;
         case QUARTETS: ta->quartblockcpu  += c;
                        ta->quartblocktime += t;
                        if (ta->quartmincpu  > c) ta->quartmincpu = c;
                        if (ta->quartmaxcpu  < c) ta->quartmaxcpu = c;
                        if (ta->quartmintime > t) ta->quartmintime = t;
                        if (ta->quartmaxtime < t) ta->quartmaxtime = t;
                        break;
         case PUZZLING: ta->puzzblockcpu  += c;
                        ta->puzzblocktime += t;
                        if (ta->puzzmincpu  > c) ta->puzzmincpu = c;
                        if (ta->puzzmaxcpu  < c) ta->puzzmaxcpu = c;
                        if (ta->puzzmintime > t) ta->puzzmintime = t;
                        if (ta->puzzmaxtime < t) ta->puzzmaxtime = t;
                        break;
         case TREEEVAL: ta->treeblockcpu  += c;
                        ta->treeblocktime += t;
                        if (ta->treemincpu  > c) ta->treemincpu = c;
                        if (ta->treemaxcpu  < c) ta->treemaxcpu = c;
                        if (ta->treemintime > t) ta->treemintime = t;
                        if (ta->treemaxtime < t) ta->treemaxtime = t;
                        break;
      }
      ta->cpu  += c;
      ta->time += t;
   
   } else {
         ta->fullcpu  += c;
         ta->fulltime += t;
   }

#     ifdef TIMEDEBUG
         {
#        if ! PARALLEL
            int PP_Myid =  -1;
#        endif /* !PARALLEL */
         printf("(%2d) CPU: +%10.6f / Time: +%10.6f (%s)\n", PP_Myid, c, t, jtype[jobtype]);
         printf("(%2d) CPU: %11.6f / Time: %11.6f (%s)\n", PP_Myid, ta->cpu, ta->time, jtype[jobtype]);
         printf("(%2d) CPU: %11.6f / Time: %11.6f (%s)\n", PP_Myid, ta->fullcpu, ta->fulltime, jtype[jobtype]);
         }
#     endif /* TIMEDEBUG */
} /* addup */


/***************/


void addtimes(int jobtype, timearray_t *ta)
{
   clock_t tempc;
   time_t  tempt;

   time(&tempt);
   tempc = clock();

   if ((tempc < ta->tempfullcpu) || (jobtype == OVERALL)) {   /* CPU counter overflow for overall time */
   	addup(OVERALL, ta->tempfullcpu, tempc, ta->tempfulltime, tempt, ta);
	ta->tempfullcpu  = tempc;
	ta->tempfulltime = tempt;
        if (jobtype == OVERALL) {
   	   addup(ta->currentjob, ta->tempcpustart, tempc, ta->temptimestart, tempt, ta);
	   ta->tempcpustart = ta->tempcpu;
	   ta->tempcpu      = tempc;
	   ta->temptimestart = ta->temptime;
	   ta->temptime      = tempt;
        }
   }

   if((jobtype != ta->currentjob) && (jobtype != OVERALL)) {   /* change of job type */
   	addup(ta->currentjob, ta->tempcpustart, ta->tempcpu, ta->temptimestart, ta->temptime, ta);
	ta->tempcpustart  = ta->tempcpu;
	ta->tempcpu       = tempc;
	ta->temptimestart = ta->temptime;
	ta->temptime      = tempt;
	ta->currentjob    = jobtype;
   }

   if (tempc < ta->tempcpustart) {   /* CPU counter overflow */
   	addup(jobtype, ta->tempcpustart, tempc, ta->temptimestart, tempt, ta);
	ta->tempcpustart = ta->tempcpu;
	ta->tempcpu      = tempc;
	ta->temptimestart = ta->temptime;
	ta->temptime      = tempt;
   }

} /* addtimes */



/******************************************************************************/
/* moved to mlparam.c                                                         */
/******************************************************************************/

#if 0
/* estimate parameters of substitution process and rate heterogeneity - no tree
   n-taxon tree is not needed because of quartet method or NJ tree topology */
void estimateparametersnotree() /* moved to mlparam.c */

/* estimate parameters of substitution process and rate heterogeneity - tree
   same as above but here the n-taxon tree is already in memory */
void estimateparameterstree() /* moved to mlparam.c */
#endif


/******************************************************************************/
/* exported from main                                                         */
/******************************************************************************/

/* evaluate ab|cd ac|bd ad|bc, give ML values and inner branch lengths */
void compute_quartlklhds(int a, int b, int c, int d, 
			double *d1, double *d2, double *d3, 
			double *iblen1, double *iblen2, double *iblen3, 
			int approx)
{
	if (approx == QUART_APPROX) {

		*d1 = quartet_alklhd(a,b, c,d, iblen1); /* (a,b)-(c,d) */
		*d2 = quartet_alklhd(a,c, b,d, iblen2); /* (a,c)-(b,d) */
		*d3 = quartet_alklhd(a,d, b,c, iblen3); /* (a,d)-(b,c) */

	} else /* approx == QUART_EXACT */ {

		*d1 = quartet_lklhd(a,b, c,d, iblen1);  /* (a,b)-(c,d) */
		*d2 = quartet_lklhd(a,c, b,d, iblen2);  /* (a,c)-(b,d) */
		*d3 = quartet_lklhd(a,d, b,c, iblen3);  /* (a,d)-(b,c) */

	}
} /* compute_quartlklhds */

/***************************************************************/ 
/* compute the approximate likelihood for (a,b)-(c,d) quartet */
double quartet_ME(int a, int b, int c, int d, dmatrix distanmat)
{
	double me;

	me = distanmat[a][b] + distanmat[a][b]
	     + distanmat[a][c]
	     + distanmat[a][d]
	     + distanmat[b][c]
	     + distanmat[b][d]
	     + distanmat[c][d] + distanmat[c][d];

#if 0  
	/* ????????? */
	me = distanmat[a][b] * distanmat[a][b]
	     + distanmat[a][c]
	     + distanmat[a][d]
	     + distanmat[b][c]
	     + distanmat[b][d]
	     + distanmat[c][d] * distanmat[c][d];
#endif

	return (me / 4);
} /* quartet_ME */


/***************************************************************/ 
void compute_quartME(int a, int b, int c, int d, double *d1, double *d2, double *d3, dmatrix distanmat)
{
	*d1 = quartet_ME(a,b, c,d, distanmat); /* (a,b)-(c,d) */
	*d2 = quartet_ME(a,c, b,d, distanmat); /* (a,c)-(b,d) */
	*d3 = quartet_ME(a,d, b,c, distanmat); /* (a,d)-(b,c) */
} /* compute_quartME */

/***************************************************************/ 
void compute_quartNJ(int a, int b, int c, int d, double *d1, double *d2, double *d3, dmatrix distanmat)
{
	double ua;
	double ub;
	double uc;
	double ud;
	double Dab, Dac, Dad, Dbc, Dbd, Dcd;
	double min;
	int min1, min2;

	/* 
	 * NJ (sensu Felsenstein, 2003/4)
	 *          n 
	 *         ---
	 *         \
	 *   u_i = /   D_ij     / (n-2)
	 *         ---
	 *         j=1  
	 *         j!=i   
	 *            
	 *  join(a,b) with a,b  min( D_ab - ua - ub ) 
	 */

	ua = (distanmat[a][b] + distanmat[a][c] + distanmat[a][d]) / 2;
	ub = (distanmat[a][b] + distanmat[b][c] + distanmat[b][d]) / 2;
	uc = (distanmat[a][c] + distanmat[b][c] + distanmat[c][d]) / 2;
	ud = (distanmat[a][d] + distanmat[b][d] + distanmat[c][d]) / 2;

	Dab = distanmat[a][b] - ua - ub;
	Dac = distanmat[a][c] - ua - uc;
	Dad = distanmat[a][d] - ua - ud;
	Dbc = distanmat[b][c] - ub - uc;
	Dbd = distanmat[b][d] - ub - ud;
	Dcd = distanmat[c][d] - uc - ud;

	min1 = a;
	min2 = b;
	min  = Dab;

	if (min > Dac) { min = Dac; min1 = a; min2 = c; }
	if (min > Dad) { min = Dad; min1 = a; min2 = d; }
	if (min > Dbc) { min = Dbc; min1 = b; min2 = c; }
	if (min > Dbd) { min = Dbd; min1 = b; min2 = d; }
	if (min > Dcd) { min = Dcd; min1 = c; min2 = d; }

#if 0
	*d1 = quartet_ME(a,b, c,d, distanmat); /* (a,b)-(c,d) */
	*d2 = quartet_ME(a,c, b,d, distanmat); /* (a,c)-(b,d) */
	*d3 = quartet_ME(a,d, b,c, distanmat); /* (a,d)-(b,c) */
#endif
} /* compute_quartNJ */

#if 0
/***************************************************************/ 
void compute_quartMP(int a, int b, int c, int d, double *d1, double *d2, double *d3, dmatrix distanmat, int )
{
	uli num_ab = 0;
	uli num_ac = 0;
	uli num_ad = 0;
	int ca, cb, cc, cd, gap;
	int site;

	if (data_optn == NUCLEOTIDE) { /* nucleotides */
		if (nuc_optn) gap=4; /* nuc - 4x4 */
		if (SH_optn) gap=16; /* SH - 16x16 */
	} else if (data_optn == AMINOACID) { /* amino acids */
		gap=20;
	} else { /* two-state model - BINARY */
		gap=2;
	} /* two-state model */


	for (site=0; site < len; site++) {
		ca = ali[a][site];
		cb = ali[b][site];
		cc = ali[c][site];
		cd = ali[d][site];

		if (ca!=gap && cb!=gap && cc!=gap && cd!=gap) { 
			if (ca == cb) { /* (ab|cd) */
				if (cc == cd) {
					if (ca != cc) num_ab++;
				}
			} else { /* no (ab|cd) */
				if (ca == cc) { /* (ac|bd) */
					if (cb == cd) {
						if (ca != cb) num_ac++;
					}
				} else { /* no (ac|bd) */
					if (ca == cd) { /* (ad|bc) */
						if (cb == cc) {
							if (ca != cb) num_ad++;
						}
					} /* end (ad|bc) */
				} /* end no (ac|bd) */
			} /* end no (ab|cd) */
		} /* end if not gapped */
	} /* for all site */
	

	*d1 = (double)num_ab; /* (a,b)-(c,d) */
	*d2 = (double)num_ac; /* (a,c)-(b,d) */
	*d3 = (double)num_ad; /* (a,d)-(b,c) */
} /* compute_quartMP */

#endif
/***************************************************************/ 

/* Reconstruct a tree with QP */
/* (parameter estimation already done) */

void recon_tree()
{
	int i;
	unsigned char tmpweight;

	/***********************************/
	/*** allocation + initialization ***/
	/***********************************/

	/* allocate and initialize qinfomatr */
	qinfomatr = new_ulimatrix(9,Maxspc);
	for (i = 0; i < Maxspc; i++) {
		qinfomatr[0][i] = 0;	/* missing quartets */
		qinfomatr[1][i] = 0;	/* fully resolved quartet 1 for taxon i */
		qinfomatr[2][i] = 0;	/* fully resolved quartet 2 for taxon i */
		qinfomatr[3][i] = 0;	/* fully resolved quartet 3 for taxon i */
		qinfomatr[4][i] = 0;	/* partly resolved quartet 1 for taxon i */
		qinfomatr[5][i] = 0;	/* partly resolved quartet 2 for taxon i */
		qinfomatr[6][i] = 0;	/* partly resolved quartet 3 for taxon i */
		qinfomatr[7][i] = 0;	/* unresolved quartet for taxon i */
		qinfomatr[8][i] = 0;	/* sum of quartets for taxon i */
	}

	/* allocate memory for taxon list of bad quartets */
	badtaxon = new_ulivector(Maxspc);
	for (i = 0; i < Maxspc; i++) badtaxon[i] = 0;

	/* allocate memory for quartets */
	quartetinfo = callocquartets(Maxspc);
	
	/* prepare for consensus tree analysis */
	initconsensus();
		
       	time(&MLstepStarttime);
#	ifdef DEBUG_PRINTTIMES
		fprintftimespan(stdout, PEstStoptime, MLstepStarttime, Starttime, "PEst -> MLstep");
#	endif /* DEBUG_PRINTTIMES */


	/***************/
	/*** ML step ***/
	/***************/

	if (!(readquart_optn) || (readquart_optn && savequart_optn)) {
	  /* compute quartets */
	  fprintf(STDOUT, "Computing quartet maximum likelihood trees\n");
	  fflush(STDOUT);
	  computeallquartets();
	}

	time(&MLstepStoptime);
#	ifdef DEBUG_PRINTTIMES
		fprintftimespan(stdout, MLstepStarttime, MLstepStoptime, Starttime, "MLstep");
#	endif /* DEBUG_PRINTTIMES */


	/** output/input if necessary **/

	if (savequart_optn) 
		writeallquarts(Maxspc, ALLQUART, quartetinfo);
	if (readquart_optn) {
		readallquarts (Maxspc, ALLQUART, quartetinfo);
		if (show_optn) { /* list all unresolved quartets */
			openfiletowrite(&unresfp, UNRESOLVED, "unresolved quartet trees", stdinput_fp);
			fprintf(unresfp, "List of all completely unresolved quartets:\n\n");
		}
		if (readsubset_optn) { /* missing data -> read subsets */
			FILE *ssfp;
			openfiletoread(&ssfp, SUBSET, "taxon subsets", stdinput_fp);
	  		fprintf(STDOUT, "Reading taxon subsets: %s\n", SUBSET);
			
			readsubsetfile(ssfp, Maxspc, Namestr, 
					&Maxsubset, &ss_setovlgraph, 
					&ss_setoverlaps, &ss_setovllist, 
					&ss_setovllistsize, &ss_matrix, 
					&ss_list, &ss_listsize);
#if 0
fprintf(stderr,"Maxspc=%d   Maxsubset=%d\n", Maxspc, Maxsubset);
			fprintfss(stdout, Maxspc, Maxsubset, ss_setovlgraph, 
			        ss_setoverlaps, ss_setovllist, 
			        ss_setovllistsize, ss_matrix, ss_list, 
			        ss_listsize);
#endif
			checkss(stdout, Maxspc, Maxsubset, ss_setovlgraph, 
			        ss_setoverlaps, ss_setovllist, 
			        ss_setovllistsize, ss_matrix, ss_list, 
			        ss_listsize);
		}
	} /* readquart_optn */

#	if !PARALLEL /* do it every time in case of a parallel run - less comunication */
	if (readquart_optn) 
#	endif /* PARALLEL */
		{
		int xx1, xx2, xx3, xx4, count;
		/* initialize qinfomatr */
		for (i = 0; i < Maxspc; i++) {
			qinfomatr[0][i] = 0;	/* missing quartets */
			qinfomatr[1][i] = 0;	/* fully resolved quartet 1 for taxon i */
			qinfomatr[2][i] = 0;	/* fully resolved quartet 2 for taxon i */
			qinfomatr[3][i] = 0;	/* fully resolved quartet 3 for taxon i */
			qinfomatr[4][i] = 0;	/* partly resolved quartet 1 for taxon i */
			qinfomatr[5][i] = 0;	/* partly resolved quartet 2 for taxon i */
			qinfomatr[6][i] = 0;	/* partly resolved quartet 3 for taxon i */
			qinfomatr[7][i] = 0;	/* unresolved quartet for taxon i */
			qinfomatr[8][i] = 0;	/* sum of quartets for taxon i */
		}

		/* initialize bad quartet memory */
		for (count = 0; count < Maxspc; count++) badtaxon[count] = 0;
		badqs = 0;
		fullresqs = 0;
		partresqs = 0;
		unresqs   = 0;
		missingqs = 0;

		for (xx4 = 3; xx4 < Maxspc; xx4++)
		   for (xx3 = 2; xx3 < xx4; xx3++)
		      for (xx2 = 1; xx2 < xx3; xx2++)
		         for (xx1 = 0; xx1 < xx2; xx1++) {
			    tmpweight = readquartet(xx1, xx2, xx3, xx4); 

			    if ((tmpweight <= 0) || (tmpweight >= 8)) { 
				/* 1-7: available quartet */
				/* else: missing quartet (should be 15 = (1111)*/
				tmpweight = 0;
			    }

			    /* compute sums of topologies per taxon, step by step */
			    ++(qinfomatr[8][xx1]);
			    ++(qinfomatr[8][xx2]);
			    ++(qinfomatr[8][xx3]);
			    ++(qinfomatr[8][xx4]);
			    ++(qinfomatr[tmpweight][xx1]);
			    ++(qinfomatr[tmpweight][xx2]);
			    ++(qinfomatr[tmpweight][xx3]);
			    ++(qinfomatr[tmpweight][xx4]);

			    if ((tmpweight <= 2) || (tmpweight == 4)) {
			       fullresqs++;
			    } else {
			       if (tmpweight == 7) {
			          unresqs++;
			       } else {
			          if (tmpweight == 0) {
			             missingqs++;
			          } else {
			             partresqs++;
			          }
			       }
			    }
						
			    if (tmpweight == 7) { /* to be deleted */
				badqs++;
				badtaxon[xx1]++;
				badtaxon[xx2]++;
				badtaxon[xx3]++;
				badtaxon[xx4]++;
				if (show_optn) {
					fputid10(unresfp, xx1);
					fprintf(unresfp, "  ");
					fputid10(unresfp, xx2);
					fprintf(unresfp, "  ");
					fputid10(unresfp, xx3);
					fprintf(unresfp, "  ");
					fputid  (unresfp, xx4);
					fprintf(unresfp, "\n");
				} /* if show_optn */
			    } /* if 7 */ /* to be deleted */
		} /* end for xx4; for xx3; for xx2; for xx1 */
		if (show_optn)  /* list all unresolved quartets */
			fclose(unresfp);
	} /* readquart_optn */

#	if PARALLEL
		PP_SendAllQuarts(numquarts(Maxspc), quartetinfo);
#	endif /* PARALLEL */


	/*********************/
	/*** puzzling step ***/
	/*********************/

	fprintf(STDOUT, "Computing quartet puzzling trees\n");
	fflush(STDOUT);
	
	/* start timer - percentage of completed trees */
	time(&time0);
	time1 = time0;
	mflag = 0;
			
	time(&PStepStarttime);
#	ifdef DEBUG_PRINTTIMES
		fprintftimespan(stdout, MLstepStoptime, PStepStarttime, Starttime, "MLstep -> Pstep");
#	endif /* DEBUG_PRINTTIMES */

	/* open file for chronological list of puzzling step trees */
	if((listqptrees_optn == PSTOUT_LIST) || (listqptrees_optn == PSTOUT_LISTORDER))
		openfiletowrite(&qptlist, OUTPTLIST, "puzzling step trees (chonological)", stdinput_fp);
							
	if(saveptall_optn == PTALL_OUT) {
		FILE *ptf;
		openfiletowrite(&ptf, OUTPTALL, "successive puzzling trees file", stdinput_fp);
		closefile(ptf);
	}

#	if PARALLEL
		PP_SendDoPermutBlock(Numtrial);
#	else /* ! PARALLEL */
		addtimes(GENERAL, &tarr);

		/* loop exported to allpstep */
		allpstep(Numtrial, quartetinfo, Maxspc, fixedorder_optn, rootstart_optn, rootquartsonly_optn); 
#	endif /* else ! PARALLEL */
			
	time(&PStepStoptime);
#	ifdef DEBUG_PRINTTIMES
		fprintftimespan(stdout, PStepStarttime, PStepStoptime, Starttime, "Pstep");
#	endif /* DEBUG_PRINTTIMES */

	/* close file for list of puzzling step trees */
	if((listqptrees_optn == PSTOUT_LIST) || (listqptrees_optn == PSTOUT_LISTORDER))
		closefile(qptlist);

	if (mflag == 1) fprintf(STDOUT, "\n");

	/* garbage collection */
	free(splitcomptemp);

#       if ! PARALLEL
		free_cmatrix(biparts);
#	endif /* ! PARALLEL */


	/**********************/
	/*** consensus step ***/
	/**********************/

	/* compute majority rule consensus tree */
	makeconsensus(Numtrial, qsupport_optn);

	/* write consensus tree to tmp file */
#if 0
	if (skipmlbranch_optn && (puzzlemode == QUARTPUZ)) 
#endif
	if (!dotreelh_optn && (puzzlemode == QUARTPUZ)) {
		openfiletowrite(&tmpfp, TREEFILE, "output tree(s)", stdinput_fp);
		writeconsensustree(tmpfp, FALSE, qsupportarr);
		closefile(tmpfp);
	} else {
		tmpfp = tmpfile();
		writeconsensustree(tmpfp, FALSE, qsupportarr);
	}
} /* recon_tree */

/***************************************************************/ 

/* do likelihood mapping with quartcrit as quartet criterion */
/* TODO: deglobalize: clusterA/B/C/D, clustA/B/C/D, ... */
/* TODO: parallelize */
void map_lklhd(
		int quartcrit, 		/* criterion: ML, MP, ME */
		uli **countarr)	/* quartet counts per sequence */
{	
	int i, a, a1, a2, b, b1, b2, c, c1, c2, d;
#if 0
	int ar; int reg; 
#endif
	uli nq;
	double logs[3], d1, d2, d3, temp;
	double bl1, bl2, bl3;
	ivector qts, mlorder, gettwo;
#if 0
		/* reset variables */
		ar1 = ar2 = ar3 = 0;
		reg1 = reg2 = reg3 = reg4 = reg5 = reg6 = reg7 = 0;
		reg1l = reg1r = reg2u = reg2d = reg3u = reg3d = reg4u =
			reg4d = reg5l = reg5r = reg6u = reg6d = 0;
#endif
			
		/* place for random quartet */
			qts = new_ivector(4);

		/* initialize output file */
		if (lmapeps_optn) {
			openfiletowrite(&triepsfp, TRIANGLEEPS, "Postscript (EPS) output", stdinput_fp);
			initeps(triepsfp);
		}
		if (lmapsvg_optn) {
			openfiletowrite(&trisvgfp, TRIANGLESVG, "SVG output", stdinput_fp);
			initsvg(trisvgfp);
		}

		fprintf(STDOUT, "Performing likelihood mapping analysis\n");
		fflush(STDOUT);
			
		nq = 0;
		mflag = 0;

		addtimes(GENERAL, &tarr);
		if (lmqts == 0) { /* all possible quartets */
			
			if (numclust == 4) { /* four-cluster analysis */

				for (a = 0; a < clustA; a++)
					for (b = 0; b < clustB; b++)
						for (c = 0; c < clustC; c++)
							for (d = 0; d < clustD; d++) {
									
								nq++;
									
								/* maximum likelihood values */
								/* approximate ML is sufficient for likelihood mapping */
								switch (quartcrit) {
									case QUART_MLEXACT:
										compute_quartlklhds(clusterA[a],clusterB[b],clusterC[c],clusterD[d],&d1,&d2,&d3, &bl1, &bl2, &bl3, QUART_EXACT);
										break;
									case QUART_MLAPPROX:
									default:
										compute_quartlklhds(clusterA[a],clusterB[b],clusterC[c],clusterD[d],&d1,&d2,&d3, &bl1, &bl2, &bl3, QUART_APPROX);
										break;
								}

								/* draw point for LM analysis */
								makelmpoint(triepsfp, trisvgfp, d1, d2, d3, 
#if 0
									&reg1, &reg2, &reg3, &reg4, &reg5, &reg6, &reg7, 
									&ar1, &ar2, &ar3, &reg1l, &reg1r, &reg2u, &reg2d, &reg3u, &reg3d, 
									&reg4u, &reg4d, &reg5l, &reg5r, &reg6u, &reg6d, 
									&ar, &reg, 
#endif
									clusterA[a],clusterB[b],clusterC[c],clusterD[d], countarr, 
									bl1, bl2, bl3, MINARC, MAXARC, lmapcol_optn);
								addtimes(QUARTETS, &tarr);
						
							}					
			}
				
			if (numclust == 3) { /* three-cluster analysis */

				gettwo = new_ivector(2);

				for (a = 0; a < clustA; a++)
					for (b = 0; b < clustB; b++)
						for (c1 = 0; c1 < clustC-1; c1++)
							for (c2 = c1+1; c2 < clustC; c2++) {

								nq++;

								/* maximum likelihood values */
								/* approximate ML is sufficient for likelihood mapping */
								switch (quartcrit) {
									case QUART_MLEXACT:
										compute_quartlklhds(clusterA[a],clusterB[b],clusterC[c1],clusterC[c2],&d1,&d2,&d3, &bl1,&bl2,&bl3, QUART_EXACT);
										break;
									case QUART_MLAPPROX:
									default:
										compute_quartlklhds(clusterA[a],clusterB[b],clusterC[c1],clusterC[c2],&d1,&d2,&d3, &bl1,&bl2,&bl3, QUART_APPROX);
										break;
								}
								
								/* randomize order of d2 and d3 */
								if (randominteger(2) == 1) {
									temp = d3;
									d3 = d2;
									d2 = temp;
								}
						
								/* draw point for LM analysis */
								makelmpoint(triepsfp, trisvgfp, d1, d2, d3, 
#if 0
									&reg1, &reg2, &reg3, &reg4, &reg5, &reg6, &reg7, 
									&ar1, &ar2, &ar3, &reg1l, &reg1r, &reg2u, &reg2d, &reg3u, &reg3d, 
									&reg4u, &reg4d, &reg5l, &reg5r, &reg6u, &reg6d, 
									&ar, &reg, 
#endif
									clusterA[a],clusterB[b],clusterC[c1],clusterC[c2], countarr, 
									bl1, bl2, bl3, MINARC, MAXARC, lmapcol_optn);
								addtimes(QUARTETS, &tarr);

				}				
				free_ivector(gettwo);
			}
				
			if (numclust == 2) { /* two-cluster analysis */
					
				gettwo = new_ivector(2);

				for (a1 = 0; a1 < clustA-1; a1++)
					for (a2 = a1+1; a2 < clustA; a2++)
						for (b1 = 0; b1 < clustB-1; b1++)
							for (b2 = b1+1; b2 < clustB; b2++) {

								nq++;

								/* maximum likelihood values */
								/* approximate ML is sufficient for likelihood mapping */
								switch (quartcrit) {
									case QUART_MLEXACT:
										compute_quartlklhds(clusterA[a1],clusterA[a2],clusterB[b1],clusterB[b2],&d1,&d2,&d3, &bl1,&bl2,&bl3, QUART_EXACT);
										break;
									case QUART_MLAPPROX:
									default:
										compute_quartlklhds(clusterA[a1],clusterA[a2],clusterB[b1],clusterB[b2],&d1,&d2,&d3, &bl1,&bl2,&bl3, QUART_APPROX);
										break;
								}
								
								/* randomize order of d2 and d3 */
								if (randominteger(2) == 1) {
									temp = d3;
									d3 = d2;
									d2 = temp;
								}
						
								/* draw point for LM analysis */
								makelmpoint(triepsfp, trisvgfp, d1, d2, d3, 
#if 0
									&reg1, &reg2, &reg3, &reg4, &reg5, &reg6, &reg7, 
									&ar1, &ar2, &ar3, &reg1l, &reg1r, &reg2u, &reg2d, &reg3u, &reg3d, 
									&reg4u, &reg4d, &reg5l, &reg5r, &reg6u, &reg6d, 
									&ar, &reg, 
#endif
									clusterA[a1],clusterA[a2],clusterB[b1],clusterB[b2], countarr, 
									bl1, bl2, bl3, MINARC, MAXARC, lmapcol_optn);
								addtimes(QUARTETS, &tarr);

				}
					
				free_ivector(gettwo);
			}
			
			if (numclust == 1) { /* normal likelihood mapping (one cluster) */
			
				mlorder = new_ivector(3);

				for (i = 3; i < Maxspc; i++) 
					for (c = 2; c < i; c++) 
						for (b = 1; b < c; b++) 
							for (a = 0; a < b; a++) {
							
								nq++;

								/* maximum likelihood values */
								/* approximate ML is sufficient for likelihood mapping */
								switch (quartcrit) {
									case QUART_MLEXACT:
										compute_quartlklhds(a,b,c,i,&logs[0],&logs[1],&logs[2], &bl1,&bl2,&bl3, QUART_EXACT);
										break;
									case QUART_MLAPPROX:
									default:
										compute_quartlklhds(a,b,c,i,&logs[0],&logs[1],&logs[2], &bl1,&bl2,&bl3, QUART_APPROX);
										break;
								}

								/* randomize order */
								chooser(3,3,mlorder);
								d1 = logs[mlorder[0]];
								d2 = logs[mlorder[1]];
								d3 = logs[mlorder[2]];
								
								/* draw point for LM analysis */
								makelmpoint(triepsfp, trisvgfp, d1, d2, d3, 
#if 0
									&reg1, &reg2, &reg3, &reg4, &reg5, &reg6, &reg7, 
									&ar1, &ar2, &ar3, &reg1l, &reg1r, &reg2u, &reg2d, &reg3u, &reg3d, 
									&reg4u, &reg4d, &reg5l, &reg5r, &reg6u, &reg6d, 
									&ar, &reg, 
#endif
									a,b,c,i, countarr, 
									bl1, bl2, bl3, MINARC, MAXARC, lmapcol_optn);
								addtimes(QUARTETS, &tarr);
				
				}
				free_ivector(mlorder);
			}
			
		} else { /* randomly selected quartets */
			
			if (numclust == 4) { /* four-cluster analysis */

				for (lmqts = 0; lmqts < Numquartets; lmqts++) {
				
					nq++;

					/* choose random quartet */	
					qts[0] = clusterA[ randominteger(clustA) ];
					qts[1] = clusterB[ randominteger(clustB) ];
					qts[2] = clusterC[ randominteger(clustC) ];
					qts[3] = clusterD[ randominteger(clustD) ];			

					/* maximum likelihood values */
					/* approximate ML is sufficient for likelihood mapping */
					switch (quartcrit) {
						case QUART_MLEXACT:
							compute_quartlklhds(qts[0],qts[1],qts[2],qts[3], &d1,&d2,&d3, &bl1,&bl2,&bl3, QUART_EXACT);
							break;
						case QUART_MLAPPROX:
						default:
							compute_quartlklhds(qts[0],qts[1],qts[2],qts[3], &d1,&d2,&d3, &bl1,&bl2,&bl3, QUART_APPROX);
							break;
					}
					
					/* draw point for LM analysis */
					makelmpoint(triepsfp, trisvgfp, d1, d2, d3, 
#if 0
						&reg1, &reg2, &reg3, &reg4, &reg5, &reg6, &reg7, 
						&ar1, &ar2, &ar3, &reg1l, &reg1r, &reg2u, &reg2d, &reg3u, &reg3d, 
						&reg4u, &reg4d, &reg5l, &reg5r, &reg6u, &reg6d, 
						&ar, &reg, 
#endif
						qts[0],qts[1],qts[2],qts[3], countarr, 
						bl1, bl2, bl3, MINARC, MAXARC, lmapcol_optn);
					addtimes(QUARTETS, &tarr);

				}
			}
				
			if (numclust == 3) { /* three-cluster analysis */

				gettwo = new_ivector(2);

				for (lmqts = 0; lmqts < Numquartets; lmqts++) {
				
					nq++;

					/* choose random quartet */	
					qts[0] = clusterA[ randominteger(clustA) ];
					qts[1] = clusterB[ randominteger(clustB) ];
					chooser(clustC, 2, gettwo);
					qts[2] = clusterC[gettwo[0]];
					qts[3] = clusterC[gettwo[1]];		

					/* maximum likelihood values */
					/* approximate ML is sufficient for likelihood mapping */
					switch (quartcrit) {
						case QUART_MLEXACT:
							compute_quartlklhds(qts[0],qts[1],qts[2],qts[3],&d1,&d2,&d3, &bl1,&bl2,&bl3, QUART_EXACT);
							break;
						case QUART_MLAPPROX:
						default:
							compute_quartlklhds(qts[0],qts[1],qts[2],qts[3],&d1,&d2,&d3, &bl1,&bl2,&bl3, QUART_APPROX);
							break;
					}
					
					/* order of d2 and d3 is already randomized! */
						
					/* draw point for LM analysis */
					makelmpoint(triepsfp, trisvgfp, d1, d2, d3, 
#if 0
						&reg1, &reg2, &reg3, &reg4, &reg5, &reg6, &reg7, 
						&ar1, &ar2, &ar3, &reg1l, &reg1r, &reg2u, &reg2d, &reg3u, &reg3d, 
						&reg4u, &reg4d, &reg5l, &reg5r, &reg6u, &reg6d, 
						&ar, &reg, 
#endif
						qts[0],qts[1],qts[2],qts[3], countarr, 
						bl1, bl2, bl3, MINARC, MAXARC, lmapcol_optn);
					addtimes(QUARTETS, &tarr);

				}
					
				free_ivector(gettwo);
			}
				
			if (numclust == 2) { /* two-cluster analysis */

				gettwo = new_ivector(2);

				for (lmqts = 0; lmqts < Numquartets; lmqts++) {
				
					nq++;

					/* choose random quartet */	
					chooser(clustA, 2, gettwo);
					qts[0] = clusterA[gettwo[0]];
					qts[1] = clusterA[gettwo[1]];		
					chooser(clustB, 2, gettwo);
					qts[2] = clusterB[gettwo[0]];
					qts[3] = clusterB[gettwo[1]];		

					/* maximum likelihood values */
					/* approximate ML is sufficient for likelihood mapping */
					switch (quartcrit) {
						case QUART_MLEXACT:
							compute_quartlklhds(qts[0],qts[1],qts[2],qts[3], &d1,&d2,&d3, &bl1,&bl2,&bl3, QUART_EXACT);
							break;
						case QUART_MLAPPROX:
						default:
							compute_quartlklhds(qts[0],qts[1],qts[2],qts[3], &d1,&d2,&d3, &bl1,&bl2,&bl3, QUART_APPROX);
							break;
					}
					
					/* order of d2 and d3 is already randomized! */
						
					/* draw point for LM analysis */
					makelmpoint(triepsfp, trisvgfp, d1, d2, d3, 
#if 0
						&reg1, &reg2, &reg3, &reg4, &reg5, &reg6, &reg7, 
						&ar1, &ar2, &ar3, &reg1l, &reg1r, &reg2u, &reg2d, &reg3u, &reg3d, 
						&reg4u, &reg4d, &reg5l, &reg5r, &reg6u, &reg6d, 
						&ar, &reg, 
#endif
						qts[0],qts[1],qts[2],qts[3], countarr, 
						bl1, bl2, bl3, MINARC, MAXARC, lmapcol_optn);
					addtimes(QUARTETS, &tarr);

				}
				free_ivector(gettwo);
			}
				
			if (numclust == 1) { /* normal likelihood mapping (one cluster) */
			
				for (lmqts = 0; lmqts < Numquartets; lmqts++) {
				
					nq++;

					/* choose random quartet */	
					chooser(Maxspc, 4, qts);				

					/* maximum likelihood values */
					/* approximate ML is sufficient for likelihood mapping */
					switch (quartcrit) {
						case QUART_MLEXACT:
							compute_quartlklhds(qts[0],qts[1],qts[2],qts[3],&d1,&d2,&d3, &bl1,&bl2,&bl3, QUART_EXACT);
							break;
						case QUART_MLAPPROX:
						default:
							compute_quartlklhds(qts[0],qts[1],qts[2],qts[3],&d1,&d2,&d3, &bl1,&bl2,&bl3, QUART_APPROX);
							break;
					}
					
					/* order of d1, d2, and d3 is already randomized! */
				
					/* draw point for LM analysis */
					makelmpoint(triepsfp, trisvgfp, d1, d2, d3, 
#if 0
						&reg1, &reg2, &reg3, &reg4, &reg5, &reg6, &reg7, 
						&ar1, &ar2, &ar3, &reg1l, &reg1r, &reg2u, &reg2d, &reg3u, &reg3d, 
						&reg4u, &reg4d, &reg5l, &reg5r, &reg6u, &reg6d, 
						&ar, &reg, 
#endif
						qts[0],qts[1],qts[2],qts[3], countarr, 
						bl1, bl2, bl3, MINARC, MAXARC, lmapcol_optn);
					addtimes(QUARTETS, &tarr);

				}
			}
		}

		if (lmapeps_optn) {
			finisheps(triepsfp, countarr);
			closefile(triepsfp);
		}
		if (lmapsvg_optn) {
			finishsvg(trisvgfp, countarr);
			closefile(trisvgfp);
		}
		free_ivector(qts);

} /* map_lklhd */

/***************************************************************/ 

void setdefaults() {

  strcpy(INFILE,      INFILEDEFAULT);
  strcpy(OUTFILE,     OUTFILEDEFAULT);
  strcpy(TREEFILE,    TREEFILEDEFAULT);
  strcpy(INTREE,      INTREEDEFAULT);
  strcpy(DISTANCES,   DISTANCESDEFAULT);
  strcpy(TSTV,        TSTVDEFAULT);
  strcpy(EDITDIST,    EDITDISTDEFAULT);
  strcpy(SITEFREQS,   SITEFREQSDEFAULT);
  strcpy(TRIANGLEEPS, TRIANGLEEPSDEFAULT);
  strcpy(TRIANGLESVG, TRIANGLESVGDEFAULT);
  strcpy(UNRESOLVED,  UNRESOLVEDDEFAULT);
  strcpy(LMAPTAB,     LMAPTABDEFAULT);
  strcpy(ALLQUART,    ALLQUARTDEFAULT);
  strcpy(ALLQUARTLH,  ALLQUARTLHDEFAULT);
  strcpy(SITELH,      SITELHDEFAULT);
  strcpy(SITELHB,     SITELHBDEFAULT);
  strcpy(SITERATE,    SITERATEDEFAULT);
  strcpy(SITERATEB,   SITERATEBDEFAULT);
  strcpy(OUTPARAM,    OUTPARAMDEFAULT);
  strcpy(SUBSET,      SUBSETDEFAULT);
  strcpy(OUTPTLIST,   OUTPTLISTDEFAULT);
  strcpy(OUTPTORDER,  OUTPTORDERDEFAULT);
  strcpy(OUTPTALL,    OUTPTALLDEFAULT);
  strcpy(NEXALL,      NEXALLDEFAULT);
  strcpy(NEXPTORDER,  NEXPTORDERDEFAULT);
  strcpy(NEXPTSPLITS, NEXPTSPLITSDEFAULT);
  strcpy(PTSPLITS,    PTSPLITSDEFAULT);
  strcpy(RDSTATS,     RDSTATSDEFAULT);
  strcpy(ALIINFO,     ALIINFODEFAULT);
  strcpy(ALIINFONUM,  ALIINFONUMDEFAULT);

  setprefix_optn     = SETPREFIX_NONE;	/* 0: not set */
  					/* 1: INFILE */
  					/* 2: INTREE */
  					/* 3: reset by openfileto... */
  					/* 4: -prefix= */
  paramfile_optn     = FALSE;
  saveptall_optn     = PTALL_NONE;

  usebestq_optn      = FALSE;
  usebranch_optn     = FALSE;
  printrmatr_optn    = FALSE; 
  savelmaptab_optn   = FALSE;
  savequartlh_optn   = FALSE;
  saveqlhblen_optn   = FALSE;
  savequart_optn     = FALSE;
  readquart_optn     = FALSE;
  fixedorder_optn    = FALSE; 
#if 0
  skipmlbranch_optn  = FALSE; 
#endif
  rootstart_optn          = FALSE; 
  rootquartsonly_optn     = FALSE; 
  conssub50_optn          = FALSE; 
  qsupport_optn           = FALSE;
  dotreetest_optn         = TRUE;
  dotreelh_optn           = TRUE;
  savesitelhb_optn        = FALSE;
  savesitelh_optn         = FALSE;
  savesiterateb_optn      = FALSE;
  savesiterate_optn       = FALSE;
  savetstv_optn           = FALSE;
  saveeditdist_optn       = FALSE;
  savesitefreqs_optn      = FALSE;
  savenexus_optn          = FALSE;
  saveptsplitsfile_optn   = FALSE;
  saverdstatsfile_optn    = FALSE;
  stopafteralistats_optn  = FALSE;
  savealiinfofile_optn    = FALSE;
  savealiinfonumfile_optn = FALSE;
  savesplitoccurfile_optn = FALSE;
  savenexusptorder_optn   = FALSE;
  consensus_optn          = FALSE;
  readsubset_optn         = FALSE;
  savenexus_optn          = FALSE;
  savenexusptsplits_optn  = FALSE;
  savenexusptorder_optn   = FALSE;
  savenexusjoin_optn      = TRUE; /* set joint nexus file to be default */
  /* lmapcol_optn           = LMAP_MINMAXLEN; */ /* coloring scheme for likelihood mapping, TODO: move to lmap.h */
  /* lmapcol_optn           = LMAP_AREA; */      /* coloring scheme for likelihood mapping, TODO: move to lmap.h */
  lmapcol_optn            = LMAP_NORMAL; /* coloring scheme for likelihood mapping, TODO: move to lmap.h */
                                 /* possible values: LMAP_NORMAL, LMAP_MINMAXLEN, LMAP_REGION */
  lmapsvg_optn            = TRUE;	/* by default: EPS and SVG */
  lmapeps_optn            = TRUE;

  exit_wait_optn         = FALSE;

#if 0
  saveparam_optn        = FALSE;
#endif

  stdinput_fp = stdin;

  randseed = -1;                  /* to set random random seed */
  aliinfo_ws = 500;               /* count alignment info in windows of 500 */
  aliinfo_ss = 25;                /* count alignment info with window steps of 25 */

} /* setdefaults */

/***************************************************************/ 

void printversion(char *fname)
{
#	if ! PARALLEL
		fprintf(stderr, "puzzle (%s) %s\n", PACKAGE, VERSION);
#	else
		fprintf(stderr, "ppuzzle (%s) %s\n", PACKAGE, VERSION);
		PP_SendDone();
# 		if 0
   			MPI_Finalize();
   			exit (0);
#		endif
#	endif
   	tp_exit(0, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
} /* printversion */
/***************************************************************/ 

void printusage(char *fname)
{
                 /* |<---                      80 characters                                   --->| */
   fprintf(stderr, "\n\nUsage: %s [-h] [options] [ Infilename [ UserTreeFilename ] ]\n\n", fname);
   fprintf(stderr, "  -h               - print usage\n");
   fprintf(stderr, "  -prefix=XXX      - use 'XXX' as filename prefix instead of 'Infilename'\n");
   fprintf(stderr, "                     of 'Infilename' or 'UserTreeFilename'\n");
   fprintf(stderr, "  -param=YYY       - use file 'YYY' for parameter input (instead of stdin)\n");
   fprintf(stderr, "  -consmrel        - perform consensus step below 50%% to first incongruence,\n");
   fprintf(stderr, "                     that is a 'relative mayority consensus' is built.\n");
   fprintf(stderr, "  -randseed<#> \n");
   fprintf(stderr, "  -randseed=<#>    - use <#> as random number seed, for debug purposes only\n");
   fprintf(stderr, "  -consmrel    or \n");
   fprintf(stderr, "  -sub50           - perform consensus step below 50%% to first incongruence\n");
   fprintf(stderr, "  -wsl             - write site llhs to PREFIX.%s (PHILIP-like)\n",SITELHEXT);
   fprintf(stderr, "  -wsr             - write site rates to PREFIX.%s (PHYLIP-like)\n",SITERATEEXT);
   fprintf(stderr, "  -wsf             - write splits file PREFIX.%s\n",PTSPLITSEXT);
   fprintf(stderr, "  -wtstv           - write pairwise substitutions counts to PREFIX.%s\n", TSTVEXT);
   fprintf(stderr, "  -weditdist       - write pairwise substitutions counts to PREFIX.%s\n", EDITDISTEXT);
   fprintf(stderr, "  -wsitefreqs      - write site frequencies to PREFIX.%s\n",SITEFREQSEXT);
   fprintf(stderr, "  -wsnex           - write splits in nexus format\n");
   fprintf(stderr, "  -witnex          - write intermediate trees in nexus format\n");
   fprintf(stderr, "  -wallnex         - write all informations possible to nexus files\n");
   fprintf(stderr, "  -nexjoin         - write joint nexus files\n");
   fprintf(stderr, "  -nexsep          - write separate nexus files\n");
   fprintf(stderr, "  Infilename       - Filename of multiple sequence alignment in PHYLIP format\n");
   fprintf(stderr, "  UserTreeFilename - Filename of the treefile in PHYLIP format\n");
#  if PARALLEL
	PP_SendDone();
#	if 0
		MPI_Finalize();
		exit (1);
#	endif
#  endif
   tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
} /* printusage */

/***************************************************************/ 

void printusagehhh(char *fname)
{
   int n;
   fprintf(stderr, "\n\nUsage: %s [options] [ Infilename [ UserTreeFilename ] ]\n\n", fname);
                 /* |<---                      80 characters                                   --->| */
   fprintf(stderr, "  -h               - print usage\n");
   fprintf(stderr, "  -prefix=XXX      - use 'XXX' as filename prefix instead of 'Infilename'\n");
   fprintf(stderr, "                     of 'Infilename' or 'UserTreeFilename'\n");
   fprintf(stderr, "  -param=YYY       - use file 'YYY' for parameter input (instead of stdin)\n");
   fprintf(stderr, "  -consmrel    or \n");
   fprintf(stderr, "  -sub50           - perform consensus step below 50%% to first incongruence\n");
   fprintf(stderr, "  -randseed<#> or \n");
   fprintf(stderr, "  -randseed=<#>    - use <#> as random number seed, for debug purposes only\n");
   fprintf(stderr, "  -wlmaptab        - write likelihood map to PREFIX.%s\n", LMAPTABEXT);
   fprintf(stderr, "  -wqf             - write quartet file to PREFIX.%s\n",ALLQUARTEXT);
   fprintf(stderr, "  -rqf             - read quartet file from PREFIX.%s\n",ALLQUARTEXT);
   fprintf(stderr, "  -wqlb            - write quart llhs to PREFIX.%s (bin)  [non-parallel]\n",ALLQUARTLHEXT);
   fprintf(stderr, "  -wqla            - write quart llhs to PREFIX.%s (ASCII)[non-parallel]\n",ALLQUARTLHEXT);
   fprintf(stderr, "  -wqltb           - like '-wqlb' with inner quartet edge length  [non-parallel]\n");
   fprintf(stderr, "  -wqlta           - like '-wqla' with inner quartet edge length  [non-parallel]\n");
   fprintf(stderr, "  -wallptrees      - write successively all puzzling trees to PREFIX.%s\n",OUTPTALLEXT);
   fprintf(stderr, "  -wsl             - write site llhs to PREFIX.%s (PHILIP-like)\n",SITELHEXT);
   fprintf(stderr, "  -wsr             - write site rates to PREFIX.%s (PHYLIP-like)\n",SITERATEEXT);
   fprintf(stderr, "  -wsf             - write splits file PREFIX.%s\n",PTSPLITSEXT);
   fprintf(stderr, "  -wtstv           - write pairwise substitutions counts to PREFIX.%s\n", TSTVEXT);
   fprintf(stderr, "  -weditdist       - write pairwise substitutions counts to PREFIX.%s\n", EDITDISTEXT);
   fprintf(stderr, "  -splitoccur      - output split occurrence in trees to PREFIX.%s\n",SPLITOCCUREXT);
#if USE_RECDETEC
   fprintf(stderr, "  -aliinfo         - compute informative sites along the alignment to PREFIX.%s (RecDetec format)\n",ALIINFOEXT);
#else
   fprintf(stderr, "  -aliinfo         - compute informative sites along the alignment to PREFIX.%s (VisRec format)\n",ALIINFOEXT);
#endif
   fprintf(stderr, "  -aliinfonum      - compute informative site counts along the alignment to PREFIX.%s (RecDetec format)\n",ALIINFONUMEXT);
   fprintf(stderr, "  -infows=<#>      - window size for aliinfo [500]\n");
   fprintf(stderr, "  -infoss=<#>      - step size for aliinfo [25]\n");
   fprintf(stderr, "  -wrdsf           - write stats for RecDetec to PREFIX.%s\n",RDSTATSEXT);
   fprintf(stderr, "  -recdetec        - write stats for RecDetec to PREFIX.%s\n", RDSTATSEXT);
   fprintf(stderr, "  -statsonly       - stop after writing alignment stats\n");
   fprintf(stderr, "  -wsitefreqs      - write site frequencies to PREFIX.%s\n",SITEFREQSEXT);
   fprintf(stderr, "  -wsnex           - write splits in nexus format\n");
   fprintf(stderr, "  -witnex          - write intermediate trees in nexus format\n");
   fprintf(stderr, "  -wallnex         - write all informations possible to nexus files\n");
   fprintf(stderr, "  -nexjoin         - write joint nexus files\n");
   fprintf(stderr, "  -nexsep          - write separate nexus files\n");
   fprintf(stderr, "  -bestq           - use best quart, no Bayesian weights\n");
   fprintf(stderr, "  -quartml         - use approximate ML for quartet evaluation\n");
   fprintf(stderr, "  -quartmlapprox   - use approximate ML for quartet evaluation (= -quartml)\n");
   fprintf(stderr, "  -quartmlexact    - use exact ML for quartet evaluation\n");
   fprintf(stderr, "  -quartme         - use ME for quartet evaluation\n");
   fprintf(stderr, "  -quartmp         - use MP for quartet evaluation\n");
   fprintf(stderr, "  -quartnj         - use NJ for quartet evaluation (should be identical to ME)\n");
   fprintf(stderr, "  -printrmat       - print rate matrix to screen\n");
   fprintf(stderr, "  -consensus       - construct a consensus tree from user trees   [non-parallel]\n");
   fprintf(stderr, "  -usebranch       - use branch length from usertree file\n");
   fprintf(stderr, "  -achim           - reads quartet set and sets puzzling step orders to 1,2,...n\n");
   fprintf(stderr, "  -rootstart       - always start with a quartet containing the outgroup\n");
   fprintf(stderr, "  -rootqonly       - only use quartets containing the outgroup\n");
   fprintf(stderr, "                     (implies -rootstart)\n");
   fprintf(stderr, "  -rssm            - read subset matrix from PREFIX.%s for missing data\n",SUBSETEXT);
   fprintf(stderr, "  -notreetest      - skip test for usertree topologies (KH, SH, ELW)\n");
   fprintf(stderr, "  -notreelh        - skip likelihood/branch length (QP or consensus)\n");
   fprintf(stderr, "  -voting<#>   or\n");
   fprintf(stderr, "  -voting=<#>      - use voting scheme <#> in the puzzling step (default=%d)\n", pstep_voting_optn);
   for (n=1; n<=VOTING_MAX; n++)
     fprintf(stderr, "                     %3d: %s\n", n, voting_string(n));
   fprintf(stderr, "  Infilename       - Filename of multiple sequence alignment in PHYLIP format\n");
   fprintf(stderr, "  UserTreeFilename - Filename of the treefile in PHYLIP format\n");
#  ifdef USE_ADJUSTABLE_EPS
      fprintf(stderr, "  -epsrate=#       - stop threshold for rate heterogeneity estimation (%.2e)\n", EPSILON_RATEPARAM_DEFAULT);
      fprintf(stderr, "  -epssubst=#      - stop threshold for subst. parameter estimation (%.2e)\n", EPSILON_SUBSTPARAM_DEFAULT);
      fprintf(stderr, "  -epsbranch=#     - stop threshold for branch length estimation (%.2e)\n", EPSILON_BRANCH_DEFAULT);
      fprintf(stderr, "  -epsheight=#     - stop threshold for tree height estimation (%.2e)\n", EPSILON_HEIGHTS_DEFAULT);
#  endif
   fprintf(stderr, "\n");
   fprintf(stderr, "Note: flags -wqlb, -wqla as well as -wqltb, -wqlta do exclude each other.\n");
   fprintf(stderr, "      If several given, the last one is in effect.\n");

   fprintf(stderr, "\n");
#ifdef HHH
                 /* |<---                      80 characters                                   --->| */
   fprintf(stderr, "  not yet implemented in this version:\n");
   fprintf(stderr, "  -wslb            - write site lhs to PREFIX.sitelhb (binary)         [not yet]\n");
   fprintf(stderr, "  -wsrb            - write site rates to PREFIX.siterateb (binary)     [not yet]\n");
   fprintf(stderr, "  -wparam          - write params to PREFIX.param                      [not yet]\n");
   fprintf(stderr, "  -qsupport        - prints quartet support for incorporated splits    [not yet]\n");
   fprintf(stderr, "  -consth=<#>      - consensus threshold, e.g. 50=M_50 consensus       [not yet]\n");
   fprintf(stderr, "  -wqnex           - write quartets in nexus format                    [not yet]\n");
   fprintf(stderr, "  -wsth=<#>        - split threshold, e.g. 50 - splits of the M_50     [not yet]\n");
   fprintf(stderr, "  -wsnex=<#>       - write splits with > <#>%% occurence - nexus format [not yet]\n");
   fprintf(stderr, "  -quartml         - use ML values to evaluate quartets                [not yet]\n");
   fprintf(stderr, "  -quartmlapprox   - use approximate ML values to evaluate quartets    [default]\n");
   fprintf(stderr, "  -quartnj         - use NJ to evaluate quartets                       [not yet]\n");
   fprintf(stderr, "  -quartme         - use ME to evaluate quartets                       [not yet]\n");
   fprintf(stderr, "  -quartpars       - use parsimony to evaluate quartets                [not yet]\n");
   fprintf(stderr, "\n");
#endif /* HHH */

#	if PARALLEL
		PP_SendDone();
#		if 0
			MPI_Finalize();
			exit (2);
#		endif
#	endif
	tp_exit(2, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
} /* printusagehhh */

/***************************************************************/ 

/* infiletype  1=infile, 2=intree */
void setfilenames(int setprefix_optn, int savenexusjoin_optn, int infiletype, char fname[]){

#  if 0
fprintf(stderr, "XXXX: %d, %d, %s\n", setprefix_optn, infiletype, fname);
#  endif


   /* set filenames, if set by -prefix=, INFILE, or INTREE */
   if (setprefix_optn < SETPREFIX_PREFIX) {
      switch(setprefix_optn) {
   	   case SETPREFIX_INTREE:
      		   sprintf(FILEPREFIX, "%s", INTREE);
		   break;
   	   case SETPREFIX_INFILE:
      		   sprintf(FILEPREFIX, "%s", INFILE);
		   break;
	   default:
		   break;
      }
   }

   sprintf(OUTFILE       ,"%s.%s", FILEPREFIX, OUTFILEEXT);
   sprintf(TREEFILE      ,"%s.%s", FILEPREFIX, TREEFILEEXT);
   sprintf(DISTANCES     ,"%s.%s", FILEPREFIX, DISTANCESEXT);
   sprintf(TSTV          ,"%s.%s", FILEPREFIX, TSTVEXT);
   sprintf(EDITDIST      ,"%s.%s", FILEPREFIX, EDITDISTEXT);
   sprintf(SITEFREQS     ,"%s.%s", FILEPREFIX, SITEFREQSEXT);
   sprintf(TRIANGLEEPS   ,"%s.%s", FILEPREFIX, TRIANGLEEPSEXT);
   sprintf(TRIANGLESVG   ,"%s.%s", FILEPREFIX, TRIANGLESVGEXT);
   sprintf(UNRESOLVED    ,"%s.%s", FILEPREFIX, UNRESOLVEDEXT);
   sprintf(LMAPTAB       ,"%s.%s", FILEPREFIX, LMAPTABEXT);
   sprintf(ALLQUART      ,"%s.%s", FILEPREFIX, ALLQUARTEXT);
   sprintf(ALLQUARTLH    ,"%s.%s", FILEPREFIX, ALLQUARTLHEXT);
   sprintf(SITELH        ,"%s.%s", FILEPREFIX, SITELHEXT);
   sprintf(SITELHB       ,"%s.%s", FILEPREFIX, SITELHBEXT);
   sprintf(SITERATE      ,"%s.%s", FILEPREFIX, SITERATEEXT);
   sprintf(SITERATEB     ,"%s.%s", FILEPREFIX, SITERATEBEXT);
   sprintf(OUTPARAM      ,"%s.%s", FILEPREFIX, OUTPARAMEXT);
   sprintf(SUBSET        ,"%s.%s", FILEPREFIX, SUBSETEXT);
   sprintf(OUTPTLIST     ,"%s.%s", FILEPREFIX, OUTPTLISTEXT);
   sprintf(OUTPTORDER    ,"%s.%s", FILEPREFIX, OUTPTORDEREXT);
   sprintf(OUTPTALL      ,"%s.%s", FILEPREFIX, OUTPTALLEXT);
   sprintf(PTSPLITS      ,"%s.%s", FILEPREFIX, PTSPLITSEXT);
   sprintf(RDSTATS       ,"%s.%s", FILEPREFIX, RDSTATSEXT);
   sprintf(SPLITOCCUR    ,"%s.%s", FILEPREFIX, SPLITOCCUREXT);
   sprintf(ALIINFO       ,"%s.%s", FILEPREFIX, ALIINFOEXT);
   sprintf(ALIINFONUM    ,"%s.%s", FILEPREFIX, ALIINFONUMEXT);
   if(savenexusjoin_optn) {
   	sprintf(NEXALL        ,"%s.%s", FILEPREFIX, NEXALLEXT);
   	sprintf(NEXPTORDER    ,"%s.%s", FILEPREFIX, NEXALLEXT);
   	sprintf(NEXPTSPLITS   ,"%s.%s", FILEPREFIX, NEXALLEXT);
   } else {
   	sprintf(NEXALL     ,"%s.%s", FILEPREFIX, NEXALLEXT);
   	sprintf(NEXPTORDER ,"%s.%s", FILEPREFIX, NEXPTORDEREXT);
   	sprintf(NEXPTSPLITS,"%s.%s", FILEPREFIX, NEXPTSPLITSEXT);
   }

} /* setfilenames */


/***************************************************************/ 

void getintargv(int *argc, char **argv[]) 
{
#if 0
	int tmpargc;
	int n;
	int len;
	int shift;

	len = strlen(inargv);
#endif

	int    done;
	int    count;
	int    n;
	int    l;
	char   ch;
	char  *argtmp;
	char **argstr;

	argtmp = calloc(10100, sizeof(char));
	argstr = calloc(100, sizeof(char*));
	for(n=0; n<100; n++) {
		argstr[n] = &(argtmp[n * 100]);
	}
	n=1;

	fprintf(STDOUT, "\nYou seem to have click-started this program,");
	fprintf(STDOUT, "\ndo you want to enter commandline parameters: [y]es, [n]o: ");
	fflush(STDOUT);

	/* read one char */
	ch = getc(stdin);
	/* ch = getchar(); */
	if (ch != '\n') {
		do ;
		while (getc(stdin) != '\n');
		/* while (getchar() != '\n'); */
	}
	ch = (char) tolower((int) ch);

	if (ch == 'y') {
		done=FALSE;

		fprintf(STDOUT, "\nEnter single parameter [! for none]: ");
		fflush(STDOUT);
		count = fscanf(stdin, "%s", argstr[n]);
		do ;
		while (getc(stdin) != '\n');

		if(argstr[0][0] == '!') {
			count = 0;
		} else {
			if (strlen(argstr[n]) > 100) {
				fprintf(STDOUT, "\nParameter too long!!!\n");
			} else {
				n++;
			}
		}

		while(!done) {
			fprintf(STDOUT, "\nCurrent commandline: ");
			for(l=1; l<n; l++) {
				fprintf(STDOUT, "%s ", argstr[l]);
			}
			fprintf(STDOUT, "\nQuit [q]; confirm [y]%s%s%s: ",
				(n<99 ? ", extend [e]" : ""),
				(n>1 ? ", delete last [l]" : ""),
				(n>1 ? ", delete all [a]" : ""));
			fflush(STDOUT);

			/* read one char */
			ch = getc(stdin);
			/* ch = getchar(); */
			if (ch != '\n') {
				do ;
				while (getc(stdin) != '\n');
				/* while (getchar() != '\n'); */
			}
			ch = (char) tolower((int) ch);
		
			switch (ch) {
				case 'y': 
					done=TRUE;
					break;
				case 'e': 
					fprintf(STDOUT, "\nEnter single parameter [! for none]: ");
					fflush(STDOUT);
					count = fscanf(stdin, "%s", argstr[n]);
					do ;
					while (getc(stdin) != '\n');
		
					if(argstr[0][0] == '!') {
						count = 0;
					} else {
						if (strlen(argstr[n]) > 100) {
							fprintf(STDOUT, "\nParameter too long!!!\n");
						} else {
							n++;
						}
					}
					break;
				case 'l': 
					if (n>1) n--;
					break;
				case 'a': 
					n=1;
					break;
				case 'q': 
   					tp_exit(0, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
					break;
			}
		}
	}

	*argc = n;
	*argv = argstr;
} /* getintargv */



void scancmdline(int *extargc, char **extargv[]) 
{
   static short infileset     = 0;
   static short intreefileset = 0;
   short flagused;
   int n;
   int found;				/* "click" found in cmd name? */
   int count, dummyint;
   char *tmpstr;
#  ifdef USE_ADJUSTABLE_EPS
     double dummydbl;
#  endif
   int    *argc; 
   char ***argv; 
   int     intargc; 
   char  **intargv; 

   intargc = 0; 
   intargv = NULL; 

   argc = extargc; 
   argv = extargv; 

   found  = FALSE; 
#if 0
   fprintf(stderr, "YYY: %s\n", (*argv)[0]);
#endif

   for (n = strlen((*argv)[0]) - 5; 
       (n >= 0) && !found && (((*argv)[0][n]) != '/')
	                  && (((*argv)[0][n]) != '\\'); n--) {

        tmpstr = &((*argv)[0][n]);
	dummyint = 0;
       	(void)sscanf(tmpstr, "click%n", &dummyint);
	if (dummyint == 5) found = TRUE;
	else {
		dummyint = 0;
       		(void)sscanf(tmpstr, "CLICK%n", &dummyint);
		if (dummyint == 5) found = TRUE;
		else {
			dummyint = 0;
       			(void)sscanf(tmpstr, "Click%n", &dummyint);
			if (dummyint == 5) found = TRUE;
		}
	}
#if 0
       	printf("XXX:   %s   %c %d\n", tmpstr, found ? '+' : '-', dummyint);
#endif
   }
   if(found) exit_wait_optn = TRUE;
   else      exit_wait_optn = FALSE;

   if(exit_wait_optn) {
	getintargv(&intargc, &intargv); 
	fprintf(STDOUT, "\n\n");
	if(intargc > 1) {
		argc = &intargc; 
		argv = &intargv; 
	} 
   }

   for (n = 1; n < *argc; n++) {
#     ifdef VERBOSE1
         printf("argv[%d] = %s\n", n, (*argv)[n]);
#     endif
         printf("argv[%d] = '%s'\n", n, (*argv)[n]);
 

      flagused = FALSE;

      /* use given prefix rather than INFILENAME for output filename */
      dummyint = 0;
      count = sscanf((*argv)[n],"-prefix=%[^\t\n\r]%n", FILEPREFIX, &dummyint);
      if (dummyint>8) {
        printf("PREFIX set to = \"%s\"\n", FILEPREFIX);
        setprefix_optn = SETPREFIX_PREFIX;
        flagused = TRUE;
      }

      /* use given parameter file rather than STDIN for menu */
      dummyint = 0;
      count = sscanf((*argv)[n],"-param=%[^\t\n\r]%n", PARAMFILE, &dummyint);
      /* count = sscanf((*argv)[n],"-param=%s%n", PARAMFILE, &dummyint); */ /* fix for paths/filenames containing spaces - HAS ;^) */
      if (dummyint>7) {
	if (PARAMFILE[0] == '-') {
        	printf("PARAMETER input from stdin\n");
        	paramfile_optn = FALSE;
	} else {
        	printf("PARAMETER input from \"%s\"\n", PARAMFILE);
        	paramfile_optn = TRUE;
	}
        flagused = TRUE;
      }

      /* write all puzzling trees sucessively to file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wallptrees%n", &dummyint);
      if (dummyint >= 7) {
	saveptall_optn = PTALL_OUT;
        flagused       = TRUE;
      }

      /* write likelihood mapping table to file - only in sequential version */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wlmaptab%n", &dummyint);
      if (dummyint >= 6) {
        savelmaptab_optn = TRUE;
        flagused         = TRUE;
      }

      /* write likelihood mapping in EPS format (only) */
      dummyint = 0;
      count = sscanf((*argv)[n], "-lmapeps%n", &dummyint);
      if (dummyint >= 6) {
        lmapsvg_optn     = FALSE;	/* EPS on, SVG off, default: both */
        lmapeps_optn     = TRUE;
        flagused         = TRUE;
      }

      /* write likelihood mapping in SVG format (only) */
      dummyint = 0;
      count = sscanf((*argv)[n], "-lmapsvg%n", &dummyint);
      if (dummyint >= 6) {
        lmapsvg_optn     = TRUE;	/* EPS off, SVG on, default: both */
        lmapeps_optn     = FALSE;
        flagused         = TRUE;
      }

      /* write quartet likelihoods (binary) - only in sequential version */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wqlb%n", &dummyint);
      if (dummyint == 5) {
        savequartlh_optn = TRUE;
	saveqlhblen_optn = FALSE;
        saveqlhbin_optn  = TRUE;
        flagused         = TRUE;
      }

      /* write quartet likelihoods (ASCII) - only in sequential version */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wqla%n", &dummyint);
      if (dummyint == 5) {
        savequartlh_optn = TRUE;
	saveqlhblen_optn = FALSE;
        saveqlhbin_optn  = FALSE;
        flagused         = TRUE;
      }

      /* write quartet likelihoods (binary) - only in sequential version */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wqltb%n", &dummyint);
      if (dummyint == 6) {
        savequartlh_optn = TRUE;
	saveqlhblen_optn = TRUE;
        saveqlhbin_optn  = TRUE;
        flagused         = TRUE;
      }

      /* write quartet likelihoods (ASCII) - only in sequential version */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wqlta%n", &dummyint);
      if (dummyint == 6) {
        savequartlh_optn = TRUE;
	saveqlhblen_optn = TRUE;
        saveqlhbin_optn  = FALSE;
        flagused         = TRUE;
      }

      /* write quartet topologies */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wqf%n", &dummyint);
      if (dummyint == 4) {
        savequart_optn = TRUE;
        flagused = TRUE;
      }

      /* read quartet topologies -> no ML step */
      dummyint = 0;
      count = sscanf((*argv)[n],"-rqf%n", &dummyint);
      if (dummyint == 4) {
        readquart_optn = TRUE; 
        flagused = TRUE;
      }

      /* write split occurrence to file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-splitoccur%n", &dummyint);
/* fprintf(stderr, " checking -splitoccur (%d)\n", dummyint); */
      if (dummyint == 11) {
/* fprintf(stderr, " setting savesplitoccurfile_optn = TRUE\n"); */
  	savesplitoccurfile_optn = TRUE;
        flagused = TRUE;
      }

      /* write alignment info file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-aliinfo%n", &dummyint);
      if (dummyint == 8) {
  	savealiinfofile_optn = TRUE;
        flagused = TRUE;
      }

      /* write alignment info count file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-aliinfonum%n", &dummyint);
      if (dummyint == 11) {
  	savealiinfonumfile_optn = TRUE;
        flagused = TRUE;
      }

      /* alignment info window size */
      dummyint = 0;
      count = sscanf((*argv)[n], "-infows=%d", &dummyint);
      if (count == 1) {
        aliinfo_ws = dummyint; 
        flagused = TRUE;
      }

      /* alignment info step size */
      dummyint = 0;
      count = sscanf((*argv)[n], "-infoss=%d", &dummyint);
      if (count == 1) {
        aliinfo_ss = dummyint; 
        flagused = TRUE;
      }

      /* write RecDetec stats file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wrdsf%n", &dummyint);
      if (dummyint == 6) {
  	saverdstatsfile_optn = TRUE;
        flagused = TRUE;
      }

      /* write RecDetec stats file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-recdetec%n", &dummyint);
      if (dummyint == 9) {
  	saverdstatsfile_optn = TRUE;
        flagused = TRUE;
      }

      /* write alignment stats only, then stop */
      dummyint = 0;
      count = sscanf((*argv)[n], "-statsonly%n", &dummyint);
      if (dummyint == 10) {
	stopafteralistats_optn  = TRUE;
        flagused = TRUE;
      }

      /* write puzzling splits to nexus file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wsf%n", &dummyint);
      if (dummyint == 4) {
  	saveptsplitsfile_optn = TRUE;
        flagused = TRUE;
      }

      /* write puzzling splits to nexus file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wsnex%n", &dummyint);
      if (dummyint == 6) {
        savenexusptsplits_optn = TRUE;
        savenexus_optn         = TRUE;
        flagused = TRUE;
      }

      /* write puzzling trees to nexus file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-witnex%n", &dummyint);
      if (dummyint == 7) {
        savenexusptorder_optn = TRUE;
        savenexus_optn        = TRUE;
        flagused = TRUE;
      }

      /* write puzzling trees to nexus file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wallnex%n", &dummyint);
      if (dummyint == 8) {
        savenexusptorder_optn  = TRUE;
        savenexusptsplits_optn = TRUE;
        savenexus_optn         = TRUE;
        flagused = TRUE;
      }

      /* write separate nexus file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-nexsep%n", &dummyint);
      if (dummyint == 7) {
        savenexusjoin_optn     = FALSE;
        savenexus_optn         = TRUE;
        flagused = TRUE;
      }

      /* write joint nexus file (default) */
      dummyint = 0;
      count = sscanf((*argv)[n], "-nexjoin%n", &dummyint);
      if (dummyint == 8) {
        savenexusjoin_optn     = TRUE;
        savenexus_optn         = TRUE;
        flagused = TRUE;
      }

      /* write nexus file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-nexus%n", &dummyint);
      if (dummyint == 6) {
        savenexusjoin_optn    = TRUE;
        savenexus_optn        = TRUE;
        flagused = TRUE;
      }

      /* use quartet topology with best likelihood -> no posterior probs */
      dummyint = 0;
      count = sscanf((*argv)[n],"-bestq%n", &dummyint);
      if (dummyint == 6) {
        usebestq_optn = TRUE; 
        flagused = TRUE;
      }

      /* evaluate quartet topologies with approx ML */
      dummyint = 0;
      count = sscanf((*argv)[n],"-quartml%n", &dummyint);
      if (dummyint == 8) {
	quartcrit_optn = QUART_MLAPPROX;
	approxqp_optn = QUART_APPROX;
        flagused = TRUE;
      }

      /* evaluate quartet topologies with approx ML */
      dummyint = 0;
      count = sscanf((*argv)[n],"-quartmlapprox%n", &dummyint);
      if (dummyint == 14) {
	quartcrit_optn = QUART_MLAPPROX;
	approxqp_optn = QUART_APPROX;
        flagused = TRUE;
      }

      /* evaluate quartet topologies with exact ML */
      dummyint = 0;
      count = sscanf((*argv)[n],"-quartmlexact%n", &dummyint);
      if (dummyint == 13) {
	quartcrit_optn = QUART_MLEXACT;
	approxqp_optn = QUART_EXACT;
        flagused = TRUE;
      }

      /* evaluate quartet topologies with MP */
      dummyint = 0;
      count = sscanf((*argv)[n],"-quartmp%n", &dummyint);
      if (dummyint == 8) {
	quartcrit_optn = QUART_MP;
	approxqp_optn = QUART_EXACT;
        flagused = TRUE;
      }

      /* evaluate quartet topologies with ME */
      dummyint = 0;
      count = sscanf((*argv)[n],"-quartme%n", &dummyint);
      if (dummyint == 8) {
	quartcrit_optn = QUART_ME;
	approxqp_optn = QUART_EXACT;
        flagused = TRUE;
      }

      /* evaluate quartet topologies with NJ */
      dummyint = 0;
      count = sscanf((*argv)[n],"-quartnj%n", &dummyint);
      if (dummyint == 8) {
	quartcrit_optn = QUART_NJ;
	approxqp_optn = QUART_EXACT;
        flagused = TRUE;
      }

      /* print substitution matrix Q to the screen */
      dummyint = 0;
      count = sscanf((*argv)[n],"-printrmat%n", &dummyint);
      if (dummyint == 10) {
        printrmatr_optn = TRUE; 
        flagused = TRUE;
      }

      /* print extended help */
      dummyint = 0;
      count = sscanf((*argv)[n],"-hhh%n", &dummyint);
      if (dummyint==4) {
        printusagehhh((*argv)[0]); 
        flagused = TRUE;
      }

      /* resolve congruent splits < 50% (M_rel) in consensus */
      dummyint = 0;
      count = sscanf((*argv)[n],"-sub50%n", &dummyint);
      if (dummyint == 6) {
        conssub50_optn = TRUE; 
        flagused = TRUE;
      }

      /* always start from a quartet containing the outgroup */
      dummyint = 0;
      count = sscanf((*argv)[n],"-rootstart%n", &dummyint);
      if (dummyint == 10) {
        rootstart_optn = TRUE; 
        flagused = TRUE;
      }

      /* use only quartets containing the outgroup */
      dummyint = 0;
      count = sscanf((*argv)[n],"-rootqonly%n", &dummyint);
      if (dummyint == 10) {
        rootquartsonly_optn = TRUE; 
        rootstart_optn = TRUE; 
        flagused = TRUE;
      }

      /* resolve congruent splits < 50% (M_rel) in consensus */
      dummyint = 0;
      count = sscanf((*argv)[n],"-consmrel%n", &dummyint);
      if (dummyint == 9) {
        conssub50_optn = TRUE; 
        flagused = TRUE;
      }

      /* include: fixed order addition (1,2,3,...,n) */
      /*          no ML branch lengths for consensus */
      /*          read quartets from file            */
      dummyint = 0;
      count = sscanf((*argv)[n],"-achim%n", &dummyint);
      if (dummyint == 6) {
        fixedorder_optn = TRUE; 
#if 0
	skipmlbranch_optn = TRUE;
#endif
	dotreelh_optn = FALSE;
        readquart_optn = TRUE; 
        flagused = TRUE;
      }

#     ifdef HHH
      /* save site likelihoods (binary) file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wslb%n", &dummyint);
      if (dummyint == 5) {
        savesitelhb_optn = TRUE;
        fprintf(stderr, "cmdline option '-wslb' is not yet implemented!!!\n");
        flagused = TRUE;
      }
#     endif /* HHH */

      /* save site likelihoods to PHYLIP like file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wsl%n", &dummyint);
      if (dummyint == 4) {
        savesitelh_optn = TRUE;
        flagused = TRUE;
      }

#     ifdef HHH
      /* save site rates (binary) file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wsrb%n", &dummyint);
      if (dummyint == 5) {
        savesiterateb_optn = TRUE;
        fprintf(stderr, "cmdline option '-wsrb' is not yet implemented!!!\n");
        flagused = TRUE;
      }
#     endif /* HHH */

      /* save site rates to PHYLIP like file */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wsr%n", &dummyint);
      if (dummyint == 4) {
        savesiterate_optn = TRUE;
        flagused = TRUE;
      }

      /* write pairwise substitutions counts to PREFIX.tstv */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wtstv%n", &dummyint);
      if (dummyint == 6) {
        savetstv_optn = TRUE;
        flagused = TRUE;
      }

      /* write pairwise substitutions counts to PREFIX.editdist */
      dummyint = 0;
      count = sscanf((*argv)[n], "-weditdist%n", &dummyint);
      if (dummyint == 10) {
        saveeditdist_optn = TRUE;
        flagused = TRUE;
      }

      /* write site frequencies to PREFIX.sitefreqs */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wsitefreqs%n", &dummyint);
      if (dummyint == 11) {
        savesitefreqs_optn = TRUE;
        flagused = TRUE;
      }

      /* print version */
      dummyint = 0;
      count = sscanf((*argv)[n],"-V%n", &dummyint);
      if (dummyint==2) {
        printversion((*argv)[0]); 
        flagused = TRUE;
      }

      /* print version */
      dummyint = 0;
      count = sscanf((*argv)[n],"-version%n", &dummyint);
      if (dummyint==8) {
        printversion((*argv)[0]); 
        flagused = TRUE;
      }

      /* print version */
      dummyint = 0;
      count = sscanf((*argv)[n],"--version%n", &dummyint);
      if (dummyint>=4) {
        printversion((*argv)[0]); 
        flagused = TRUE;
      }

      /* print help message */
      dummyint = 0;
      count = sscanf((*argv)[n],"-h%n", &dummyint);
      if (dummyint==2) {
        printusage((*argv)[0]); 
        flagused = TRUE;
      }

      /* set random number seed to fixed value */
      count = sscanf((*argv)[n],"-randseed%d", &dummyint);
      if (count == 1) {
        randseed = dummyint; 
        flagused = TRUE;
      }

      /* set random number seed to fixed value */
      count = sscanf((*argv)[n],"-randseed=%d", &dummyint);
      if (count == 1) {
        randseed = dummyint; 
        flagused = TRUE;
      }

      /* set voting scheme for puzzling step */
      count = sscanf((*argv)[n],"-voting%d", &dummyint);
      if (count == 1) {
	if ((dummyint > 0) && (dummyint <= VOTING_MAX)) {
	   pstep_voting_optn = dummyint; 
           fprintf(stderr, "voting scheme set to %d! \"%s\"\n", pstep_voting_optn, voting_string(pstep_voting_optn));
           flagused = TRUE;
        } else {
           fprintf(stderr, "WARNING: %d is not a valid voting scheme (1..%d)\n", dummyint, VOTING_MAX);
        }
      }

      /* set voting scheme for puzzling step */
      count = sscanf((*argv)[n],"-voting=%d", &dummyint);
      if (count == 1) {
	if ((dummyint > 0) && (dummyint <= VOTING_MAX)) {
	   pstep_voting_optn = dummyint; 
           fprintf(stderr, "voting scheme set to %d! \"%s\"\n", pstep_voting_optn, voting_string(pstep_voting_optn));
           flagused = TRUE;
        } else {
           fprintf(stderr, "WARNING: %d is not a valid voting scheme (1..%d)\n", dummyint, VOTING_MAX);
        }
      }

#     ifdef USE_ADJUSTABLE_EPS
         /* set stop threshold for branch length estimation */
         dummydbl=EPSILON_BRANCH_DEFAULT; 
         count = sscanf((*argv)[n],"-epsbranch%lf", &dummydbl);
         if (count == 1) {
           EPSILON_BRANCH = dummydbl; 
           fprintf(stderr, "branch length estimation threshold set to %e! (default=%e)\n",
		   EPSILON_BRANCH, EPSILON_BRANCH_DEFAULT);
           flagused = TRUE;
         }

         /* set stop threshold for tree heights estimation */
         dummydbl=EPSILON_HEIGHTS_DEFAULT; 
         count = sscanf((*argv)[n],"-epsheight%lf", &dummydbl);
         if (count == 1) {
           EPSILON_HEIGHTS = dummydbl; 
           fprintf(stderr, "tree heights estimation threshold set to %e! (default=%e)\n",
		   EPSILON_HEIGHTS, EPSILON_HEIGHTS_DEFAULT);
           flagused = TRUE;
         }

         /* set stop threshold for rate heterogeneity estimation */
         dummydbl=EPSILON_RATEPARAM_DEFAULT; 
         count = sscanf((*argv)[n],"-epsrate%lf", &dummydbl);
         if (count == 1) {
           EPSILON_RATEPARAM = dummydbl; 
           fprintf(stderr, "rate heterogeneity estimation threshold set to %e! (default=%.2e)\n", 
		   EPSILON_RATEPARAM, EPSILON_RATEPARAM_DEFAULT);
           flagused = TRUE;
         }

         /* set stop threshold for substitution model parameter estimation */
         dummydbl=EPSILON_SUBSTPARAM_DEFAULT; 
         count = sscanf((*argv)[n],"-epssubst%lf", &dummydbl);
         if (count == 1) {
           EPSILON_SUBSTPARAM = dummydbl; 
           fprintf(stderr, "substitution model parameter estimation threshold set to %e! (default=%e)\n",
		   EPSILON_SUBSTPARAM, EPSILON_SUBSTPARAM_DEFAULT);
           flagused = TRUE;
         }
#     endif

      /* compute consensus from usertrees (also 'k' in menu) */
      dummyint = 0;
      count = sscanf((*argv)[n],"-consensus%n", &dummyint);
      if (dummyint == 10) {
        consensus_optn = TRUE;
        flagused = TRUE;
      }

      /* read branch lengths from usertree file */
      dummyint = 0;
      count = sscanf((*argv)[n],"-usebranch%n", &dummyint);
      if (dummyint == 10) {
        usebranch_optn = TRUE;
        flagused = TRUE;
      }

      /* read subset matrix for missing data analysis */
      dummyint = 0;
      count = sscanf((*argv)[n], "-rssm%n", &dummyint);
      if (dummyint == 5) {
        readsubset_optn = TRUE;
	readquart_optn  = TRUE;
        flagused = TRUE;
      }

      /* write quartet support for splits */
      dummyint = 0;
      count = sscanf((*argv)[n], "-qsupport%n", &dummyint);
      if (dummyint == 9) {
        qsupport_optn = TRUE;
        flagused = TRUE;
      }

      /* skip tree tests (KH,SH,ELW) */
      dummyint = 0;
      count = sscanf((*argv)[n], "-notreetest%n", &dummyint);
      if (dummyint == 11) {
        dotreetest_optn = FALSE;
        flagused = TRUE;
      }

      /* skip lh/branch length computation (QP/consensus)*/
      dummyint = 0;
      count = sscanf((*argv)[n], "-notreelh%n", &dummyint);
      if (dummyint == 9) {
        dotreelh_optn = FALSE;
        flagused = TRUE;
      }

#if 0
      /* use window of alignment */
	/* todo (HAS) */
      count = sscanf((*argv)[n],"-ws%d", &dummyint);
      if (count == 1) windowsize = dummyint; 

      /* write parameter file (for resart) */
      dummyint = 0;
      count = sscanf((*argv)[n], "-wparam%n", &dummyint);
      if (dummyint == 7) {
        saveparam_optn = TRUE;
        flagused = TRUE;
      }


#endif

      /* get alignment filename */
      if ((*argv)[n][0] != '-') {
         if (infileset == 0) {
            if (strlen((*argv)[n]) >= FILENAMELENGTH) {
               fprintf(STDOUT, "Unable to proceed (filename too long)\n");
               fprintf(STDOUT, "You may want to recompile with FILENAMELENGTH>%d\n\n\n", FILENAMELENGTH);
#		if PARALLEL
#			if 0
				PP_Finalize();
				exit(1);
#			endif
#		endif
               tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
            }
            strcpy(INFILE, (*argv)[n]);
            infileset++;
            if (setprefix_optn < SETPREFIX_PREFIX) {
                strcpy(FILEPREFIX, INFILE);
/* printf("PREFIX set to = \"%s\"\n", FILEPREFIX); */
                setprefix_optn = SETPREFIX_INFILE;
            }
            fprintf(STDOUT, "Input file: %s\n", INFILE);
            flagused = TRUE;
         } else {
            /* get usertree filename */
            if (intreefileset == 0) {
               if (strlen((*argv)[n]) >= FILENAMELENGTH) {
                  fprintf(STDOUT, "Unable to proceed (filename too long)\n");
                  fprintf(STDOUT, "You may want to recompile with FILENAMELENGTH>%d\n\n\n", FILENAMELENGTH);
#                 if PARALLEL
#		    if 0
			PP_Finalize();
			exit(1);
#		    endif
#                 endif
                  tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
               }
               strcpy(INTREE, (*argv)[n]);
               intreefileset++;
               if (setprefix_optn < SETPREFIX_PREFIX) {
                   strcpy(FILEPREFIX, INTREE);
/* printf("PREFIX set to = \"%s\"\n", FILEPREFIX); */
                   setprefix_optn = SETPREFIX_INTREE;
               }
               fprintf(STDOUT, "Usertree file: %s\n", INTREE);
               flagused = TRUE;
            }
         }

      }
      if (flagused == FALSE) {
         fprintf(stderr, "WARNING: commandline parameter %d not recognized (\"%s\")\n", n, (*argv)[n]);
      }
      flagused = FALSE;
   }

                   /* setprefix_optn = SETPREFIX_INFILE; */
   if (setprefix_optn > 0) {
   	setfilenames(setprefix_optn, savenexusjoin_optn, RESET_NONE, INFILE);
   }

} /* scancmdline */


/***************************************************************/ 

void inputandinit(int *argc, char **argv[]) {

	int ci;
	int taxon;
	int reset;
#ifdef EPE_DEBUG
	int i; /*epe*/
#endif /* EPE_DEBUG */

#	ifndef ALPHA
		fprintf(STDOUT, "\n\n\nWELCOME TO TREE-PUZZLE %s!\n\n\n\n", VERSION);
#	else
		fprintf(STDOUT, "\n\n\nWELCOME TO TREE-PUZZLE %s%s!\n\n\n\n", VERSION, ALPHA);
#	endif


	/* vectors used in QP and LM analysis */
	qweight = new_dvector(3);
	sqdiff = new_dvector(3);
	qworder = new_ivector(3);
	sqorder = new_ivector(3);
	
	/**************************************/
	/*** pre-calculations of parameters ***/
	/**************************************/

	/* Initialization and parsing of Commandline */
	setdefaults();
	scancmdline(argc, argv);

	/* initialize random numbers generator */
	if (randseed >= 0)
	   fprintf(stderr, "WARNING: random seed set to %d for debugging!\n", randseed);
	randseed = initrandom(randseed);
fprintf(STDOUT, "RANDOM SEED: %d\n", randseed);

	psteptreelist = NULL;
        psteptreesum = 0;
	bestratefound = 0;

	/* get sequences */
	reset = openfiletoread(&seqfp, INFILE, "sequence data", stdinput_fp);
#if 0
fprintf(stderr, "INFILE=%s\n", INFILE);
#endif
	if (reset && (setprefix_optn < SETPREFIX_INTREE)) {
		setprefix_optn = SETPREFIX_INFILE;
   		setfilenames(setprefix_optn, savenexusjoin_optn, RESET_INFILE, INFILE);
	}
	/* XXX INFILE */
	readsequencefile(seqfp, &Maxspc, &Maxseqc, &Identif, &Namestr, &Seqchars);
	fprintf(STDOUT, "\nInput data set (%s) contains %d sequences of length %d\n", INFILE, Maxspc, Maxseqc);

	Maxbrnch = 2*Maxspc - 3;

	/* output taxa to STDOUT */
	for (taxon = 0; taxon < Maxspc; taxon++) {
		fprintf(stdout, "%4d. ", taxon+1);
		fputid(stdout, taxon);
		fprintf(stdout, "\n");
	} /* for taxon (species) */

	closefile(seqfp);		
	data_optn = guessdatatype(Seqchars, Maxspc, Maxseqc);
	
	/* translate characters into format used by ML engine */
	nuc_optn = TRUE; 
	SH_optn = FALSE;
	Seqchar = NULL;
	translatedataset(Maxspc, Maxseqc, &Maxsite, Seqchars, &Seqchar, &Seqgapchar, &Seqotherchar);
	
	/* estimate base frequencies from data set */
	Freqtpm = NULL;
	Basecomp = NULL;
	estimatebasefreqs();
	
	/* guess model of substitution */
	guessmodel();

	/* initialize guess variables */
	auto_datatype = AUTO_GUESS;
	if (data_optn == AMINOACID) auto_aamodel = AUTO_GUESS;
	else                        auto_aamodel = AUTO_DEFAULT;
	/* save guessed amino acid options */
	guessDayhf_optn    = Dayhf_optn;
	guessJtt_optn      = Jtt_optn;
	guessmtrev_optn    = mtrev_optn;
	guesscprev_optn    = cprev_optn;
	guessblosum62_optn = blosum62_optn;
	guessvtmv_optn     = vtmv_optn;
	guesswag_optn      = wag_optn;
	guesslg_optn       = lg_optn;
	/* guesspoisson_optn  = poisson_optn; */
	/* guessequalin_optn  = equalin_optn; */
	/* guessmtmam_optn    = mtmam_optn; */
	/* guessrtrev_optn    = rtrev_optn; */
	guessauto_aamodel  = auto_aamodel;


	/* check for user specified tree */
	if ((utfp = fopen(INTREE, "r")) != NULL) {
		fclose(utfp);
		if (! consensus_optn) puzzlemode = USERTREE;
		else                  puzzlemode = CONSENSUS;
	} else {
		puzzlemode = QUARTPUZ;
	}

	/* reserve memory for cluster LM analysis */
	clusterA = new_ivector(Maxspc);
	clusterB = new_ivector(Maxspc);
	clusterC = new_ivector(Maxspc);
	clusterD = new_ivector(Maxspc);


	/**********************************/
	/*** menu setting of parameters ***/
	/**********************************/

	/* set options interactively */
	if (paramfile_optn) {
		openfiletoread(&stdinput_fp, PARAMFILE, "parameter input", stdin);
	} else {
		stdinput_fp = stdin;
	}
	setoptions(stdinput_fp);

	/* open usertree file right after start */
	if (typ_optn == TREERECON_OPTN && (puzzlemode == USERTREE || puzzlemode == CONSENSUS)) {
		reset = openfiletoread(&utfp, INTREE, "user trees", stdinput_fp);
		if (reset && (setprefix_optn < SETPREFIX_PREFIX)) {
			setprefix_optn = SETPREFIX_INTREE;
   			setfilenames(setprefix_optn, savenexusjoin_optn, RESET_INTREE, INTREE);
		}
		/* XXX INFILE */
	}

	/* start main timer */
	time(&Starttime);
	Startcpu=clock();
	addtimes(OPTIONS, &tarr);

	/* symmetrize doublet frequencies if specified */
	symdoublets();

	/* initialise ML */
	mlstart();

	/* determine how many usertrees */
	if (typ_optn == TREERECON_OPTN && (puzzlemode == USERTREE || puzzlemode == CONSENSUS)) {
		numutrees = 0;		
		do {
			ci = fgetc(utfp);
			if ((char) ci == ';') numutrees++;
		} while (ci != EOF);
		rewind(utfp);
		if (numutrees < 1) {
			fprintf(STDOUT, "Unable to proceed (no tree in input tree file)\n\n\n");
#			if PARALLEL
				#if 0
					PP_Finalize();
					exit(1);
#				endif
#			endif
			tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
		}		
	}
	
/*epe   PP_SendSizes    ()/SendData() relocated*/
#	if PARALLEL
#		ifndef USE_WINDOWS
			PP_SendSizes(Maxspc, Maxsite, 
                                     numcats, Numptrn, tpmradix, 
                                     outgroup, fracconst, randseed, 
			             fixedorder_optn, rootstart_optn, 
			             rootquartsonly_optn, consensus_optn);
#		else
			PP_SendSizes(Maxspc, Maxsite, 
                                     alimaxsite, alistart, aliend, 
                                     numcats, Numptrn, tpmradix, 
			             outgroup, fracconst, randseed, 
			             fixedorder_optn, rootstart_optn, 
			             rootquartsonly_optn, consensus_optn);
#		endif
		PP_SendData(Seqpat,		       /* cmatrix */
			    Alias, Weight, constpat,      /* ivector */
			    Rates, Eval, Freqtpm,         /* dvector */
			    Evec, Ievc, iexp,
			    /* Distanmat,*/  /* dmatrix */
			    ltprobr);                     /* dcube   */
		PP_NoUpdate();
#       endif /* PARALLEL */

	addtimes(GENERAL, &tarr);
	time(&PEstStarttime);
#	ifdef PRINTTIME_DEBUG
		fprintftimespan(stdout, Starttime, PEstStarttime, Starttime, "Start -> PEst");
#	endif /* PRINTTIME_DEBUG */

	/*moved from mlstart by epe*/
	/* computing ML distances */
	computedistan();

#ifdef EPE_DEBUG
/*epe*/	for (i=1; i<Maxspc/2; i++) fprintf(STDOUT, "%.12f ", Distanmat[0][i]/100.0);
	fprintf(STDOUT, "\n");
#endif /* EPE_DEBUG */

	/* check fraction of invariable sites */
	if ((rhetmode == TWORATE || rhetmode == MIXEDRATE) && !fracinv_optim)
		/* fraction of invariable site was specified manually */
		if (fracinv > MAXFI)
			fracinv = MAXFI;

	addtimes(GENERAL, &tarr);
	time(&PEstStarttime);
#	ifdef DEBUG_PRINTTIMES
		fprintftimespan(stdout, Starttime, PEstStarttime, Starttime, "Start -> PEst");
#	endif /* DEBUG_PRINTTIMES */


	/***************************/
	/*** estimate parameters ***/
	/***************************/

	if (!(typ_optn == TREERECON_OPTN && (puzzlemode == USERTREE || puzzlemode == CONSENSUS))) {
		/* no tree present */
		estimateparametersnotree(clockmode);
	} else {
		if (utree_optn) {
			/* use 1st user tree */
			readusertree(utfp, usebranch_optn);
			rewind(utfp);
			estimateparameterstree();
		} else {
			/* don't use first user tree */
			estimateparametersnotree(clockmode);
		}
	}
	time(&PEstStoptime);
#	ifdef PRINTTIME_DEBUG
		fprintftimespan(stdout, PEstStarttime, PEstStoptime, Starttime, "PEst");
#	endif /* PRINTTIME_DEBUG */
	addtimes(PARAMEST, &tarr);

	/* compute expected Ts/Tv ratio */
	if (data_optn == NUCLEOTIDE) computeexpectations();

/*epe*/
#	if PARALLEL
		PP_Final_Update();
#	endif

	/* free_ivector(Seqgapchar); */
	/* free_ivector(Seqotherchar); */
} /* inputandinit */



/***************************************************************/ 

void evaluatetree(FILE *intreefp, FILE *outtreefp, int pmode, int utreenum, int maxutree, int *oldlocroot)
		/* FILE *intreefp,	- file to read tree(s) from		*/
		/* FILE *outtreefp,	- file to write result to		*/
		/* int   pmode,		- analysis type: QUARTPUZ/USERTREE	*/
		/* int   utreenum,	- current tree number			*/
		/* int   maxutree,	- amount of trees to analyse		*/
		/* int  *oldlocroot	- root location for clock analysis	*/
{

	switch (pmode) {
		case QUARTPUZ: /* read QP tree */
			readusertree(intreefp, usebranch_optn);			
			fprintf(STDOUT, "Computing maximum likelihood branch lengths (without clock)\n");
			fflush(STDOUT);
			/* pre-set branchlen = FALSE; parallel estim = FALSE */
			usertree_lklhd(FALSE, FALSE);
			/* for savesitelh_optn */
			allsitelkl(Ctree->condlkl, allsites[0]);
			if (rhetmode != UNIFORMRATE) {
				findbestratecombination();
			}
			break;
		case USERTREE: /* read user tree */
			readusertree(intreefp, usebranch_optn);
			fprintf(STDOUT, "Computing maximum likelihood branch lengths (without clock) for tree # %d\n", utreenum+1);
			fflush(STDOUT);

			/* pre-set branchlen =  TRUE; parallel estim = FALSE */
			if (usebranch_optn) usertree_lklhd(TRUE, FALSE);
			/* pre-set branchlen = FALSE; parallel estim = FALSE */
			else                usertree_lklhd(FALSE, FALSE);


	 		if (maxutree > 1) {
				ulkl[utreenum] = Ctree->lklhd;
				allsitelkl(Ctree->condlkl, allsites[utreenum]);
			} else { /* if maxutree == 1 */
                               	/* for savesitelh_optn */
                                allsitelkl(Ctree->condlkl, allsites[0]);
			}
			if ((utreenum==0) && (rhetmode != UNIFORMRATE)) {
				findbestratecombination();
			}
			break;
	} /* switch (pmode) */


	if (compclock) { /* clocklike branch length */
		switch (pmode) {
			case QUARTPUZ:
				fprintf(STDOUT, "Computing maximum likelihood branch lengths (with clock)\n");
				fflush(STDOUT);
				break;
			case USERTREE:
				fprintf(STDOUT, "Computing maximum likelihood branch lengths (with clock) for tree # %d\n", utreenum+1);
				fflush(STDOUT);
				break;
		}
									
		/* find best place for root */

		/* default user-set root */
		rootsearch = ROOT_USER; 

		/* save or reset the default (user set or -1) */
		if ((pmode == USERTREE) && (utreenum > 0)) { /* user trees >1 */
		    locroot = *oldlocroot;
		} else {               /* 1st user tree or reconstructed tree */
		    *oldlocroot = locroot;
		}

		if (locroot < 0) { /* not set (-1) -> automatic */
			locroot = findrootedge();
			rootsearch = ROOT_AUTO;
		}

		/* if user-specified edge for root does not exist use */
		/* displayed outgroup */
		if (!checkedge(locroot)) {
			locroot = outgroup; 
			rootsearch = ROOT_DISPLAYED;
		}

		/* compute likelihood */
		clock_lklhd(locroot);
		if (maxutree > 1) {
			ulklc[utreenum] = Ctree->lklhdc;
			allsitelkl(Ctree->condlkl, allsitesc[utreenum]);
		} else { /* if maxutree == 1 */
			/* for savesitelh_optn */
			allsitelkl(Ctree->condlkl, allsitesc[0]);
		}

	}

	/* write ML branch length tree to outree file */
	clockmode = 0; /* nonclocklike branch lengths */
	fprintf(outtreefp, "[ lh=%.6f ]", Ctree->lklhd);
	fputphylogeny(outtreefp, clockmode, FALSE); /* FALSE => don't fold lines longer 60 chars  */
		
	/* clocklike branch lengths */
	if (compclock) {
		clockmode = 1;
		fprintf(outtreefp, "[ lh=%.6f ]", Ctree->lklhdc);
		fputrooted(outtreefp, locroot, FALSE);
	}
	fflush(outtreefp);
} /* evaluatetree */

/***************************************************************/ 

void memcleanup() { 
	int i;
	if (puzzlemode == QUARTPUZ && typ_optn == TREERECON_OPTN) {
		free(splitfreqs);
		free(splitpatterns);
		free(splitsizes);
		free_ivector(consconfid);
		free_ivector(conssizes);
		free_cmatrix(consbiparts);
		free_ulivector(badtaxon);
		free_ulimatrix(qinfomatr);

		if(readsubset_optn) {
                	free_imatrix(ss_setovlgraph);
                	free_imatrix(ss_setoverlaps);
                	free_imatrix(ss_setovllist);
                	free_ivector(ss_setovllistsize);
                	free_imatrix(ss_matrix);
                	free_imatrix(ss_list);
                	free_ivector(ss_listsize);
		}
	}
	free_cmatrix(Identif);
	free_cmatrix(Namestr);
	free_dvector(Freqtpm);
	free_imatrix(Basecomp);
	free_ivector(clusterA);
	free_ivector(clusterB);
	free_ivector(clusterC);
	free_ivector(clusterD);
	free_dvector(qweight);
	free_dvector(sqdiff);
	free_ivector(qworder);
	free_ivector(sqorder);
	freetreelist(&psteptreelist, &psteptreenum, &psteptreesum);
	freequartets();

	if (typ_optn == LIKMAPING_OPTN) {
		for (i=0; i<Maxspc+1; i++){
			free(qcountarray[i]);
		}
		free(qcountarray);
	}

} /* memcleanup */

/***************************************************************/
/***                                                         ***/
/*** routines for consensus tree computation                 ***/
/***                                                         ***/
/***************************************************************/
/*   produce consensus from usertrees  (onlyconsensus.c)       */
/***************************************************************/ 


/* print i leading spaces to stream fp */
void indent(FILE *fp, int i)
{
  int n;
  for (n=0; n < i; n++)
    fputc(' ', fp);
} /* indent */

/******************/

/* print speciesnames in leafset (size = setsize) to stream fp */
void printset(FILE *fp, int *leafset, int setsize)
{
   int i;
   fprintf(fp, "Size=%d: ", setsize);

   for (i = 0; i < (setsize) ; i++) {
       fprintf(fp, "%d (", leafset[i]);
       fputid10(fp, leafset[i]);
       fprintf(fp, "),");
   }
   fprintf(fp, "\n");
   fflush(fp);
} /* printset */

/***************************************************************************/

/* copy subtree recursively */
void subtree2bipart(int      depth,        /* depth from root (for debug)   */
                    cmatrix  bip,          /* list of bipartitions          */
                    int     *numsp,        /* number of bipartitions in it  */
                    int     *leafset,      /* set of leaves in this subtree */
                    int     *setsize,      /* size of the set of leaves     */
                    Node    *np)           /* edge in puzzling step tree    */
{
        int   x;
        int  *leafsetr;         /* set of leaves in this subtree */
        int   setsizer;         /* size of the set of leaves     */
	Node *tp;

        /* test whether we are on an external node */
        if (np->isop == NULL) {
           leafset[(*setsize)] = np->number;
           (*setsize)++;
	   return;
	}

        /* leafsetr = new_ivector(Maxspc); */
        setsizer = 0;
        
        /* we are NOT on a leaf */
	tp = np->isop;
	while (tp != np) {
        	leafsetr = new_ivector(Maxspc);
        	setsizer = 0;
        	for (x = 0; x < setsizer ; x++) {
			leafsetr[x]=-1;
		}
			
        	subtree2bipart(depth + 1, bip, numsp, leafsetr, &setsizer, tp->kinp);

        	for (x = 0; x < setsizer ; x++) {
        	    leafset[(*setsize) + x] = leafsetr[x];
        	}
        	(*setsize) += setsizer;

		tp = tp->isop;
		free_ivector(leafsetr);
	}
	if (depth > 1){
       		for (x = 0; x < (*setsize) ; x++) {
		    bip[*numsp][leafset[x]] = '.';
       		}

#		ifdef VERBOSE1
			indent(stderr, depth*2);
       			for (x = 0; x < Maxspc ; x++) {
	       	    		fprintf(stderr, "%c", bip[*numsp][x]);
       			}
       			fprintf(stderr, "\n");
#		endif /* VERBOSE */

		(*numsp)++;
	}

} /* subtree2bipart */


/***************************************************************************/


/* copy treestructure to sorting structure */
void tree2bipart(cmatrix bip, int *numsp)
{
        int *leafset;         /* set of leaves in this subtree */
        int  setsize;         /* size of the set of leaves     */
	int depth;

        leafset = new_ivector(Maxspc);

	depth = 0;
        setsize = 0;

        /* we are NOT on a leaf */
        subtree2bipart(depth + 1, bip, numsp, leafset, &setsize, Ctree->ebrnchp[outgroup]->kinp);
	free_ivector(leafset);

} /* tree2bipart */


/***************************************************************************/
/***************************************************************************/



void usertreeconsensus(FILE* utfp, FILE* outfp, int *oldlocrootptr)
{
	int   ci;
	int   i; 
	int   n1;
	int   n2;
	int   numsp;
	FILE *treefp;
	FILE *splitoccurfp; /* file pointer for split occurrences */

	fprintf(STDOUT, "Performing consensus construction\n");
	fflush(STDOUT);
	numutrees = 0;
	do {
		ci = fgetc(utfp);
		if ((char) ci == ';') numutrees++;
	} while (ci != EOF);
	rewind(utfp);
	if (numutrees < 1) {
		fprintf(STDOUT, "Unable to proceed (no tree in input tree file)\n\n\n");
#		if 0
			exit(1);
#		endif
		tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
	}

	/* prepare for consensus tree analysis */
	initconsensus();
       	if(savesplitoccurfile_optn){
		openfiletowrite(&splitoccurfp, SPLITOCCUR, "split occurrence file", stdinput_fp);
		fprintf(splitoccurfp, "%s\t%s\t%s\n", "split", "tree", "curroccur");
		fclose(splitoccurfp);
	}


	for (i = 0; i < numutrees; i++) {
		/* fprintf(stdout, "%d ", i); */

		readusertree(utfp, usebranch_optn); 

        	for (n1 = 0; n1 < Maxspc - 3; n1++)
                	for (n2 = 0; n2 < Maxspc; n2++)
                        	biparts[n1][n2] = '*';
		numsp = 0;
		tree2bipart(biparts, &numsp);

		makenewsplitentries(biparts, numsp, &splitpatterns, &splitsizes, &splitfreqs, &numbiparts, &maxbiparts, i+1, Maxspc, savesplitoccurfile_optn);

	}

	/* compute majority rule consensus tree */
	makeconsensus(numutrees, FALSE);

	/* write consensus tree */
	openfiletowrite(&treefp, TREEFILE, "output tree(s)", stdinput_fp);

	tmpfp = tmpfile();
	writeconsensustree(tmpfp, FALSE, qsupportarr);

#if 0
	if (! skipmlbranch_optn) {
#endif
	if (dotreelh_optn) {
		rewind(tmpfp);
		openfiletowrite(&treefp, TREEFILE, "output tree(s)", stdinput_fp);
		evaluatetree(tmpfp, treefp, QUARTPUZ, 0, 1, oldlocrootptr);
	} else {
		writeconsensustree(treefp, FALSE, qsupportarr);
	}
		
	closefile(utfp);
	closefile(treefp);
	closefile(tmpfp);

	 /* exit(0); */

} /* usertreeconsensus */

/* end onlyconsensus.c */



/******************************************************************************/
/* main part                                                                  */
/******************************************************************************/

int main(int argc, char *argv[])
{
	int i, oldlocroot=0;
	
#	if !PARALLEL
#		ifdef USE_CONSOLE
        		argc = ccommand(&argv);
#		endif
#	endif

	/* start main timer */
	time(&walltimestart);
	cputimestart = clock();
	inittimearr(&tarr);

#	if PARALLEL
		PP_Init(&argc, &argv);
		if (PP_IamSlave) {
			slave_main(argc, argv);
		} else {
#	endif /* PARALLEL */
	
	inputandinit(&argc, &argv);

	fprintf(STDOUT, "Writing parameters to file %s\n", OUTFILE);
	openfiletowrite(&ofp, OUTFILE, "general output", stdinput_fp);
	/* openfiletowrite(&ofp, "xxxx", "general output", stdinput_fp); */
	writeoutputfile(ofp,WRITEPARAMS, clockmode);
	fclose(ofp);


	fprintf(STDOUT, "Writing parameters to file %s\n", OUTFILE);
	/* write distance matrix */
	fprintf(STDOUT, "Writing pairwise distances to file %s\n", DISTANCES);
	openfiletowrite(&dfp, DISTANCES, "pairwise distances", stdinput_fp);
	putdistance(dfp);
	closefile(dfp);

	fprintf(STDOUT, "Writing parameters to file %s\n", OUTFILE);
	if(savetstv_optn)
		puttstv();	/* output of ts:tv data, if nucleotides */

	if(saveeditdist_optn)
		puteditdist();	/* output of edit distances */

	fprintf(STDOUT, "Writing parameters to file %s\n", OUTFILE);

/*epe   PP_SendSizes()/SendData() relocated*/
#if 0

#	if PARALLEL
#ifndef USE_WINDOWS
		PP_SendSizes(Maxspc, Maxsite, numcats, Numptrn, tpmradix, outgroup, fracconst, randseed, fixedorder_optn, consensus_optn);
#else
		PP_SendSizes(Maxspc, Maxsite, alimaxsite, alistart, aliend, numcats, Numptrn, tpmradix, outgroup, fracconst, randseed, fixedorder_optn, consensus_optn);
#endif
		PP_SendData(Seqpat,                       /* cmatrix */
		            Alias, Weight, constpat,      /* ivector */
		            Rates, Eval, Freqtpm,         /* dvector */
		            Evec, Ievc, iexp, Distanmat,  /* dmatrix */
		            ltprobr);                     /* dcube   */
#	endif /* PARALLEL */
#endif

	psteptreestrlen = (Maxspc * (int)(1 + log10((double)Maxspc))) +
			  (Maxspc * 3);

	if (savenexus_optn) {
		FILE *nexfp;
		if (savenexusjoin_optn) {
			openfiletowrite(&nexfp, NEXALL, "joint nexus file", stdinput_fp);
			fprintf(nexfp, "#NEXUS\n\n");
			fflush(nexfp);
			fprintfnexustaxablock(nexfp, Maxspc);  /* print NEXUS taxa block */
			fprintf(nexfp, "\n");
			putdistancenexus(nexfp);
			fprintf(nexfp, "\n");
			fclose(nexfp);
		} else {
			if ((puzzlemode == QUARTPUZ) || (puzzlemode == CONSENSUS)) {
				if (savenexusptsplits_optn) {
					openfiletowrite(&nexfp, NEXPTSPLITS, "joint nexus file", stdinput_fp);
					fprintf(nexfp, "#NEXUS\n\n");
					fflush(nexfp);
					fprintfnexustaxablock(nexfp, Maxspc);  /* print NEXUS taxa block */
					fprintf(nexfp, "\n");
					putdistancenexus(nexfp);
					fprintf(nexfp, "\n");
					fclose(nexfp);
				} /* if savenexusptsplits_optn */
				if (savenexusptorder_optn) {
					openfiletowrite(&nexfp, NEXPTORDER, "nexus trees file", stdinput_fp);
					fprintf(nexfp, "#NEXUS\n\n");
					fflush(nexfp);
					fprintfnexustaxablock(nexfp, Maxspc);  /* print NEXUS taxa block */
					fprintf(nexfp, "\n");
					putdistancenexus(nexfp);
					fprintf(nexfp, "\n");
					fclose(nexfp);
				} /* if savenexuspttrees_optn */
			} /* if savenexuspttrees_optn */
		}
	} /* if savenexus_optn */

	switch (typ_optn) {
		case TREERECON_OPTN: /* tree reconstruction */

			if (puzzlemode == QUARTPUZ) { /* quartet puzzling */
				recon_tree();
			} /* quartet puzzling */
			break;
	
		case LIKMAPING_OPTN: /* likelihood mapping */
fprintf(stderr, "PPP1: %d (%s:%d)\n", PPP1++, __FILE__, __LINE__);
			qcountarray = (uli **)calloc(Maxspc+1, sizeof(uli *));
			for (i=0; i<Maxspc+1; i++){
				qcountarray[i] = (uli *)calloc(LM_MAX, sizeof(uli));
			}
			map_lklhd(quartcrit_optn, qcountarray);
fprintf(stderr, "PPP1: %d (%s:%d)\n", PPP1++, __FILE__, __LINE__);
			break;
	} /* switch typ_optn */


	free_cmatrix(Seqchar);
	free_cmatrix(Seqchars);

	/* reserve memory for tree statistics */
	if (typ_optn == TREERECON_OPTN) {
/* CONSENSUS -> QUARTPUZ, allocates unnecessary memory (HAS) */
		if ((puzzlemode == USERTREE) && numutrees > 1) {
			ulkl = new_dvector(numutrees);
			allsites = new_dmatrix(numutrees,Numptrn);
			if (compclock) {
				ulklc = new_dvector(numutrees);
				allsitesc = new_dmatrix(numutrees,Numptrn);
			}
		} else { /* QUARTPUZ, CONSENSUS */
			allsites = new_dmatrix(1,Numptrn);
			if (compclock) {
				allsitesc = new_dmatrix(1,Numptrn);
			}
		}
	}

	/* write puzzling step tree list to ptorder file */
	if ((listqptrees_optn == PSTOUT_ORDER) || (listqptrees_optn == PSTOUT_LISTORDER)) {
		openfiletowrite(&qptorder, OUTPTORDER, "puzzling step trees (unique)", stdinput_fp);

		fprintfsortedpstrees(qptorder, psteptreelist, psteptreenum, psteptreesum, PT_FTYPE_PTORDER, 0.0);
		closefile(qptorder);
	}

	/* compute ML branch lengths for QP tree and for 1st user tree */
	switch(typ_optn) {
		case TREERECON_OPTN:
			addtimes(GENERAL, &tarr);

			/* write puzzling step tree list to nexus file */
/* not for consensus!!! for consensus, no tree read yet!!! (HAS) nex */ 
/* 			if (savenexusptorder_optn && ((puzzlemode == QUARTPUZ) || (puzzlemode == CONSENSUS))) { */
/*			} */
			if (savenexusptorder_optn && (puzzlemode == QUARTPUZ)) {
				FILE *nexfp;
				openfiletoappend(&nexfp, NEXPTSPLITS, "nexus splits file", stdinput_fp);
				fprintfsortedpstrees(nexfp, psteptreelist, psteptreenum, psteptreesum, PT_FTYPE_NEXUS, 0.0);
				/* fprintfsortedpstrees(nexfp, psteptreelist, psteptreenum, psteptreesum, PT_FTYPE_NEXUS, 0.0); */
				/* fprintfsortedpstrees(nexfp, psteptreelist, psteptreenum, psteptreesum, PT_FTYPE_NEXUS_NOTRANSLATE, 0.0); */
				fprintf(nexfp, "\n");
				fclose(nexfp);
			} /* if savenexusptorder_optn */

			switch (puzzlemode) {
				case QUARTPUZ: /* read QP tree */
#if 0
					if (! skipmlbranch_optn) {
					}
#endif
					if (dotreelh_optn) {
						rewind(tmpfp);
						openfiletowrite(&tfp, TREEFILE, "output tree(s)", stdinput_fp);
						evaluatetree(tmpfp, tfp, puzzlemode, 0, 1, &oldlocroot);
						addtimes(TREEEVAL, &tarr);
						closefile(tmpfp);
						closefile(tfp);
					}

					openfiletoappend(&ofp, OUTFILE, "general output", stdinput_fp);
					writeoutputfile(ofp,WRITEREST,clockmode);
					break;
				case USERTREE: /* read user tree */
					openfiletoappend(&ofp, OUTFILE, "general output", stdinput_fp);

					openfiletowrite(&tfp, TREEFILE, "output tree(s)", stdinput_fp);
					for (i = 0; i < numutrees; i++) {
						evaluatetree(utfp, tfp, puzzlemode, i, numutrees, &oldlocroot);
						if (i==0) writeoutputfile(ofp,WRITEREST,clockmode);
						writecutree(ofp, i+1, clockmode);
						addtimes(TREEEVAL, &tarr);
					}
					closefile(tfp);
					closefile(utfp);
					break;
				case CONSENSUS: /* USERCONSENSUS */
					openfiletoappend(&ofp, OUTFILE, "general output", stdinput_fp);
					usertreeconsensus(utfp, ofp, &oldlocroot); /* ends with exit */
					openfiletoappend(&ofp, OUTFILE, "general output", stdinput_fp);
					writeoutputfile(ofp,WRITEREST,clockmode);
					break;
				default: /* e.g. distances only */
					openfiletoappend(&ofp, OUTFILE, "general output", stdinput_fp);
					writeoutputfile(ofp,WRITEREST,clockmode);
					break;
			} /* switch puzzlemode */
			break;
		default:
			openfiletoappend(&ofp, OUTFILE, "general output", stdinput_fp);
			writeoutputfile(ofp,WRITEREST,clockmode);
			break;
	} /* switch typ_optn */


	/* print tree statistics */
	if ((typ_optn == TREERECON_OPTN) && (puzzlemode == USERTREE) && (numutrees > 1) && dotreetest_optn) 
		printtreestats(ofp, ulkl, ulklc, numutrees, 
			allsites, allsitesc, Alias, Maxsite,
			Numptrn, Weight, compclock);

	
	if ((savesitelh_optn || savesitelhb_optn) && (typ_optn == TREERECON_OPTN)) {
		if (savesitelh_optn) {
			FILE *outf;
			openfiletowrite(&outf, SITELH, "write site likelihood", stdinput_fp);
			if ((puzzlemode == QUARTPUZ) || (puzzlemode == CONSENSUS))
				writesitelklmatrixphy(outf, 1, Maxsite, allsites, allsitesc, compclock);
			else /* puzzlemode == CONSENSUS ??? */
				writesitelklmatrixphy(outf, numutrees, Maxsite, allsites, allsitesc, compclock);
			fclose(outf);
		}
	}

	/* free memory for tree statistics */
	if (typ_optn == TREERECON_OPTN) {
		if ((puzzlemode == USERTREE || puzzlemode == CONSENSUS) && numutrees > 1) {
			free_dvector(ulkl);
			free_dmatrix(allsites);
			if (compclock) {
				free_dvector(ulklc);
				free_dmatrix(allsitesc);
			}
		} else {
			free_dmatrix(allsites);
			if (compclock) 
				free_dmatrix(allsitesc);
		}
	}
	
#	if PARALLEL
		PP_SendDone();
#	endif /* PARALLEL */

	/* write CPU/Wallclock times and parallel statistics */
	time(&walltimestop);
	cputimestop = clock();
	addtimes(OVERALL, &tarr);
#	ifdef TIMEDEBUG
		printtimearr(&tarr);
#	endif /* TIMEDEBUG */
        fullcpu          = tarr.fullcpu;
        fulltime         = tarr.fulltime;

#	if PARALLEL
		writetimesstat(ofp);
#	endif /* PARALLEL */

	/* stop timer */
	time(&Stoptime);
	Stopcpu=clock();
	timestamp(ofp);
	closefile(ofp);


        /* printbestratecombination(stderr); */
	mlfinish();

	fprintf(STDOUT, "\nAll results written to disk:\n");
	fprintf(STDOUT, "       Puzzle report file:           %s\n", OUTFILE);
	fprintf(STDOUT, "       Likelihood distances:         %s\n", DISTANCES);
	
	if (typ_optn == TREERECON_OPTN && puzzlemode != PAIRDIST) 
		fprintf(STDOUT, "       Phylip tree file:             %s\n", TREEFILE);
	if (typ_optn == TREERECON_OPTN && puzzlemode == QUARTPUZ) {
		if ((listqptrees_optn == PSTOUT_ORDER) ||(listqptrees_optn == PSTOUT_LISTORDER)) 
			fprintf(STDOUT, "       Unique puzzling step trees:   %s\n", OUTPTORDER);	
		if ((listqptrees_optn == PSTOUT_LIST) ||(listqptrees_optn == PSTOUT_LISTORDER)) 
			fprintf(STDOUT, "       Puzzling step tree list:      %s\n", OUTPTLIST);	
		if (saveptall_optn == PTALL_OUT) 
			fprintf(STDOUT, "       All puzzling step trees:      %s\n", OUTPTALL);	
	}
	if (typ_optn == TREERECON_OPTN && (puzzlemode == USERTREE || puzzlemode == CONSENSUS)) {

		if (savesplitoccurfile_optn)
			fprintf(STDOUT, "       Split occurrence file:        %s\n", SPLITOCCUR);
	}
	if (dotreelh_optn && typ_optn == TREERECON_OPTN && puzzlemode != PAIRDIST) {
		if (savesitelh_optn)
			fprintf(STDOUT, "       Site likelihoods (PHYLIP):    %s\n", SITELH);	
		if (savesitelhb_optn)
			fprintf(STDOUT, "       Site likelihoods (binary):    %s\n", SITELHB);	
		if (savesiterate_optn)
			fprintf(STDOUT, "       Site rates (PHYLIP):          %s\n", SITERATE);	
		if (savesiterateb_optn)
			fprintf(STDOUT, "       Site rates (binary):          %s\n", SITERATEB);	
		if (savelmaptab_optn) 
			fprintf(STDOUT, "       Likelihood mapping table:     %s\n", LMAPTAB);
		if (saveptsplitsfile_optn)
			fprintf(STDOUT, "       Splits:                       %s\n", PTSPLITS);	
		if (savequart_optn) {
			if (saveqlhbin_optn)
				fprintf(STDOUT, "       Quartet file (binary):        %s\n", ALLQUART);
			else
				fprintf(STDOUT, "       Quartet file (text):          %s\n", ALLQUART);
		}
	}
	if (show_optn && typ_optn == TREERECON_OPTN && puzzlemode == QUARTPUZ) 
		fprintf(STDOUT, "       Unresolved quartets:          %s\n", UNRESOLVED);
	if (typ_optn == LIKMAPING_OPTN)  {
		fprintf(STDOUT, " Likelihood mapping diagram (EPS):   %s\n", TRIANGLEEPS);
		fprintf(STDOUT, " Likelihood mapping diagram (SVG):   %s\n", TRIANGLESVG);
		if (savelmaptab_optn) 
			fprintf(STDOUT, "       Likelihood mapping table:     %s\n", LMAPTAB);
	}
	if (savetstv_optn)
		fprintf(STDOUT, "       Pair substitution counts:     %s\n", TSTV);	
	if (saveeditdist_optn)
		fprintf(STDOUT, "       Pairwise edit distances:      %s\n", EDITDIST);	
	if (saverdstatsfile_optn)
		fprintf(STDOUT, "       RecDetec Statistics:          %s\n", RDSTATS);	
	if (savealiinfofile_optn)
		fprintf(STDOUT, "       Informative sites statistics: %s\n", ALIINFO);
	if (savealiinfonumfile_optn)
		fprintf(STDOUT, "       Inform. sites stat. (counts): %s\n", ALIINFONUM);
	if (savesitefreqs_optn)
		fprintf(STDOUT, "       Site character frequensies:   %s\n", SITEFREQS);	
	fprintf(STDOUT, "\n");

#	ifdef DEBUG_PRINTTIMES
		fprintftimespan(stdout, PStepStoptime, Stoptime, Starttime, "Pstep -> end");
#	endif /* DEBUG_PRINTTIMES */

	/* runtime message */
	fprintf(STDOUT,
		"The parameter estimation took %.2f seconds (= %.2f minutes = %.2f hours)\n",
			difftime(PEstStoptime, PEstStarttime), difftime(PEstStoptime, PEstStarttime)/60.,
			difftime(PEstStoptime, PEstStarttime)/3600.);
	if (puzzlemode == QUARTPUZ && typ_optn == TREERECON_OPTN) {
		fprintf(STDOUT,
			"The ML step took              %.2f seconds (= %.2f minutes = %.2f hours)\n",
				difftime(MLstepStoptime, MLstepStarttime), difftime(MLstepStoptime, MLstepStarttime)/60.,
				difftime(MLstepStoptime, MLstepStarttime)/3600.);
		fprintf(STDOUT,
			"The puzzling step took        %.2f seconds (= %.2f minutes = %.2f hours)\n",
				difftime(PStepStoptime, PStepStarttime), difftime(PStepStoptime, PStepStarttime)/60.,
				difftime(PStepStoptime, PStepStarttime)/3600.);
	}
	fprintf(STDOUT, 
		"The computation took %.2f seconds (= %.2f minutes = %.2f hours)\n",
			difftime(Stoptime, Starttime), difftime(Stoptime, Starttime)/60.,
			difftime(Stoptime, Starttime)/3600.);
	fprintf(STDOUT, 
		"     including input %.2f seconds (= %.2f minutes = %.2f hours)\n",
			fulltime, fulltime/60., fulltime/3600.);
#ifdef TIMEDEBUG
	fprintf(STDOUT, 
		"and %.0f seconds CPU time (= %.2f minutes = %.2f hours)\n\n",
			fullcpu, fullcpu/60., fullcpu/3600.);
#endif /* TIMEDEBUG */

	/* free memory */
	memcleanup();

#	if PARALLEL
		} /* !IamSlave */
#		if 0
			PP_Finalize();
#		endif
#	endif /* PARALLEL */

	/* printf("XXX: exit_wait_optn = %c\n", exit_wait_optn ? '+' : '-'); */
	tp_exit(0, NULL, TRUE, __FILE__, __LINE__, exit_wait_optn);
	return 0;
} /* main */


/* compare function for uli - sort largest numbers first */
int ulicmp(const void *ap, const void *bp)
{
	uli a, b;
	
	a = *((uli *) ap);
	b = *((uli *) bp);

	if (a > b) return -1;
	else if (a < b) return 1;
	else return 0;
} /* ulicmp */

/* compare function for int - sort smallest numbers first */
int intcmp(const void *ap, const void *bp)
{
	int a, b;
	
	a = *((int *) ap);
	b = *((int *) bp);

	if (a < b) return -1;
	else if (a > b) return 1;
	else return 0;
} /* intcmp */
