/*
 *  MrBayes 3
 *
 *  (c) 2002-2010
 *
 *  John P. Huelsenbeck
 *  Dept. Integrative Biology
 *  University of California, Berkeley
 *  Berkeley, CA 94720-3140
 *  johnh@berkeley.edu
 *
 *  Fredrik Ronquist
 *  Swedish Museum of Natural History
 *  Box 50007
 *  SE-10405 Stockholm, SWEDEN
 *  fredrik.ronquist@nrm.se
 *
 *  With important contributions by
 *
 *  Paul van der Mark (paulvdm@sc.fsu.edu)
 *  Maxim Teslenko (maxim.teslenko@nrm.se)
 *
 *  and by many users (run 'acknowledgements' to see more info)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details (www.gnu.org).
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <memory.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <stdarg.h>
#include <assert.h>
#include "mb.h"
#include "globals.h"
#include "bayes.h"
#include "best.h"
#include "mbbeagle.h"
#include "mcmc.h"
#include "model.h"
#include "command.h"
#include "mbmath.h"
#include "sump.h"
#include "sumt.h"
#include "plot.h"
#include "tree.h"
#include "utils.h"

char *svnRevisionMcmcC="$Rev: 513 $";   /* Revision keyword which is expanded/updated by svn on each commit/update*/

#if defined(BEAGLE_ENABLED)
#include "libhmsbeagle/beagle.h"
#endif

#if defined(WIN_VERSION) && !defined(__GNUC__)
#define VISUAL
#endif

#ifdef VISUAL
/* NO_ERROR is defined in mb.h (as 0) and also in WinError.h (as 0L) */
#undef NO_ERROR 
/* ERROR is defined in mb.h (as 1) and also in WinGDI.h (as 0). we use the mb.h value */
#undef ERROR
#include <windows.h>
#undef ERROR
#define ERROR 1
#include <signal.h>
#else
#include <signal.h>
typedef void (*sighandler_t)(int);
#endif
/*static int requestAbortRun;*/

#if defined(__MWERKS__)
#include "SIOUX.h"
#endif

#define	A							0
#define	C							1
#define	G							2
#define	T							3
#define	AA							0
#define	AC							1
#define	AG							2
#define	AT							3
#define	CA							4
#define	CC							5
#define	CG							6
#define	CT							7
#define	GA							8
#define	GC							9
#define	GG							10
#define	GT							11
#define	TA							12
#define	TC							13
#define	TG							14
#define	TT							15
#define LIKE_EPSILON				1.0e-300
#define BRLEN_EPSILON				1.0e-8
#define BEAGLE_RESCALE_FREQ			160
#define BEAGLE_RESCALE_FREQ_DOUBLE	10			/* The factor by which BEAGLE_RESCALE_FREQ get multiplied if double presition is used */
#define RESCALE_FREQ				1			/* node cond like rescaling frequency */
#define	SCALER_REFRESH_FREQ			1			/* generations between refreshing scaler nodes */
#define GIBBS_SAMPLE_FREQ			100			/* generations between gibbs sampling of gamma cats */
#define MAX_SMALL_JUMP				10			/* threshold for precalculating trans probs of adgamma model */
#define BIG_JUMP					100			/* threshold for using stationary approximation */
#define MAX_RUNS                    120         /* maximum number of independent runs */
#define	PFILE                       0
#define TFILE						1
#define	CALFILE						2
#define MCMCFILE                    3
#define MAXLOGTUNINGPARAM           100000      /* limit to ensure convergence for autotuning */
#define SAMPLE_ALL_SS               /*if defined makes ss sample every generation instead of every sample frequency*/


/* debugging compiler statements */
#undef	DEBUG_CREATEPARSMATRIX
#undef	DEBUG_SETUPTERMSTATE
#undef	DEBUG_INITCHAINCONDLIKES
#undef	DEBUG_SETCHAINPARAMS
#undef	DEBUG_RUNCHAIN
#undef	DEBUG_NOSHORTCUTS
#undef	DEBUG_NOSCALING
#undef	DEBUG_LOCAL
#undef	DEBUG_SPRCLOCK
#undef	DEBUG_TIPROBS_STD
#undef	DEBUG_RUN_WITHOUT_DATA
#undef	DEBUG_UNROOTED_SLIDER
#undef	DEBUG_ParsSPR
#undef  DEBUG_CONSTRAINTS
#undef  DEBUG_ExtSS
#undef  DEBUG_CSLIDER
#undef  DEBUG_ExtSPRClock
#undef  DEBUG_ParsSPRClock
#undef  DEBUG_ExtSS
#undef  DEBUG_ExtTBR
#undef  DEBUG_MOVE_TREEAGE
#undef  DEBUG_LNLIKELIHOODRATIO
#undef  DEBUG_NNIClock
#undef  DEBUG_SPLITMERGE
#undef  SHOW_MOVE

#undef  DEBUG_SLOW //defining it enable extra slow debug option 

//#define TIMING_ANALIZ
#if defined (TIMING_ANALIZ)
    static clock_t         CPUCondLikeDown;
    static clock_t         CPUScalers;
    static clock_t         CPUScalersRemove;
    static clock_t         CPUCondLikeRoot;
    static clock_t         CPULilklihood;

#define TIME(X1,CPUtime)\
                {CPUTimeStart = clock();\
				X1;\
                CPUtime += (clock()-CPUTimeStart);}
#else
    #define TIME(X1,CPUtime)\
    X1;
#endif


#define TNODE TreeNode

#if defined (MPI_ENABLED)
#define ERROR_TEST2(failString,X1,X2) \
	MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);\
	if (sumErrors > 0)\
		{\
        MrBayesPrint ("%s   "failString"\n", spacer);\
		X1;X2;\
		}
#	else
#define ERROR_TEST2(failString,X1,X2) \
	if (nErrors > 0)\
		{\
        MrBayesPrint ("%s   "failString"\n", spacer);\
		X1;X2;\
		}
#	endif



/* local (to this file) data types */
typedef struct pfnode
    {
    struct pfnode   *left;
    struct pfnode   *right;
    int             *count;
    SafeLong        *partition;
    } PFNODE;


/* local prototypes */
int     AddTreeSamples (int from, int to, int saveToList);
PFNODE *AddPartition (PFNODE *r, SafeLong *p, int runId);
int     AddTreeToPartitionCounters (Tree *tree, int treeId, int runId);
int     AttemptSwap (int swapA, int swapB, SafeLong *seed);
int	    Bit (int n, SafeLong *p);
void    BuildExhaustiveSearchTree (Tree *t, int chain, int nTaxInTree, TreeInfo *tInfo);
int     BuildStepwiseTree (Tree *t, int chain, SafeLong *seed);
int     CalcLike_Adgamma (int d, Param *param, int chain, MrBFlt *lnL);
void    CalcPartFreqStats (PFNODE *p, STATS *stat);
void    CalculateTopConvDiagn (int numSamples);
#ifdef VISUAL
BOOL WINAPI CatchInterrupt(DWORD signum);
#else
void    CatchInterrupt(int signum);
#endif
int     CheckTemperature (void);
void	CloseMBPrintFiles (void);
PFNODE *CompactTree (PFNODE *p);
int     CondLikeDown_Bin (TreeNode *p, int division, int chain);

#		if !defined (SSE_ENABLED)
int     CondLikeDown_Gen (TreeNode *p, int division, int chain);
#		else
int		CondLikeDown_Gen_SSE (TreeNode *p, int division, int chain);
#		endif

int     CondLikeDown_Gen_GibbsGamma (TreeNode *p, int division, int chain);

#		if !defined (SSE_ENABLED)
int	    CondLikeDown_NUC4 (TreeNode *p, int division, int chain);
#		else
int	    CondLikeDown_NUC4_SSE (TreeNode *p, int division, int chain);
#		endif

int		CondLikeDown_NUC4_GibbsGamma (TreeNode *p, int division, int chain);

#		if !defined (SSE_ENABLED)
int	    CondLikeDown_NY98 (TreeNode *p, int division, int chain);
#		else
int	    CondLikeDown_NY98_SSE (TreeNode *p, int division, int chain);
#		endif

int     CondLikeDown_Std (TreeNode *p, int division, int chain);

#		if !defined (SSE_ENABLED)
int     CondLikeRoot_Bin (TreeNode *p, int division, int chain);
#		else
int		CondLikeRoot_Bin_SSE (TreeNode *p, int division, int chain);
#		endif

#		if !defined (SSE_ENABLED)
int     CondLikeRoot_Gen (TreeNode *p, int division, int chain);
#		else
int		CondLikeRoot_Gen_SSE (TreeNode *p, int division, int chain);
#		endif

int     CondLikeRoot_Gen_GibbsGamma (TreeNode *p, int division, int chain);

#		if !defined (SSE_ENABLED)
int	    CondLikeRoot_NUC4 (TreeNode *p, int division, int chain);
#		else
int	    CondLikeRoot_NUC4_SSE (TreeNode *p, int division, int chain);
#		endif

int	    CondLikeRoot_NUC4_GibbsGamma (TreeNode *p, int division, int chain);

#		if !defined (SSE_ENABLED)
int	    CondLikeRoot_NY98 (TreeNode *p, int division, int chain);
#		else
int		CondLikeRoot_NY98_SSE (TreeNode *p, int division, int chain);
#		endif

int     CondLikeRoot_Std (TreeNode *p, int division, int chain);

#		if !defined (SSE_ENABLED)
int	    CondLikeScaler_Gen (TreeNode *p, int division, int chain);
#		else
int	    CondLikeScaler_Gen_SSE (TreeNode *p, int division, int chain);
#		endif

int	    CondLikeScaler_Gen_GibbsGamma (TreeNode *p, int division, int chain);

#		if !defined (SSE_ENABLED)
int	    CondLikeScaler_NUC4 (TreeNode *p, int division, int chain);
#		else
int	    CondLikeScaler_NUC4_SSE (TreeNode *p, int division, int chain);
#		endif

int	    CondLikeScaler_NUC4_GibbsGamma (TreeNode *p, int division, int chain);

#		if !defined (SSE_ENABLED)
int	    CondLikeScaler_NY98 (TreeNode *p, int division, int chain);
#		else
int		CondLikeScaler_NY98_SSE (TreeNode *p, int division, int chain);
#		endif

int     CondLikeScaler_Std (TreeNode *p, int division, int chain);
int     CondLikeUp_Bin (TreeNode *p, int division, int chain);
int     CondLikeUp_Gen (TreeNode *p, int division, int chain);
int     CondLikeUp_NUC4 (TreeNode *p, int division, int chain);
int     CondLikeUp_Std (TreeNode *p, int division, int chain);
int     ConfirmAbortRun(void);
void    CopyParams (int chain);
void	CopyPFNodeDown (PFNODE *p);
void    CopySiteScalers (ModelInfo *m, int chain);
void    CopyTrees (int chain);
#		if defined (MPI_ENABLED)
int     DoesProcHaveColdChain (void);
#       endif
int     ExhaustiveParsimonySearch (Tree *t, int chain, TreeInfo *tInfo);
int     ExtendChainQuery (void);
int     FillNumSitesOfPat (void);
TNODE  *FindBestNode (Tree *t, TreeNode *p, TreeNode *addNode, CLFlt *minLength, int chain);
void    FlipCijkSpace (ModelInfo *m, int chain);
void    FlipCondLikeSpace (ModelInfo *m, int chain, int nodeIndex);
void    FlipNodeScalerSpace (ModelInfo *m, int chain, int nodeIndex);
void    FlipSiteScalerSpace (ModelInfo *m, int chain);
void    FlipTiProbsSpace (ModelInfo *m, int chain, int nodeIndex);
void    FreeChainMemory (void);
MrBFlt  GetFitchPartials (ModelInfo *m, int chain, int source1, int source2, int destination);
MrBFlt  GetParsDP (Tree *t, TreeNode *p, int chain);
void    GetParsFP (Tree *t, TreeNode *p, int chain);
int     GetParsimonyBrlens (Tree *t, int chain, MrBFlt *brlens);
MrBFlt  GetParsimonyLength (Tree *t, int chain);
void    GetParsimonySubtreeRootstate (Tree *t, TreeNode *root, int chain);
MrBFlt  GetRate (int division, int chain);
void    GetStamp (void);
void    GetSwappers (int *swapA, int *swapB, int curGen);
void    GetTempDownPassSeq (TreeNode *p, int *i, TreeNode **dp);
MrBFlt	GibbsSampleGamma (int chain, int division, SafeLong *seed);
int     InitChainCondLikes (void);
int     InitClockBrlens (Tree *t);
int     InitEigenSystemInfo (ModelInfo *m);
int     InitInvCondLikes (void);
int     InitParsSets (void);
int     InitPrintParams (void);
int		IsPFNodeEmpty (PFNODE *p);
void    JukesCantor (MrBFlt *tiP, MrBFlt length);
PFNODE *LargestNonemptyPFNode (PFNODE *p, int *i, int j);
int     Likelihood_Adgamma (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats);
int	    Likelihood_Gen (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats);
int	    Likelihood_NUC4 (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats);
int	    Likelihood_NUC4_GibbsGamma (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats);
int     Likelihood_NY98 (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats);
int     Likelihood_Pars (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats);
int     Likelihood_ParsCodon (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats);
int     Likelihood_ParsStd (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats);
int     Likelihood_Res (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats);
int     Likelihood_Std (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats);
int     LogClockTreePriorRatio (Param *param, int chain, MrBFlt *lnPriorRatio);
MrBFlt  LogLike (int chain);
MrBFlt  LogOmegaPrior (MrBFlt w1, MrBFlt w2, MrBFlt w3);
MrBFlt  LogPrior (int chain);
int     LnBirthDeathPriorPrRandom(Tree *t, MrBFlt clockRate, MrBFlt *prob, MrBFlt sR, MrBFlt eR, MrBFlt sF);
int     LnBirthDeathPriorPrDiversity(Tree *t, MrBFlt clockRate, MrBFlt *prob, MrBFlt sR, MrBFlt eR, MrBFlt sF);
int     LnBirthDeathPriorPrCluster(Tree *t, MrBFlt clockRate, MrBFlt *prob, MrBFlt sR, MrBFlt eR, MrBFlt sF);
MrBFlt  LnP0 (MrBFlt t, MrBFlt l, MrBFlt m);
MrBFlt  LnP0Subsample (MrBFlt t, MrBFlt l, MrBFlt m, MrBFlt f);
MrBFlt  LnP1 (MrBFlt t, MrBFlt l, MrBFlt m);
MrBFlt  LnP1Subsample (MrBFlt t, MrBFlt l, MrBFlt m, MrBFlt f);
void    MarkClsBelow (TreeNode *p);
MrBFlt  MaximumValue (MrBFlt x, MrBFlt y);
MrBFlt  MinimumValue (MrBFlt x, MrBFlt y);
int     NewtonRaphsonBrlen (Tree *t, TreeNode *p, int chain);
void    NodeToNodeDistances (Tree *t, TreeNode *fromNode);
int     PickProposal (SafeLong *seed, int chainIndex);
int     NumCppEvents (Param *p, int chain);
int     PosSelProbs (TreeNode *p, int division, int chain);
int		PreparePrintFiles (void);
int     PrintAncStates_Bin (TreeNode *p, int division, int chain);
int     PrintAncStates_Gen (TreeNode *p, int division, int chain);
int     PrintAncStates_NUC4 (TreeNode *p, int division, int chain);
int     PrintAncStates_Std (TreeNode *p, int division, int chain);
int     PrintCalTree (int curGen, Tree *tree);
int		PrintCheckPoint (int gen);
int     PrintMCMCDiagnosticsToFile (int curGen);
#		if defined (MPI_ENABLED)
int     PrintMPISlaves (FILE *fp);
#		endif
void    PrintParamValues (Param *p, int chain, char *s);
int	    PrintParsMatrix (void);
int		PrintSiteRates_Gen (TreeNode *p, int division, int chain);
int		PrintSiteRates_Std (TreeNode *p, int division, int chain);
int     PrintStates (int curGen, int coldId);
int     PrintStatesToFiles (int n);
int     PrintSwapInfo (void);
int     PrintTermState (void);
void	PrintTiProbs (CLFlt *tP, MrBFlt *bs, int nStates);
int     PrintTopConvInfo (void);
void    PrintToScreen (int curGen, int startGen, time_t endingT, time_t startingT);
int     PrintTree (int curGen, Param *treeParam, int chain, int showBrlens, MrBFlt clockRate);
#       if defined (MPI_ENABLED)
int     ReassembleMoveInfo (void);
int     ReassembleParamVals (int *curId);
int     ReassembleSwapInfo (void);
int     ReassembleTuningParams (void);
void    RedistributeMoveInfo (void);
int     RedistributeParamVals (void);
int     RedistributeTuningParams (void);
#       endif
int     RemoveNodeScalers(TreeNode *p, int division, int chain);
#if defined (SSE_ENABLED)
int     RemoveNodeScalers_SSE(TreeNode *p, int division, int chain);
#endif
int     RemovePartition (PFNODE *r, SafeLong *p, int runId);
int     RemoveTreeFromPartitionCounters (Tree *tree, int treeId, int runId);
int     RemoveTreeSamples (int from, int to);
int     ReopenMBPrintFiles (void);
void    ResetChainIds (void);
void    ResetFlips(int chain);
int     ResetScalers (void);
void    ResetSiteScalers (ModelInfo *m, int chain);
int     ReusePreviousResults(int *numSamples, int);
int     RunChain (SafeLong *seed);
int     SafeSprintf(char **target, int *targetLen, char *fmt, ...);
int     SetAARates (void);
void    SetChainIds (void);
void    SetFileNames (void);
int		SetLikeFunctions (void);
int		SetModelInfo (void);
int		SetMoves (void);
int     SetNucQMatrix (MrBFlt **a, int n, int whichChain, int division, MrBFlt rateMult, MrBFlt *rA, MrBFlt *rS);
int     SetProteinQMatrix (MrBFlt **a, int n, int whichChain, int division, MrBFlt rateMult);
int	    SetStdQMatrix (MrBFlt **a, int nStates, MrBFlt *bs, int cType);
int     SetUpPartitionCounters (void);
int	    SetUpTermState (void);
int     SetUsedMoves (void);
int     SiteOmegas (TreeNode *p, int division, int chain);
int     ShowMoveSummary (void);
void    ShowValuesForChain (int chn);
PFNODE *SmallestNonemptyPFNode (PFNODE *p, int *i, int j);
PFNODE *Talloc (void);
void	Tfree (PFNODE *r);
MrBFlt  Temperature (int x);
int     TiProbs_Fels (TreeNode *p, int division, int chain);
int     TiProbs_Gen (TreeNode *p, int division, int chain);
int     TiProbs_GenCov (TreeNode *p, int division, int chain);
int     TiProbs_Hky (TreeNode *p, int division, int chain);
int     TiProbs_JukesCantor (TreeNode *p, int division, int chain);
int     TiProbs_Std (TreeNode *p, int division, int chain);
int     TiProbs_Res (TreeNode *p, int division, int chain);
void	TouchAllCijks (int chain);
void    TouchAllPartitions (void);
void    TouchAllTreeNodes (ModelInfo *m, int chain);
void    TouchAllTrees (int chain);
MrBFlt  TreeLength (Param *param, int chain);
#if defined (BEAGLE_ENABLED)
int     TreeCondLikes_Beagle (Tree *t, int division, int chain);
int     TreeLikelihood_Beagle (Tree *t, int division, int chain, MrBFlt *lnL, int whichSitePats);
int     TreeTiProbs_Beagle (Tree *t, int division, int chain);
int		SetBinaryQMatrix (MrBFlt **a, int whichChain, int division);
#endif
int     UpDateCijk (int whichPart, int whichChain);

/* globals */
int				*bsIndex;				     /* compressed std stat freq index               */
Chain			chainParams;                 /* parameters of Markov chain                   */
int				*compCharPos;		         /* char position in compressed matrix           */
int				*compColPos;		         /* column position in compressed matrix		 */
SafeLong		*compMatrix;		         /* compressed character matrix					 */
int				compMatrixRowSize;	         /* row size of compressed matrix				 */
char			inputFileName[100];          /* input (NEXUS) file name                      */
MoveType		moveTypes[NUM_MOVE_TYPES];   /* holds information on the move types          */
int				numCompressedChars;          /* number of compressed characters				 */
int				numMoveTypes;		         /* the number of move types                     */
CLFlt			*numSitesOfPat;		         /* no. sites of each pattern					 */
int				*origChar;			         /* index from compressed char to original char  */
char			stamp[11];                   /* holds a unique identifier for each analysis  */
MrBFlt			*stdStateFreqs;				 /* std char state frequencies					 */
int				*stdType;				     /* compressed std char type: ord, unord, irrev  */
int				*tiIndex;				     /* compressed std char ti index                 */

#if defined (BEAGLE_ENABLED)
int				recalcScalers;			 /* shoud we recalculate scalers for current state YES/NO */
#endif

/* local (to this file) variables */
int				numLocalChains;              /* number of Markov chains                      */
int				*chainId = NULL;             /* information on the id (0 ...) of the chain   */
MrBFlt			*curLnL = NULL;              /* stores log likelihood                        */
MrBFlt			*curLnPr = NULL;             /* stores log prior probability                 */
int             stepRelativeBurninSS;        /* Should we use relative burn in within each step or not.*/
MrBFlt          powerSS;                     /* power (betta) in power posterior destribution used in SS*/ 
MrBFlt			*marginalLnLSS = NULL;       /* marginal liklihood obtained using stepppingstone sampling */
MrBFlt			*stepAcumulatorSS = NULL;    /* accumulates liklihoods for current step in SS*/
MrBFlt			*stepScalerSS = NULL;        /* scaler of stepAcumulatorSS in log scale in SS*/
MrBFlt			*splitfreqSS = NULL;         /* array holding split frequencis for each step in SS        */
int				*sympiIndex;                 /* sympi state freq index for multistate chars  */
int				stdStateFreqsRowSize;		 /* row size for std state frequencies			 */
int				*weight;			         /* weight of each compressed char				 */
int				*chainTempId;                /* info ton temp, change to float holding temp?  */
int				state[MAX_CHAINS];           /* state of chain								 */
int				augmentData;		         /* are data being augmented for any division?	 */
int				*nAccepted;			         /* counter of accepted moves					 */
int				*termState = NULL;			 /* stores character states of tips              */
int				*isPartAmbig = NULL;         /* records whether tips are partially ambiguous */
SafeLong		**parsPtrSpace = NULL;	     /* space holding pointers to parsimony sets     */
SafeLong		***parsPtr = NULL;		     /* pointers to pars state sets for chain & node */
CLFlt			*parsNodeLengthSpace = NULL; /* space for parsimony node lengths			 */
CLFlt			**parsNodeLen = NULL;        /* pointers to pars node lengths for chains     */
char			*printString;                /* string for printing to a file                */
size_t			printStringSize;             /* length of printString                        */
CLFlt			*preLikeL;			         /* precalculated cond likes for left descendant */
CLFlt			*preLikeR;			         /* precalculated cond likes for right descendant*/
CLFlt			*preLikeA;			         /* precalculated cond likes for ancestor        */
MCMCMove		**usedMoves;				 /* vector of pointers to used moves		     */
int				numUsedMoves;			     /* the number of moves used by chain			 */
Param			**printParam;                /* vector of pointers to normal params to print */
int				numPrintParams;			     /* the number of normal params to print         */
Param           **printTreeParam;            /* vector of pointers to tree params to print   */
Param			**topologyParam;             /* vector of pointers to topology params        */
int				numPrintTreeParams;			 /* the number of tree params to print           */
int				codon[6][64];                /* holds info on amino acids coded in code      */
int				chainHasAdgamma;			 /* indicates if chain has adgamma HMMs			 */
int				inferPosSel;			 	 /* indicates if positive selection is inferred  */
MrBFlt			*posSelProbs;                /* probs. for positive selection                */
int				hasMarkovTi[MAX_SMALL_JUMP]; /* vector marking size of observed HMM jumps    */
int				*siteJump;					 /* vector of sitejumps for adgamma model        */
int				rateProbRowSize;			 /* size of rate probs for one chain one state   */
MrBFlt			*rateProbSpace;				 /* space for rate probs used by adgamma model   */
MrBFlt			**rateProbs;				 /* pointers to rate probs used by adgamma model */
MrBFlt			**markovTi[MAX_SMALL_JUMP];  /* trans prob matrices used in calc of adgamma  */
MrBFlt			**markovTiN;				 /* trans prob matrices used in calc of adgamma  */
int				whichReweightNum;            /* used for setting reweighting of char pats    */
int				***swapInfo;                 /* keeps track of attempts & successes of swaps */
int				tempIndex;                   /* keeps track of which user temp is specified  */
int				abortMove;					 /* flag determining whether to abort move       */
PFNODE			**partFreqTreeRoot;			 /* root of tree(s) holding partition freqs      */
int				nLongsNeeded;				 /* number of longs needed for partitions        */
SafeLong		**partition;                 /* matrix holding partitions                    */
MrBFlt          *maxLnL0 = NULL;             /* maximum likelihood                           */
FILE			*fpMcmc = NULL;              /* pointer to .mcmc file                        */
FILE			**fpParm = NULL;             /* pointer to .p file(s)                        */
FILE			***fpTree = NULL;            /* pointer to .t file(s)                        */
FILE			*fpSS = NULL;                /* pointer to .ss file                          */
static int		requestAbortRun;             /* flag for aborting mcmc analysis              */
int				*topologyPrintIndex;	     /* print file index of each topology            */
int				*printTreeTopologyIndex;	 /* topology index of each tree print file       */
int             numPreviousGen;              /* number of generations in run to append to    */
int             gTopologyHasChanged;         /* flag whether topology has changed            */

#if defined (MPI_ENABLED)
int				lowestLocalRunId;			 /* lowest local run Id                          */
int				highestLocalRunId;			 /* highest local run Id                         */
#endif

/* AddPartition: Add a partition to the tree keeping track of partition frequencies */
PFNODE *AddPartition (PFNODE *r, SafeLong *p, int runId)
{
	int		i, comp;
	
	if (r == NULL)
		{
		/* new partition */
		r = Talloc ();					/* create a new node */
		if (r == NULL)
			return NULL;
		for (i=0; i<nLongsNeeded; i++)
			r->partition[i] = p[i];
		for (i=0; i<chainParams.numRuns; i++)
			r->count[i] = 0;
		r->count[runId] = 1;
		r->left = r->right = NULL;
		}
	else
		{
		for (i=0; i<nLongsNeeded; i++)
			{
			if (r->partition[i] != p[i])
				break;
			}
		
		if (i == nLongsNeeded)
			comp = 0;
		else if (r->partition[i] < p[i])
			comp = -1;
		else
			comp = 1;
		
		if (comp == 0)			/* repeated partition */
			r->count[runId]++;
		else if (comp < 0)		/* greater than -> into left subtree */
			{
			if ((r->left = AddPartition (r->left, p, runId)) == NULL)
				{
				Tfree (r);
				return NULL;
				}
			}
		else
			{
			/* smaller than -> into right subtree */
			if ((r->right = AddPartition (r->right, p, runId)) == NULL)
				{
				Tfree (r);
				return NULL;
				}
			}
		}

	return r;
}





int AddToPrintString (char *tempStr)

{

	size_t			len1, len2;
	
	len1 = (int) strlen(printString);
	len2 = (int) strlen(tempStr);
	if (len1 + len2 + 5 > printStringSize)
		{
		printStringSize += len1 + len2 - printStringSize + 200;
		printString = (char*)SafeRealloc((void*)printString, printStringSize * sizeof(char));
		if (!printString)
			{
			MrBayesPrint ("%s   Problem reallocating printString (%d)\n", spacer, printStringSize * sizeof(char));
			goto errorExit;
			}
		}
	strcat(printString, tempStr);	
#	if 0
	printf ("printString(%d) -> \"%s\"\n", printStringSize, printString);
#	endif	
	return (NO_ERROR);
	
	errorExit:
		return (ERROR);

}





/* AddTreeSamples: Add tree samples from .t files to partition counters. if saveToList == YES then also save trees in tree list */
int AddTreeSamples (int from, int to, int saveToList)
{
	int	i, j, k, longestLine;
	SafeLong	lastBlock;
	char	*word, *s, *lineBuf;
	FILE	*fp;
	Tree	*t;
	char	*tempStr;
	int     tempStrSize = TEMPSTRSIZE;

    if( from > to)
        return (NO_ERROR);

#	if defined (MPI_ENABLED)
	if (proc_id != 0)
		return (NO_ERROR);
#	endif

	tempStr = (char *) SafeMalloc((size_t) (tempStrSize * sizeof(char)));
	if (!tempStr)
		{
		MrBayesPrint ("%s   Problem allocating tempString (%d)\n", spacer, tempStrSize * sizeof(char));
		return (ERROR);
		}

	for (i=0; i<numTopologies; i++)
		{
		t = chainParams.dtree;

		for (j=0; j<chainParams.numRuns; j++)
			{
            if (numPrintTreeParams == 1)
                {
                if( chainParams.numRuns == 1 )
                    SafeSprintf(&tempStr, &tempStrSize, "%s.t", chainParams.chainFileName);
                else
                    SafeSprintf(&tempStr, &tempStrSize, "%s.run%d.t", chainParams.chainFileName, j+1);
                }
			else
                {
                if( chainParams.numRuns == 1 )
				    SafeSprintf(&tempStr, &tempStrSize, "%s.tree%d.t", chainParams.chainFileName, i+1);
                else
                    SafeSprintf(&tempStr, &tempStrSize, "%s.tree%d.run%d.t", chainParams.chainFileName, i+1, j+1);
                }


			if ((fp = OpenBinaryFileR (tempStr)) == NULL) 
                {
                MrBayesPrint ("%s   Problem openning file %s.\n", spacer, tempStr);
			    free (tempStr);
				return (ERROR);
				}

			longestLine = LongestLine (fp);
			SafeFclose (&fp);

			if ((fp = OpenTextFileR (tempStr)) == NULL) 
			    {
				free (tempStr);
				return (ERROR);
			    }

			lineBuf = (char *) SafeCalloc (longestLine + 10, sizeof (char));
			if (!lineBuf)
				{
				SafeFclose (&fp);
                free (tempStr);
                return (ERROR);
				}

			lastBlock = LastBlock (fp, lineBuf, longestLine);
			fseek (fp, lastBlock, SEEK_SET);

			for (k=1; k<=to; k++)
				{
				do {
					if (fgets (lineBuf, longestLine, fp) == NULL) 
					        {
                            SafeFclose (&fp);
			                free (lineBuf);
					        free (tempStr);
						return ERROR;
                                                }
					word = strtok (lineBuf, " ");
					} while (strcmp (word, "tree") != 0);
				if (k>=from)
					{
					s = strtok (NULL, ";");
					while (*s != '(')
						s++;
					StripComments(s);
                    if (ResetTopology (t, s) == ERROR)
						{
						SafeFclose (&fp);
						free (lineBuf);
                        free (tempStr);
						return ERROR;
						}
					if (AddTreeToPartitionCounters (t, i, j) == ERROR)
						{
						SafeFclose (&fp);
						free (lineBuf);
                        free (tempStr);
						return ERROR;
						}
                    if (saveToList == YES)
                        if (AddToTreeList(&chainParams.treeList[numTopologies*j+i],t) == ERROR)
                            return (ERROR);
					}
				}
			SafeFclose (&fp);
			free (lineBuf);
			} /* next run */
		} /* next tree */
	free (tempStr);
	return (NO_ERROR);
}





/* AddTreeToPartitionCounters: Break a tree into partitions and add those to counters */
int AddTreeToPartitionCounters (Tree *tree, int treeId, int runId)
{
	int			i, j, nTaxa;
	TreeNode	*p;

    if (tree->isRooted == YES)
        nTaxa = tree->nNodes - tree->nIntNodes - 1;
    else
        nTaxa = tree->nNodes - tree->nIntNodes;

    for (i=0; i<nTaxa; i++)
        {
        ClearBits(partition[i], nLongsNeeded);
        SetBit(i, partition[i]);
        }

    for (i=0; i<tree->nIntNodes-1; i++)
		{
		p = tree->intDownPass[i];
        assert (p->index >= tree->nNodes - tree->nIntNodes - (tree->isRooted == YES ? 1 : 0));
		for (j=0; j<nLongsNeeded; j++)
			{
			partition[p->index][j] = partition[p->left->index][j] | partition[p->right->index][j];
			}

		if ((partFreqTreeRoot[treeId] = AddPartition (partFreqTreeRoot[treeId], partition[p->index], runId)) == NULL)
			{
			MrBayesPrint ("%s   Could not allocate space for new partition in AddTreeToPartitionCounters\n", spacer);
			return ERROR;
			}
		}

	return NO_ERROR;
}





int AttemptSwap (int swapA, int swapB, SafeLong *seed)
{

	int			    d, tempX, reweightingChars, isSwapSuccessful, chI, chJ, runId;
	MrBFlt			tempA, tempB, lnLikeA, lnLikeB, lnPriorA, lnPriorB, lnR, r,
					lnLikeStateAonDataB=0.0, lnLikeStateBonDataA=0.0, lnL;
	ModelInfo		*m;
	Tree			*tree;
#					if defined (MPI_ENABLED)
	int				numChainsForProc, tempIdA=0, tempIdB=0, proc, procIdForA=0, procIdForB=0, tempIdMy=0, procIdPartner=0,
					whichElementA=0, whichElementB=0, lower, upper, areWeA, doISwap, ierror,
					myId, partnerId, i, run;
	MrBFlt			swapRan;
	MPI_Status 		status[2];
	MPI_Request		request[2];
#					endif
	

#	if defined (MPI_ENABLED)

    /* get the number of chains handled by this proc */
	/* the number will be corrected further down for unbalanced scenarios */
	numChainsForProc = (int) (chainParams.numChains * chainParams.numRuns / num_procs);

#	endif

	/* are we using character reweighting? */
	reweightingChars = NO;
	if ((chainParams.weightScheme[0] + chainParams.weightScheme[1]) > 0.00001)
		reweightingChars = YES;
			
#	if defined (MPI_ENABLED)

	/* figure out processors involved in swap */
	lower = upper = 0;
	for (proc=0; proc<num_procs; proc++)
		{
		/* assign or increment chain id */
		if (proc < (chainParams.numChains * chainParams.numRuns) % num_procs)
			upper += numChainsForProc+1;
		else
			upper += numChainsForProc;

		/* if swapA lies between lower and upper
			* chain id's we know that this is the proc
			* swapA is in */
		if (swapA >= lower && swapA < upper)
			{
			procIdForA = proc;
			whichElementA = swapA - lower;
			}
		if (swapB >= lower && swapB < upper)
			{
			procIdForB = proc;
			whichElementB = swapB - lower;
			}
		lower = upper;
		}

	/* NOTE: at this point, procIdForA and procIdForB *
		* store the proc id's of swapping procs. Also,   *
		* whichElementA and whichElementB store the      *
		* chainId[] index of swapping procs              */

	/* figure out if I am involved in the swap */
	doISwap = areWeA = NO;
	if (proc_id == procIdForA)
		{
		doISwap = YES;
		areWeA = YES;
		}
	else if (proc_id == procIdForB)
		{
		doISwap = YES;
		}

	/* chain's that do not swap, continue to the next iteration */	
	if (doISwap == YES)
		{
		
		/* no need to communicate accross processors if swapping chains are in the same proc */
		if (procIdForA == procIdForB)
			{
			if (reweightingChars == YES)
				{
				/* use character reweighting */
				lnLikeStateAonDataB = 0.0;
				for (d=0; d<numCurrentDivisions; d++)
					{
					m = &modelSettings[d];
					tree = GetTree(m->brlens, whichElementA, state[whichElementA]);
					lnL = 0.0;
					m->Likelihood (tree->root->left, d, whichElementA, &lnL, chainId[whichElementB] % chainParams.numChains);
					lnLikeStateAonDataB += lnL;
					}
				lnLikeStateBonDataA = 0.0;
				for (d=0; d<numCurrentDivisions; d++)
					{
					m = &modelSettings[d];
					tree = GetTree(m->brlens, whichElementB, state[whichElementB]);
					lnL = 0.0;
					m->Likelihood (tree->root->left, d, whichElementB, &lnL, chainId[whichElementA] % chainParams.numChains);
					lnLikeStateBonDataA += lnL;
					}
				}

			/*curLnPr[whichElementA] = LogPrior(whichElementA);
			curLnPr[whichElementB] = LogPrior(whichElementB);*/

			/* then do the serial thing - simply swap chain id's */
			tempA = Temperature (chainId[whichElementA]);
			tempB = Temperature (chainId[whichElementB]);
			lnLikeA = curLnL[whichElementA];
			lnLikeB = curLnL[whichElementB];
            if( chainParams.isSS == YES )
                {
                lnLikeA *= powerSS;
                lnLikeB *= powerSS;
                }
			lnPriorA = curLnPr[whichElementA];
			lnPriorB = curLnPr[whichElementB];
			if (reweightingChars == YES)
                {
                if( chainParams.isSS == YES )
                    lnR = (tempB * (lnLikeStateAonDataB*powerSS + lnPriorA) + tempA * (lnLikeStateBonDataA*powerSS + lnPriorB)) - (tempA * (lnLikeA + lnPriorA) + tempB * (lnLikeB + lnPriorB));
                else
				    lnR = (tempB * (lnLikeStateAonDataB + lnPriorA) + tempA * (lnLikeStateBonDataA + lnPriorB)) - (tempA * (lnLikeA + lnPriorA) + tempB * (lnLikeB + lnPriorB));
                }
			else
				lnR = (tempB * (lnLikeA + lnPriorA) + tempA * (lnLikeB + lnPriorB)) - (tempA * (lnLikeA + lnPriorA) + tempB * (lnLikeB + lnPriorB));
			if (lnR <  -100.0)
				r =  0.0;
			else if (lnR > 0.0)
				r =  1.0;
			else
				r =  exp(lnR);

			isSwapSuccessful = NO;
			if (RandomNumber(seed) < r)
				{
				/* swap chain id's (heats) */
				tempX = chainId[whichElementA];
				chainId[whichElementA] = chainId[whichElementB];
				chainId[whichElementB] = tempX;
				if (reweightingChars == YES)
					{
					curLnL[whichElementA] = lnLikeStateAonDataB;
					curLnL[whichElementB] = lnLikeStateBonDataA;
					}
				isSwapSuccessful = YES;
				}
				
			chI = chainId[whichElementA];
			chJ = chainId[whichElementB];
			if (chainId[whichElementB] < chainId[whichElementA])
				{
				chI = chainId[whichElementB];
				chJ = chainId[whichElementA];
				}
			runId = chI / chainParams.numChains;
			chI = chI % chainParams.numChains;
			chJ = chJ % chainParams.numChains;
			swapInfo[runId][chJ][chI]++;
			if (isSwapSuccessful == YES)
				swapInfo[runId][chI][chJ]++;
			}
		/* we need to communicate across processors */
		else
			{
			if (reweightingChars == YES)
				{
				/* If we are reweighting characters, then we need to do an additional communication to
					figure out the chainId's of the partner. We need to have this information so we can
					properly calculate likelihoods with switched observations. */
				if (areWeA == YES)
					{
					lnLikeStateAonDataB = 0.0;
					myId = chainId[whichElementA];
					ierror = MPI_Isend (&myId, 1, MPI_INT, procIdForB, 0, MPI_COMM_WORLD, &request[0]);
					if (ierror != MPI_SUCCESS)
						{
						return (ERROR);
						}
					ierror = MPI_Irecv (&partnerId, 1, MPI_INT, procIdForB, 0, MPI_COMM_WORLD, &request[1]);
					if (ierror != MPI_SUCCESS)
						{
						return (ERROR);
						}
					ierror = MPI_Waitall (2, request, status);
					if (ierror != MPI_SUCCESS)
						{
						return (ERROR);
						}
					for (d=0; d<numCurrentDivisions; d++)
						{
						m = &modelSettings[d];
						tree = GetTree(m->brlens, whichElementA, state[whichElementA]);
						lnL = 0.0;
						m->Likelihood (tree->root->left, d, whichElementA, &lnL, partnerId);
						lnLikeStateAonDataB = lnL;
						}
					}
				else
					{
					lnLikeStateBonDataA = 0.0;
					myId = chainId[whichElementB];
					ierror = MPI_Isend (&myId, 1, MPI_INT, procIdForA, 0, MPI_COMM_WORLD, &request[0]);
					if (ierror != MPI_SUCCESS)
						{
						return (ERROR);
						}
					ierror = MPI_Irecv (&partnerId, 1, MPI_INT, procIdForA, 0, MPI_COMM_WORLD, &request[1]);
					if (ierror != MPI_SUCCESS)
						{
						return (ERROR);
						}
					ierror = MPI_Waitall (2, request, status);
					if (ierror != MPI_SUCCESS)
						{
						return (ERROR);
						}
					for (d=0; d<numCurrentDivisions; d++)
						{
						m = &modelSettings[d];
						tree = GetTree(m->brlens, whichElementB, state[whichElementB]);
						lnL = 0.0;
						m->Likelihood (tree->root->left, d, whichElementB, &lnL, partnerId);
						lnLikeStateBonDataA = lnL;
						}
					}
				}


			if (areWeA == YES)
				{
				/*curLnPr[whichElementA] = LogPrior(whichElementA);*/

				/* we are processor A */
				tempIdA = chainId[whichElementA];
				lnLikeA = curLnL[whichElementA];
				lnPriorA = curLnPr[whichElementA];
				swapRan = RandomNumber(seed);

				myStateInfo[0] = lnLikeA;
				myStateInfo[1] = lnPriorA;
				myStateInfo[2] = tempIdA;
				myStateInfo[3] = swapRan;
                myStateInfo[4] = 0.0;
				if (reweightingChars == YES)
					{
					myStateInfo[2] = lnLikeStateAonDataB;
					tempIdB = partnerId;
					}
					
				ierror = MPI_Isend (&myStateInfo, 5, MPI_DOUBLE, procIdForB, 0, MPI_COMM_WORLD, &request[0]);
				if (ierror != MPI_SUCCESS)
					{
					return (ERROR);
					}
				ierror = MPI_Irecv (&partnerStateInfo, 5, MPI_DOUBLE, procIdForB, 0, MPI_COMM_WORLD, &request[1]);
				if (ierror != MPI_SUCCESS)
					{
					return (ERROR);
					}
				ierror = MPI_Waitall (2, request, status);
				if (ierror != MPI_SUCCESS)
					{
					return (ERROR);
					}

				lnLikeA = curLnL[whichElementA];
				lnLikeB = partnerStateInfo[0];
                if( chainParams.isSS == YES )
                    {
                    lnLikeA *= powerSS;
                    lnLikeB *= powerSS;
                    }
				lnPriorA = curLnPr[whichElementA];
				lnPriorB = partnerStateInfo[1];
				if (reweightingChars == YES)
					lnLikeStateBonDataA = partnerStateInfo[2];
				else
					tempIdB = partnerStateInfo[2];
				
				tempA = Temperature (tempIdA);
				tempB = Temperature (tempIdB);

                if (reweightingChars == YES)
                    {
                    if( chainParams.isSS == YES )
					    lnR = (tempB * (lnLikeStateAonDataB*powerSS + lnPriorA) + tempA * (lnLikeStateBonDataA*powerSS + lnPriorB)) - (tempA * (lnLikeA + lnPriorA) + tempB * (lnLikeB + lnPriorB));
                    else
                        lnR = (tempB * (lnLikeStateAonDataB + lnPriorA) + tempA * (lnLikeStateBonDataA + lnPriorB)) - (tempA * (lnLikeA + lnPriorA) + tempB * (lnLikeB + lnPriorB));
                    }
				else
					lnR = (tempB * (lnLikeA + lnPriorA) + tempA * (lnLikeB + lnPriorB)) - (tempA * (lnLikeA + lnPriorA) + tempB * (lnLikeB + lnPriorB));
				if (lnR < -100.0)
					r = 0.0;
				else if (lnR > 0.0)
					r = 1.0;
				else
					r = exp(lnR);

				/* process A's random number is used to make the swap decision */
				isSwapSuccessful = NO;
				if (swapRan < r)
					{
					/* swap chain id's (heats) */
					isSwapSuccessful = YES;
					tempIdMy = chainId[whichElementA];
					procIdPartner = procIdForB;

					if (reweightingChars == YES)
						chainId[whichElementA] = tempIdB;
					else
						chainId[whichElementA] = (int)(partnerStateInfo[2]);
					if (reweightingChars == YES)
						{
						curLnL[whichElementA] = lnLikeStateAonDataB;
						}
					}
					
				/* only processor A keeps track of the swap success/failure */
				chI = tempIdA;
				chJ = tempIdB;
				if (tempIdB < tempIdA)
					{
					chI = tempIdB;
					chJ = tempIdA;
					}
				runId = chI / chainParams.numChains;
				chI = chI % chainParams.numChains;
				chJ = chJ % chainParams.numChains;
				swapInfo[runId][chJ][chI]++;
				if (isSwapSuccessful == YES)
                    {
					swapInfo[runId][chI][chJ]++;
                    /* exchange the move info */
		            for (i=0; i<numUsedMoves; i++)
                        {
					    myStateInfo[0] = usedMoves[i]->nAccepted[tempIdA];
        				myStateInfo[1] = usedMoves[i]->nTried[tempIdA];
		        		myStateInfo[2] = usedMoves[i]->nBatches[tempIdA];
					    myStateInfo[3] = usedMoves[i]->nTotAccepted[tempIdA];
        				myStateInfo[4] = usedMoves[i]->nTotTried[tempIdA];
				        myStateInfo[5] = usedMoves[i]->lastAcceptanceRate[tempIdA];
                        if (usedMoves[i]->moveType->numTuningParams > 0)
							myStateInfo[6] = usedMoves[i]->tuningParam[tempIdA][0];
						else
							myStateInfo[6] = 0.0;

                        ierror = MPI_Isend (&myStateInfo, 7, MPI_DOUBLE, procIdForB, 0, MPI_COMM_WORLD, &request[0]);
				        if (ierror != MPI_SUCCESS)
					        {
					        return (ERROR);
					        }
				        ierror = MPI_Irecv (&partnerStateInfo, 7, MPI_DOUBLE, procIdForB, 0, MPI_COMM_WORLD, &request[1]);
				        if (ierror != MPI_SUCCESS)
					        {
					        return (ERROR);
					        }
				        ierror = MPI_Waitall (2, request, status);
				        if (ierror != MPI_SUCCESS)
					        {
					        return (ERROR);
					        }

				        usedMoves[i]->nAccepted[tempIdB]          = (int)partnerStateInfo[0];
				        usedMoves[i]->nTried[tempIdB]             = (int)partnerStateInfo[1];
				        usedMoves[i]->nBatches[tempIdB]           = (int)partnerStateInfo[2];
				        usedMoves[i]->nTotAccepted[tempIdB]       = (int)partnerStateInfo[3];
				        usedMoves[i]->nTotTried[tempIdB]          = (int)partnerStateInfo[4];
				        usedMoves[i]->lastAcceptanceRate[tempIdB] = partnerStateInfo[5];
						if (usedMoves[i]->moveType->numTuningParams > 0)
				        	usedMoves[i]->tuningParam[tempIdB][0]     = partnerStateInfo[6];

                        usedMoves[i]->nAccepted[tempIdA]          = 0;
				        usedMoves[i]->nTried[tempIdA]             = 0;
				        usedMoves[i]->nBatches[tempIdA]           = 0;
				        usedMoves[i]->lastAcceptanceRate[tempIdA] = 0.0;
                        usedMoves[i]->nTotAccepted[tempIdA]       = 0;
                        usedMoves[i]->nTotTried[tempIdA]          = 0;
					    if (usedMoves[i]->moveType->numTuningParams > 0)
                            usedMoves[i]->tuningParam[tempIdA][0]     = 0.0;
				
			            }
		            }
		        }
			else
				{
				/*curLnPr[whichElementB] = LogPrior(whichElementB);*/

				/* we are processor B */
				tempIdB  = chainId[whichElementB];
				lnLikeB  = curLnL[whichElementB];
				lnPriorB = curLnPr[whichElementB];
				swapRan  = -1.0;

				myStateInfo[0] = lnLikeB;
				myStateInfo[1] = lnPriorB;
				myStateInfo[2] = tempIdB;
				myStateInfo[3] = swapRan;
                myStateInfo[4] = 0.0;
				if (reweightingChars == YES)
					{
					myStateInfo[2] = lnLikeStateBonDataA;
					tempIdA = partnerId;
					}

				ierror = MPI_Isend (&myStateInfo, 5, MPI_DOUBLE, procIdForA, 0, MPI_COMM_WORLD, &request[0]);
				if (ierror != MPI_SUCCESS)
					{
					return (ERROR);
					}
				ierror = MPI_Irecv (&partnerStateInfo, 5, MPI_DOUBLE, procIdForA, 0, MPI_COMM_WORLD, &request[1]);
				if (ierror != MPI_SUCCESS)
					{
					return (ERROR);
					}
				ierror = MPI_Waitall (2, request, status);
				if (ierror != MPI_SUCCESS)
					{
					return (ERROR);
					}

				lnLikeB = curLnL[whichElementB];
				lnLikeA = partnerStateInfo[0];
				lnPriorB = curLnPr[whichElementB];
				lnPriorA = partnerStateInfo[1];
				if (reweightingChars == YES)
					lnLikeStateAonDataB = partnerStateInfo[2];
				else
					tempIdA = partnerStateInfo[2];

				tempB = Temperature (tempIdB);
				tempA = Temperature (tempIdA);

                if( chainParams.isSS == YES )
                    {
                    lnLikeA *= powerSS;
                    lnLikeB *= powerSS;
                    }

                if (reweightingChars == YES)
                    {
                    if( chainParams.isSS == YES )
                        lnR = (tempB * (lnLikeStateAonDataB*powerSS + lnPriorA) + tempA * (lnLikeStateBonDataA*powerSS + lnPriorB)) - (tempA * (lnLikeA + lnPriorA) + tempB * (lnLikeB + lnPriorB));
                    else
					    lnR = (tempB * (lnLikeStateAonDataB + lnPriorA) + tempA * (lnLikeStateBonDataA + lnPriorB)) - (tempA * (lnLikeA + lnPriorA) + tempB * (lnLikeB + lnPriorB));
                    }
				else
					lnR = (tempB * (lnLikeA + lnPriorA) + tempA * (lnLikeB + lnPriorB)) - (tempA * (lnLikeA + lnPriorA) + tempB * (lnLikeB + lnPriorB));
				if (lnR < -100.0)
					r = 0.0;
				else if (lnR > 0.0)
					r = 1.0;
				else
					r = exp(lnR);

				/* we use process A's random number to make the swap decision */
				isSwapSuccessful = NO;
				if (partnerStateInfo[3] < r)
					{
					isSwapSuccessful = YES;
					tempIdMy = chainId[whichElementB];
					procIdPartner = procIdForA;

					if (reweightingChars == YES)
						chainId[whichElementB] = tempIdA;
					else
						chainId[whichElementB] = (int)(partnerStateInfo[2]);
					if (reweightingChars == YES)
						{
						curLnL[whichElementB] = lnLikeStateBonDataA;
						}
                    /* swap the move info */
        	        for (i=0; i<numUsedMoves; i++)
                        {
        				myStateInfo[0] = usedMoves[i]->nAccepted[tempIdB];
        				myStateInfo[1] = usedMoves[i]->nTried[tempIdB];
		        		myStateInfo[2] = usedMoves[i]->nBatches[tempIdB];
        				myStateInfo[3] = usedMoves[i]->nTotAccepted[tempIdB];
        				myStateInfo[4] = usedMoves[i]->nTotTried[tempIdB];
				        myStateInfo[5] = usedMoves[i]->lastAcceptanceRate[tempIdB];
                        if (usedMoves[i]->moveType->numTuningParams > 0)
							myStateInfo[6] = usedMoves[i]->tuningParam[tempIdB][0];
                        else
							myStateInfo[6] = 0.0; 

                        ierror = MPI_Isend (&myStateInfo, 7, MPI_DOUBLE, procIdForA, 0, MPI_COMM_WORLD, &request[0]);
				        if (ierror != MPI_SUCCESS)
					        {
					        return (ERROR);
					        }
				        ierror = MPI_Irecv (&partnerStateInfo, 7, MPI_DOUBLE, procIdForA, 0, MPI_COMM_WORLD, &request[1]);
				        if (ierror != MPI_SUCCESS)
					        {
					        return (ERROR);
					        }
				        ierror = MPI_Waitall (2, request, status);
				        if (ierror != MPI_SUCCESS)
					        {
					        return (ERROR);
					        }

				        usedMoves[i]->nAccepted[tempIdA]          = (int)partnerStateInfo[0];
				        usedMoves[i]->nTried[tempIdA]             = (int)partnerStateInfo[1];
				        usedMoves[i]->nBatches[tempIdA]           = (int)partnerStateInfo[2];
				        usedMoves[i]->nTotAccepted[tempIdA]       = (int)partnerStateInfo[3];
				        usedMoves[i]->nTotTried[tempIdA]          = (int)partnerStateInfo[4];
				        usedMoves[i]->lastAcceptanceRate[tempIdA] = partnerStateInfo[5];
                        if (usedMoves[i]->moveType->numTuningParams > 0)
				        	usedMoves[i]->tuningParam[tempIdA][0]     = partnerStateInfo[6];

                        usedMoves[i]->nAccepted[tempIdB]          = 0;
				        usedMoves[i]->nTried[tempIdB]             = 0;
				        usedMoves[i]->nBatches[tempIdB]           = 0;
                        usedMoves[i]->nTotAccepted[tempIdB]       = 0;
                        usedMoves[i]->nTotTried[tempIdB]          = 0;
				        usedMoves[i]->lastAcceptanceRate[tempIdB] = 0.0;
                        if (usedMoves[i]->moveType->numTuningParams > 0)
							usedMoves[i]->tuningParam[tempIdB][0]     = 0.0;
                        }
                    }
                }

			/*We exchange only if swap successful and (my id is cold or patner id is cold)*/
			if ( chainParams.isSS == YES && isSwapSuccessful == YES && (tempIdMy % chainParams.numChains == 0 || (areWeA == YES && chainId[whichElementA] % chainParams.numChains == 0) || (areWeA == NO && chainId[whichElementB] % chainParams.numChains == 0)  ))
				{
					run = tempIdMy/chainParams.numChains;

					myStateInfo[0] = tempIdMy;
				    myStateInfo[1] = marginalLnLSS	 [ run ];
        			myStateInfo[2] = stepAcumulatorSS[ run ];
		       		myStateInfo[3] = stepScalerSS	 [ run ];

                    ierror = MPI_Isend (&myStateInfo, 4, MPI_DOUBLE, procIdPartner, 0, MPI_COMM_WORLD, &request[0]);
			        if (ierror != MPI_SUCCESS)
				        {
					    return (ERROR);
				        }

			        ierror = MPI_Irecv (&partnerStateInfo, 4, MPI_DOUBLE, procIdPartner, 0, MPI_COMM_WORLD, &request[1]);
				    if (ierror != MPI_SUCCESS)
					    {
					    return (ERROR);
					    }
				    ierror = MPI_Waitall (2, request, status);
				    if (ierror != MPI_SUCCESS)
					    {
					    return (ERROR);
					    }

				    /*we swap chains from the same run*/
				    assert(run == (int)partnerStateInfo[0]/chainParams.numChains );

					/*If my chain is the cold chain then send current SS values of corresponding run*/
					if( tempIdMy % chainParams.numChains == 0)
						{
						assert( (int)partnerStateInfo[0] % chainParams.numChains != 0 );
						assert(partnerStateInfo[1] == 0.0);
						marginalLnLSS	[ run ] = (MrBFlt) 0.0;
						stepAcumulatorSS[ run ] = (MrBFlt) 0.0;
						stepScalerSS	[ run ] = (MrBFlt) 0.0;
						}
					else if( (int)partnerStateInfo[0] % chainParams.numChains == 0 )
						{
						marginalLnLSS	[ run ] = (MrBFlt) partnerStateInfo[1];
						stepAcumulatorSS[ run ] = (MrBFlt) partnerStateInfo[2];
						stepScalerSS	[ run ] = (MrBFlt) partnerStateInfo[3];
						}
				}


			}
		}
#	else
	if (reweightingChars == YES)
		{
		/* use character reweighting */
		lnLikeStateAonDataB = 0.0;
		for (d=0; d<numCurrentDivisions; d++)
			{
			m = &modelSettings[d];
			tree = GetTree(m->brlens, swapA, state[swapA]);
			lnL = 0.0;
			m->Likelihood (tree->root->left, d, swapA, &lnL, chainId[swapB] % chainParams.numChains);
			lnLikeStateAonDataB += lnL;
			}
		lnLikeStateBonDataA = 0.0;
		for (d=0; d<numCurrentDivisions; d++)
			{
			m = &modelSettings[d];
			tree = GetTree(m->brlens, swapB, state[swapB]);
			lnL = 0.0;
			m->Likelihood (tree->root->left, d, swapB, &lnL, chainId[swapA] % chainParams.numChains);
			lnLikeStateBonDataA += lnL;
			}
		}

	assert (fabs((curLnPr[swapA]-LogPrior(swapA))/curLnPr[swapA]) < 0.0001);
    assert (fabs((curLnPr[swapB]-LogPrior(swapB))/curLnPr[swapB]) < 0.0001);

    tempA = Temperature (chainId[swapA]);
	tempB = Temperature (chainId[swapB]);
	lnLikeA = curLnL[swapA];
	lnLikeB = curLnL[swapB];
	lnPriorA = curLnPr[swapA];
	lnPriorB = curLnPr[swapB];

    if( chainParams.isSS == YES )
        {
        lnLikeA *= powerSS;
        lnLikeB *= powerSS;
        }

    if (reweightingChars == YES)
        {
        if( chainParams.isSS == YES )
            lnR = (tempB * (lnLikeStateAonDataB*powerSS + lnPriorA) + tempA * (lnLikeStateBonDataA*powerSS + lnPriorB)) - (tempA * (lnLikeA + lnPriorA) + tempB * (lnLikeB + lnPriorB));
        else
		    lnR = (tempB * (lnLikeStateAonDataB + lnPriorA) + tempA * (lnLikeStateBonDataA + lnPriorB)) - (tempA * (lnLikeA + lnPriorA) + tempB * (lnLikeB + lnPriorB));
        }
	else
		lnR = (tempB * (lnLikeA + lnPriorA) + tempA * (lnLikeB + lnPriorB)) - (tempA * (lnLikeA + lnPriorA) + tempB * (lnLikeB + lnPriorB));
	if (lnR < -100.0)
		r = 0.0;
	else if (lnR > 0.0)
		r =  1.0;
	else
		r =  exp (lnR);

	isSwapSuccessful = NO;
	if (RandomNumber(seed) < r)
		{
		tempX = chainId[swapA];
		chainId[swapA] = chainId[swapB];
		chainId[swapB] = tempX;

		if (reweightingChars == YES)
			{
			curLnL[swapA] = lnLikeStateAonDataB;
			curLnL[swapB] = lnLikeStateBonDataA;
			}
		isSwapSuccessful = YES;
		}
		
	chI = chainId[swapA];
	chJ = chainId[swapB];
	if (chainId[swapB] < chainId[swapA])
		{
		chI = chainId[swapB];
		chJ = chainId[swapA];
		}
	runId = chI / chainParams.numChains;
	chI = chI % chainParams.numChains;
	chJ = chJ % chainParams.numChains;
	swapInfo[runId][chJ][chI]++;
	if (isSwapSuccessful == YES)
		swapInfo[runId][chI][chJ]++;
#	endif
	
	return (NO_ERROR);
	
}





/* Autotune Dirichlet move */
void AutotuneDirichlet (MrBFlt acceptanceRate, MrBFlt targetRate, int batch, MrBFlt *alphaPi, MrBFlt minTuning, MrBFlt maxTuning)
{
    MrBFlt delta, logTuning, newTuning;

    delta = 1.0 / sqrt(batch);
    delta = 0.01 < delta ? 0.01 : delta;

    logTuning = log(*alphaPi);

    if (acceptanceRate > targetRate)
        logTuning -= delta;
    else
        logTuning += delta;

    newTuning = exp(logTuning);
    if (newTuning > minTuning && newTuning < maxTuning)
        *alphaPi = newTuning;
}





/* Autotune multiplier move */
void AutotuneMultiplier (MrBFlt acceptanceRate, MrBFlt targetRate, int batch, MrBFlt *lambda, MrBFlt minTuning, MrBFlt maxTuning)
{
    MrBFlt delta, logTuning, newTuning;

    delta = 1.0 / sqrt(batch);
    delta = 0.01 < delta ? 0.01 : delta;

    logTuning = log(*lambda);

    if (acceptanceRate > targetRate)
        logTuning += delta;
    else
        logTuning -= delta;

    newTuning = exp(logTuning);
    if (newTuning > minTuning && newTuning < maxTuning)
        *lambda = newTuning;
}





/* Autotune sliding window move */
void AutotuneSlider (MrBFlt acceptanceRate, MrBFlt targetRate, int batch, MrBFlt *width, MrBFlt minTuning, MrBFlt maxTuning)
{
    MrBFlt delta, logTuning, newTuning;

    delta = 1.0 / sqrt(batch);
    delta = 0.01 < delta ? 0.01 : delta;

    logTuning = log(*width);

    if (acceptanceRate > targetRate)
        logTuning += delta;
    else
        logTuning -= delta;

    newTuning = exp(logTuning);
    if (newTuning > minTuning && newTuning < maxTuning)
        *width = newTuning;
}





/*----------------------------------------------------------------
|
|	Bit: return 1 if bit n is set in SafeLong *p
|		else return 0
|
-----------------------------------------------------------------*/
int Bit (int n, SafeLong *p)

{

	SafeLong		x;

	p += n / nBitsInALong;
	x = 1 << (n % nBitsInALong);

	if ((x & (*p)) == 0)
		return 0;
	else
		return 1;

}





void BuildExhaustiveSearchTree (Tree *t, int chain, int nTaxInTree, TreeInfo *tInfo)
{
	int			i;
	TreeNode	*p, *q, *r;
		
	if (nTaxInTree == t->nIntNodes + 1) {
		
		/* Get downpass */
		GetDownPass (t);

		/* Calculate cost of this tree and add to counter */
		tInfo->curScore = GetParsimonyLength (t, chain);
		if (tInfo->curScore < tInfo->minScore)
			{
			tInfo->totalScore *= pow ((tInfo->warp/3.0) / (1.0 - tInfo->warp), tInfo->minScore - tInfo->curScore);
			tInfo->totalScore += 1.0;
			tInfo->minScore = tInfo->curScore;
			}
		else
			tInfo->totalScore += pow (tInfo->warp/3.0, tInfo->curScore - tInfo->minScore) * pow (1.0-tInfo->warp, tInfo->minScore - tInfo->curScore);
	}

	else {

		/* find node to connect */
		q=tInfo->leaf[nTaxInTree];

		/* add using this ancestral node */
		p=tInfo->vertex[nTaxInTree-1];
		q->anc=p;
		p->right=q;

		for (i=0;i<2*nTaxInTree-1;i++) {
			/* find node to connect to */
			if (i>=nTaxInTree)
				r=tInfo->vertex[i-nTaxInTree];
			else
				r=tInfo->leaf[i];

			/* add to this node */
			p->left=r;
			if (r->anc==NULL)
				p->anc=NULL;
			else {
				p->anc=r->anc;
				if (r->anc->left==r)
					r->anc->left=p;
				else
					r->anc->right=p;
			}
			r->anc=p;

			/* next level */
			BuildExhaustiveSearchTree (t, chain, nTaxInTree+1, tInfo);

			if (tInfo->stopScore > 0.0 && tInfo->totalScore >= tInfo->stopScore)
				return;

			/* restore tree before trying next possibility */
			r->anc=p->anc;
			if (r->anc!=NULL) {
				if (r->anc->left==p)
					r->anc->left=r;
				else
					r->anc->right=r;
			}
		}
	}
}





/*------------------------------------------------------------------
|
|	BuildParsTrees: Fill in trees using random add seq with parsimony
|
------------------------------------------------------------------*/
int BuildParsTrees (SafeLong *seed)

{

	int			k, chn, nTaxa;
	Param		*p, *q;
	Tree		*tree;

	/* Build starting trees for state 0 TODO: check that numLocalChains is used correctly here(may be numGlobalChains is needed instead)*/
	for (chn=0; chn<numLocalChains; chn++)
		{
		for (k=0; k<numParams; k++)
			{
			p = &params[k];
			if (p->paramType == P_TOPOLOGY)
				{
                assert (p->nSubParams == 1);
				q = p->subParams[0];
				tree = GetTree (q, chn, 0);
				if (tree->isRooted == YES)
					nTaxa = tree->nNodes - tree->nIntNodes - 1;
				else
					nTaxa = tree->nNodes - tree->nIntNodes;
                /* fixed topology */
                if (p->paramId == TOPOLOGY_RCL_FIXED ||
                    p->paramId == TOPOLOGY_RCCL_FIXED ||
                    p->paramId == TOPOLOGY_CL_FIXED ||
                    p->paramId == TOPOLOGY_CCL_FIXED ||
                    p->paramId == TOPOLOGY_NCL_FIXED ||
                    p->paramId == TOPOLOGY_PARSIMONY_FIXED)
                    {
					MrBayesPrint ("%s   Tree %s is fixed so a parsimony-based starting tree is not built\n", spacer, p->name);
					return (NO_ERROR);
					}
                /* constrained topology */
                else if (tree->nConstraints > 0)
					{
					MrBayesPrint ("%s   Tree %s is constrained and parsimony-based starting trees are not implemented for constrained trees (yet)\n", spacer, p->name);
					return (NO_ERROR);
                    }
				/* random topology */
                else
					{
					if (BuildStepwiseTree (tree, chn, &globalSeed) == ERROR)
						return (ERROR);
					}
				if (InitializeTreeCalibrations (tree) == ERROR)
					return (ERROR);
				FillTopologySubParams(p, chn, 0, seed);
				}
			}
		}

	return (NO_ERROR);
}





/* build (starting) topology stepwise */
int BuildStepwiseTree (Tree *t, int chain, SafeLong *seed) {

    int         i, j, nTips;
    TreeNode    *p, *q, *r;
	CLFlt 		 length;

    // Allocate parsimony matrix if not done already

    /* get the tips */
    for (i=j=0; i<t->nNodes; i++) {
        p =  t->allDownPass[i];
        if (p->left == NULL && p->right == NULL)
            t->allDownPass[j++] = p;
        else if (p->right == NULL && p->anc == NULL && t->isRooted == NO)
            t->allDownPass[j++] = p;
    }
    nTips = j;

    /* order the tips randomly, use last as root */
    for (i=0; i<nTips-1; i++) {
        j = (int) (RandomNumber(seed)*(nTips-1-i));
        j += i;
        p = t->allDownPass[i];
        t->allDownPass[i] = t->allDownPass[j];
        t->allDownPass[j] = p;
    }

    /* build first tree */
    j = 0;
    q = t->allDownPass[0];
    r = t->allDownPass[1];
    p = t->intDownPass[j++];
    q->anc   = p;
    r->anc   = p;
    p->left  = q;
    p->right = r;
    q = t->allDownPass[nTips-1];
    q->anc   = NULL;
    q->right = NULL;
    q->left = p;
    p->anc = q;
    t->root = q;

    /* add nodes one at a time */
    for (i=2; i<nTips-1; i++) {
        r = t->allDownPass[i];
        p = t->intDownPass[j++];
        GetParsDP(t, t->root->left, chain);
        GetParsFP(t, t->root->left, chain);
        q = FindBestNode(t, t->root->left, r, &length, chain);
        p->left = q;
        p->right = r;
        p->anc = q->anc;
        if (q->anc->left == q)
            q->anc->left = p;
        else
            q->anc->right = p;
        q->anc = p;
        r->anc = p;
    }

    /* take care of the root */
    if (t->isRooted == YES) {
        r = t->root;
        q = t->allDownPass[t->nNodes-1];
        p = t->intDownPass[j];
        q->anc = q->right = NULL;
        q->left = p;
        p->anc = q;
        p->left = r->left;
        p->right = r;
        p->left->anc = p;
        r->left = r->right = NULL;
        r->anc = p;
        t->root = q;
    }
    GetDownPass(t);

    return (NO_ERROR);
}





/*------------------------------------------------------------------
|
|	CalcLike_Adgamma: calc likelihood for one adgamma correlation HMM
|
-------------------------------------------------------------------*/
int CalcLike_Adgamma (int d, Param *param, int chain, MrBFlt *lnL)

{
	int				c, i, j, nRates, posit, lastCharId;
	MrBFlt			logScaler, max, prob, *F,
					*oldF, *tempF, fSpace[2][MAX_GAMMA_CATS];
	MrBFlt			*rP;
	CLFlt			freq, *lnScaler;
	ModelInfo		*m;
    ModelParams     *mp;
    SafeLong        *inHMM;
	
    /* find nRates for first division in HMM */
	m = &modelSettings[d];
    mp = &modelParams[d];
	nRates = m->numGammaCats;

	/* calculate rate category frequencies */
	freq = (CLFlt) ((CLFlt) 1.0 / nRates);

	/* find Markov trans probs */
	F = GetParamSubVals (param,chain, state[chain]);
	for (i=posit=0; i<nRates; i++)
		for (j=0; j<nRates; j++)
			markovTi[0][i][j] = F[posit++];
	
	/* precalculate Markov trans probs up to largest small jump */
	/* but only if needed                                       */
	for (i=1; i<MAX_SMALL_JUMP; i++)
		{
		if (hasMarkovTi[i] == YES)
			{
			if (hasMarkovTi[i-1] == YES || i == 1)
				MultiplyMatrices(nRates, markovTi[i-1], markovTi[0], markovTi[i]);
			else
				MultiplyMatrixNTimes(nRates, markovTi[0], i+1, markovTi[i]);
			}
		}
		
	/* find site scaler for this chain and state */
	lnScaler = m->scalers[m->siteScalerIndex[chain]];
	
	/* find rate probs for this chain and state */
	rP = rateProbs[chain] + state[chain] * rateProbRowSize;
	
	/* set bit vector indicating divisions in this HMM */
	inHMM = (SafeLong *) SafeCalloc (((param->nRelParts/nBitsInALong) + 1), sizeof(SafeLong));
	for (i=0; i<param->nRelParts; i++)
		{
		if (modelSettings[param->relParts[i]].shape ==
			modelSettings[d].shape)
			{
			SetBit(param->relParts[i], inHMM);
			}
		}
	
	/* reset logScaler */
	logScaler = 0.0;

	/* Perform the so-called forward algorithm of HMMs  */	
	/* set up the space for f(c,i) */
	F = fSpace[0];
	oldF = fSpace[1];

	for (c=0; c<numChar; c++)
		{
		if (IsBitSet(partitionId[c][partitionNum] - 1, inHMM) == YES)
			break;
		}

			
	/* fill in fi(0) */
	max = 0.0;
	m = &modelSettings[partitionId[c][partitionNum] - 1];
	posit = m->rateProbStart + (compCharPos[c] - m->compCharStart) * m->numGammaCats;

	for (i=0; i<nRates; i++)
		{
		F[i] = rP[posit++];
		if (F[i] > max)
			max = F[i];
		}

	for (i=0; i<nRates; i++)
		F[i] /= max;

	logScaler += lnScaler[compCharPos[c]] +  log(max);

	/* now step along the sequence to the end */
    lastCharId = charInfo[c].charId;
	for (c++; c<numChar; c++)
		{
		/* skip if excluded */
		if (charInfo[c].isExcluded == YES)
			continue;

        /* skip if part of same codon in translated protein model */
        if ((mp->dataType == DNA || mp->dataType == RNA) && m->dataType == PROTEIN && charInfo[c].charId == lastCharId)
            continue;
        else
            lastCharId = charInfo[c].charId;
		
		/* skip if not in HMM */
		if (IsBitSet(partitionId[c][partitionNum] - 1, inHMM) == NO)
			continue;
		
		/* switch F and oldF, since the previous F is now old */
		tempF = F;
		F = oldF;
		oldF = tempF;

		/* find the position of the rate probs */
		m = &modelSettings[partitionId[c][partitionNum] - 1];
		posit = m->rateProbStart + (compCharPos[c] - m->compCharStart) * m->numGammaCats;
				
		/* calculate the HMM forward probs fi(x) at site x in HMM */
		if (siteJump[c] <= MAX_SMALL_JUMP)
			{
			max = 0.0;
			for (i=0; i<nRates; i++)
				{
				prob = 0.0;
				for (j=0; j<nRates; j++)
					prob += markovTi[siteJump[c]-1][i][j] * oldF[j];
				F[i] = rP[posit++] * prob;
				if (F[i] > max)
					max = F[i];
				}
			}
		else if (siteJump[c] < BIG_JUMP)	/* intermediate jump, calculate trans probs */
			{
			MultiplyMatrixNTimes(nRates, markovTi[0], siteJump[c], markovTiN);
			max = 0.0;
			for (i=0; i<nRates; i++)
				{
				prob = 0.0;
				for (j=0; j<nRates; j++)
					prob += markovTiN[i][j] * oldF[j];
				F[i] = rP[posit++] * prob;
				if (F[i] > max)
					max = F[i];
				}
			}
		else	/* big jump, use stationary freqs */
			{
			max = 0.0;
			for (i=0; i<nRates; i++)
				{
				prob = 0.0;
				for (j=0; j<nRates; j++)
					prob += (oldF[j] / freq);
				F[i] = rP[posit++] * prob;
				if (F[i] > max)
					max = F[i];
				}
			}

		/* rescale and adjust total scaler with HMM scaler and site scaler */
		for (i=0; i<nRates; i++)
			F[i] /= max;

		logScaler += lnScaler[compCharPos[c]] +  log(max);
		
		}
	
	/* now pull the rate probs together at the end, F contains the vals needed */
	prob =  0.0;
	for (i=0; i<nRates; i++)
		prob += (freq * F[i]);

	(*lnL) = logScaler +  log(prob);

    free (inHMM);

    return (NO_ERROR);

}





/* CalcPartFreqStats: Calculate standard deviation of partition frequencies */
void CalcPartFreqStats (PFNODE *p, STATS *stat)
{
	int 	i, j, n, min;
	MrBFlt 	f, sum, sumsq, stdev;

	n = chainParams.numRuns;
	min = (int)(chainParams.minPartFreq * stat->numSamples);
    if( ((MrBFlt)min) != chainParams.minPartFreq * stat->numSamples )
        min++;

    /* recursively compute partition frequencies for all subpartitions */
	if (p->left != NULL) 
		CalcPartFreqStats (p->left, stat);
	if (p->right != NULL)
		CalcPartFreqStats (p->right, stat);

	for (i=0; i<n; i++)
	    {
	    if (p->count[i] >= min)
		    break;
	    }

	if (i == n)
		return;

	sum = 0.0;
	sumsq = 0.0;
	for (i=0; i<n; i++)
		{
		f = p->count[i] / stat->numSamples;
		sum += f;
		sumsq += f * f;
		}
	
	f = (sumsq - sum * sum / n) / (n - 1);
	if (f < 0.0)
		stdev = 0.0;
	else
		stdev = sqrt (f);
	
	stat->sum += stdev;
	if (stdev > stat->max)
		stat->max = stdev;

	stat->numPartitions++;

	if (chainParams.allComps == YES)
		{
		for (i=0; i<n; i++)
			{
			for (j=i+1; j<n; j++)
				{
				if (p->count[i] < min && p->count[j] < min)
					continue;

				sum = 0.0;
				sumsq = 0.0;

				f = p->count[i] / stat->numSamples;
				sum += f;
				sumsq += f * f;
				
				f = p->count[j] / stat->numSamples;
				sum += f;
				sumsq += f * f;

				f = (2.0 * sumsq - sum * sum);
				if (f < 0.0)
					stdev = 0.0;
				else
					stdev = sqrt (f / (MrBFlt) 2.0);
				
				if (chainParams.diagnStat == AVGSTDDEV)
					stat->pair[i][j] += stdev;
				else if (stdev > stat->pair[i][j])
					stat->pair[i][j] = stdev;
				stat->pair[j][i]++;
				}
			}
		}
}





/*----------------------------------------------------------------
|
|	CalculateTopConvDiagn: Calculate average and max standard
|      deviation in clade credibility (partition frequency) values
|
----------------------------------------------------------------*/
void CalculateTopConvDiagn (int numSamples)
{
	int		i, j, n;
	STATS	*stat;
	
	for (n=0; n<numTopologies; n++)
		{
		stat = &chainParams.stat[n];
		stat->numSamples = numSamples;
		stat->numPartitions = 0.0;
		stat->sum = 0.0;
        stat->max = 0.0;

		if (chainParams.allComps == YES)
			{
			for (i=0; i<chainParams.numRuns; i++)
				for (j=0; j<chainParams.numRuns; j++)
					stat->pair[i][j] = 0.0;
			}
	
		CalcPartFreqStats (partFreqTreeRoot[n], stat);
		
        stat->avgStdDev = stat->sum / stat->numPartitions;
		}
}





int CheckTemperature (void)

{

	if (chainParams.userDefinedTemps == YES)
	        {
		  if(AreDoublesEqual(chainParams.userTemps[0], 1.0, ETA)==NO)
			{
			MrBayesPrint ("%s   The first user-defined temperature must be 1.0.\n", spacer);
			return (ERROR);
			}
		}

	return (NO_ERROR);
	
}




void CloseMBPrintFiles (void)
{
	int		i, k, n;

	for (n=0; n<chainParams.numRuns; n++)
		{
#		if defined (MPI_ENABLED)
		if (proc_id == 0)
			{
#		endif
		k = n;

		SafeFclose (&fpParm[k]);

		for (i=0; i<numTrees; i++)
			{
			if (fpTree[k][i])
				{
				fprintf (fpTree[k][i], "end;\n");
				SafeFclose (&fpTree[k][i]);
				}
			fpTree[k][i] = NULL;
			}

#		if defined (MPI_ENABLED)
			}
#		endif
		}

#	if defined (MPI_ENABLED)
	if (proc_id != 0)
		return;
#	endif

	if (chainParams.mcmcDiagn == YES)
		SafeFclose (&fpMcmc);

    if ( chainParams.isSS == YES )
		SafeFclose (&fpSS);
		
}



/* CompactTree: prune partition tree */
PFNODE *CompactTree (PFNODE *p)
{
	int			i, j;
	PFNODE		*q, *r;

	if (p == NULL)
		return NULL;
	
	i = j = 0;
	if (IsPFNodeEmpty(p) == YES)
		{
		/* steal info from terminal on the way up */
		q = SmallestNonemptyPFNode (p->left, &i, 0);
		r = LargestNonemptyPFNode (p->right, &j, 0);

		if (q != NULL || r != NULL)
			{
			if (i < j)
				q = r;
		
			for (i=0; i<chainParams.numRuns; i++)
				{
				p->count[i] = q->count[i];
				q->count[i] = 0;
				}
			for (i=0; i<nLongsNeeded; i++)
				p->partition[i] = q->partition[i];
			}
		}

	p->left = CompactTree (p->left);
	p->right = CompactTree (p->right);

	/* delete on the way down if empty */
	if (IsPFNodeEmpty(p) == YES)
		{
		Tfree (p);
		return NULL;
		}
	else
		return p;
}




#if !defined (SSE_ENABLED)|| 1
/*----------------------------------------------------------------
|
|	CondLikeDown_Bin: binary model with or without rate
|		variation
|
-----------------------------------------------------------------*/
int CondLikeDown_Bin (TreeNode *p, int division, int chain)

{

	int				c, k;
	CLFlt			*clL, *clR, *clP, *pL, *pR, *tiPL, *tiPR;
	ModelInfo		*m;
	
	/* find model settings for this division */
	m = &modelSettings[division];

	/* Flip conditional likelihood space */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = m->condLikes[m->condLikeIndex[chain][p->right->index]];
	clP = m->condLikes[m->condLikeIndex[chain][p->index       ]];
	
	/* find transition probabilities */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];

	tiPL = pL;
	tiPR = pR;
	for (k=0; k<m->numGammaCats; k++)
		{
		for (c=0; c<m->numChars; c++)
			{
			*(clP++) = (tiPL[0]*clL[0] + tiPL[1]*clL[1])
					  *(tiPR[0]*clR[0] + tiPR[1]*clR[1]);
			*(clP++) = (tiPL[2]*clL[0] + tiPL[3]*clL[1])
					  *(tiPR[2]*clR[0] + tiPR[3]*clR[1]);

			clL += 2;
			clR += 2;
			}
		tiPL += 4;
		tiPR += 4;
		}


	return NO_ERROR;
	
}
#endif




#if defined (SSE_ENABLED)
/*----------------------------------------------------------------
|
|	CondLikeDown_Bin_SSE: binary model with or without rate
|		variation
|
-----------------------------------------------------------------*/
int CondLikeDown_Bin_SSE (TreeNode *p, int division, int chain)

{
	int				c, k;
    CLFlt           *pL, *pR, *tiPL, *tiPR;
	__m128			*clL, *clR, *clP;
	__m128			m1, m2, m3, m4, m5, m6;
	ModelInfo		*m;
	
	m = &modelSettings[division];

	/* flip state of node so that we are not overwriting old cond likes */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->right->index]];
	clP = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->index       ]];
	
	/* find transition probabilities */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];

	tiPL = pL;
	tiPR = pR;
	for (k=0; k<m->numGammaCats; k++)
		{
	    for (c=0; c<m->numSSEChars; c++)
		    {
            m1 = _mm_load1_ps (&tiPL[0]);
			m2 = _mm_load1_ps (&tiPR[0]);
            m5 = _mm_mul_ps (m1, clL[0]);
            m6 = _mm_mul_ps (m2, clR[0]);

            m1 = _mm_load1_ps (&tiPL[1]);
			m2 = _mm_load1_ps (&tiPR[1]);
            m3 = _mm_mul_ps (m1, clL[1]);
            m4 = _mm_mul_ps (m2, clR[1]);

            m5 = _mm_add_ps (m3, m5);
            m6 = _mm_add_ps (m4, m6);

            *clP++ = _mm_mul_ps (m5, m6);

            m1 = _mm_load1_ps (&tiPL[2]);
			m2 = _mm_load1_ps (&tiPR[2]);
            m5 = _mm_mul_ps (m1, clL[0]);
            m6 = _mm_mul_ps (m2, clR[0]);

            m1 = _mm_load1_ps (&tiPL[3]);
			m2 = _mm_load1_ps (&tiPR[3]);
            m3 = _mm_mul_ps (m1, clL[1]);
            m4 = _mm_mul_ps (m2, clR[1]);

            m5 = _mm_add_ps (m3, m5);
            m6 = _mm_add_ps (m4, m6);
           
            *clP++ = _mm_mul_ps (m5, m6);
			clL += 2;
			clR += 2;
			}
        tiPL += 4;
        tiPR += 4;
		}

	return NO_ERROR;
	
}
#endif





/*----------------------------------------------------------------
|
|	CondLikeDown_Gen: general n-state model with or without rate
|		variation
|
-----------------------------------------------------------------*/
int CondLikeDown_Gen (TreeNode *p, int division, int chain)

{

	int				a, b, c, h, i, k, j, shortCut, *lState=NULL, *rState=NULL,
					nObsStates, nStates, nStatesSquared, preLikeJump;
	CLFlt			likeL, likeR, *pL, *pR, *tiPL, *tiPR, *clL, *clR, *clP;
	ModelInfo		*m;
#	if !defined (DEBUG_NOSHORTCUTS)
	int	catStart;
#endif
	
	/* find model settings for this division and nStates, nStatesSquared */
	m = &modelSettings[division];
	nObsStates = m->numStates;
	nStates = m->numModelStates;
	nStatesSquared = nStates * nStates;
	preLikeJump = nObsStates * nStates;

	/* flip conditional likelihood space */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = m->condLikes[m->condLikeIndex[chain][p->right->index]];
	clP = m->condLikes[m->condLikeIndex[chain][p->index       ]];
	
	/* find transition probabilities */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];

	/* find likelihoods of site patterns for left branch if terminal */
	shortCut = 0;
#	if !defined (DEBUG_NOSHORTCUTS)
	if (p->left->left == NULL && m->isPartAmbig[p->left->index] == NO)
		{
		shortCut |= 1;
		lState = m->termState[p->left->index];
		tiPL = pL;
		for (k=a=0; k<m->numGammaCats; k++)
			{
			catStart = a;
			for (i=0; i<nObsStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeL[a++] = tiPL[j];
			for (b=1; b<nStates/nObsStates; b++)
				{
				a = catStart;
				for (i=0; i<nObsStates; i++)
					{
					for (j=i+b*nObsStates; j<nStatesSquared; j+=nStates)
						preLikeL[a++] += tiPL[j];
					}
				}
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeL[a++] = 1.0;
			tiPL += nStatesSquared;
			}
		}

	/* find likelihoods of site patterns for right branch if terminal */
	if (p->right->left == NULL && m->isPartAmbig[p->right->index] == NO)
		{
		shortCut |= 2;
		rState = m->termState[p->right->index];
		tiPR = pR;
		for (k=a=0; k<m->numGammaCats; k++)
			{
			catStart = a;
			for (i=0; i<nObsStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeR[a++] = tiPR[j];
			for (b=1; b<nStates/nObsStates; b++)
				{
				a = catStart;
				for (i=0; i<nObsStates; i++)
					{
					for (j=i+b*nObsStates; j<nStatesSquared; j+=nStates)
						preLikeR[a++] += tiPR[j];
					}
				}
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeR[a++] = 1.0;
			tiPR += nStatesSquared;
			}
		}
#	endif
	switch (shortCut)
		{
		case 0:
			tiPL = pL;
			tiPR = pR;
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					for (i=h=0; i<nStates; i++)
						{
						likeL = likeR = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeL += tiPL[h]*clL[j];
							likeR += tiPR[h++]*clR[j];
							}
						*(clP++) = likeL * likeR;
						}
					clL += nStates;
					clR += nStates;
					}
				tiPL += nStatesSquared;
				tiPR += nStatesSquared;
				}
			break;
		case 1:
			tiPR = pR;
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					a = lState[c] + k*(preLikeJump+nStates);
					for (i=h=0; i<nStates; i++)
						{
						likeR = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeR += tiPR[h++]*clR[j];
							}
						*(clP++) = preLikeL[a++] * likeR;
						}
					clR += nStates;
					}
				tiPR += nStatesSquared;
				}
			break;
		case 2:
			tiPL = pL;
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					a = rState[c] + k*(preLikeJump+nStates);
					for (i=h=0; i<nStates; i++)
						{
						likeL = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeL += tiPL[h++]*clL[j];
							}
						*(clP++) = preLikeR[a++] * likeL;
						}
					clL += nStates;
					}
				tiPL += nStatesSquared;
				}
			break;
		case 3:
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					a = rState[c] + k*(preLikeJump+nStates);
					b = lState[c] + k*(preLikeJump+nStates);
					for (i=0; i<nStates; i++)
						{
						*(clP++) = preLikeR[a++] * preLikeL[b++];
						}
					}
				}
			break;
		}

	return NO_ERROR;
	
}





#if defined (SSE_ENABLED)
/*----------------------------------------------------------------
|
|	CondLikeDown_Gen_SSE: general n-state model with or without rate
|		variation
|
-----------------------------------------------------------------*/
int CondLikeDown_Gen_SSE (TreeNode *p, int division, int chain)

{

	int				c, c1, h, i, j, k, t, shortCut, *lState=NULL, *rState=NULL, nStates, nStatesSquared, nObsStates, preLikeJump;
	CLFlt			*pL, *pR, *tiPL, *tiPR;
	__m128			*clL, *clR, *clP;
	__m128			mTiPL, mTiPR, mL, mR, mAcumL, mAcumR;
	ModelInfo		*m;
	CLFlt			*preLikeRV[FLOATS_PER_VEC];
	CLFlt			*preLikeLV[FLOATS_PER_VEC];

#	if !defined (DEBUG_NOSHORTCUTS)
	int				a, b, catStart;
#endif
	
	/* find model settings for this division and nStates, nStatesSquared */
	m = &modelSettings[division];
	nObsStates = m->numStates;
	nStates = m->numModelStates;
	nStatesSquared = nStates * nStates;
	preLikeJump = nObsStates * nStates;

	/* Flip conditional likelihood space */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = (__m128 *)m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = (__m128 *)m->condLikes[m->condLikeIndex[chain][p->right->index]];
	clP = (__m128 *)m->condLikes[m->condLikeIndex[chain][p->index       ]];
	
	/* find transition probabilities */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];

	/* find likelihoods of site patterns for left branch if terminal */
	shortCut = 0;
#	if !defined (DEBUG_NOSHORTCUTS)
	if (p->left->left == NULL && m->isPartAmbig[p->left->index] == NO)
		{
		shortCut |= 1;
		lState = m->termState[p->left->index];
		tiPL = pL;
		for (k=a=0; k<m->numGammaCats; k++)
			{
			catStart = a;
			for (i=0; i<nObsStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeL[a++] = tiPL[j];
			for (b=1; b<nStates/nObsStates; b++)
				{
				a = catStart;
				for (i=0; i<nObsStates; i++)
					{
					for (j=i+b*nObsStates; j<nStatesSquared; j+=nStates)
						preLikeL[a++] += tiPL[j];
					}
				}
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeL[a++] = 1.0;
			tiPL += nStatesSquared;
			}
		}

	/* find likelihoods of site patterns for right branch if terminal */
	if (p->right->left == NULL && m->isPartAmbig[p->right->index] == NO)
		{
		shortCut |= 2;
		rState = m->termState[p->right->index];
		tiPR = pR;
		for (k=a=0; k<m->numGammaCats; k++)
			{
			catStart = a;
			for (i=0; i<nObsStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeR[a++] = tiPR[j];
			for (b=1; b<nStates/nObsStates; b++)
				{
				a = catStart;
				for (i=0; i<nObsStates; i++)
					{
					for (j=i+b*nObsStates; j<nStatesSquared; j+=nStates)
						preLikeR[a++] += tiPR[j];
					}
				}
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeR[a++] = 1.0;
			tiPR += nStatesSquared;
			}
		}
#	endif

	switch (shortCut)
		{
		case 0:
			tiPL = pL;
			tiPR = pR;
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=0; c<m->numSSEChars; c++)
					{
					for (i=h=0; i<nStates; i++)
						{
						mAcumL = _mm_setzero_ps();
						mAcumR = _mm_setzero_ps();
						for (j=0; j<nStates; j++)
							{
							mTiPL  = _mm_load1_ps (&tiPL[h]);
							mTiPR  = _mm_load1_ps (&tiPR[h++]);
							mL     = _mm_mul_ps (mTiPL, clL[j]);
							mR     = _mm_mul_ps (mTiPR, clR[j]);
							mAcumL = _mm_add_ps (mL, mAcumL);
							mAcumR = _mm_add_ps (mR, mAcumR);
							}
						*(clP++) = _mm_mul_ps (mAcumL, mAcumR);
						}
					clL += nStates;
					clR += nStates;
					}
				tiPL += nStatesSquared;
				tiPR += nStatesSquared;
				}
			break;
		case 1:
			tiPR = pR;
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=t=0; c<m->numSSEChars; c++)
					{
					for(c1=0; c1<FLOATS_PER_VEC; c1++,t++)
						{
						preLikeLV[c1] = &preLikeL[lState[t] + k*(preLikeJump+nStates)];
						}
					for (i=h=0; i<nStates; i++)
						{
						assert( FLOATS_PER_VEC == 4 ); /* In the following statment we assume that SSE register can hold exactly 4 ClFlts. */
						mAcumL = _mm_set_ps( *(preLikeLV[3]++), *(preLikeLV[2]++), *(preLikeLV[1]++), *(preLikeLV[0]++));
						mAcumR = _mm_setzero_ps();
						for (j=0; j<nStates; j++)
							{
							mTiPR  = _mm_load1_ps (&tiPR[h++]);
							mR     = _mm_mul_ps (mTiPR, clR[j]);
							mAcumR = _mm_add_ps (mR, mAcumR);
							}
						*(clP++) = _mm_mul_ps (mAcumL,mAcumR);
						}
					clR += nStates;
					}
				tiPR += nStatesSquared;
				}
			break;
		case 2:
			tiPL = pL;
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=t=0; c<m->numSSEChars; c++)
					{
					for(c1=0; c1<FLOATS_PER_VEC; c1++,t++)
						{
						preLikeRV[c1] = &preLikeR[rState[t] + k*(preLikeJump+nStates)];
						}
					for (i=h=0; i<nStates; i++)
						{
						assert( FLOATS_PER_VEC == 4 ); /* In the following statment we assume that SSE register can hold exactly 4 ClFlts. */
						mAcumR = _mm_set_ps( *(preLikeRV[3]++), *(preLikeRV[2]++), *(preLikeRV[1]++), *(preLikeRV[0]++));
						mAcumL = _mm_setzero_ps();
						for (j=0; j<nStates; j++)
							{
							mTiPL  = _mm_load1_ps (&tiPL[h++]);
							mL     = _mm_mul_ps (mTiPL, clL[j]);
							mAcumL = _mm_add_ps (mL, mAcumL);
							}
						*(clP++) = _mm_mul_ps (mAcumL,mAcumR);
						}
					clL += nStates;
					}
				tiPL += nStatesSquared;
				}
			break;
		case 3:
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=t=0; c<m->numSSEChars; c++)
					{
					for(c1=0; c1<FLOATS_PER_VEC; c1++,t++)
						{
						preLikeRV[c1] = &preLikeR[rState[t] + k*(preLikeJump+nStates)];
						preLikeLV[c1] = &preLikeL[lState[t] + k*(preLikeJump+nStates)];
						}
					for (i=0; i<nStates; i++)
						{
						assert( FLOATS_PER_VEC == 4 ); /* In the following 2 statments we assume that SSE register can hold exactly 4 ClFlts. */
						mL = _mm_set_ps( *(preLikeLV[3]++), *(preLikeLV[2]++), *(preLikeLV[1]++), *(preLikeLV[0]++));
						mR = _mm_set_ps( *(preLikeRV[3]++), *(preLikeRV[2]++), *(preLikeRV[1]++), *(preLikeRV[0]++));
						*(clP++) = _mm_mul_ps (mL,mR);
						}
					}
				}
			break;
		}
	return NO_ERROR;
	
}
#endif





/*----------------------------------------------------------------
|
|	CondLikeDown_Gen_GibbsGamma: general n-state model with rate
|		variation modeled using discrete gamma with Gibbs resampling
|
-----------------------------------------------------------------*/
int CondLikeDown_Gen_GibbsGamma (TreeNode *p, int division, int chain)

{

	int				a, b, c, i, j, r, *rateCat, shortCut, *lState=NULL, *rState=NULL,
					nObsStates, nStates, nStatesSquared, preLikeJump,
					nGammaCats;
	CLFlt			likeL, likeR, *pL, *pR, *tiPL, *tiPR, *clL, *clR, *clP;
	ModelInfo		*m;
#	if !defined (DEBUG_NOSHORTCUTS)
	int	k, catStart;
#endif
	
	/* find model settings for this division and nStates, nStatesSquared */
	m = &modelSettings[division];
	nObsStates = m->numStates;
	nStates = m->numModelStates;
	nStatesSquared = nStates * nStates;
	preLikeJump = nObsStates * nStates;

	/* flip conditional likelihood space */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = m->condLikes[m->condLikeIndex[chain][p->right->index]];
	clP = m->condLikes[m->condLikeIndex[chain][p->index       ]];
	
	/* find transition probabilities */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];

	/* find rate category index and number of gamma categories */
	rateCat = m->tiIndex + chain * m->numChars;
	nGammaCats = m->numGammaCats;

	/* find likelihoods of site patterns for left branch if terminal */
	shortCut = 0;
#	if !defined (DEBUG_NOSHORTCUTS)
	if (p->left->left == NULL && m->isPartAmbig[p->left->index] == NO)
		{
		shortCut |= 1;
		lState = m->termState[p->left->index];
		tiPL = pL;
		for (k=a=0; k<nGammaCats; k++)
			{
			catStart = a;
			for (i=0; i<nObsStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeL[a++] = tiPL[j];
			for (b=1; b<nStates/nObsStates; b++)
				{
				a = catStart;
				for (i=0; i<nObsStates; i++)
					{
					for (j=i+b*nObsStates; j<nStatesSquared; j+=nStates)
						preLikeL[a++] += tiPL[j];
					}
				}
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeL[a++] = 1.0;
			tiPL += nStatesSquared;
			}
		}

	/* find likelihoods of site patterns for right branch if terminal */
	if (p->right->left == NULL && m->isPartAmbig[p->right->index] == NO)
		{
		shortCut |= 2;
		rState = m->termState[p->right->index];
		tiPR = pR;
		for (k=a=0; k<nGammaCats; k++)
			{
			catStart = a;
			for (i=0; i<nObsStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeR[a++] = tiPR[j];
			for (b=1; b<nStates/nObsStates; b++)
				{
				a = catStart;
				for (i=0; i<nObsStates; i++)
					{
					for (j=i+b*nObsStates; j<nStatesSquared; j+=nStates)
						preLikeR[a++] += tiPR[j];
					}
				}
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeR[a++] = 1.0;
			tiPR += nStatesSquared;
			}
		}
#	endif

	switch (shortCut)
		{
		case 0:
			for (c=0; c<m->numChars; c++)
				{
				r = (*rateCat++);
				if (r < nGammaCats)
					{
					tiPL = pL + r*nStatesSquared;
					tiPR = pR + r*nStatesSquared;
					for (i=0; i<nStates; i++)
						{
						likeL = likeR = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeL += (*tiPL++) * clL[j];
							likeR += (*tiPR++) * clR[j];
							}
						*(clP++) = likeL * likeR;
						}
					}
				else
					clP += nStates;
				clL += nStates;
				clR += nStates;
				}
			break;
		case 1:
			for (c=0; c<m->numChars; c++)
				{
				r = (*rateCat++);
				if (r < nGammaCats)
					{
					tiPR = pR + r*nStatesSquared;
					a = lState[c] + r*(nStatesSquared+nStates);
					for (i=0; i<nStates; i++)
						{
						likeR = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeR += (*tiPR++)*clR[j];
							}
						*(clP++) = preLikeL[a++] * likeR;
						}
					}
				else
					clP += nStates;
				clR += nStates;
				}
			break;
		case 2:
			for (c=0; c<m->numChars; c++)
				{
				r = (*rateCat++);
				if (r < nGammaCats)
					{
					tiPL = pL + r*nStatesSquared;
					a = rState[c] + r*(nStatesSquared+nStates);
					for (i=0; i<nStates; i++)
						{
						likeL = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeL += (*tiPL++)*clL[j];
							}
						*(clP++) = preLikeR[a++] * likeL;
						}
					}
				else
					clP += nStates;
				clL += nStates;
				}
			break;
		case 3:
			for (c=0; c<m->numChars; c++)
				{
				r = (*rateCat++);
				if (r < nGammaCats)
					{
					a = lState[c] + r*(nStatesSquared+nStates);
					b = rState[c] + r*(nStatesSquared+nStates);
					for (i=0; i<nStates; i++)
						*(clP++) = preLikeL[a++]*preLikeR[b++];
					}
				else
					clP += nStates;
				}
			break;
		}

	return NO_ERROR;
	
}






/*----------------------------------------------------------------
|
|	CondLikeDown_NUC4: 4by4 nucleotide model with or without rate
|		variation
|
-----------------------------------------------------------------*/
int CondLikeDown_NUC4 (TreeNode *p, int division, int chain)

{
	int				c, h, i, j, k, shortCut, *lState=NULL, *rState=NULL;
	CLFlt			*clL, *clR, *clP, *pL, *pR, *tiPL, *tiPR;
	ModelInfo		*m;
	
	m = &modelSettings[division];

	/* flip space so that we do not overwrite old cond likes */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = m->condLikes[m->condLikeIndex[chain][p->right->index]];
	clP = m->condLikes[m->condLikeIndex[chain][p->index       ]];
	
	/* find transition probabilities */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];

    /* find likelihoods of site patterns for left branch if terminal */
	shortCut = 0;
#	if !defined (DEBUG_NOSHORTCUTS)
	if (p->left->left == NULL && m->isPartAmbig[p->left->index] == NO)
		{
		shortCut |= 1;
		lState = m->termState[p->left->index];
		tiPL = pL;
		for (k=j=0; k<m->numGammaCats; k++)
			{
			for (i=0; i<4; i++)
				{
				preLikeL[j++] = tiPL[0];
				preLikeL[j++] = tiPL[4];
				preLikeL[j++] = tiPL[8];
				preLikeL[j++] = tiPL[12];
				tiPL++;
				}
			/* for ambiguous */
			for (i=0; i<4; i++)
				preLikeL[j++] = 1.0;
			tiPL += 12;
			}
		}

	/* find likelihoods of site patterns for right branch if terminal */
	if (p->right->left == NULL && m->isPartAmbig[p->right->index] == NO)
		{
		shortCut |= 2;
		rState = m->termState[p->right->index];
		tiPR = pR;
		for (k=j=0; k<m->numGammaCats; k++)
			{
			for (i=0; i<4; i++)
				{
				preLikeR[j++] = tiPR[0];
				preLikeR[j++] = tiPR[4];
				preLikeR[j++] = tiPR[8];
				preLikeR[j++] = tiPR[12];
				tiPR++;
				}
			/* for ambiguous */
			for (i=0; i<4; i++)
				preLikeR[j++] = 1.0;
			tiPR += 12;
			}
		}
#	endif

	switch (shortCut)
		{
		case 0:
			tiPL = pL;
			tiPR = pR;
			for (k=h=0; k<m->numGammaCats; k++)
				{
			    for (c=0; c<m->numChars; c++)
				    {
					clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
								*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
					clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
								*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
					clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
								*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
					clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
								*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
					clL += 4;
					clR += 4;
					}
				tiPL += 16;
				tiPR += 16;
				}
			break;
		case 1:
			tiPR = pR;
			for (k=h=0; k<m->numGammaCats; k++)
				{
			    for (c=0; c<m->numChars; c++)
				    {
				    i = lState[c] + k*20;
					clP[h++] =   preLikeL[i++]
								*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
					clP[h++] =   preLikeL[i++]
								*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
					clP[h++] =   preLikeL[i++]
								*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
					clP[h++] =   preLikeL[i++]
								*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
					clR += 4;
					}
				tiPR += 16;
				}
			break;
		case 2:
			tiPL = pL;
			for (k=h=0; k<m->numGammaCats; k++)
				{
			    for (c=0; c<m->numChars; c++)
				    {
			        i = rState[c] + k*20;
					clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
								*preLikeR[i++];
					clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
								*preLikeR[i++];
					clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
								*preLikeR[i++];
					clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
								*preLikeR[i++];
					clL += 4;
					}
				tiPL += 16;
				}
			break;
		case 3:
			for (k=h=0; k<m->numGammaCats; k++)
				{
			    for (c=0; c<m->numChars; c++)
				    {
                    i = j = k*20;
				    i += lState[c];
				    j += rState[c];
					clP[h++] =   preLikeL[i++]*preLikeR[j++];
					clP[h++] =   preLikeL[i++]*preLikeR[j++];
					clP[h++] =   preLikeL[i++]*preLikeR[j++];
					clP[h++] =   preLikeL[i++]*preLikeR[j++];
					}
				}
		}

    return NO_ERROR;
	
}





/*----------------------------------------------------------------
|
|	CondLikeDown_NUC4_GibbsGamma: 4by4 nucleotide model with rate
|		variation approximated using Gibbs sampling of gamma
|
-----------------------------------------------------------------*/
int CondLikeDown_NUC4_GibbsGamma (TreeNode *p, int division, int chain)

{
	int				c, h, i, j, r, *rateCat, shortCut, *lState=NULL, *rState=NULL,
					nGammaCats;
	CLFlt			*clL, *clR, *clP, *pL, *pR, *tiPL, *tiPR;
	ModelInfo		*m;
#	if !defined (DEBUG_NOSHORTCUTS)
	int	k;
#endif
	
	m = &modelSettings[division];

	/* flip conditional likelihood space */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = m->condLikes[m->condLikeIndex[chain][p->right->index]];
	clP = m->condLikes[m->condLikeIndex[chain][p->index       ]];
	
	/* find transition probabilities */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];

	/* find rate category index  and number of gamma categories */
	rateCat = m->tiIndex + chain * m->numChars;
	nGammaCats = m->numGammaCats;

	/* find likelihoods of site patterns for left branch if terminal */
	shortCut = 0;
#	if !defined (DEBUG_NOSHORTCUTS)
	if (p->left->left == NULL && m->isPartAmbig[p->left->index] == NO)
		{
		shortCut |= 1;
		lState = m->termState[p->left->index];
		tiPL = pL;
		for (k=j=0; k<nGammaCats; k++)
			{
			for (i=0; i<4; i++)
				{
				preLikeL[j++] = tiPL[0];
				preLikeL[j++] = tiPL[4];
				preLikeL[j++] = tiPL[8];
				preLikeL[j++] = tiPL[12];
				tiPL++;
				}
			/* for ambiguous */
			for (i=0; i<4; i++)
				preLikeL[j++] = 1.0;
			tiPL += 12;
			}
		}

	/* find likelihoods of site patterns for right branch if terminal */
	if (p->right->left == NULL && m->isPartAmbig[p->right->index] == NO)
		{
		shortCut |= 2;
		rState =  m->termState[p->right->index];
		tiPR = pR;
		for (k=j=0; k<nGammaCats; k++)
			{
			for (i=0; i<4; i++)
				{
				preLikeR[j++] = tiPR[0];
				preLikeR[j++] = tiPR[4];
				preLikeR[j++] = tiPR[8];
				preLikeR[j++] = tiPR[12];
				tiPR++;
				}
			/* for ambiguous */
			for (i=0; i<4; i++)
				preLikeR[j++] = 1.0;
			tiPR += 12;
			}
		}
#	endif

	switch (shortCut)
		{
		case 0:
			for (c=h=0; c<m->numChars; c++)
				{
				r = rateCat[c];
				if (r < nGammaCats)
					{
					tiPL = pL + r * 16;
					tiPR = pR + r * 16;
					clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
								*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
					clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
								*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
					clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
								*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
					clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
								*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
					}
				else
					h += 4;
				clL += 4;
				clR += 4;
				}
			break;
		case 1:
			for (c=h=0; c<m->numChars; c++)
				{
				r = rateCat[c];
				if (r < nGammaCats)
					{
					tiPR = pR + r * 16;
					i = lState[c] + r * 20;
					clP[h++] =   preLikeL[i++]
								*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
					clP[h++] =   preLikeL[i++]
								*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
					clP[h++] =   preLikeL[i++]
								*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
					clP[h++] =   preLikeL[i++]
								*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
					}
				else
					h += 4;
				clR += 4;
				}
			break;
		case 2:
			for (c=h=0; c<m->numChars; c++)
				{
				r = rateCat[c];
				if (r < nGammaCats)
					{
					tiPL = pL + r * 16;
					i = rState[c] + r * 20;
					clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
								*preLikeR[i++];
					clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
								*preLikeR[i++];
					clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
								*preLikeR[i++];
					clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
								*preLikeR[i++];
					}
				else
					h += 4;
				clL += 4;
				}
			break;
		case 3:
			for (c=h=0; c<m->numChars; c++)
				{
				r = rateCat[c];
				if (r < nGammaCats)
					{
					i = lState[c] + r * 20;
					j = rState[c] + r * 20;
					clP[h++] =   preLikeL[i++]*preLikeR[j++];
					clP[h++] =   preLikeL[i++]*preLikeR[j++];
					clP[h++] =   preLikeL[i++]*preLikeR[j++];
					clP[h++] =   preLikeL[i++]*preLikeR[j++];
					}
				else
					h += 4;
				}
			break;
		}

	return NO_ERROR;
	
}





#if defined (SSE_ENABLED)
/*----------------------------------------------------------------
|
|	CondLikeDown_NUC4_SSE: 4by4 nucleotide model with or without rate
|		variation, using SSE instructions
|
-----------------------------------------------------------------*/
int CondLikeDown_NUC4_SSE (TreeNode *p, int division, int chain)

{
	int				c, k;
    CLFlt           *pL, *pR, *tiPL, *tiPR;
	__m128			*clL, *clR, *clP;
	__m128			m1, m2, m3, m4, m5, m6;
	ModelInfo		*m;
	
	m = &modelSettings[division];

	/* flip state of node so that we are not overwriting old cond likes */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->right->index]];
	clP = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->index       ]];
	
	/* find transition probabilities */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];

	tiPL = pL;
	tiPR = pR;
	for (k=0; k<m->numGammaCats; k++)
		{
	    for (c=0; c<m->numSSEChars; c++)
		    {
            m1 = _mm_load1_ps (&tiPL[AA]);
			m2 = _mm_load1_ps (&tiPR[AA]);
            m5 = _mm_mul_ps (m1, clL[A]);
            m6 = _mm_mul_ps (m2, clR[A]);

            m1 = _mm_load1_ps (&tiPL[AC]);
			m2 = _mm_load1_ps (&tiPR[AC]);
            m3 = _mm_mul_ps (m1, clL[C]);
            m4 = _mm_mul_ps (m2, clR[C]);
            m5 = _mm_add_ps (m3, m5);
            m6 = _mm_add_ps (m4, m6);

            m1 = _mm_load1_ps (&tiPL[AG]);
			m2 = _mm_load1_ps (&tiPR[AG]);
            m3 = _mm_mul_ps (m1, clL[G]);
            m4 = _mm_mul_ps (m2, clR[G]);
            m5 = _mm_add_ps (m3, m5);
            m6 = _mm_add_ps (m4, m6);

            m1 = _mm_load1_ps (&tiPL[AT]);
			m2 = _mm_load1_ps (&tiPR[AT]);
            m3 = _mm_mul_ps (m1, clL[T]);
            m4 = _mm_mul_ps (m2, clR[T]);
            m5 = _mm_add_ps (m3, m5);
            m6 = _mm_add_ps (m4, m6);

            *clP++ = _mm_mul_ps (m5, m6);

            m1 = _mm_load1_ps (&tiPL[CA]);
			m2 = _mm_load1_ps (&tiPR[CA]);
            m5 = _mm_mul_ps (m1, clL[A]);
            m6 = _mm_mul_ps (m2, clR[A]);

            m1 = _mm_load1_ps (&tiPL[CC]);
			m2 = _mm_load1_ps (&tiPR[CC]);
            m3 = _mm_mul_ps (m1, clL[C]);
            m4 = _mm_mul_ps (m2, clR[C]);
            m5 = _mm_add_ps (m3, m5);
            m6 = _mm_add_ps (m4, m6);

            m1 = _mm_load1_ps (&tiPL[CG]);
			m2 = _mm_load1_ps (&tiPR[CG]);
            m3 = _mm_mul_ps (m1, clL[G]);
            m4 = _mm_mul_ps (m2, clR[G]);
            m5 = _mm_add_ps (m3, m5);
            m6 = _mm_add_ps (m4, m6);

            m1 = _mm_load1_ps (&tiPL[CT]);
			m2 = _mm_load1_ps (&tiPR[CT]);
            m3 = _mm_mul_ps (m1, clL[T]);
            m4 = _mm_mul_ps (m2, clR[T]);
            m5 = _mm_add_ps (m3, m5);
            m6 = _mm_add_ps (m4, m6);

            *clP++ = _mm_mul_ps (m5, m6);

            m1 = _mm_load1_ps (&tiPL[GA]);
			m2 = _mm_load1_ps (&tiPR[GA]);
            m5 = _mm_mul_ps (m1, clL[A]);
            m6 = _mm_mul_ps (m2, clR[A]);

            m1 = _mm_load1_ps (&tiPL[GC]);
			m2 = _mm_load1_ps (&tiPR[GC]);
            m3 = _mm_mul_ps (m1, clL[C]);
            m4 = _mm_mul_ps (m2, clR[C]);
            m5 = _mm_add_ps (m3, m5);
            m6 = _mm_add_ps (m4, m6);

            m1 = _mm_load1_ps (&tiPL[GG]);
			m2 = _mm_load1_ps (&tiPR[GG]);
            m3 = _mm_mul_ps (m1, clL[G]);
            m4 = _mm_mul_ps (m2, clR[G]);
            m5 = _mm_add_ps (m3, m5);
            m6 = _mm_add_ps (m4, m6);

            m1 = _mm_load1_ps (&tiPL[GT]);
			m2 = _mm_load1_ps (&tiPR[GT]);
            m3 = _mm_mul_ps (m1, clL[T]);
            m4 = _mm_mul_ps (m2, clR[T]);
            m5 = _mm_add_ps (m3, m5);
            m6 = _mm_add_ps (m4, m6);

            *clP++ = _mm_mul_ps (m5, m6);

            m1 = _mm_load1_ps (&tiPL[TA]);
			m2 = _mm_load1_ps (&tiPR[TA]);
            m5 = _mm_mul_ps (m1, clL[A]);
            m6 = _mm_mul_ps (m2, clR[A]);

            m1 = _mm_load1_ps (&tiPL[TC]);
			m2 = _mm_load1_ps (&tiPR[TC]);
            m3 = _mm_mul_ps (m1, clL[C]);
            m4 = _mm_mul_ps (m2, clR[C]);
            m5 = _mm_add_ps (m3, m5);
            m6 = _mm_add_ps (m4, m6);

            m1 = _mm_load1_ps (&tiPL[TG]);
			m2 = _mm_load1_ps (&tiPR[TG]);
            m3 = _mm_mul_ps (m1, clL[G]);
            m4 = _mm_mul_ps (m2, clR[G]);
            m5 = _mm_add_ps (m3, m5);
            m6 = _mm_add_ps (m4, m6);

            m1 = _mm_load1_ps (&tiPL[TT]);
			m2 = _mm_load1_ps (&tiPR[TT]);
            m3 = _mm_mul_ps (m1, clL[T]);
            m4 = _mm_mul_ps (m2, clR[T]);
            m5 = _mm_add_ps (m3, m5);
            m6 = _mm_add_ps (m4, m6);

            *clP++ = _mm_mul_ps (m5, m6);
			clL += 4;
			clR += 4;
			}
        tiPL += 16;
        tiPR += 16;
		}

	return NO_ERROR;
	
}
#endif





#if !defined (SSE_ENABLED) || 1
/*----------------------------------------------------------------
|
|	CondLikeDown_NY98: codon model with omega variation
|
-----------------------------------------------------------------*/
int CondLikeDown_NY98 (TreeNode *p, int division, int chain)

{

	int				a, b, c, h, i, j, k, shortCut, *lState=NULL, *rState=NULL, nStates, nStatesSquared;
	CLFlt			likeL, likeR, *pL, *pR, *tiPL, *tiPR, *clL, *clR, *clP;
	ModelInfo		*m;
	
	/* find model settings for this division and nStates, nStatesSquared */
	m = &modelSettings[division];
	nStates = m->numModelStates;
	nStatesSquared = nStates * nStates;

	/* Flip conditional likelihood space */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = m->condLikes[m->condLikeIndex[chain][p->right->index]];
	clP = m->condLikes[m->condLikeIndex[chain][p->index       ]];
	
	/* find transition probabilities */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];

	/* find likelihoods of site patterns for left branch if terminal */
	shortCut = 0;
#	if !defined (DEBUG_NOSHORTCUTS)
	if (p->left->left == NULL && m->isPartAmbig[p->left->index] == NO)
		{
		shortCut |= 1;
		lState = m->termState[p->left->index];
		tiPL = pL;
		for (k=a=0; k<m->numOmegaCats; k++)
			{
			for (i=0; i<nStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeL[a++] = tiPL[j];
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeL[a++] = 1.0;
			tiPL += nStatesSquared;
			}
		}

	/* find likelihoods of site patterns for right branch if terminal */
	if (p->right->left == NULL && m->isPartAmbig[p->right->index] == NO)
		{
		shortCut |= 2;
		rState = m->termState[p->right->index];
		tiPR = pR;
		for (k=a=0; k<m->numOmegaCats; k++)
			{
			for (i=0; i<nStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeR[a++] = tiPR[j];
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeR[a++] = 1.0;
			tiPR += nStatesSquared;
			}
		}
#	endif

	switch (shortCut)
		{
		case 0:
			tiPL = pL;
			tiPR = pR;
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					for (i=h=0; i<nStates; i++)
						{
						likeL = likeR = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeL += tiPL[h]*clL[j];
							likeR += tiPR[h++]*clR[j];
							}
						*(clP++) = likeL * likeR;
						}
					clL += nStates;
					clR += nStates;
					}
				tiPL += nStatesSquared;
				tiPR += nStatesSquared;
				}
			break;
		case 1:
			tiPR = pR;
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					a = lState[c] + k*(nStatesSquared+nStates);
					for (i=h=0; i<nStates; i++)
						{
						likeR = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeR += tiPR[h++]*clR[j];
							}
						*(clP++) = preLikeL[a++] * likeR;
						}
					clR += nStates;
					}
				tiPR += nStatesSquared;
				}
			break;
		case 2:
			tiPL = pL;
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					a = rState[c] + k*(nStatesSquared+nStates);
					for (i=h=0; i<nStates; i++)
						{
						likeL = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeL += tiPL[h++]*clL[j];
							}
						*(clP++) = preLikeR[a++] * likeL;
						}
					clL += nStates;
					}
				tiPL += nStatesSquared;
				}
			break;
		case 3:
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					a = rState[c] + k*(nStatesSquared+nStates);
					b = lState[c] + k*(nStatesSquared+nStates);
					for (i=0; i<nStates; i++)
						{
						*(clP++) = preLikeR[a++] * preLikeL[b++];
						}
					}
				}
			break;
		}

	return NO_ERROR;
	
}
#endif



#if defined (SSE_ENABLED)
/*----------------------------------------------------------------
|
|	CondLikeDown_NY98_SSE: codon model with omega variation
|
-----------------------------------------------------------------*/
int CondLikeDown_NY98_SSE (TreeNode *p, int division, int chain)

{

	int				c, c1, h, i, j, k, t, shortCut, *lState=NULL, *rState=NULL, nStates, nStatesSquared;
	CLFlt			*pL, *pR, *tiPL, *tiPR;
	__m128			*clL, *clR, *clP;
	__m128			mTiPL, mTiPR, mL, mR, mAcumL, mAcumR;
	ModelInfo		*m;
	CLFlt			*preLikeRV[FLOATS_PER_VEC];
	CLFlt			*preLikeLV[FLOATS_PER_VEC];
#	if !defined (DEBUG_NOSHORTCUTS)
	int				a;
#endif
	
	/* find model settings for this division and nStates, nStatesSquared */
	m = &modelSettings[division];
	nStates = m->numModelStates;
	nStatesSquared = nStates * nStates;

	/* Flip conditional likelihood space */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = (__m128 *)m->condLikes[m->condLikeIndex[chain][p->right->index]];
	clP = (__m128 *)m->condLikes[m->condLikeIndex[chain][p->index       ]];
	
	/* find transition probabilities */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];

	/* find likelihoods of site patterns for left branch if terminal */
	shortCut = 0;
#	if !defined (DEBUG_NOSHORTCUTS)
	if (p->left->left == NULL && m->isPartAmbig[p->left->index] == NO)
		{
		shortCut |= 1;
		lState = m->termState[p->left->index];
		tiPL = pL;
		for (k=a=0; k<m->numOmegaCats; k++)
			{
			for (i=0; i<nStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeL[a++] = tiPL[j];
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeL[a++] = 1.0;
			tiPL += nStatesSquared;
			}
		}

	/* find likelihoods of site patterns for right branch if terminal */
	if (p->right->left == NULL && m->isPartAmbig[p->right->index] == NO)
		{
		shortCut |= 2;
		rState = m->termState[p->right->index];
		tiPR = pR;
		for (k=a=0; k<m->numOmegaCats; k++)
			{
			for (i=0; i<nStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeR[a++] = tiPR[j];
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeR[a++] = 1.0;
			tiPR += nStatesSquared;
			}
		}
#	endif

	switch (shortCut)
		{
		case 0:
			tiPL = pL;
			tiPR = pR;
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=0; c<m->numSSEChars; c++)
					{
					for (i=h=0; i<nStates; i++)
						{
						mAcumL = _mm_setzero_ps();
						mAcumR = _mm_setzero_ps();
						for (j=0; j<nStates; j++)
							{
							mTiPL  = _mm_load1_ps (&tiPL[h]);
							mTiPR  = _mm_load1_ps (&tiPR[h++]);
							mL     = _mm_mul_ps (mTiPL, clL[j]);
							mR     = _mm_mul_ps (mTiPR, clR[j]);
							mAcumL = _mm_add_ps (mL, mAcumL);
							mAcumR = _mm_add_ps (mR, mAcumR);
							}
						*(clP++) = _mm_mul_ps (mAcumL, mAcumR);
						}
					clL += nStates;
					clR += nStates;
					}
				tiPL += nStatesSquared;
				tiPR += nStatesSquared;
				}
			break;
		case 1:
			tiPR = pR;
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=t=0; c<m->numSSEChars; c++)
					{
					for(c1=0; c1<FLOATS_PER_VEC; c1++,t++)
						{
						preLikeLV[c1] = &preLikeL[lState[t] + k*(nStatesSquared+nStates)];
						}
					for (i=h=0; i<nStates; i++)
						{
						assert( FLOATS_PER_VEC == 4 ); /* In the following statment we assume that SSE register can hold exactly 4 ClFlts. */
						mAcumL = _mm_set_ps( *(preLikeLV[3]++), *(preLikeLV[2]++), *(preLikeLV[1]++), *(preLikeLV[0]++));
						mAcumR = _mm_setzero_ps();
						for (j=0; j<nStates; j++)
							{
							mTiPR  = _mm_load1_ps (&tiPR[h++]);
							mR     = _mm_mul_ps (mTiPR, clR[j]);
							mAcumR = _mm_add_ps (mR, mAcumR);
							}
						*(clP++) = _mm_mul_ps (mAcumL,mAcumR);
						}
					clR += nStates;
					}
				tiPR += nStatesSquared;
				}
			break;
		case 2:
			tiPL = pL;
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=t=0; c<m->numSSEChars; c++)
					{
					for(c1=0; c1<FLOATS_PER_VEC; c1++,t++)
						{
						preLikeRV[c1] = &preLikeR[rState[t] + k*(nStatesSquared+nStates)];
						}
					for (i=h=0; i<nStates; i++)
						{
						assert( FLOATS_PER_VEC == 4 ); /* In the following statment we assume that SSE register can hold exactly 4 ClFlts. */
						mAcumR = _mm_set_ps( *(preLikeRV[3]++), *(preLikeRV[2]++), *(preLikeRV[1]++), *(preLikeRV[0]++));
						mAcumL = _mm_setzero_ps();
						for (j=0; j<nStates; j++)
							{
							mTiPL  = _mm_load1_ps (&tiPL[h++]);
							mL     = _mm_mul_ps (mTiPL, clL[j]);
							mAcumL = _mm_add_ps (mL, mAcumL);
							}
						*(clP++) = _mm_mul_ps (mAcumL,mAcumR);
						}
					clL += nStates;
					}
				tiPL += nStatesSquared;
				}
			break;
		case 3:
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=t=0; c<m->numSSEChars; c++)
					{
					for(c1=0; c1<FLOATS_PER_VEC; c1++,t++)
						{
						preLikeRV[c1] = &preLikeR[rState[t] + k*(nStatesSquared+nStates)];
						preLikeLV[c1] = &preLikeL[lState[t] + k*(nStatesSquared+nStates)];
						}
					for (i=0; i<nStates; i++)
						{
						assert( FLOATS_PER_VEC == 4 ); /* In the following 2 statments we assume that SSE register can hold exactly 4 ClFlts. */
						mL = _mm_set_ps( *(preLikeLV[3]++), *(preLikeLV[2]++), *(preLikeLV[1]++), *(preLikeLV[0]++));
						mR = _mm_set_ps( *(preLikeRV[3]++), *(preLikeRV[2]++), *(preLikeRV[1]++), *(preLikeRV[0]++));
						*(clP++) = _mm_mul_ps (mL,mR);
						}
					}
				}
			break;
		}

	return NO_ERROR;
	
}
#endif





/*----------------------------------------------------------------
|
|	CondLikeDown_Std: variable number of states model
|		with or without rate variation
|
-----------------------------------------------------------------*/
int CondLikeDown_Std (TreeNode *p, int division, int chain)

{

	int				a, c, h, i, j, k, nStates, nCats, tmp;
	CLFlt			*clL, *clR, *clP, *pL, *pR, *tiPL, *tiPR, likeL, likeR;
	ModelInfo		*m;
	
	m = &modelSettings[division];

	/* Flip conditional likelihood space */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = m->condLikes[m->condLikeIndex[chain][p->right->index]];
	clP = m->condLikes[m->condLikeIndex[chain][p->index       ]];
	
	/* find transition probabilities */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];

	/* Conditional likelihood space is assumed to be arranged in numGammaCats blocks of data. Each block contains all data for one gamma category.
	Each gamma cat block consist of numChars sequences of data, each of this sequences corresponds to a character of data matrix. 
	A sequence consists of nStates for all non-binary data, otherwise length of sequence is nStates*numBetaCats (i.e. 2*numBetaCats) */

	/* calculate ancestral probabilities */
	for (k=h=0; k<m->numGammaCats; k++)
		{
		/* calculate ancestral probabilities */
		for (c=0; c<m->numChars; c++)
			{
			nStates = m->nStates[c];
		
			/* the following lines ensure that nCats is 1 unless */
			/* the character is binary and beta categories are used  */
			if (nStates == 2)
				nCats = m->numBetaCats;
			else
				nCats = 1;

			tmp = k*nStates*nStates; /* tmp contains offset to skip gamma cats that already processed*/
			tiPL = pL + m->tiIndex[c] + tmp;
			tiPR = pR + m->tiIndex[c] + tmp;
			tmp = (m->numGammaCats-1)*2*2; /* tmp contains size of block of tpi matrices across all gamma cats (minus one) for single beta category. Further used only if character is binary to jump to next beta category */
				
			for(j=0; j<nCats;j++)
				{
				for (a=0; a<nStates; a++)
					{
					likeL = likeR = 0.0;
					for (i=0; i<nStates; i++)
						{
						likeL += *(tiPL++) * clL[i];
						likeR += *(tiPR++) * clR[i];
						}
	                clP[h++] = likeL * likeR;
					}
				clL += nStates;
				clR += nStates;
		
				tiPL += tmp;
				tiPR += tmp;
				}
			}
		}


	return NO_ERROR;
}




#if !defined (SSE_ENABLED)|| 1
/*----------------------------------------------------------------
|
|	CondLikeRoot_Bin: binary model with or without rate
|		variation
|
-----------------------------------------------------------------*/
int CondLikeRoot_Bin (TreeNode *p, int division, int chain)

{

	int				c, k;
	CLFlt			*clL, *clR, *clP, *clA, *pL, *pR, *pA, *tiPL, *tiPR, *tiPA;
	ModelInfo		*m;

	/* find model settings for this division */
	m = &modelSettings[division];
	
	/* flip state of node so that we are not overwriting old cond likes */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = m->condLikes[m->condLikeIndex[chain][p->right->index]];
    clP = m->condLikes[m->condLikeIndex[chain][p->index       ]];
    clA = m->condLikes[m->condLikeIndex[chain][p->anc->index  ]];

	/* find transition probabilities (or calculate instead) */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];
	pA = m->tiProbs[m->tiProbsIndex[chain][p->index       ]];

	tiPL = pL;
	tiPR = pR;
	tiPA = pA;
	for (k=0; k<m->numGammaCats; k++)
		{
		for (c=0; c<m->numChars; c++)
			{
			*(clP++) = (tiPL[0]*clL[0] + tiPL[1]*clL[1])
					  *(tiPR[0]*clR[0] + tiPR[1]*clR[1])
					  *(tiPA[0]*clA[0] + tiPA[1]*clA[1]);
			*(clP++) = (tiPL[2]*clL[0] + tiPL[3]*clL[1])
					  *(tiPR[2]*clR[0] + tiPR[3]*clR[1])
					  *(tiPA[2]*clA[0] + tiPA[3]*clA[1]);

			clA += 2;
			clL += 2;
			clR += 2;
			}
		tiPA += 4;
		tiPL += 4;
		tiPR += 4;
		}

	return NO_ERROR;
	
}
#endif





#if defined (SSE_ENABLED)
/*----------------------------------------------------------------
|
|	CondLikeRoot_Bin_SSE:binary model with or without rate
|		variation 
|
-----------------------------------------------------------------*/
int CondLikeRoot_Bin_SSE (TreeNode *p, int division, int chain)

{
	int				c, k;
    CLFlt           *pL, *pR, *pA, *tiPL, *tiPR, *tiPA;
	__m128			*clL, *clR, *clP, *clA;
	__m128			m1, m2, m3, m4, m5, m6, m7;
	ModelInfo		*m;

	m = &modelSettings[division];

	/* flip state of node so that we are not overwriting old cond likes */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->left->index ]];
    clR = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->right->index]];
    clP = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->index       ]];
    clA = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->anc->index  ]];

	/* find transition probabilities */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
    pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];
    pA = m->tiProbs[m->tiProbsIndex[chain][p->index       ]];

	tiPL = pL;
	tiPR = pR;
	tiPA = pA;
	for (k=0; k<m->numGammaCats; k++)
		{
        for (c=0; c<m->numSSEChars; c++)
		    {
			m1 = _mm_load1_ps (&tiPL[0]);
			m5 = *clL++;
			m2 = _mm_mul_ps (m1, m5);
			m1 = _mm_load1_ps (&tiPL[2]);
			m6 = _mm_mul_ps (m1, m5);

			m1 = _mm_load1_ps (&tiPL[1]);
			m5 = *clL++;
			m3 = _mm_mul_ps (m1, m5);
			m1 = _mm_load1_ps (&tiPL[3]);
			m5 = _mm_mul_ps (m1, m5);

			m4 = _mm_add_ps (m2, m3); /* in m4 we get (tiPL[0]*clL[0] + tiPL[1]*clL[1]) */
			m6 = _mm_add_ps (m5, m6); /* in m6 we get (tiPL[2]*clL[0] + tiPL[3]*clL[1]) */

			m1 = _mm_load1_ps (&tiPR[0]);
			m5 = *clR++;
			m2 = _mm_mul_ps (m1, m5);
			m1 = _mm_load1_ps (&tiPR[2]);
			m7 = _mm_mul_ps (m1, m5);

			m1 = _mm_load1_ps (&tiPR[1]);
			m5 = *clR++;
            m3 = _mm_mul_ps (m1, m5);
			m1 = _mm_load1_ps (&tiPR[3]);
            m5 = _mm_mul_ps (m1, m5);

            m1 = _mm_add_ps (m2, m3); /* in m1 we get (tiPR[0]*clR[0] + tiPR[1]*clR[1]) */
            m7 = _mm_add_ps (m5, m7); /* in m7 we get (tiPR[2]*clR[0] + tiPR[3]*clR[1]) */

            m4 = _mm_mul_ps (m1, m4); /* in m4 we get (tiPL[0]*clL[0] + tiPL[1]*clL[1])*(tiPR[0]*clR[0] + tiPR[1]*clR[1]) */
			m7 = _mm_mul_ps (m6, m7); /* in m7 we get (tiPL[2]*clL[0] + tiPL[3]*clL[1])*(tiPR[2]*clR[0] + tiPR[3]*clR[1]) */

			m1 = _mm_load1_ps (&tiPA[0]);
			m5 = *clA++;
			m2 = _mm_mul_ps (m1, m5);
			m1 = _mm_load1_ps (&tiPA[2]);
			m6 = _mm_mul_ps (m1, m5);

			m1 = _mm_load1_ps (&tiPA[1]);
			m5 = *clA++;
            m3 = _mm_mul_ps (m1, m5);
			m1 = _mm_load1_ps (&tiPA[3]);
            m1 = _mm_mul_ps (m1, m5);

			m2 = _mm_add_ps (m2, m3); /* in m1 we get (tiPA[0]*clA[0] + tiPA[1]*clA[1]) */
			m1 = _mm_add_ps (m1, m6); /* in m1 we get (tiPA[2]*clA[0] + tiPA[3]*clA[1]) */

			*clP++ = _mm_mul_ps (m2, m4);
			*clP++ = _mm_mul_ps (m1, m7);

			}
        tiPL += 4;
        tiPR += 4;
        tiPA += 4;
		}

	return NO_ERROR;
	
}
#endif




/*----------------------------------------------------------------
|
|	CondLikeRoot_Gen: general n-state model with or without rate
|		variation
|
-----------------------------------------------------------------*/
int CondLikeRoot_Gen (TreeNode *p, int division, int chain)

{

	int				a, b, c, d, h, i, j, k, shortCut, *lState=NULL, *rState=NULL, *aState=NULL,
					nObsStates, nStates, nStatesSquared, preLikeJump;
	CLFlt			likeL, likeR, likeA, *clL, *clR, *clP, *clA, *pL, *pR, *pA,
					*tiPL, *tiPR, *tiPA;
	ModelInfo		*m;
#	if !defined (DEBUG_NOSHORTCUTS)
	int	catStart;
#endif
	
	/* find model settings for this division and nStates, nStatesSquared */
	m = &modelSettings[division];
	nObsStates = m->numStates;
	nStates = m->numModelStates;
	nStatesSquared = nStates * nStates;
	preLikeJump = nObsStates * nStates;

	/* flip state of node so that we are not overwriting old cond likes */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = m->condLikes[m->condLikeIndex[chain][p->right->index]];
    clP = m->condLikes[m->condLikeIndex[chain][p->index       ]];
    clA = m->condLikes[m->condLikeIndex[chain][p->anc->index  ]];

	/* find transition probabilities (or calculate instead) */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];
	pA = m->tiProbs[m->tiProbsIndex[chain][p->index       ]];


	/* find likelihoods of site patterns for left branch if terminal */
	shortCut = 0;
#	if !defined (DEBUG_NOSHORTCUTS)
	if (p->left->left == NULL && m->isPartAmbig[p->left->index] == NO)
		{
		shortCut |= 1;
		lState = m->termState[p->left->index];
		tiPL = pL;
		for (k=a=0; k<m->numGammaCats; k++)
			{
			catStart = a;
			for (i=0; i<nObsStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeL[a++] = tiPL[j];
			for (b=1; b<nStates/nObsStates; b++)
				{
				a = catStart;
				for (i=0; i<nObsStates; i++)
					{
					for (j=i+b*nObsStates; j<nStatesSquared; j+=nStates)
						preLikeL[a++] += tiPL[j];
					}
				}
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeL[a++] = 1.0;
			tiPL += nStatesSquared;
			}
		}

	/* find likelihoods of site patterns for right branch if terminal */
	if (p->right->left == NULL && m->isPartAmbig[p->right->index] == NO)
		{
		shortCut |= 2;
		rState = m->termState[p->right->index];
		tiPR = pR;
		for (k=a=0; k<m->numGammaCats; k++)
			{
			catStart = a;
			for (i=0; i<nObsStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeR[a++] = tiPR[j];
			for (b=1; b<nStates/nObsStates; b++)
				{
				a = catStart;
				for (i=0; i<nObsStates; i++)
					{
					for (j=i+b*nObsStates; j<nStatesSquared; j+=nStates)
						preLikeR[a++] += tiPR[j];
					}
				}
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeR[a++] = 1.0;
			tiPR += nStatesSquared;
			}
		}

	/* find likelihoods of site patterns for anc branch, always terminal */
	if (m->isPartAmbig[p->anc->index] == YES)
		{
		shortCut = 4;
		}
	else 
		{
		aState = m->termState[p->anc->index];
		tiPA = pA;
		for (k=a=0; k<m->numGammaCats; k++)
			{
			catStart = a;
			for (i=0; i<nObsStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeA[a++] = tiPA[j];
			for (b=1; b<nStates/nObsStates; b++)
				{
				a = catStart;
				for (i=0; i<nObsStates; i++)
					{
					for (j=i+b*nObsStates; j<nStatesSquared; j+=nStates)
						preLikeA[a++] += tiPA[j];
					}
				}
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeA[a++] = 1.0;
			tiPA += nStatesSquared;
			}
		}
#	else
	shortCut = 4;
#	endif

	//shortCut = 4;
	switch (shortCut)
		{
		case 4:
			tiPL = pL;
			tiPR = pR;
			tiPA = pA;
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					for (i=h=0; i<nStates; i++)
						{
						likeL = likeR = likeA = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeL += tiPL[h]*clL[j];
							likeR += tiPR[h]*clR[j];
							likeA += tiPA[h++]*clA[j];
							}
						*(clP++) = likeL * likeR * likeA;
						}
					clL += nStates;
					clR += nStates;
					clA += nStates;
					}
				tiPL += nStatesSquared;
				tiPR += nStatesSquared;
				tiPA += nStatesSquared;
				}
			break;
		case 0:
			tiPR = pR;
			tiPL = pL;
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					a = aState[c] + k*(preLikeJump+nStates);
					for (i=h=0; i<nStates; i++)
						{
						likeR = likeL = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeR += tiPR[h]*clR[j];
							likeL += tiPL[h++]*clL[j];
							}
						*(clP++) = preLikeA[a++] * likeR * likeL;
						}
					clR += nStates;
					clL += nStates;
					}
				tiPR += nStatesSquared;
				tiPL += nStatesSquared;
				}
			break;
		case 1:
			tiPR = pR;
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					a = lState[c] + k*(preLikeJump+nStates);
					b = aState[c] + k*(preLikeJump+nStates);
					for (i=h=0; i<nStates; i++)
						{
						likeR = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeR += tiPR[h++]*clR[j];
							}
						*(clP++) = preLikeL[a++] * preLikeA[b++] * likeR;
						}
					clR += nStates;
					}
				tiPR += nStatesSquared;
				}
			break;
		case 2:
			tiPL = pL;
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					a = rState[c] + k*(preLikeJump+nStates);
					b = aState[c] + k*(preLikeJump+nStates);
					for (i=h=0; i<nStates; i++)
						{
						likeL = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeL += tiPL[h++]*clL[j];
							}
						*(clP++) = preLikeR[a++] * preLikeA[b++] * likeL;
						}
					clL += nStates;
					}
				tiPL += nStatesSquared;
				}
			break;	
		case 3:
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					a = rState[c] + k*(preLikeJump+nStates);
					b = lState[c] + k*(preLikeJump+nStates);
					d = aState[c] + k*(preLikeJump+nStates);
					for (i=0; i<nStates; i++)
						{
						*(clP++) = preLikeR[a++] * preLikeL[b++] * preLikeA[d++];
						}
					}
				}
			break;
		}

	return NO_ERROR;
}





#if defined (SSE_ENABLED)
/*----------------------------------------------------------------
|
|	CondLikeRoot_Gen_SSE:general n-state model with or without rate
|		variation
|
-----------------------------------------------------------------*/
int CondLikeRoot_Gen_SSE (TreeNode *p, int division, int chain)

{

	int				c, c1, t, h, i, j, k, shortCut, *lState=NULL, *rState=NULL, *aState=NULL, nObsStates, preLikeJump,
					nStates, nStatesSquared;
	CLFlt			*pL, *pR, *pA,
					*tiPL, *tiPR, *tiPA;
	__m128			*clL, *clR, *clP, *clA;
	__m128			mTiPL, mTiPR, mTiPA, mL, mR, mA, mAcumL, mAcumR, mAcumA;
	ModelInfo		*m;
	CLFlt			*preLikeRV[FLOATS_PER_VEC];
	CLFlt			*preLikeLV[FLOATS_PER_VEC];
	CLFlt			*preLikeAV[FLOATS_PER_VEC];

#	if !defined (DEBUG_NOSHORTCUTS)
	int	a, b, catStart;
#endif


	/* find model settings for this division and nStates, nStatesSquared */
	m = &modelSettings[division];
	nObsStates = m->numStates;
	nStates = m->numModelStates;
	nStatesSquared = nStates * nStates;
	preLikeJump = nObsStates * nStates;


	/* flip state of node so that we are not overwriting old cond likes */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = (__m128 *)m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = (__m128 *)m->condLikes[m->condLikeIndex[chain][p->right->index]];
    clP = (__m128 *)m->condLikes[m->condLikeIndex[chain][p->index       ]];
    clA = (__m128 *)m->condLikes[m->condLikeIndex[chain][p->anc->index  ]];

	/* find transition probabilities (or calculate instead) */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];
	pA = m->tiProbs[m->tiProbsIndex[chain][p->index       ]];

	/* find likelihoods of site patterns for left branch if terminal */
	shortCut = 0;
#	if !defined (DEBUG_NOSHORTCUTS)
	if (p->left->left == NULL && m->isPartAmbig[p->left->index] == NO)
		{
		shortCut |= 1;
		lState = m->termState[p->left->index];
		tiPL = pL;
		for (k=a=0; k<m->numGammaCats; k++)
			{
			catStart = a;
			for (i=0; i<nObsStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeL[a++] = tiPL[j];
			for (b=1; b<nStates/nObsStates; b++)
				{
				a = catStart;
				for (i=0; i<nObsStates; i++)
					{
					for (j=i+b*nObsStates; j<nStatesSquared; j+=nStates)
						preLikeL[a++] += tiPL[j];
					}
				}
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeL[a++] = 1.0;
			tiPL += nStatesSquared;
			}
		}

	/* find likelihoods of site patterns for right branch if terminal */
	if (p->right->left == NULL && m->isPartAmbig[p->right->index] == NO)
		{
		shortCut |= 2;
		rState = m->termState[p->right->index];
		tiPR = pR;
		for (k=a=0; k<m->numGammaCats; k++)
			{
			catStart = a;
			for (i=0; i<nObsStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeR[a++] = tiPR[j];
			for (b=1; b<nStates/nObsStates; b++)
				{
				a = catStart;
				for (i=0; i<nObsStates; i++)
					{
					for (j=i+b*nObsStates; j<nStatesSquared; j+=nStates)
						preLikeR[a++] += tiPR[j];
					}
				}
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeR[a++] = 1.0;
			tiPR += nStatesSquared;
			}
		}

	/* find likelihoods of site patterns for anc branch, always terminal */
	if (m->isPartAmbig[p->anc->index] == YES)
		{
		shortCut = 4;
		}
	else 
		{
		aState = m->termState[p->anc->index];
		tiPA = pA;
		for (k=a=0; k<m->numGammaCats; k++)
			{
			catStart = a;
			for (i=0; i<nObsStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeA[a++] = tiPA[j];
			for (b=1; b<nStates/nObsStates; b++)
				{
				a = catStart;
				for (i=0; i<nObsStates; i++)
					{
					for (j=i+b*nObsStates; j<nStatesSquared; j+=nStates)
						preLikeA[a++] += tiPA[j];
					}
				}
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeA[a++] = 1.0;
			tiPA += nStatesSquared;
			}
		}
#	else
	shortCut = 4;
#	endif

		switch (shortCut)
		{
		case 4:
			tiPL = pL;
			tiPR = pR;
			tiPA = pA;
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=0; c<m->numSSEChars; c++)
					{
					for (i=h=0; i<nStates; i++)
						{
						mAcumL = _mm_setzero_ps();
						mAcumR = _mm_setzero_ps();
						mAcumA = _mm_setzero_ps();
						for (j=0; j<nStates; j++)
							{
							mTiPL  = _mm_load1_ps (&tiPL[h]);
							mTiPR  = _mm_load1_ps (&tiPR[h]);
							mTiPA  = _mm_load1_ps (&tiPA[h++]);
							mL     = _mm_mul_ps (mTiPL, clL[j]);
							mR     = _mm_mul_ps (mTiPR, clR[j]);
							mA     = _mm_mul_ps (mTiPA, clA[j]);
							mAcumL = _mm_add_ps (mL, mAcumL);
							mAcumR = _mm_add_ps (mR, mAcumR);
							mAcumA = _mm_add_ps (mA, mAcumA);
							}
						mAcumL = _mm_mul_ps (mAcumL, mAcumR);
						*(clP++) = _mm_mul_ps (mAcumL, mAcumA);
						}
					clL += nStates;
					clR += nStates;
					clA += nStates;
					}
				tiPL += nStatesSquared;
				tiPR += nStatesSquared;
				tiPA += nStatesSquared;
				}
			break;
		case 0:
			tiPL =pL;
			tiPR =pR;
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=t=0; c<m->numSSEChars; c++)
					{
					for(c1=0; c1<FLOATS_PER_VEC; c1++,t++)
						{
						preLikeAV[c1] = &preLikeA[aState[t] + k*(preLikeJump+nStates)];
						}
					for (i=h=0; i<nStates; i++)
						{
						assert( FLOATS_PER_VEC == 4 ); /* In the following statment we assume that SSE register can hold exactly 4 ClFlts. */
						mAcumA = _mm_set_ps( *(preLikeAV[3]++), *(preLikeAV[2]++), *(preLikeAV[1]++), *(preLikeAV[0]++));
						mAcumL = _mm_setzero_ps();
						mAcumR = _mm_setzero_ps();
						for (j=0; j<nStates; j++)
							{
							mTiPL  = _mm_load1_ps (&tiPL[h]);
							mL     = _mm_mul_ps (mTiPL, clL[j]);
							mAcumL = _mm_add_ps (mL, mAcumL);
							mTiPR  = _mm_load1_ps (&tiPR[h++]);
							mR     = _mm_mul_ps (mTiPR, clR[j]);
							mAcumR = _mm_add_ps (mR, mAcumR);
							}
						mAcumL = _mm_mul_ps (mAcumL, mAcumR);
						*(clP++) = _mm_mul_ps (mAcumL, mAcumA);
						}
					clR += nStates;
					clL += nStates;
					}
				tiPL += nStatesSquared;
				tiPR += nStatesSquared;
				}
			break;
		case 1:
			tiPR = pR;
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=t=0; c<m->numSSEChars; c++)
					{
					for(c1=0; c1<FLOATS_PER_VEC; c1++,t++)
						{
						preLikeLV[c1] = &preLikeL[lState[t] + k*(preLikeJump+nStates)];
						preLikeAV[c1] = &preLikeA[aState[t] + k*(preLikeJump+nStates)];
						}
					for (i=h=0; i<nStates; i++)
						{
						assert( FLOATS_PER_VEC == 4 ); /* In the following statment we assume that SSE register can hold exactly 4 ClFlts. */
						mAcumL = _mm_set_ps( *(preLikeLV[3]++), *(preLikeLV[2]++), *(preLikeLV[1]++), *(preLikeLV[0]++));
						mAcumA = _mm_set_ps( *(preLikeAV[3]++), *(preLikeAV[2]++), *(preLikeAV[1]++), *(preLikeAV[0]++));
						mAcumR = _mm_setzero_ps();
						for (j=0; j<nStates; j++)
							{
							mTiPR  = _mm_load1_ps (&tiPR[h++]);
							mR     = _mm_mul_ps (mTiPR, clR[j]);
							mAcumR = _mm_add_ps (mR, mAcumR);
							}
						mAcumL = _mm_mul_ps (mAcumL, mAcumR);
						*(clP++) = _mm_mul_ps (mAcumL, mAcumA);
						}
					clR += nStates;
					}
				tiPR += nStatesSquared;
				}
			break;
		case 2:
			tiPL = pL;
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=t=0; c<m->numSSEChars; c++)
					{
					for(c1=0; c1<FLOATS_PER_VEC; c1++,t++)
						{
						preLikeRV[c1] = &preLikeR[rState[t] + k*(preLikeJump+nStates)];
						preLikeAV[c1] = &preLikeA[aState[t] + k*(preLikeJump+nStates)];
						}
					for (i=h=0; i<nStates; i++)
						{
						assert( FLOATS_PER_VEC == 4 ); /* In the following statment we assume that SSE register can hold exactly 4 ClFlts. */
						mAcumR = _mm_set_ps( *(preLikeRV[3]++), *(preLikeRV[2]++), *(preLikeRV[1]++), *(preLikeRV[0]++));
						mAcumA = _mm_set_ps( *(preLikeAV[3]++), *(preLikeAV[2]++), *(preLikeAV[1]++), *(preLikeAV[0]++));
						mAcumL = _mm_setzero_ps();
						for (j=0; j<nStates; j++)
							{
							mTiPL  = _mm_load1_ps (&tiPL[h++]);
							mL     = _mm_mul_ps (mTiPL, clL[j]);
							mAcumL = _mm_add_ps (mL, mAcumL);
							}
						mAcumL = _mm_mul_ps (mAcumL, mAcumR);
						*(clP++) = _mm_mul_ps (mAcumL,mAcumA);
						}
					clL += nStates;
					}
				tiPL += nStatesSquared;
				}
			break;
		case 3:
			for (k=0; k<m->numGammaCats; k++)
				{
				for (c=t=0; c<m->numSSEChars; c++)
					{
					for(c1=0; c1<FLOATS_PER_VEC; c1++,t++)
						{
						preLikeRV[c1] = &preLikeR[rState[t] + k*(preLikeJump+nStates)];
						preLikeLV[c1] = &preLikeL[lState[t] + k*(preLikeJump+nStates)];
						preLikeAV[c1] = &preLikeA[aState[t] + k*(preLikeJump+nStates)];
						}
					for (i=0; i<nStates; i++)
						{
						assert( FLOATS_PER_VEC == 4 ); /* In the following 2 statments we assume that SSE register can hold exactly 4 ClFlts. */
						mL = _mm_set_ps( *(preLikeLV[3]++), *(preLikeLV[2]++), *(preLikeLV[1]++), *(preLikeLV[0]++));
						mR = _mm_set_ps( *(preLikeRV[3]++), *(preLikeRV[2]++), *(preLikeRV[1]++), *(preLikeRV[0]++));
						mA = _mm_set_ps( *(preLikeAV[3]++), *(preLikeAV[2]++), *(preLikeAV[1]++), *(preLikeAV[0]++));
						mL = _mm_mul_ps (mL,mR);
						*(clP++) = _mm_mul_ps (mL,mA);
						}
					}
				}
			break;
		}

    return NO_ERROR;
}
#endif




/*----------------------------------------------------------------
|
|	CondLikeRoot_Gen_GibbsGamma: general n-state model with rate
|		variation modeled using a discrete gamma distribution with
|		Gibbs resampling of rate categories
|
-----------------------------------------------------------------*/
int CondLikeRoot_Gen_GibbsGamma (TreeNode *p, int division, int chain)

{

	int				a, b, c, i, j, r, *rateCat, shortCut, *lState=NULL,
					*rState=NULL, *aState=NULL, nObsStates, nStates,
					nStatesSquared, preLikeJump, nGammaCats;
	CLFlt			likeL, likeR, likeA, *clL, *clR, *clP, *clA, *pL, *pR, *pA,
					*tiPL, *tiPR, *tiPA;
	ModelInfo		*m;
#	if !defined (DEBUG_NOSHORTCUTS)
	int	k, catStart;
#endif
	
	/* find model settings for this division and nStates, nStatesSquared */
	m = &modelSettings[division];
	nObsStates = m->numStates;
	nStates = m->numModelStates;
	nStatesSquared = nStates * nStates;
	preLikeJump = nObsStates * nStates;

	/* flip conditional likelihood space */
	FlipCondLikeSpace (m, chain, p->index);

	/* find conditional likelihood pointers */
	clL = m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = m->condLikes[m->condLikeIndex[chain][p->right->index]];
    clP = m->condLikes[m->condLikeIndex[chain][p->index       ]];
    clA = m->condLikes[m->condLikeIndex[chain][p->anc->index  ]];

	/* find transition probabilities (or calculate instead) */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];
	pA = m->tiProbs[m->tiProbsIndex[chain][p->index       ]];

	/* find rate category index and number of gamma categories */
	rateCat = m->tiIndex + chain * m->numChars;
	nGammaCats = m->numGammaCats;

	/* find likelihoods of site patterns for left branch if terminal */
	shortCut = 0;
#	if !defined (DEBUG_NOSHORTCUTS)
	if (p->left->left == NULL && m->isPartAmbig[p->left->index] == NO)
		{
		shortCut |= 1;
		lState = m->termState[p->left->index];
		tiPL = pL;
		for (k=a=0; k<nGammaCats; k++)
			{
			catStart = a;
			for (i=0; i<nObsStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeL[a++] = tiPL[j];
			for (b=1; b<nStates/nObsStates; b++)
				{
				a = catStart;
				for (i=0; i<nObsStates; i++)
					{
					for (j=i+b*nObsStates; j<nStatesSquared; j+=nStates)
						preLikeL[a++] += tiPL[j];
					}
				}
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeL[a++] = 1.0;
			tiPL += nStatesSquared;
			}
		}

	/* find likelihoods of site patterns for right branch if terminal */
	if (p->right->left == NULL && m->isPartAmbig[p->right->index] == NO)
		{
		shortCut |= 2;
		rState = m->termState[p->right->index];
		tiPR = pR;
		for (k=a=0; k<nGammaCats; k++)
			{
			catStart = a;
			for (i=0; i<nObsStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeR[a++] = tiPR[j];
			for (b=1; b<nStates/nObsStates; b++)
				{
				a = catStart;
				for (i=0; i<nObsStates; i++)
					{
					for (j=i+b*nObsStates; j<nStatesSquared; j+=nStates)
						preLikeR[a++] += tiPR[j];
					}
				}
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeR[a++] = 1.0;
			tiPR += nStatesSquared;
			}
		}

	/* find likelihoods of site patterns for anc branch, always terminal */
	if (m->isPartAmbig[p->anc->index] == YES)
		{
		shortCut = 4;
		}
	else 
		{
		aState = m->termState[p->anc->index];
		tiPA = pA;
		for (k=a=0; k<nGammaCats; k++)
			{
			catStart = a;
			for (i=0; i<nObsStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeA[a++] = tiPA[j];
			for (b=1; b<nStates/nObsStates; b++)
				{
				a = catStart;
				for (i=0; i<nObsStates; i++)
					{
					for (j=i+b*nObsStates; j<nStatesSquared; j+=nStates)
						preLikeA[a++] += tiPA[j];
					}
				}
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeA[a++] = 1.0;
			tiPA += nStatesSquared;
			}
		}
#	else
	shortCut = 4;
#	endif

	switch (shortCut)
		{
	case 4:
		for (c=0; c<m->numChars; c++)
			{
			r = (*rateCat++);
			if (r < nGammaCats)
				{
				tiPL = pL + r*nStatesSquared;
				tiPR = pR + r*nStatesSquared;
				tiPA = pA + r*nStatesSquared;
				for (i=0; i<nStates; i++)
					{
					likeL = likeR = likeA = 0.0;
					for (j=0; j<nStates; j++)
						{
						likeL += (*tiPL++) * clL[j];
						likeR += (*tiPR++) * clR[j];
						likeA += (*tiPA++) * clA[j];
						}
					*(clP++) = likeL * likeR * likeA;
					}
				}
			else
				clP += nStates;
			clL += nStates;
			clR += nStates;
			clA += nStates;
			}
		break;
	case 0:
	case 3:
		for (c=0; c<m->numChars; c++)
			{
			r = (*rateCat++);
			if (r < nGammaCats)
				{
				tiPL = pL + r*nStatesSquared;
				tiPR = pR + r*nStatesSquared;
				a = aState[c] + r*(nStatesSquared+nStates);
				for (i=0; i<nStates; i++)
					{
					likeL = likeR = 0.0;
					for (j=0; j<nStates; j++)
						{
						likeL += (*tiPL++) * clL[j];
						likeR += (*tiPR++) * clR[j];
						}
					*(clP++) = likeL * likeR * preLikeA[a++];
					}
				}
			else
				clP += nStates;
			clL += nStates;
			clR += nStates;
			}
		break;
	case 1:
		for (c=0; c<m->numChars; c++)
			{
			r = (*rateCat++);
			if (r < nGammaCats)
				{
				tiPR = pR + r*nStatesSquared;
				a = lState[c] + r*(nStatesSquared+nStates);
				b = aState[c] + r*(nStatesSquared+nStates);
				for (i=0; i<nStates; i++)
					{
					likeR = 0.0;
					for (j=0; j<nStates; j++)
						{
						likeR += (*tiPR++) * clR[j];
						}
					*(clP++) = preLikeL[a++] * likeR * preLikeA[b++];
					}
				}
			else
				clP += nStates;
			clR += nStates;
			}
		break;
	case 2:
		for (c=0; c<m->numChars; c++)
			{
			r = (*rateCat++);
			if (r < nGammaCats)
				{
				tiPL = pL + r*nStatesSquared;
				a = rState[c] + r*(nStatesSquared+nStates);
				b = aState[c] + r*(nStatesSquared+nStates);
				for (i=0; i<nStates; i++)
					{
					likeL = 0.0;
					for (j=0; j<nStates; j++)
						{
						likeL += (*tiPL++) * clL[j];
						}
					*(clP++) = likeL * preLikeR[a++] * preLikeA[b++];
					}
				}
			else
				clP += nStates;
			clL += nStates;
			}
		break;
		}

	return NO_ERROR;
}





/*----------------------------------------------------------------
|
|	CondLikeRoot_NUC4: 4by4 nucleotide model with or without rate
|		variation
|
-----------------------------------------------------------------*/
int CondLikeRoot_NUC4 (TreeNode *p, int division, int chain)

{
	int				a, c, h, i, j, k, shortCut, *lState=NULL, *rState=NULL, *aState=NULL;
	CLFlt			*clL, *clR, *clP, *clA, *pL, *pR, *pA, *tiPL, *tiPR, *tiPA;
	ModelInfo		*m;
	
	m = &modelSettings[division];

	/* flip state of node so that we are not overwriting old cond likes */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = m->condLikes[m->condLikeIndex[chain][p->right->index]];
    clP = m->condLikes[m->condLikeIndex[chain][p->index       ]];
    clA = m->condLikes[m->condLikeIndex[chain][p->anc->index  ]];

	/* find transition probabilities (or calculate instead) */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];
	pA = m->tiProbs[m->tiProbsIndex[chain][p->index       ]];

	/* find likelihoods of site patterns for left branch if terminal */
	shortCut = 0;
#	if !defined (DEBUG_NOSHORTCUTS)
	if (p->left->left == NULL && m->isPartAmbig[p->left->index] == NO)
		{
		shortCut |= 1;
		lState = m->termState[p->left->index];
		tiPL = pL;
		for (k=j=0; k<m->numGammaCats; k++)
			{
			for (i=0; i<4; i++)
				{
				preLikeL[j++] = tiPL[0];
				preLikeL[j++] = tiPL[4];
				preLikeL[j++] = tiPL[8];
				preLikeL[j++] = tiPL[12];
				tiPL++;
				}
			/* for ambiguous */
			for (i=0; i<4; i++)
				preLikeL[j++] = 1.0;
			tiPL += 12;
			}
		}

	/* find likelihoods of site patterns for right branch if terminal */
	if (p->right->left == NULL && m->isPartAmbig[p->right->index] == NO)
		{
		shortCut |= 2;
		rState = m->termState[p->right->index];
		tiPR = pR;
		for (k=j=0; k<m->numGammaCats; k++)
			{
			for (i=0; i<4; i++)
				{
				preLikeR[j++] = tiPR[0];
				preLikeR[j++] = tiPR[4];
				preLikeR[j++] = tiPR[8];
				preLikeR[j++] = tiPR[12];
				tiPR++;
				}
			/* for ambiguous */
			for (i=0; i<4; i++)
				preLikeR[j++] = 1.0;
			tiPR += 12;
			}
		}

	/* find likelihoods of site patterns for anc branch, always terminal */
	if (m->isPartAmbig[p->anc->index] == YES)
		{
		shortCut = 4;
		}
	else 
		{
		aState = m->termState[p->anc->index];
		tiPA = pA;
		for (k=j=0; k<m->numGammaCats; k++)
			{
			for (i=0; i<4; i++)
				{
				preLikeA[j++] = tiPA[0];
				preLikeA[j++] = tiPA[4];
				preLikeA[j++] = tiPA[8];
				preLikeA[j++] = tiPA[12];
				tiPA++;
				}
			/* for ambiguous */
			for (i=0; i<4; i++)
				preLikeA[j++] = 1.0;
			tiPA += 12;
			}
		}
#	else
	shortCut = 4;
#	endif

	switch (shortCut)
		{
	case 4:
		tiPL = pL;
		tiPR = pR;
		tiPA = pA;
		for (k=h=0; k<m->numGammaCats; k++)
			{
		    for (c=0; c<m->numChars; c++)
			    {
				clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
							*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
							*(tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
				clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
							*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
							*(tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
				clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
							*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
							*(tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
				clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
							*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
							*(tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
				clL += 4;
				clR += 4;
				clA += 4;
				}
			tiPL += 16;
			tiPR += 16;
			tiPA += 16;
			}
		break;

	case 0:
		tiPL = pL;
		tiPR = pR;
		for (k=h=0; k<m->numGammaCats; k++)
			{
		    for (c=0; c<m->numChars; c++)
			    {
			    i = aState[c] + k*20;
				clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
							*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
							*preLikeA[i++];
				clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
							*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
							*preLikeA[i++];
				clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
							*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
							*preLikeA[i++];
				clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
							*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
							*preLikeA[i++];
				clL += 4;
				clR += 4;
				}
			tiPL += 16;
			tiPR += 16;
			}
		break;

	case 1:
		tiPR = pR;
		for (k=h=0; k<m->numGammaCats; k++)
			{
		    for (c=0; c<m->numChars; c++)
			    {
			    i = lState[c] + k*20;
			    j = aState[c] + k*20;
				clP[h++] =   (tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
							*preLikeL[i++]*preLikeA[j++];
				clP[h++] =   (tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
							*preLikeL[i++]*preLikeA[j++];
				clP[h++] =   (tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
							*preLikeL[i++]*preLikeA[j++];
				clP[h++] =   (tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
							*preLikeL[i++]*preLikeA[j++];
                clR += 4;
				}
			tiPR += 16;
			}
		break;

	case 2:
		tiPL = pL;
		for (k=h=0; k<m->numGammaCats; k++)
			{
		    for (c=0; c<m->numChars; c++)
			    {
			    i = rState[c] + k*20;
			    j = aState[c] + k*20;
				clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
							*preLikeR[i++]*preLikeA[j++];
				clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
							*preLikeR[i++]*preLikeA[j++];
				clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
							*preLikeR[i++]*preLikeA[j++];
				clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
							*preLikeR[i++]*preLikeA[j++];
				clL += 4;
				}
			tiPL += 16;
			}
		break;

	case 3:
		for (k=h=0; k<m->numGammaCats; k++)
			{
		    for (c=0; c<m->numChars; c++)
			    {
				a = lState[c] + k*20;
			    i = rState[c] + k*20;
			    j = aState[c] + k*20;
				clP[h++] =   preLikeL[a++]*preLikeR[i++]*preLikeA[j++];
				clP[h++] =   preLikeL[a++]*preLikeR[i++]*preLikeA[j++];
				clP[h++] =   preLikeL[a++]*preLikeR[i++]*preLikeA[j++];
				clP[h++] =   preLikeL[a++]*preLikeR[i++]*preLikeA[j++];
				}
			}
		break;
		}

	return NO_ERROR;
	
}





/*----------------------------------------------------------------
|
|	CondLikeRoot_NUC4_GibbsGamma: 4by4 nucleotide model with rate
|		variation approimated by Gibbs sampling from gamma
|
-----------------------------------------------------------------*/
int CondLikeRoot_NUC4_GibbsGamma (TreeNode *p, int division, int chain)

{
	int				c, h, i, j, r, *rateCat, shortCut, *lState=NULL, *rState=NULL, *aState=NULL,
					nGammaCats;
	CLFlt			*clL, *clR, *clP, *clA, *pL, *pR, *pA, *tiPL, *tiPR, *tiPA;
	ModelInfo		*m;
#	if !defined (DEBUG_NOSHORTCUTS)
	int	k;
#endif
	
	m = &modelSettings[division];

	/* flip conditional likelihood space */
	FlipCondLikeSpace (m, chain, p->index);

		/* find conditional likelihood pointers */
	clL = m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = m->condLikes[m->condLikeIndex[chain][p->right->index]];
    clP = m->condLikes[m->condLikeIndex[chain][p->index       ]];
    clA = m->condLikes[m->condLikeIndex[chain][p->anc->index  ]];

	/* find transition probabilities (or calculate instead) */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];
	pA = m->tiProbs[m->tiProbsIndex[chain][p->index       ]];

	/* find rate category index and number of gamma categories */
	rateCat = m->tiIndex + chain * m->numChars;
	nGammaCats = m->numGammaCats;

	/* find likelihoods of site patterns for left branch if terminal */
	shortCut = 0;
#	if !defined (DEBUG_NOSHORTCUTS)
	if (p->left->left == NULL && m->isPartAmbig[p->left->index] == NO)
		{
		shortCut |= 1;
		lState = m->termState[p->left->index];
		tiPL = pL;
		for (k=j=0; k<nGammaCats; k++)
			{
			for (i=0; i<4; i++)
				{
				preLikeL[j++] = tiPL[0];
				preLikeL[j++] = tiPL[4];
				preLikeL[j++] = tiPL[8];
				preLikeL[j++] = tiPL[12];
				tiPL++;
				}
			/* for ambiguous */
			for (i=0; i<4; i++)
				preLikeL[j++] = 1.0;
			tiPL += 12;
			}
		}

	/* find likelihoods of site patterns for right branch if terminal */
	if (p->right->left == NULL && m->isPartAmbig[p->right->index] == NO)
		{
		shortCut |= 2;
		rState = m->termState[p->right->index];
		tiPR = pR;
		for (k=j=0; k<nGammaCats; k++)
			{
			for (i=0; i<4; i++)
				{
				preLikeR[j++] = tiPR[0];
				preLikeR[j++] = tiPR[4];
				preLikeR[j++] = tiPR[8];
				preLikeR[j++] = tiPR[12];
				tiPR++;
				}
			/* for ambiguous */
			for (i=0; i<4; i++)
				preLikeR[j++] = 1.0;
			tiPR += 12;
			}
		}

	/* find likelihoods of site patterns for anc branch, always terminal */
	if (m->isPartAmbig[p->anc->index] == YES)
		{
		shortCut = 4;
		}
	else 
		{
		aState = m->termState[p->anc->index];
		tiPA = pA;
		for (k=j=0; k<nGammaCats; k++)
			{
			for (i=0; i<4; i++)
				{
				preLikeA[j++] = tiPA[0];
				preLikeA[j++] = tiPA[4];
				preLikeA[j++] = tiPA[8];
				preLikeA[j++] = tiPA[12];
				tiPA++;
				}
			/* for ambiguous */
			for (i=0; i<4; i++)
				preLikeA[j++] = 1.0;
			tiPA += 12;
			}
		}
#	else
	shortCut = 4;
#	endif

	switch (shortCut)
		{
	case 4:
		for (c=h=0; c<m->numChars; c++)
			{
			r = rateCat[c];
			if (r < nGammaCats)
				{
				tiPL = pL + r * 16;
				tiPR = pR + r * 16;
				tiPA = pA + r * 16;
				clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
							*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
							*(tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
				clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
							*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
							*(tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
				clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
							*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
							*(tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
				clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
							*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
							*(tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
				}
			else
				h += 4;
			clL += 4;
			clR += 4;
			clA += 4;
			}
		break;

	case 0:
	case 3:
		for (c=h=0; c<m->numChars; c++)
			{
			r = rateCat[c];
			if (r < nGammaCats)
				{
				tiPL = pL + r * 16;
				tiPR = pR + r * 16;
				i = aState[c] + r * 20;
				clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
							*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
							*preLikeA[i++];
				clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
							*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
							*preLikeA[i++];
				clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
							*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
							*preLikeA[i++];
				clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
							*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
							*preLikeA[i++];
				}
			else
				h += 4;
			clL += 4;
			clR += 4;
			}
		break;

	case 1:
		for (c=h=0; c<m->numChars; c++)
			{
			r = rateCat[c];
			if (r < nGammaCats)
				{
				tiPR = pR + r * 16;
				i = lState[c] + r * 20;
				j = aState[c] + r * 20;
				clP[h++] =   (tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
							*preLikeL[i++]*preLikeA[j++];
				clP[h++] =   (tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
							*preLikeL[i++]*preLikeA[j++];
				clP[h++] =   (tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
							*preLikeL[i++]*preLikeA[j++];
				clP[h++] =   (tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
							*preLikeL[i++]*preLikeA[j++];
				}
			else
				h += 4;
			clR += 4;
			}
		break;

	case 2:
		for (c=h=0; c<m->numChars; c++)
			{
			r = rateCat[c];
			if (r < nGammaCats)
				{
				tiPL = pL + r * 16;
				i = rState[c] + r * 20;
				j = aState[c] + r * 20;
				clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
							*preLikeR[i++]*preLikeA[j++];
				clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
							*preLikeR[i++]*preLikeA[j++];
				clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
							*preLikeR[i++]*preLikeA[j++];
				clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
							*preLikeR[i++]*preLikeA[j++];
				}
			else
				h += 4;
			clL += 4;
			}
		break;
		}

	return NO_ERROR;

}





#if defined (SSE_ENABLED)
/*----------------------------------------------------------------
|
|	CondLikeRoot_NUC4_SSE: 4by4 nucleotide model with or without rate
|		variation using SSE instructions
|
-----------------------------------------------------------------*/
int CondLikeRoot_NUC4_SSE (TreeNode *p, int division, int chain)

{
	int				c, k;
    CLFlt           *pL, *pR, *pA, *tiPL, *tiPR, *tiPA;
	__m128			*clL, *clR, *clP, *clA;
	__m128			m1, m2, m3, m4, m5, m6, m7, m8, m9;
	ModelInfo		*m;

	m = &modelSettings[division];

	/* flip state of node so that we are not overwriting old cond likes */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->left->index ]];
    clR = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->right->index]];
    clP = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->index       ]];
    clA = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->anc->index  ]];

	/* find transition probabilities */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
    pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];
    pA = m->tiProbs[m->tiProbsIndex[chain][p->index       ]];

	tiPL = pL;
	tiPR = pR;
	tiPA = pA;
	for (k=0; k<m->numGammaCats; k++)
		{
        for (c=0; c<m->numSSEChars; c++)
		    {
            m1 = _mm_load1_ps (&tiPL[AA]);
			m2 = _mm_load1_ps (&tiPR[AA]);
            m3 = _mm_load1_ps (&tiPA[AA]);
            m7 = _mm_mul_ps (m1, clL[A]);
            m8 = _mm_mul_ps (m2, clR[A]);
            m9 = _mm_mul_ps (m3, clA[A]);

            m1 = _mm_load1_ps (&tiPL[AC]);
			m2 = _mm_load1_ps (&tiPR[AC]);
            m3 = _mm_load1_ps (&tiPA[AC]);
            m4 = _mm_mul_ps (m1, clL[C]);
            m5 = _mm_mul_ps (m2, clR[C]);
            m6 = _mm_mul_ps (m3, clA[C]);
            m7 = _mm_add_ps (m4, m7);
            m8 = _mm_add_ps (m5, m8);
            m9 = _mm_add_ps (m6, m9);

            m1 = _mm_load1_ps (&tiPL[AG]);
			m2 = _mm_load1_ps (&tiPR[AG]);
            m3 = _mm_load1_ps (&tiPA[AG]);
            m4 = _mm_mul_ps (m1, clL[G]);
            m5 = _mm_mul_ps (m2, clR[G]);
            m6 = _mm_mul_ps (m3, clA[G]);
            m7 = _mm_add_ps (m4, m7);
            m8 = _mm_add_ps (m5, m8);
            m9 = _mm_add_ps (m6, m9);

            m1 = _mm_load1_ps (&tiPL[AT]);
			m2 = _mm_load1_ps (&tiPR[AT]);
            m3 = _mm_load1_ps (&tiPA[AT]);
            m4 = _mm_mul_ps (m1, clL[T]);
            m5 = _mm_mul_ps (m2, clR[T]);
            m6 = _mm_mul_ps (m3, clA[T]);
            m7 = _mm_add_ps (m4, m7);
            m8 = _mm_add_ps (m5, m8);
            m9 = _mm_add_ps (m6, m9);

            m7 = _mm_mul_ps (m7, m8);
            *clP++ = _mm_mul_ps (m7, m9);

            m1 = _mm_load1_ps (&tiPL[CA]);
			m2 = _mm_load1_ps (&tiPR[CA]);
            m3 = _mm_load1_ps (&tiPA[CA]);
            m7 = _mm_mul_ps (m1, clL[A]);
            m8 = _mm_mul_ps (m2, clR[A]);
            m9 = _mm_mul_ps (m3, clA[A]);

            m1 = _mm_load1_ps (&tiPL[CC]);
			m2 = _mm_load1_ps (&tiPR[CC]);
            m3 = _mm_load1_ps (&tiPA[CC]);
            m4 = _mm_mul_ps (m1, clL[C]);
            m5 = _mm_mul_ps (m2, clR[C]);
            m6 = _mm_mul_ps (m3, clA[C]);
            m7 = _mm_add_ps (m4, m7);
            m8 = _mm_add_ps (m5, m8);
            m9 = _mm_add_ps (m6, m9);

            m1 = _mm_load1_ps (&tiPL[CG]);
			m2 = _mm_load1_ps (&tiPR[CG]);
            m3 = _mm_load1_ps (&tiPA[CG]);
            m4 = _mm_mul_ps (m1, clL[G]);
            m5 = _mm_mul_ps (m2, clR[G]);
            m6 = _mm_mul_ps (m3, clA[G]);
            m7 = _mm_add_ps (m4, m7);
            m8 = _mm_add_ps (m5, m8);
            m9 = _mm_add_ps (m6, m9);

            m1 = _mm_load1_ps (&tiPL[CT]);
			m2 = _mm_load1_ps (&tiPR[CT]);
            m3 = _mm_load1_ps (&tiPA[CT]);
            m4 = _mm_mul_ps (m1, clL[T]);
            m5 = _mm_mul_ps (m2, clR[T]);
            m6 = _mm_mul_ps (m3, clA[T]);
            m7 = _mm_add_ps (m4, m7);
            m8 = _mm_add_ps (m5, m8);
            m9 = _mm_add_ps (m6, m9);

            m7 = _mm_mul_ps (m7, m8);
            *clP++ = _mm_mul_ps (m7, m9);

            m1 = _mm_load1_ps (&tiPL[GA]);
			m2 = _mm_load1_ps (&tiPR[GA]);
            m3 = _mm_load1_ps (&tiPA[GA]);
            m7 = _mm_mul_ps (m1, clL[A]);
            m8 = _mm_mul_ps (m2, clR[A]);
            m9 = _mm_mul_ps (m3, clA[A]);

            m1 = _mm_load1_ps (&tiPL[GC]);
			m2 = _mm_load1_ps (&tiPR[GC]);
            m3 = _mm_load1_ps (&tiPA[GC]);
            m4 = _mm_mul_ps (m1, clL[C]);
            m5 = _mm_mul_ps (m2, clR[C]);
            m6 = _mm_mul_ps (m3, clA[C]);
            m7 = _mm_add_ps (m4, m7);
            m8 = _mm_add_ps (m5, m8);
            m9 = _mm_add_ps (m6, m9);

            m1 = _mm_load1_ps (&tiPL[GG]);
			m2 = _mm_load1_ps (&tiPR[GG]);
            m3 = _mm_load1_ps (&tiPA[GG]);
            m4 = _mm_mul_ps (m1, clL[G]);
            m5 = _mm_mul_ps (m2, clR[G]);
            m6 = _mm_mul_ps (m3, clA[G]);
            m7 = _mm_add_ps (m4, m7);
            m8 = _mm_add_ps (m5, m8);
            m9 = _mm_add_ps (m6, m9);

            m1 = _mm_load1_ps (&tiPL[GT]);
			m2 = _mm_load1_ps (&tiPR[GT]);
            m3 = _mm_load1_ps (&tiPA[GT]);
            m4 = _mm_mul_ps (m1, clL[T]);
            m5 = _mm_mul_ps (m2, clR[T]);
            m6 = _mm_mul_ps (m3, clA[T]);
            m7 = _mm_add_ps (m4, m7);
            m8 = _mm_add_ps (m5, m8);
            m9 = _mm_add_ps (m6, m9);

            m7 = _mm_mul_ps (m7, m8);
            *clP++ = _mm_mul_ps (m7, m9);

            m1 = _mm_load1_ps (&tiPL[TA]);
			m2 = _mm_load1_ps (&tiPR[TA]);
            m3 = _mm_load1_ps (&tiPA[TA]);
            m7 = _mm_mul_ps (m1, clL[A]);
            m8 = _mm_mul_ps (m2, clR[A]);
            m9 = _mm_mul_ps (m3, clA[A]);

            m1 = _mm_load1_ps (&tiPL[TC]);
			m2 = _mm_load1_ps (&tiPR[TC]);
            m3 = _mm_load1_ps (&tiPA[TC]);
            m4 = _mm_mul_ps (m1, clL[C]);
            m5 = _mm_mul_ps (m2, clR[C]);
            m6 = _mm_mul_ps (m3, clA[C]);
            m7 = _mm_add_ps (m4, m7);
            m8 = _mm_add_ps (m5, m8);
            m9 = _mm_add_ps (m6, m9);

            m1 = _mm_load1_ps (&tiPL[TG]);
			m2 = _mm_load1_ps (&tiPR[TG]);
            m3 = _mm_load1_ps (&tiPA[TG]);
            m4 = _mm_mul_ps (m1, clL[G]);
            m5 = _mm_mul_ps (m2, clR[G]);
            m6 = _mm_mul_ps (m3, clA[G]);
            m7 = _mm_add_ps (m4, m7);
            m8 = _mm_add_ps (m5, m8);
            m9 = _mm_add_ps (m6, m9);

            m1 = _mm_load1_ps (&tiPL[TT]);
			m2 = _mm_load1_ps (&tiPR[TT]);
            m3 = _mm_load1_ps (&tiPA[TT]);
            m4 = _mm_mul_ps (m1, clL[T]);
            m5 = _mm_mul_ps (m2, clR[T]);
            m6 = _mm_mul_ps (m3, clA[T]);
            m7 = _mm_add_ps (m4, m7);
            m8 = _mm_add_ps (m5, m8);
            m9 = _mm_add_ps (m6, m9);

            m7 = _mm_mul_ps (m7, m8);
            *clP++ = _mm_mul_ps (m7, m9);

            clL += 4;
			clR += 4;
			clA += 4;
			}
        tiPL += 16;
        tiPR += 16;
        tiPA += 16;
		}

	return NO_ERROR;
	
}
#endif




#if !defined (SSE_ENABLED)|| 1
/*----------------------------------------------------------------
|
|	CondLikeRoot_NY98: codon model with omega variation
|
-----------------------------------------------------------------*/
int CondLikeRoot_NY98 (TreeNode *p, int division, int chain)

{

	int				a, b, c, d, h, i, j, k, shortCut, *lState=NULL, *rState=NULL, *aState=NULL,
					nStates, nStatesSquared;
	CLFlt			likeL, likeR, likeA, *clL, *clR, *clP, *clA, *pL, *pR, *pA,
					*tiPL, *tiPR, *tiPA;
	ModelInfo		*m;
	
	/* find model settings for this division and nStates, nStatesSquared */
	m = &modelSettings[division];
	nStates = m->numModelStates;
	nStatesSquared = nStates * nStates;

	/* flip state of node so that we are not overwriting old cond likes */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = m->condLikes[m->condLikeIndex[chain][p->right->index]];
    clP = m->condLikes[m->condLikeIndex[chain][p->index       ]];
    clA = m->condLikes[m->condLikeIndex[chain][p->anc->index  ]];

	/* find transition probabilities (or calculate instead) */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];
	pA = m->tiProbs[m->tiProbsIndex[chain][p->index       ]];


	/* find likelihoods of site patterns for left branch if terminal */
	shortCut = 0;
#	if !defined (DEBUG_NOSHORTCUTS)
	if (p->left->left == NULL && m->isPartAmbig[p->left->index] == NO)
		{
		shortCut |= 1;
		lState = m->termState[p->left->index];
		tiPL = pL;
		for (k=a=0; k<m->numOmegaCats; k++)
			{
			for (i=0; i<nStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeL[a++] = tiPL[j];
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeL[a++] = 1.0;
			tiPL += nStatesSquared;
			}
		}

	/* find likelihoods of site patterns for right branch if terminal */
	if (p->right->left == NULL && m->isPartAmbig[p->right->index] == NO)
		{
		shortCut |= 2;
		rState = m->termState[p->right->index];
		tiPR = pR;
		for (k=a=0; k<m->numOmegaCats; k++)
			{
			for (i=0; i<nStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeR[a++] = tiPR[j];
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeR[a++] = 1.0;
			tiPR += nStatesSquared;
			}
		}

	/* find likelihoods of site patterns for anc branch, always terminal */
	if (m->isPartAmbig[p->anc->index] == YES)
		{
		shortCut = 4;
		}
	else 
		{
		aState = m->termState[p->anc->index];
		tiPA = pA;
		for (k=a=0; k<m->numOmegaCats; k++)
			{
			for (i=0; i<nStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeA[a++] = tiPA[j];
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeA[a++] = 1.0;
			tiPA += nStatesSquared;
			}
		}
#	else
	shortCut = 4;
#	endif

		switch (shortCut)
		{
		case 4:
			tiPL = pL;
			tiPR = pR;
			tiPA = pA;
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					for (i=h=0; i<nStates; i++)
						{
						likeL = likeR = likeA = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeA += tiPA[h]*clA[j];
							likeL += tiPL[h]*clL[j];
							likeR += tiPR[h++]*clR[j];
							}
						*(clP++) = likeL * likeR * likeA;
						}
					clL += nStates;
					clR += nStates;
					clA += nStates;
					}
				tiPL += nStatesSquared;
				tiPR += nStatesSquared;
				tiPA += nStatesSquared;
				}
			break;
		case 0:
			tiPR = pR;
			tiPL = pL;
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					b = aState[c] + k*(nStatesSquared+nStates);
					for (i=h=0; i<nStates; i++)
						{
						likeR = likeL = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeR += tiPR[h]*clR[j];
							likeL += tiPL[h++]*clL[j];
							}
						*(clP++) =  preLikeA[b++] * likeL * likeR;
						}
					clR += nStates;
					clL += nStates;
					}
				tiPR += nStatesSquared;
				tiPL += nStatesSquared;
				}
			break;
		case 1:
			tiPR = pR;
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					a = lState[c] + k*(nStatesSquared+nStates);
					b = aState[c] + k*(nStatesSquared+nStates);
					for (i=h=0; i<nStates; i++)
						{
						likeR = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeR += tiPR[h++]*clR[j];
							}
						*(clP++) = preLikeL[a++] * preLikeA[b++] * likeR;
						}
					clR += nStates;
					}
				tiPR += nStatesSquared;
				}
			break;
		case 2:
			tiPL = pL;
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					a = rState[c] + k*(nStatesSquared+nStates);
					b = aState[c] + k*(nStatesSquared+nStates);
					for (i=h=0; i<nStates; i++)
						{
						likeL = 0.0;
						for (j=0; j<nStates; j++)
							{
							likeL += tiPL[h++]*clL[j];
							}
						*(clP++) = preLikeR[a++] * preLikeA[b++] * likeL;
						}
					clL += nStates;
					}
				tiPL += nStatesSquared;
				}
			break;
		case 3:
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=0; c<m->numChars; c++)
					{
					a = rState[c] + k*(nStatesSquared+nStates);
					b = lState[c] + k*(nStatesSquared+nStates);
					d = aState[c] + k*(nStatesSquared+nStates);
					for (i=0; i<nStates; i++)
						{
						*(clP++) = preLikeR[a++] * preLikeL[b++] * preLikeA[d++];
						}
					}
				}
			break;
		}

	return NO_ERROR;
}
#endif





#if defined (SSE_ENABLED)
/*----------------------------------------------------------------
|
|	CondLikeRoot_NY98_SSE: codon model with omega variation
|
-----------------------------------------------------------------*/
int CondLikeRoot_NY98_SSE (TreeNode *p, int division, int chain)

{

	int				c, c1, t, h, i, j, k, shortCut, *lState=NULL, *rState=NULL, *aState=NULL,
					nStates, nStatesSquared;
	CLFlt			*pL, *pR, *pA,
					*tiPL, *tiPR, *tiPA;
	__m128			*clL, *clR, *clP, *clA;
	__m128			mTiPL, mTiPR, mTiPA, mL, mR, mA, mAcumL, mAcumR, mAcumA;
	ModelInfo		*m;
	CLFlt			*preLikeRV[FLOATS_PER_VEC];
	CLFlt			*preLikeLV[FLOATS_PER_VEC];
	CLFlt			*preLikeAV[FLOATS_PER_VEC];

#	if !defined (DEBUG_NOSHORTCUTS)
	int             a;

#endif


	/* find model settings for this division and nStates, nStatesSquared */
	m = &modelSettings[division];
	nStates = m->numModelStates;
	nStatesSquared = nStates * nStates;

	/* flip state of node so that we are not overwriting old cond likes */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = (__m128 *)m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = (__m128 *)m->condLikes[m->condLikeIndex[chain][p->right->index]];
    clP = (__m128 *)m->condLikes[m->condLikeIndex[chain][p->index       ]];
    clA = (__m128 *)m->condLikes[m->condLikeIndex[chain][p->anc->index  ]];

	/* find transition probabilities (or calculate instead) */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];
	pA = m->tiProbs[m->tiProbsIndex[chain][p->index       ]];


	/* find likelihoods of site patterns for left branch if terminal */
	shortCut = 0;
#	if !defined (DEBUG_NOSHORTCUTS)
	if (p->left->left == NULL && m->isPartAmbig[p->left->index] == NO)
		{
		shortCut |= 1;
		lState = m->termState[p->left->index];
		tiPL = pL;
		for (k=a=0; k<m->numOmegaCats; k++)
			{
			for (i=0; i<nStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeL[a++] = tiPL[j];
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeL[a++] = 1.0;
			tiPL += nStatesSquared;
			}
		}

	/* find likelihoods of site patterns for right branch if terminal */
	if (p->right->left == NULL && m->isPartAmbig[p->right->index] == NO)
		{
		shortCut |= 2;
		rState = m->termState[p->right->index];
		tiPR = pR;
		for (k=a=0; k<m->numOmegaCats; k++)
			{
			for (i=0; i<nStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeR[a++] = tiPR[j];
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeR[a++] = 1.0;
			tiPR += nStatesSquared;
			}
		}

	/* find likelihoods of site patterns for anc branch, always terminal */
	if (m->isPartAmbig[p->anc->index] == YES)
		{
		shortCut = 4;
		}
	else 
		{
		aState = m->termState[p->anc->index];
		tiPA = pA;
		for (k=a=0; k<m->numOmegaCats; k++)
			{
			for (i=0; i<nStates; i++)
				for (j=i; j<nStatesSquared; j+=nStates)
					preLikeA[a++] = tiPA[j];
			/* for ambiguous */
			for (i=0; i<nStates; i++)
				preLikeA[a++] = 1.0;
			tiPA += nStatesSquared;
			}
		}
#	else
	shortCut = 4;
#	endif
		switch (shortCut)
		{
		case 4:
			tiPL = pL;
			tiPR = pR;
			tiPA = pA;
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=0; c<m->numSSEChars; c++)
					{
					for (i=h=0; i<nStates; i++)
						{
						mAcumL = _mm_setzero_ps();
						mAcumR = _mm_setzero_ps();
						mAcumA = _mm_setzero_ps();
						for (j=0; j<nStates; j++)
							{
							mTiPL  = _mm_load1_ps (&tiPL[h]);
							mTiPR  = _mm_load1_ps (&tiPR[h]);
							mTiPA  = _mm_load1_ps (&tiPA[h++]);
							mL     = _mm_mul_ps (mTiPL, clL[j]);
							mR     = _mm_mul_ps (mTiPR, clR[j]);
							mA     = _mm_mul_ps (mTiPA, clA[j]);
							mAcumL = _mm_add_ps (mL, mAcumL);
							mAcumR = _mm_add_ps (mR, mAcumR);
							mAcumA = _mm_add_ps (mA, mAcumA);
							}
						mAcumL = _mm_mul_ps (mAcumL, mAcumR);
						*(clP++) = _mm_mul_ps (mAcumL, mAcumA);
						}
					clL += nStates;
					clR += nStates;
					clA += nStates;
					}
				tiPL += nStatesSquared;
				tiPR += nStatesSquared;
				tiPA += nStatesSquared;
				}
			break;
		case 0:
			tiPL =pL;
			tiPR =pR;
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=t=0; c<m->numSSEChars; c++)
					{
					for(c1=0; c1<FLOATS_PER_VEC; c1++,t++)
						{
						preLikeAV[c1] = &preLikeA[aState[t] + k*(nStatesSquared+nStates)];
						}
					for (i=h=0; i<nStates; i++)
						{
						assert( FLOATS_PER_VEC == 4 ); /* In the following statment we assume that SSE register can hold exactly 4 ClFlts. */
						mAcumA = _mm_set_ps( *(preLikeAV[3]++), *(preLikeAV[2]++), *(preLikeAV[1]++), *(preLikeAV[0]++));
						mAcumL = _mm_setzero_ps();
						mAcumR = _mm_setzero_ps();
						for (j=0; j<nStates; j++)
							{
							mTiPL  = _mm_load1_ps (&tiPL[h]);
							mL     = _mm_mul_ps (mTiPL, clL[j]);
							mAcumL = _mm_add_ps (mL, mAcumL);
							mTiPR  = _mm_load1_ps (&tiPR[h++]);
							mR     = _mm_mul_ps (mTiPR, clR[j]);
							mAcumR = _mm_add_ps (mR, mAcumR);
							}
						mAcumL = _mm_mul_ps (mAcumL, mAcumR);
						*(clP++) = _mm_mul_ps (mAcumL, mAcumA);
						}
					clR += nStates;
					clL += nStates;
					}
				tiPL += nStatesSquared;
				tiPR += nStatesSquared;
				}
			break;
		case 1:
			tiPR = pR;
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=t=0; c<m->numSSEChars; c++)
					{
					for(c1=0; c1<FLOATS_PER_VEC; c1++,t++)
						{
						preLikeLV[c1] = &preLikeL[lState[t] + k*(nStatesSquared+nStates)];
						preLikeAV[c1] = &preLikeA[aState[t] + k*(nStatesSquared+nStates)];
						}
					for (i=h=0; i<nStates; i++)
						{
						assert( FLOATS_PER_VEC == 4 ); /* In the following statment we assume that SSE register can hold exactly 4 ClFlts. */
						mAcumL = _mm_set_ps( *(preLikeLV[3]++), *(preLikeLV[2]++), *(preLikeLV[1]++), *(preLikeLV[0]++));
						mAcumA = _mm_set_ps( *(preLikeAV[3]++), *(preLikeAV[2]++), *(preLikeAV[1]++), *(preLikeAV[0]++));
						mAcumR = _mm_setzero_ps();
						for (j=0; j<nStates; j++)
							{
							mTiPR  = _mm_load1_ps (&tiPR[h++]);
							mR     = _mm_mul_ps (mTiPR, clR[j]);
							mAcumR = _mm_add_ps (mR, mAcumR);
							}
						mAcumL = _mm_mul_ps (mAcumL, mAcumR);
						*(clP++) = _mm_mul_ps (mAcumL, mAcumA);
						}
					clR += nStates;
					}
				tiPR += nStatesSquared;
				}
			break;
		case 2:
			tiPL = pL;
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=t=0; c<m->numSSEChars; c++)
					{
					for(c1=0; c1<FLOATS_PER_VEC; c1++,t++)
						{
						preLikeRV[c1] = &preLikeR[rState[t] + k*(nStatesSquared+nStates)];
						preLikeAV[c1] = &preLikeA[aState[t] + k*(nStatesSquared+nStates)];
						}
					for (i=h=0; i<nStates; i++)
						{
						assert( FLOATS_PER_VEC == 4 ); /* In the following statment we assume that SSE register can hold exactly 4 ClFlts. */
						mAcumR = _mm_set_ps( *(preLikeRV[3]++), *(preLikeRV[2]++), *(preLikeRV[1]++), *(preLikeRV[0]++));
						mAcumA = _mm_set_ps( *(preLikeAV[3]++), *(preLikeAV[2]++), *(preLikeAV[1]++), *(preLikeAV[0]++));
						mAcumL = _mm_setzero_ps();
						for (j=0; j<nStates; j++)
							{
							mTiPL  = _mm_load1_ps (&tiPL[h++]);
							mL     = _mm_mul_ps (mTiPL, clL[j]);
							mAcumL = _mm_add_ps (mL, mAcumL);
							}
						mAcumL = _mm_mul_ps (mAcumL, mAcumR);
						*(clP++) = _mm_mul_ps (mAcumL,mAcumA);
						}
					clL += nStates;
					}
				tiPL += nStatesSquared;
				}
			break;
		case 3:
			for (k=0; k<m->numOmegaCats; k++)
				{
				for (c=t=0; c<m->numSSEChars; c++)
					{
					for(c1=0; c1<FLOATS_PER_VEC; c1++,t++)
						{
						preLikeRV[c1] = &preLikeR[rState[t] + k*(nStatesSquared+nStates)];
						preLikeLV[c1] = &preLikeL[lState[t] + k*(nStatesSquared+nStates)];
						preLikeAV[c1] = &preLikeA[aState[t] + k*(nStatesSquared+nStates)];
						}
					for (i=0; i<nStates; i++)
						{
						assert( FLOATS_PER_VEC == 4 ); /* In the following 2 statments we assume that SSE register can hold exactly 4 ClFlts. */
						mL = _mm_set_ps( *(preLikeLV[3]++), *(preLikeLV[2]++), *(preLikeLV[1]++), *(preLikeLV[0]++));
						mR = _mm_set_ps( *(preLikeRV[3]++), *(preLikeRV[2]++), *(preLikeRV[1]++), *(preLikeRV[0]++));
						mA = _mm_set_ps( *(preLikeAV[3]++), *(preLikeAV[2]++), *(preLikeAV[1]++), *(preLikeAV[0]++));
						mL = _mm_mul_ps (mL,mR);
						*(clP++) = _mm_mul_ps (mL,mA);
						}
					}
				}
			break;
		}

	return NO_ERROR;
}
#endif




/*----------------------------------------------------------------
|
|	CondLikeRoot_Std: variable number of states model
|		with or without rate variation
|
-----------------------------------------------------------------*/
int CondLikeRoot_Std (TreeNode *p, int division, int chain)

{

	int				a, c, h, i, j, k, nStates=0, nCats=0, tmp;
	CLFlt			*clL, *clR, *clP, *clA, *pL, *pR, *pA, *tiPL, *tiPR, *tiPA,
					likeL, likeR, likeA;
	ModelInfo		*m;
	
	m = &modelSettings[division];

	/* flip state of node so that we are not overwriting old cond likes */
	FlipCondLikeSpace (m, chain, p->index);
	
	/* find conditional likelihood pointers */
	clL = m->condLikes[m->condLikeIndex[chain][p->left->index ]];
	clR = m->condLikes[m->condLikeIndex[chain][p->right->index]];
    clP = m->condLikes[m->condLikeIndex[chain][p->index       ]];
    clA = m->condLikes[m->condLikeIndex[chain][p->anc->index  ]];

	/* find transition probabilities (or calculate instead) */
	pL = m->tiProbs[m->tiProbsIndex[chain][p->left->index ]];
	pR = m->tiProbs[m->tiProbsIndex[chain][p->right->index]];
	pA = m->tiProbs[m->tiProbsIndex[chain][p->index       ]];

	/* calculate ancestral probabilities */
	for (k=h=0; k<m->numGammaCats; k++)
		{
		/* calculate ancestral probabilities */
		for (c=0; c<m->numChars; c++)
			{
			nStates = m->nStates[c];
		
			/* the following lines ensure that nCats is 1 unless */
			/* the character is binary and beta categories are used  */
			if (nStates == 2)
				nCats = m->numBetaCats;
			else
				nCats = 1;

			tmp = k*nStates*nStates; /* tmp contains offset to skip gamma cats that already processed*/
			tiPL = pL + m->tiIndex[c] + tmp;
			tiPR = pR + m->tiIndex[c] + tmp;
			tiPA = pA + m->tiIndex[c] + tmp;
			tmp = (m->numGammaCats-1)*2*2; /* tmp contains size of block of tpi matrices across all gamma cats (minus one) for single beta category. Further used only if character is binary to jump to next beta category */
				
			for(j=0; j<nCats;j++)
				{
				for (a=0; a<nStates; a++)
					{
					likeL = likeR = likeA = 0.0;
					for (i=0; i<nStates; i++)
						{
						likeL += *(tiPL++) * clL[i];
						likeR += *(tiPR++) * clR[i];
						likeA += *(tiPA++) * clA[i];
						}
	                clP[h++] = likeL * likeR * likeA;
					}
				clL += nStates;
				clR += nStates;
				clA += nStates;
		
				tiPL += tmp;
				tiPR += tmp;
				tiPA += tmp;
				}
            }
		}

	return NO_ERROR;
}




/*----------------------------------------------------------------
|
|	CondLikeUp_Bin: pull likelihoods up and calculate scaled
|		finals, binary model with or without rate variation
|
-----------------------------------------------------------------*/
int CondLikeUp_Bin (TreeNode *p, int division, int chain)

{

	int				c, k;
	CLFlt			*clFA, *clFP, *clDP, *tiP, condLikeUp[2], sum[2];
	ModelInfo		*m;
	
	/* find model settings for this division */
	m = &modelSettings[division];

	if (p->anc->anc == NULL)
		{
		/* this is the root node */
		/* find conditional likelihood pointers = down cond likes */
		/* use conditional likelihood scratch space for final cond likes */
		clDP = m->condLikes[m->condLikeIndex[chain][p->index]];
        clFP = m->condLikes[m->condLikeScratchIndex[p->index]];

		for (k=0; k<m->numGammaCats; k++)
			{
			for (c=0; c<m->numChars; c++)
				{
				*(clFP++) = *(clDP++);
				*(clFP++) = *(clDP++);
				}
			}
		}
	else
		{
		/* find conditional likelihood pointers */
		/* use conditional likelihood scratch space for final cond likes */
        clFA = m->condLikes[m->condLikeScratchIndex[p->anc->index]];
		clFP = m->condLikes[m->condLikeScratchIndex[p->index     ]];
		clDP = m->condLikes[m->condLikeIndex[chain][p->index     ]];
        
		/* find transition probabilities */
		tiP = m->tiProbs[m->tiProbsIndex[chain][p->index]];

		for (k=0; k<m->numGammaCats; k++)
			{
			for (c=0; c<m->numChars; c++)
				{
                condLikeUp[0] = condLikeUp[1] = 0.0;
                
                sum[0] = tiP[0]*clDP[0] + tiP[1]*clDP[1];
                sum[1] = tiP[2]*clDP[0] + tiP[3]*clDP[1];

                if (sum[0] != 0.0) condLikeUp[0] = clFA[0] / sum[0];
				if (sum[1] != 0.0) condLikeUp[1] = clFA[1] / sum[1];
				
                *(clFP++) = (condLikeUp[0]*tiP[0] + condLikeUp[1]*tiP[1])*clDP[0];
				*(clFP++) = (condLikeUp[0]*tiP[2] + condLikeUp[1]*tiP[3])*clDP[1];
				
				clFA += 2;
				clDP += 2;
				}
            tiP += 4;
			}
		}	

	return NO_ERROR;
	
}




/*----------------------------------------------------------------
|
|	CondLikeUp_Gen: pull likelihoods up and calculate scaled
|		finals for an interior node
|
-----------------------------------------------------------------*/
int CondLikeUp_Gen (TreeNode *p, int division, int chain)

{

	int				a, c, i, j, k, nStates, nStatesSquared, nGammaCats;
	CLFlt			*clFA, *clFP, *clDP, *tiP, *condLikeUp, sum;
	ModelInfo		*m;
	
	/* find model settings for this division */
	m = &modelSettings[division];

	/* find number of states in the model */
	nStates = m->numModelStates;
	nStatesSquared = nStates * nStates;

	/* find number of gamma cats */
	nGammaCats = m->numGammaCats;
	if (m->gibbsGamma == YES)
		nGammaCats = 1;

	/* use preallocated scratch space */
	condLikeUp = m->ancStateCondLikes;

	/* calculate final states */
	if (p->anc->anc == NULL)
		{
		/* this is the root node */
		/* find conditional likelihood pointers = down cond likes */
		/* use conditional likelihood scratch space for final cond likes */
		clDP = m->condLikes[m->condLikeIndex[chain][p->index]];
		clFP = m->condLikes[m->condLikeScratchIndex[p->index]];
        
		/* final cond likes = downpass cond likes */
        for (k=0; k<nGammaCats; k++)
			{
			/* copy cond likes */ 
			for (c=0; c<m->numChars*nStates; c++)
				*(clFP++) = *(clDP++);
			}
		}
	else
		{
		/* find conditional likelihood pointers */
		/* use conditional likelihood scratch space for final cond likes */
		clFA = m->condLikes[m->condLikeScratchIndex[p->anc->index]];
        clFP = m->condLikes[m->condLikeScratchIndex[p->index     ]];
        clDP = m->condLikes[m->condLikeIndex[chain][p->index     ]];
        
		/* find transition probabilities */
		tiP = m->tiProbs[m->tiProbsIndex[chain][p->index]];
        
        for (k=0; k<nGammaCats; k++)
			{
			for (c=0; c<m->numChars; c++)
				{
				for (a=j=0; a<nStates; a++)
					{
					sum = 0.0; // Also was here??? condLikeUp[A] = 0.0
					for (i=0; i<nStates; i++)
						sum += tiP[j++]*clDP[i];
                    if (sum != 0.0) condLikeUp[a] = clFA[a] / sum;
					}
					
				for (a=j=0; a<nStates; a++)
					{
					sum = 0.0;
					for (i=0; i<nStates; i++)
						{
						sum += condLikeUp[i] * tiP[j++];
						}
					*(clFP++) = sum * clDP[a];
					}

				clFA += nStates;
				clDP += nStates;
				}
            tiP += nStatesSquared;
			}
		}	

	return NO_ERROR;
}




/*----------------------------------------------------------------
|
|	CondLikeUp_NUC4: pull likelihoods up and calculate scaled
|		finals for an interior node
|
-----------------------------------------------------------------*/
int     CondLikeUp_NUC4 (TreeNode *p, int division, int chain)

{

	int				c, k, nGammaCats;
	CLFlt			*clFA, *clFP, *clDP, *tiP, condLikeUp[4], sum[4];
	ModelInfo		*m;
	
	/* find model settings for this division */
	m = &modelSettings[division];

	/* find number of gamma cats */
	nGammaCats = m->numGammaCats;
	if (m->gibbsGamma == YES)
		nGammaCats = 1;

	/* calculate final states */
	if (p->anc->anc == NULL)
		{
		/* this is the root node */
		/* find conditional likelihood pointers = down cond likes */
		/* use conditional likelihood scratch space for final cond likes */
		clDP = m->condLikes[m->condLikeIndex[chain][p->index]];
		clFP = m->condLikes[m->condLikeScratchIndex[p->index]];
        
		/* final cond likes = downpass cond likes */
		for (k=0; k<nGammaCats; k++)
			{
			/* copy cond likes */ 
			for (c=0; c<m->numChars; c++)
				{
				*(clFP++) = *(clDP++);
				*(clFP++) = *(clDP++);
				*(clFP++) = *(clDP++);
				*(clFP++) = *(clDP++);
				}
			}
		}
	else
		{
		/* find conditional likelihood pointers */
		/* use conditional likelihood scratch space for final cond likes */
        clFA = m->condLikes[m->condLikeScratchIndex[p->anc->index]];
        clFP = m->condLikes[m->condLikeScratchIndex[p->index     ]];
        clDP = m->condLikes[m->condLikeIndex[chain][p->index     ]];
        
		/* find transition probabilities */
		tiP = m->tiProbs[m->tiProbsIndex[chain][p->index]];
        
		for (k=0; k<nGammaCats; k++)
			{
			for (c=0; c<m->numChars; c++)
				{
                condLikeUp[A] = condLikeUp[C] = condLikeUp[G] = condLikeUp[T] = 0.0;

                sum[A] = (tiP[AA]*clDP[A] + tiP[AC]*clDP[C] + tiP[AG]*clDP[G] + tiP[AT]*clDP[T]);
				sum[C] = (tiP[CA]*clDP[A] + tiP[CC]*clDP[C] + tiP[CG]*clDP[G] + tiP[CT]*clDP[T]);
				sum[G] = (tiP[GA]*clDP[A] + tiP[GC]*clDP[C] + tiP[GG]*clDP[G] + tiP[GT]*clDP[T]);
				sum[T] = (tiP[TA]*clDP[A] + tiP[TC]*clDP[C] + tiP[TG]*clDP[G] + tiP[TT]*clDP[T]);

                if (sum[A] != 0.0) condLikeUp[A] = clFA[A] / sum[A];
				if (sum[C] != 0.0) condLikeUp[C] = clFA[C] / sum[C];
				if (sum[G] != 0.0) condLikeUp[G] = clFA[G] / sum[G];
				if (sum[T] != 0.0) condLikeUp[T] = clFA[T] / sum[T];

/*
                clFP[A] = (condLikeUp[A]*tiP[AA] + condLikeUp[C]*tiP[CA] + condLikeUp[G]*tiP[GA] + condLikeUp[T]*tiP[TA])*clDP[A];
				clFP[C] = (condLikeUp[A]*tiP[AC] + condLikeUp[C]*tiP[CC] + condLikeUp[G]*tiP[GC] + condLikeUp[T]*tiP[TC])*clDP[C];
				clFP[G] = (condLikeUp[A]*tiP[AG] + condLikeUp[C]*tiP[CG] + condLikeUp[G]*tiP[GG] + condLikeUp[T]*tiP[TG])*clDP[G];
				clFP[T] = (condLikeUp[A]*tiP[AT] + condLikeUp[C]*tiP[CT] + condLikeUp[G]*tiP[GT] + condLikeUp[T]*tiP[TT])*clDP[T];
*/

                clFP[A] = (condLikeUp[A]*tiP[AA] + condLikeUp[C]*tiP[AC] + condLikeUp[G]*tiP[AG] + condLikeUp[T]*tiP[AT])*clDP[A];
				clFP[C] = (condLikeUp[A]*tiP[CA] + condLikeUp[C]*tiP[CC] + condLikeUp[G]*tiP[CG] + condLikeUp[T]*tiP[CT])*clDP[C];
				clFP[G] = (condLikeUp[A]*tiP[GA] + condLikeUp[C]*tiP[GC] + condLikeUp[G]*tiP[GG] + condLikeUp[T]*tiP[GT])*clDP[G];
				clFP[T] = (condLikeUp[A]*tiP[TA] + condLikeUp[C]*tiP[TC] + condLikeUp[G]*tiP[TG] + condLikeUp[T]*tiP[TT])*clDP[T];

				clFA += 4;
				clFP += 4;
				clDP += 4;
				}
            tiP += 16;
			}
		}	

	return NO_ERROR;
}





/*----------------------------------------------------------------
|
|	CondLikeUp_Std: pull likelihoods up and calculate scaled
|		finals for an interior node
|
-----------------------------------------------------------------*/
int     CondLikeUp_Std (TreeNode *p, int division, int chain)
{

	int				a, c, i, j, k, t, nStates, nCats, coppySize,tmp;
	CLFlt			*clFA, *clFP, *clDP, *pA, *tiP, condLikeUp[10], sum;
	ModelInfo		*m;
	
	/* find model settings for this division */
	m = &modelSettings[division];
    
    /* calculate final states */
	if (p->anc->anc == NULL)
		{
		/* this is the root node */
		/* find conditional likelihood pointers = down cond likes */
		/* use conditional likelihood scratch space for final cond likes */
		clDP = m->condLikes[m->condLikeIndex[chain][p->index]];
        clFP = m->condLikes[m->condLikeScratchIndex[p->index]];
        
        coppySize=0;
		/* final cond likes = downpass cond likes */
		for (c=0; c<m->numChars; c++)
			{
			/* calculate nStates and nCats */
			nStates = m->nStates[c];
			
			/* the following lines ensure that nCats is 1 unless */
			/* the character is binary and beta categories are used  */
			if (nStates == 2)
				nCats = m->numBetaCats;
			else
				nCats = 1;

            coppySize+=nCats*nStates;
            }

		/* finally multiply with the gamma cats */
		coppySize *= m->numGammaCats;

		/* copy cond likes */ 
		for (k=0; k<coppySize; k++)
			*(clFP++) = *(clDP++);
		}
	else
		{
		/* find conditional likelihood pointers */
		/* use conditional likelihood scratch space for final cond likes */
        clFA = m->condLikes[m->condLikeScratchIndex[p->anc->index]];
        clFP = m->condLikes[m->condLikeScratchIndex[p->index     ]];
        clDP = m->condLikes[m->condLikeIndex[chain][p->index     ]];

		/* find transition probabilities */
        pA = m->tiProbs[m->tiProbsIndex[chain][p->index]];
        
        for (k=0; k<m->numGammaCats; k++)
		    {
		    for (c=0; c<m->numChars; c++)
			    {

			    /* calculate nStates and nCats */
			    nStates = m->nStates[c];
    			
			    /* the following lines ensure that nCats is 1 unless */
			    /* the character is binary and beta categories are used  */
			    if (nStates == 2)
				    nCats = m->numBetaCats;
			    else
				    nCats = 1;

			    tmp = k*nStates*nStates; /* tmp contains offset to skip gamma cats that already processed*/
			    tiP = pA + m->tiIndex[c] + tmp;
			    tmp = (m->numGammaCats-1)*2*2; /* tmp contains size of block of tpi matrices across all gamma cats (minus one) for single beta category. Further used only if character is binary to jump to next beta category */
    			

			    /* finally multiply with the gamma cats */
			    //nCats *= m->numGammaCats;

			    /* now calculate the final cond likes */
			    for (t=0; t<nCats; t++)
				    {
				    for (a=j=0; a<nStates; a++)
					    {
					    sum = 0.0;
					    for (i=0; i<nStates; i++)
						    sum += tiP[j++]*clDP[i];
                        if (sum == 0.0)
                            condLikeUp[a] = 0.0;    /* we lost the conditional likelihood in the downpass (can occur in gamma model) */
                        else
    					    condLikeUp[a] = clFA[a] / sum;
					    }
    					
				    for (a=j=0; a<nStates; a++)
					    {
					    sum = 0.0;
					    for (i=0; i<nStates; i++)
						    {
						    sum += condLikeUp[i] * tiP[j++];
						    }
					    clFP[a] = sum * clDP[a];
					    }

				    clFP += nStates;
				    clFA += nStates;
				    clDP += nStates;
				    tiP += tmp;
				    }
			    }
            }
		}

	return NO_ERROR;
}





/*----------------------------------------------------------------
|
|	CondLikeScaler_Gen: general n-state model with or without rate
|		variation
|
-----------------------------------------------------------------*/
int CondLikeScaler_Gen (TreeNode *p, int division, int chain)

{

	int				c, k, n, nStates;
	CLFlt			scaler, **clP, *clPtr, *scP, *lnScaler;
	ModelInfo		*m;
#if defined (FAST_LOG)
	int				index;
#endif

    assert(p->scalerNode == YES);

	m = &modelSettings[division];
    nStates = m->numModelStates;

	/* find conditional likelihood pointers */
    clPtr = m->condLikes[m->condLikeIndex[chain][p->index]];
    clP   = m->clP;
	for (k=0; k<m->numGammaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += m->numChars * m->numModelStates;
        }
	
	/* find node scalers */
    scP = m->scalers[m->nodeScalerIndex[chain][p->index]];

    /* find site scalers */
    lnScaler = m->scalers[m->siteScalerIndex[chain]];

	/* rescale */
	for (c=0; c<m->numChars; c++)
		{
		scaler = 0.0;
		for (k=0; k<m->numGammaCats; k++)
			{
			for (n=0; n<nStates; n++)
				{
				if (clP[k][n] > scaler)
					scaler = clP[k][n];
				}
			}

#if defined (FAST_LOG)
		frexp (scaler, &index);
		index = 1-index;
		scaler = scalerValue[index];
#endif
		for (k=0; k<m->numGammaCats; k++)
			{
			for (n=0; n<nStates; n++)
				clP[k][n] /= scaler;
			clP[k] += n;
			}

#if defined (FAST_LOG)
		scP[c]       = logValue[index];			/* store node scaler */
		lnScaler[c] += scP[c];				/* add into tree scaler  */
#else
		scP[c]       = (CLFlt) log (scaler);	/* store node scaler */
		lnScaler[c] += scP[c];	/* add into tree scaler  */
#endif
		}

    m->scalersSet[chain][p->index] = YES;

	return (NO_ERROR);

}





#if defined (SSE_ENABLED)
/*----------------------------------------------------------------
|
|	CondLikeScaler_Gen_SSE: general n-state model with or without rate
|		variation
|
-----------------------------------------------------------------*/
int CondLikeScaler_Gen_SSE (TreeNode *p, int division, int chain)

{
	int				c, i, k, n, nStates;
	CLFlt			*scP, *lnScaler;
	__m128          *clPtr, **clP, m1;
	ModelInfo		*m;
#if defined (FAST_LOG)
	int				index;
#endif

	m = &modelSettings[division];
	nStates = m->numModelStates;

	/* find conditional likelihood pointers */
    clPtr = ( __m128 *) m->condLikes[m->condLikeIndex[chain][p->index]];
    clP   = m->clP_SSE;
	for (k=0; k<m->numGammaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += m->numSSEChars * m->numModelStates;
        }
	
	/* find node scalers */
    scP = m->scalers[m->nodeScalerIndex[chain][p->index]];
	//scP_SSE = (__m128 *) scP;

    /* find site scalers */
    lnScaler = m->scalers[m->siteScalerIndex[chain]];

	/* rescale */
	i  = 0;
	for (c=0; c<m->numSSEChars; c++)
		{
		//scaler = 0.0;
		m1 = _mm_setzero_ps ();
		for (k=0; k<m->numGammaCats; k++)
			{
			for (n=0; n<nStates; n++)
				{
				m1 = _mm_max_ps (m1, clP[k][n]);
				}
			}
		_mm_store_ps( scP,  m1);
		scP += FLOATS_PER_VEC;

#undef FAST_LOG

#if defined (FAST_LOG)
		frexp (scaler, &index);
		index = 1-index;
		scaler = scalerValue[index];
#endif
		for (k=0; k<m->numGammaCats; k++)
			{
			for (n=0; n<nStates; n++)
				{
				*clP[k] = _mm_div_ps (*clP[k], m1);
                clP[k]++;
				}
			}
		}
	
	/* Reset scP to original position*/
	scP = m->scalers[m->nodeScalerIndex[chain][p->index]];
	for (c=0; c<m->numChars; c++)
		{
#if defined (FAST_LOG)
		scP[c]       = logValue[index];			/* store node scaler */
		lnScaler[c] += scP[c];  				/* add into tree scaler  */
#else
		scP[c]       = (CLFlt) log (scP[c]);	/* store node scaler */
		lnScaler[c] += scP[c];                  /* add into tree scaler  */
#endif
		}

    m->scalersSet[chain][p->index] = YES;

	return (NO_ERROR);

}
#endif




/*----------------------------------------------------------------
|
|	CondLikeScaler_Gen_GibbsGamma: general n-state model with Gibbs
|		sampling of rate categories in discrete gamma
|
-----------------------------------------------------------------*/
int CondLikeScaler_Gen_GibbsGamma (TreeNode *p, int division, int chain)

{

	int				c, i, j, n, nStates, *rateCat, nGammaCats;
	CLFlt			scaler, *clP, *scP, *lnScaler;
	ModelInfo		*m;
#if defined (FAST_LOG)
	int				index;
#endif

    assert (p->scalerNode ==  YES);

	m = &modelSettings[division];
	nStates = m->numModelStates;

	/* find conditional likelihood pointer */
	clP = m->condLikes[m->condLikeIndex[chain][p->index]];

	/* flip node scalers */
    scP = m->scalers[m->nodeScalerIndex[chain][p->index]];

	/* find site scalers */
    lnScaler = m->scalers[m->siteScalerIndex[chain]];

	/* find rate category index and number of gamma categories */
	rateCat = m->tiIndex + chain * m->numChars;
	nGammaCats = m->numGammaCats;

	/* scale */
	i = j = 0;
	for (c=0; c<m->numChars; c++)
		{
		if (rateCat[c] < nGammaCats)
			{
			scaler = 0.0;
			for (n=0; n<nStates; n++)
				{
				if (clP[i] > scaler)
					scaler = clP[i];
				i++;
				}

#if defined (FAST_LOG)
			frexp (scaler, &index);
			index = 1-index;
			scaler = scalerValue[index];
#endif


			for (n=0; n<nStates; n++)
				clP[j++] /= scaler;

#if defined (FAST_LOG)
			scP[c]       = logValue[index];			/* store node scaler */
			lnScaler[c] += scP[c];  				/* add into tree scaler  */
#else
			scP[c]       = (CLFlt) log (scaler);	/* store node scaler */
			lnScaler[c] += scP[c];	                /* add into tree scaler  */
#endif

			}
		else
			{
			scP[c] = 0.0;
			/* no need to add it to the lnScaler */
			i += nStates;
			j += nStates;
			}
		}

	m->scalersSet[chain][p->index] = YES;

	return (NO_ERROR);

}





/*----------------------------------------------------------------
|
|	CondLikeScaler_NUC4: 4by4 nucleotide model with or without rate
|		variation
|
-----------------------------------------------------------------*/
int CondLikeScaler_NUC4 (TreeNode *p, int division, int chain)

{
	int				c, k;
	CLFlt			scaler, *scP, *lnScaler, *clPtr, **clP;
	ModelInfo		*m;
	
#if defined (FAST_LOG)
	int				index;
#endif

	m = &modelSettings[division];
    assert (p->scalerNode == YES);

	/* find conditional likelihood pointers */
    clPtr = m->condLikes[m->condLikeIndex[chain][p->index]];
    clP   = m->clP;
	for (k=0; k<m->numGammaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += m->numChars * m->numModelStates;
        }
	
	/* find node scalers */
    scP = m->scalers[m->nodeScalerIndex[chain][p->index]];

    /* find site scalers */
    lnScaler = m->scalers[m->siteScalerIndex[chain]];

    /* rescale values */
    for (c=0; c<m->numChars; c++)
		{
		scaler = 0.0;
        for (k=0; k<m->numGammaCats; k++)
			{
			if (clP[k][A] > scaler)
				scaler = clP[k][A];
			if (clP[k][C] > scaler)
				scaler = clP[k][C];
			if (clP[k][G] > scaler)
				scaler = clP[k][G];
			if (clP[k][T] > scaler)
				scaler = clP[k][T];
			}

#if defined (FAST_LOG)
		frexp (scaler, &index);
		index = 1-index;
		scaler = scalerValue[index];
#endif
		for (k=0; k<m->numGammaCats; k++)
			{
			clP[k][A] /= scaler;
			clP[k][C] /= scaler;
			clP[k][G] /= scaler;
			clP[k][T] /= scaler;
            clP[k] += 4;
			}

#if defined (FAST_LOG)
		scP[c]       = logValue[index];     /* store node scaler */
		lnScaler[c] += scP[c];				/* add into tree scaler  */
#else
		scP[c]       = (CLFlt) log(scaler);	/* store node scaler */
		lnScaler[c] += scP[c];	/* add into tree scaler  */
#endif
		}

	m->scalersSet[chain][p->index] = YES;	/* set flag marking scalers set */

	return NO_ERROR;
	
}





#if defined (SSE_ENABLED)
/*----------------------------------------------------------------
|
|	CondLikeScaler_NUC4_SSE: 4by4 nucleotide model with or without rate
|		variation using SSE code
|
-----------------------------------------------------------------*/
int CondLikeScaler_NUC4_SSE (TreeNode *p, int division, int chain)

{
	int				c, k;
	CLFlt			*scP, *lnScaler;
    __m128          *clPtr, **clP, *scP_SSE, m1;
	ModelInfo		*m;
	
	m = &modelSettings[division];
    assert(p->scalerNode == YES);

	/* find conditional likelihood pointers */
    clPtr = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->index]];
    clP   = m->clP_SSE;
	for (k=0; k<m->numGammaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += m->numSSEChars * m->numModelStates;
        }
	
	/* find node scalers */
    scP = m->scalers[m->nodeScalerIndex[chain][p->index]];
    scP_SSE = (__m128 *) scP;

    /* find site scalers */
    lnScaler = m->scalers[m->siteScalerIndex[chain]];

	/* rescale */
    for (c=0; c<m->numSSEChars; c++)
		{
        m1 = _mm_setzero_ps ();
        for (k=0; k<m->numGammaCats; k++)
			{
            m1 = _mm_max_ps (m1, clP[k][A]);
            m1 = _mm_max_ps (m1, clP[k][C]);
            m1 = _mm_max_ps (m1, clP[k][G]);
            m1 = _mm_max_ps (m1, clP[k][T]);
			}

		for (k=0; k<m->numGammaCats; k++)
			{
			*clP[k] = _mm_div_ps (*clP[k], m1);
            clP[k]++;
			*clP[k] = _mm_div_ps (*clP[k], m1);
            clP[k]++;
			*clP[k] = _mm_div_ps (*clP[k], m1);
            clP[k]++;
			*clP[k] = _mm_div_ps (*clP[k], m1);
            clP[k]++;
			}

		(*scP_SSE++) = m1;
		}

	/* update site scalers */
    for (c=0; c<m->numChars; c++)
        lnScaler[c] += (scP[c] = (CLFlt)(log (scP[c])));	/* add log of new scaler into tree scaler  */

	m->scalersSet[chain][p->index] = YES;	/* set flag marking scalers set */

    return NO_ERROR;
	
}
#endif





/*----------------------------------------------------------------
|
|	CondLikeScaler_NUC4_GibbsGamma: 4by4 nucleotide model with rate
|		variation approximated by Gibbs sampling from gamma
|
-----------------------------------------------------------------*/
int CondLikeScaler_NUC4_GibbsGamma (TreeNode *p, int division, int chain)

{
	int				c, i, j, nGammaCats, *rateCat;
	CLFlt			scaler, *clP, *scP, *lnScaler;
	ModelInfo		*m;
	
#if defined (FAST_LOG)
	int				index;
#endif

    assert (p->scalerNode == YES);

    m = &modelSettings[division];

	/* find conditional likelihood pointer */
	clP = m->condLikes[m->condLikeIndex[chain][p->index]];

	/* find node scalers */
    scP = m->scalers[m->nodeScalerIndex[chain][p->index]];

	/* find site scalers */
    lnScaler = m->scalers[m->siteScalerIndex[chain]];

	/* find rate category index and number of gamma categories */
	rateCat = m->tiIndex + chain * m->numChars;
	nGammaCats = m->numGammaCats;

	/* scale */
	i = j = 0;
	for (c=0; c<m->numChars; c++)
		{
		if (rateCat[c] < nGammaCats)
			{
			scaler = 0.0;
			if (clP[i] > scaler)
				scaler = clP[i];
			i++;
			if (clP[i] > scaler)
				scaler = clP[i];
			i++;
			if (clP[i] > scaler)
				scaler = clP[i];
			i++;
			if (clP[i] > scaler)
				scaler = clP[i];
			i++;

#if defined (FAST_LOG)
			frexp (scaler, &index);
			index = 1-index;
			scaler = scalerValue[index];
#endif

			clP[j++] /= scaler;
			clP[j++] /= scaler;
			clP[j++] /= scaler;
			clP[j++] /= scaler;

#if defined (FAST_LOG)
			scP[c]       = logValue[index];			/* store node scaler */
			lnScaler[c] += scP[c];				    /* add into tree scaler  */
#else
			scP[c]       = (CLFlt) log (scaler);	/* store node scaler */
			lnScaler[c] += scP[c];	                /* add into tree scaler  */
#endif
			}
		else
			{
			scP[c] = 0.0;	/* store node scaler */
			/* no need to add it to the lnScaler */
			i += 4;
			j += 4;
			}
		}

	m->scalersSet[chain][p->index] = YES;

	return NO_ERROR;
	
}





#if !defined (SSE_ENABLED)|| 1
/*----------------------------------------------------------------
|
|	CondLikeScaler_NY98: codon model with omega variation
|
-----------------------------------------------------------------*/
int CondLikeScaler_NY98 (TreeNode *p, int division, int chain)

{
	int				c, i, k, n, nStates;
	CLFlt			scaler, **clP, *clPtr, *scP, *lnScaler;
	ModelInfo		*m;
#if defined (FAST_LOG)
	int				index;
#endif

	m = &modelSettings[division];
	nStates = m->numModelStates;

	/* find conditional likelihood pointers */
    clPtr = m->condLikes[m->condLikeIndex[chain][p->index]];
    clP   = m->clP;
	for (k=0; k<m->numOmegaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += m->numChars * m->numModelStates;
        }
	
	/* find node scalers */
    scP = m->scalers[m->nodeScalerIndex[chain][p->index]];

    /* find site scalers */
    lnScaler = m->scalers[m->siteScalerIndex[chain]];

	/* rescale */
	i  = 0;
	for (c=0; c<m->numChars; c++)
		{
		scaler = 0.0;
		for (k=0; k<m->numOmegaCats; k++)
			{
			for (n=0; n<nStates; n++)
				{
				if (clP[k][n] > scaler)
					scaler = clP[k][n];
				}
			}

#if defined (FAST_LOG)
		frexp (scaler, &index);
		index = 1-index;
		scaler = scalerValue[index];
#endif
		for (k=0; k<m->numOmegaCats; k++)
			{
			for (n=0; n<nStates; n++)
				{
				clP[k][n] /= scaler;
				}
			clP[k] += n;
			}

#if defined (FAST_LOG)
		scP[c]       = logValue[index];			/* store node scaler */
		lnScaler[c] += scP[c];  				/* add into tree scaler  */
#else
		scP[c]       = (CLFlt) log (scaler);	/* store node scaler */
		lnScaler[c] += scP[c];                  /* add into tree scaler  */
#endif
		}

    m->scalersSet[chain][p->index] = YES;

	return (NO_ERROR);

}
#endif





#if defined (SSE_ENABLED)
/*----------------------------------------------------------------
|
|	CondLikeScaler_NY98_SSE: codon model with omega variation
|
-----------------------------------------------------------------*/
int CondLikeScaler_NY98_SSE (TreeNode *p, int division, int chain)

{
	int				c, i, k, n, nStates;
	CLFlt			*scP, *lnScaler;
	__m128          *clPtr, **clP, m1;
	ModelInfo		*m;
#if defined (FAST_LOG)
	int				index;
#endif

	m = &modelSettings[division];
	nStates = m->numModelStates;

	/* find conditional likelihood pointers */
    clPtr = ( __m128 *) m->condLikes[m->condLikeIndex[chain][p->index]];
    clP   = m->clP_SSE;
	for (k=0; k<m->numOmegaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += m->numSSEChars * m->numModelStates;
        }
	
	/* find node scalers */
    scP = m->scalers[m->nodeScalerIndex[chain][p->index]];
	//scP_SSE = (__m128 *) scP;

    /* find site scalers */
    lnScaler = m->scalers[m->siteScalerIndex[chain]];

	/* rescale */
	i  = 0;
	for (c=0; c<m->numSSEChars; c++)
		{
		//scaler = 0.0;
		m1 = _mm_setzero_ps ();
		for (k=0; k<m->numOmegaCats; k++)
			{
			for (n=0; n<nStates; n++)
				{
				m1 = _mm_max_ps (m1, clP[k][n]);
				}
			}
		_mm_store_ps( scP,  m1);
		scP += FLOATS_PER_VEC;

#undef FAST_LOG

#if defined (FAST_LOG)
		frexp (scaler, &index);
		index = 1-index;
		scaler = scalerValue[index];
#endif
		for (k=0; k<m->numOmegaCats; k++)
			{
			for (n=0; n<nStates; n++)
				{
				*clP[k] = _mm_div_ps (*clP[k], m1);
                clP[k]++;
				}
			}
		}
	
	/* Reset scP to original position*/
	scP = m->scalers[m->nodeScalerIndex[chain][p->index]];
	for (c=0; c<m->numChars; c++)
		{
#if defined (FAST_LOG)
		scP[c]       = logValue[index];			/* store node scaler */
		lnScaler[c] += scP[c];  				/* add into tree scaler  */
#else
		scP[c]       = (CLFlt) log (scP[c]);	/* store node scaler */
		lnScaler[c] += scP[c];                  /* add into tree scaler  */
#endif
		}

    m->scalersSet[chain][p->index] = YES;

	return (NO_ERROR);

}
#endif




/*----------------------------------------------------------------
|
|	CondLikeScaler_Std: variable states model with or without
|		rate variation
|
-----------------------------------------------------------------*/
int CondLikeScaler_Std (TreeNode *p, int division, int chain)

{

	int				c, n, k, nStates, numReps;
	CLFlt			scaler, *clPtr, **clP, *scP, *lnScaler;
	ModelInfo		*m;
#if defined (FAST_LOG)
	int				index;
#endif

    assert(p->scalerNode == YES);

	m = &modelSettings[division];

	numReps=0;
	for (c=0; c<m->numChars; c++)
		{
		if ( m->nStates[c] == 2 )
				numReps += m->numBetaCats * 2;
			else
				numReps += m->nStates[c];
		}

    /* find conditional likelihood pointers */
    clPtr = m->condLikes[m->condLikeIndex[chain][p->index]];
    clP   = m->clP;
	for (k=0; k<m->numGammaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += numReps;
        }
	
	/* find node scalers */
    scP = m->scalers[m->nodeScalerIndex[chain][p->index]];

    /* find site scalers */
    lnScaler = m->scalers[m->siteScalerIndex[chain]];

	/* rescale */
	for (c=0; c<m->numChars; c++)
		{
		scaler = 0.0;
		nStates = m->nStates[c];
		if ( nStates == 2 )
			nStates = m->numBetaCats * 2;

		for (k=0; k<m->numGammaCats; k++)
			{
			for (n=0; n<nStates; n++)
				{
				if (clP[k][n] > scaler)
					scaler = clP[k][n];
				}
			}

#if defined (FAST_LOG)
		frexp (scaler, &index);
		index = 1-index;
		scaler = scalerValue[index];
#endif
		for (k=0; k<m->numGammaCats; k++)
			{
			for (n=0; n<nStates; n++)
				clP[k][n] /= scaler;
			clP[k] += nStates;
			}

#if defined (FAST_LOG)
		scP[c]       = logValue[index];			/* store node scaler */
		lnScaler[c] += scP[c];		    		/* add into tree scaler  */
#else
		scP[c]       = (CLFlt) log (scaler);	/* store node scaler */
		lnScaler[c] += scP[c];	                /* add into tree scaler  */
#endif
		}

    m->scalersSet[chain][p->index] = YES;
    	
	return NO_ERROR;
	
}





/*-----------------------------------------------------------------
|
|	CopyParams: copy parameters of touched divisions
|
-----------------------------------------------------------------*/
void CopyParams (int chain)

{

	int			i, j, k, fromState, toState, *fromInt, *toInt;
	MrBFlt		*from, *to;
	ModelInfo	*m;
	Param		*p;

	/* copy all params                                               */
	/* now done for all vars, can also be done for only touched vars */
	/* but then m->upDateCl must be kept separate for each chain!    */
	for (i=0; i<numParams; i++)
		{
		p = &params[i];

		from = GetParamVals (p, chain, state[chain]);
		to = GetParamVals (p, chain, (state[chain] ^ 1));

		for (j=0; j<p->nValues; j++)
			to[j] = from[j];

		from = GetParamSubVals (p, chain, state[chain]);
		to = GetParamSubVals (p, chain, (state[chain] ^ 1));

		for (j=0; j<p->nSubValues; j++)
			to[j] = from[j];

		fromInt = GetParamIntVals (p, chain, state[chain]);
		toInt = GetParamIntVals (p, chain, (state[chain] ^ 1));

		for (j=0; j<p->nIntValues; j++)
			toInt[j] = fromInt[j];

		if (p->nStdStateFreqs > 0)
			{
			from = GetParamStdStateFreqs (p, chain, state[chain]);
			to = GetParamStdStateFreqs (p, chain, state[chain] ^ 1);
			for (j=0; j<p->nStdStateFreqs; j++)
				to[j] = from[j];
			}

		if (p->paramType == P_CPPEVENTS)
			{
			fromState = 2*chain + state[chain];
			toState   = 2*chain + (state[chain] ^ 1);
			for (j=0; j<2*numLocalTaxa-2; j++)
				{
				if (p->nEvents[toState][j] != p->nEvents[fromState][j])
					{
					if (p->nEvents[fromState][j] == 0)
						{
						free (p->position[toState][j]);
						p->position[toState][j] = NULL;
						free (p->rateMult[toState][j]);
						p->rateMult[toState][j] = NULL;
						}
					else if (p->nEvents[toState][j] == 0)
						{
						p->position[toState][j] = (MrBFlt *) SafeCalloc (p->nEvents[fromState][j], sizeof (MrBFlt));
						p->rateMult[toState][j] = (MrBFlt *) SafeCalloc (p->nEvents[fromState][j], sizeof (MrBFlt));
						}
					else
						{
						p->position[toState][j] = (MrBFlt *) SafeRealloc ((void *)p->position[toState][j], p->nEvents[fromState][j] * sizeof (MrBFlt));
						p->rateMult[toState][j] = (MrBFlt *) SafeRealloc ((void *)p->rateMult[toState][j], p->nEvents[fromState][j] * sizeof (MrBFlt));
						}
					p->nEvents[toState][j] = p->nEvents[fromState][j];
					}
				if (p->nEvents[fromState][j] > 0)
					{
					for (k=0; k<p->nEvents[fromState][j]; k++)
						{
						p->position[toState][j][k] = p->position[fromState][j][k];
						p->rateMult[toState][j][k] = p->rateMult[fromState][j][k];
						}
					}
				}
			}
		}

	/* copy division params (model settings) for chain */
	/* reset division update flags                     */
	fromState = 2 * chain + state[chain];
	toState   = 2 * chain + (state[chain] ^ 1);
	for (i=0; i<numCurrentDivisions; i++)
		{
		m = &modelSettings[i];
		m->lnLike[toState] = m->lnLike[fromState];
		if (m->parsModelId == YES)
			m->parsTreeLength[toState] = m->parsTreeLength[fromState];
		m->upDateCl = NO;
        m->upDateCijk = NO;
        m->upDateAll = NO;
		}
		
	return;

}





/* CopySiteScalers: Copy site scalers from scratch space into current space */
void CopySiteScalers (ModelInfo *m, int chain)
{
    CLFlt       *from, *to;
#if defined (BEAGLE_ENABLED)
    int         i, j;
#endif

#if defined (BEAGLE_ENABLED)
    if (m->useBeagle == YES)
        {
        j = m->siteScalerScratchIndex;
        for (i=0; i<m->nCijkParts; i++)
            {
            beagleResetScaleFactors (m->beagleInstance,
                                     m->siteScalerIndex[chain] + i);
            beagleAccumulateScaleFactors (m->beagleInstance,
                                          &j,
                                          1,
                                          m->siteScalerIndex[chain] + i);
            j++;
            }
        return;
        }
#endif
    from = m->scalers[m->siteScalerScratchIndex];
    to   = m->scalers[m->siteScalerIndex[chain]];
    memcpy ((void*) to, (void*) from, (size_t)(m->numChars*sizeof(CLFlt)));
}





/*-----------------------------------------------------------------
|
|	CopyTrees: copies touched trees for chain
|		resets division and node update flags in the process
|       Note: partition information of nodes are not copied if
|       either sorce or destination tree does not have bitsets allocated
|
-----------------------------------------------------------------*/
void CopyTrees (int chain)

{

	int			i, j, n;
	TreeNode	*p, *q;
	Tree		*from, *to;
    int         numTaxa, nLongsNeeded, nLongsNeededTmp;

    /* get some handy numbers */
    from = GetTreeFromIndex (0, chain, state[chain]);
    numTaxa = from->nNodes - from->nIntNodes - (from->isRooted == YES ? 1 : 0);
    nLongsNeeded = (numTaxa - 1) / nBitsInALong + 1;

    /* reset division update flags */
    for (i=0; i<numCurrentDivisions; i++)
        modelSettings[i].upDateCl = NO;

    for (n=0; n<numTrees; n++)
		{
		from = GetTreeFromIndex (n, chain, state[chain]);		
		to = GetTreeFromIndex (n, chain, (state[chain]^1));
        assert( from->nNodes - from->nIntNodes - (from->isRooted == YES ? 1 : 0) == numTaxa );/*so that nLongsNeeded is correct*/
        if( from->bitsets!=NULL && to->bitsets!=NULL )
            nLongsNeededTmp=nLongsNeeded;
        else
            nLongsNeededTmp=0;

        /* copy nodes */
		for (j=0; j<from->nNodes; j++)
			{
			/* copy pointers */
			p  = from->nodes + j;
			q  = to->nodes + j;

			if (p->anc != NULL)
				q->anc = to->nodes + p->anc->memoryIndex;
			else
				q->anc = NULL;

			if (p->left != NULL)	
				q->left = to->nodes + p->left->memoryIndex;
			else
				q->left = NULL;

			if (p->right != NULL)	
				q->right = to->nodes + p->right->memoryIndex;
			else
				q->right = NULL;

			CopyTreeNodes (q, p, nLongsNeededTmp);
            q->upDateCl = q->upDateTi = NO;     /* reset update flags */
			}
		
		for (i=0; i<from->nIntNodes; i++)
			{
			to->intDownPass[i] = to->nodes + from->intDownPass[i]->memoryIndex;
			}
		for (i=0; i<from->nNodes; i++)
			{
			to->allDownPass[i] = to->nodes + from->allDownPass[i]->memoryIndex;
			}

		to->root = to->nodes + from->root->memoryIndex;

		/* rest of tree info is constant and need not be copied */
		}
	
	return;

}





#ifdef VISUAL
BOOL WINAPI CatchInterrupt2(DWORD signum) 
{
    /* set up signal handler to do the same */

    MrBayesPrint("\n   Ctrl-C detected\n");
    requestAbortRun = YES;
    return TRUE;
}
#else
void CatchInterrupt(int signum)
{
    /* set up signal handler to do the same */
    signal(signum, CatchInterrupt);

    requestAbortRun = YES;
	
    MrBayesPrint("\n   Ctrl-C detected\n");
}
#endif




/*----------------------------------------------------------------
|
|	DebugNodeScalers: Calculate node scalers sum
|
-----------------------------------------------------------------*/
CLFlt DebugNodeScalers (TreeNode *p, int division, int chain)

{
	int				c;
	CLFlt			*scP;
    CLFlt           sum=0.0;
	ModelInfo		*m;
	
    m = &modelSettings[division];

    /* find scalers */
    scP = m->scalers[m->nodeScalerIndex[chain][p->index]];

	/* remove scalers */
	for (c=0; c<m->numChars; c++)
		sum += scP[c];

	return sum;
	
}




/*----------------------------------------------------------------
|
|	DebugTreeScalers: Calculate DebugNodeScalers for each node and printit
|
-----------------------------------------------------------------*/
void DebugTreeScalers(int chain, int d) {
	int i;
	TreeNode		*p;
	ModelInfo		*m;
	Tree			*tree;
	
	m = &modelSettings[d];
	tree = GetTree(m->brlens, chain, state[chain]);
	
	if (m->parsModelId == NO)
	{
		for (i=0; i<tree->nIntNodes; i++)
		{
			p = tree->intDownPass[i];
			
            if (p->scalerNode == YES){			
                printf("Node:%d Sum scalers:%f\n",p->index,DebugNodeScalers(p, d, chain));
                }
				
        }
    }
}
   




int DoMcmc (void)

{

	SafeLong	seed;
	int		    rc, i, j, run;
    char        c;
    FILE        *tempFile;
    char        temp[20];
    char        *strBuf,*tmpcp;
    double      tmp;


#if defined (BEST_MPI_ENABLED)
    Tree        *tree;
#endif

#if !defined (VISUAL) && !defined (MPI_ENABLED)
    sighandler_t sigint_oldhandler, sigterm_oldhandler;
#endif

#	if defined (MPI_ENABLED)
	int			testNumChains;
#	endif

    numPreviousGen = 0;     /* Make sure this is reset */

	/* Check to see that we have a data matrix. Otherwise, the MCMC is rather
	   pointless. */
	if (defMatrix == NO)
		{
		MrBayesPrint ("%s   A character matrix must be defined first\n", spacer);
		goto errorExit;
		}

    if ( setUpAnalysisSuccess == NO )
        {
        MrBayesPrint ("%s   The analysis could not be started because there was an error during its setup.\n", spacer);
        MrBayesPrint ("%s   Refer to error messeges printed during modeal set up to adress the problem.\n", spacer);
		goto errorExit;
        }

    /* set file names */
	sumtParams.numRuns = chainParams.numRuns;
	sumpParams.numRuns = chainParams.numRuns;
    sumssParams.numRuns = chainParams.numRuns;
	
	if (fileNameChanged == YES)
		{
		SetFileNames();
		fileNameChanged = NO;
		}

	MrBayesPrint ("%s   Running Markov chain\n", spacer);
	
	/* Check the chain temperature parameters */
	if (CheckTemperature () == ERROR)
		goto errorExit;
	
	/* Set the chain random number seeds here. We have two seeds. One
	   (called swapSeed) is only used to determine which two chains 
	   will swap states in the next trial. The other (called seed) is
	   the seed for our work-horse pseudorandom number generator. Note
	   that if we are doing MPI, we want the swap seed to be the same
	   for every processor. This is taken care of when we initialize
	   things in the program. If we are doing MPI, we also want to make
	   certain that seed is different for every processor. */
#	if defined (MPI_ENABLED)
	seed = globalSeed + (proc_id + 1);
	if (seed < 0)
		seed = -seed;
#	else
	seed = globalSeed;
#	endif

	/* Get a unique identifier (stamp) for this run. This is used as
	   an identifier for each mcmc analysis. It uses runIDSeed to initialize 
	   the stamp. All of the processors should have the same seed, so 
	   this should be safe. */
	GetStamp ();
	
	MrBayesPrint ("%s   Seed = %d\n", spacer, seed);
	MrBayesPrint ("%s   Swapseed = %d\n", spacer, swapSeed);

	/* Show the model to make sure the user sees it before running the analysis */
	if (ShowModel() == ERROR)
		goto errorExit;
	MrBayesPrint ("\n");

    /* Warn the user or stop analysis in case the model is strange */
    if (CheckModel() == ERROR)
        goto errorExit;
				
	/* Determine the number of local chains */
#	if defined (MPI_ENABLED)
	/* tell user how many chains each processor has been assigned */
	if (num_procs > numGlobalChains)
		{
		MrBayesPrint ("%s   The number of chains must be at least as great\n", spacer);
		MrBayesPrint ("%s   as the number of processors (%d)\n", spacer, num_procs);
		goto errorExit;
		}
	if (proc_id == 0)
		{
		for (i=0; i<num_procs; i++)
			{
			testNumChains = (int)(numGlobalChains / num_procs);
			if (i < (numGlobalChains % num_procs))
				testNumChains++;
			MrBayesPrint ("%s   Number of chains on processor %d = %d\n", spacer, i+1, testNumChains);
			}
		}
		
	/* Try to evenly distribute the chains on all processors. */
	numLocalChains = (int)(numGlobalChains / num_procs);

	/* If there are any chains remaining, distribute them
	   in order starting with proc 0. (This may cause a load imbalance.) */
	if (proc_id < (numGlobalChains % num_procs))
		numLocalChains++;
#	else
	numLocalChains = numGlobalChains;
#	endif
	if (numLocalChains < 1)
		return (NO_ERROR);
		
	/* How many taxa and characters ? */
	MrBayesPrint ("%s   Number of taxa = %d\n", spacer, numLocalTaxa);
	MrBayesPrint ("%s   Number of characters = %d\n", spacer, numLocalChar);

#if defined (BEST_MPI_ENABLED)

    // TODO: BEST MPI Set up BEST MPI run
    /* Set up the load balancing scheme. Here we give each processor an equal number of trees.
       If trees are not evenly divisibly by the number of processors, we give the odd n trees to
       the first n processors. */

    /* Throw an error if we have too many processors */
    if (numTopologies < num_procs)
        {
        MrBayesPrint("%s   There are too many processors (%d processors and only %d gene trees)\n", spacer, num_procs, numTopologies);
        return (ERROR);
        }

    /* First deal with the basic case */
    from = proc_id * (numTopologies / num_procs);
    to   = (proc_id + 1) * (numTopologies / num_procs);

    /* Now adjust to deal with the odd trees */
    if (proc_id < numTopologies % num_procs)
        {
        from += proc_id;
        to += proc_id + 1;
        }
    else
        {
        from += numTopologies % num_procs;
        to += numTopologies % num_procs;
        }

    /* Now set the active divisions. Note that if one tree has several model partitions, we set all divisions
       relevant to the tree as being active by checking the relevant partitions for the tree (tree->relParts). */
    for (i=from; i<to; i++)
        {
        for (j=0; j<topologyParam[i]->nRelParts; j++)
            isDivisionActive[topologyParam[i]->relParts[j]] = YES;
        }
#endif

    /* Set up the moves to be used */
	if (SetUsedMoves () == ERROR)
		goto errorExit;

    /* Check to see that we have at least one move. Otherwise, the MCMC is rather
       pointless. */
    if (numUsedMoves == 0)
        {
		MrBayesPrint ("%s   No move is currently switched on.\n", spacer);
		MrBayesPrint ("%s   There must be at least one move to run an MCMC analysis.\n", spacer);
		MrBayesPrint ("%s   Switch on moves using the 'propset' command.\n", spacer);
		goto errorExit;
        }

	/* Show summary table of moves that will be used */	
	if (ShowMoveSummary () == ERROR)
		goto errorExit;

	/* Set the likelihood function pointers. */
	if (SetLikeFunctions () == ERROR)
		goto errorExit;

	/* Set up number of characters of each character pattern. */
	if (FillNumSitesOfPat () == ERROR)
		goto errorExit;

	/* Initialize parsimony sets. */
	if (InitParsSets() == ERROR)
		goto errorExit;

	/* Set up a terminal state index matrix for local compression. */
	if (SetUpTermState() == ERROR)
		goto errorExit;

	/* Initialize conditional likelihoods and transition probabilities for chain (the working space). */
	if (InitChainCondLikes () == ERROR)
		goto errorExit;
	
	/* Initialize invariable conditional likelihoods. */
	if (InitInvCondLikes() == ERROR)
		goto errorExit;

    /* Allocate BEST chain variables */
    if (numTopologies > 1 && !strcmp(modelParams[0].topologyPr,"Speciestree"))
        AllocateBestChainVariables();

    /* allocate SS memory for the chains if needed */
    if(chainParams.isSS == YES)
        {
	    if (memAllocs[ALLOC_SS] == YES)
		    {
		    MrBayesPrint ("%s   SS is already allocated\n", spacer);
		    goto errorExit;
		    }
        else if ((marginalLnLSS = (MrBFlt *) SafeCalloc (chainParams.numRuns, sizeof(MrBFlt))) == NULL)
		    {
		    MrBayesPrint ("%s   Problem allocating marginalLnLSS\n", spacer);
		    goto errorExit;
		    }
        else if ((stepScalerSS = (MrBFlt *) SafeCalloc (chainParams.numRuns, sizeof(MrBFlt))) == NULL)
		    {
		    MrBayesPrint ("%s   Problem allocating stepScalerSS\n", spacer);
            free (marginalLnLSS);
		    goto errorExit;
		    }
        else if ((stepAcumulatorSS = (MrBFlt *) SafeCalloc (chainParams.numRuns, sizeof(MrBFlt))) == NULL)
		    {
		    MrBayesPrint ("%s   Problem allocating stepAcumulatorSS\n", spacer);
            free (stepScalerSS);
            free (marginalLnLSS);
		    goto errorExit;
		    }
	    else if ((splitfreqSS = (MrBFlt *) SafeCalloc (chainParams.numStepsSS*numTopologies, sizeof(MrBFlt))) == NULL)
		    {
		    MrBayesPrint ("%s   Problem allocating splitfreqSS\n", spacer);
            free (stepScalerSS);
            free (marginalLnLSS);
            free (stepAcumulatorSS);
		    goto errorExit;
		    }
        else
		    memAllocs[ALLOC_SS] = YES;
        }


    /* Either append to previous run or deal with starting values */
    if (chainParams.append == YES)
        {
        /* Continue old run */
       
        /* Get starting values from checkpoint file */
		MrBayesPrint ("%s   Getting values from previous run\n", spacer);
        strcpy(inputFileName,chainParams.chainFileName);
        strcat(inputFileName,".ckp");
        if (OpenTextFileR(inputFileName) == NULL)
            {
            MrBayesPrint ("%s   Could not find the checkpoint file '%s'.\n", spacer, inputFileName);
            MrBayesPrint ("%s   Make sure it is in the working directory.\n", spacer);
            goto errorExit;
            }

        if (DoExecute () == ERROR)
            goto errorExit;

        /* Get number of generations to start from and SS information if needed */
        temp[0] = '\0';
        numPreviousGen = 0;
#if defined (MPI_ENABLED)
        if (proc_id == 0) {
#endif
        tempFile = OpenBinaryFileR (inputFileName);
        do { c = fgetc(tempFile);
            } while (c!=':' && c!=EOF);
        if (c!=EOF)
            {
            do { c = fgetc(tempFile);
                } while (c!=':' && c!=EOF);
            }
        if (c!=EOF)
            {
            do { c = fgetc(tempFile);
                } while (!isdigit(c) && c!=EOF);
            }
        if (c!=EOF)
            {
            i=0;
            while (c >= '0' && c <= '9' && i < 18)
                {
                temp[i++] = c;
                c = fgetc(tempFile);
                }
            temp[i] = '\0';
            numPreviousGen = atoi(temp);
            }
        if ( chainParams.isSS==YES && c!=EOF)
            {
            do { c = fgetc(tempFile);
                } while (c!=':' && c!=EOF);
            strBuf = (char *) SafeCalloc ( chainParams.numRuns*20,sizeof(char));
            if( fgets(strBuf,chainParams.numRuns*20,tempFile)==NULL )
                {
                MrBayesPrint ("%s   Error: Reading SsAcumulators from .ckp file fails.\n", spacer);
                free(strBuf);
                goto errorExit;
                }

            tmpcp=strtok(strBuf," "); 
            for (run=0; run<chainParams.numRuns; run++)
                {
                if(tmpcp == NULL )
                    {
                    MrBayesPrint ("%s   Error: Not enough values in SsAcumulators comment of .ckp file.   \n", spacer);
                    free(strBuf);
                    goto errorExit;
                    }
                    
                tmp=atof(tmpcp);
                stepScalerSS[run]=tmp-10;
                stepAcumulatorSS[run]=exp(10);
                tmpcp=strtok(NULL," ]");
                }
                      
            free(strBuf);
            }
#if defined (MPI_ENABLED)
        }
    	MPI_Bcast (&numPreviousGen, 1, MPI_INT, 0, MPI_COMM_WORLD);
#endif
        if (numPreviousGen == 0)
            {
    		MrBayesPrint ("%s   Could not find the number of generations in previous run.\n", spacer);
    		goto errorExit;
            }
        else if (numPreviousGen >= chainParams.numGen)
            {
    		MrBayesPrint ("%s   The specified number of generations (%d) was already finished in\n", spacer, chainParams.numGen);
    		MrBayesPrint ("%s   the previous run you are trying to append to.\n", spacer);
    		goto errorExit;
            }
        else
    		MrBayesPrint ("%s   Using samples up to generation %d from previous analysis.\n", spacer, numPreviousGen);
        }
    else
        {
        /* New run */
        
        /* deal with starting param values */
	    if (!strcmp(chainParams.startParams,"Reset"))
		    {
		    MrBayesPrint ("%s   Resetting starting values for substitution model parameters\n", spacer);
		    FillNormalParams(&seed, 0, numLocalChains);
		    }

        /* deal with starting treeparam values */
        if (!strcmp(chainParams.startTree,"Random"))
	        {
	        MrBayesPrint ("%s   Resetting starting trees and tree parameters\n", spacer);
	        FillTreeParams(&seed, 0, numLocalChains);
	        }
        else if (!strcmp(chainParams.startTree,"Parsimony"))
            {
            MrBayesPrint ("%s   Rebuilding starting trees using random addition sequences and parsimony\n", spacer);
            BuildParsTrees(&seed);
            }

        /* Perturb start trees if requested */
        if (chainParams.numStartPerts > 0)
	        {
	        MrBayesPrint ("%s   Randomly perturbing starting trees\n", spacer);
	        for (i=0; i<numTrees; i++)
		        {
		        for (j=0; j<numGlobalChains; j++)
			        RandPerturb (GetTreeFromIndex(i, j, 0), chainParams.numStartPerts, &seed);
		        }
	        }
        }            

/*Set clockRate if we have calibration */
   for (j=0; j<numGlobalChains; j++)
        {
        if( UpdateClockRate(0.0, j) == ERROR) 
            goto errorExit;
        }


    for (i=0; i<numParams; i++)
        for (j=0; j<numGlobalChains; j++)
            assert (IsTreeConsistent(&params[i], j, 0) == YES);

    /* Initialize vectors of print parameters */
	if (InitPrintParams () == ERROR)
		goto errorExit;
	
	/*! setup a signal handler to catch interrupts, ignore failure */
#ifdef VISUAL
	SetConsoleCtrlHandler(CatchInterrupt2, TRUE);
#else
#if !defined (MPI_ENABLED)
	/* we do not want to mess with the signal handling in MPI version */
	sigint_oldhandler  = signal(SIGINT, CatchInterrupt);
	sigterm_oldhandler = signal(SIGTERM, CatchInterrupt);
#endif
#endif
	requestAbortRun = NO;

	/* Run the Markov chain. */
	rc = RunChain (&seed);
	if (rc == ERROR)
		{
#ifdef VISUAL
		SetConsoleCtrlHandler(CatchInterrupt2, FALSE);
#else
#if !defined MPI_ENABLED
		signal(SIGINT, sigint_oldhandler);
		signal(SIGTERM, sigterm_oldhandler);
#endif
#endif
		goto errorExit;
		}
	else if (rc == ABORT)
		{
		ResetChainIds();
		FreeChainMemory();
#ifdef VISUAL
		SetConsoleCtrlHandler(CatchInterrupt2, FALSE);
#else
#if !defined (MPI_ENABLED)
		signal(SIGINT, sigint_oldhandler);
		signal(SIGTERM, sigterm_oldhandler);
#endif
#endif
		return ABORT;
		}
		
	/*! restore the default signal handler */
#ifdef VISUAL
	SetConsoleCtrlHandler(CatchInterrupt2, FALSE);
#else
#if !defined (MPI_ENABLED)
	signal(SIGINT, sigint_oldhandler);
	signal(SIGTERM, sigterm_oldhandler);
#endif
#endif

	/* Reset the global seed at end of chain. We don't want successive
	   chains to all start with the same random number seed. */
	globalSeed = seed;

	/* Free up all memory allocated for the chain. */
	FreeChainMemory ();
	
	return (NO_ERROR);
	
	errorExit:
		FreeChainMemory ();
		return (ERROR);
	
}





int DoMcmcp (void)

{

	if (defMatrix == NO)
		{
		MrBayesPrint ("%s   A character matrix must be defined first\n", spacer);
		return (ERROR);
		}

	sumtParams.numRuns = chainParams.numRuns;
	sumpParams.numRuns = chainParams.numRuns;
	
	if (fileNameChanged == YES)
		{
        SetFileNames();
		fileNameChanged = NO;
		}

	MrBayesPrint ("%s   Successfully set chain parameters\n", spacer);

	return (NO_ERROR);
	
}





int DoSsParm (char *parmName, char *tkn)

{

	int			tempI;
	MrBFlt		tempD;
    char        tempStr[5];
	

	if (defMatrix == NO)
		{
		MrBayesPrint ("%s   A character matrix must be defined first\n", spacer);
		return (ERROR);
		}

	if (expecting == Expecting(PARAMETER))
		{
		expecting = Expecting(EQUALSIGN);
		}
	else
		{
		if (!strcmp(parmName, "Burninss"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
			    chainParams.burninSS = tempI;
				MrBayesPrint ("%s   Setting burnin for stepping-stone sampling to %ld\n", spacer, chainParams.burninSS);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else 
				{
				return (ERROR);
				}         
			}
        else if (!strcmp(parmName, "Nsteps"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
			    chainParams.numStepsSS = tempI;
				MrBayesPrint ("%s   Setting number of steps in stepping-stone sampling to %ld\n", spacer, chainParams.numStepsSS);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else 
				{
				return (ERROR);
				}                
			}
         else if (!strcmp(parmName, "FromPrior"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						chainParams.startFromPriorSS = YES;
					else
						chainParams.startFromPriorSS = NO;
					}
                else
                	{
					MrBayesPrint ("%s   Invalid argument for FromPrior paramiter\n", spacer);
					return (ERROR);
					}
                MrBayesPrint ("%s   Setting FromPrior=%s\n", spacer, (chainParams.startFromPriorSS==YES)?"Yes":"No");
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else 
				{
				return (ERROR);
				}                
			}
        else if (!strcmp(parmName, "Alpha"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%lf", &tempD);
			    chainParams.alphaSS = tempD;
				MrBayesPrint ("%s   Setting alpha in stepping-stone sampling to %lf\n", spacer, chainParams.alphaSS);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else 
				{
				return (ERROR);
				}                
			}
        else
			{
            return (ERROR);
			}
		}
	return (NO_ERROR);
}





int DoMcmcParm (char *parmName, char *tkn)

{

	int			tempI;
	MrBFlt		tempD;
	char		*tempStr;
	int         tempStrSize = TEMPSTRSIZE;
	
	tempStr = (char *) SafeMalloc((size_t) (tempStrSize * sizeof(char)));
	if (!tempStr)
		{
		MrBayesPrint ("%s   Problem allocating tempString (%d)\n", spacer, tempStrSize * sizeof(char));
		return (ERROR);
		}
	*tempStr='\0';

	if (defMatrix == NO)
		{
		MrBayesPrint ("%s   A character matrix must be defined first\n", spacer);
		return (ERROR);
		}

	if (expecting == Expecting(PARAMETER))
		{
		expecting = Expecting(EQUALSIGN);
		}
	else
		{
		/* set Seed (globalSeed) ***************************************************************/
		if (!strcmp(parmName, "Seed"))
			{
                MrBayesPrint ("%s   Error: Setting \"Seed\" in mcmc command is depricated. Use \"set\" command instead.\n", spacer);
                MrBayesPrint ("%s   For more information type \"help set\";\n", spacer);
                free (tempStr);
			    return (ERROR);
            /*
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				globalSeed = tempI;
				MrBayesPrint ("%s   Setting seed to %ld\n", spacer, globalSeed);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else 
				{
				free (tempStr);
				return (ERROR);
				}
                */
			}
		/* set Swapseed (global variable swapSeed) ***************************************************************/
		else if (!strcmp(parmName, "Swapseed"))
			{
                MrBayesPrint ("%s   Error: Setting \"Swapseed\" in mcmc command is depricated. Use \"set\" command instead.\n", spacer);
                MrBayesPrint ("%s   For more information type \"help set\";\n", spacer);
                free (tempStr);
			    return (ERROR);
                /*
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				swapSeed = tempI;
				MrBayesPrint ("%s   Setting swapseed to %ld\n", spacer, swapSeed);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free (tempStr);
				return (ERROR);
				}
                */
			}
		/* set run ID */
		/* this setting is provided for GRID use only, so that identical runs can be generated */
		else if (!strcmp(parmName, "Runidseed"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				runIDSeed = tempI;
				MrBayesPrint ("%s   Setting run ID [stamp] seed to %ld [for GRID use]\n", spacer, runIDSeed);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free (tempStr);
				return (ERROR);
				}
			}
		/* set Ngen (numGen) ******************************************************************/
		else if (!strcmp(parmName, "Ngen"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				if (tempI < 1)
					{
					MrBayesPrint ("%s   Too few generations\n", spacer);
					return (ERROR);
					}
				chainParams.numGen = tempI;
				MrBayesPrint ("%s   Setting number of generations to %d\n", spacer, chainParams.numGen);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free (tempStr);
				return (ERROR);
				}
			}
		/* set Samplefreq (sampleFreq) ********************************************************/
		else if (!strcmp(parmName, "Samplefreq"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				if (tempI < 1)
					{
					MrBayesPrint ("%s   Sampling chain too infrequently\n", spacer);
					free (tempStr);
					return (ERROR);
					}
				chainParams.sampleFreq = tempI;
				MrBayesPrint ("%s   Setting sample frequency to %d\n", spacer, chainParams.sampleFreq);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free (tempStr);
				return (ERROR);
				}
			}
		/* set Printfreq (printFreq) **********************************************************/
		else if (!strcmp(parmName, "Printfreq"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				if (tempI < 1)
					{
					MrBayesPrint ("%s   Printing to screen too infrequently\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				chainParams.printFreq = tempI;
				MrBayesPrint ("%s   Setting print frequency to %d\n", spacer, chainParams.printFreq);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Printmax (printMax) **********************************************************/
		else if (!strcmp(parmName, "Printmax"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				if (tempI < 1)
					{
					MrBayesPrint ("%s   You need to print at least one chain\n", spacer);
					return (ERROR);
					}
				chainParams.printMax = tempI;
				MrBayesPrint ("%s   Setting maximum number of chains to print to screen to %d\n", spacer, chainParams.printMax);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Printall (printAll) ********************************************************/
		else if (!strcmp(parmName, "Printall"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						chainParams.printAll = YES;
					else
						chainParams.printAll = NO;
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for Printall\n", spacer);
					free (tempStr);
					return (ERROR);
					}
				if (chainParams.allChains == YES)
					MrBayesPrint ("%s   Printing all chains to screen\n", spacer);
				else
					MrBayesPrint ("%s   Printing only cold chains to screen\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Swapfreq (swapFreq) ************************************************************/
		else if (!strcmp(parmName, "Swapfreq"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				if (tempI < 1)
					{
					MrBayesPrint ("%s   Swapping states too infrequently\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				chainParams.swapFreq = tempI;
				MrBayesPrint ("%s   Setting swap frequency to %d\n", spacer, chainParams.swapFreq);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free (tempStr);
				return (ERROR);
				}
			}
		/* set Nswaps (numSwaps) ************************************************************/
		else if (!strcmp(parmName, "Nswaps"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				if (tempI < 1)
					{
					MrBayesPrint ("%s   There must be at least one swap per swapping cycle\n", spacer);
					free (tempStr);
					return (ERROR);
					}
				chainParams.numSwaps = tempI;
				MrBayesPrint ("%s   Setting number of swaps per swapping cycle to %d\n", spacer, chainParams.numSwaps);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Allchains (allChains) ********************************************************/
		else if (!strcmp(parmName, "Allchains"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						chainParams.allChains = YES;
					else
						chainParams.allChains = NO;
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for Allchains\n", spacer);
					free (tempStr);
					return (ERROR);
					}
				if (chainParams.allChains == YES)
					MrBayesPrint ("%s   Calculating MCMC diagnostics for all chains\n", spacer);
				else
					MrBayesPrint ("%s   Calculating MCMC diagnostics only for cold chain(s)\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free (tempStr);
				return (ERROR);
				}
			}
		/* set Allcomps (allComps) ************************************************************/
		else if (!strcmp(parmName, "Allcomps"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						chainParams.allComps = YES;
					else
						chainParams.allComps = NO;
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for Allcomps\n", spacer);
					free (tempStr);
					return (ERROR);
					}
				if (chainParams.allComps == YES)
					MrBayesPrint ("%s   Calculating MCMC diagnostics for all pairwise run comparisons\n", spacer);
				else
					MrBayesPrint ("%s   Only calculating overall MCMC diagnostics\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Mcmcdiagn (mcmcDiagn) ********************************************************/
		else if (!strcmp(parmName, "Mcmcdiagn"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						chainParams.mcmcDiagn = YES;
					else
						chainParams.mcmcDiagn = NO;
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for mcmc diagnostics\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (chainParams.mcmcDiagn == YES)
					MrBayesPrint ("%s   Setting calculation of MCMC diagnostics ('Mcmcdiagn') to yes\n", spacer);
				else
					MrBayesPrint ("%s   Setting calculation of MCMC diagnostics ('Mcmcdiagn') to no\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Diagnfreq (diagnFreq) ************************************************************/
		else if (!strcmp(parmName, "Diagnfreq"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				if (tempI < 1)
					{
					MrBayesPrint ("%s   Diagnosing MCMC behavior too infrequently\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				chainParams.diagnFreq = tempI;
				MrBayesPrint ("%s   Setting diagnosing frequency to %d\n", spacer, chainParams.diagnFreq);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else 
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Savetrees (saveTrees) ********************************************************/
		else if (!strcmp(parmName, "Savetrees"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						chainParams.saveTrees = YES;
					else
						chainParams.saveTrees = NO;
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for Savetrees\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (chainParams.saveBrlens == YES)
					MrBayesPrint ("%s   Saving trees for MCMC diagnostics in memory (if needed)\n", spacer);
				else
					MrBayesPrint ("%s   Not saving trees for MCMC diagnostics in memory\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Diagnstat (diagnStat) ********************************************************/
		else if (!strcmp(parmName, "Diagnstat"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Avgstddev"))
						chainParams.diagnStat = AVGSTDDEV;
					else /* if (!strcmp(tempStr, "Maxstddev")) */
						chainParams.diagnStat = MAXSTDDEV;
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for Savetrees\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (chainParams.saveBrlens == YES)
					MrBayesPrint ("%s   Saving trees for MCMC diagnostics in memory (if needed)\n", spacer);
				else
					MrBayesPrint ("%s   Not saving trees for MCMC diagnostics in memory\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Checkpoint (checkPoint) ********************************************************/
		else if (!strcmp(parmName, "Checkpoint"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						chainParams.checkPoint = YES;
					else
						chainParams.checkPoint = NO;
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for 'Checkpoint' (check-pointing)\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (chainParams.saveBrlens == YES)
					MrBayesPrint ("%s   Setting check-pointing ('Checkpoint') to yes\n", spacer);
				else
					MrBayesPrint ("%s   Setting check-pointing ('Checkpoint') to no\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Checkfreq (checkFreq) ************************************************************/
		else if (!strcmp(parmName, "Checkfreq"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				if (tempI < 100)
					{
					MrBayesPrint ("%s   Check-pointing frequency must be at least 100\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				chainParams.checkFreq = tempI;
				MrBayesPrint ("%s   Setting check-pointing frequency to %d\n", spacer, chainParams.checkFreq);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else 
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Minpartfreq (minPartFreq) ************************************************************/
		else if (!strcmp(parmName, "Minpartfreq"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%lf", &tempD);
				if (tempD < 0.01)
					{
					MrBayesPrint ("%s   Minimum partition frequency too low (< 0.01)\n", spacer);
					free (tempStr);
					return (ERROR);
					}
				if (tempD > 0.8)
					{
					MrBayesPrint ("%s   Minimum partition frequency too high (> 0.8)\n", spacer);
					free (tempStr);
					return (ERROR);
					}
				chainParams.minPartFreq = tempD;
				MrBayesPrint ("%s   Setting minimum partition frequency to %.2f\n", spacer, chainParams.minPartFreq);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else 
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Nruns (numRuns) ****************************************************************/
		else if (!strcmp(parmName, "Nruns"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				if (tempI < 1)
					{
					MrBayesPrint ("%s   Too few runs (minimum of 1 run)\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (tempI > MAX_RUNS)
					{
					MrBayesPrint ("%s   Too many runs (maximum of %d runs)\n", spacer, MAX_RUNS);
					free(tempStr);
					return (ERROR);
					}
				if (ChangeNumRuns (chainParams.numRuns, tempI) == ERROR)
					return (ERROR);
				chainParams.numRuns = tempI;
				fileNameChanged = YES;
				MrBayesPrint ("%s   Setting number of runs to %d\n", spacer, chainParams.numRuns);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Nchains (numChains) ************************************************************/
		else if (!strcmp(parmName, "Nchains"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				if (tempI < 1)
					{
					MrBayesPrint ("%s   Too few chains (minimum of 1 chain)\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (tempI > MAX_CHAINS)
					{
					MrBayesPrint ("%s   Too many chains (maximum of %d chains)\n", spacer, MAX_CHAINS);
					free(tempStr);
					return (ERROR);
					}
				if (ChangeNumChains (chainParams.numChains, tempI) == ERROR)
					return (ERROR);
				chainParams.numChains = tempI;
				MrBayesPrint ("%s   Setting number of chains to %d\n", spacer, chainParams.numChains);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Temp (chainTemp) ***************************************************************/
		else if (!strcmp(parmName, "Temp"))
			{
			if (expecting == Expecting(EQUALSIGN))
				{
				tempIndex = 0;
				expecting = Expecting(NUMBER) | Expecting(LEFTPAR);
				}
			else if (expecting == Expecting(LEFTPAR))
				{
				chainParams.userDefinedTemps = YES;
				expecting = Expecting(NUMBER);
				}
			else if (expecting == Expecting(RIGHTPAR))
				{
				MrBayesPrint ("%s   Setting user-defined temperatures\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else if (expecting == Expecting(COMMA))
				{
				expecting = Expecting(NUMBER);
				}
			else if (expecting == Expecting(NUMBER))
				{
				if (chainParams.userDefinedTemps == NO)
					{
					sscanf (tkn, "%lf", &tempD);
					chainParams.chainTemp = tempD;
					MrBayesPrint ("%s   Setting heating parameter to %lf\n", spacer, chainParams.chainTemp);
					expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
					}
				else
					{
					if (tempIndex >= MAX_CHAINS)
						{
						MrBayesPrint ("%s   Too many user-defined temperatures (%d maximum)\n", spacer, MAX_CHAINS);
						free(tempStr);
						return (ERROR);
						}
					sscanf (tkn, "%lf", &tempD);
					chainParams.userTemps[tempIndex++] = tempD;
					expecting = Expecting(COMMA) | Expecting(RIGHTPAR);
					}
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Reweight (weightScheme) ********************************************************/
		else if (!strcmp(parmName, "Reweight"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(LEFTPAR);
			else if (expecting == Expecting(LEFTPAR))
				{
				expecting = Expecting(NUMBER);
				whichReweightNum = 0;
				}
			else if (expecting == Expecting(NUMBER))
				{
				if (whichReweightNum < 0 || whichReweightNum > 2)
					{
					free(tempStr);
					return (ERROR);
					}
				sscanf (tkn, "%lf", &tempD);
				chainParams.weightScheme[whichReweightNum] = tempD;
				if (whichReweightNum < 2)
					{
					if (tempD < 0.0 || tempD > 100.0)
						{
						MrBayesPrint ("%s   The reweighting parameter must be between 0 and 100\n", spacer);
						chainParams.weightScheme[0] = chainParams.weightScheme[1] = 0.0;
						chainParams.weightScheme[2] = 1.0;
						free(tempStr);
						return (ERROR);
						}
					}
				else
					{
					if (tempD <= 0.0 || tempD > 1.0)
						{
						MrBayesPrint ("%s   The reweighting increment must be between 0 and 1\n", spacer);
						chainParams.weightScheme[0] = chainParams.weightScheme[1] = 0.0;
						chainParams.weightScheme[2] = 1.0;
						free(tempStr);
						return (ERROR);
						}
					}
				if (whichReweightNum == 0)
					{
					expecting = Expecting(COMMA);
					}
				else if (whichReweightNum == 1)
					{
					if (chainParams.weightScheme[0] + chainParams.weightScheme[1] > 100.0)
						{
						MrBayesPrint ("%s   The sum of the reweighting parameters cannot exceed 100 %%\n", spacer);
						chainParams.weightScheme[0] = chainParams.weightScheme[1] = 0.0;
						chainParams.weightScheme[2] = 1.0;
						free(tempStr);
						return (ERROR);
						}
					expecting = Expecting(COMMA) | Expecting(RIGHTPAR);
					}
				else
					{
					expecting = Expecting(RIGHTPAR);
					}
				whichReweightNum++;
				}
			else if ((expecting & Expecting(COMMA)) == Expecting(COMMA))
				expecting = Expecting(NUMBER);
			else if ((expecting & Expecting(RIGHTPAR)) == Expecting(RIGHTPAR))
				{
				if (chainParams.weightScheme[0] >= 100.0)
					{
					MrBayesPrint ("%s   Cannot decrease weight of all characters\n", spacer);
					chainParams.weightScheme[0] = chainParams.weightScheme[1] = 0.0;
					chainParams.weightScheme[2] = 1.0;
					free(tempStr);
					return (ERROR);
					}
				MrBayesPrint ("%s   Setting reweighting parameter to (%1.2lf v, %1.2lf ^) increment = %1.2lf\n", 
					spacer, chainParams.weightScheme[0], chainParams.weightScheme[1], chainParams.weightScheme[2]);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Filename (chainFileName) *******************************************************/
		else if (!strcmp(parmName, "Filename"))
			{
			if (expecting == Expecting(EQUALSIGN))
				{
				expecting = Expecting(ALPHA);
				readWord = YES;
				}
			else if (expecting == Expecting(ALPHA))
				{
				sscanf (tkn, "%s", tempStr);
                if(strlen(tempStr)>99)
                    {
                    MrBayesPrint ("%s   Maximum allowed length of chain file name is 99 characters. The given name:\n", spacer);
                    MrBayesPrint ("%s      '%s'\n", spacer,tempStr);
                    MrBayesPrint ("%s   has %d characters.\n", spacer,strlen(tempStr));
                    return (ERROR);
                    }
				strcpy (chainParams.chainFileName, tempStr);
				fileNameChanged = YES;
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Relburnin (relativeBurnin) ********************************************************/
		else if (!strcmp(parmName, "Relburnin"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						chainParams.relativeBurnin = YES;
					else
						chainParams.relativeBurnin = NO;
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for Relburnin\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (chainParams.relativeBurnin == YES)
					MrBayesPrint ("%s   Using relative burnin (a fraction of samples discarded).\n", spacer);
				else
					MrBayesPrint ("%s   Using absolute burnin (a fixed number of samples discarded).\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free (tempStr);
				return (ERROR);
				}
			}
		/* set Burnin (chainBurnIn) ***********************************************************/
		else if (!strcmp(parmName, "Burnin"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				chainParams.chainBurnIn = tempI;
				MrBayesPrint ("%s   Setting chain burn-in to %d\n", spacer, chainParams.chainBurnIn);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Burninfrac (burninFraction) ************************************************************/
		else if (!strcmp(parmName, "Burninfrac"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%lf", &tempD);
				if (tempD < 0.01)
					{
					MrBayesPrint ("%s   Burnin fraction too low (< 0.01)\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (tempD > 0.50)
					{
					MrBayesPrint ("%s   Burnin fraction too high (> 0.50)\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				chainParams.burninFraction = tempD;
				MrBayesPrint ("%s   Setting burnin fraction to %.2f\n", spacer, chainParams.burninFraction);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else 
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Stoprule (stopRule) ********************************************************/
		else if (!strcmp(parmName, "Stoprule"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						chainParams.stopRule = YES;
					else
						chainParams.stopRule = NO;
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for Stoprule\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (chainParams.stopRule == YES)
					MrBayesPrint ("%s   Using stopping rule.\n", spacer);
				else
					MrBayesPrint ("%s   Not using stopping rule.\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Stopval (stopVal) ************************************************************/
		else if (!strcmp(parmName, "Stopval"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%lf", &tempD);
				if (tempD < 0.000001)
					{
					MrBayesPrint ("%s   Stop value too low (< 0.000001)\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (tempD > 0.20)
					{
					MrBayesPrint ("%s   Stop value too high (> 0.20)\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				chainParams.stopVal = tempD;
				MrBayesPrint ("%s   Setting burnin fraction to %.2f\n", spacer, chainParams.burninFraction);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else 
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Starttree (startTree) **************************************************/
		else if (!strcmp(parmName, "Starttree"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr,"User"))
						{
						MrBayesPrint ("%s   The 'user' setting of 'Starttree' is deprecated. Set starting trees using 'Startvals' instead.\n", spacer);
						free (tempStr);
						return (ERROR);
						}
					else
						strcpy(chainParams.startTree, tempStr);
					}
				else
					{
					MrBayesPrint ("%s   Invalid 'Starttree' argument\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				MrBayesPrint ("%s   Setting 'Starttree' to \"%s\"\n", spacer, chainParams.startTree);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Startingtrees (deprecated) **************************************************/
		else if (!strcmp(parmName, "Startingtrees"))
			{
			free (tempStr);
			MrBayesPrint ("%s   Parameter 'Startingtrees' is deprecated. Use the 'Starttree' parameter or the 'Startvals' command instead.\n", spacer);
			return (ERROR);
			}
		/* set Nperts (numStartPerts) *********************************************************/
		else if (!strcmp(parmName, "Nperts"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				chainParams.numStartPerts = tempI;
				MrBayesPrint ("%s   Setting number of perturbations to start tree to %d\n", spacer, chainParams.numStartPerts);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Startparams (startParams) **************************************************/
		else if (!strcmp(parmName, "Startparams"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					strcpy(chainParams.startParams, tempStr);
				else
					{
					MrBayesPrint ("%s   Invalid 'Startparams' argument\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				MrBayesPrint ("%s   Setting 'Startparams' to \"%s\"\n", spacer, chainParams.startParams);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Savebrlens (saveBrlens) ********************************************************/
		else if (!strcmp(parmName, "Savebrlens"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						; /* This is the only option in version 3.2 */
					else
						MrBayesPrint ("%s   WARNING: Ignoring savebrlens setting; since version 3.2, branch lengths are always saved\n", spacer);
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for savebrlens\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			}
		/* set Redirect (redirect) ********************************************************/
		else if (!strcmp(parmName, "Redirect"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						chainParams.redirect = YES;
					else
						chainParams.redirect = NO;
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for redirecting output\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (chainParams.redirect == YES)
					MrBayesPrint ("%s   Setting program to redirect output\n", spacer);
				else
					MrBayesPrint ("%s   Setting program not to redirect output\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Data (runWithData) ************************************************************/
		else if (!strcmp(parmName, "Data"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						chainParams.runWithData = YES;
					else
						chainParams.runWithData = NO;
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for Data\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (chainParams.runWithData == NO)
					MrBayesPrint ("%s   Running without data (WARNING: use this only for checking priors!)\n", spacer);
				else
					MrBayesPrint ("%s   Running with data (standard analysis)\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Ordertaxa (chainParams.orderTaxa) *********************************************/
		else if (!strcmp(parmName, "Ordertaxa"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						chainParams.orderTaxa = YES;
					else
						chainParams.orderTaxa = NO;
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for ordertaxa\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (chainParams.orderTaxa == YES)
					MrBayesPrint ("%s   Setting ordertaxa to yes\n", spacer);
				else
					MrBayesPrint ("%s   Setting ordertaxa to no\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Append (chainParams.append) *********************************************/
		else if (!strcmp(parmName, "Append"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						chainParams.append = YES;
					else
						chainParams.append = NO;
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for append\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (chainParams.append == YES)
					MrBayesPrint ("%s   Setting append to yes\n", spacer);
				else
					MrBayesPrint ("%s   Setting append to no\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Autotune (chainParams.autotune) *********************************************/
		else if (!strcmp(parmName, "Autotune"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						chainParams.autotune = YES;
					else
						chainParams.autotune = NO;
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for Autotune\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (chainParams.orderTaxa == YES)
					MrBayesPrint ("%s   Setting Autotune to yes\n", spacer);
				else
					MrBayesPrint ("%s   Setting Autotune to no\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Tunefreq (tuneFreq) ************************************************************/
		else if (!strcmp(parmName, "Tunefreq"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(NUMBER);
			else if (expecting == Expecting(NUMBER))
				{
				sscanf (tkn, "%d", &tempI);
				if (tempI < 10)
					{
					MrBayesPrint ("%s   Autotuning frequency must be at least 10\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				chainParams.tuneFreq = tempI;
				MrBayesPrint ("%s   Setting autotuning frequency to %d\n", spacer, chainParams.tuneFreq);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else 
				{
				free(tempStr);
				return (ERROR);
				}
			}
		/* set Swapadjacent (swapAdjacentOnly) **************************************************/
		else if (!strcmp(parmName, "Swapadjacent"))
			{
			if (expecting == Expecting(EQUALSIGN))
				expecting = Expecting(ALPHA);
			else if (expecting == Expecting(ALPHA))
				{
				if (IsArgValid(tkn, tempStr) == NO_ERROR)
					{
					if (!strcmp(tempStr, "Yes"))
						chainParams.swapAdjacentOnly = YES;
					else
						chainParams.swapAdjacentOnly = NO;
					}
				else
					{
					MrBayesPrint ("%s   Invalid argument for Swapadjacent\n", spacer);
					free(tempStr);
					return (ERROR);
					}
				if (chainParams.swapAdjacentOnly == YES)
					MrBayesPrint ("%s   Setting program to attempt swaps only between chains of adjacent temperatures\n", spacer);
				else
					MrBayesPrint ("%s   Setting program to attempt all possible swaps between chains\n", spacer);
				expecting = Expecting(PARAMETER) | Expecting(SEMICOLON);
				}
			else
				{
				free(tempStr);
				return (ERROR);
				}
			}
		else
			{
			free(tempStr);
			return (ERROR);
			}
		}
	free(tempStr);
	return (NO_ERROR);
		
}





int DoSs (void)
{
    int ret, oldBurnin;

    if( chainParams.numGen/chainParams.sampleFreq <= chainParams.burninSS )
        {/*Do not change print out to generations vs samples because of danger of overflow*/
        MrBayesPrint ("%s      ERROR: Burnin %d samples is too large compared with requested total %d samples (%d generations).\n", spacer ,chainParams.burninSS, chainParams.numGen/chainParams.sampleFreq, chainParams.numGen );
        return ERROR;
        }

    oldBurnin = chainParams.burninSS;;
    stepRelativeBurninSS = chainParams.relativeBurnin;


    chainParams.relativeBurnin = YES;
 
    if( chainParams.burninSS < 0 )
        chainParams.burninSS =  chainParams.numGen / ((chainParams.numStepsSS-chainParams.burninSS)*chainParams.sampleFreq);
    chainParams.isSS = YES;

    ret=DoMcmc();

    chainParams.isSS = NO;
    chainParams.burninSS = oldBurnin;
    chainParams.relativeBurnin = stepRelativeBurninSS;

    return ret;
}





int DoSsp (void)
{
    return NO_ERROR;
}





int ExhaustiveParsimonySearch (Tree *t, int chain, TreeInfo *tInfo)

{

	int			i, j, k;
	TreeNode    *p;
	
	for (i=j=k=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->left == NULL || p->right == NULL)
			tInfo->leaf[j++] = p;
		else
			tInfo->vertex[k++] = p;
		}

	tInfo->leaf[0]->anc = tInfo->leaf[1]->anc = tInfo->vertex[0];
	tInfo->vertex[0]->left = tInfo->leaf[0];
	tInfo->vertex[0]->right = tInfo->leaf[1];
	tInfo->leaf[t->nIntNodes+1]->left = tInfo->vertex[0];
	tInfo->vertex[0]->anc = tInfo->leaf[t->nIntNodes+1];

	BuildExhaustiveSearchTree (t, chain, 2, tInfo);

	return (NO_ERROR);
}




int ExtendChainQuery ()

{

	int				extendChain, additionalCycles;
	char			s[100];
	
#	if defined (MPI_ENABLED)
	if (proc_id == 0)
		{
		MrBayesPrint ("\n");
		extendChain = WantTo ("Continue with analysis");
		}
	MPI_Bcast (&extendChain, 1, MPI_INT, 0, MPI_COMM_WORLD);
	if (extendChain == YES)
		{
		if (proc_id == 0)
			{
			additionalCycles = 0;
			do
				{
				if (additionalCycles < 0)
					MrBayesPrint ("%s      Number must be greater than or equal to 0: ", spacer);
				else
					MrBayesPrint ("%s      Additional number of generations: ", spacer);

				if( fgets (s, 100, stdin) == NULL )
					{
						printf("Error in function: %s at line: %d in file: %s", __FUNCTION__, __LINE__, __FILE__);
					}
				sscanf (s, "%d", &additionalCycles);

				} while (additionalCycles < 0);
			MrBayesPrint ("\n");
			}
		MPI_Bcast (&additionalCycles, 1, MPI_INT, 0, MPI_COMM_WORLD);
			
		return (additionalCycles);
		}
	else
		return (0);
#	else
	MrBayesPrint ("\n");
	extendChain = WantTo ("Continue with analysis");
	
	if (extendChain == YES)
		{
		additionalCycles = 0;
		do
			{
			if (additionalCycles < 0)
				MrBayesPrint ("%s      Number must be greater than or equal to 0: ", spacer);
			else
				MrBayesPrint ("%s      Additional number of generations: ", spacer);

			if( fgets (s, 20, stdin) == NULL )
				{
					printf("Error in function: %s at line: %d in file: %s", __FUNCTION__, __LINE__, __FILE__);
				}
			sscanf (s, "%d", &additionalCycles);

			} while (additionalCycles < 0);
		MrBayesPrint ("\n");
		return (additionalCycles);
		}
	else
		return (0);
#	endif

}

		
int FillNumSitesOfPat (void)

{

	int			i, j, n, *increased, *decreased, nToDecrease, nToIncrease, whichToChange;
	MrBFlt		ran, sum;
	CLFlt		wtIncrement;
	
	wtIncrement = (CLFlt) chainParams.weightScheme[2];
	increased = decreased = NULL;
	
	/* reallocate numSitesOfPat */
	if (memAllocs[ALLOC_NUMSITESOFPAT] == NO)
		{
		MrBayesPrint ("%s   numSitesOfPat is not allocated\n", spacer);
		goto errorExit;
		}
	memAllocs[ALLOC_NUMSITESOFPAT] = NO;
	numSitesOfPat = (CLFlt *) SafeRealloc((void *) numSitesOfPat, numCompressedChars * chainParams.numChains * sizeof(MrBFlt));
	if (!numSitesOfPat)
		{
		MrBayesPrint ("%s   Problem reallocating numSitesOfPat (%d)\n", spacer, numCompressedChars * chainParams.numChains * sizeof(MrBFlt));
		goto errorExit;
		}
	memAllocs[ALLOC_NUMSITESOFPAT] = YES;

	/* copy first numCompressedChars into the remaining bits */
	if (chainParams.numChains > 1)
		{
		for (i=0; i<numCompressedChars; i++)
			{
			for (j=1; j<chainParams.numChains; j++)
				{
				numSitesOfPat[j * numCompressedChars + i] = numSitesOfPat[i];
				}
			}
		}	
		
	/* reweight characters for each chain */
	if (chainParams.numChains > 1)
		{
		if (chainParams.weightScheme[0] + chainParams.weightScheme[1] > 0.0001)
			MrBayesPrint ("%s   Reweighting of characters for chains 1 to %d\n", spacer, chainParams.numChains);

		/* check that we don't have an HMM */
		if (chainHasAdgamma == YES && chainParams.weightScheme[0] + chainParams.weightScheme[1] > 0.0001)
			{
			MrBayesPrint ("%s   Reweighting of characters is not allowed with an autocorrelated gamma model\n", spacer);
			goto errorExit;
			}
		
		/* how many characters */
		n = 0;
		for (i=0; i<numCompressedChars; i++)
			n += (int)numSitesOfPat[0 * numCompressedChars + i];
		nToDecrease = (int)(n * chainParams.weightScheme[0] / 100.0);
		nToIncrease = (int)(n * chainParams.weightScheme[1] / 100.0);
		if (chainParams.weightScheme[0] + chainParams.weightScheme[1] > 0.0001)
			{
			MrBayesPrint ("%s      Decreasing weight of %d characters\n", spacer, nToDecrease);
			MrBayesPrint ("%s      Increasing weight of %d characters\n", spacer, nToIncrease);
			}
		
		/* allocate memory */
		increased = (int *)SafeMalloc((size_t) (2 * numCompressedChars * sizeof(int)));
		if (!increased)
			{
			MrBayesPrint ("%s   Problem reallocating increased (%d)\n", spacer, numCompressedChars * chainParams.numChains * sizeof(int));
			goto errorExit;
			}
		decreased = increased + numCompressedChars;

		/* reweight characters for each chain */
		for (j=1; j<chainParams.numChains; j++)
			{
			for (i=0; i<numCompressedChars; i++)
				increased[i] = decreased[i] = 0;

			/* decrease weight of characters */
			for (i=0; i<nToDecrease; i++)
				{
				do
					{
					ran = RandomNumber(&swapSeed);
					sum = 0.0;
					for (whichToChange=0; whichToChange<numCompressedChars; whichToChange++)
						{
						sum += numSitesOfPat[0 * numCompressedChars + whichToChange] / n;
						if (ran < sum)
							break;
						}
					if (whichToChange < 0 || whichToChange >= numCompressedChars)
						continue;
					} while (decreased[whichToChange] >= numSitesOfPat[0 * numCompressedChars + whichToChange]);
				decreased[whichToChange]++;
				numSitesOfPat[j * numCompressedChars + whichToChange] -= wtIncrement;
				if (numSitesOfPat[j * numCompressedChars + whichToChange] < 0)
					{
					MrBayesPrint ("%s   Problem reweighting characters\n", spacer);
					goto errorExit;
					}
				}

			/* increase weight of characters */
			for (i=0; i<nToDecrease; i++)
				{
				do
					{
					ran = RandomNumber(&swapSeed);
					sum = 0.0;
					for (whichToChange=0; whichToChange<numCompressedChars; whichToChange++)
						{
						sum += numSitesOfPat[0 * numCompressedChars + whichToChange] / n;
						if (ran < sum)
							break;
						}
					if (whichToChange < 0 || whichToChange >= numCompressedChars)
						continue;
					} while ((increased[whichToChange] + decreased[whichToChange]) >= numSitesOfPat[0 * numCompressedChars + whichToChange]);
				increased[whichToChange]++;
				numSitesOfPat[j * numCompressedChars + whichToChange] += wtIncrement;
				if (numSitesOfPat[j * numCompressedChars + whichToChange] < 0)
					{
					MrBayesPrint ("%s   Problem reweighting characters\n", spacer);
					goto errorExit;
					}
				}

			}
			
		/* free allocated memory */
		free (increased);
		}
		
#	if 0
	/* print site patterns for each chain */
	for (i=0; i<numCompressedChars; i++)
		{
		MrBayesPrint ("%4d -- ", i);
		for (j=0; j<chainParams.numChains; j++)
			{
			MrBayesPrint ("%4.1lf ", numSitesOfPat[j * numCompressedChars + i]);
			}
		MrBayesPrint ("\n");
		}
#	endif

	return (NO_ERROR);
	
	errorExit:
		if (increased)
			free (increased);
		return (ERROR);
	
}





/* FindBestNode: Recursive function for finding best attachment point */
TreeNode *FindBestNode (Tree *t, TreeNode *p, TreeNode *addNode, CLFlt *minLength, int chain) {

    int         c, n, division;
    TreeNode    *q=NULL, *r=NULL;
    SafeLong    *pA, *pP, *pX;
    CLFlt       *nSitesOfPat, fpLength, length;
    ModelInfo   *m;

	/* Calculate length, looping over divisions */
	fpLength = 0;
    for (n=0; n<t->nRelParts; n++)
		{
		division = t->relParts[n];

		/* Find model settings */
		m = &modelSettings[division];

		/* Find number of site patterns */
		nSitesOfPat = numSitesOfPat + ((1 % chainParams.numChains) * numCompressedChars) + m->compCharStart;

		/* Find final-pass parsimony sets for the node and its ancestor */
		pP    = m->parsSets[p->index      ];
        pA    = m->parsSets[p->anc->index ];
		pX    = m->parsSets[addNode->index];

		for (c=0; c<m->numChars; c++)
			{
            if (((pP[c] | pA[c])&pX[c]) == 0)
				fpLength += nSitesOfPat[c];
			}
		}

    /* If tip, this is the best node and its length is the min length */
    if (p->left == NULL)
        {
        *minLength = fpLength;
        return p;
        }

    /* Find best node and min length above this node */
    if (p->left != NULL) {
        q = FindBestNode(t, p->left,  addNode, minLength, chain);
        r = FindBestNode(t, p->right, addNode, &length,   chain);
        if (length < *minLength) {
            *minLength = length;
            q = r;
        }
    }

    /* Return best node and min length */
    if (*minLength < fpLength)
        return q;
    else /* This node is the best */
        {
        *minLength = fpLength;
        return p;
        }
}





/* FlipCijkSpace: Flip space for cijks with scratch area */
void FlipCijkSpace (ModelInfo* m, int chain)
{
    int         temp;

    temp                = m->cijkIndex[chain];
    m->cijkIndex[chain] = m->cijkScratchIndex;
    m->cijkScratchIndex = temp;
}





/* FlipCondLikeSpace: Flip space for conditional likelihoods with scratch area */
void FlipCondLikeSpace (ModelInfo* m, int chain, int nodeIndex)
{
    int         temp;

    temp                               = m->condLikeIndex[chain][nodeIndex];
    m->condLikeIndex[chain][nodeIndex] = m->condLikeScratchIndex[nodeIndex];
    m->condLikeScratchIndex[nodeIndex] = temp;
}





/* FlipNodeScalerSpace: Flip space for node scalers and scaler flag with scratch area */
void FlipNodeScalerSpace (ModelInfo* m, int chain, int nodeIndex)
{
    int         temp;

    temp                                 = m->nodeScalerIndex[chain][nodeIndex];
    m->nodeScalerIndex[chain][nodeIndex] = m->nodeScalerScratchIndex[nodeIndex];
    m->nodeScalerScratchIndex[nodeIndex] = temp;

    temp                                 = m->scalersSet[chain][nodeIndex];
    m->scalersSet[chain][nodeIndex]      = m->scalersSetScratch[nodeIndex];
    m->scalersSetScratch[nodeIndex]      = temp;
}





/* FlipSiteScalerSpace: Flip space for ln site scalers */
void FlipSiteScalerSpace (ModelInfo *m, int chain)
{
    int  temp;

#if defined (BEAGLE_ENABLED)
    int *tempp;
#endif

    temp = m->siteScalerIndex[chain];
    m->siteScalerIndex[chain] = m->siteScalerScratchIndex;
    m->siteScalerScratchIndex = temp;

#if defined (BEAGLE_ENABLED)
	if ( m->useBeagle == YES )
		{
		tempp = m->isScalerNode[chain];
		m->isScalerNode[chain] = m->isScalerNodeScratch ;
		m->isScalerNodeScratch = tempp;
		}
#endif
}





/* FlipTiProbsSpace: Flip space for ti probs with scratch area */
void FlipTiProbsSpace (ModelInfo* m, int chain, int nodeIndex)
{
    int         temp;

    temp                              = m->tiProbsIndex[chain][nodeIndex];
    m->tiProbsIndex[chain][nodeIndex] = m->tiProbsScratchIndex[nodeIndex];
    m->tiProbsScratchIndex[nodeIndex] = temp;
}





void FreeChainMemory (void)

{

    int			i, j, k, nRateCats;
    ModelInfo   *m;

    /* free model variables for Gibbs gamma */
    for (i=0; i<numCurrentDivisions; i++)
        {
        if (modelSettings[i].gibbsGamma == YES)
            {
            if (modelSettings[i].pInvar != NULL)
                nRateCats = modelSettings[i].numGammaCats + 1;
            else
                nRateCats = modelSettings[i].numGammaCats;
            for (j=0; j<numLocalChains; j++)
                {
                for (k=0; k<nRateCats; k++)
                    {
                    free(modelSettings[i].catLnScaler[j][k]);
                    free(modelSettings[i].catLike[j][k]);
                    }
                free (modelSettings[i].catLnScaler[j]);
                free (modelSettings[i].catLike[j]);
                }
            free (modelSettings[i].tiIndex);
            free (modelSettings[i].catLike);
            free (modelSettings[i].catLnScaler);
            }
        }

    /* free parsimony sets and node lens */
    for (i=0; i<numCurrentDivisions; i++)
        {
        m = &modelSettings[i];
        if (m->parsSets)
            {
            for (j=0; j<m->numParsSets; j++)
				free (m->parsSets[j]);
            free (m->parsSets);
            m->parsSets = NULL;
            }
        if (m->parsNodeLens)
            {
			free(m->parsNodeLens);
            m->parsNodeLens = NULL;
            }
        }

    /* free model variables for conditional likelihoods */
    for (i=0; i<numCurrentDivisions; i++)
        {
        m = &modelSettings[i];
        if (m->condLikes)
            {
            for (j=0; j<m->numCondLikes; j++)
                {
#if defined (SSE_ENABLED)
                if (m->useSSE == YES)
                    AlignedSafeFree ((void **)(&m->condLikes[j]));
                else
                    free (m->condLikes[j]);
#else
				free (m->condLikes[j]);
#endif
                }
            free (m->condLikes);
            m->condLikes = NULL;
            }

        if (m->scalers)
            {
            for (j=0; j<m->numScalers; j++)
#if defined (SSE_ENABLED)
            if (m->useSSE == YES)
                AlignedSafeFree ((void **)(&m->scalers[j]));
            else
                free (m->scalers[j]);
#else
				free (m->scalers[j]);

#endif
            free (m->scalers);
            m->scalers = NULL;
            }

        if (m->clP)
            {
			free (m->clP);
            m->clP = NULL;
            }
#if defined (SSE_ENABLED)
        if (m->useSSE == YES)
            {
            if (m->clP_SSE)
                {
			    free (m->clP_SSE);
                m->clP_SSE = NULL;
                }
            if (m->lnL_SSE)
                AlignedSafeFree ((void **)(&m->lnL_SSE));
            if (m->lnLI_SSE)
                AlignedSafeFree ((void **)(&m->lnLI_SSE));
            }
#endif

        if (m->tiProbs)
            {
            for (j=0; j<m->numTiProbs; j++)
				free (m->tiProbs[j]);
            free (m->tiProbs);
            m->tiProbs = NULL;
            }
                
        if (m->cijks)
            {
            for (j=0; j<numLocalChains+1; j++)
				free (m->cijks[j]);
            free (m->cijks);
            m->cijks = NULL;
            }

        if (m->condLikeIndex)
            {
            for (j=0; j<numLocalChains; j++)
				free (m->condLikeIndex[j]);
            free (m->condLikeIndex);
            m->condLikeIndex = NULL;
            }

        if (m->condLikeScratchIndex)
            {
			free (m->condLikeScratchIndex);
            m->condLikeScratchIndex=NULL;
            }

        if (m->tiProbsIndex)
            {
            for (j=0; j<numLocalChains; j++)
				free (m->tiProbsIndex[j]);
            free (m->tiProbsIndex);
            m->tiProbsIndex = NULL;
            }
        if (m->tiProbsScratchIndex)
            {
			free (m->tiProbsScratchIndex);
            m->tiProbsScratchIndex = NULL;
            }
        if (m->nodeScalerIndex)
            {
            for (j=0; j<numLocalChains; j++)
				free (m->nodeScalerIndex[j]);
            free (m->nodeScalerIndex);
            m->nodeScalerIndex = NULL;
            }
        if (m->nodeScalerScratchIndex)
            {
			free (m->nodeScalerScratchIndex);
            m->nodeScalerScratchIndex = NULL;
            }
        if (m->scalersSet)
            {
            for (j=0; j<numLocalChains; j++)
				free (m->scalersSet[j]);
            free (m->scalersSet);
            m->scalersSet = NULL;
            }
        if (m->scalersSetScratch)
            {
			free (m->scalersSetScratch);
            m->scalersSetScratch = NULL;
            }
        if (m->siteScalerIndex)
            {
			free (m->siteScalerIndex);
            m->siteScalerIndex = NULL;
            }
        if (m->cijkIndex)
            {
			free (m->cijkIndex);
            m->cijkIndex = NULL;
            }
        if (m->ancStateCondLikes)
            {
			free (m->ancStateCondLikes);
            m->ancStateCondLikes = NULL;
            }

#if defined (BEAGLE_ENABLED)
        if (m->useBeagle == NO)
            continue;

        beagleFinalizeInstance(m->beagleInstance);
        SafeFree((void **)(&m->logLikelihoods));
        SafeFree((void **)(&m->inRates));
        SafeFree((void **)(&m->branchLengths));
        SafeFree((void **)(&m->tiProbIndices));
        SafeFree((void **)(&m->inWeights));
        SafeFree((void **)(&m->bufferIndices));
        SafeFree((void **)(&m->eigenIndices));
        SafeFree((void **)(&m->childBufferIndices));
        SafeFree((void **)(&m->childTiProbIndices));
        SafeFree((void **)(&m->cumulativeScaleIndices));

		m->isScalerNodeScratch += numLocalTaxa;
		SafeFree((void **)&(m->isScalerNodeScratch)); 
		for (j=0; j<numLocalChains; j++)
			{
			m->isScalerNode[j] += numLocalTaxa;
			SafeFree((void **)&(m->isScalerNode[j]));
			}
		SafeFree((void **)(&m->isScalerNode));

		SafeFree((void **)(&m->beagleComputeCount));
		SafeFree((void **)(&m->succesCount));
		SafeFree((void **)(&m->rescaleFreq));

#endif
        }

    if (memAllocs[ALLOC_CURLNL] == YES) /*alloc in RunChain()*/
		{
		free (maxLnL0); 
		free (curLnL);
		memAllocs[ALLOC_CURLNL] = NO;
		}
    if (memAllocs[ALLOC_SS] == YES) /*alloc in mcmc()*/
		{
        free (marginalLnLSS);
        free (stepScalerSS);
        free (stepAcumulatorSS);
        free (splitfreqSS);
		memAllocs[ALLOC_SS] = NO;
		}
	if (memAllocs[ALLOC_CURLNPR] == YES) /*alloc in RunChain()*/
		{
		free (curLnPr); 
		memAllocs[ALLOC_CURLNPR] = NO;
		}
	if (memAllocs[ALLOC_CHAINID] == YES) /*alloc in RunChain()*/
		{
		free (chainId); 
		memAllocs[ALLOC_CHAINID] = NO;
		}
	if (memAllocs[ALLOC_USEDMOVES] == YES) /*alloc in setUsedMoves()*/
		{
		free (usedMoves);
		memAllocs[ALLOC_USEDMOVES] = NO;
		}
    if (memAllocs[ALLOC_TERMSTATE] == YES) /*alloc in SetUpTermState()*/
		{
		free (termState);
        termState = NULL;  
		memAllocs[ALLOC_TERMSTATE] = NO;
		}
    if (memAllocs[ALLOC_ISPARTAMBIG] == YES) /*alloc in SetUpTermState()*/
		{
		free (isPartAmbig);
        isPartAmbig = NULL;
		memAllocs[ALLOC_ISPARTAMBIG] = NO;
		}
    if (memAllocs[ALLOC_PRELIKES] == YES) /*alloc in InitCondLike()*/
		{
		free (preLikeL);
        preLikeL = NULL;
		memAllocs[ALLOC_PRELIKES] = NO;
		}
	if (memAllocs[ALLOC_RATEPROBS] == YES) /*alloc in InitAdGamma() not used */
		{
		free (rateProbSpace);
		free (rateProbs);
        rateProbs = NULL;
		memAllocs[ALLOC_RATEPROBS] = NO;
		}
	if (memAllocs[ALLOC_SITEJUMP] == YES) /*alloc in InitAdGamma() not used */
		{
		free (siteJump);
        siteJump = NULL;
		memAllocs[ALLOC_SITEJUMP] = NO;
		}
	if (memAllocs[ALLOC_MARKOVTIS] == YES)  /*alloc in InitAdGamma() not used */
		{
		for (i=0; i<MAX_SMALL_JUMP; i++)
			if (markovTi[i] != NULL)
				FreeSquareDoubleMatrix(markovTi[i]);
		FreeSquareDoubleMatrix(markovTiN);
		memAllocs[ALLOC_MARKOVTIS] = NO;
		}
	if (memAllocs[ALLOC_SWAPINFO] == YES) /*alloc in RunChain()*/
		{
		for (i=0; i<chainParams.numRuns; i++)
			FreeSquareIntegerMatrix(swapInfo[i]);
		free (swapInfo);
		memAllocs[ALLOC_SWAPINFO] = NO;
		}
	if (memAllocs[ALLOC_POSSELPROBS] == YES) /*alloc in PrintStates() <- RunChain()*/
		{
		free (posSelProbs);
		memAllocs[ALLOC_POSSELPROBS] = NO;
		}
	if (memAllocs[ALLOC_PFCOUNTERS] == YES) /*alloc in SetUpParitionCounters() <- RunChain()*/
		{
		free (partition[0]);
		free (partition);
		for (i=0; i<numTopologies; i++)
			Tfree (partFreqTreeRoot[i]);
		free (partFreqTreeRoot);
		memAllocs[ALLOC_PFCOUNTERS] = NO;
		}
	if (memAllocs[ALLOC_FILEPOINTERS] == YES) /* alloc in ( PreparePrintFiles(), ReusePreviousResults() ) <- RunChain() */
		{
		CloseMBPrintFiles ();
		if (fpTree != NULL)
			{
			free (fpTree[0]);
			free (fpTree);
			}
		if (fpParm != NULL)
			free (fpParm);
		fpParm = NULL;
		fpTree = NULL;
		fpMcmc = NULL;
        fpSS = NULL;
		memAllocs[ALLOC_FILEPOINTERS] = NO;
		}
	if (memAllocs[ALLOC_STATS] == YES) /* alloc in RunChain() */
		{
		if (chainParams.allComps == YES)
			{
			for (i=0; i<numTopologies; i++)
				FreeSquareDoubleMatrix (chainParams.stat[i].pair);
			}
		free (chainParams.stat);
		memAllocs[ALLOC_STATS] = NO;
		}
	if (memAllocs[ALLOC_DIAGNTREE] == YES)
		{
        FreeTree (chainParams.dtree);
		memAllocs[ALLOC_DIAGNTREE] = NO;
		}
	if (memAllocs[ALLOC_PRINTPARAM] == YES)
		{
		free (printParam);
		free (topologyPrintIndex);
		memAllocs[ALLOC_PRINTPARAM] = NO;
		}
	if (memAllocs[ALLOC_TFILEPOS] == YES)
		{
		free (chainParams.tFilePos);
		chainParams.tFilePos = NULL;
		memAllocs[ALLOC_TFILEPOS] = NO;
		}
	if (memAllocs[ALLOC_TREELIST] == YES)
		{
		for (i=0; i<chainParams.numRuns * numTopologies; i++)
			EraseTreeList (&chainParams.treeList[i]);
		free (chainParams.treeList);
		chainParams.treeList = NULL;
		memAllocs[ALLOC_TREELIST] = NO;
		}
    if (memAllocs[ALLOC_BEST] == YES)
        {
        FreeBestChainVariables();
        memAllocs[ALLOC_BEST] = NO;
        }
}





MrBFlt GetFitchPartials (ModelInfo *m, int chain, int source1, int source2, int destination)
{

    int         c, i;
    SafeLong    x[2], *pS1, *pS2, *pD;
    MrBFlt      length = 0.0;
    CLFlt       *nSitesOfPat;
    
    assert (m->nParsIntsPerSite <= 2 && m->nParsIntsPerSite > 0);
    assert (source1 >= 0 && source1 < m->numParsSets);
    assert (source2 >= 0 && source2 < m->numParsSets);
    assert (destination >= 0 && destination < m->numParsSets);

    /* find parsimony sets for the nodes */
    pS1 = m->parsSets[source1    ];
	pS2 = m->parsSets[source2    ];
    pD  = m->parsSets[destination];
		
	/* Find number of site patterns */
	nSitesOfPat = numSitesOfPat + ((1 % chainParams.numChains) * numCompressedChars) + m->compCharStart;//chainId[chain]

    if (m->nParsIntsPerSite == 1)
        {
        for (c=0; c<m->numChars; c++)
		    {
            x[0] = pS1[c] & pS2[c];
			if (x[0] == 0)
				{
                length += nSitesOfPat[c];
				x[0] = pS1[c] | pS2[c];
				}
			pD[c] = x[0];
			}
        }
    else /* if (m->nParsIntsPerSite == 2) */
        {
        assert(m->nParsIntsPerSite == 2);
        for (c=i=0; c<m->numChars; c++)
		    {
            x[0] = pS1[i]   & pS2[i];
            x[1] = pS1[i+1] & pS2[i+1];
			if ((x[0] | x[1]) == 0)
				{
                length += nSitesOfPat[c];
                x[0] = pS1[i]   | pS2[i];
                x[1] = pS1[i+1] | pS2[i+1];
				}
			pD[i++] = x[0];
            pD[i++] = x[1];
			}
        }

    return length;
}





MrBFlt GetParsDP (Tree *t, TreeNode *p, int chain)

{
	
	int				n, division;
    MrBFlt          length;
	ModelInfo		*m;

    length = 0.0;
    if (p->left != NULL)
		{
		length += GetParsDP (t, p->left, chain);
		length += GetParsDP (t, p->right, chain);

		for (n=0; n<t->nRelParts; n++)
			{
			division = t->relParts[n];
			
			/* Find model settings */
			m = &modelSettings[division];

			/* Get Fitch partials and length */
			length += GetFitchPartials(m,
                                       chain,
                                       p->left->index,
                                       p->right->index,
                                       p->index);
 		
			}
		}

    return length;
}





void GetParsFP (Tree *t, TreeNode *p, int chain)

{
	
	int				i, c, n, division;
	SafeLong		*pL, *pR, *pP, *pA, x[2];
	ModelInfo		*m;

	if (p->left != NULL)
		{
		for (n=0; n<t->nRelParts; n++)
			{
			division = t->relParts[n];
			
			/* Find model settings */
			m = &modelSettings[division];
            assert (m->nParsIntsPerSite == 1 || m->nParsIntsPerSite == 2);

			/* find parsimony sets for the node and its environment */
			pL   = m->parsSets[p->left->index ];
			pR   = m->parsSets[p->right->index];
            pP   = m->parsSets[p->index       ];
            pA   = m->parsSets[p->anc->index  ];
            
            if (m->nParsIntsPerSite == 1)
                {
			    for (c=0; c<m->numChars; c++)
				    {
				    x[0] = pP[c] & pA[c];

				    if (x[0] != pA[c])
					    {/*means that we allow change of state from p to a*/
					    if ((pL[c] & pR[c]) != 0)
						    x[0] = ((pL[c] | pR[c]) & pA[c]) | pP[c] ;/*we still allow only one change from both children of p through p to a. So state from a  that belong to one of the children of p can be added to pP[c], if p assume the state then the only change would be on the other child. */
					    else
						    x[0] = pP[c] | pA[c]; /*Here we allow two change from both children of p through p to a *//*adding pA[c] to pP[c] means that if p assume state exclusive in a theneven if both children will be in different state from p we still get optimal parsimony*/
					    }
				    pP[c] = x[0];
				    }
			    }
            else /* if (m->nParsIntsPerSite == 2) */
                {
                for (c=i=0; c<m->numChars; c++)
		            {
                    x[0] = pP[i]   & pA[i];
                    x[1] = pP[i+1] & pA[i+1];
			        if (x[0] != pA[i] || x[1] != pA[i+1])
				        {
                        x[0] = pL[i] & pR[i];
                        x[1] = pL[i+1] & pR[i+1];
                        if ((x[0] | x[1]) != 0)
                            {
					        x[0] = ((pL[i] | pR[i]) & pA[i]) | pP[i] ;
					        x[1] = ((pL[i+1] | pR[i+1]) & pA[i+1]) | pP[i+1] ;
                            }
                        else
                            {
					        x[0] = pP[i] | pA[i];
					        x[1] = pP[i+1] | pA[i+1];
                            }
				        }
			        pP[i++] = x[0];
                    pP[i++] = x[1];
			        }
                }
            }
		GetParsFP (t, p->left, chain);
		GetParsFP (t, p->right, chain);
		}
}





int GetParsimonyBrlens (Tree *t, int chain, MrBFlt *brlens)

{
	
	int				c, i, j, n, division;
	SafeLong		*pP, *pA;
	CLFlt			*nSitesOfPat;
	TreeNode        *p;
	ModelInfo		*m;

	/* Reset all brlens */
	for (i=0; i<t->nNodes-1; i++)
		brlens[i] = 0.0;
	
	/* Get final parsimony state sets */
    GetParsDP(t, t->root->left, chain);
    GetParsFP(t, t->root, chain);
    
    /* Get all branch lengths, looping over divisions */
	for (n=0; n<t->nRelParts; n++)		
		{
		division = t->relParts[n];

		/* Find model settings */
		m = &modelSettings[division];

		/* Find number of site patterns */
		nSitesOfPat = numSitesOfPat + ((chainId[chain] % chainParams.numChains) * numCompressedChars) + m->compCharStart;

		/* Record branch lengths in downpass */
		for (i=0; i<t->nNodes-1; i++)
			{
			p = t->allDownPass[i];

			/* Find final-pass parsimony sets for the node and its ancestor */
			pP    = m->parsSets[p->index     ];
			pA    = m->parsSets[p->anc->index];
            
			if (m->nParsIntsPerSite == 1)
                {
                for (c=0; c<m->numChars; c++)
			        {
			        if ((pP[c] & pA[c]) == 0)
				        brlens[i] += nSitesOfPat[c];
			        }
                }
            else
                {
                for (c=j=0; c<m->numChars; c++, j+=2)
			        {
			        if ((pP[j] & pA[j]) == 0 && (pP[j+1] & pA[j+1]) == 0)
				        brlens[i] += nSitesOfPat[c];
			        }
                }
			}
		}

	return (NO_ERROR);

}





MrBFlt GetParsimonyLength (Tree *t, int chain)

{
	
	int				c, i, n, division;
	SafeLong		*pP, *pA;
	CLFlt			*nSitesOfPat;
	MrBFlt			length;
	TreeNode		*p;
	ModelInfo		*m;

    /* Get length down to internal root */
	length = GetParsDP(t, t->root->left, chain);

    /* return if rooted */
    if (t->isRooted == NO)
        return length;

    /* add in the last terminal if not rooted */
    for (n=0; n<t->nRelParts; n++)		
		{
		division = t->relParts[n];

		/* Find model settings */
		m = &modelSettings[division];

		/* Find number of site patterns */
		nSitesOfPat = numSitesOfPat + ((chainId[chain] % chainParams.numChains) * numCompressedChars) + m->compCharStart;

		/* Deal with last branch */
		p = t->intDownPass[t->nIntNodes-1];

		/* find downpass parsimony sets for the node and its environment */
		pP    = m->parsSets[p->index     ];
		pA    = m->parsSets[p->anc->index];
        
        if (m->nParsIntsPerSite == 1)
            {
            for (c=0; c<m->numChars; c++)
		        {
		        if ((pP[c] & pA[c]) == 0)
			        {
			        length += nSitesOfPat[c];
			        }
		        }
            }
        else /* if (m->nParsIntsPerSite == 2) */
            {
            for (c=i=0; c<m->numChars; c++, i+=2)
		        {
		        if ((pP[i] & pA[i]) == 0 && (pP[i+1] & pA[i+1]) == 0)
			        {
			        length += nSitesOfPat[c];
			        }
		        }
            }
		}

	return length;

}





void GetParsimonySubtreeRootstate (Tree *t, TreeNode *root, int chain)

{
	
	int				c, i, n, division;
	SafeLong        *pD, *pP, *pA, x[2];
	TreeNode		*p;
	ModelInfo		*m;

	/* Loop over divisions */
	for (n=0; n<t->nRelParts; n++)
		{
		division = t->relParts[n];
			
		/* Find model settings */
		m = &modelSettings[division];
        assert (m->nParsIntsPerSite == 1 || m->nParsIntsPerSite == 2);

		for (i=0; i<t->nNodes; i++)
			{
			p = t->allDownPass[i];
			p->marked = NO;
			}

		p = root;
		while (p->anc != NULL)
			{
			p->marked = YES;
			p = p->anc;
			}

		/* Make uppass node by node */
		for (i=t->nIntNodes-1; i>=0; i--)
			{
			p = t->intDownPass[i];

			/* continue if no work needs to be done */
			if (p->marked == NO)
				continue;

			/* find downpass and uppass parsimony sets for the node and its environment */
			pP     = m->parsSets[p->index       ];
            if (p->left->marked == YES)
				pD = m->parsSets[p->right->index];
            else
				pD = m->parsSets[p->left->index ];
            pA     = m->parsSets[p->anc->index  ];
            
			if (m->nParsIntsPerSite == 1)
                {
                for (c=0; c<m->numChars; c++)
			        {
			        x[0] = pD[c] & pA[c];
			        if (x[0] == 0)
				        {
				        x[0] = (pD[c] | pA[c]);
				        }
			        pP[c] = x[0];
			        }
                }
            else if (m->nParsIntsPerSite == 2)
                {
                for (c=i=0; c<m->numChars; c++, i+=2)
			        {
			        x[0] = pD[i  ] & pA[i  ];
			        x[1] = pD[i+1] & pA[i+1];
			        if (x[0] + x[1] == 0)
				        {
				        x[0] = (pD[i  ] | pA[i  ]);
				        x[1] = (pD[i+1] | pA[i+1]);
				        }
			        pP[i  ] = x[0];
			        pP[i+1] = x[1];
			        }
                }
			if (p == root)
				break;
			}
		}

}





/* GetRate: retrieve the base rate for the division and chain in current state */
MrBFlt GetRate (int division, int chain)

{

	Param	*p;
	MrBFlt	*values, rate;
	int		i;

    rate = 0.0;

    p = modelSettings[division].rateMult;
	values = GetParamVals (p, chain, state[chain]);
	if (p->nValues == 1)
		rate = values[0];
    else
        {
	    for (i=0; i<p->nRelParts; i++)
		    {
		    if (p->relParts[i] == division)
                {
			    rate = values[i];
                break;
                }
		    }
        }

    p = modelSettings[division].geneTreeRateMult;
    if (p != NULL)
        {
	    values = GetParamVals (p, chain, state[chain]);
	    for (i=0; i<p->nRelParts; i++)
		    {
		    if (p->relParts[i] == division)
                {
			    rate *= values[i];
                break;
                }
		    }
        }
    
    return rate;

}





void GetStamp (void)

{

	int		i;

    for (i=0; i<10; i++)
        stamp[i] = '0' + (int)(RandomNumber(&runIDSeed) * 10);
    stamp[10] = '\0';

    MrBayesPrint ("%s   MCMC stamp = %s\n", spacer, stamp);
}





void GetSwappers (int *swapA, int *swapB, int run)

{

	int			i;
	
	/* this works for both the serial and parallel versions because the swapSeed is identical for all
		processors, ensuring they all get the same sequence of chainIds to swap */
#	if defined (MPI_ENABLED)

	/* For now, we wonly allow random swaps in the MPI version. Other schemes require
	   tagging of messages, or a dedicated server node doing message processing.      */
	(*swapA) = (int) (RandomNumber(&swapSeed) * chainParams.numChains);
	(*swapB) = (int) (RandomNumber(&swapSeed) * (chainParams.numChains - 1));
	if ((*swapB) == (*swapA))
		(*swapB) = chainParams.numChains - 1;

#	else

	if (chainParams.swapAdjacentOnly == NO)
		{
		(*swapA) = (int) (RandomNumber(&swapSeed) * chainParams.numChains);
		(*swapB) = (int) (RandomNumber(&swapSeed) * (chainParams.numChains - 1));
		if ((*swapB) == (*swapA))
			(*swapB) = chainParams.numChains - 1;
		}
	else
		{
		(*swapA) = (int) (RandomNumber(&swapSeed) * (chainParams.numChains - 1));
		(*swapB) = (*swapA) + 1;
		}
#   endif

	i = run * chainParams.numChains;
	(*swapA) += i;
	(*swapB) += i;

	return;
}





void GetTempDownPassSeq (TreeNode *p, int *i, TreeNode **dp)

{
	
	if (p != NULL)
		{
		GetTempDownPassSeq (p->left,  i, dp);
		GetTempDownPassSeq (p->right, i, dp);
		dp[(*i)++] = p;
		}
		
}





MrBFlt GibbsSampleGamma (int chain, int division, SafeLong *seed)
{

	int				c, i, k, *rateCat, nStates, nRateCats, nGammaCats, id;
	CLFlt			**catLike, **catLnScaler, *lnScaler, maxLnScaler,
					*clRoot, f, bs[64], *clInvar, pInvar, freq;
	MrBFlt			ran, lnL, *bsVals, deltaLnL, temp;
	ModelInfo		*m;
	Tree			*t;
	TreeNode		*p;

	m = &modelSettings[division];

	/* find base frequencies */
	bsVals = GetParamSubVals (m->stateFreq, chain, state[chain]);
	nStates = m->numModelStates;
	for (i=0; i<nStates; i++)
		bs[i] = (CLFlt) bsVals[i];

	/* find tree scaler */
    lnScaler = m->scalers[m->siteScalerIndex[chain]];
    
	/* find category like array and associated sccaler */
	catLike = m->catLike[chain];
	catLnScaler = m->catLnScaler[chain];
	
	/* find rate category index */
	rateCat = m->tiIndex + chain*m->numChars;
	
	/* find number of rate cats and gamma cats */
	nRateCats = nGammaCats = m->numGammaCats;
	if (m->pInvar != NULL)
		nRateCats++;

	/* find tree */
	t = GetTree (m->brlens, chain, state[chain]);

	/* find invar cond likes (if we have invariable rate category) */
	clInvar = m->invCondLikes;

	/* get pInvar */
	if (m->pInvar == NULL)
		pInvar = 0.0;
	else
		pInvar = (CLFlt) *GetParamVals (m->pInvar, chain, state[chain]);
	freq = ((CLFlt)1.0 - pInvar) / nGammaCats;

	/* get chain temperature */
	temp = Temperature (chainId[chain]);
	id = chainId[chain] % chainParams.numChains;

	/* calculate rate probs */
	for (k=0; k<nGammaCats; k++)
		{
        FlipSiteScalerSpace(m, chain);
        ResetSiteScalers(m, chain);
		for (c=0; c<m->numChars; c++)
			rateCat[c] = k;
		for (i=0; i<t->nIntNodes; i++)
			{
			p = t->intDownPass[i];
			if (t->isRooted == NO && p->anc->anc == NULL)
				m->CondLikeRoot (p, division, chain);
			else
				m->CondLikeDown (p, division, chain);
			if (p->scalerNode == YES)
				m->CondLikeScaler (p, division, chain);
			}
		/* find root conditional likes */
		p = t->root->left;
		clRoot = m->condLikes[m->condLikeIndex[chain][p->index]];
        for (c=0; c<m->numChars; c++)
			{
			catLike[k][c] = 0.0;
			for (i=0; i<nStates; i++)
				catLike[k][c] += bs[i]*clRoot[i];
			catLike[k][c] *= freq;
			catLnScaler[k][c] = lnScaler[c];
			clRoot += nStates;
			}
        FlipSiteScalerSpace(m, chain);
		}

	/* fill in the invar cond likes if needed */
	if (m->pInvar != NULL)
		{
		k = nGammaCats;
		for (c=0; c<m->numChars; c++)
			{
			catLike[k][c] = 0.0;
			for (i=0; i<nStates; i++)
				catLike[k][c] += bs[i]*clInvar[i];
			catLike[k][c] *= pInvar;
			clInvar += nStates;
			catLnScaler[k][c] = 0.0;
			}
		}

	/* Now Gibbs sample the rate categories */
	for (c=0; c<m->numChars; c++)
		{
		/* find max scaler */
		maxLnScaler = catLnScaler[0][c];
		for (k=1; k<nRateCats; k++)
			{
			if (catLnScaler[k][c] > maxLnScaler && catLike[k][c] > 0.0)
				maxLnScaler = catLnScaler[k][c];
			}
		/* scale values */
		for (k=0; k<nRateCats; k++)
			{
			f = catLnScaler[k][c] - maxLnScaler;
			if (f < -100.0)
				catLike[k][c] = 0.0;
			else
				{
				catLike[k][c] *= (CLFlt) exp (f);
				/* take the temperature into account */
				if (id != 0)
					catLike[k][c] = (CLFlt) pow(catLike[k][c], temp);
				}
			}
		/* get cumulative sum */
		for (k=1; k<nRateCats; k++)
			catLike[k][c] += catLike[k-1][c];
		/* randomly sample a category; multiply by total to avoid scaling probs */
		ran = RandomNumber (seed) * catLike[nRateCats-1][c];
		for (k=0; k<nRateCats; k++)
			{
			if (ran < catLike[k][c])
				break;
			}
		rateCat[c] = k;
		}

	/* recalculate everything */
    FlipSiteScalerSpace(m, chain);
    ResetSiteScalers(m, chain);
	for (i=0; i<t->nIntNodes; i++)
		{
		p = t->intDownPass[i];
		if (t->isRooted == NO && p->anc->anc == NULL)
			m->CondLikeRoot (p, division, chain);
		else
			m->CondLikeDown (p, division, chain);
		if (p->scalerNode == YES)
			m->CondLikeScaler (p, division, chain);
		}
	lnL = 0.0;
	m->Likelihood (t->root->left, division, chain, &lnL, (chainId[chain] % chainParams.numChains));
	
	deltaLnL = lnL - m->lnLike[2*chain + state[chain]];
	m->lnLike[2*chain + state[chain]] =  lnL;

	return (deltaLnL);
}





/*------------------------------------------------------------------------
|
|	InitAdGamma: initialize variables for adgamma model.
|
-------------------------------------------------------------------------*/
int InitAdGamma (void)
{
    int         d, c, i, j, k, maxRates, *corrModel;
    ModelInfo   *m;
    
	/* take care of adgamma model */
	if (chainHasAdgamma == NO)
        return (NO_ERROR);
    
    MrBayesPrint ("%s   Initializing autocorrelated discrete gamma model\n", spacer);
    
    /* allocate corr space */
    corrModel = (int *) SafeCalloc (numCurrentDivisions, sizeof(int));
    if (!corrModel)
        return ERROR;
    
    /* allocate siteJump */
    if (memAllocs[ALLOC_SITEJUMP] == YES)
        {
        MrBayesPrint ("%s   siteJump not free in InitAdGamma\n", spacer);
        free (corrModel);
        return ERROR;
        }
    siteJump = (int *) SafeCalloc (numChar, sizeof(int));
    if (siteJump)
        memAllocs[ALLOC_SITEJUMP] = YES;
    else
        {
        MrBayesPrint ("%s   Problem allocating siteJump in InitAdGamma (%d ints)\n", spacer, numChar);
        free (corrModel);
        return ERROR;
        }
    
    /* reset vector indicating the matrices needed */
    for (i=0; i<MAX_SMALL_JUMP; i++)
        hasMarkovTi[i] = NO;
    
    /* fill in siteJump */
    for (i=0; i<numCurrentDivisions; i++)
        corrModel[i] = 0;

    k = 1;	/* index to corr model, 0 means no corr model */
    maxRates = 0;	/* max no. rates */
    for (d=0; d<numCurrentDivisions; d++)
        modelSettings[d].mark = NO;

    for (d=0; d<numCurrentDivisions; d++)
        {
        m = &modelSettings[d];
        
        if (m->correlation == NULL || m->mark == YES)
            continue;
        
        m->mark = YES;
        for (i=0; i<m->correlation->nRelParts; i++)
            {
            if (modelSettings[m->correlation->relParts[i]].shape == 
                modelSettings[d].shape)
                {
                modelSettings[m->correlation->relParts[i]].mark = YES;
                corrModel[m->correlation->relParts[i]] = k;
                }
            }
        k++;

        if (m->numGammaCats > maxRates)
            maxRates = m->numGammaCats;

        }

    for (c=0; c<numChar; c++)
        {
        if (charInfo[c].isExcluded == YES)
            continue;
        
        if ((k=corrModel[partitionId[c][partitionNum] - 1]) == 0)
            continue;

        /* How far back is last char in this HMM? */
        for (j=c-1; j>=0; j--)
            {
            if (corrModel[partitionId[j][partitionNum] - 1] == k)
                break;
            }

        if (j<0)
            siteJump[c] = 0;
        else if (charInfo[j].bigBreakAfter == YES)
            siteJump[c] = BIG_JUMP;
        else
            {
            siteJump[c] = c - j;
            hasMarkovTi[c-j-1] = YES;
            }
        }

    /* check if any HMM is empty */
    k=0;
    for (i=0; i<numCurrentDivisions; i++)
        {
        if (corrModel[i] > k)
            k = corrModel[i];
        }
    for (i=1; i<=k; i++)
        {
        for (c=j=0; c<numChar; c++)
            {
            if (charInfo[c].isExcluded == NO && corrModel[partitionId[c][partitionNum] - 1] == i)
                j = c;
            }
        if (j == 0)
            {
            MrBayesPrint ("%s   ERROR: HMM model %d is empty.\n",spacer,i);
            free (corrModel);
            return (ERROR);
            }
        }

    /* allocate MarkovTis (space needed for calculations) */
    if (memAllocs[ALLOC_MARKOVTIS] == YES)
        {
        MrBayesPrint ("%s   markovTis not free in InitAdGamma\n", spacer);
        free (corrModel);
        return ERROR;
        }

    for (i=0; i<MAX_SMALL_JUMP; i++)
        {
        if (hasMarkovTi[i] == YES || i == 0)	/* base matrix always needed */
            {
            markovTi[i] = AllocateSquareDoubleMatrix(maxRates);
            if (markovTi[i] == NULL)
                break;
            }
        else
            markovTi[i] = NULL;
        }

    markovTiN = AllocateSquareDoubleMatrix(maxRates);
    if (i >= MAX_SMALL_JUMP && markovTiN)
        memAllocs[ALLOC_MARKOVTIS] = YES;
    else
        {
        MrBayesPrint ("%s   Problem allocating MarkovTis in InitAdGamma (%d MrBFlt)\n", spacer, 2 * MAX_GAMMA_CATS * MAX_GAMMA_CATS);
        for (i=0; i<MAX_SMALL_JUMP; i++)
            if (markovTi[i] != NULL) 
                FreeSquareDoubleMatrix (markovTi[i]);
        if (markovTiN != NULL) 
            FreeSquareDoubleMatrix(markovTiN);
        free (corrModel);
        return ERROR;
        }

	/* allocate space for rateProbs needed by adgamma model */

    /* calculate size needed */
    i = 0;
    for (j=0; j<numCurrentDivisions; j++)
        {
        m = &modelSettings[j];
        if (m->correlation != NULL)
            {
            m->rateProbStart = i;
            i += m->numGammaCats * m->numChars;
            }
        }
    rateProbRowSize = i;

    /* allocate space */
    if (memAllocs[ALLOC_RATEPROBS] == YES)
        {
        MrBayesPrint ("%s   Space for rate probs not free in InitAdGamma\n", spacer);
        free (corrModel);
        return ERROR;
        }
    rateProbSpace = (MrBFlt *) SafeMalloc (2 * numLocalChains * rateProbRowSize * sizeof(MrBFlt));
    rateProbs = (MrBFlt **) SafeMalloc (numLocalChains * sizeof(MrBFlt *));
    if (!rateProbSpace || !rateProbs)
        {
        MrBayesPrint ("%s   Problem allocating rate probs\n", spacer);
        if (rateProbSpace) 
            free (rateProbSpace);
        if (rateProbs) 
            free (rateProbs);
        free (corrModel);
        return ERROR;
        }
    else
        memAllocs[ALLOC_RATEPROBS] = YES;

    /* set chain rateProbs pointers */
    for (i=j=0; i<numLocalChains; i++)
        {
        rateProbs[i] = rateProbSpace + j;
        j += 2 * rateProbRowSize;
        }

    free (corrModel);

    return (NO_ERROR);
}





/*------------------------------------------------------------------------
|
|	InitAugmentedModels: allocate and initialize space for augmented
|      models
|
-------------------------------------------------------------------------*/
int InitAugmentedModels (void)
{
    int         d, i, j, useAugmentedModels, nRateCats;
    ModelInfo   *m;

    useAugmentedModels = NO;
	for (d=0; d<numCurrentDivisions; d++)
        {
		if (modelSettings[d].gibbsGamma == YES)
		        useAugmentedModels = YES;
        }
    
    if (useAugmentedModels == NO)
        return (NO_ERROR);
    
    MrBayesPrint ("%s   Initializing variables for model augmentation\n", spacer);
    
	for (d=0; d<numCurrentDivisions; d++)
		{
		m = &modelSettings[d];
		if (m->gibbsGamma == NO)
		        continue;
		m->tiIndex = (int *) SafeMalloc (numLocalChains * m->numChars * sizeof (int));
        if (!m->tiIndex)
            return ERROR;
		m->catLike = (CLFlt ***) SafeMalloc (numLocalChains * sizeof (CLFlt **));
        if (!m->catLike)
            return ERROR;
		m->catLnScaler = (CLFlt ***) SafeMalloc (numLocalChains * sizeof (CLFlt **));
        if (!m->catLnScaler)
            return ERROR;
		if (m->pInvar == NULL)
			nRateCats = m->numGammaCats;
		else
			nRateCats = m->numGammaCats + 1;
		for (i=0; i<numLocalChains; i++)
			{
			m->catLike[i] = (CLFlt **) SafeCalloc (nRateCats, sizeof (CLFlt *));
            if (!m->catLike[i])
                return ERROR;
			m->catLnScaler[i] = (CLFlt **) SafeCalloc (nRateCats, sizeof (CLFlt *));
            if (!m->catLnScaler[i])
                return ERROR;
			for (j=0; j<nRateCats; j++)
				{
				m->catLike[i][j] = (CLFlt *) SafeCalloc (m->numChars, sizeof (CLFlt));
                if (!m->catLike[i][j])
                    return ERROR;
				m->catLnScaler[i][j] = (CLFlt *) SafeCalloc (m->numChars, sizeof (CLFlt));
                if (!m->catLnScaler[i][j])
                    return ERROR;
				}
			}
		}

	return NO_ERROR;
}


/*------------------------------------------------------------------------
|
|	InitChainCondLikes: (1) calculate size of cond like arrays, tiprob arrays
|       and scaler arrays; (2) allocate space for cond like, tiprob and
|		scaler arrays; (3) allocate and set node indices pointing to
|       cond like and scaler arrays; (4) initialize tip cond likes;
|		(5) allocate space for precalculated cond likes;
|
-------------------------------------------------------------------------*/
int InitChainCondLikes (void)

{

	int			c, d, i, j, k, s, t, numReps, condLikesUsed, nIntNodes, nNodes, useBeagle,
                clIndex, tiIndex, scalerIndex, indexStep;
	SafeLong	*charBits;
	CLFlt		*cL;
	ModelInfo	*m;
#if defined (SSE_ENABLED)
    int         j1;
#endif
#if defined (BEAGLE_ENABLED)
    double      *nSitesOfPat;
    MrBFlt      freq;
#endif

    /* Figure out how large cond like array is needed, and how many cond like, scaler and tiprob arrays are needed.
       Also check for possible use of Beagle */
    condLikesUsed = NO;
	for (d=0; d<numCurrentDivisions; d++)
		{
		m = &modelSettings[d];

		MrBayesPrint ("%s   Division %d has %d unique site patterns\n", spacer, d+1, m->numChars);

		m->condLikeLength = 0;
        m->numCondLikes = 0;

		if (m->parsModelId == YES)
			continue;

		condLikesUsed = YES;

        /* figure out length of cond like array */
        if (m->dataType == STANDARD)
			{
#if defined (BEAGLE_ENABLED)
            m->useBeagle = NO;
#endif
            for (c=0; c<m->numChars; c++)
				{
				numReps = m->numGammaCats;
				if (m->nStates[c] == 2)
					numReps *= m->numBetaCats;
				m->condLikeLength += m->nStates[c] * numReps;
				}
			}
		else
			{
			if (m->gibbsGamma == YES)
				m->condLikeLength = m->numChars * m->numModelStates;
			else
				m->condLikeLength = m->numChars * m->numGammaCats * m->numOmegaCats * m->numModelStates;
#if defined (BEAGLE_ENABLED)
            /* tentatively decide on whether to use Beagle */
            if( tryToUseBEAGLE == YES )
                {
                if ( m->printAncStates == YES || m->printSiteRates == YES ||m->printPosSel ==YES ||m->printSiteOmegas==YES )
		            {
		            MrBayesPrint ("%s   Non-beagle version of conditional liklihood calculator will be used for devision %d due to request\n", spacer, d+1);
                    MrBayesPrint ("%s   of reprting 'ancestaral states', 'site rates', 'pos selection' or 'site omegas'.\n", spacer);
		            }                
                else if (m->gibbsGamma == NO)
                    m->useBeagle = YES;
                }
#endif
			}
        
        /* find size of tree */
        nIntNodes = GetTree(m->brlens, 0, 0)->nIntNodes;
        nNodes = GetTree(m->brlens, 0, 0)->nNodes;

        /* figure out number of cond like arrays */
        m->numCondLikes = (numLocalChains + 1) * (nIntNodes);
        m->numCondLikes += numLocalTaxa;
		/*
#if !defined (DEBUG_NOSHORTCUTS)
        for (i=0; i<numLocalTaxa; i++)
            {
            if (m->isPartAmbig[i] == NO && m->dataType != STANDARD)
                m->numCondLikes--;
            }
#endif
		*/

        /* figure out number of node and site scalers */
        m->numScalers = (numLocalChains + 1) * (nIntNodes + 1);   /* add 1 for site scalers */

        /* figure out length of ti prob array and number of ti prob arrays */
        m->tiProbLength = 0;
        if (m->dataType == STANDARD)
            {
            m->numTiCats = 0;   /* We do not have repeated similar transition probability matrices */
			if (m->stateFreq->paramId == SYMPI_EQUAL)
				{
				for (k=0; k<9; k++)
					{
					if (m->isTiNeeded[k] == YES)
						m->tiProbLength += (k + 2) * (k + 2) * m->numGammaCats;
					}
				for (k=9; k<13; k++)
					{
					if (m->isTiNeeded[k] == YES)
						m->tiProbLength += (k - 6) * (k - 6) * m->numGammaCats;
					}
				for (k=13; k<18; k++)
					{
					if (m->isTiNeeded[k] == YES)
						 m->tiProbLength += (k - 11) * (k - 11) * m->numGammaCats;
					}
				}
			else
				{
				/* deal with unequal state frequencies */
				if (m->isTiNeeded[0] == YES)
					m->tiProbLength += 4 * m->numGammaCats * m->numBetaCats;
				for (c=0; c<m->numChars; c++)
					{
					if (m->nStates[c] > 2 && (m->cType[c] == UNORD || m->cType[c] == ORD))
						{
						m->tiProbLength += (m->nStates[c] * m->nStates[c]) * m->numGammaCats;
						}
					}
				}
            }
        else
            {
            m->numTiCats    = m->numGammaCats * m->numBetaCats * m->numOmegaCats;   /* A single partition has either gamma, beta or omega categories */
            m->tiProbLength = m->numModelStates * m->numModelStates * m->numTiCats;
            }
        m->numTiProbs = (numLocalChains + 1) * nNodes;
        
		/* set info about eigen systems */
        if (InitEigenSystemInfo (m) == ERROR)
            return (ERROR);
        }

	/* check if conditional likelihoods are needed */
	if (condLikesUsed == YES)
		MrBayesPrint ("%s   Initializing conditional likelihoods\n", spacer);
	else
		return NO_ERROR;

	/* allocate space and fill in info for tips */
    for (d=0; d<numCurrentDivisions; d++)
        {
        m = &modelSettings[d];
       
        /* allocate space for conditional likelihoods */
        useBeagle = NO;
#if defined (BEAGLE_ENABLED)
        if (m->useBeagle == YES)
            {
            if (InitBeagleInstance(m, d) != ERROR)
                useBeagle = YES;
            else
                m->useBeagle = NO;
            }
#endif
        //m->useSSE = NO;
#if defined (SSE_ENABLED)
        /*if (useBeagle == NO && m->dataType != STANDARD)
            m->useSSE = YES;*/
        if (useBeagle == YES)
            m->useSSE = NO;

#endif
        if (useBeagle == NO && m->useSSE == NO)
            MrBayesPrint ("%s   Using standard non-SSE likelihood calculator for division %d (%s-precision)\n", spacer, d+1, (sizeof(CLFlt) == 4 ? "single" : "double"));
        else if (useBeagle == NO && m->useSSE == YES)
            MrBayesPrint ("%s   Using standard SSE likelihood calculator for division %d (single-precision)\n", spacer, d+1);


        if (useBeagle == NO)
            {
            /* allocate cond like space */
            m->condLikes = (CLFlt**) SafeMalloc(m->numCondLikes * sizeof(CLFlt*));
            if (!m->condLikes)
                return (ERROR);
            for (i=0; i<m->numCondLikes; i++)
                {
#if defined (SSE_ENABLED)
                if (m->useSSE == YES)
                    {
                    /* calculate number SSE chars */
                    m->numSSEChars = ((m->numChars - 1) / FLOATS_PER_VEC) + 1;

                    /* allocate space with padding (m->condLikeLength is without padding) */
                    if (m->gibbsGamma == YES)
                        numReps = 1;
                    else
                        numReps = m->numGammaCats * m->numOmegaCats;
                    k = m->numSSEChars * FLOATS_PER_VEC * m->numModelStates * numReps;
                    
#if defined (MS_VCPP_SSE)
					m->condLikes[i] = (CLFlt*) ALIGNED_MALLOC(k * sizeof(CLFlt), 16);
#else
					ALIGNED_MALLOC((void **)(&m->condLikes[i]), 16, k * sizeof(CLFlt));
#endif
                    if (!m->condLikes[i])
                        return (ERROR);

                    /* start by filling all with 0.0f; pad when filling in tips */
                    for (j=0; j<k; j++)
                        m->condLikes[i][j] = 0.0f;
                    }
                else
                    {
                    m->condLikes[i] = (CLFlt*) SafeMalloc(m->condLikeLength * sizeof(CLFlt));
                    if (!m->condLikes[i])
                        return (ERROR);
                    }
#else
                m->condLikes[i] = (CLFlt*) SafeMalloc(m->condLikeLength * sizeof(CLFlt));
                if (!m->condLikes[i])
                    return (ERROR);
#endif
                }

            /* allocate scaler space and pointers for scaling */
            m->scalers = (CLFlt**) SafeMalloc(m->numScalers * sizeof(CLFlt*));
            if (!m->scalers)
                return (ERROR);
            for (i=0; i<m->numScalers; i++)
                {
#if defined (SSE_ENABLED)
                if (m->useSSE == YES)
                    {
                    /* allocate space with padding */
#if defined (MS_VCPP_SSE)
                    m->scalers[i] = (CLFlt*) ALIGNED_MALLOC(m->numSSEChars * FLOATS_PER_VEC * sizeof(CLFlt), 16);
#else
                    ALIGNED_MALLOC((void **)(&(m->scalers[i])), 16, m->numSSEChars * FLOATS_PER_VEC * sizeof(CLFlt));
#endif
                    if (!m->scalers[i])
                        return (ERROR);
                    for (j=0; j<m->numSSEChars*FLOATS_PER_VEC; j++)
                        m->scalers[i][j] = 0.0f;
                    }
                else
                    {
                    m->scalers[i] = (CLFlt*) SafeMalloc (m->numChars * sizeof(CLFlt));
                    if (!m->scalers[i])
                        return (ERROR);
                    }
#else
                m->scalers[i] = (CLFlt*) SafeMalloc (m->numChars * sizeof(CLFlt));
                if (!m->scalers[i])
                    return (ERROR);
#endif
                }

            /* allocate stuff for facilitating scaling and accumulation of cond likes */
			if (m->dataType == STANDARD)
				{
				m->clP = (CLFlt **) SafeMalloc(m->numGammaCats * sizeof(CLFlt *));
				if (!m->clP)
					return (ERROR);
				}
			else
				{
				m->clP = (CLFlt **) SafeMalloc(m->numTiCats * sizeof(CLFlt *));
				if (!m->clP)
					return (ERROR);
#if defined (SSE_ENABLED)
				if (m->useSSE == YES)
                    {
                    m->clP_SSE = (__m128 **) SafeMalloc(m->numTiCats * sizeof(__m128 *));
				    if (!m->clP_SSE)
					    return (ERROR);
#if defined (MS_VCPP_SSE)
				    m->lnL_SSE  = ALIGNED_MALLOC (m->numSSEChars * FLOATS_PER_VEC * sizeof(CLFlt*), 16);
				    m->lnLI_SSE = ALIGNED_MALLOC (m->numSSEChars * FLOATS_PER_VEC * sizeof(CLFlt*), 16);
#else
				    ALIGNED_MALLOC ((void **)(&m->lnL_SSE) , 16, m->numSSEChars * FLOATS_PER_VEC * sizeof(CLFlt*));
				    ALIGNED_MALLOC ((void **)(&m->lnLI_SSE), 16, m->numSSEChars * FLOATS_PER_VEC * sizeof(CLFlt*));
#endif
                    }
#endif
				}


            /* allocate tiprob space */
            m->tiProbs = (CLFlt**) SafeMalloc(m->numTiProbs * sizeof(CLFlt*));
            if (!m->tiProbs)
                return (ERROR);
            for (i=0; i<m->numTiProbs; i++)
                {
                m->tiProbs[i] = (CLFlt*) SafeMalloc(m->tiProbLength * sizeof(CLFlt));
                if (!m->tiProbs[i])
                    return (ERROR);
                }
            }

        /* allocate eigen system space (needed also for Beagle version */
        if (m->nCijkParts > 0)
            {
            m->cijks = (MrBFlt**) SafeMalloc((numLocalChains + 1) * sizeof(MrBFlt*));
            if (!m->cijks)
                return ERROR;
            for (i=0; i<numLocalChains+1; i++)
                {
                m->cijks[i] = (MrBFlt*) SafeMalloc(m->cijkLength * sizeof(MrBFlt));
                if (!m->cijks[i])
                    return (ERROR);
                }
            }

        /* get size of tree */
        nIntNodes = GetTree(m->brlens,0,0)->nIntNodes;
        nNodes = GetTree(m->brlens,0,0)->nNodes;

            
        /* allocate and set indices from tree nodes to cond like arrays */
        m->condLikeIndex = (int **) SafeMalloc (numLocalChains * sizeof(int *));
        if (!m->condLikeIndex)
            return (ERROR);
        for (i=0; i<numLocalChains; i++)
            {
            m->condLikeIndex[i] = (int *) SafeMalloc (nNodes * sizeof(int));
            if (!m->condLikeIndex[i])
                return (ERROR);
            }
        for (i=0; i<numLocalChains; i++)
            for (j=0; j<nNodes; j++)
                m->condLikeIndex[i][j] = -1;

        /* set up indices for terminal nodes */
        clIndex = 0;
        if (useBeagle == YES)
            indexStep = m->nCijkParts;
        else
            indexStep = 1;
        for (i=0; i<numLocalTaxa; i++)
            {
#if !defined (DEBUG_NOSHORTCUTS)
            /* TODO: Untill CondLikeRoot_XXX are fixed (case 4 when one of the children is non-ambig) we allocate space for non-ambig tips. if fixed also uncoment down the function */
            /*if (useBeagle == NO && useSSE == NO && m->isPartAmbig[i] == NO && m->dataType != STANDARD)
                continue;
            */
#endif
            for (j=0; j<numLocalChains; j++)
                m->condLikeIndex[j][i] = clIndex;
            clIndex += 1; /* even for multiple omega cat we need only one set of conditional likelihoods  for terminals for all chains.*/
            }

        /* reserve private space for parsimony-based moves if parsimony model is used */
        if (m->parsModelId == YES && m->parsimonyBasedMove == YES)
            clIndex += nIntNodes;

        /* set up indices for internal nodes */
        for (j=0; j<numLocalChains; j++)
            {
            for (i=0; i<nIntNodes; i++)
                {
                m->condLikeIndex[j][i+numLocalTaxa] = clIndex;
                clIndex += indexStep;
                }
            }

        /* allocate and set up scratch cond like indices */
        m->condLikeScratchIndex = (int *) SafeMalloc (nNodes * sizeof(int));
        if (!m->condLikeScratchIndex)
            return (ERROR);
        for (i=0; i<nNodes; i++)
            m->condLikeScratchIndex[i] = -1;
        for (i=0; i<nIntNodes; i++)
            {
            m->condLikeScratchIndex[i+numLocalTaxa] = clIndex;
            clIndex += indexStep;
            }

        /* allocate and set indices from tree edges to ti prob arrays */
        m->tiProbsIndex = (int **) SafeMalloc (numLocalChains * sizeof(int *));
        if (!m->tiProbsIndex)
            return (ERROR);
        for (i=0; i<numLocalChains; i++)
            {
            m->tiProbsIndex[i] = (int *) SafeMalloc (nNodes * sizeof(int));
            if (!m->tiProbsIndex[i])
                return (ERROR);
            }

        /* set up indices for nodes */
        tiIndex = 0;
        for (i=0; i<numLocalChains; i++)
            {
            for (j=0; j<nNodes; j++)
                {
                m->tiProbsIndex[i][j] = tiIndex;
                tiIndex += indexStep;
                }
            }

        /* allocate and set up scratch transition prob indices */
        m->tiProbsScratchIndex = (int *) SafeMalloc (nNodes * sizeof(int));
        if (!m->tiProbsScratchIndex)
            return (ERROR);
        for (i=0; i<nNodes; i++)
            {
            m->tiProbsScratchIndex[i] = tiIndex;
            tiIndex += indexStep;
            }

        /* allocate and set up node scaler indices */
        scalerIndex = 0;
        m->nodeScalerIndex = (int **) SafeMalloc (numLocalChains * sizeof(int *));
        if (!m->nodeScalerIndex)
            return (ERROR);
        for (i=0; i<numLocalChains; i++)
            {
            m->nodeScalerIndex[i] = (int *) SafeMalloc (nNodes * sizeof(int));
            if (!m->nodeScalerIndex[i])
                return (ERROR);
            for (j=0; j<nNodes; j++)
                m->nodeScalerIndex[i][j] = -1;
            for (j=0; j<nIntNodes; j++)
                {
                m->nodeScalerIndex[i][j+numLocalTaxa] = scalerIndex;
                scalerIndex += indexStep;
                }
            }
        m->nodeScalerScratchIndex = (int *) SafeMalloc (nNodes * sizeof (int));
        if (!m->nodeScalerScratchIndex)
            return (ERROR);
        for (i=0; i<nNodes; i++)
            m->nodeScalerScratchIndex[i] = -1;
        for (i=0; i<nIntNodes; i++)
            {
            m->nodeScalerScratchIndex[i+numLocalTaxa] = scalerIndex;
            scalerIndex += indexStep;
            }

        /* allocate and set up node scaler flags */
        m->scalersSet = (int **) SafeMalloc (numLocalChains * sizeof(int *));
        if (!m->scalersSet)
            return (ERROR);
        for (i=0; i<numLocalChains; i++)
            {
            m->scalersSet[i] = (int *) SafeMalloc (nNodes * sizeof(int));
            if (!m->scalersSet[i])
                return (ERROR);
            for (j=0; j<nNodes; j++)
                m->scalersSet[i][j] = NO;
            }
        m->scalersSetScratch = (int *) SafeMalloc (nNodes * sizeof (int));
        if (!m->scalersSetScratch)
            return (ERROR);
        for (i=0; i<nNodes; i++)
            m->scalersSetScratch[i] = NO;

        /* allocate and set up site scaler indices */
        m->siteScalerIndex = (int *) SafeMalloc (numLocalChains * sizeof(int));
        if (!m->siteScalerIndex)
            return (ERROR);
        for (i=0; i<numLocalChains; i++)
            {
            m->siteScalerIndex[i] = scalerIndex;
            scalerIndex += indexStep;
            }
        m->siteScalerScratchIndex = scalerIndex;

#if defined (BEAGLE_ENABLED)
        /* used only with Beagle advanced dynamic rescaling where we set scaler nodes for each partition  */
        if ( m->useBeagle == YES )
			{
			m->succesCount = (int*) SafeMalloc((numLocalChains) * sizeof(int));
			m->rescaleFreq = (int*) SafeMalloc((numLocalChains) * sizeof(int));
			m->beagleComputeCount = (long *) SafeMalloc(sizeof(long) * numLocalChains);
			t=BEAGLE_RESCALE_FREQ/m->numModelStates;
			if ( beagleFlags & BEAGLE_FLAG_PRECISION_DOUBLE ) /*if double presition is used*/
				t*=BEAGLE_RESCALE_FREQ_DOUBLE;
			for (i=0; i<numLocalChains; i++)
			   {
			   m->rescaleFreq[i] = t;
			   }
			m->isScalerNode = (int**) SafeMalloc((numLocalChains) * sizeof(int*));
			/* we will use m->isScalerNode[chain][node->index] to determine whether the node is scaled or not. We do it only for internal nodes whose indexes start from numLocalTaxa thus we skew the pointer */
			m->isScalerNodeScratch = (int*) SafeMalloc(nIntNodes * sizeof(int)) - numLocalTaxa; 
			assert( NO == 0 ); /* SafeMalloc set the allocated memmory to 0 while we need to set it to NO */
			for (i=0; i<numLocalChains; i++)
			   {
			   m->isScalerNode[i] = (int*) SafeMalloc(nIntNodes * sizeof(int)) - numLocalTaxa;
			   }
			}
#endif

        /* allocate and set up cijk indices */
        if (m->nCijkParts > 0)
            {
            m->cijkIndex = (int *) SafeMalloc (numLocalChains * sizeof(int));
            if (!m->cijkIndex)
                return (ERROR);
            for (i=0; i<numLocalChains; i++)
                m->cijkIndex[i] = i*indexStep;
            m->cijkScratchIndex = numLocalChains*indexStep;
            }

#if defined (BEAGLE_ENABLED)
            /* Set up nSitesOfPat for Beagle */
            if (m->useBeagle == YES)
            {
                nSitesOfPat = (double *) SafeMalloc (m->numChars * sizeof(double));
                for (c=0; c<m->numChars; c++)
                    nSitesOfPat[c] = numSitesOfPat[m->compCharStart + c];
                beagleSetPatternWeights(m->beagleInstance,
                                        nSitesOfPat);
                free (nSitesOfPat);
                nSitesOfPat = NULL;

                /* find category frequencies */
                if (m->pInvar == NO)
                {
                    freq =  1.0 /  m->numGammaCats;
                    
                    /* set category frequencies in beagle instance */
                    if (m->numOmegaCats <= 1)
                    {
                        for (i=0; i<m->numGammaCats; i++)
                            m->inWeights[i] = freq;
                        for (i=0; i< (numLocalChains); i++) {
                            beagleSetCategoryWeights(m->beagleInstance,
                                                     m->cijkIndex[i],
                                                     m->inWeights);
                        }
                        beagleSetCategoryWeights(m->beagleInstance,
                                                 m->cijkScratchIndex,
                                                 m->inWeights);
                    }
                }
                
                /* Set up scalers for Beagle */
                for (i=0; i<m->numScalers*m->nCijkParts; i++)
                    beagleResetScaleFactors(m->beagleInstance, i);
            }
#endif

        /* fill in tip conditional likelihoods */
        if (m->dataType == STANDARD)
			{
            clIndex = 0;
			for (i=0; i<numLocalTaxa; i++)
				{
				cL = m->condLikes[clIndex++];
				for(t=0; t<m->numGammaCats;t++)
					{
					charBits = m->parsSets[i];
 					for (c=0; c<m->numChars; c++)
						{					
						if (m->nStates[c] == 2)
							numReps = m->numBetaCats;
						else
							numReps = 1;
						for (k=0; k<numReps; k++)
							{
							for (s=0; s<m->nStates[c]; s++)
								{
								if (IsBitSet(s, charBits))
									(*cL) = 1.0;
								cL++;
								}
							}
						charBits += m->nParsIntsPerSite;
						}
					}
				}
			}
		else if (useBeagle == NO)
			{
			if (m->gibbsGamma == YES)
				numReps = m->numTiCats / m->numGammaCats;
			else
				numReps = m->numTiCats;

            clIndex = 0;
			for (i=0; i<numLocalTaxa; i++)
				{
#if !defined (DEBUG_NOSHORTCUTS) && !defined (SSE_ENABLED)
                /* TODO: Untill CondLikeRoot_XXX are fixed (case 4 when one of the children is non-ambig) we allocate space for non-ambig tips. if fixed also uncomment up the function */
                /*if (m->isPartAmbig[i] == NO && m->dataType != RESTRICTION)
                    continue;
                */
#endif
				cL = m->condLikes[clIndex++];
#if defined (SSE_ENABLED)
                if (m->useSSE == YES)
                    {
                    for (k=0; k<numReps; k++)
					    {
					    charBits = m->parsSets[i];
				        for (c=0; c<m->numChars/FLOATS_PER_VEC; c++)
					        {
                            for (j=0; j<m->numModelStates/m->numStates; j++)
                                {
						        for (s=0; s<m->numStates; s++)
							        {
                                    for (j1=0; j1<FLOATS_PER_VEC; j1++)
                                        {
							            if (IsBitSet(s, charBits + j1*m->nParsIntsPerSite))
								            (*cL) = 1.0;
                                        cL++;
                                        }
							        }
                                }   
					        charBits += FLOATS_PER_VEC * m->nParsIntsPerSite;
						    }
                        if (m->numChars % FLOATS_PER_VEC > 0)
                            {
                            /* add last characters and padd */
                            for (j=0; j<m->numModelStates/m->numStates; j++)
                                {
					            for (s=0; s<m->numStates; s++)
						            {
                                    for (j1=0; j1<m->numChars%FLOATS_PER_VEC; j1++)
                                        {
						                if (IsBitSet(s, charBits + j1*m->nParsIntsPerSite))
							                (*cL) = 1.0;
                                        cL++;
                                        }
                                    for (; j1<FLOATS_PER_VEC; j1++)
                                        {
						                (*cL) = 1.0;
                                        cL++;
                                        }
						            }
                                }
                            }
					    }
                    }
                else
                    {
                    for (k=0; k<numReps; k++)
					    {
                        charBits = m->parsSets[i];
				        for (c=0; c<m->numChars; c++)
					        {
                            for (j=0; j<m->numModelStates/m->numStates; j++)
                                {
						        for (s=0; s<m->numStates; s++)
							        {
							        if (IsBitSet(s, charBits))
								        (*cL) = 1.0;
							        cL++;
							        }
                                }
							    charBits += m->nParsIntsPerSite;
						    }
					    }
                    }

#else
                for (k=0; k<numReps; k++)
					{
                    charBits = m->parsSets[i];
				    for (c=0; c<m->numChars; c++)
					    {
                        for (j=0; j<m->numModelStates/m->numStates; j++)
                            {
						    for (s=0; s<m->numStates; s++)
							    {
							    if (IsBitSet(s, charBits))
								    (*cL) = 1.0;
							    cL++;
							    }
                            }
							charBits += m->nParsIntsPerSite;
						}
					}
#endif
                }
			}

        if (m->printAncStates == YES)
            {
            m->ancStateCondLikes = (CLFlt *) SafeMalloc (m->condLikeLength * sizeof(CLFlt));
            if (!m->ancStateCondLikes)
                return (ERROR);
            }
		}
    /* allocate space for precalculated likelihoods */
    j = 0;
    for (d=0; d<numCurrentDivisions; d++)
        {
        m = &modelSettings[d];
        if (m->dataType == STANDARD || m->parsModelId == YES)
            continue;

        i = (m->numModelStates + 1) * m->numModelStates * m->numTiCats;
        if (i > j)
            j = i;
        }
    if (j > 0) /* don't bother allocating precalculated likelihoods if we only have parsimony model or morphological characters */
		{
		if (memAllocs[ALLOC_PRELIKES] == YES)
			{
			MrBayesPrint ("%s   Space for preLikes not free in InitChainCondLikes\n", spacer);
			return ERROR;
			}
		preLikeL = (CLFlt *) SafeMalloc (3 * j * sizeof(CLFlt));
		if (!preLikeL)
			{
			MrBayesPrint ("%s   Problem allocating preLikes\n", spacer);
			return ERROR;
			}
		memAllocs[ALLOC_PRELIKES] = YES;
		preLikeR = preLikeL + j;
		preLikeA = preLikeR + j;
		}
	
    return NO_ERROR;
}





/*------------------------------------------------------------------------
|
|	InitEigenSystemInfo: set info about eigen decompositions
|
-------------------------------------------------------------------------*/
int InitEigenSystemInfo (ModelInfo *m)
{
    int         ts;
    
    if (m->dataType == STANDARD)
        {
        /* dealt with in ProcessStdChars */
        return (NO_ERROR);
        }

    m->cijkLength = 0;
    m->nCijkParts = 0;
    if (m->dataType == PROTEIN)
        {
        ts = m->numModelStates;
        m->cijkLength = (ts * ts * ts) + (2 * ts);
        m->nCijkParts = 1;
        if (m->switchRates != NULL) /* covarion model */
            {
            m->cijkLength *= m->numGammaCats;
            m->nCijkParts = m->numGammaCats;
            }
        }
    else if (m->dataType == DNA || m->dataType == RNA)
        {
        if (m->nucModelId == NUCMODEL_4BY4)
            {
            if (m->switchRates==NULL && m->nst != 6 && m->nst != NST_MIXED)
                {
                m->cijkLength = 0;
                m->nCijkParts = 0;
#if defined (BEAGLE_ENABLED)
                ts = m->numModelStates;
                m->cijkLength = (ts * ts * ts) + (2 * ts);
                m->nCijkParts = 1;
#endif
                }
            else
                {
                ts = m->numModelStates;
                m->cijkLength = (ts * ts * ts) + (2 * ts);
                m->nCijkParts = 1;
                }
            if (m->switchRates != NULL)
                {
                m->cijkLength *= m->numGammaCats;
                m->nCijkParts = m->numGammaCats;
                }
            }
        else if (m->nucModelId == NUCMODEL_DOUBLET)
            {
            ts = m->numModelStates;
            m->cijkLength = (ts * ts * ts) + (2 * ts);
            m->nCijkParts = 1;
            }
        else if (m->nucModelId == NUCMODEL_CODON)
            {
            ts = m->numModelStates;
            m->cijkLength = (ts * ts * ts) + (2 * ts);
            m->cijkLength *= m->numOmegaCats;
            m->nCijkParts = m->numOmegaCats;
            }
        else
            {
            MrBayesPrint ("%s   ERROR: Something is wrong if you are here.\n", spacer);
            return ERROR;
            }
		}
#if defined (BEAGLE_ENABLED)
    else if (m->dataType == RESTRICTION)
        {
				assert( m->numModelStates == 2);
                ts = 2;
                m->cijkLength = (ts * ts * ts) + (2 * ts);
                m->nCijkParts = 1;
		}
#endif
    return (NO_ERROR);
}





/*------------------------------------------------------------------------
|
|	InitFinalStateCondLikes: allocate space for final conditional
|		likelihoods if needed
|
-------------------------------------------------------------------------*/
int InitFinalStateCondLikes (void)
{
    int         d;
    ModelInfo   *m;
    
    for (d=0; d<numCurrentDivisions; d++)
        {
        m = &modelSettings[d];
        if (m->printAncStates == YES)
            {
            m->ancStateCondLikes = (CLFlt *) SafeMalloc (m->condLikeLength * sizeof(CLFlt));
            if (!m->ancStateCondLikes)
                return ERROR;
            }
        }
    return (NO_ERROR);
}





/*------------------------------------------------------------------------
|
|	InitInvCondLikes: allocate and initialize invariable conditional
|		likelihoods if needed
|
|		NB! Fills in invariable cond likes for all hidden states; this
|		is convenient although some space is wasted
|
-------------------------------------------------------------------------*/
int InitInvCondLikes (void)

{

	int			c, d, i, s, isConstant, usingInvCondLikes;
	SafeLong	*charBits;
	CLFlt		*cI;
	ModelInfo	*m;
    ModelParams *mp;

#if defined (SSE_ENABLED)
    int         c1;
#endif

	/* allocate space for invariable cond likes */
    usingInvCondLikes = NO;
	for (d=0; d<numCurrentDivisions; d++)
		{
		m = &modelSettings[d];

		if (m->pInvar == NULL)
			continue;

        usingInvCondLikes = YES;
#if defined (SSE_ENABLED)
        c1 = m->numSSEChars * FLOATS_PER_VEC * m->numModelStates;
#if defined (MS_VCPP_SSE)
        m->invCondLikes = (CLFlt *) ALIGNED_MALLOC (c1 * sizeof(CLFlt), 16);
#else
        ALIGNED_MALLOC ((void **)(&m->invCondLikes), 16, c1 * sizeof(CLFlt));
#endif
        for (i=0; i<c1; i++)
            m->invCondLikes[i] = 0.0f;
#else
        m->invCondLikes = (CLFlt *) SafeMalloc (m->numChars * m->numModelStates * sizeof(CLFlt));
#endif
        if (!m->invCondLikes)
            return ERROR;
		}
	
	if (usingInvCondLikes == NO)
		return NO_ERROR;
	
	MrBayesPrint ("%s   Initializing invariable-site conditional likelihoods\n", spacer);
		
	/* fill in invariable-site conditional likelihoods */
	for (d=0; d<numCurrentDivisions; d++)
		{

		m = &modelSettings[d];
		mp = &modelParams[d];
		
		if (m->pInvar == NULL)
			continue;
		
		cI = m->invCondLikes;
        if (m->dataType == STANDARD)
			{
			for (c=0; c<m->numChars; c++)
				{
				for (s=0; s<m->nStates[c]; s++)
					{
					isConstant = YES;
                    for (i=0; i<numLocalTaxa; i++)
						{
					    charBits = &m->parsSets[i][c*m->nParsIntsPerSite];
						if (IsBitSet(s, charBits) == NO)
							{
							isConstant = NO;
							break;
							}
						}
					if (isConstant == YES)
						*cI = 1.0;
                    else
                        *cI = 0.0;
                    cI++;
					}
				}
			}
		else	/* all other models for which pInvar is applicable */
			{
			assert( m->numModelStates == m->numStates );
#if defined (SSE_ENABLED)
             for (c=0; c<m->numChars/FLOATS_PER_VEC; c++)
				{
				for (s=0; s<m->numModelStates; s++)
					{
                    for (c1=0; c1<FLOATS_PER_VEC; c1++)
                        {
					    isConstant = YES;
					    //charBits = parsMatrix + m->parsMatrixStart + ((c * FLOATS_PER_VEC) + c1) * m->nParsIntsPerSite;
					    for (i=0; i<numLocalTaxa; i++)
						    {
							charBits = &m->parsSets[i][((c * FLOATS_PER_VEC) + c1) *m->nParsIntsPerSite];
						    if (IsBitSet(s, charBits) == NO)
							    {
							    isConstant = NO;
							    break;
							    }
						    //charBits += parsMatrixRowSize;
						    }
					    if (isConstant == YES)
						    *cI = 1.0;
					    cI++;
                        }
					}
				}
             if (m->numChars % FLOATS_PER_VEC != 0)
                {
				for (s=0; s<m->numModelStates; s++)
					{
                    for (c1=0; c1<m->numChars%FLOATS_PER_VEC; c1++)
                        {
					    isConstant = YES;
					    //charBits = parsMatrix + m->parsMatrixStart + (((m->numChars / FLOATS_PER_VEC) * FLOATS_PER_VEC) + c1) * m->nParsIntsPerSite;
					    for (i=0; i<numLocalTaxa; i++)
						    {
							charBits = &m->parsSets[i][(((m->numChars / FLOATS_PER_VEC) * FLOATS_PER_VEC) + c1) *m->nParsIntsPerSite];
						    if (IsBitSet(s, charBits) == NO)
							    {
							    isConstant = NO;
							    break;
							    }
						    //charBits += parsMatrixRowSize;
						    }
					    if (isConstant == YES)
						    *cI = 1.0;
					    cI++;
                        }
                    for (; c1<FLOATS_PER_VEC; c1++)
                        {
					    *cI = 1.0;
					    cI++;
                        }
					}
				}
#else
            for (c=0; c<m->numChars; c++)
				{
				for (s=0; s<m->numModelStates; s++)
					{
					isConstant = YES;
					for (i=0; i<numLocalTaxa; i++)
						{
                        charBits = &m->parsSets[i][c*m->nParsIntsPerSite];
						if (IsBitSet(s, charBits) == NO)
							{
							isConstant = NO;
							break;
							}
						}
					if (isConstant == YES)
						*cI = 1.0;
					cI++;
					}
				}
#endif
			}
		}	/* next division */

#	if 0
	invCondLikeSize = 0;
	for (d=0; d<numCurrentDivisions; d++)
		{
		m = &modelSettings[d];
		if (m->pInvar == NULL)
			continue;
		cI = m->invCondLikes;
		if (m->dataType == STANDARD)
			{
			}
		else
			{
			for (c=0; c<m->numChars; c++)
				{
				printf ("%4d -- ", c);
				for (s=0; s<m->numModelStates; s++)
					{
					printf ("%1.0lf", *cI);
					cI++;
					}
				printf ("\n");
				}
			}
		}
#	endif
		
	return NO_ERROR;
}





/*------------------------------------------------------------------------
|
|	InitParsSets: allocate space for and set parsimony state sets
|
-------------------------------------------------------------------------*/
int InitParsSets (void)

{

	int				c, i, j, k, d, nParsStatesForCont, nIntNodes, nNodes,
                    nuc1, nuc2, nuc3, codingNucCode, allNucCode, allAmbig;
	SafeLong        x, x1, x2, x3, *longPtr;
	ModelInfo		*m;
	ModelParams		*mp;

    /* this variable determines how many parsimony states are used           */
	/* to represent continuous characters (determines weight of these chars) */
	nParsStatesForCont = 3;

	/* find number and size of parsimony sets and node lengths */
	for (d=0; d<numCurrentDivisions; d++)
		{
		m  = &modelSettings[d];
		mp = &modelParams[d];

        /* find how many parsimony ints (SafeLong) are needed for each model site */
		if (mp->dataType == CONTINUOUS)
			{
			/* scale continuous characters down to an ordered parsimony character */
			/* with nParsStatesForCont states, represent this character as a set */
			/* of binary characters by additive binary coding */
			m->nParsIntsPerSite = nParsStatesForCont - 1;
			}
		else
			m->nParsIntsPerSite = 1 + m->numStates / nBitsInALong;

        /* Calculate number of nodes and number of internal nodes */
        nIntNodes = GetTree(m->brlens,0,0)->nIntNodes;
        nNodes    = GetTree(m->brlens,0,0)->nNodes;
        
        /* Calculate number of parsimony sets */
        m->numParsSets = numLocalTaxa;
        if (m->parsimonyBasedMove == YES || !strcmp(chainParams.startTree, "Parsimony"))
            m->numParsSets += nIntNodes;
        if (m->parsModelId == YES)
            m->numParsSets += (numLocalChains + 1) * nIntNodes;

        if (m->parsModelId == YES)
            m->numParsNodeLens = (numLocalChains + 1) * nNodes;
        else
            m->numParsNodeLens = 0;
        }
		
	/* then allocate space for the sets and node lengths */
	for (d=0; d<numCurrentDivisions; d++)
		{
		m = &modelSettings[d];
		mp = &modelParams[d];

        m->parsSets = (SafeLong **) SafeCalloc (m->numParsSets, sizeof(SafeLong*));
        if (!m->parsSets)
            return (ERROR);
        for (i=0; i<m->numParsSets; i++)
            {
            m->parsSets[i] = (SafeLong *) SafeCalloc (m->numChars*m->nParsIntsPerSite, sizeof(SafeLong));
            if (!m->parsSets[i])
                return (ERROR);
            }

        if (m->numParsNodeLens > 0)
            {
            m->parsNodeLens = (CLFlt *) SafeCalloc (m->numParsNodeLens, sizeof(CLFlt));
            if (!m->parsNodeLens)
                return (ERROR);
            }
        }
	
	/* finally fill in tip parsimony sets */
	for (d=0; d<numCurrentDivisions; d++)
		{
		m = &modelSettings[d];
		mp = &modelParams[d];

		if (mp->dataType == CONTINUOUS)
			{
            /* Note: This is only a placeholder since continuous characters are not implemented yet.
               Using additive parsimony would be more efficient than using multiple binary chars as here. */
			for (i=0; i<numLocalTaxa; i++)
				{
				for (c=0, j=m->compMatrixStart; j<m->compMatrixStop; j++, c++)
					{
					x = compMatrix[pos(i,j,compMatrixRowSize)];

					for (k=0; k<m->nParsIntsPerSite; k++)
						{
						if (x > (k + 1) * 1000 / (m->nParsIntsPerSite + 1))
							m->parsSets[i][c*m->nParsIntsPerSite + k] = 1;
						else
							m->parsSets[i][c*m->nParsIntsPerSite + k] = 2;
						}
					}
				}
			}
		else if (m->nCharsPerSite == 1 && m->nParsIntsPerSite == 1)
			{
			allAmbig = (1<<mp->nStates) - 1;
			for (i=0; i<numLocalTaxa; i++)
				{
				for (c=0, j=m->compMatrixStart; j<m->compMatrixStop; j++, c++)
					{
					x = compMatrix[pos(i,j,compMatrixRowSize)];

					if (x == MISSING || x == GAP)
						m->parsSets[i][c] = allAmbig;
					else
						m->parsSets[i][c] = x;
					}
				}
			}
		else if (!strcmp(mp->nucModel, "Doublet") && (mp->dataType == DNA || mp->dataType == RNA))
			{
			allAmbig = 15;
			for (i=0; i<numLocalTaxa; i++)
				{
				for (c=0, j=m->compMatrixStart; j<m->compMatrixStop; j+=m->nCharsPerSite, c++)
					{
					/* fetch the original values x1 and x2 */
					x1 = compMatrix[pos(i,j,compMatrixRowSize)];
					if (x1 == MISSING || x1 == GAP)
						x1 = allAmbig;
					x2 = compMatrix[pos(i,j+1,compMatrixRowSize)];
					if (x2 == MISSING || x2 == GAP)
						x2 = allAmbig;
					/* squeeze them together in the new value x */
					x = 0;
					for (nuc1=0; nuc1<4; nuc1++)
						{
						for (nuc2=0; nuc2<4; nuc2++)
							{
							if (IsBitSet(nuc1,&x1) == YES && IsBitSet(nuc2, &x2) == YES)
								x |= (1<<(nuc1*4 + nuc2));
							}
						}
					
					m->parsSets[i][c] = x;
					}
				}
			}
		else if (!strcmp(mp->nucModel, "Codon") && (mp->dataType == DNA || mp->dataType == RNA))
			{
			allAmbig = 15;
			for (i=0; i<numLocalTaxa; i++)
				{
				for (c=0, j=m->compMatrixStart; j<m->compMatrixStop; j+=m->nCharsPerSite, c++)
					{
					/* fetch the original values x1, x2, and x3*/
					x1 = compMatrix[pos(i,j,compMatrixRowSize)];
					if (x1 == MISSING || x1 == GAP)
						x1 = allAmbig;
					x2 = compMatrix[pos(i,j+1,compMatrixRowSize)];
					if (x2 == MISSING || x2 == GAP)
						x2 = allAmbig;
					x3 = compMatrix[pos(i,j+2,compMatrixRowSize)];
					if (x3 == MISSING || x3 == GAP)
						x3 = allAmbig;

					/* squeeze them together in the new long string pointed to by longPtr */
					longPtr = &m->parsSets[i][c*m->nParsIntsPerSite];
					allNucCode = codingNucCode = 0;
					for (nuc1=0; nuc1<4; nuc1++)
						for (nuc2=0; nuc2<4; nuc2++)
							for (nuc3=0; nuc3<4; nuc3++)
								{
								if (mp->codon[allNucCode] != 21)
									{
									if (IsBitSet(nuc1, &x1) == YES && IsBitSet(nuc2, &x2) == YES && IsBitSet(nuc3, &x3) == YES)
										SetBit(codingNucCode, longPtr);
									codingNucCode++;
									}
								allNucCode++;
								}
					}
				}
			}
		else if (!strcmp(mp->nucModel, "Protein") && (mp->dataType == DNA || mp->dataType == RNA))
			{
			allAmbig = 15;
			for (i=0; i<numLocalTaxa; i++)
				{
				for (c=0, j=m->compMatrixStart; j<m->compMatrixStop; j+=m->nCharsPerSite, c++)
					{
					/* fetch the original values x1, x2, and x3*/
					x1 = compMatrix[pos(i,j,compMatrixRowSize)];
					if (x1 == MISSING || x1 == GAP)
						x1 = allAmbig;
					x2 = compMatrix[pos(i,j+1,compMatrixRowSize)];
					if (x2 == MISSING || x2 == GAP)
						x2 = allAmbig;
					x3 = compMatrix[pos(i,j+2,compMatrixRowSize)];
					if (x3 == MISSING || x3 == GAP)
						x3 = allAmbig;

					/* squeeze them together in the new long string pointed to by longPtr */
					longPtr = &m->parsSets[i][c*m->nParsIntsPerSite];   /* m->nParsIntsPerSite should be 1 */
					allNucCode = 0;
					for (nuc1=0; nuc1<4; nuc1++)
						for (nuc2=0; nuc2<4; nuc2++)
							for (nuc3=0; nuc3<4; nuc3++)
								{
								if (mp->codon[allNucCode] != 21)
									{
									if (IsBitSet(nuc1, &x1) == YES && IsBitSet(nuc2, &x2) == YES && IsBitSet(nuc3, &x3) == YES)
										SetBit(mp->codon[allNucCode]-1, longPtr);
									}
								allNucCode++;
								}
					}
				}
			}
		else
			{
			MrBayesPrint ("%s   Unrecognized data format during bitset compression\n", spacer);
			return ERROR;
			}
		}
	
	return (NO_ERROR);

}





/*------------------------------------------------
|
|   InitPrintParams: Set up arrays of print para-
|      meters and print tree parameters
|
------------------------------------------------*/
int InitPrintParams (void)

{
	int		i, j, k, k1=0;
	Param	*p;

	/* count number of model params to print */
	numPrintParams = 0;
	for (i=0; i<numParams; i++)
		{
		p = &params[i];
		if (p->printParam == YES &&
			p->paramType != P_TOPOLOGY &&
			p->paramType != P_BRLENS &&
            p->paramType != P_SPECIESTREE &&
			p->paramType != P_CPPEVENTS &&
			p->paramType != P_TK02BRANCHRATES &&
            p->paramType != P_IGRBRANCHLENS)
			numPrintParams++;
		}

	/* count number of tree params to print */
	numPrintTreeParams = 0;
	for (i=0; i<numParams; i++)
		{
		p = &params[i];
		if (p->paramType == P_TOPOLOGY)
			{
			/* always print parsimony topology (printParam == YES), otherwise */
			/* print topology only if brlens never requested (nPrintSubParams == 0)*/
			if (p->printParam == YES || p->nPrintSubParams == 0)
				numPrintTreeParams++;
			}
		else if (p->paramType == P_BRLENS)
			{
			/* print only if brlens (or events) requested for at least one partition */
			if (p->printParam == YES || p->nPrintSubParams > 0)
				numPrintTreeParams++;
			}
		else if (p->paramType == P_SPECIESTREE)
			{
			/* always print if printParam set to YES */
			if (p->printParam == YES)
				numPrintTreeParams++;
			}
		}

	/* allocate space */
	printParam = (Param **) SafeCalloc (numPrintParams + numPrintTreeParams + numTopologies, sizeof(Param *));
	topologyPrintIndex = (int *) SafeCalloc (numTopologies + numPrintTreeParams, sizeof(int)); 
	if (!printParam || !topologyPrintIndex)
		{
		free (printParam);
		free (topologyPrintIndex);
		MrBayesPrint ("%s   Could not allocate printParam vector in InitPrintParams\n", spacer);
		return (ERROR);
		}
	printTreeParam = printParam + numPrintParams;
	topologyParam = printTreeParam + numPrintTreeParams;
	printTreeTopologyIndex = topologyPrintIndex + numTopologies;
	memAllocs[ALLOC_PRINTPARAM] = YES;

	/* assign normal print params */
	for (i=j=0; i<numParams; i++)
		{
		p = &params[i];
		if (p->printParam == YES &&
			p->paramType != P_TOPOLOGY &&
			p->paramType != P_BRLENS &&
            p->paramType != P_SPECIESTREE &&
			p->paramType != P_CPPEVENTS &&
			p->paramType != P_TK02BRANCHRATES)
			printParam[j++] = p;
		}
	
	/* assign tree print params */
	for (i=j=k=0; i<numParams; i++)
		{
		p = &params[i];
		if (p->paramType == P_TOPOLOGY)
			{
			/* always print parsimony topology (printParam == YES), otherwise */
			/* print topology only if brlens never requested (nPrintSubParams == 0)*/
			if (p->printParam == YES || p->nPrintSubParams == 0)
				numPrintTreeParams++;
			}
		else if (p->paramType == P_BRLENS)
			{
			/* print only if brlens (or events) requested for at least one partition */
			if (p->printParam == YES || p->nPrintSubParams > 0)
				printTreeParam[k++] = p;
			}
        else if (p->paramType == P_SPECIESTREE)
            {
            if (p->printParam == YES)
                printTreeParam[k++] = p;
            }
		}

	/* find topologies, topology file index, and printtree topology index */
	for (i=0; i<numPrintTreeParams; i++)
		printTreeTopologyIndex[i] = numTopologies;
	for (i=j=0; i<numParams; i++)
		{
		p = &params[i];
        if (p->paramType == P_SPECIESTREE)
            {
			topologyParam[j] = p;
			for (k=0; k<numPrintTreeParams; k++)
				if (printTreeParam[k] == p)
					break;
			topologyPrintIndex[j] = k;
			printTreeTopologyIndex[k] = j;
			j++;
			}
		else if (p->paramType == P_TOPOLOGY)
			{
			topologyParam[j] = p;
			for (k=0; k<numPrintTreeParams; k++)
				if (printTreeParam[k] == p)
					break;
			if (k<numPrintTreeParams)
				{
				topologyPrintIndex[j] = k;
				printTreeTopologyIndex[k] = j;
				}
			else
				{
				for (k=0; k<p->nSubParams; k++)
					{
					for (k1=0; k1<numPrintTreeParams; k1++)
						if (printTreeParam[k1] == p->subParams[k])
							break;
					if (k1 < numPrintTreeParams)
						break;
					}
				topologyPrintIndex[j] = k1;
				printTreeTopologyIndex[k1] = j;
				}
			j++;
			}
		}

	return (NO_ERROR);
}





int IsPFNodeEmpty (PFNODE *p)
{
	int	i;

	for (i=0; i<chainParams.numRuns; i++)
		{
		if (p->count[i] > 0)
			break;
		}
	if (i == chainParams.numRuns)
		return YES;
	else
		return NO;
}





void JukesCantor (MrBFlt *tiP, MrBFlt length)

{

	int		i, j, index;
	MrBFlt	pChange, pNoChange;
	
	/* calculate probabilities */
	pChange   =  0.25 -  0.25 * exp(-( 4.0/ 3.0)*length);
	pNoChange =  0.25 +  0.75 * exp(-( 4.0/ 3.0)*length);

	/* fill in values */
	for (i=index=0; i<4; i++)
		{
		for (j=0; j<4; j++)
			{
			if (i == j)
				tiP[index++] = pNoChange;
			else
				tiP[index++] = pChange;
			}
		}
		
}





/* LargestNonemptyPFNode: recursive function to largest nonempty node in a subtree */
PFNODE *LargestNonemptyPFNode (PFNODE *p, int *i, int j)
{
	PFNODE *q;

	++j;
	if (p == NULL)
		return NULL;
	
	q = LargestNonemptyPFNode (p->left, i, j);
	
	if (q != NULL)
		{
		return q;
		}
	else if (IsPFNodeEmpty (p) == NO)
		{
		*i = j;
		return p;
		}
	else
		{
		return LargestNonemptyPFNode (p->right, i, j);
		}
}





/*------------------------------------------------------------------
|
|	Likelihood_Adgamma: all n-state models with autocorrelated
|		 discrete gamma rate variation, NOT morph, restriction,
|		 codon or doublet models; just fill in rateProbs
|
-------------------------------------------------------------------*/
int Likelihood_Adgamma (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)

{

	int				c, j, k, nStates, nStatesDiv2;
	MrBFlt			*bs, *swr, s01, s10, probOn, probOff, covBF[40];
	MrBFlt			like, *rP;
	CLFlt			*clP;
	ModelInfo		*m;
	
	/* NOTE: whichSitePats offsets numSitesOfPat by whichSitePats X numCompressedChars.
	   This is done so we can use the character reweighting scheme for "heating" chains. This was easy to
	   accomplish for all of the models except this one, which doesn't use numSitesOfPat when calculating
	   likelihoods. Either we disallow autocorrelated rates when using MCMC with character reweighting, or
	   we properly calculate likelihoods when some site patterns have increased or decreased weight. For
	   now, we do not allow MCMCMC with character reweighting with this HMM; we bail out in the function
	   FillNumSitesOfPat if we have Adgamma rate variation and reweighting. */
	k = whichSitePats;
	
	/* find model settings */
	m = &modelSettings[division];
	
	/* get the number of states */
	nStates = m->numModelStates;
	nStatesDiv2 = nStates / 2;
	
	/* find base frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);

	/* find conditional likelihood pointer */
	clP = m->condLikes[m->condLikeIndex[chain][p->index]];
    
	/* find pointer to rate probabilities */
	rP = rateProbs[chain] + state[chain] * rateProbRowSize + m->rateProbStart;

	/* loop over characters and calculate rate probs */
	if (m->switchRates != NULL)
		{
		swr = GetParamVals (m->switchRates, chain, state[chain]);
		s01 = swr[0];
		s10 = swr[1];
		probOn = s01 / (s01 + s10);
		probOff =  1.0 - probOn;
		for (j=0; j<nStatesDiv2; j++)
			{
			covBF[j] = bs[j] * probOn;
			covBF[j+nStatesDiv2] = bs[j] * probOff;
			}
		bs = covBF;
		}

	for (c=0; c<m->numChars; c++)
		{
		for (k=0; k<m->numGammaCats; k++)
			{
			like =  0.0;
			for (j=0; j<nStates; j++)
				like += (*(clP++)) *  bs[j];
			*(rP++) = like;
			}
		}

	/* reset lnL, likelihood calculated later for this model */
	*lnL =  0.0;

	return (NO_ERROR);

}





/*------------------------------------------------------------------
|
|	Likelihood_Gen: general n-state models with or without rate
|		variation
|
-------------------------------------------------------------------*/

int Likelihood_Gen (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)

{
	int				c, j, k, nStates, hasPInvar;
	MrBFlt			s01, s10, probOn, probOff, *swr;
	MrBFlt			covBF[40], freq, *bs, like, likeI, pInvar=0.0, lnLike;
	CLFlt			*clPtr, **clP, *lnScaler, *nSitesOfPat, *clInvar=NULL;
	ModelInfo		*m;
	
	/* find model settings and nStates, pInvar, invar cond likes */
	m = &modelSettings[division];
	nStates = m->numModelStates;
	if (m->pInvar == NULL)
		{
		hasPInvar = NO;
		}
	else
		{
		hasPInvar = YES;
		pInvar =  *(GetParamVals (m->pInvar, chain, state[chain]));
		clInvar = m->invCondLikes;
		}

	/* find conditional likelihood pointers */
	clPtr = m->condLikes[m->condLikeIndex[chain][p->index]];
    clP = m->clP;
    for (k=0; k<m->numGammaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += m->numChars * m->numModelStates;
        }

	
	/* find base frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);

	/* if covarion model, adjust base frequencies */
	if (m->switchRates != NULL)
		{
		/* find the stationary frequencies */
		swr = GetParamVals(m->switchRates, chain, state[chain]);
		s01 = swr[0];
		s10 = swr[1];
		probOn = s01 / (s01 + s10);
		probOff =  1.0 - probOn;

		/* now adjust the base frequencies; on-state stored first in cond likes */
		for (j=0; j<nStates/2; j++)
			{
			covBF[j] = bs[j] * probOn;
			covBF[j+nStates/2] = bs[j] * probOff;
			}

		/* finally set bs pointer to adjusted values */
		bs = covBF;
		}

	/* find category frequencies */
	if (hasPInvar == NO)
		freq =  1.0 /  m->numGammaCats;
	else
		freq = (1.0 - pInvar) /  m->numGammaCats;

	/* find site scaler */
	lnScaler = m->scalers[m->siteScalerIndex[chain]];
	
	/* find nSitesOfPat */
	nSitesOfPat = numSitesOfPat + (whichSitePats*numCompressedChars) + m->compCharStart;
	
	/* reset lnL */
	*lnL = 0.0;

	/* loop over characters */
	if (hasPInvar == NO)
		{
		for (c=0; c<m->numChars; c++)
			{
			like = 0.0;
			for (k=0; k<m->numGammaCats; k++)
				for (j=0; j<nStates; j++)
				  {
					like += (*(clP[k]++)) * bs[j];
#ifdef DEBUG_OUTPUT
					printf("char=%d cat=%d j=%d like %E\n",c, k,j,like);
#endif
				  }
			like *= freq;

			/* check against LIKE_EPSILON (values close to zero are problematic) */
			if (like < LIKE_EPSILON)
				{
				MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division, c, like);
                (*lnL)=MRBFLT_NEG_MAX;
				return ERROR;
				}
			else	
				{
				(*lnL) += (lnScaler[c] +  log(like)) * nSitesOfPat[c];
				}
			}
		}
	else
		{
		/* has invariable category */
		for (c=0; c<m->numChars; c++)
			{
			likeI = like = 0.0;
			for (k=0; k<m->numGammaCats; k++)
				for (j=0; j<nStates; j++)
					{
					like += (*(clP[k]++)) * bs[j];
					}
			like *= freq;
			for (j=0; j<nStates; j++)
				likeI += (*(clInvar++)) * bs[j] * pInvar;
			if (lnScaler[c] < -200.0)
				{
				/* we are not going to be able to exponentiate the scaling factor */
				if (likeI > 1E-70)
					{
					/* forget about like; it is going to be insignificant compared to likeI */
					lnLike = log(likeI);
					}
				else
					{
					/* treat likeI as if 0.0, that is, ignore it completely */
					lnLike = log(like) + lnScaler[c];
					}
				}
			else
				lnLike = log (like + (likeI / exp (lnScaler[c]))) + lnScaler[c];

			/* check against LIKE_EPSILON (values close to zero are problematic) */
			if (like < LIKE_EPSILON)
				{
#ifdef DEBUG_OUTPUT
				printf ("lnScaler[%d] = %lf likeI = %lf\n", c, lnScaler[c], likeI);
#endif
				MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division, c, like);
                (*lnL)=MRBFLT_NEG_MAX;
				return ERROR;
				}
			else	
				{
				(*lnL) += lnLike * nSitesOfPat[c];
				}
			}		
		}
		
	return NO_ERROR;
	
}




#if defined (SSE_ENABLED)
#if 0
CLFlt DeleteME[1000];
int PrintOld_SSE (TreeNode *p, int division, int chain){

	int				c, c1, j, k, nStates;
	//MrBFlt			*swr, likeI, pInvar=0.0, lnLike;
	CLFlt			*temp_vector;
    __m128          *clPtr, **clP;
	ModelInfo		*m;

	m = &modelSettings[division];
	nStates = m->numModelStates;
	/* find conditional likelihood pointers */


	temp_vector =  DeleteME;

	clPtr = (__m128 *) (m->condLikes[m->condLikeIndex[chain][p->index]]);
    clP = m->clP_SSE;
    for (k=0; k<m->numGammaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += m->numSSEChars * m->numModelStates;
        }

	for (c=0; c<m->numChars; c++)
		{
		c1 = c / FLOATS_PER_VEC;
		for (k=0; k<m->numGammaCats; k++)
			{
			for (j=0; j<nStates; j++)
				{
				*temp_vector++ = *(((CLFlt*)&clP[k][c1*nStates+j])+c % FLOATS_PER_VEC);
				}
			}
		}
	temp_vector=DeleteME;

	return 1;
}
#endif



/*------------------------------------------------------------------
|
|	Likelihood_Gen_SSE: general n-state model with or without rate
|		variation
|
-------------------------------------------------------------------*/

int Likelihood_Gen_SSE (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)

{	
	int				c, j, k, nStates, hasPInvar;
	MrBFlt			like, *bs;
	MrBFlt			s01, s10, probOn, probOff, *swr, covBF[40], freq, likeI, pInvar=0.0, lnLike;
	CLFlt			*lnScaler, *nSitesOfPat, *lnL_SSE, *lnLI_SSE;
    __m128          *clPtr, **clP, *clInvar=NULL;
	__m128			m1, mCatLike, mLike, mFreq, mPInvar;
	ModelInfo		*m;


	/* find model settings and nStates, pInvar, invar cond likes */
	m = &modelSettings[division];
	nStates = m->numModelStates;
	if (m->pInvar == NULL)
		{
		hasPInvar = NO;
		}
	else
		{
		hasPInvar = YES;
		pInvar =  *(GetParamVals (m->pInvar, chain, state[chain]));
        mPInvar = _mm_set1_ps ((CLFlt)(pInvar));
		clInvar = (__m128 *) (m->invCondLikes);
		}

	/* find conditional likelihood pointers */
	clPtr = (__m128 *) (m->condLikes[m->condLikeIndex[chain][p->index]]);
    clP = m->clP_SSE;
    for (k=0; k<m->numGammaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += m->numSSEChars * m->numModelStates;
        }
    lnL_SSE  = m->lnL_SSE;
    lnLI_SSE = m->lnLI_SSE;
	
	/* find base frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);

	/* if covarion model, adjust base frequencies */
	if (m->switchRates != NULL)
		{
		/* find the stationary frequencies */
		swr = GetParamVals(m->switchRates, chain, state[chain]);
		s01 = swr[0];
		s10 = swr[1];
		probOn = s01 / (s01 + s10);
		probOff =  1.0 - probOn;

		/* now adjust the base frequencies; on-state stored first in cond likes */
		for (j=0; j<nStates/2; j++)
			{
			covBF[j] = bs[j] * probOn;
			covBF[j+nStates/2] = bs[j] * probOff;
			}

		/* finally set bs pointer to adjusted values */
		bs = covBF;
		}

	/* find category frequencies */
	if (hasPInvar == NO)
		freq =  1.0 /  m->numGammaCats;
	else
		freq = (1.0 - pInvar) /  m->numGammaCats;

	mFreq = _mm_set1_ps ((CLFlt)(freq));

	/* find site scaler */
	lnScaler = m->scalers[m->siteScalerIndex[chain]];
	
	/* find nSitesOfPat */
	nSitesOfPat = numSitesOfPat + (whichSitePats*numCompressedChars) + m->compCharStart;
	
	/* reset lnL */
	*lnL = 0.0;

	for (c=0; c<m->numSSEChars; c++)
		{
		mLike = _mm_setzero_ps ();
		for (k=0; k<m->numGammaCats; k++)
			{
			mCatLike = _mm_setzero_ps ();
			for (j=0; j<nStates; j++)
				{
				m1 = _mm_mul_ps (clP[k][j], _mm_set1_ps ((CLFlt)bs[j]) );
				mCatLike = _mm_add_ps (mCatLike, m1);
				}
			m1 = _mm_mul_ps (mCatLike, mFreq );
			mLike = _mm_add_ps (mLike, m1);
			clP[k] += nStates;
			}
		_mm_store_ps (lnL_SSE, mLike);
        lnL_SSE += FLOATS_PER_VEC;
		}


	/* loop over characters */
	if (hasPInvar == NO)
		{
		for (c=0; c<m->numChars; c++)
			{
			like = m->lnL_SSE[c];
			/* check against LIKE_EPSILON (values close to zero are problematic) */
			if (like < LIKE_EPSILON)
				{
				MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division, c, like);
                (*lnL)=MRBFLT_NEG_MAX;
				return ERROR;
				}
			else	
				{
				(*lnL) += (lnScaler[c] +  log(like)) * nSitesOfPat[c];
				}
			}
		}
	else
		{
		/* has invariable category */
		for (c=0; c<m->numSSEChars; c++)
			{
			mCatLike = _mm_setzero_ps ();
			for (j=0; j<nStates; j++)
				{
				m1 = _mm_mul_ps (clInvar[j], _mm_set1_ps ((CLFlt)bs[j]) );
				mCatLike = _mm_add_ps (mCatLike, m1);
				}
			clInvar += nStates;
			_mm_store_ps (lnL_SSE, mCatLike);
			lnLI_SSE += FLOATS_PER_VEC;
			}


		for (c=0; c<m->numChars; c++)
			{
			like  = m->lnL_SSE[c];
            likeI = m->lnLI_SSE[c];
			if (lnScaler[c] < -200.0)
				{
				/* we are not going to be able to exponentiate the scaling factor */
				if (likeI > 1E-70)
					{
					/* forget about like; it is going to be insignificant compared to likeI */
					lnLike = log(likeI);
					}
				else
					{
					/* treat likeI as if 0.0, that is, ignore it completely */
					lnLike = log(like) + lnScaler[c];
					}
				}
			else
				lnLike = log (like + (likeI / exp (lnScaler[c]))) + lnScaler[c];

			/* check against LIKE_EPSILON (values close to zero are problematic) */
			if (like < LIKE_EPSILON)
				{
#ifdef DEBUG_OUTPUT
				printf ("lnScaler[%d] = %lf likeI = %lf\n", c, lnScaler[c], likeI);
#endif
				MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division, c, like);
                (*lnL)=MRBFLT_NEG_MAX;
				return ERROR;
				}
			else	
				{
				(*lnL) += lnLike * nSitesOfPat[c];
				}
			}		
		}
		
	return NO_ERROR;
	
}
#endif




/*------------------------------------------------------------------
|
|	Likelihood_Gen_GibbsGamma: general n-state models using
|		Gibbs resampling of discrete gamma rate categories
|
-------------------------------------------------------------------*/

int Likelihood_Gen_GibbsGamma (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)

{
	int				c, j, nStates, nGammaCats, *rateCat;
	MrBFlt			s01, s10, probOn, probOff, *swr;
	MrBFlt			covBF[40], *bs, like;
	CLFlt			*clP, *lnScaler, *nSitesOfPat, *clInvar=NULL;
	ModelInfo		*m;
	
	/* find model settings, nStates and invar cond likes */
	m = &modelSettings[division];
	nStates = m->numModelStates;
	clInvar = m->invCondLikes;

	/* find conditional likelihood pointer */
	clP = m->condLikes[m->condLikeIndex[chain][p->index]];
	
	/* find base frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);

	/* if covarion model, adjust base frequencies */
	if (m->switchRates != NULL)
		{
		/* find the stationary frequencies */
		swr = GetParamVals(m->switchRates, chain, state[chain]);
		s01 = swr[0];
		s10 = swr[1];
		probOn = s01 / (s01 + s10);
		probOff =  1.0 - probOn;

		/* now adjust the base frequencies; on-state stored first in cond likes */
		for (j=0; j<nStates/2; j++)
			{
			covBF[j] = bs[j] * probOn;
			covBF[j+nStates/2] = bs[j] * probOff;
			}

		/* finally set bs pointer to adjusted values */
		bs = covBF;
		}

	/* find site scaler */
	lnScaler = m->scalers[m->siteScalerIndex[chain]];
	
	/* find nSitesOfPat */
	nSitesOfPat = numSitesOfPat + (whichSitePats*numCompressedChars) + m->compCharStart;
	
	/* find rate category index and number of gamma categories */
	rateCat = m->tiIndex + chain * m->numChars;
	nGammaCats = m->numGammaCats;

	/* reset lnL */
	*lnL = 0.0;

	/* loop over characters */
	if (m->pInvar == NULL)
		{
		for (c=0; c<m->numChars; c++)
			{
			like = 0.0;
			for (j=0; j<nStates; j++)
				{
				like += (*(clP++)) * bs[j];
#ifdef DEBUG_OUTPUT
				printf("char=%d cat=%d j=%d like %E\n",c, k,j,like);
#endif
				}

			/* check against LIKE_EPSILON (values close to zero are problematic) */
			if (like < LIKE_EPSILON)
				{
				MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division, c, like);
                (*lnL)=MRBFLT_NEG_MAX;
				return ERROR;
				}
			else	
				{
				(*lnL) += (lnScaler[c] +  log(like)) * nSitesOfPat[c];
				}
			}
		}
	else
		{
		/* has invariable category */
		for (c=0; c<m->numChars; c++)
			{
			like = 0.0;
			if (rateCat[c] < nGammaCats)
				{
				for (j=0; j<nStates; j++)
					like += (*(clP++)) * bs[j];
				clInvar += nStates;
				}
			else
				{
				for (j=0; j<nStates; j++)
					like += (*(clInvar++)) * bs[j];
				clP += nStates;
				}

			/* check against LIKE_EPSILON (values close to zero are problematic) */
			if (like < LIKE_EPSILON)
				{
#ifdef DEBUG_OUTPUT
				printf ("lnScaler[%d] = %lf likeI = %lf\n", c, lnScaler[c], likeI);
#endif
				MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division, c, like);
                (*lnL)=MRBFLT_NEG_MAX;
				return ERROR;
				}
			else	
				{
				(*lnL) += (log(like) + lnScaler[c]) * nSitesOfPat[c];
				}
			}		
		}
		
	return NO_ERROR;
	
}





/*------------------------------------------------------------------
|
|	Likelihood_NUC4: 4by4 nucleotide models with or without rate
|		variation
|
-------------------------------------------------------------------*/
int Likelihood_NUC4 (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)

{

	int				c, k, hasPInvar;
	MrBFlt			freq, likeI, *bs, like, pInvar=0.0;
	CLFlt			*clPtr, **clP, *lnScaler, *nSitesOfPat, *clInvar=NULL;
	ModelInfo		*m;

#if defined (FAST_LOG)
	int				index;
	MrBFlt			likeAdjust = 1.0, f;
#endif

	/* find model settings and pInvar, invar cond likes */
	m = &modelSettings[division];
	if (m->pInvar == NULL)
		{
		hasPInvar = NO;
		}
	else
		{
		hasPInvar = YES;
		pInvar =  *(GetParamVals (m->pInvar, chain, state[chain]));
		clInvar = m->invCondLikes;
		}

	/* find conditional likelihood pointers */
	clPtr = m->condLikes[m->condLikeIndex[chain][p->index]];
    clP = m->clP;
    for (k=0; k<m->numGammaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += m->numChars * m->numModelStates;
        }
	
	/* find base frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);

	/* find category frequencies */
	if (hasPInvar == NO)
		freq =  1.0 /  m->numGammaCats;
	else
		freq =  (1.0 - pInvar) /  m->numGammaCats;

	/* find tree scaler */
	lnScaler = m->scalers[m->siteScalerIndex[chain]];
	
	/* find nSitesOfPat */
	nSitesOfPat = numSitesOfPat + (whichSitePats*numCompressedChars) + m->compCharStart;
	
	/* reset lnL */
	*lnL = 0.0;

	/* loop over characters */
	if (hasPInvar == NO)
		{
		for (c=0; c<m->numChars; c++)
			{
			like = 0.0;
			for (k=0; k<m->numGammaCats; k++)
				{
				like += (clP[k][A] * bs[A] + clP[k][C] * bs[C] + clP[k][G] * bs[G] + clP[k][T] * bs[T]);
				clP[k] += 4;
				}
			like *= freq;
			
			/* check against LIKE_EPSILON (values close to zero are problematic) */
			if (like < LIKE_EPSILON)
				{
				MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division+1, c+1, like);
                (*lnL)=MRBFLT_NEG_MAX;
				return ERROR;
				}
			else	
				{
#if defined (FAST_LOG)
				f = frexp (like, &index);
				index = 1-index;
				(*lnL) += (lnScaler[c] +  logValue[index]) * nSitesOfPat[c];				
				for (k=0; k<(int)nSitesOfPat[c]; k++)
					likeAdjust *= f;
#else
                (*lnL) += (lnScaler[c] +  log(like)) * nSitesOfPat[c];
#endif
                }
			}
		}
	else
		{
		/* has invariable category */
		for (c=0; c<m->numChars; c++)
			{
			like = 0.0;
			for (k=0; k<m->numGammaCats; k++)
				{
				like += (clP[k][A] * bs[A] + clP[k][C] * bs[C] + clP[k][G] * bs[G] + clP[k][T] * bs[T]);
				clP[k] += 4;
				}
			like *= freq;
			likeI = (clInvar[A] * bs[A] + clInvar[C] * bs[C] + clInvar[G] * bs[G] + clInvar[T] * bs[T]) * pInvar;
			if (lnScaler[c] < -200)
				{
				/* we are not going to be able to exponentiate the scaling factor */
				if (likeI > 1E-70)
					{
					/* forget about like; it is going to be insignificant compared to likeI */
					like = likeI;
					}
				else
					{
					/* treat likeI as if 0.0, that is, ignore it completely */
					}
				}
			else
				like = like + (likeI / exp (lnScaler[c]));

			clInvar += 4;

			/* check against LIKE_EPSILON (values close to zero are problematic) */
			if (like < LIKE_EPSILON)
				{
				MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division+1, c+1, like);
                (*lnL)=MRBFLT_NEG_MAX;
				return ERROR;
				}
			else	
				{
#if defined (FAST_LOG)
				f = frexp (like, &index);
				index = 1-index;
				(*lnL) += (lnScaler[c] +  logValue[index]) * nSitesOfPat[c];				
				for (k=0; k<(int)nSitesOfPat[c]; k++)
					likeAdjust *= f;
#else
				(*lnL) += (lnScaler[c] +  log(like)) * nSitesOfPat[c];
#endif
				}
			}		
		}
		
#if defined (FAST_LOG)
	(*lnL) += log (likeAdjust);
#endif

	return NO_ERROR;
}





/*------------------------------------------------------------------
|
|	Likelihood_NUC4_GibbsGamma: 4by4 nucleotide models with rate
|		variation using Gibbs sampling from gamma rate categories
|
-------------------------------------------------------------------*/
int Likelihood_NUC4_GibbsGamma (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)

{

	int				c, i, r, nGammaCats, *rateCat;
	MrBFlt			*bs, like;
	CLFlt			*clP, *lnScaler, *nSitesOfPat, *clInvar;
	ModelInfo		*m;

#if defined (FAST_LOG)
	int				k, index;
	MrBFlt			likeAdjust = 1.0, f;
#endif

	/* find model settings and invar cond likes */
	m = &modelSettings[division];
	clInvar = m->invCondLikes;

	/* find conditional likelihood pointer */
	clP = m->condLikes[m->condLikeIndex[chain][p->index]];
	
	/* find base frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);

	/* find tree scaler */
	lnScaler = m->scalers[m->siteScalerIndex[chain]];
	
	/* find nSitesOfPat */
	nSitesOfPat = numSitesOfPat + (whichSitePats*numCompressedChars) + m->compCharStart;
	
	/* find rate category index  and number of gamma categories */
	rateCat = m->tiIndex + chain * m->numChars;
	nGammaCats = m->numGammaCats;

	/* reset lnL */
	*lnL = 0.0;

	/* loop over characters */
	if (m->pInvar == NULL)
		{
		for (c=i=0; c<m->numChars; c++)
			{
			like = (clP[A] * bs[A] + clP[C] * bs[C] + clP[G] * bs[G] + clP[T] * bs[T]);
			clP += 4;
			
			/* check against LIKE_EPSILON (values close to zero are problematic) */
			if (like < LIKE_EPSILON)
				{
				MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division, c, like);
                (*lnL)=MRBFLT_NEG_MAX;
				return ERROR;
				}
			else	
				{
#if defined (FAST_LOG)
				f = frexp (like, &index);
				index = 1-index;
				(*lnL) += (lnScaler[c] +  logValue[index]) * nSitesOfPat[c];				
				for (k=0; k<(int)nSitesOfPat[c]; k++)
					likeAdjust *= f;
#else
				(*lnL) += (lnScaler[c] +  log(like)) * nSitesOfPat[c];
#endif
				}
			}
		}
	else
		{
		/* has invariable category */
		for (c=i=0; c<m->numChars; c++)
			{
			r = rateCat[c];
			if (r < nGammaCats)
				like = (clP[A] * bs[A] + clP[C] * bs[C] + clP[G] * bs[G] + clP[T] * bs[T]);
			else
				like = (clInvar[A] * bs[A] + clInvar[C] * bs[C] + clInvar[G] * bs[G] + clInvar[T] * bs[T]);
			clInvar += 4;
			clP += 4;

			/* check against LIKE_EPSILON (values close to zero are problematic) */
			if (like < LIKE_EPSILON)
				{
				MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division, c, like);
                (*lnL)=MRBFLT_NEG_MAX;
				return ERROR;
				}
			else	
				{
				(*lnL) += (log (like) + lnScaler[c]) * nSitesOfPat[c];
				}
			}		
		}
		
#if defined (FAST_LOG)
	(*lnL) += log (likeAdjust);
#endif

	return NO_ERROR;
}





//
//#if defined (SSE_ENABLED)
///*------------------------------------------------------------------
//|
//|	Likelihood_NUC4_GibbsGamma: 4by4 nucleotide models with rate
//|		variation using Gibbs sampling from gamma rate categories
//|
//-------------------------------------------------------------------*/
//int Likelihood_NUC4_GibbsGamma_SSE (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)
//
//{
//
//	int				c, i, r, nGammaCats, *rateCat;
//	MrBFlt			*bs, like;
//	CLFlt			*lnScaler, *nSitesOfPat, *lnL_SSE, *lnLI_SSE;
//	__m128          *clP, *clInvar=NULL;
//    __m128          m1, mA, mC, mG, mT, mFreq, mPInvar, mLike;
//	ModelInfo		*m;
//
//#if defined (FAST_LOG)
//	int				k, index;
//	MrBFlt			likeAdjust = 1.0, f;
//#endif
//
//	/* find model settings and invar cond likes */
//	m = &modelSettings[division];
//	clInvar = (__m128 *)m->invCondLikes;
//	/* find conditional likelihood pointer */
//	clP = (__m128 *)m->condLikes[m->condLikeIndex[chain][p->index]];
//
//	lnL_SSE  = m->lnL_SSE;
//    lnLI_SSE = m->lnLI_SSE;
//	
//	/* find base frequencies */
//	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);
//
//	/* find tree scaler */
//	lnScaler = m->scalers[m->siteScalerIndex[chain]];
//	
//	/* find nSitesOfPat */
//	nSitesOfPat = numSitesOfPat + (whichSitePats*numCompressedChars) + m->compCharStart;
//	
//	/* find rate category index  and number of gamma categories */
//	rateCat = m->tiIndex + chain * m->numChars;
//	nGammaCats = m->numGammaCats;
//
//	/* reset lnL */
//	*lnL = 0.0;
//
//	/* calculate variable likelihood */
//	for (c=0; c<m->numSSEChars; c++)
//		{
//		mLike = _mm_mul_ps (clP[A], mA);
//        m1    = _mm_mul_ps (clP[C], mC);
//        mLike = _mm_add_ps (mLike, m1);
//        m1    = _mm_mul_ps (clP[G], mG);
//        mLike = _mm_add_ps (mLike, m1);
//        m1    = _mm_mul_ps (clP[T], mT);
//        mLike = _mm_add_ps (mLike, m1);
//
//		clP += 4;
//		_mm_store_ps (lnL_SSE, mLike);
//        lnL_SSE += FLOATS_PER_VEC;
//		}
//    
//    /* calculate invariable likelihood */
//    if (hasPInvar == YES)
//        {
//		for (c=0; c<m->numSSEChars; c++)
//			{
//			mLike = _mm_mul_ps (clInvar[A], mA);
//            m1    = _mm_mul_ps (clInvar[C], mC);
//            mLike = _mm_add_ps (mLike, m1);
//            m1    = _mm_mul_ps (clInvar[G], mG);
//            mLike = _mm_add_ps (mLike, m1);
//            m1    = _mm_mul_ps (clInvar[T], mT);
//            mLike = _mm_add_ps (mLike, m1);
//            mLike = _mm_mul_ps (mLike, mPInvar);
//
//            _mm_store_ps (lnLI_SSE, mLike);
//            clInvar += 4;
//            lnLI_SSE += FLOATS_PER_VEC;
//            }
//        }
//
//
//	/* loop over characters */
//	if (m->pInvar == NULL)
//		{
//		for (c=i=0; c<m->numChars; c++)
//			{
//			like = m->lnL_SSE[c];
//			/* check against LIKE_EPSILON (values close to zero are problematic) */
//			if (like < LIKE_EPSILON)
//				{
//				MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division, c, like);
//              (*lnL)=MRBFLT_NEG_MAX;
//				return ERROR;
//				}
//			else	
//				{
//#if defined (FAST_LOG)
//				f = frexp (like, &index);
//				index = 1-index;
//				(*lnL) += (lnScaler[c] +  logValue[index]) * nSitesOfPat[c];				
//				for (k=0; k<(int)nSitesOfPat[c]; k++)
//					likeAdjust *= f;
//#else
//				(*lnL) += (lnScaler[c] +  log(like)) * nSitesOfPat[c];
//#endif
//				}
//			}
//		}
//	else
//		{
//		/* has invariable category */
//		for (c=i=0; c<m->numChars; c++)
//			{
//			r = rateCat[c];
//			if (r < nGammaCats)
//				like = m->lnL_SSE[c];
//			else
//				like = m->lnLI_SSE[c];
//
//			/* check against LIKE_EPSILON (values close to zero are problematic) */
//			if (like < LIKE_EPSILON)
//				{
//				MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division, c, like);
//              (*lnL)=MRBFLT_NEG_MAX;
//				return ERROR;
//				}
//			else	
//				{
//				(*lnL) += (log (like) + lnScaler[c]) * nSitesOfPat[c];
//				}
//			}		
//		}
//		
//#if defined (FAST_LOG)
//	(*lnL) += log (likeAdjust);
//#endif
//
//	return NO_ERROR;
//}
//#endif




#if defined (SSE_ENABLED)
/*------------------------------------------------------------------
|
|	Likelihood_NUC4_SSE: 4by4 nucleotide models with or without rate
|		variation
|
-------------------------------------------------------------------*/
int Likelihood_NUC4_SSE (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)

{

	int				c, k, hasPInvar;
	MrBFlt			freq, *bs, pInvar=0.0, like, likeI;
	CLFlt			*lnScaler, *nSitesOfPat, *lnL_SSE, *lnLI_SSE;
    __m128          *clPtr, **clP, *clInvar=NULL;
    __m128          m1, mA, mC, mG, mT, mFreq, mPInvar=_mm_set1_ps(0.0f), mLike;
	ModelInfo		*m;

#if defined (FAST_LOG)
	int				index;
	MrBFlt			likeAdjust = 1.0, f;
#endif

	/* find model settings and pInvar, invar cond likes */
	m = &modelSettings[division];
	if (m->pInvar == NULL)
		{
		hasPInvar = NO;
		}
	else
		{
		hasPInvar = YES;
		pInvar =  *(GetParamVals (m->pInvar, chain, state[chain]));
        mPInvar = _mm_set1_ps ((CLFlt)(pInvar));
		clInvar = (__m128 *) (m->invCondLikes);
		}

	/* find conditional likelihood pointers */
	clPtr = (__m128 *) (m->condLikes[m->condLikeIndex[chain][p->index]]);
    clP = m->clP_SSE;
    for (k=0; k<m->numGammaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += m->numSSEChars * m->numModelStates;
        }
    lnL_SSE  = m->lnL_SSE;
    lnLI_SSE = m->lnLI_SSE;
	
	/* find base frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);
    mA = _mm_set1_ps ((CLFlt)(bs[A]));
    mC = _mm_set1_ps ((CLFlt)(bs[C]));
    mG = _mm_set1_ps ((CLFlt)(bs[G]));
    mT = _mm_set1_ps ((CLFlt)(bs[T]));

	/* find category frequencies */
	if (hasPInvar == NO)
		freq =  1.0 / m->numGammaCats;
	else
		freq =  (1.0 - pInvar) / m->numGammaCats;
    mFreq = _mm_set1_ps ((CLFlt)(freq));

	/* find tree scaler */
	lnScaler = m->scalers[m->siteScalerIndex[chain]];

	/* find nSitesOfPat */
	nSitesOfPat = numSitesOfPat + (whichSitePats*numCompressedChars) + m->compCharStart;
	
	/* reset lnL */
	*lnL = 0.0;

	/* calculate variable likelihood */
	for (c=0; c<m->numSSEChars; c++)
		{
		mLike = _mm_setzero_ps ();
		for (k=0; k<m->numGammaCats; k++)
			{
			m1    = _mm_mul_ps (clP[k][A], mA);
            mLike = _mm_add_ps (mLike, m1);
            m1    = _mm_mul_ps (clP[k][C], mC);
            mLike = _mm_add_ps (mLike, m1);
            m1    = _mm_mul_ps (clP[k][G], mG);
            mLike = _mm_add_ps (mLike, m1);
            m1    = _mm_mul_ps (clP[k][T], mT);
            mLike = _mm_add_ps (mLike, m1);
			clP[k] += 4;
			}
        mLike = _mm_mul_ps (mLike, mFreq);
		_mm_store_ps (lnL_SSE, mLike);
        lnL_SSE += FLOATS_PER_VEC;
		}
    
    /* calculate invariable likelihood */
    if (hasPInvar == YES)
        {
		for (c=0; c<m->numSSEChars; c++)
			{
			mLike = _mm_mul_ps (clInvar[A], mA);
            m1    = _mm_mul_ps (clInvar[C], mC);
            mLike = _mm_add_ps (mLike, m1);
            m1    = _mm_mul_ps (clInvar[G], mG);
            mLike = _mm_add_ps (mLike, m1);
            m1    = _mm_mul_ps (clInvar[T], mT);
            mLike = _mm_add_ps (mLike, m1);
            mLike = _mm_mul_ps (mLike, mPInvar);

            _mm_store_ps (lnLI_SSE, mLike);
            clInvar += 4;
            lnLI_SSE += FLOATS_PER_VEC;
            }
        }

    /* accumulate results */
    if (hasPInvar == NO)
        {
        for (c=0; c<m->numChars; c++)
            {
            like = m->lnL_SSE[c];
            /* check against LIKE_EPSILON (values close to zero are problematic) */
		    if (like < LIKE_EPSILON)
			    {
			    MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division+1, c+1, like);
                (*lnL)=MRBFLT_NEG_MAX;
			    return ERROR;
			    }
		    else	
			    {
#if defined (FAST_LOG)
			    f = frexp (like, &index);
			    index = 1-index;
			    (*lnL) += (lnScaler[c] +  logValue[index]) * nSitesOfPat[c];				
			    for (k=0; k<(int)nSitesOfPat[c]; k++)
				    likeAdjust *= f;
#else
			    (*lnL) += (lnScaler[c] +  log(like)) * nSitesOfPat[c];
#endif
			    }
		    }
        }
    else
        {
		/* has invariable category */
		for (c=0; c<m->numChars; c++)
			{
			like  = m->lnL_SSE[c];
            likeI = m->lnLI_SSE[c];
			if (lnScaler[c] < -200)
				{
				/* we are not going to be able to exponentiate the scaling factor */
				if (likeI > 1E-70)
					{
					/* forget about like; it is going to be insignificant compared to likeI */
					like = likeI;
					}
				else
					{
					/* treat likeI as if 0.0, that is, ignore it completely */
					}
				}
			else
				like = like + (likeI / exp (lnScaler[c]));

			/* check against LIKE_EPSILON (values close to zero are problematic) */
			if (like < LIKE_EPSILON)
				{
				MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division+1, c+1, like);
                (*lnL)=MRBFLT_NEG_MAX;
				return ERROR;
				}
			else	
				{
#if defined (FAST_LOG)
				f = frexp (like, &index);
				index = 1-index;
				(*lnL) += (lnScaler[c] +  logValue[index]) * nSitesOfPat[c];				
				for (k=0; k<(int)nSitesOfPat[c]; k++)
					likeAdjust *= f;
#else
				(*lnL) += (lnScaler[c] +  log(like)) * nSitesOfPat[c];
#endif
                }
            }
        }

#if defined (FAST_LOG)
	(*lnL) += log (likeAdjust);
#endif

	return NO_ERROR;
}
#endif





/*------------------------------------------------------------------
|
|	Likelihood_NY98: Codon model with three selection categories,
|		after Nielsen and Yang (1998).
|
-------------------------------------------------------------------*/
int Likelihood_NY98 (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)

{

	int				c, j, k, nStates;
	MrBFlt			catLike, like, *bs, *omegaCatFreq;
	CLFlt			**clP,*clPtr, *lnScaler, *nSitesOfPat;
	ModelInfo		*m;
	
	m = &modelSettings[division];

	/* number of states */
	nStates = m->numModelStates;

	/* find conditional likelihood pointers */
    clPtr = m->condLikes[m->condLikeIndex[chain][p->index]];
    clP   = m->clP;
	for (k=0; k<m->numOmegaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += m->numChars * m->numModelStates;
        }
	
	/* find codon frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);
	
	/* find category frequencies */
	omegaCatFreq = GetParamSubVals (m->omega, chain, state[chain]);

	/* find site scaler */
	lnScaler = m->scalers[m->siteScalerIndex[chain]];
	
	/* find nSitesOfPat */
	nSitesOfPat = numSitesOfPat + (whichSitePats*numCompressedChars) + m->compCharStart;
	
	*lnL = 0.0;	/* reset lnL */

	for (c=m->numDummyChars; c<m->numChars; c++)
		{
		like = 0.0;
		for (k=0; k<m->numOmegaCats; k++)
			{
			catLike = 0.0;
			for (j=0; j<nStates; j++)
				catLike += clP[k][j] * bs[j];
			like += catLike * omegaCatFreq[k];
			clP[k] += nStates;
			}
		/* check against LIKE_EPSILON (values close to zero are problematic) */
		if (like < LIKE_EPSILON)
			{
			MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division, c, like);
            (*lnL)=MRBFLT_NEG_MAX;
			return ERROR;
			}
		else	
			{
			(*lnL) += (lnScaler[c] +  log(like)) * nSitesOfPat[c];
			}
		}

	return NO_ERROR;
	
}





#if defined (SSE_ENABLED)
/*------------------------------------------------------------------
|
|	Likelihood_NY98_SSE: Codon model with three selection categories,
|		after Nielsen and Yang (1998).
|
-------------------------------------------------------------------*/
int Likelihood_NY98_SSE (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)

{

	int				c, j, k, nStates;
	MrBFlt			like, *bs, *omegaCatFreq;
	CLFlt			*lnScaler, *nSitesOfPat, *lnL_SSE;
    __m128          *clPtr, **clP;
	__m128			m1, mCatLike, mLike;
	ModelInfo		*m;
	
	m = &modelSettings[division];

	/* number of states */
	nStates = m->numModelStates;

	/* find conditional likelihood pointers */
    clPtr = (__m128 *) m->condLikes[m->condLikeIndex[chain][p->index]];
    clP   = m->clP_SSE;
	for (k=0; k<m->numOmegaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += m->numSSEChars * nStates;
        }
	
	/* find codon frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);
	
	/* find category frequencies */
	omegaCatFreq = GetParamSubVals (m->omega, chain, state[chain]);

	/* find site scaler */
	lnScaler = m->scalers[m->siteScalerIndex[chain]];
	
	/* find nSitesOfPat */
	nSitesOfPat = numSitesOfPat + (whichSitePats*numCompressedChars) + m->compCharStart;
	
	*lnL = 0.0;	/* reset lnL */

	lnL_SSE  = m->lnL_SSE;
	for (c=0; c<m->numSSEChars; c++)
		{
		mLike = _mm_setzero_ps ();
		for (k=0; k<m->numOmegaCats; k++)
			{
			mCatLike = _mm_setzero_ps ();
			for (j=0; j<nStates; j++)
				{
				m1 = _mm_mul_ps (clP[k][j], _mm_set1_ps ((CLFlt)bs[j]) );
				mCatLike = _mm_add_ps (mCatLike, m1);
				}
			m1 = _mm_mul_ps (mCatLike, _mm_set1_ps ((CLFlt)omegaCatFreq[k]) );
			mLike = _mm_add_ps (mLike, m1);
			clP[k] += nStates;
			}
		_mm_store_ps (lnL_SSE, mLike);
        lnL_SSE += FLOATS_PER_VEC;
		}
	for (c=m->numDummyChars; c<m->numChars; c++)
		{
		like = m->lnL_SSE[c];
		/* check against LIKE_EPSILON (values close to zero are problematic) */
		if (like < LIKE_EPSILON)
			{
			MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division, c, like);
            (*lnL)=MRBFLT_NEG_MAX;
			return ERROR;
			}
		else	
			{
			(*lnL) += (lnScaler[c] +  log(like)) * nSitesOfPat[c];
			}
		}

	return NO_ERROR;
	
}
#endif




/*------------------------------------------------------------------
|
|	Likelihood_Res: restriction site model with or without rate
|		variation
|
-------------------------------------------------------------------*/
int Likelihood_Res (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)

{

	int				c, k;
	MrBFlt			*bs, freq, like, pUnobserved, pObserved;
	CLFlt			*clPtr, **clP, *lnScaler, *nSitesOfPat;
	ModelInfo		*m;

	
	m = &modelSettings[division];

	/* find conditional likelihood pointer */
	clPtr = m->condLikes[m->condLikeIndex[chain][p->index]];
    clP = m->clP;
    for (k=0; k<m->numGammaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += m->numChars * m->numModelStates;
        }

	/* find base frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);

	/* find category frequencies */
	freq =  1.0 /  m->numGammaCats;

	/* find site scaler */
	lnScaler = m->scalers[m->siteScalerIndex[chain]];
    
	/* find nSitesOfPat */
	nSitesOfPat = numSitesOfPat + (whichSitePats*numCompressedChars) + m->compCharStart;
	
	*lnL = 0.0;	/* reset lnL */

	pUnobserved = 0.0;
	for (c=0; c<m->numDummyChars; c++)
		{
		like = 0.0;
		for (k=0; k<m->numGammaCats; k++)
			{
			like += (clP[k][0]*bs[0] + clP[k][1]*bs[1]) * freq;
			clP[k] += 2;
			}
		pUnobserved += like *  exp(lnScaler[c]);
		}

	pObserved =  1.0 - pUnobserved;
	if (pObserved < LIKE_EPSILON)
		{
		MrBayesPrint ("%s   WARNING: p(Observed) < LIKE_EPSILON - for division %d p(Observed) = %1.30lf\n", spacer, division, pObserved);
        (*lnL)=MRBFLT_NEG_MAX;
		return ERROR;
		}

	for (c=m->numDummyChars; c<m->numChars; c++)
		{
		like = 0.0;
		for (k=0; k<m->numGammaCats; k++)
			{
			like += (clP[k][0]*bs[0] + clP[k][1]*bs[1]) * freq;
			clP[k] += 2;
			}
		/* check against LIKE_EPSILON (values close to zero are problematic) */
		if (like < LIKE_EPSILON)
			{
			MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division, c, like);
            (*lnL)=MRBFLT_NEG_MAX;
			return ERROR;
			}
		else	
			{
			(*lnL) += (lnScaler[c] +  log(like)) * nSitesOfPat[c];
			}
		}

	/* correct for absent characters */
	(*lnL) -=  log(pObserved) * (m->numUncompressedChars);

	return NO_ERROR;
	
}





#if defined (SSE_ENABLED)
/*------------------------------------------------------------------
|
|	Likelihood_Res_SSE: 4by4 nucleotide models with or without rate
|		variation
|
-------------------------------------------------------------------*/
int Likelihood_Res_SSE (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)

{

	int				c, k;
	MrBFlt			freq, *bs, like, pUnobserved, pObserved;
	CLFlt			*lnScaler, *nSitesOfPat, *lnL_SSE;
    __m128          *clPtr, **clP;
    __m128          m1, mA, mB, mFreq, mLike;
	ModelInfo		*m;


	/* find model settings and pInvar, invar cond likes */
	m = &modelSettings[division];

	/* find conditional likelihood pointers */
	clPtr = (__m128 *) (m->condLikes[m->condLikeIndex[chain][p->index]]);
    clP = m->clP_SSE;
    for (k=0; k<m->numGammaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += m->numSSEChars * m->numModelStates;
        }
    lnL_SSE  = m->lnL_SSE;
	
	/* find base frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);
    mA = _mm_set1_ps ((CLFlt)(bs[0]));
    mB = _mm_set1_ps ((CLFlt)(bs[1]));

	freq =  1.0 / m->numGammaCats;
    mFreq = _mm_set1_ps ((CLFlt)(freq));

	/* find tree scaler */
	lnScaler = m->scalers[m->siteScalerIndex[chain]];

	/* find nSitesOfPat */
	nSitesOfPat = numSitesOfPat + (whichSitePats*numCompressedChars) + m->compCharStart;
	
	/* reset lnL */
	*lnL = 0.0;

	/* calculate variable likelihood */
	for (c=0; c<m->numSSEChars; c++)
		{
		mLike = _mm_setzero_ps ();
		for (k=0; k<m->numGammaCats; k++)
			{
			m1    = _mm_mul_ps (clP[k][0], mA);
            mLike = _mm_add_ps (mLike, m1);
            m1    = _mm_mul_ps (clP[k][1], mB);
            mLike = _mm_add_ps (mLike, m1);
			clP[k] += 2;
			}
        mLike = _mm_mul_ps (mLike, mFreq);
		_mm_store_ps (lnL_SSE, mLike);
        lnL_SSE += FLOATS_PER_VEC;
		}

	pUnobserved = 0.0;
	for (c=0; c<m->numDummyChars; c++)
		{
		like  = m->lnL_SSE[c];
		pUnobserved += like *  exp(lnScaler[c]);
		}

	pObserved =  1.0 - pUnobserved;
	if (pObserved < LIKE_EPSILON)
		{
		MrBayesPrint ("%s   WARNING: p(Observed) < LIKE_EPSILON - for division %d p(Observed) = %1.30lf\n", spacer, division, pObserved);
        (*lnL)=MRBFLT_NEG_MAX;
		return ERROR;
		}

	for (c=m->numDummyChars; c<m->numChars; c++)
		{
		like  = m->lnL_SSE[c];
		/* check against LIKE_EPSILON (values close to zero are problematic) */
		if (like < LIKE_EPSILON)
			{
			MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division, c, like);
            (*lnL)=MRBFLT_NEG_MAX;
			return ERROR;
			}
		else	
			{
			(*lnL) += (lnScaler[c] +  log(like)) * nSitesOfPat[c];
			}
		}

	/* correct for absent characters */
	(*lnL) -=  log(pObserved) * (m->numUncompressedChars);

	return NO_ERROR;


}
#endif





/*------------------------------------------------------------------
|
|	Likelihood_Std: variable states model with or without rate
|		variation
|
-------------------------------------------------------------------*/
int Likelihood_Std (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)

{
	int				b, c, j, k, nBetaCats, nGammaCats, nStates, numReps;
	MrBFlt			catLike, catFreq, gammaFreq, like, *bs, *bsBase,
					pUnobserved, pObserved;
	CLFlt			*clPtr, **clP, *lnScaler, *nSitesOfPat;
	ModelInfo		*m;


	m = &modelSettings[division];

	numReps=0;
	for (c=0; c<m->numChars; c++)
		{
		if ( m->nStates[c] == 2 )
				numReps += m->numBetaCats * 2;
			else
				numReps += m->nStates[c];
		}
	/* find conditional likelihood pointers */
    clPtr = m->condLikes[m->condLikeIndex[chain][p->index]];
    clP   = m->clP;
	for (k=0; k<m->numGammaCats; k++)
        {
        clP[k] = clPtr;
        clPtr += numReps;
        }
	
	/* find base frequencies */
	bsBase = GetParamStdStateFreqs (m->stateFreq, chain, state[chain]);

	/* find gamma category number and frequencies */
	nGammaCats = m->numGammaCats;
	gammaFreq = 1.0 /  nGammaCats;

	/* find site scaler */
	lnScaler = m->scalers[m->siteScalerIndex[chain]];
	
	/* find nSitesOfPat */
	nSitesOfPat = numSitesOfPat + (whichSitePats*numCompressedChars) + m->compCharStart;
	
	*lnL = 0.0;	/* reset lnL */

	if (m->numBetaCats == 1)
		{
		pUnobserved = 0.0;
		catFreq = gammaFreq;
		for (c=j=0; c<m->numDummyChars; c++)
			{
			like = 0.0;
			nStates = m->nStates[c];
			bs = bsBase + m->bsIndex[c];
			for (k=0; k<nGammaCats; k++)
				{
				catLike = 0.0;
				for (j=0; j<nStates; j++)
					catLike += clP[k][j] * bs[j];
				like += catLike * catFreq;
				clP[k] += nStates;
				}
			pUnobserved += like *  exp(lnScaler[c]);
			}

		pObserved =  1.0 - pUnobserved;
		if (pObserved < LIKE_EPSILON)
			pObserved =  LIKE_EPSILON;

		for (c=m->numDummyChars; c<m->numChars; c++)
			{
			like = 0.0;
			nStates = m->nStates[c];
			bs = bsBase + m->bsIndex[c];

			for (k=0; k<nGammaCats; k++)
				{
				catLike = 0.0;
				for (j=0; j<nStates; j++)
					catLike += clP[k][j] * bs[j];
				like += catLike * catFreq;
				clP[k] += nStates;
				}
			/* check against LIKE_EPSILON (values close to zero are problematic) */
			if (like < LIKE_EPSILON)
				{
				MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division+1, c+1, like);
                (*lnL)=MRBFLT_NEG_MAX;
				return ERROR;
				}
			else	
				{
				(*lnL) += (lnScaler[c] +  log(like)) * nSitesOfPat[c];
				}
			}
		}
	else
		{
		pUnobserved = 0.0;
		for (c=j=0; c<m->numDummyChars; c++)
			{
			like = 0.0;
			nStates = m->nStates[c];
			bs = bsBase + m->bsIndex[c];
			if (nStates == 2)
				{
				nBetaCats = m->numBetaCats;
				catFreq = gammaFreq /  nBetaCats;
				}
			else
				{
				nBetaCats = 1;
				catFreq = gammaFreq;
				}
			for (b=0; b<nBetaCats; b++)
				{
				for (k=0; k<nGammaCats; k++)
					{
					catLike = 0.0;
					for (j=0; j<nStates; j++)
						catLike += clP[k][j] * bs[j];
					like += catLike * catFreq;
					clP[k] += nStates;
					}
				bs += nStates;
				}
			pUnobserved += like *  exp(lnScaler[c]);
			}

		pObserved =  1.0 - pUnobserved;
		if (pObserved < LIKE_EPSILON)
			pObserved =  LIKE_EPSILON;

		for (c=m->numDummyChars; c<m->numChars; c++)
			{
			like = 0.0;
			nStates = m->nStates[c];
			bs = bsBase + m->bsIndex[c];
			if (nStates == 2)
				{
				nBetaCats = m->numBetaCats;
				catFreq = gammaFreq /  nBetaCats;
				}
			else
				{
				nBetaCats = 1;
				catFreq = gammaFreq;
				}
			for (b=0; b<nBetaCats; b++)
				{
				for (k=0; k<nGammaCats; k++)
					{
					catLike = 0.0;
					for (j=0; j<nStates; j++)
						catLike += clP[k][j] * bs[j];
					like += catLike * catFreq;
					clP[k] += nStates;
					}
				bs += nStates;
				}
			/* check against LIKE_EPSILON (values close to zero are problematic) */
			if (like < LIKE_EPSILON)
				{
				MrBayesPrint ("%s   WARNING: In LIKE_EPSILON - for division %d char %d has like = %1.30lf\n", spacer, division+1, c+1, like);
                (*lnL)=MRBFLT_NEG_MAX;
				return ERROR;
				}
			else	
				{
				(*lnL) += (lnScaler[c] +  log(like)) * nSitesOfPat[c];
				}
			}
		}

	/* correct for absent characters */
	(*lnL) -=  log(pObserved) * (m->numUncompressedChars);

	return NO_ERROR;
	
}





/*------------------------------------------------------------------
|
|	Likelihood_Pars: likelihood under the Tuffley and Steel (1997)
|		model for characters with constant number of states. The idea
|		is described in:
|
|       Tuffley, C., and M. Steel. 1997. Links between maximum likelihood
|          and maximum parsimony under a simple model of site substitution.
|          Bull. Math. Bio. 59:581-607.
|
|		The likelihood under the Tuffley and Steel (1997) model is:
|       
|	    L = k^[-(T + n)]
|	   
|	    where L is the likelihood
|	          k is the number of character states
|	          T is the parsimony tree length
|	          n is the number of characters 
|
|	The parsimony calculator does not use character packing; this is
|		to enable reweighting of characters 
|
|	Note that this is an empirical Bayes approach in that it uses the
|		maximum likelihood branch length.
|
-------------------------------------------------------------------*/
int Likelihood_Pars (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)

{
	
	int 			c, i, nStates;
	SafeLong		done, *pL, *pR, *pP, *pA, *oldpP, x;
	CLFlt			nParsChars, treeLength;
	CLFlt			length, *nSitesOfPat, *newNodeLength, oldNodeLength;
	Tree			*t;
	ModelInfo		*m;

	/* Find model settings */
	m = &modelSettings[division];

	/* Get tree */
	t = GetTree(m->brlens,chain,state[chain]);
	
	/* Get parsimony tree length */
	treeLength = (CLFlt) m->parsTreeLength[2 * chain + state[chain]];
	
	/* Get number of states */
	nStates = m->numStates;

	/* Get number of sites of pat */
	nSitesOfPat = numSitesOfPat + (whichSitePats*numCompressedChars) + m->compCharStart;

	/* Mark the nodes that can be stop nodes				 */
	/* (there must not be any touched side nodes below them) */
	p = t->root;
	p->marked = YES;
	for (i=t->nIntNodes-1; i>=0; i--)
		{
		p = t->intDownPass[i];
		p->marked = NO;
		if (p->upDateCl == YES && p->anc->marked == YES)
			{
			if (p->left->upDateCl == NO || p->right->upDateCl == NO)
				p->marked = YES;
			}
		}

	/* Now make downpass node by node */
	for (i=0; i<t->nIntNodes; i++)
		{
		p = t->intDownPass[i];

		/* continue if no work needs to be done */
		if (p->upDateCl == NO)
			continue;

        /* flip space */
		FlipCondLikeSpace(m, chain, p->index);
        
        /* find parsimony sets for the node and its environment */
		pL    = m->parsSets[m->condLikeIndex[chain][p->left->index ]];
        pR    = m->parsSets[m->condLikeIndex[chain][p->right->index]];
		oldpP = m->parsSets[m->condLikeScratchIndex[p->index       ]];
        pP    = m->parsSets[m->condLikeIndex[chain][p->index       ]];

		/* find old and new node lengths */
		oldNodeLength =  m->parsNodeLens[m->condLikeScratchIndex[p->index]];
		newNodeLength = &m->parsNodeLens[m->condLikeIndex[chain][p->index]];
		
		if (t->isRooted == NO && p->anc->anc == NULL)
			{
			pA = m->parsSets[m->condLikeIndex[chain][p->anc->index]];
            length = 0.0;
			for (c=0; c<m->numChars; c++)
				{
				x = pL[c] & pR[c];
				if (x == 0)
					{
					x = pL[c] | pR[c];
					length += nSitesOfPat[c];
					}
				if ((x & pA[c]) == 0)
					length += nSitesOfPat[c];
				pP[c] = x;
				}
			treeLength += (length - oldNodeLength);
			newNodeLength[0] = length;
			}
		else
			{
			length = 0.0;
			done = 0;
			for (c=0; c<m->numChars; c++)
				{
				x = pL[c] & pR[c];
				if (x == 0)
					{
					x = pL[c] | pR[c];
					length += nSitesOfPat[c];
					}
				pP[c] = x;
				done |= (x^oldpP[c]);
				}
			treeLength += (length - oldNodeLength);
			newNodeLength[0] = length;
			if (p->marked == YES && done == 0)
				break;
			}
		}

	/* Count number of characters in the partition. It is calculated
	   on the fly because this number is going to differ for
	   different chains if character reweighting is used. */
	nSitesOfPat = numSitesOfPat + (whichSitePats*numCompressedChars) + m->compCharStart;
	nParsChars = 0.0;
	for (c=0; c<m->numChars; c++)
		nParsChars += nSitesOfPat[c];

	/* Calculate likelihood from parsimony tree length */
	*lnL = - ((treeLength + nParsChars) *  log (nStates));

	/* Store current parsimony tree length */
	m->parsTreeLength[2 * chain + state[chain]] = treeLength;

	return (NO_ERROR);

}





int Likelihood_ParsCodon (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)

{

	int				x, y;
	TreeNode		*q;
	
	/* no warnings */
	q = p;
	x = division;
	y = chain;
	*lnL = 0.0;
	x = whichSitePats;

	MrBayesPrint ("%s   Parsimony calculator for codons not yet implemented\n", spacer);
	
	return ERROR;

}





/*------------------------------------------------------------------
|
|	Likelihood_Pars: likelihood under the Tuffley and Steel (1997)
|		model for characters with constant number of states. The idea
|		is described in:
|
|       Tuffley, C., and M. Steel. 1997. Links between maximum likelihood
|          and maximum parsimony under a simple model of site substitution.
|          Bull. Math. Bio. 59:581-607.
|
|		The likelihood under the Tuffley and Steel (1997) model is:
|       
|	    L = k^[-(T + n)]
|	   
|	    where L is the likelihood
|	          k is the number of character states
|	          T is the parsimony tree length
|	          n is the number of characters 
|
|	The parsimony calculator does not use character packing; this is
|		to enable reweighting of characters 
|
|	Note that this is an empirical Bayes approach in that it uses the
|		maximum likelihood branch length.
|
|	This variant of the calculator assumes that the number of states
|       is variable. It does not take state order into account.
|
-------------------------------------------------------------------*/
int Likelihood_ParsStd (TreeNode *p, int division, int chain, MrBFlt *lnL, int whichSitePats)

{
	
	int				c, i, *nStates;
	SafeLong			*pL, *pR, *pP, *pA, *oldpP, x;
	CLFlt			*treeLength;
	CLFlt			*nSitesOfPat;
	Tree			*t;
	ModelInfo		*m;

	/* Find model settings */
	m = &modelSettings[division];

	/* Get tree */
	t = GetTree(m->brlens,chain,state[chain]);
	
	/* Allocate space for parsimony tree length */
	treeLength = (CLFlt *) SafeCalloc (m->numChars, sizeof (CLFlt));
	
	/* Get number of states */
	nStates = m->nStates;

	/* Get number of sites of pat */
	nSitesOfPat = numSitesOfPat + (whichSitePats*numCompressedChars) + m->compCharStart;

	/* Make downpass node by node; do not skip any nodes */
	for (i=0; i<t->nIntNodes; i++)
		{
		p = t->intDownPass[i];

        /* flip space */
		FlipCondLikeSpace(m, chain, p->index);
        
        /* find parsimony sets for the node and its environment */
		pL    = m->parsSets[m->condLikeIndex[chain][p->left->index ]];
        pR    = m->parsSets[m->condLikeIndex[chain][p->right->index]];
		oldpP = m->parsSets[m->condLikeScratchIndex[p->index       ]];
        pP    = m->parsSets[m->condLikeIndex[chain][p->index       ]];

		if (t->isRooted == NO && p->anc->anc == NULL)
			{
			pA = m->parsSets[m->condLikeIndex[chain][p->anc->index]];
            for (c=0; c<m->numChars; c++)
				{
				x = pL[c] & pR[c];
				if (x == 0)
					{
					x = pL[c] | pR[c];
					treeLength[c] += nSitesOfPat[c];
					}
				if ((x & pA[c]) == 0)
					treeLength[c] += nSitesOfPat[c];
				pP[c] = x;
				}
			}
		else
			{
			for (c=0; c<m->numChars; c++)
				{
				x = pL[c] & pR[c];
				if (x == 0)
					{
					x = pL[c] | pR[c];
					treeLength[c] += nSitesOfPat[c];
					}
				pP[c] = x;
				}
			}
		}

	/* Calculate the likelihood one character at a time */
	*lnL = 0.0;
	for (c=0; c<m->numChars; c++)
		{
		*lnL -= ((treeLength[c] + nSitesOfPat[c]) * log (nStates[c]));
		}

	/* Free space for parsimony character states */
	free (treeLength);

	return (NO_ERROR);

}





/* ln prior ratio for clock trees */
int LogClockTreePriorRatio (Param *param, int chain, MrBFlt *lnPriorRatio)

{
    MrBFlt          oldLnPrior, newLnPrior, theta, N, growth, sR, eR, sF, clockRate;
    char            *sS;
    Model           *mp;
    ModelInfo       *m;
    Tree            *newTree, *oldTree;
    TreeNode        *p, *q=NULL;
    int             i, j;

    (*lnPriorRatio) = 0.0;
    
    mp = &modelParams[param->relParts[0]];
    m  = &modelSettings[param->relParts[0]];
    
    newTree = GetTree (m->brlens, chain, state[chain]);
    oldTree = GetTree (m->brlens, chain, state[chain]^1);

    if (m->clockRate != NULL)
        clockRate = *GetParamVals(m->clockRate, chain, state[chain]);
    else
        clockRate = 1.0;
    
    /* calculate prior ratio on brlens of clock tree */
	if (!strcmp(mp->clockPr,"Coalescence"))
		{
		/* coalescence prior */
        /* first calculate theta as 4*N*mu, 3*N*mu or 2*N*mu */
		N = *(GetParamVals (m->popSize, chain, state[chain]));
        if (!strcmp(mp->ploidy, "Diploid"))
            theta = 4 * N * clockRate;
        else if (!strcmp(mp->ploidy, "Zlinked"))
            theta = 3 * N * clockRate;
        else
            theta = 2 * N * clockRate;
        /* deal with growth */
        if (!strcmp(mp->growthPr, "Fixed"))
			growth = mp->growthFix;
		else
			growth = *(GetParamVals (m->growthRate, chain, state[chain]));
		if (LnCoalescencePriorPr (oldTree, clockRate, &oldLnPrior, theta, growth) == ERROR)
			{
			MrBayesPrint ("%s   Problem calculating prior for coalescence process\n", spacer);
			return (ERROR);
			}
		if (LnCoalescencePriorPr (newTree, clockRate, &newLnPrior, theta, growth) == ERROR)
			{
			MrBayesPrint ("%s   Problem calculating prior for coalescence process\n", spacer);
			return (ERROR);
			}
        (*lnPriorRatio) = (newLnPrior - oldLnPrior);
		}
	else if (!strcmp(mp->clockPr,"Birthdeath"))
		{
		/* birth-death prior */
		sR = *(GetParamVals (m->speciationRates, chain, state[chain]));
		eR = *(GetParamVals (m->extinctionRates, chain, state[chain]));
		sS = mp->sampleStrat;
		sF = mp->sampleProb;
		if (LnBirthDeathPriorPr (oldTree, clockRate, &oldLnPrior, sR, eR, sS, sF) == ERROR)
			{
			MrBayesPrint ("%s   Problem calculating prior for birth-death process\n", spacer);
			return (ERROR);
			}
		if (LnBirthDeathPriorPr (newTree, clockRate, &newLnPrior, sR, eR, sS, sF) == ERROR)
			{
			MrBayesPrint ("%s   Problem calculating prior for birth-death process\n", spacer);
			return (ERROR);
			}
        (*lnPriorRatio) = (newLnPrior - oldLnPrior);
		}
    else if (!strcmp(mp->clockPr,"Uniform"))
        {
        oldLnPrior = LnUniformPriorPr(oldTree, clockRate);
        newLnPrior = LnUniformPriorPr(newTree, clockRate);
        (*lnPriorRatio) = (newLnPrior - oldLnPrior);
        }
    else if (!strcmp(mp->clockPr,"Speciestreecoalescence"))
        {
        // Defer this calculation to the BEST code
        }

    assert (*lnPriorRatio > NEG_INFINITY);

    /* take care of calibrations */
    if (newTree->isCalibrated == YES)
        {
        for (i=0; i<newTree->nNodes-1; i++)
            {
            p = newTree->allDownPass[i];
            if (p->isDated == NO)
                continue;
            for (j=0; j<oldTree->nNodes-1; j++)
                {
                q = oldTree->allDownPass[j];
                if (p->lockID == q->lockID)
                    break;
                }
            assert (j != oldTree->nNodes-1);
            if (p->isDated == YES && p->calibration->prior != fixed)
                {
                if (p->calibration->prior == offsetExponential)
                    (*lnPriorRatio) += p->calibration->lambda * (q->age - p->age);
                }
            }
        }

    return (NO_ERROR);
}




/*-----------------------------------------------------------------
|
|	LaunchLogLikeForDivision: calculate the log likelihood of the 
|		new state of the chain for a single division
|
-----------------------------------------------------------------*/
void LaunchLogLikeForDivision(int chain, int d, MrBFlt* lnL) {
	int i;
	TreeNode		*p;
	ModelInfo		*m;
	Tree			*tree;
#if defined (TIMING_ANALIZ)
    clock_t         CPUTimeStart;
#endif
	
	m = &modelSettings[d];
	tree = GetTree(m->brlens, chain, state[chain]);
	
	if (m->upDateCijk == YES)
		{
        if( UpDateCijk(d, chain)== ERROR)
            {
            (*lnL) = MRBFLT_NEG_MAX; /*effectively abort the move*/
            return;
            }
		m->upDateAll = YES;
		}
	
#if defined (BEAGLE_ENABLED)
	if (m->useBeagle == YES)
		{
		LaunchBEAGLELogLikeForDivision(chain, d, m, tree, lnL);
		return;
		}
#endif
		
	/* Flip and copy or reset site scalers */
	FlipSiteScalerSpace(m, chain);
	if (m->upDateAll == YES)
		ResetSiteScalers(m, chain);
	else
		CopySiteScalers(m, chain);
	
	if (m->parsModelId == NO)
	{
		for (i=0; i<tree->nIntNodes; i++)
		{
			p = tree->intDownPass[i];
			
			if (p->left->upDateTi == YES)
			{
				/* shift state of ti probs for node */
				FlipTiProbsSpace (m, chain, p->left->index);
				m->TiProbs (p->left, d, chain);
			}
			
			if (p->right->upDateTi == YES)
			{
				/* shift state of ti probs for node */
				FlipTiProbsSpace (m, chain, p->right->index);
				m->TiProbs (p->right, d, chain);
			}
			
			if (tree->isRooted == NO)
			{
				if (p->anc->anc == NULL /* && p->upDateTi == YES */)
				{
					/* shift state of ti probs for node */
					FlipTiProbsSpace (m, chain, p->index);
					m->TiProbs (p, d, chain);
				}
			}
			
			if (p->upDateCl == YES)
			{
				if (tree->isRooted == NO)
				{
                    if (p->anc->anc == NULL)
                        {
						TIME(m->CondLikeRoot (p, d, chain),CPUCondLikeRoot);
                        }
					else
                        {
						TIME(m->CondLikeDown (p, d, chain),CPUCondLikeDown);                        
                        }
				}
				else
                    {
					TIME(m->CondLikeDown (p, d, chain),CPUCondLikeDown);
                    }

				if (m->scalersSet[chain][p->index] == YES && m->upDateAll == NO)
                    {
#if defined (SSE_ENABLED)
                    if (m->useSSE == YES)
                        {
    					TIME(RemoveNodeScalers_SSE (p, d, chain),CPUScalersRemove);
                        }
                    else
                        {
                        TIME(RemoveNodeScalers (p, d, chain),CPUScalersRemove);
                        }
#else
				TIME(RemoveNodeScalers (p, d, chain),CPUScalersRemove);
#endif
                    }
				FlipNodeScalerSpace (m, chain, p->index);
				m->scalersSet[chain][p->index] = NO;
				
                if (p->scalerNode == YES)
                    {
                    TIME(m->CondLikeScaler (p, d, chain),CPUScalers);
                    }
			}
		}
	}
	TIME(m->Likelihood (tree->root->left, d, chain, lnL, (chainId[chain] % chainParams.numChains)),CPULilklihood);
    return;
}





/*-----------------------------------------------------------------
|
|	LogLike: calculate the log likelihood of the new state of the
|		chain
|
-----------------------------------------------------------------*/
MrBFlt LogLike (int chain)

{

	int				i, d;
	ModelInfo		*m;
	MrBFlt			chainLnLike, lnL;
						
	/* initialize chain cond like */
	chainLnLike = 0.0;
	
	if (chainParams.runWithData == NO)
		return (chainLnLike);

#	if defined (DEBUG_RUN_WITHOUT_DATA)
	return (chainLnLike);
#	endif

#if defined (THREADS_ENABLED)
    if (tryToUseThreads && ScheduleLogLikeForAllDivisions()) 
		{
		/* Launch all divisions that require updating simultaneously */
		chainLnLike = LaunchLogLikeForAllDivisionsInParallel(chain);
		} 
		else 
		{
		/* Launch divisions in series */
#endif
		
	/* Cycle through divisions and recalculate tis and cond likes as necessary. */
	/* Code below does not try to avoid recalculating ti probs for divisions    */
	/* that could share ti probs with other divisions.                          */
	for (d=0; d<numCurrentDivisions; d++)
		{
		
#if defined (BEST_MPI_ENABLED)
        if (isDivisionActive[d] == NO)
            continue;
#endif
		m = &modelSettings[d];
		if (m->upDateCl == YES)	
			{	
			/* Work has been delegated to a separate function so we can wrap    */
			/* a thread around it                                               */				
			LaunchLogLikeForDivision(chain, d, &(m->lnLike[2 * chain + state[chain]]));							
			}
		chainLnLike += m->lnLike[2*chain + state[chain]];	
		}
		
#if defined (THREADS_ENABLED)
		}
#endif				

	/* unmark all divisions */
	if (chainHasAdgamma == YES)
		{
		for (d=0; d<numCurrentDivisions; d++)
			{
			m = &modelSettings[d];
			m->mark = NO;
			}
		
		/* update HMM likelihoods if appropriate */
		for (d=0; d<numCurrentDivisions; d++)
			{
#if defined (BEST_MPI_ENABLED)
            if (isDivisionActive[d] == NO)
                continue;
#endif
			m = &modelSettings[d];
			
			if (m->upDateCl == YES && m->correlation != NULL && m->mark != YES)
				{
				lnL = 0.0;
				CalcLike_Adgamma(d, m->correlation, chain, &lnL);

				/* store the value for the cases where the HMM is not touched */
				m->lnLike[2*chain + state[chain]] =  lnL;
				
				/* add it to chainLnLike - it was not added above since the division */
				/* lnL was set to zero after the update call to Likelihood_Adgamma */
				chainLnLike += lnL;
				
				/* set mark for other divisions in the HMM
				   (i.e., those with the same correlation parameter
				   AND the same gamma shape parameter) */
				for (i=0; i<m->correlation->nRelParts; i++)
					{
					if (modelSettings[m->correlation->relParts[i]].shape ==
						modelSettings[d].shape)
						{
						modelSettings[m->correlation->relParts[i]].mark = YES;
						}
					}
				}
			}
		}

	return (chainLnLike);	
}



MrBFlt LogOmegaPrior (MrBFlt w1, MrBFlt w2, MrBFlt w3)

{

	/* This function returns the log prior probability of 
	   the ratio on three omegas. Here, we have three
	   nonsynonymous/synonymous rate ratios, denoted w1, w2,
	   and w3. They have the property that w1 < w2 < w3. 
	   Remember that w1 = dN1/dS, w2 = dN2/dS, and
	   w3 = dN3/dS. We assume that dN1, dN2, dN3, and dS
	   are all independent draws from the same exponential
	   distribution, and that dN1, dN2, and dN3 are the
	   order statistics. The w1, w2, and w3, then, are
	   all scaled to the same dS r.v. */
	   
	MrBFlt		lnProb;
	
	lnProb =  (log(36.0) - 4.0 * log(1.0 + w1 + w2 + w3));
	 
	return (lnProb);
	 
}




 
MrBFlt LogPrior (int chain)

{

	int				i, j, c, n, nStates, *nEvents, sumEvents, *ist, nRates, nParts[6];
	const int		*rateCat;
	MrBFlt			*st, *sst, lnPrior, sum, x, clockRate, theta, popSize, growth, *alphaDir, newProp[190],
					sR, eR, sF, freq, pInvar, lambda, sigma, nu, igrvar, **rateMultiplier;
	char			*sS;
	CLFlt			*nSitesOfPat;
	Param			*p;
	ModelParams 	*mp;
	ModelInfo		*m;
	Tree			*t;
	TreeNode		*branch, *q;
	
	lnPrior	= 0.0;
	for (n=0; n<numParams; n++)
		{
		p = &params[n];
#if defined (MPI_BEST_ENABLED)
        /* We skip all parameters that are not handled on this processor. The scheme used here
           requires that parameters either be unique to one partition (processor) or that they
           are shared across all partitions and that the first processor has all the relevant
           information about that parameter. */
        if (isDivisionActive[p->relParts[0]] == NO)
            continue;
#endif
        
		st  = GetParamVals (p, chain, state[chain]);
		sst = GetParamSubVals (p, chain, state[chain]);
		mp = &modelParams[p->relParts[0]];
		m = &modelSettings[p->relParts[0]];

        if (p->paramType == P_TRATIO)
			{
			/* tratio parameter */
			if (p->paramId == TRATIO_DIR)
				{
				alphaDir = mp->tRatioDir;
				newProp[0] =  (st[0] / (st[0] + 1.0));
				newProp[1] =  (1.0 - newProp[0]);
				x = 0.0;
				for (i=0; i<2; i++)
					x += (alphaDir[i]-1.0)*log(newProp[i]);
				lnPrior += x;
				}
			else
				{
				
				}
			}
		else if (p->paramType == P_REVMAT)
			{
			/* revmat parameter */
			if (p->paramId == REVMAT_DIR)
				{
				if (p->nValues == 6)
                    alphaDir = mp->revMatDir;
                else /* if (p->nValues == 190) */
                    alphaDir = mp->aaRevMatDir;
                sum = 0.0;
                for (i=0; i<p->nValues; i++)
                    sum += alphaDir[i];
                x = LnGamma(sum);
                for (i=0; i<p->nValues; i++)
                    x -= LnGamma(alphaDir[i]);
				for (i=0; i<p->nValues; i++)
					x += (alphaDir[i] - 1.0) * log(st[i]);
				lnPrior += x;
				}
			else if (p->paramId == REVMAT_MIX)
				{
				assert (p->nValues == 6);
                alphaDir = &mp->revMatSymDir;
                ist      = GetParamIntVals(p, chain, state[chain]); /* the growth fxn */
                nRates   = GetKFromGrowthFxn(ist);
                /* get the actual rate proportions of the current groups */
                for (i=0; i<nRates; i++)
                    {
					newProp[i] = 0.0;
                    nParts[i] = 0;
                    }
				for (i=0; i<6; i++)
                    {
                    nParts[ist[i]]++;
                    newProp[ist[i]] += st[i];
                    }
                /* now we calculate probability as usual, with alpha
                   parameter multiplied by number of parts */
                x = LnGamma(6.0 * alphaDir[0]);
                for (i=0; i<nRates; i++)
                    x -= LnGamma(nParts[i] * alphaDir[0]);
				for (i=0; i<nRates; i++)
					x += (nParts[i] * alphaDir[0] - 1.0) * log(newProp[i]);
                /* finally take model probability into account */
                x += log (1.0 / 203);
				lnPrior += x;
				}
			else
				{
                /* fixed or empirical */
				}
			}
		else if (p->paramType == P_OMEGA)
			{
			/* account for prior on omega proportion if 1 omega category */
			if (p->paramId == OMEGA_DIR)
				{
				alphaDir = mp->omegaDir;
				newProp[0] = st[0] / (st[0] + 1.0);
				newProp[1] = 1.0 - newProp[0];
                sum = 0.0;
                for (i=0; i<2; i++)
                    sum += alphaDir[i];
                x = LnGamma(sum);
                for (i=0; i<2; i++)
                    x -= LnGamma(alphaDir[i]);
				for (i=0; i<2; i++)
					x += (alphaDir[i]-1.0)*log(newProp[i]);
				lnPrior += x;
				}
			/* account for stationary state frequencies of M3 and ny98 omega categories */
			if (p->paramId == OMEGA_BUD || p->paramId == OMEGA_BED ||
                p->paramId == OMEGA_BFD || p->paramId == OMEGA_FUD ||
                p->paramId == OMEGA_FED || p->paramId == OMEGA_FFD ||
                p->paramId == OMEGA_ED || p->paramId == OMEGA_FD)
                {
                alphaDir = mp->codonCatDir;             
				x = 0.0;
				for (i=0; i<3; i++)
					x += (alphaDir[i]-1.0)*log(sst[i]);
				lnPrior += x;
                }
			/* account for beta prior on omeganeg in NY98 */
			if (p->paramId == OMEGA_BUD || p->paramId == OMEGA_BUF ||
                p->paramId == OMEGA_BED || p->paramId == OMEGA_BEF ||
                p->paramId == OMEGA_BFD || p->paramId == OMEGA_BFF)
				{
                alphaDir = mp->ny98omega1Beta;
				newProp[0] = st[0] / (st[0] + 1.0);
				newProp[1] = 1.0 - newProp[0];
				x = 0.0;
				for (i=0; i<2; i++)
					x += (alphaDir[i]-1.0)*log(newProp[i]);
				lnPrior += x;
				}
			/* account for omegapos in NY98 with uniform prior prob */
			if (p->paramId == OMEGA_BUD || p->paramId == OMEGA_BUF ||
                p->paramId == OMEGA_FUD || p->paramId == OMEGA_FUF)
				{
                lnPrior += log(mp->ny98omega3Uni[0] - mp->ny98omega3Uni[0]);
				}
			/* account for omegapos in NY98 with exponential prior prob */
			if (p->paramId == OMEGA_BED || p->paramId == OMEGA_BEF ||
                p->paramId == OMEGA_FED || p->paramId == OMEGA_FEF)
				{
                lnPrior += (log(mp->ny98omega3Exp) - mp->ny98omega3Exp * st[2]);
				}
			/* account for omegas in M3, which can only be exponential; if fixed, ln prior prob is 0 */
			if (p->paramId == OMEGA_EF || p->paramId == OMEGA_ED)
				{
                lnPrior += LogOmegaPrior (st[0], st[1], st[2]);
				}
			}
		else if (p->paramType == P_PI)
			{
			/* state frequencies parameter */
			if (p->paramId == PI_DIR)
				{
				nStates = p->nSubValues;
				sum = 0.0;
				for (i=0; i<nStates; i++)
					sum += st[i];
				x = LnGamma(sum);
				for (i=0; i<nStates; i++)
					x -= LnGamma(st[i]);
				for (i=0; i<nStates; i++)
					x += (st[i] - 1.0)*log(sst[i]);
				lnPrior += x;
				}
            else if (p->paramId == SYMPI_EXP || p->paramId == SYMPI_EXP_MS)
                {
                lnPrior += - mp->symBetaExp * st[0] + log(mp->symBetaExp);
                }
            else if (p->paramId == SYMPI_UNI || p->paramId == SYMPI_UNI_MS)
                {
                lnPrior += - log(mp->symBetaUni[1] - mp->symBetaUni[0]);
                }                
            if (p->paramId == SYMPI_EXP_MS || p->paramId == SYMPI_UNI_MS || p->paramId == SYMPI_FIX_MS)
                {
                sst = GetParamStdStateFreqs(p, chain, state[chain]);
                sst += 2*m->numBetaCats;
                for (i=0; i<p->nSympi; i++)
                    {
			        nStates = p->sympinStates[i];
			        x = LnGamma(nStates*st[0]) - nStates*LnGamma(st[0]);
			        for (j=0; j<nStates; j++)
				        x += (st[0] - 1.0)*log(sst[j]);
			        lnPrior += x;
                    sst += nStates;
                    }
                }
			}
		else if (p->paramType == P_SHAPE)
			{
			/* gamma shape parameter */
			if (p->paramId == SHAPE_UNI)
				{
				lnPrior += log(1.0) - log(mp->shapeUni[1] - mp->shapeUni[0]);
				}
			else if (p->paramId == SHAPE_EXP)
				{
				lnPrior += log(mp->shapeExp) - mp->shapeExp * st[0];
				}
			for (i=0; i<p->nRelParts; i++)
				{
				m = &modelSettings[p->relParts[i]];
				if (m->gibbsGamma == YES)
					{
					if (m->pInvar == NULL)
						lnPrior += log(1.0/m->numGammaCats) * m->numUncompressedChars;
					else
						{
						rateCat = m->tiIndex + chain * m->numChars;
						pInvar = *GetParamVals (m->pInvar, chain, state[chain]);
						nSitesOfPat = numSitesOfPat + m->compCharStart;
						freq = (1.0 - pInvar)/m->numGammaCats;
						for (c=0; c<m->numChars; c++)
							{
							if (rateCat[c] < m->numGammaCats)
								lnPrior += log(freq) * nSitesOfPat[c];
							else
								lnPrior += log(pInvar) * nSitesOfPat[c];
							}
						}
					}
				}
			}
		else if (p->paramType == P_PINVAR)
			{
			/* proportion of invariable sites parameter */
			lnPrior += log(1.0) - log(mp->pInvarUni[1] - mp->pInvarUni[0]);
			}
		else if (p->paramType == P_CORREL)
			{
			/* adGamma model parameter */
			lnPrior += log(1.0) - log(mp->corrUni[1] - mp->corrUni[0]);
			}
		else if (p->paramType == P_SWITCH)
			{
			/* switching rate parameter of covarion model */
			if (p->paramId == SWITCH_UNI)
				{
				lnPrior += log(1.0) - log(mp->covswitchUni[1] - mp->covswitchUni[0]);
				}
			else if (p->paramId == SWITCH_EXP)
				{
				lnPrior += log(mp->covswitchExp) - mp->covswitchExp * st[0];
				}
			}
		else if (p->paramType == P_RATEMULT && p->nValues > 1)
			{
			nStates = p->nValues;
			sum = 0.0;
			for (i=0; i<nStates; i++)
				sum += sst[i+nStates];
			x = LnGamma(sum);
			for (i=0; i<nStates; i++)
				x -= LnGamma(sst[i+nStates]);
			for (i=0; i<nStates; i++)
				x += (sst[i+nStates] - 1.0)*log(st[i]);
			lnPrior += x;
			}
		else if (p->paramType == P_GENETREERATE && p->nValues > 1)
			{
			nStates = p->nValues;
			sum = 0.0;
			for (i=0; i<nStates; i++)
				sum += sst[i+nStates];
			x = LnGamma(sum);
			for (i=0; i<nStates; i++)
				x -= LnGamma(sst[i+nStates]);
			for (i=0; i<nStates; i++)
				x += (sst[i+nStates] - 1.0)*log(st[i]);
			lnPrior += x;
			}
		else if (p->paramType == P_TOPOLOGY)
			{
            // Note that a topology can have several unlinked branch length subparameters but only
            // one set of clock branch lengths. To find all the branch length subparameters of a
            // topology, cycle through the p->subParams, which will contain at least one branch length
            // parameter.
			t = GetTree (p, chain, state[chain]);
            if (t->isClock == YES)
                continue;   /* prior probability taken care of in the brlens parameter */
            if (t->nLocks > 0)
                {
                for (i=0; i<t->nNodes-1; i++)
                    {
                    branch = t->allDownPass[i];
                    if (branch->left == NULL)
                        branch->x = 1;
                    else
                        branch->x = branch->left->x + branch->right->x;
                    if (branch->isLocked == YES || branch->anc->anc == NULL)
                        {
                        for (j = 2*branch->x - 3; j>=1; j-=2)
                            {
                            lnPrior -= log ((MrBFlt)j);
                            }
                        branch->x = 1;
                        }
                    }
                }
            else
                {
                for (j = 2*(t->nNodes-t->nIntNodes)-5; j>=1; j-=2)
                    {
                    lnPrior -= log ((MrBFlt)j);
                    }
                }
			}
		else if (p->paramType == P_BRLENS)
			{
			/* branch lengths */
			t = GetTree (p, chain, state[chain]);
			if (t->isClock == YES)
				{
                if (p->paramId == BRLENS_CLOCK_UNI)
					{
					/* uniformly distributed branch lengths */
                    clockRate = *(GetParamVals (m->clockRate, chain, state[chain]));
                    lnPrior += LnUniformPriorPr(t, clockRate);
                    }
				else if (p->paramId == BRLENS_CLOCK_COAL)
					{
					/* coalescence prior */
					popSize   = *(GetParamVals (m->popSize, chain, state[chain]));
                    clockRate = *(GetParamVals (m->clockRate, chain, state[chain]));
                    if (strcmp(mp->ploidy, "Diploid") == 0)
                        theta = 4.0 * popSize * clockRate;
                    else if (strcmp(mp->ploidy, "Zlinked") == 0)
                        theta = 3.0 * popSize * clockRate;
                    else
                        theta = 2.0 * popSize * clockRate;
					if (!strcmp(mp->growthPr, "Fixed"))
						growth = mp->growthFix;
					else
						growth = *(GetParamVals (m->growthRate, chain, state[chain]));
					if (LnCoalescencePriorPr (t, clockRate, &x, theta, growth) == ERROR)
						{
						MrBayesPrint ("%s   Problem calculating prior for coalescence process\n", spacer);
						}
					lnPrior += x;
					}
                else if (p->paramId == BRLENS_CLOCK_BD)
					{
					/* birth-death prior */
					sR        = *(GetParamVals (m->speciationRates, chain, state[chain]));
					eR        = *(GetParamVals (m->extinctionRates, chain, state[chain]));
					sS        = mp->sampleStrat;
					sF        = mp->sampleProb;
                    if (m->clockRate != NULL)
                        clockRate = *(GetParamVals (m->clockRate, chain, state[chain]));
                    else
                        clockRate = 1.0;
					if (LnBirthDeathPriorPr (t, clockRate, &x, sR, eR, sS, sF) == ERROR)
						{
						MrBayesPrint ("%s   Problem calculating prior for birth-death process\n", spacer);
						}
					lnPrior += x;
					}
                else if (p->paramId == BRLENS_CLOCK_SPCOAL)
                    {
                    /* delegate this calculation to the P_SPECIESTREE parameter */
                    }
                if (t->isCalibrated == YES)
                    {
                    /* take care of calibrations */
                    for (i=0; i<t->nNodes-1; i++)
                        {
                        q = t->allDownPass[i];
                        if (q->isDated == YES && q->calibration->prior != fixed)
                            {
                            if (q->calibration->prior == uniform)
                                lnPrior += -log(q->calibration->max-q->calibration->min);
                            else if (q->calibration->prior == offsetExponential)
                                lnPrior +=  log (q->calibration->lambda) - q->calibration->lambda*(q->age - q->calibration->offset);
                            }
                        }
                    }
				}
			else
				{
				if (p->paramId == BRLENS_UNI)
					{
					for (i=0; i<t->nNodes; i++)
						{
						branch = t->allDownPass[i];
						if (branch->anc != NULL)
							lnPrior += log(1.0) - log(mp->brlensUni[1] - BRLENS_MIN);
						}
					}
				else if (p->paramId == BRLENS_EXP)
					{
					for (i=0; i<t->nNodes; i++)
						{
						branch = t->allDownPass[i];
						if (branch->anc != NULL)
							lnPrior += log(mp->brlensExp) - mp->brlensExp * branch->length;
						}
					}
				}
			}
		else if (p->paramType == P_SPECRATE)
			{
			/* speciation rate parameter */
			if (p->paramId == SPECRATE_UNI)
				{
				lnPrior += log(1.0) - log(mp->speciationUni[1] - mp->speciationUni[0]);
				}
			else if (p->paramId == SPECRATE_EXP)
				{
				lnPrior += log(mp->speciationExp) - mp->speciationExp * st[0];
				}
			}
		else if (p->paramType == P_EXTRATE)
			{
			/* extinction rate parameter */
			if (p->paramId == EXTRATE_BETA)
				{
				alphaDir = mp->extinctionBeta;
				newProp[0] =  (st[0] / (st[0] + 1.0));
				newProp[1] =  (1.0 - newProp[0]);
				x = 0.0;
				for (i=0; i<2; i++)
					x += (alphaDir[i]-1.0)*log(newProp[i]);
				lnPrior += x;
				}
			}
		else if (p->paramType == P_POPSIZE)
			{
			/* neutral coalescence population size parameter; one value, or one value per branch of species tree */
			for (i=0; i<p->nValues; i++)
                {
                lnPrior += p->LnPriorProb(st[i], p->priorParams);
                }
			}
		else if (p->paramType == P_AAMODEL)
			{
			lnPrior += sst[(int)st[0]];
			}
		else if (p->paramType == P_BRCORR)
			{
			
			
			

			}
		else if (p->paramType == P_BRSIGMA)
			{
			
			
			

			}
		else if (p->paramType == P_GROWTH)
			{
			/* population growth parameter */
			if (p->paramId == GROWTH_UNI)
				{
				lnPrior += log(1.0) - log(mp->growthUni[1] - mp->growthUni[0]);
				}
			else if (p->paramId == GROWTH_EXP)
				{
				lnPrior += log(mp->growthExp) - mp->growthExp * st[0];
				}
			}
		else if (p->paramType == P_CPPRATE)
			{
			/* rate (lambda) of comp poisson process of relaxed clock */
			if (p->paramId == CPPRATE_EXP)
				{
				lnPrior += log (mp->cppRateExp) - mp->cppRateExp * st[0];
				}
			}
		else if (p->paramType == P_CPPMULTDEV)
			{
			/* standard deviation (log) of lognormal distribution of rate multipliers for cpp relaxed clock */
            /* only fixed value allowed currently */
			}
		else if (p->paramType == P_CPPEVENTS)
			{
			/* events of CPP relaxed clock process */
			lambda = *GetParamVals (m->cppRate, chain, state[chain]);
			sigma = *GetParamVals (m->cppMultDev, chain, state[chain]);
			nEvents = p->nEvents[2*chain+state[chain]];
			rateMultiplier = p->rateMult[2*chain+state[chain]];
			/* cpp events */
			sumEvents = 0;
			for (i=0; i<2*numLocalTaxa-2; i++)
				sumEvents += nEvents[i];
			t = GetTree (p, chain, state[chain]);
			lnPrior += - lambda * TreeLength (p, chain) + (sumEvents * log (lambda));
			/* rate multipliers */
			for (i=0; i<2*numLocalTaxa-2; i++)
				{
				for (j=0; j<nEvents[i]; j++)
					lnPrior += LnProbLogNormal (0.0, sigma, rateMultiplier[i][j]);
				}
			for (i=0; i<t->nNodes-2; i++)
				{
                branch = t->allDownPass[i];
                assert (fabs(branch->length - (branch->anc->nodeDepth - branch->nodeDepth)) < 0.000001);
				}
			}
		else if (p->paramType == P_TK02VAR)
			{
			/* variance of rates (nu) in Thorne-Kishino model */
			if (p->paramId == TK02VAR_EXP)
				{
				lnPrior += log (mp->tk02varExp) - mp->tk02varExp * st[0];
				}
			else if (p->paramId == TK02VAR_UNI)
				{
				lnPrior += (- log (mp->tk02varUni[1] - mp->tk02varUni[0]));
				}
			}
		else if (p->paramType == P_TK02BRANCHRATES)
			{
			/* branch rates of Thorne-Kishino model */
			t = GetTree (p, chain, state[chain]);
			nu = *GetParamVals (m->tk02var, chain, state[chain]);
			for (i=0; i<t->nNodes-2; i++)
				{
				branch = t->allDownPass[i];
				lnPrior += LnProbTK02LogNormal (st[branch->anc->index], nu*branch->length, st[branch->index]);
				}
			}
        else if (p->paramType == P_IGRVAR)
			{
			/* shape of scaled gamma used in independent branch rates model */
			if (p->paramId == IGRVAR_EXP)
				{
				lnPrior += log (mp->igrvarExp) - mp->igrvarExp * st[0];
				}
			else if (p->paramId == IGRVAR_UNI)
				{
				lnPrior += (- log (mp->igrvarUni[1] - mp->igrvarUni[0]));
				}
			}
		else if (p->paramType == P_IGRBRANCHLENS)
			{
			/* branch rates of independent branch rate model */
			t = GetTree (p, chain, state[chain]);
			igrvar = *GetParamVals (m->igrvar, chain, state[chain]);
			for (i=0; i<t->nNodes-2; i++)
				{
				branch = t->allDownPass[i];
				lnPrior += LnProbTruncGamma (branch->length/igrvar, 1.0/igrvar, sst[branch->index], RELBRLENS_MIN, RELBRLENS_MAX);
                assert (fabs(sst[branch->index] - branch->length * st[branch->index]) < 0.000001);
                assert (fabs(branch->length - (branch->anc->nodeDepth - branch->nodeDepth)) < 0.000001);
				}
			}
		else if (p->paramType == P_CLOCKRATE)
			{
			/* base rate of molecular clock */
            lnPrior += p->LnPriorProb(st[0], p->priorParams);
			}
        else if (p->paramType == P_SPECIESTREE)
            {
            /* calculate prior */
            lnPrior += LnSpeciesTreeProb(chain);
            }
		}

#if defined (BEST_MPI_ENABLED)
    /* Assemble prior probabilities across processors */
    myLnPrior = lnPrior;
    MPI_AllReduce (&myLnPrior, &lnPrior, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
#endif

    return (lnPrior);

}


int LnBirthDeathPriorPr (Tree *t, MrBFlt clockRate, MrBFlt *prob, MrBFlt sR, MrBFlt eR, char *sS, MrBFlt sF)
{
	if (!strcmp(sS, "Random")) 
		{
			return LnBirthDeathPriorPrRandom (t, clockRate, prob, sR, eR, sF);
		}
	else if (!strcmp(sS, "Diversity")) 
    {
        return LnBirthDeathPriorPrDiversity (t, clockRate, prob, sR, eR, sF);
    }
	else if (!strcmp(sS, "Cluster")) 
    {
        return LnBirthDeathPriorPrCluster (t, clockRate, prob, sR, eR, sF);
    }
	else 
		{
		printf ("\n   ERROR: Sampling strategy for birth-death process not implemented.\n");
		return (ERROR);
		}

}


/*---------------------------------------------------------------------------------
|
|   LnBirthDeathPriorPrRandom
|
|   We assume a rooted tree that satisfies the molecular clock constraint. The
|   tree is labelled as follows:
|
|                                      t_4 (age of tips)
|     \         \         \        /            
|      \         \         \      /              
|       \         \         \    /         
|        \         \         \  /          
|         \         \         \/       t_3 
|          \         \        /            
|           \         \      /             
|            \         \    /              
|             \         \  /               
|              \         \/            t_2  
|               \        /                 
|                \      /                  
|                 \    /                        
|                  \  /                         
|                   \/                 t_1 (age of most recent common ancestor)
|    
|
|   This function calculates the probability of such a tree under the neutral
|   birth death prior with constant birth and death rates, conditioned on
|   a particular time of the first split, t_1, and a particular number of
|   species, n. We assume rho-sampling, that is, a constant sampling pro-
|   bability rho, which is known, across tips of the tree. Variables:
|
|   T:   the unlabeled oriented tree, which is equivalent to a set of unordered
|        speciation times from a point process
|   tau: the labeled unoriented tree
|   b:   birth (speciation) rate
|   d:   death (extintion) rate
|   f:   sampling fraction
|   n:   number of species in the sampled tree
|
|   See:
|   Tanja Stadler (2009) On incomplete sampling under birth-death models and
|   connections to the sampling-based coalescent. Journal of Theoretical Biology
|   261: 58-66.
|
|   We use f(T|n), which is derived from f(T|n,t_or) using Stadler's approach,
|   in which the time of origin of the tree is associated with a uniform prior
|   and integrated out of the density. We then have:
|
|   We have the following distribution for ordered bifurcation times (cf.
|   equation 5 in Stadler, 2009, simplified here using the p0 and p1 functions):
|
|
|              n! * p1(t_1)    n-1
|   f(T|n) = --------------- * prod (b * p1(t_i))
|             (1 - p0(t_1))    i=1
|
|
|   where   t_1   = time of most recent common ancestor
|           p0(t) = prob. of no descendants surviving and being sampled after time t (see LnP0 function below)
|           p1(t) = prob. of one descendant surviving and being sampled after time t (see LnP1 function below)
|
|   To get the distribution on oriented trees, this density needs to be divided by the
|   number of ways of ordering n-1 bifurcation times, (n-1)!, since each way of ordering
|   the bifurcation times corresponds to a distinct oriented tree. The result is the following
|   density on oritented trees:
|
|              n * p1(t_1)     n-1
|   f(T|n) = --------------- * prod (b * p1(t_i))
|             (1 - p0(t_1))    i=1
|
|
|   To translate this to a density on distinct labeled trees, the density needs to be multiplied by
|   (2^(n-1) / n!).
|
|   For the critical process where the speciation and extinction rates are equal, we obtain the
|   following result in the limit (cf. equation 6 in Stadler (2009)):
|
|                  n          n-1          f*b      
|   f(T|n) = -------------- * prod -----------------
|            (1 + f*b*t_1)    i=1   (1 + f*b*t_i)^2
|
---------------------------------------------------------------------------------*/

int LnBirthDeathPriorPrRandom (Tree *t, MrBFlt clockRate, MrBFlt *prob, MrBFlt sR, MrBFlt eR, MrBFlt sF)
{

	int				i, nTaxa;
	MrBFlt			*nt, lambda, mu, rho;
	TreeNode		*p;

	/* allocate space for the speciation times */
	nt = (MrBFlt *)SafeMalloc((size_t) (t->nIntNodes) * sizeof(MrBFlt));
	if (!nt)
		{
		printf ("\n   ERROR: Problem allocating nt\n");
		return (ERROR);
		}

    /* transform to standard variables */
    rho    = sF;
    lambda = sR / (1.0 - eR);
    mu     = eR * lambda;

    /* get the node times and put them into a vector */
	for (i=0; i<t->nIntNodes; i++)
		{
		p = t->intDownPass[i];
		nt[i] = p->nodeDepth / clockRate;
		}
    nTaxa = t->nIntNodes + 1;

	/* calculate probability of tree using standard variables */
	if (AreDoublesEqual(lambda,mu,ETA)==NO)
		{
		// birth rate != death rate, see equation (5) in Stadler (2009) and above
        (*prob) = log(nTaxa) + log(lambda - mu) - (lambda - mu) * nt[t->nIntNodes-1];
        (*prob) -= log(rho*lambda + (lambda*(1.0 - rho) - mu)*exp((mu - lambda)*nt[t->nIntNodes-1]));
		for (i=0; i<t->nIntNodes; i++)
			(*prob) += log(rho*lambda) + LnP1Subsample(nt[i], lambda, mu, rho);
        (*prob) += (nTaxa - 1.0) * log(2.0) - LnFactorial(nTaxa);    /* conversion to labeled tree from oriented tree */
		}
	else
		{
		// birth rate == death rate -> the critical branching process
        (*prob) = log(nTaxa/(1.0 + rho*lambda*nt[t->nIntNodes-1]));
        for (i=0; i<t->nIntNodes; i++)
            (*prob) += log(rho*lambda) - 2.0 * log(1.0 + rho*lambda*nt[i]);
        (*prob) += (nTaxa - 1.0) * log(2.0) - LnFactorial(nTaxa);    /* conversion to labeled tree from oriented tree */
		}

	/* free memory */
	free (nt);
	
	return (NO_ERROR);
}

/*---------------------------------------------------------------------------------
 |
 |   LnBirthDeathPriorPrRandom
 |
 |   We assume a rooted tree that satisfies the molecular clock constraint. The
 |   tree is labelled as follows:
 |
 |                                      t_4 (age of tips)
 |     \         \         \        /            
 |      \         \         \      /              
 |       \         \         \    /         
 |        \         \         \  /          
 |         \         \         \/       t_3 
 |          \         \        /            
 |           \         \      /             
 |            \         \    /              
 |             \         \  /               
 |              \         \/            t_2  
 |               \        /                 
 |                \      /                  
 |                 \    /                        
 |                  \  /                         
 |                   \/                 t_1 (age of most recent common ancestor)
 |    
 |
 |   This function calculates the probability of such a tree under the neutral
 |   birth death prior with constant birth and death rates, conditioned on
 |   a particular time of the first split, t_1, and a particular number of
 |   species, n. We assume diversity-sampling, that is, a constant sampling frac-
 |   tion rho, which is known, across tips of the tree. Variables:
 |
 |   T:   the unlabeled oriented tree, which is equivalent to a set of unordered
 |        speciation times from a point process
 |   tau: the labeled unoriented tree
 |   b:   birth (speciation) rate
 |   d:   death (extintion) rate
 |   f:   sampling fraction
 |   n:   number of species in the sampled tree
 |
 |
 ---------------------------------------------------------------------------------*/

int LnBirthDeathPriorPrDiversity (Tree *t, MrBFlt clockRate, MrBFlt *prob, MrBFlt sR, MrBFlt eR, MrBFlt sF)
{
    
	int				i, nTaxa, n, m;
	MrBFlt			*nt, lambda, mu, rho;
	TreeNode		*p;
    
	/* allocate space for the speciation times */
	nt = (MrBFlt *)SafeMalloc((size_t) (t->nIntNodes) * sizeof(MrBFlt));
	if (!nt)
    {
		printf ("\n   ERROR: Problem allocating nt\n");
		return (ERROR);
    }
    
    /* transform to standard variables */
    rho    = sF;
    lambda = sR / (1.0 - eR);
    mu     = eR * lambda;
    
    n      = t->nIntNodes+1;
    m      = (int)floor(n/sF+0.5);/*equal to round(n/sF) plus it is compartable with MS Visula Studio*/
    
    /* get the node times and put them into a vector */
	for (i=0; i<t->nIntNodes; i++)
    {
		p = t->intDownPass[i];
		nt[i] = p->nodeDepth / clockRate;
    }
    nTaxa = t->nIntNodes + 1;
    
	/* calculate probability of tree using standard variables */
	if (AreDoublesEqual(lambda,mu,ETA)==NO)
    {
		// birth rate != death rate
        MrBFlt p0_t1;
        p0_t1 = LnP0(nt[t->nIntNodes-1], lambda, mu);
        (*prob) = log(nTaxa); // we need to add here the binomial coefficient
        (*prob) += (m-n) * (LnP0(nt[0], lambda, mu) - p0_t1);
		for (i=0; i<t->nIntNodes-1; i++)
			(*prob) += (LnP1(nt[i], lambda, mu) - p0_t1);
        (*prob) += (nTaxa - 1.0) * log(2.0) - LnFactorial(nTaxa);    /* conversion to labeled tree from oriented tree */
    }
	else
    {
		printf ("\n   ERROR: Critical branchin process for diversity sampling not implemented\n");
		return (ERROR);
    }
    
	/* free memory */
	free (nt);
	
	return (NO_ERROR);
}


/*---------------------------------------------------------------------------------
 |
 |   LnBirthDeathPriorPrRandom
 |
 |   We assume a rooted tree that satisfies the molecular clock constraint. The
 |   tree is labelled as follows:
 |
 |                                      t_4 (age of tips)
 |     \         \         \        /            
 |      \         \         \      /              
 |       \         \         \    /         
 |        \         \         \  /          
 |         \         \         \/       t_3 
 |          \         \        /            
 |           \         \      /             
 |            \         \    /              
 |             \         \  /               
 |              \         \/            t_2  
 |               \        /                 
 |                \      /                  
 |                 \    /                        
 |                  \  /                         
 |                   \/                 t_1 (age of most recent common ancestor)
 |    
 |
 |   This function calculates the probability of such a tree under the neutral
 |   birth death prior with constant birth and death rates, conditioned on
 |   a particular time of the first split, t_1, and a particular number of
 |   species, n. We assume cluster-sampling, that is, a constant sampling frac-
 |   tion rho, which is known, across tips of the tree. Variables:
 |
 |   T:   the unlabeled oriented tree, which is equivalent to a set of unordered
 |        speciation times from a point process
 |   tau: the labeled unoriented tree
 |   b:   birth (speciation) rate
 |   d:   death (extintion) rate
 |   f:   sampling fraction
 |   n:   number of species in the sampled tree
 |
 |
 ---------------------------------------------------------------------------------*/

int LnBirthDeathPriorPrCluster (Tree *t, MrBFlt clockRate, MrBFlt *prob, MrBFlt sR, MrBFlt eR, MrBFlt sF)
{
    
	int				i, nTaxa, n, m;
	MrBFlt			*nt, lambda, mu, rho;
	TreeNode		*p;
    
	/* allocate space for the speciation times */
	nt = (MrBFlt *)SafeMalloc((size_t) (t->nIntNodes) * sizeof(MrBFlt));
	if (!nt)
    {
		printf ("\n   ERROR: Problem allocating nt\n");
		return (ERROR);
    }
    
    /* transform to standard variables */
    rho    = sF;
    lambda = sR / (1.0 - eR);
    mu     = eR * lambda;
    
    n      = t->nIntNodes+1;
    m      = (int)floor(n/sF+0.5);/*equal to round(n/sF) plus it is compartable with MS Visula Studio*/
    
    /* get the node times and put them into a vector */
	for (i=0; i<t->nIntNodes; i++)
    {
		p = t->intDownPass[i];
		nt[i] = p->nodeDepth / clockRate;
    }
    nTaxa = t->nIntNodes + 1;
    
	/* calculate probability of tree using standard variables */
	if (AreDoublesEqual(lambda,mu,ETA)==NO)
    {
		// birth rate != death rate
        MrBFlt p0_t1;
        p0_t1 = LnP0(nt[t->nIntNodes-1], lambda, mu);
        (*prob) = log(nTaxa); // we need to add here the binomial coefficient
        (*prob) += (m-n) * (LnP0(nt[t->nIntNodes-2], lambda, mu) - p0_t1);
		for (i=0; i<t->nIntNodes-1; i++)
			(*prob) += (LnP1(nt[i], lambda, mu) - p0_t1);
        (*prob) += (nTaxa - 1.0) * log(2.0) - LnFactorial(nTaxa);    /* conversion to labeled tree from oriented tree */
    }
	else
    {
		printf ("\n   ERROR: Critical branchin process for cluster sampling not implemented\n");
		return (ERROR);
    }
    
	/* free memory */
	free (nt);
	
	return (NO_ERROR);
}





/*---------------------------------------------------------------------------------
|
|   LnCoalescencePriorPr
|
|   This function calculates the probability of a tree under the neutral
|   coalescence prior with a (potentially) exponentially growing population.
|   We assume a rooted tree that satisfies the molecular clock constraint. The
|   Tree is labelled as follows:
|
|                                      t_4 ___  
|     \         \         \        /            \
|      \         \         \      /             | 
|   I_4 \         \         \    /              | g_4
|        \         \         \  /               |
|         \         \         \/       t_3 ___  /
|          \         \        /                 \
|           \         \      /                  |
|   I_3      \         \    /                   | g_3
|             \         \  /                    |
|              \         \/            t_2 ___  / 
|               \        /                      \
|                \      /                       |
|   I_2           \    /                        | g_2
|                  \  /                         |
|                   \/                 t_1 ___  /
|    
|   Each interval on the tree is specified by successive coalescence events.
|   These intervals are denoted I_2, I_3, I_4, ..., with the subscript denoting
|   how many lineages exist in that interval. The time of each coalescence event
|   is designated t_1, t_2, t_3, ..., where the subscript denotes the number
|   of lineages that exist after the coalescence (t_3, for instance, would be
|   the time of the coalescence that went from four lineages to three lineages).
|   The duration of the i-th interval is designated g_i.
|
|   The probability of the coalescence tree is:
|   
|   prob = (k_C_2 / (N(t_k + t_k))) * exp(-integral_(from x=t_k, to g_k + t_k)  (k_C_2 / N(x)) dx)
|
|   where N(x) = N(0) * exp(-r*x). For the constant population size case,
|   N(0) = N_e. r is the population growth parameter for the exponentially
|   growing population. Here, theta = N(0) * mu when organisms are haploid and
|   theta = 2 * N(0) * mu when the organism is diploid.
|
|   Below, ct holds the n - 1 coalescence times (t_i, above) sorted from the
|   smallest to the largest. Remember that t_4 < t_3 < t_2, etc. 
|
|   2010-03-23
|   The original function (described above) was incorrect in that it used theta = 2 * N * mu
|   in one part of the equation and theta = 4 * N * mu in another. It is now corrected to
|   consistently use theta = 4 * N * mu, which is the standard for diploid populations
|   and theta = 2 * N * mu for haploid populations. The calculations are the same for the
|   diploid and haploid cases, only the interpretation is different. See, e.g., Felsenstein
|   (2004; Inferring Phylogenies). -- Fredrik.
|
---------------------------------------------------------------------------------*/
int LnCoalescencePriorPr (Tree *t, MrBFlt clockRate, MrBFlt *prob, MrBFlt theta, MrBFlt growth)

{

	int				i, j, k, nNodes;
	MrBFlt			*ct, tempD, lastCoalescenceTime, coalescenceTime, intervalLength;
	TreeNode		*p;

	/* allocate space for the coalescence times */
	ct = (MrBFlt *)SafeMalloc((size_t) (t->nIntNodes) * sizeof(MrBFlt));
	if (!ct)
		{
		printf ("\n   ERROR: Problem allocating ct\n");
		return (ERROR);
		}

	/* get the coalescence times and put them into a vector */
	for (i=j=0; i<t->nIntNodes; i++)
		{
		p = t->intDownPass[i];
		if (p->anc != NULL)
			ct[j++] = p->nodeDepth / clockRate;
		}
	nNodes = j;

	/* sort the coalescence times */
	SortMrBFlt (ct, 0, nNodes-1);
	
	/*for (i=0, k=numLocalTaxa; i<nNodes; i++)
		{
		printf ("%4d -- %2d %lf\n", i, k, ct[i]);
		k--;
		}*/
		
	/* calculate probability of the tree */
	if (AreDoublesEqual (growth, 0.0, 0.000001) == YES)
		{
		/* use this if there is no population growth */
		tempD = lastCoalescenceTime = 0.0;
		for (i=0, k=numLocalTaxa; i<nNodes; i++)
			{
			coalescenceTime = ct[i];
			intervalLength = coalescenceTime - lastCoalescenceTime;
			lastCoalescenceTime = ct[i];
			tempD += - (k * (k-1) * intervalLength) / (theta);
			k--;
			}
		(*prob) = (numLocalTaxa - 1) * log(2.0 / theta) + tempD;
		}
	else
		{
		/* use this if the population is growing exponentially */
		tempD = lastCoalescenceTime = 0.0;
		for (i=0, k=numLocalTaxa; i<nNodes; i++)
			{
			coalescenceTime = ct[i];
			intervalLength = coalescenceTime - lastCoalescenceTime;
			tempD += growth * coalescenceTime + (((k * (k-1)) / (theta * growth)) * (exp(growth * lastCoalescenceTime) - exp(growth * coalescenceTime)));
			lastCoalescenceTime = ct[i];
			k--;
			}
		(*prob) = (numLocalTaxa - 1) * log(2.0 / theta) + tempD;
		}

	/*printf ("coal pr = %lf theta = %lf, nNodes = %d, nt = %d tempD = %lf\n", *prob, theta, nNodes, numLocalTaxa, tempD);*/

	/* free memory */
	free (ct);
	
	return (NO_ERROR);

}





/*---------------------------------------------------------------------------------
|
|   LnUniformPriorPr
|
|   This function calculates the probability of a calibrated clock tree under the
|   uniform prior probability distribution on node depths. The tree is labeled as
|   follows:
|                                                interval between tip dates 
|    t_0                          t_1      time  ____  0 (interval between t_0 and t_1, duration 0) 
|     \                            /            |  
|      \                  t_2     /             |___   1 (interval between t_1 and t_2)
|       \                   \    /              | 
|        \                   \  /               |
|         \                   \/        0.33 ___|      2 (interval between t_2 and t_3)
|          \        t_3       /                 |___ 
|           \         \      /                  |
|            \         \    /                   | 
|             \         \  /                    |
|              \   t_4   \/             0.67 ___| 
|               \     \  /                      |      3 (interval between t_3 and root)
|                \     \/                       |
|                 \    /                        |      Note that t_4 is irrelevant for intervals
|                  \  /                         |      because we need not have a single coalescent
|                   \/                  1.00 ___|___   event beneath t_4 except for the root.
|    
|   The probability depends on the number of nodes falling in each interval between
|   tip dates, the time interval on which each node depth can vary (if it is interior
|   node number i, it can vary on the interval (t_{i+1},1)). Finally, the probability
|   is multiplied by the number of coalescent histories compatible with the node order.
|
---------------------------------------------------------------------------------*/
MrBFlt LnUniformPriorPr (Tree *t, MrBFlt clockRate)

{
    int         i, j, k, *nLineages=NULL, nDatedTips, nLineagesIn, nLineagesOut, nTips;
    MrBFlt      lnProb, treeAge, *nodeDepths=NULL;
    TreeNode    *p, *root;
    Model       *mp;

    lnProb      = 0.0;
    mp          = &modelParams[t->relParts[0]];
    treeAge     = t->root->left->nodeDepth / clockRate;
    assert (t->root->left->isDated == NO || AreDoublesEqual(treeAge, t->root->left->age, 0.000001) == YES);

    /* Calculate number of tips for convenience */
    nTips   = t->nNodes - t->nIntNodes - 1;

    /* First take tree age into account f(t_0) */
    if (t->root->left->isDated == YES)
        {
        lnProb += 0.0;  /* calibrations are dealt with separately */
        }
    else
        {
        if (!strcmp(mp->treeAgePr, "Exponential"))
		    lnProb += log(mp->treeAgeExp) - mp->treeAgeExp * treeAge;
	    else if (!strcmp(mp->treeAgePr, "Gamma"))
		    lnProb += mp->treeAgeGamma[0] * log(mp->treeAgeGamma[1]) - LnGamma(mp->treeAgeGamma[0]) + (mp->treeAgeGamma[0] - 1.0) * log(treeAge) - mp->treeAgeGamma[1] * treeAge;
        }

    /* If tree is not calibrated or only root is calibrated, it is easy */
    for (i=j=0; i<t->nNodes-2; i++)
        {
        if (t->allDownPass[i]->isDated == YES)
            j++;
        }
    if (j == 0)
        {
        /* Calculate simple probability f(tau|t_0) */
        lnProb += (nTips - 1.0)*log(2.0) - LnFactorial(nTips) - log(nTips-1.0) - (nTips - 2.0)*log(treeAge);
        assert (lnProb > NEG_INFINITY);
        return lnProb;
        }

    /* We have a tree with interior or tip calibrations */

    /* Color subtrees by assigning an index 1,...,k to the x variable of each node,
       where k is the total number of separate subtrees. A subtree is characterized
       by having all interior nodes being unconstrained and all tips being either
       terminals or constrained interior nodes. The root of a subtree may be the
       root of the tree, or an interior node that is constrained and dated, or an
       interior node that is constrained but not dated. */
    i = 0;
    ColorClusters (t->root->left, &i);

    /* Get the probability for each subtree */
    for (i=0; i<t->nIntNodes; i++)
        {
        p = t->intDownPass[i];
        
        /* Skip unless this is the root of a subtree */
        if (p->anc->anc != NULL && p->isDated != YES)
            continue;

        /* Save the root of the subtree */
        root = p;

        /* Create an array containing the sorted times */

        /* Allocate space for node depths */
        nDatedTips = NumDatedTips (root);
        nodeDepths = (MrBFlt *) SafeRealloc ((void *)nodeDepths, (nDatedTips+1)*sizeof(MrBFlt));

        /* Get the dated node depths and sort them. The call to GetDatedNodeDepths also
           returns the root node depth into nodeDepths, which is convenient. For now, this
           only works for dated tips, not for constrained but undated interior nodes. */
        GetDatedNodeDepths (root, nodeDepths);
        SortMrBFlt (nodeDepths, 0, nDatedTips);   /* use index of left and right in call */

        /* Get probability due to the uniform node depths; we do not use first and last tip depth
           for obvious reasons (see figure above) */
        for (j=1; j<nDatedTips-1; j++)
            lnProb -= log ((root->nodeDepth - nodeDepths[j]) / clockRate);

        /* Get probability due to sorting of interior node depths */
        
        /* First get the potential number of lineages leaving each interval j at time nodeDepths[j+1] */
        nLineages = (int *) SafeRealloc ((void *)nLineages, nDatedTips*sizeof(int));
        for (j=0; j<nDatedTips; j++)
            nLineages[j] = j+1;
        
        /* Subtract interior nodes so that we get the real number of lineages leaving each interval.
           The number of lineages entering each interval is always 1 + the number of lineages
           leaving the previous interval. We utilize the fact here that the last node depth is the
           root node depth and is held in nodeDepths[nDatedTips] */
        for (j=0; j<t->nIntNodes; j++)
            {
            p = t->intDownPass[j];
            if (p->x != root->x || p == root || p->isDated == YES)
                continue;
            for (k=0; k<nDatedTips; k++)
                if (p->nodeDepth < nodeDepths[k+1])
                        nLineages[k]--;
            }
        
        /* Now get the density effect of the sorting constraints */
        for (j=1; j<nDatedTips-1; j++)
            {
            nLineagesIn = nLineages[j-1] + 1;
            if (j==nDatedTips-2)
                nLineagesOut = 2;    /* skip the last segment and jump directly to root */
            else
                nLineagesOut = nLineages[j];
            /* only calculate if ln different from 0 */
            if (nLineagesIn > 1 && nLineagesIn - nLineagesOut >= 1)
                {
                lnProb += LnFactorial (nLineagesIn-1) - LnFactorial(nLineagesOut-1);
                }
            }

        /* Finally get the effect of the number of possible coalescent histories */
        for (j=1; j<nDatedTips; j++)
            {
            nLineagesIn = nLineages[j-1] + 1;
            nLineagesOut = nLineages[j];
            if (nLineagesIn != nLineagesOut)
                {
                lnProb += log(2.0) * (nLineagesIn - nLineagesOut);
                lnProb += LnFactorial (nLineagesOut) + LnFactorial (nLineagesOut-1);
                lnProb -= LnFactorial (nLineagesIn)  + LnFactorial (nLineagesIn-1);
                }
            }

        /* Last but not least, change color of root so that it can be a tip in the next
           subtree (if we wanted to use the colors). */
        root->x = root->anc->x;

        }

    free (nodeDepths);
    free (nLineages);

    assert (lnProb > NEG_INFINITY);

    return lnProb;
}


/*
 |
 | The probability of having zero lineages remaining after time t in the
 | birth-death process.
 |
 | param: t - speciation time
 | param: b - birth rate
 | param: d - death rate
 | return: log probability of zero remaining lineages
 |
 */
MrBFlt LnP0 (MrBFlt t, MrBFlt b, MrBFlt d)

{
    
	MrBFlt		p0t;
	
	p0t = d*(1.0-exp((d-b)*t)) / (b -d*exp((d-b)*t));
	
	return (log(p0t));
    
}


/*
|
| The probability of having zero lineages remaining after time t in the
| birth-death process.
|
| param: t - speciation time
| param: b - birth rate
| param: d - death rate
| param: f - sample frequency
| return: log probability of zero remaining lineages
|
*/
MrBFlt LnP0Subsample (MrBFlt t, MrBFlt b, MrBFlt d, MrBFlt f)

{

	MrBFlt		p0t;
	
	p0t = (f*d + (b*(1.0-f) - d)*exp((d-b)*t)) / (f*b + (b*(1.0-f)-d)*exp((d-b)*t));
	
	return (log(p0t));

}


/*
 |
 | The probability of having one lineage remaining after time t
 | in the birth-death process.
 |
 | param: t - speciation time
 | param: b - birth rate
 | param: d - death rate
 | return: log probability of one remaining lineage
 |
 */
MrBFlt LnP1 (MrBFlt t, MrBFlt b, MrBFlt d)

{
    
	MrBFlt		p0t;
    
    p0t = 2.0 * log(b-d) - (b-d)*t;
	
	p0t -= 2.0 * log(b - d*exp((d-b)*t));
	
	return p0t;
    
}


/*
|
| The probability of having one lineage remaining after time t
| in the birth-death process.
|
| param: t - speciation time
| param: b - birth rate
| param: d - death rate
| param: f - sample frequency
| return: log probability of one remaining lineage
|
*/
MrBFlt LnP1Subsample (MrBFlt t, MrBFlt b, MrBFlt d, MrBFlt f)

{

	MrBFlt		p0t;
	
	p0t = (b-d) / (f*b + (b*(1.0-f)-d)*exp((d-b)*t));
	
	return (2.0*log(p0t) + (d-b)*t);

}





/*----------------------------------------------------------------
|
|	MarkClsBelow: We mark all of the nodes below p as in need of
|      updating for the conditional likelihoods. Note that we do
|      do not mark p itself or the very root node of the tree.
|
----------------------------------------------------------------*/
void MarkClsBelow (TreeNode *p)

{

	TreeNode *q;

	q = p;
	while (q->anc != NULL)
		{
		if (q != p) 
 		    q->upDateCl = YES; 
		q = q->anc;
		}

}





MrBFlt MaximumValue (MrBFlt x, MrBFlt y)

{

	if (x > y)
		return (x);
	else
		return (y);
		
}





MrBFlt MinimumValue (MrBFlt x, MrBFlt y)

{

	if (x < y)
		return (x);
	else
		return (y);
		
}





int Move_Aamodel (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* Change amino acid model for model mixing 
	   amino acid model ID's
		AAMODEL_POISSON			0
		AAMODEL_JONES			1
		AAMODEL_DAY				2
		AAMODEL_MTREV			3
		AAMODEL_MTMAM			4
		AAMODEL_WAG				5
		AAMODEL_RTREV			6 
		AAMODEL_CPREV           7 
		AAMODEL_VT				8
		AAMODEL_BLOSUM			9 */

	int			i, oldM, newM;
	MrBFlt		*bs, x, *subValue;
	ModelParams *mp;
	
	/* no warnings */
	x = mvp[0];
	
	/* get model params */
	mp = &modelParams[param->relParts[0]];

	subValue = GetParamSubVals(param, chain, state[chain]);

	/* get old value of model */
	newM = oldM = (int)*GetParamVals(param, chain, state[chain]);
	
	/* get a new model ID */
	do
		{
		newM = (int)(RandomNumber(seed) * 10);
		} while (newM == oldM);

	/* set proposal ratio */
	*lnProposalRatio = 0.0;
	
	/* set prior ratio */
	*lnPriorRatio = subValue[newM] - subValue[oldM];
	
	/* copy new amino acid model ID back */
	*GetParamVals(param, chain, state[chain]) = (MrBFlt)newM;
	
	/* set amino acid frequencies */
	bs = GetParamSubVals (modelSettings[param->relParts[0]].stateFreq, chain, state[chain]);
	if (newM == AAMODEL_POISSON)
		{
		for (i=0; i<mp->nStates; i++)
			bs[i] = 1.0 / 20.0;
		}
	else if (newM == AAMODEL_JONES)
		{
		for (i=0; i<mp->nStates; i++)
			bs[i] = jonesPi[i];
		}
	else if (newM == AAMODEL_DAY)
		{
		for (i=0; i<mp->nStates; i++)
			bs[i] = dayhoffPi[i];
		}
	else if (newM == AAMODEL_MTREV)
		{
		for (i=0; i<mp->nStates; i++)
			bs[i] = mtrev24Pi[i];
		}
	else if (newM == AAMODEL_MTMAM)
		{
		for (i=0; i<mp->nStates; i++)
			bs[i] = mtmamPi[i];
		}
	else if (newM == AAMODEL_WAG)
		{
		for (i=0; i<mp->nStates; i++)
			bs[i] = wagPi[i];
		}
	else if (newM == AAMODEL_RTREV)
		{
		for (i=0; i<mp->nStates; i++)
			bs[i] = rtrevPi[i];
		}
	else if (newM == AAMODEL_CPREV)
		{
		for (i=0; i<mp->nStates; i++)
			bs[i] = cprevPi[i];
		}
	else if (newM == AAMODEL_VT)
		{
		for (i=0; i<mp->nStates; i++)
			bs[i] = vtPi[i];
		}
	else if (newM == AAMODEL_BLOSUM)
		{
		for (i=0; i<mp->nStates; i++)
			bs[i] = blosPi[i];
		}

	/* Set update flags for all partitions that share this amino acid model. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);

	/* Set update flags for cijks for all affected partitions. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);
	
}





int Move_AddDeleteCPPEvent (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* add or delete one Poisson process event */
	
	int			i, k, addEvent, *nEvents, numEvents;
	MrBFlt		sigma, m, lognormalLnProb, **position, **rateMultiplier, *brlens, length, pos, rate;
	TreeNode	*p, *q;
	ModelParams *mp;
	ModelInfo	*model;
	Tree		*t;

	/* get the model parameters */
	mp = &modelParams[param->relParts[0]];
	model = &modelSettings[param->relParts[0]];

	/* get cpp rate */
	rate = *GetParamVals (model->cppRate, chain, state[chain]);
	
	/* get sigma of lognormal of rate multipliers */
	sigma = *GetParamVals (model->cppMultDev, chain, state[chain]);

	/* get the cpp event data */
	nEvents = param->nEvents[2*chain+state[chain]];
	position = param->position[2*chain+state[chain]];
	rateMultiplier = param->rateMult[2*chain+state[chain]];
	brlens = GetParamSubVals(param, chain, state[chain]);

	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* pick a branch */
	do
		{
		p = t->allDownPass[(int)(RandomNumber(seed)*(t->nNodes - 2))];
		} while (p->anc == NULL || (p->anc->anc == NULL));

	/* get number of events for convenience */
	numEvents = nEvents[p->index];

	/* add or delete ? */
	addEvent = NO;
	if (numEvents == 0)
		addEvent = YES;
	else if (RandomNumber (seed) < 0.5)
		addEvent = YES;
	
	if (addEvent == NO)
		{
		/* delete event */

		/* choose random event */
		k = (int) (RandomNumber (seed) * numEvents);
		
		/* save multiplier to be deleted */
        m = rateMultiplier[p->index][k];

        /* rearrange and reduce */
		for (i=k; i<numEvents-1; i++)
			{
			position[p->index][i] = position[p->index][i+1];
			rateMultiplier[p->index][i] = rateMultiplier[p->index][i+1];
			}
		if (numEvents-1 > 0)
			{
			position[p->index] = (MrBFlt *) SafeRealloc ((void *) position[p->index], (numEvents-1)*sizeof(MrBFlt));
			rateMultiplier[p->index] = (MrBFlt *) SafeRealloc ((void *) rateMultiplier[p->index], (numEvents-1)*sizeof(MrBFlt));
			assert (position[p->index] != NULL && rateMultiplier[p->index] != NULL);
            }
		else
			{
			free (position[p->index]);
			free (rateMultiplier[p->index]);
			position[p->index] = rateMultiplier[p->index] = NULL;
			}
		/* update number of events */
		nEvents[p->index]--;
		}
	else /* if (addEvent == YES) */
		{
		/* add event */

		/* generate new multiplier */
		m = LogNormalRandomVariable (0.0, sigma, seed);

		/* generate new position */
		pos = RandomNumber (seed);

		/* find place in current array */
		for (k=0; k<numEvents; k++)
			{
			if (position[p->index][k] > pos)
				break;
			}

		/* rearrange and insert */
		position[p->index] = (MrBFlt *) SafeRealloc ((void *)position[p->index], (numEvents+1)*sizeof(MrBFlt));
		rateMultiplier[p->index] = (MrBFlt *) SafeRealloc ((void *)rateMultiplier[p->index], (numEvents+1)*sizeof(MrBFlt));
		assert (position[p->index] != NULL && rateMultiplier[p->index] != NULL);
        for (i=numEvents; i>k; i--)
			{
			position[p->index][i] = position[p->index][i-1];
			rateMultiplier[p->index][i] = rateMultiplier[p->index][i-1];
			}
		position[p->index][k] = pos;
		rateMultiplier[p->index][k] = m;

		/* update number of events */
		nEvents[p->index]++;
		}
	
	/* the CPP process is relative to expected substitutions */
    length = p->length;
	
	lognormalLnProb = LnProbLogNormal(0.0, sigma, m);
    if (addEvent == YES)
		(*lnPriorRatio) = lognormalLnProb + log (rate); 
	else
		(*lnPriorRatio) = -(lognormalLnProb + log(rate));

	if (addEvent == YES)
        /* note that nEvents[p->index] now contains k+1 after addition */
		(*lnProposalRatio) = log (length / ((double) nEvents[p->index])) - lognormalLnProb;
	else
		/* note that nEvents[p->index] contains k after deletion */
        (*lnProposalRatio) = log ((double)(nEvents[p->index]+1) / length) + lognormalLnProb;

	/* take care of asymmetric add and delete probabilities around 0 and 1 events */
    if (addEvent == YES && nEvents[p->index] == 1)
		(*lnProposalRatio) += log (0.5);
	else if (addEvent == NO && nEvents[p->index] == 0)
		(*lnProposalRatio) += log (2.0);

	/* update evolLengths in subtree above new event */
	if (UpdateCppEvolLengths (param, p, chain)==ERROR)
        {
        abortMove=YES;
        return (NO_ERROR);
        }
	
	/* set update of cond likes down to root */
	/* crown tree update flags set in UpdateCppEvolLengths */
	q = p->anc;
	while (q->anc != NULL)
		{
		q->upDateCl = YES;
		q = q->anc;
		}

	return (NO_ERROR);
	
}




int Move_Adgamma (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)
{

	/* Change correlation parameter (-1, 1) of adgamma model */

	int			i, isValidP;
	MrBFlt		oldP, newP, window, minP, maxP, ran, *markovTiValues;
	ModelParams *mp;

	/* get size of window, centered on current rho */
	window = mvp[0];

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* get minimum and maximum values for rho */
	minP = mp->corrUni[0];
	maxP = mp->corrUni[1];

	/* get address of markovTi */
	markovTiValues = GetParamSubVals (param, chain, state[chain]);

	/* get old value of rho */
	newP = oldP = *GetParamVals(param, chain, state[chain]);

	/* change value for rho */
	ran = RandomNumber(seed);
	 if( maxP-minP < window )
		{
		window = maxP-minP;
		}
	newP = oldP + window * (ran - 0.5);
	
	/* check that new value is valid */
	isValidP = NO;
	do
		{
		if (newP < minP)
			newP = 2* minP - newP;
		else if (newP > maxP)
			newP = 2 * maxP - newP;
		else
			isValidP = YES;
		} while (isValidP == NO);

	/* get proposal ratio */
	*lnProposalRatio = 0.0;
	
	/* get prior ratio */
	*lnPriorRatio = 0.0;
	
	/* copy new rho value back */
	*GetParamVals(param, chain, state[chain]) = newP;

	/* fill in new Markov trans probs */
	AutodGamma (markovTiValues, newP, mp->numGammaCats);
		
	/* Set update flags for all partitions that share this rho. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);

	/* Update flags for divisions already set */

	return (NO_ERROR);
}





int Move_Beta (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* change symmetric Dirichlet variance using multiplier */

	int			i, j, k, isValidB, isPriorExp, nStates;
	MrBFlt		oldB, newB, minB, maxB, priorExp=0.0, *bs, ran, factor, tuning,
				x, y;
	ModelParams *mp;

	/* get tuning parameter */
	tuning = mvp[0];	/* multiplier tuning parameter lambda */

	/* get model paramaters */
	mp = &modelParams[param->relParts[0]];

	/* get prior, minimum and maximum values for rate     */
	if (!strcmp(mp->symPiPr,"Uniform"))
		{
		isPriorExp = NO;
		minB = mp->symBetaUni[0];
		maxB = mp->symBetaUni[1];
		}
	else
		{
		isPriorExp = YES;
		priorExp = mp->symBetaExp;
		minB = SYMPI_MIN;
		maxB = SYMPI_MAX;
		}

	/* get old value of symDir */
	oldB = *GetParamVals(param, chain, state[chain]);

	/* change value */
	ran = RandomNumber(seed);
	factor = exp(tuning * (ran - 0.5));
	newB = oldB * factor;

	/* check validity */
	isValidB = NO;
	do
		{
		if (newB < minB)
			newB = minB * minB / newB;
		else if (newB > maxB)
			newB = maxB * maxB / newB;
		else
			isValidB = YES;
		} while (isValidB == NO);

	/* set new value of symDir */
	*GetParamVals(param, chain, state[chain]) = newB;

	/* get proposal ratio */
	*lnProposalRatio = log (newB / oldB);

	/* get prior ratio */
	if (isPriorExp == YES)
		{
		*lnPriorRatio = priorExp * (oldB - newB);
		}
	else
		*lnPriorRatio = 0.0;

    /* fill in the new betacat frequencies */
	bs = GetParamStdStateFreqs(param, chain, state[chain]);
	k = mp->numBetaCats;
	BetaBreaks (newB, newB, bs, k);
	k *= 2;
	for (i=k-2; i>0; i-=2)
		{
		bs[i] = bs[i/2];
		}
	for (i=1; i<k; i+=2)
		{
		bs[i] = 1.0 - bs[i-1];
		}
		
	/* if there are multistate characters, update prior probability of current pis */
	bs += 2 * mp->numBetaCats;
	for (i=0; i<param->nSympi; i++)
		{
		/* get number of states */
		nStates = param->sympinStates[i];

		/* get prior ratio update */
		x = LnGamma(newB*nStates) - nStates*LnGamma(newB);
		y = LnGamma(oldB*nStates) - nStates*LnGamma(oldB);
		for (j=0; j<nStates; j++)
			{
			x += (newB-1.0)*log(bs[j]);
			y += (oldB-1.0)*log(bs[j]);
			}
		(*lnPriorRatio) += x - y;

		/* update pointer to state freqs */
		bs += nStates;
		}
		
	/* Set update flags for all tree nodes. Note that the conditional
	   likelihood update flags have been set for the relevant partitions
	   before we even call the move function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
		
	/* may need to hit update flag for cijks if we have multistate characters */
	for (i=0; i<param->nRelParts; i++)
		{
		if (modelSettings[param->relParts[i]].nCijkParts > 0)
			modelSettings[param->relParts[i]].upDateCijk = YES;
		}

	return (NO_ERROR);

}





int Move_TK02BranchRate (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* move one TK02 relaxed clock branch rate using multiplier */

	int			i;
	MrBFlt		newRate, oldRate, tuning, minR, maxR, nu, *tk02Rate, *brlens;
	TreeNode	*p = NULL;
	ModelParams *mp;
	ModelInfo	*m;
	Tree		*t;
	TreeNode	*q;

	/* get the tuning parameter */
	tuning = mvp[0];
	
	/* get the model parameters */
	mp = &modelParams[param->relParts[0]];
	m = &modelSettings[param->relParts[0]];

    /* get the TK02 branch rate and effective branch length data */
	tk02Rate = GetParamVals (param, chain, state[chain]);
	brlens   = GetParamSubVals (param, chain, state[chain]);

	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* get minimum and maximum rate */
	minR = RATE_MIN;
	maxR = RATE_MAX;
	
	/* randomly pick a rate */
	i = (int) (RandomNumber(seed) * (t->nNodes - 2));
	p = t->allDownPass[i];

	/* find new rateMultiplier */
	oldRate = tk02Rate[p->index];
	newRate = oldRate * (exp ((0.5 - RandomNumber (seed)) * tuning));

	/* reflect if necessary */
	while (newRate < minR || newRate > maxR)
		{
		if (newRate < minR)
			newRate = minR * minR / newRate;
		if (newRate > maxR)
			newRate = maxR * maxR / newRate;
		}

	tk02Rate[p->index] = newRate;
	
	/* calculate prior ratio */
	nu = *GetParamVals (m->tk02var, chain, state[chain]);
	(*lnPriorRatio) += LnRatioTK02LogNormal (tk02Rate[p->anc->index], nu*p->length, newRate, oldRate);
	if (p->left != NULL)
		{
		(*lnPriorRatio) -= LnProbTK02LogNormal (oldRate, nu*p->left->length,  tk02Rate[p->left->index ]);
		(*lnPriorRatio) += LnProbTK02LogNormal (newRate, nu*p->left->length,  tk02Rate[p->left->index ]);
		(*lnPriorRatio) -= LnProbTK02LogNormal (oldRate, nu*p->right->length, tk02Rate[p->right->index]);
		(*lnPriorRatio) += LnProbTK02LogNormal (newRate, nu*p->right->length, tk02Rate[p->right->index]);
		}

	/* calculate proposal ratio */
	(*lnProposalRatio) = log (newRate / oldRate);

	/* update branch evolution lengths */
	brlens[p->index] = p->length * (newRate + tk02Rate[p->anc->index]) / 2.0;
    if (p->left != NULL)
        {
        brlens[p->left->index ] = p->left->length  * (tk02Rate[p->left->index ] + newRate) / 2.0;
        brlens[p->right->index] = p->right->length * (tk02Rate[p->right->index] + newRate) / 2.0;
        }

	/* set update of ti probs */
    p->upDateTi = YES;
    if (p->left != NULL)
        {
        p->left ->upDateTi = YES;
        p->right->upDateTi = YES;
        }
    
    /* set update of cond likes down to root */
	/* update of crowntree set in UpdateCppEvolLengths */
    p->upDateCl = YES;
    q = p->anc;
	while (q->anc != NULL)
		{
		q->upDateCl = YES;
		q = q->anc;
		}

	return (NO_ERROR);
	
}





int Move_BrLen (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* change one branch length */

	MrBFlt		tuning, maxV, minV, m, newM, brlensPrExp=0.0;
	TreeNode	*p;
	ModelParams *mp;
	Tree		*t;

	tuning = mvp[0]; /* Larget & Simon's tuning parameter lambda */

	mp = &modelParams[param->relParts[0]];

    /* max and min brlen */
	if (param->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0];
		maxV = mp->brlensUni[1];
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensPrExp = mp->brlensExp;
		}

	/* get tree */
	t = GetTree (param, chain, state[chain]);

#if defined (DEBUG_CONSTRAINTS)
    if (CheckConstraints(t) == ERROR) {
        printf ("Constraint error in input tree to brlen multiplier\n");
        getchar();
        }
#endif

	/* pick a branch */
	do
		{
		p = t->allDownPass[(int)(RandomNumber(seed)*t->nNodes)];
		} while (p->anc == NULL || (t->isRooted == YES && p->anc->anc == NULL));

	/* determine new length */
	m = p->length;
	newM = m * exp(tuning * (RandomNumber(seed) - 0.5));

	/* reflect new length if necessary */
	while (newM < minV || newM > maxV)
		{
		if (newM < minV)
			newM = minV * minV / newM;
		else if (newM > maxV)
			newM = maxV * maxV / newM;
		}
	p->length = newM;

	/* calculate proposal ratio */
	/* must be based on new length after reflection */
	(*lnProposalRatio) = log(newM / m);

	/* set flags for update of transition probabilities at p */
	p->upDateTi = YES;

	/* set the update flag for cond likes if p is connected to root in unrooted */
	/* tree, if this is not done, cond likes are not updated in this case       */
  	if (t->isRooted == NO && p->anc->anc == NULL)  
  		p->upDateCl = YES;  

	/* set flags for update of cond likes from p->anc and down to root */
	while (p->anc->anc != NULL)
		{
		p = p->anc;
		p->upDateCl = YES; 
		}

	/* update prior if exponential prior on branch lengths */
	if (param->paramId == BRLENS_EXP)
		(*lnPriorRatio) = brlensPrExp * (m - newM);

	return (NO_ERROR);
	
}





int Move_ClockRateM (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)
{

	/* change clock rate using multiplier */
	
	int			i, j, k, *nEvents;
	MrBFlt		minV, maxV, minB, maxB, oldR, newR, factor, lambda, nu, igrvar, *brlens, *igrRate, *tk02Rate;
	Tree		*t, *oldT;
    TreeNode    *p, *q;
    Param       *treeParam, *subParm;

    assert (IsTreeConsistent(modelSettings[param->relParts[0]].brlens, chain, state[chain]) == YES);

	/* get old value of clock rate */
	oldR = *GetParamVals(param, chain, state[chain]);

    /* Rely on general algorithm to change the value */
    Move_PosRealMultiplier(param, chain, seed, lnPriorRatio, lnProposalRatio, mvp);
    if (abortMove == YES)
        return NO_ERROR;

    /* get new value of clock rate */
	newR = *GetParamVals(param, chain, state[chain]);

    /* calculate factor */
    factor = newR / oldR;

    /* min and max values for branch lengths in relative time and substitution units */
    minV = BRLENS_MIN;
    maxV = BRLENS_MAX;
    minB = RELBRLENS_MIN;
    maxB = RELBRLENS_MAX;

    /* clock rate applies to all clock trees */
    for (i=0; i<numTrees; i++)
        {
        t = GetTreeFromIndex(i, chain, state[chain]);
        if (t->isClock == NO)
            continue;
        if (!strcmp(modelParams[t->relParts[0]].clockPr, "Fixed"))
            continue;

        oldT      = GetTreeFromIndex(i, chain, 1^state[chain]);
        treeParam = modelSettings[t->relParts[0]].brlens;

        /* no proposal ratio effect or prior ratio effect on clock model since the time tree remains the same */
        
        /* adjust the node depths and lengths */
        for (j=0; j<t->nNodes-1; j++)
            {
            p = t->allDownPass[j];
            p->nodeDepth *= factor; /* no harm done if nodeDepth==0.0 (undated tips) */
            p->length *= factor;    /* no harm done if length==0.0 (root)*/
            if (p->anc->anc != NULL && (p->length < minV || p->length > maxV))
                {
                abortMove = YES;
                return (NO_ERROR);
                }
            }
        
        /* adjust proposal and prior ratio for relaxed clock models */
        for (k=0; k<treeParam->nSubParams; k++)
		    {
            subParm = treeParam->subParams[k];
	        if (subParm->paramType == P_CPPEVENTS)
		        {
		        nEvents = subParm->nEvents[2*chain+state[chain]];
		        lambda = *GetParamVals (modelSettings[subParm->relParts[0]].cppRate, chain, state[chain]);
		        /* proposal ratio */
		        for (j=0; j<t->nNodes-2; j++)
                    {
                    p = t->allDownPass[j];
                    q = oldT->allDownPass[j];
                    (*lnProposalRatio) += nEvents[p->index ] * log (p->length  / q->length);
                    }
		        /* prior ratio */
                (*lnPriorRatio) += lambda * (TreeLen(oldT) - TreeLen(t));
		        /* update effective evolutionary lengths */
		        if (UpdateCppEvolLengths (subParm, t->root->left, chain) == ERROR)
                    {
                    abortMove = YES;
                    return (NO_ERROR);
                    }
		        }
            else if (subParm->paramType == P_TK02BRANCHRATES)
    		    {
	    	    nu       = *GetParamVals (modelSettings[subParm->relParts[0]].tk02var, chain, state[chain]);
		        tk02Rate = GetParamVals (subParm, chain, state[chain]);
		        brlens   = GetParamSubVals (subParm, chain, state[chain]);

                /* no proposal ratio effect */

                /* prior ratio and update of brlens */
			    for (j=0; j<t->nNodes-2; j++)
                    {
                    p = t->allDownPass[j];
                    q = oldT->allDownPass[j];
                    (*lnPriorRatio) -= LnProbTK02LogNormal (tk02Rate[q->anc->index], nu*q->length, tk02Rate[q->index]);
			        (*lnPriorRatio) += LnProbTK02LogNormal (tk02Rate[p->anc->index], nu*p->length, tk02Rate[p->index]);
                    brlens[p->index] = p->length * (tk02Rate[p->anc->index]+tk02Rate[p->index])/2.0;
                    }
		        }
		    else if (subParm->paramType == P_IGRBRANCHLENS)
    		    {
                igrvar = *GetParamVals (modelSettings[subParm->relParts[0]].igrvar, chain, state[chain]);
                igrRate = GetParamVals (subParm, chain, state[chain]);
                brlens = GetParamSubVals (subParm, chain, state[chain]);
            
                /* prior ratio and update of igr rates */
                for (j=0; j<t->nNodes-2; j++)
                    {
                    p = t->allDownPass[j];
                    q = oldT->allDownPass[j];
                    (*lnPriorRatio) -= LnProbTruncGamma (q->length/igrvar, 1.0/igrvar, brlens[q->index], minB, maxB);
                    (*lnPriorRatio) += LnProbTruncGamma (p->length/igrvar, 1.0/igrvar, brlens[p->index], minB, maxB);
                    igrRate[p->index] = brlens[p->index] / p->length;
                    }
                }
                /*The following if (*lnPriorRatio != *lnPriorRatio) should be removed if LnProbTruncGamma() would be made more exact and would never return -infinity */
                if (*lnPriorRatio != *lnPriorRatio)
                    {
                    abortMove=YES;
                    return (NO_ERROR);
                    }
            }
        }
 
	return (NO_ERROR);

}





int Move_CPPEventPosition (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{
	/* move the position of one CPP event */

	int			i, j, k, *nEvents;
	MrBFlt		pos, temp, **position, **rateMultiplier;
	TreeNode	*p=NULL, *q;
	ModelParams *mp;
	Tree		*t;

	/* get the model parameters */
	mp = &modelParams[param->relParts[0]];

	/* get the cpp event data */
	nEvents = param->nEvents[2*chain+state[chain]];
	position = param->position[2*chain+state[chain]];
	rateMultiplier = param->rateMult[2*chain+state[chain]];

	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* pick a branch and an event */
	for (i=j=0; i<t->nNodes - 2; i++)
		{
		p = t->allDownPass[i];
		j += nEvents[p->index];
		}		
	if (j == 0)
		{
		abortMove = YES;
		return (NO_ERROR);
		}
	k = (int) (RandomNumber (seed) * j);
	for (i=j=0; i<t->nNodes - 2; i++)
		{
		p = t->allDownPass[i];
		j += nEvents[p->index];
		if (j > k)
			break;
		}		
	if (position[p->index] == NULL)
		getchar();

	/* find local index */
	k = k - (j - nEvents[p->index]);

	/* find new position */
	pos = RandomNumber (seed);
    if (pos < POS_MIN || 1.0 - pos < POS_MIN)
        {
        abortMove = YES;
        return (NO_ERROR);
        }
	position[p->index][k] = pos;

	/* sort events; bubble sort for now */
	for (i=0; i<nEvents[p->index]; i++)
		{
		for (j=i+1; j<nEvents[p->index]; j++)
			{
			if (position[p->index][j] < position[p->index][i])
				{
				temp = position[p->index][i];
				position[p->index][i] = position[p->index][j];
				position[p->index][j] = temp;
				temp = rateMultiplier[p->index][i];
				rateMultiplier[p->index][i] = rateMultiplier[p->index][j];
				rateMultiplier[p->index][j] = temp;
				}
			}
		}

	/* calculate prior and proposal ratio */
	(*lnPriorRatio) = (*lnProposalRatio) = 0.0;

	/* update branch evolution lengths */
	if (UpdateCppEvolLengths (param, p, chain) == ERROR)
        {
        abortMove = YES;
        return (NO_ERROR);
        }

	/* set update of cond likes down to root */
	/* update of crowntree set in UpdateCppEvolLengths */
	q = p->anc;
	while (q->anc != NULL)
		{
		q->upDateCl = YES;
		q = q->anc;
		}

	return (NO_ERROR);
}





int Move_CPPRate (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* move the CPP rate (lambda) using multiplier */

	int			i, j, *nEvents, sumEvents;
	MrBFlt		oldLambda, newLambda, treeLength, tuning;
	ModelInfo	*m;
	Model		*mp;
	TreeNode	*p;
	Tree		*t;

	/* get tuning parameter */
	tuning = mvp[0];

	/* get model settings */
	m = &modelSettings[param->relParts[0]];
	mp = &modelParams[param->relParts[0]];

	/* get the CPP rate */
	oldLambda = *GetParamVals (param, chain, state[chain]);

	/* set new value */
	newLambda = oldLambda * exp ((0.5 - RandomNumber(seed))*tuning);
	
	/* reflect if necessary */
	while (newLambda < CPPLAMBDA_MIN || newLambda > CPPLAMBDA_MAX)
		{
		if (newLambda < CPPLAMBDA_MIN)
			newLambda = CPPLAMBDA_MIN * CPPLAMBDA_MIN / newLambda;
		if (newLambda > CPPLAMBDA_MAX)
			newLambda = CPPLAMBDA_MAX * CPPLAMBDA_MAX / newLambda;
		}
	
	/* store new value */
	(*GetParamVals (param, chain, state[chain])) = newLambda;

	/* calculate prior ratio */
	(*lnPriorRatio) = 0.0;
    for (i=0; i<param->nSubParams; i++)
		{
		nEvents = param->subParams[i]->nEvents[2*chain+state[chain]];
		sumEvents = 0;
		t = GetTree (param->subParams[i], chain, state[chain]);	
		treeLength = 0.0;
		for (j=0; j<t->nNodes-2; j++)
			{
			p = t->allDownPass[j];
			sumEvents += nEvents[p->index];
			treeLength += p->length;
			}
		(*lnPriorRatio) += (oldLambda - newLambda) * treeLength;
		(*lnPriorRatio) += sumEvents * log (newLambda / oldLambda);
		}

	/* adjust for prior on cppRate */
	if (!strcmp(mp->cppRatePr,"Exponential"))
		(*lnPriorRatio) += 	mp->cppRateExp * (oldLambda - newLambda);

	/* calculate proposal ratio */
	(*lnProposalRatio) = log (newLambda / oldLambda);

	/* we do not need to update likelihoods */
	for (i=0; i<param->nRelParts; i++)
		{
		modelSettings[param->relParts[i]].upDateCl = NO;
		}

	return (NO_ERROR);
	
}





int Move_CPPRateMultiplierMult (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* move one CPP rate multiplier using multiplier */

	int			i, j, k, *nEvents;
	MrBFlt		newRateMultiplier, oldRateMultiplier, tuning, minM, maxM, sigma, **rateMultiplier;
	TreeNode	*p = NULL;
	ModelParams *mp;
	ModelInfo	*m;
	Tree		*t;
	TreeNode	*q;

	/* get the tuning parameter */
	tuning = mvp[0];
	
	/* get the model parameters */
	mp = &modelParams[param->relParts[0]];
	m = &modelSettings[param->relParts[0]];

	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* get CPP event data */
	nEvents = param->nEvents[2*chain+state[chain]];
	rateMultiplier = param->rateMult[2*chain+state[chain]];

	/* get minimum and maximum of CPP rate multiplier */
	minM = param->min;
	maxM = param->max;
	
	/* pick a branch and a rateMultiplier */
	for (i=j=0; i<t->nNodes - 2; i++)
		{
		p = t->allDownPass[i];
		j += nEvents[p->index];
		}		
	if (j == 0)
		{
		abortMove = YES;
		return (NO_ERROR);
		}
	k = (int) (RandomNumber (seed) * j);
	for (i=j=0; i<t->nNodes - 2; i++)
		{
		p = t->allDownPass[i];
		j += nEvents[p->index];
		if (j > k)
			break;
		}		

	/* find local index */
	k = nEvents[p->index] - (j - k);

	/* find new rateMultiplier */
	oldRateMultiplier = rateMultiplier[p->index][k];
	newRateMultiplier = oldRateMultiplier * (exp (0.5 - RandomNumber (seed) * tuning));

	/* reflect if necessary */
	while (newRateMultiplier < minM || newRateMultiplier > maxM)
		{
		if (newRateMultiplier < minM)
			newRateMultiplier = minM * minM / newRateMultiplier;
		if (newRateMultiplier > maxM)
			newRateMultiplier = maxM * maxM / newRateMultiplier;
		}

	rateMultiplier[p->index][k] = newRateMultiplier;
	
	/* calculate prior ratio */
	sigma = *GetParamVals (m->cppMultDev, chain, state[chain]);
	(*lnPriorRatio) = LnRatioLogNormal (0.0, sigma, newRateMultiplier, oldRateMultiplier);

	/* calculate proposal ratio */
	(*lnProposalRatio) = log (newRateMultiplier / oldRateMultiplier);

	/* update branch evolution lengths */
	if (UpdateCppEvolLengths (param, p, chain)==ERROR)
        {
        abortMove = YES;
        return (NO_ERROR);
        }

	/* set update of cond likes down to root */
	/* update of crowntree set in UpdateCppEvolLengths */
	q = p->anc;
	while (q->anc != NULL)
		{
		q->upDateCl = YES;
		q = q->anc;
		}

	return (NO_ERROR);
	
}





int Move_CPPRateMultiplierRnd (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* move one CPP rate multiplier by redrawing from prior */

	int			i, j, k, *nEvents;
	MrBFlt		sigma, newRateMultiplier, oldRateMultiplier, **rateMultiplier;
	TreeNode	*p=NULL, *q;
	ModelParams *mp;
	ModelInfo	*m;
	Tree		*t;

	/* get the model parameters */
	mp = &modelParams[param->relParts[0]];
	m = &modelSettings[param->relParts[0]];

	/* get the CPP event data */
	nEvents = param->nEvents[2*chain+state[chain]];
	rateMultiplier = param->rateMult[2*chain+state[chain]];

	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* pick a branch and a rateMultiplier */
	for (i=j=0; i<t->nNodes - 2; i++)
		{
		p = t->allDownPass[i];
		j += nEvents[p->index];
		}		
	if (j == 0)
		{
		abortMove = YES;
		return (NO_ERROR);
		}
	k = (int) (RandomNumber (seed) * j);
	for (i=j=0; i<t->nNodes - 2; i++)
		{
		p = t->allDownPass[i];
		j += nEvents[p->index];
		if (j > k)
			break;
		}		

	/* find local index */
	k = nEvents[p->index] - (j - k);

	/* record old rate multiplier */
	oldRateMultiplier = rateMultiplier[p->index][k];

	/* find stdev of lognormal */
	sigma = *GetParamVals (m->cppMultDev, chain, state[chain]);

	/* set new value */
	do {
		newRateMultiplier = LogNormalRandomVariable (0.0, sigma, seed);
		} while (newRateMultiplier < param->min || newRateMultiplier > param->max);
	rateMultiplier[p->index][k] = newRateMultiplier;

	/* calculate prior ratio */
	(*lnPriorRatio) = LnRatioLogNormal(0.0, sigma, newRateMultiplier, oldRateMultiplier);
		
	/* calculate proposal ratio */
    (*lnProposalRatio) += LnRatioLogNormal (0.0, sigma, oldRateMultiplier, newRateMultiplier);

	/* update branch evolution lengths */
	if (UpdateCppEvolLengths (param, p, chain) == ERROR)
        {
        abortMove = YES;
        return (NO_ERROR);
        }

	/* set update of cond likes down to root */
	/* update of crowntree set in UpdateCppEvolLengths */
	q = p->anc;
	while (q->anc != NULL)
		{
		q->upDateCl = YES;
		q = q->anc;
		}

	return (NO_ERROR);
	
}





int Move_Extinction (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)
{

	/* change relative extinction rate using sliding window */
	
	int			i, isValidM;
	MrBFlt		oldM, newM, window, minM, maxM, ran, sR, eR, sF, oldLnPrior, newLnPrior,
                oldProp[2], newProp[2], x, y, *alphaDir, clockRate;
	char		*sS;
	ModelParams *mp;
	ModelInfo	*m;
	Tree		*t;

	/* get size of window, centered on current mu value */
	window = mvp[0];

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* get speciation rate */
	m = &modelSettings[param->relParts[0]];
	sR = *(GetParamVals (m->speciationRates, chain, state[chain]));
	
	/* get minimum and maximum values for mu/lambda */
	minM = 0.0;
    maxM = 1.0;

	/* get old value of mu/lambda */
	newM = oldM = *GetParamVals(param, chain, state[chain]);

	/* change value for mu/lambda */
	ran = RandomNumber(seed);
	if( window > maxM-minM )
		{
		window = maxM-minM;
		}
	newM = oldM + window * (ran - 0.5);
	
	/* check that new value is valid */
	isValidM = NO;
	do
		{
		if (newM < minM)
			newM = 2* minM - newM;
		else if (newM > maxM)
			newM = 2 * maxM - newM;
		else
			isValidM = YES;
		} while (isValidM == NO);

    /* get proportions */
    oldProp[0] = oldM;
    oldProp[1] = 1.0 - oldM;
    newProp[0] = newM;
    newProp[1] = 1.0 - newM;

    /* get proposal ratio */
	*lnProposalRatio = 0.0;
	
	/* calculate prior ratio */
	t         = GetTree(modelSettings[param->relParts[0]].brlens,chain,state[chain]);
	sS        = mp->sampleStrat;
	sF        = mp->sampleProb;
	eR        = oldM;
    clockRate = *GetParamVals(m->clockRate, chain, state[chain]);
	if (LnBirthDeathPriorPr (t, clockRate, &oldLnPrior, sR, eR,sS, sF) == ERROR)
		{
		MrBayesPrint ("%s   Problem calculating prior for birth-death process\n", spacer);
		return (ERROR);
		}
	eR = newM;
	if (LnBirthDeathPriorPr (t, clockRate, &newLnPrior, sR, eR, sS, sF) == ERROR)
		{
		MrBayesPrint ("%s   Problem calculating prior for birth-death process\n", spacer);
		return (ERROR);
		}

    /* adjust prior ratio according to beta distribution */
	alphaDir = mp->extinctionBeta;
    x = y = 0.0;
	for (i=0; i<2; i++)
		x += (alphaDir[i]-1.0)*log(newProp[i]);
	for (i=0; i<2; i++)
		y += (alphaDir[i]-1.0)*log(oldProp[i]);
	(*lnPriorRatio) = x - y + newLnPrior - oldLnPrior;
		
	
	/* copy new mu value back */
	*GetParamVals(param, chain, state[chain]) = newM;

	return (NO_ERROR);

}





int Move_ExtSPR (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* Change branch lengths and topology (potentially) using SPR (unrooted) 
	   with extension probability (rather than window). */

	/* For a description, see Lakner et al. (2008).

	   This move type has been tested on all combinations of rooted and unrooted,
	   constrained and unconstrained trees */
	
	int			i, j, topologyHasChanged, nCrownNodes, nRootNodes, directionLeft, directionUp, 
				isVPriorExp, moveInRoot, isStartConstrained, isStopConstrained;
	MrBFlt		m, x, y, tuning, maxV, minV, extensionProb, brlensExp=0.0;
	TreeNode	*p, *a, *b, *c, *d, *u, *v, *brlenNode[7];
	Tree		*t;
	ModelParams *mp;

	/* these parameters should be possible to set by user */
	extensionProb = mvp[0];	/* extension probability */
	tuning = mvp[1];        /* Larget & Simon's tuning parameter lambda */
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* max and min brlen */
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}

	topologyHasChanged = NO;

#	if defined (DEBUG_ExtSPR)
	printf ("Before:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
#	endif
	
	/* pick an internal branch that is free to move in either end
       (i and j keep track of number of locked directions) */
	do
		{
		p = t->intDownPass[(int)(RandomNumber(seed)*t->nIntNodes-1)];
        if (p->anc->left == p)
            a = p->anc->right;
        else
            a = p->anc->left;
        i = j = 0;
        if (a->isLocked == YES || a->left == NULL)
            i++;
        if (p->anc->isLocked == YES || p->anc->anc->anc == NULL)
            i++;
        if (p->left->isLocked == YES || p->left->left == NULL)
            j++;
        if (p->right->isLocked == YES || p->right->left == NULL)
            j++;
		} while (i == 2 && j == 2);
		
	/* set up pointers for nodes around the picked branch */
	/* cut the tree into crown, root and attachment part */
	/* change the relevant lengths in the attachment part */
	/* the lengths of a and v are automatically contained in the */
	/* "attachment" part but the length of c has to be stored in x */
	v = p;
	u = p->anc;

	/* store brlen node */
	brlenNode[3] = v;

	/* change in root tree ? */
	if (j == 2)
        moveInRoot = YES;
    else if (i == 2)
        moveInRoot = NO;
    else if (RandomNumber (seed) < 0.5)
		moveInRoot = YES;
	else
		moveInRoot = NO;

    /* determine whether start is constrained on backward move */
    isStartConstrained = isStopConstrained = NO;
    if (moveInRoot == YES && i == 1)
        isStartConstrained = YES;
    else if (moveInRoot == NO && j == 1)
        isStartConstrained = YES;

	/* set up pointers for crown part */
	/* also determine direction of move in crown part */
	if (v->right->left == NULL || v->right->isLocked == YES)
        directionLeft = YES;
    else if (v->left->left == NULL || v->left->isLocked == YES)
        directionLeft = NO;
    else if (RandomNumber(seed) < 0.5)
        directionLeft = YES;
    else
        directionLeft = NO;
    if (directionLeft == YES)
        {
		c = v->left;
		d = v->right;
		}
	else
		{
		c = v->right;
		d = v->left;
		}

	/* store brlen nodes and brlen to move */
	brlenNode[0] = d;
	brlenNode[1] = c;
	x = c->length;

	/* cut and reconnect crown part */
	c->anc = d;
	d->anc = c;
	
	/* mark nodes in root part */
	/* also determine direction of move in root part */
	if (u->left == v)
		a = u->right;
	else
		a = u->left;
	b = u->anc;
	if (u->anc->anc == NULL || u->isLocked == YES)
        directionUp = YES;
    else if (a->left == NULL || a->isLocked == YES)
        directionUp = NO;
    else if (RandomNumber(seed) < 0.5)
		directionUp = YES;
	else
        directionUp = NO;
    if (directionUp == NO)
        {
        /* switch a and b */
        b = a;
		a = u->anc;
		}

	/* store brlen nodes */
	if (directionUp == YES)
		{
		brlenNode[4] = u;
		brlenNode[5] = a;
		}
	else
		{
		brlenNode[4] = b;
		brlenNode[5] = u;
		}

	/* cut root part*/
	/* store branch to move in u->length */
	if (directionUp == NO) 
		{
		b->anc = a;
		if (a->left == u)
			a->left = b;
		else
			a->right = b;
		}
	else 
		{
		a->anc = b;
		if (b->left == u)
			b->left = a;
		else
			b->right = a;
		y = a->length;
		a->length = u->length;
		u->length = y;
		a->upDateTi = YES;
		u->upDateTi = YES;
		}

	/* move around in root subtree */
	nRootNodes = 0;
	if (moveInRoot == YES)
		{
		for (nRootNodes=0; RandomNumber(seed)<extensionProb || nRootNodes==0; nRootNodes++) 
			{
			if (directionUp == YES) 
				{	/* going up tree */
				if (a->left == NULL || a->isLocked == YES)
					break;		/* can't go further */
				topologyHasChanged = YES;
				b = a;
				if (RandomNumber(seed) < 0.5)
					a = a->left;
				else
					a = a->right;
				if (u->isLocked == YES)
					{
					b->isLocked = YES;
					u->isLocked = NO;
					b->lockID = u->lockID;
					u->lockID = 0;
					}
				}
			else 
				{	/* going down tree */
				if (a->anc == NULL || u->isLocked == YES)
					break;		/* can't go further */
				topologyHasChanged = YES;
				if (RandomNumber(seed)<0.5) 
					{
					directionUp = YES; /* switch direction */
					/* find sister of a */
					if (a->left == b) 
						{
						b = a;
						a = a->right;
						}
					else 
						{  
						b = a;
						a = a->left;
						}
					/* as long as we are moving upwards
					the cond likes to update will be
					flagged by the last pass from u to the root */
					}	
				else 
					{	/* continue down */
					b = a;
					a = a->anc;
					b->upDateCl = YES; 
					if (b->isLocked == YES)
						{
						u->isLocked = YES;
						b->isLocked = NO;
						u->lockID = b->lockID;
						b->lockID = 0;
						}
					}
				}
			}
        /* check whether stop is constrained */
	    if (directionUp == YES) 
		    {
		    if (a->left == NULL || a->isLocked == YES) 
			    isStopConstrained = YES;
		    }
	    else 
		    {
		    if (a->anc  == NULL || u->isLocked == YES)
			    isStopConstrained = YES;
		    }
        }

	/* store brlen nodes */
	if (nRootNodes > 0)
		{
		if (directionUp == YES)
			{
			brlenNode[6] = a;
			brlenNode[5] = u;
			}
		else
			{
			brlenNode[6] = u;
			brlenNode[5] = b;
			}
		}

	/* move around in crown subtree */
	nCrownNodes = 0;
	if (moveInRoot == NO)		
		{
		for (nCrownNodes=0; RandomNumber(seed)<extensionProb || nCrownNodes==0; nCrownNodes++) 
			{
			if (c->left == NULL || c->isLocked == YES)
				break;	/* can't go further */
			topologyHasChanged = YES;
			if (RandomNumber(seed) < 0.5) 
				{
				/* rotate c anticlockwise - prepare pointers for move left */
				c->anc = c->left;  /* the root will be in the direction we are heading */
				c->left = c->right;
				c->right = d;
				}
			else 
				{
				/* rotate c clockwise - prepare pointers for move right */
				c->anc = c->right;	/* the root will be in the direction we are heading */
				c->right = c->left;
				c->left = d;  
				}
			/* OK - let's move!; c->anc points in the right direction
			don't forget to move the branch lengths as well */
			d = c;
			c = c->anc;
			d->length = c->length;
			d->upDateCl = YES; 
			d->upDateTi = YES;
			}
        /* check if stop constrained */
	    if (c->left == NULL || c->isLocked == YES)
		    isStopConstrained = YES;
		}

	/* store brlen nodes */
	if (nCrownNodes > 0)
		{
		brlenNode[2] = c;
		brlenNode[1] = d;
		}

	/* adjust proposal ratio for constraints */
	if (isStartConstrained == NO && isStopConstrained == YES)
        (*lnProposalRatio) += log (2.0 * (1.0 - extensionProb));
    else if (isStartConstrained == YES && isStopConstrained == NO)
		(*lnProposalRatio) -= log (2.0 * (1.0 - extensionProb));

	/* combine the subtrees */
	c->anc = v;
	d->anc = v;
	if (directionLeft == YES) 
		{
		v->left = c;
		v->right = d;
		}
	else 
		{
		v->left = d;
		v->right = c;
		}

	/* the dangling branch is inserted in reverted position
	   such that the back move will be possible
	   if we have moved around in crown subtree
	   otherwise it is left in its original position */
	if (nCrownNodes > 0)
		{
		d->length = x;
		d->upDateTi = YES;
		}
	else
		{
		c->length = x;
		}	

	if (directionUp == YES) 
		{
		u->anc = b;
		if (u->left == v)
			u->right = a;
		else 
			u->left = a;
		a->anc = u;
		if (b->left == a)
			b->left = u;
		else
			b->right = u;
		/* the dangling branch is contained in u->length
		   and will automatically be inserted in the right position
		   to enable the back move regardless of whether it was
		   initially directed upwards or downwards
		   BUT if we haven't moved in root subtree, it is advantageous (necessary
		   for rooted trees) to avoid switching branches, which occurs otherwise
		   if directionUp == YES */
		if (nRootNodes == 0) 
			{
			x = u->length;
			u->length = a->length;
			a->length = x;
			a->upDateTi = NO;
			u->upDateTi = NO;
			}
		}
	else 
		{
		u->anc = a;
		if (u->left == v)
			u->right = b;
		else 
			u->left = b;
		b->anc = u;
		if (a->left == b)
			a->left = u;
		else
			a->right = u;
		/* the modified branch contained in u->length will have
		   to be moved to b->length to enable back move
		   BUT if we haven't moved, it is better to keep it in place
		   (necessary for rooted trees) */
		if (nRootNodes > 0) 
			{
			x = u->length;
			u->length = b->length;
			b->length = x;
			b->upDateTi = YES;
			u->upDateTi = YES;
			}
		}
	
	/* modify branch lengths */
	/* first modify length of middle branch */
	m = brlenNode[3]->length;
	x = m * exp(tuning * (RandomNumber(seed) - 0.5));		/* save the modified dangling branch for later use */
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	brlenNode[3]->length = x;
	brlenNode[3]->upDateTi = YES;

	/* update proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - x);

	if (moveInRoot == NO)
		{
		/* if no move in crown, then select randomly, otherwise always the moved branch */
		if (nCrownNodes == 0 && RandomNumber (seed) < 0.5)
			p = brlenNode[0];
		else
			p = brlenNode[1];

		/* modify branch length */
		m = p->length;
		x = m * exp(tuning * (RandomNumber(seed) - 0.5));
		while (x < minV || x > maxV)
			{
			if (x < minV)
				x = minV * minV / x;
			else if (x > maxV)
				x = maxV * maxV / x;
			}
		p->length = x;
		p->upDateTi = YES;

		/* update proposal and prior ratio based on length modification */
		(*lnProposalRatio) += log (x / m);
		if (isVPriorExp == YES)
			(*lnPriorRatio) += brlensExp * (m - x);
		}
			
	if (moveInRoot == YES)
		{
		/* if no move in root, then select randomly, otherwise always the moved branch */
		if (nRootNodes == 0 && RandomNumber(seed) < 0.5)
			p = brlenNode[4];
		else
			p = brlenNode[5];
		
		/* modify branch length but not if 'root' branch in rooted tree */
		if (t->isRooted == NO || p->anc->anc != NULL)
			{
			m = p->length;
			x = m * exp(tuning * (RandomNumber(seed) - 0.5));
			while (x < minV || x > maxV)
				{
				if (x < minV)
					x = minV * minV / x;
				else if (x > maxV)
					x = maxV * maxV / x;
				}
			p->length = x;
			p->upDateTi = YES;

			/* update proposal and prior ratio based on length modification */
			(*lnProposalRatio) += log (x / m);
			if (isVPriorExp == YES)
				(*lnPriorRatio) += brlensExp * (m - x);	
			}
		}

	/* set flags for update of cond likes from v and down to root */
	p = v;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}

#	if defined (DEBUG_FTBR)
	printf ("After:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  c: %d  d: %d  a: %d  b: %d\n",v->index, u->index, 
		c->index, d->index, a->index, b->index);
	printf ("No. nodes moved in root subtree: %d\n",nRootNodes);
	printf ("No. nodes moved in crown subtree: %d\n",nCrownNodes);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

	gNodeMoves = nCrownNodes + nRootNodes;
#	endif

#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in output tree to eSPR2\n");
		getchar();
		}
#endif

    assert (nCrownNodes > 0 || nRootNodes > 0);

    return (NO_ERROR);
	
}





int Move_ExtSPRClock (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* Change branch lengths and topology (potentially) using SPR-type move 
	   with extension probability (rather than window, attachment rate or similar).
       The move is Metropolized, which should improve mixing. However, this means 
       that it must be combined with a node slider move to be efficient.

	   The move picks a branch and then moves its lower attachment point 
	   from its original position, one node at a time, with
	   a probability determined by the extensionProb parameter. This is
	   done in a way consistent with the clock constraints and any locked
	   nodes there might be in the tree. The lower attachment point is 
       minimally moved one node away.
	   
	   On the ending branch, the attachment point is reinserted randomly
	   along the branch (below the minimum age of the node). */
	
	int		    i, j, topologyHasChanged, isStartLocked=NO, isStopLocked=NO, nRootNodes, directionUp,
		        n1=0, n2=0, n3=0, n4=0, n5=0, *nEvents;
	MrBFlt		x, y, oldBrlen=0.0, newBrlen=0.0, extensionProb, igrvar, *igrRate=NULL,
			    v1=0.0, v2=0.0, v3=0.0, v4=0.0, v5=0.0, v3new=0.0, lambda, *tk02Rate=NULL,
				**position=NULL, **rateMultiplier=NULL, *brlens, nu, origProp, origBrlenProp=1.0,
                minV, maxV, minB, maxB;
    TreeNode	*p, *a, *b, *u, *v, *oldA;
	Tree		*t;
	ModelParams *mp;
	ModelInfo	*m = NULL;
	Param		*subParm;

    extensionProb = mvp[0];	/* extension probability */

	(*lnProposalRatio) = (*lnPriorRatio) = 0.0;

	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* get model params and model info */
	mp = &modelParams[param->relParts[0]];
	m = &modelSettings[param->relParts[0]];
	
    /* get min and max branch lengths in relative time and substitution units */
    minV = BRLENS_MIN;
    maxV = BRLENS_MAX;
    minB = RELBRLENS_MIN;
    maxB = RELBRLENS_MAX;

	/* assume no topology change */
	topologyHasChanged = NO;

#	if defined (DEBUG_ExtSPRClock)
	printf ("Before:\n");
	ShowNodes (t->root, 2, YES);
#	endif
	
	/* pick a branch */
	do
		{
		p = t->allDownPass[(int)(RandomNumber(seed)*(t->nNodes - 1))];
		} while (p->anc->anc == NULL || p->anc->isLocked == YES || p->anc->anc->anc == NULL);
		
	/* set up pointers for nodes around the picked branch */
	v = p;
	u = p->anc;
	if (u->left == v)
		a = u->right;
	else
		a = u->left;
	b = u->anc;
	oldA = a;

	/* record branch length for insertion in back move */
	if (v->nodeDepth > a->nodeDepth)
		oldBrlen = b->nodeDepth - v->nodeDepth;
	else
		oldBrlen = b->nodeDepth - a->nodeDepth;

	v1 = a->length;
	v2 = u->length;
	v3 = v->length;

    origProp = u->length / oldBrlen;

    /* reassign events for CPP */
	for (i=0; i<param->subParams[0]->nSubParams; i++)
		{
		subParm = param->subParams[0]->subParams[i];
		if (subParm->paramType == P_CPPEVENTS)
			{
            /* get pointers to CPP events */
			nEvents = subParm->nEvents[2*chain+state[chain]];
			position = subParm->position[2*chain+state[chain]];
			rateMultiplier = subParm->rateMult[2*chain+state[chain]];
			n1 = nEvents[a->index];
			n2 = nEvents[u->index];
			n3 = nEvents[v->index];
			if (n2 > 0)
				{
				position[a->index] = (MrBFlt *) SafeRealloc ((void *) position[a->index], (n1+n2) * sizeof (MrBFlt));
				rateMultiplier[a->index] = (MrBFlt *) SafeRealloc ((void *) rateMultiplier[a->index], (n1+n2) * sizeof (MrBFlt));
				}
			for (j=0; j<n1; j++)
				position[a->index][j] *= v1 / (v1+v2);
			for (j=n1; j<n1+n2; j++)
				{
				position[a->index][j] = (position[u->index][j-n1] * v2 + v1) / (v1+v2);
				rateMultiplier[a->index][j] = rateMultiplier[u->index][j-n1];
				}
			nEvents[a->index] = n1+n2;
			nEvents[u->index] = 0;
			if (n2 > 0)
				{
				free (position[u->index]);
				free (rateMultiplier[u->index]);
				position[u->index] = rateMultiplier[u->index] = NULL;
				}
			}	/* end CPP events parm */
		else if (subParm->paramType == P_TK02BRANCHRATES)
			{
			/* adjust prior ratio */
			nu = *GetParamVals (modelSettings[subParm->relParts[0]].tk02var, chain, state[chain]);
			tk02Rate = GetParamVals (subParm, chain, state[chain]);
			(*lnPriorRatio) -= LnProbTK02LogNormal(tk02Rate[a->anc->index], nu*a->length, tk02Rate[a->index]);
			(*lnPriorRatio) -= LnProbTK02LogNormal(tk02Rate[v->anc->index], nu*v->length, tk02Rate[v->index]);
			(*lnPriorRatio) -= LnProbTK02LogNormal(tk02Rate[u->anc->index], nu*u->length, tk02Rate[u->index]);
			(*lnPriorRatio) += LnProbTK02LogNormal(tk02Rate[u->anc->index], nu*(a->length+u->length), tk02Rate[a->index]);
			/* adjust effective branch lengths */
			brlens = GetParamSubVals (subParm, chain, state[chain]);
			brlens[a->index] = ((tk02Rate[a->index] + tk02Rate[b->index])/2.0)*(a->length + u->length);
			}	/* end tk02 branch rate parameter */
        else if (subParm->paramType == P_IGRBRANCHLENS)
            {
            igrvar = *GetParamVals (modelSettings[subParm->relParts[0]].igrvar, chain, state[chain]);
            igrRate = GetParamVals (subParm, chain, state[chain]);
			brlens = GetParamSubVals (subParm, chain, state[chain]);

            /* no proposal ratio effect or dealt with below, record value here */
            origBrlenProp = brlens[u->index] / (brlens[a->index] + brlens[u->index]);

             /* adjust prior ratio for old branches */
            (*lnPriorRatio) -= LnProbTruncGamma(a->length/igrvar, 1.0/igrvar, brlens[a->index], minB, maxB);
			(*lnPriorRatio) -= LnProbTruncGamma(v->length/igrvar, 1.0/igrvar, brlens[v->index], minB, maxB);
			(*lnPriorRatio) -= LnProbTruncGamma(u->length/igrvar, 1.0/igrvar, brlens[u->index], minB, maxB);

            /* adjust effective branch lengths and rates */
            /* we just move brlens[u->index] to new location; Hastings ratio of the alternative not worked out yet */
            // brlens[a->index] += brlens[u->index];
            igrRate[a->index] = brlens[a->index] / (a->length + u->length); /* times not changed yet */
    
            /* adjust prior ratio for new branch lengths */
			(*lnPriorRatio) += LnProbTruncGamma((a->length+u->length)/igrvar, 1.0/igrvar, brlens[a->index], minB, maxB);

            /*The following if (*lnPriorRatio != *lnPriorRatio) should be removed if LnProbTruncGamma() would be made more exact and would never return -infinity */
            if (*lnPriorRatio != *lnPriorRatio)
                {
                abortMove=YES;
                return (NO_ERROR);
                }
            }
		}	/* next subparameter */

    /* cut tree */
	a->anc = b;
	if (b->left == u)
		b->left = a;
	else
		b->right = a;
	a->length += u->length;
	a->upDateTi = YES;

	/* determine initial direction of move and whether the reverse move would be stopped by constraints */
	if (a->left == NULL || a->isLocked == YES || a->nodeDepth < v->nodeDepth + minV)
        {
		isStartLocked = YES;
        directionUp = NO;
        }
	else
        {
        isStartLocked = NO;
    	if (RandomNumber(seed) < 0.5)
	    	directionUp = YES;
	    else
		    directionUp = NO;
        }
		
	/* move around in root subtree */
	for (nRootNodes=0; nRootNodes==0 || RandomNumber(seed)<extensionProb; nRootNodes++) 
		{
		if (directionUp == YES) 
			{	/* going up tree */
			if (a->left == NULL || a->isLocked == YES || a->nodeDepth < v->nodeDepth + minV)
				break;		/* can't go farther */
			topologyHasChanged = YES;
			b = a;
			if (RandomNumber(seed) < 0.5)
				a = a->left;
			else
				a = a->right;
			}
		else 
			{	/* going down tree */
			topologyHasChanged = YES;
			if (RandomNumber(seed)<0.5 || b->anc->anc == NULL || b->isLocked == YES)
				{
				directionUp = YES; /* switch direction */
				/* find sister of a */
				if (b->left == a) 
					{
					a = b->right;
					}
				else 
					{  
					a = b->left;
					}
				/* as long as we are moving upwards
	     		the cond likes to update will be
				flagged by the last pass from u to the root */
				}	
			else 
				{	/* continue down */
				a = b;
				b = b->anc;
				a->upDateCl = YES;
				}
			}
		}
		
	/* determine whether the forward move was or would have been stopped by constraints */
	isStopLocked = NO;
	if (directionUp == YES)
		{
		if (a->left == NULL || a->isLocked == YES || a->nodeDepth < v->nodeDepth + minV)
			isStopLocked = YES;
		}

	/* reattach u */
	if (u->left == v)
		u->right = a;
	else
		u->left = a;
	a->anc = u;
	u->anc = b;
	if (b->left == a)
		b->left = u;
	else
		b->right = u;

	/* insert u randomly on branch below a */
	if (a->nodeDepth > v->nodeDepth)
		x = b->nodeDepth - a->nodeDepth;
	else
		x = b->nodeDepth - v->nodeDepth;
	newBrlen = x;
    if (x <= 2.0 * minV)
        {
        abortMove = YES;
        return (NO_ERROR);
        }

    y = RandomNumber(seed);

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}

	/* adjust lengths */
	u->nodeDepth = b->nodeDepth - minV - y*(x-2.0*minV);
    u->length = b->nodeDepth - u->nodeDepth;
	a->length = u->nodeDepth - a->nodeDepth;
    v->length = u->nodeDepth - v->nodeDepth;
	
	v3new = v->length;
	v4 = a->length;
	v5 = u->length;

	/* adjust prior ratio for clock tree */
    if (LogClockTreePriorRatio(param, chain, &x) == ERROR)
        {
        return (ERROR);
        }
    (*lnPriorRatio) += x;

    /* adjust events, prior ratio and proposal ratio for relaxed clock models */
	for (i=0; i<param->subParams[0]->nSubParams; i++)
		{
		subParm = param->subParams[0]->subParams[i];
		if (subParm->paramType == P_CPPEVENTS)
			{
            /* reassign events for CPP */
            nEvents = subParm->nEvents[2*chain+state[chain]];
			position = subParm->position[2*chain+state[chain]];
			rateMultiplier = subParm->rateMult[2*chain+state[chain]];
			for (j=0; j<nEvents[a->index]; j++)
				{
				if (position[a->index][j] > v4 / (v4+v5))
					break;
				}
			n4 = j;
			n5 = nEvents[a->index] - j;
			nEvents[u->index] = n5;
			if (n5 > 0)
				{
				position[u->index] = (MrBFlt *) SafeRealloc ((void *) position[u->index], n5 * sizeof (MrBFlt));
				rateMultiplier[u->index] = (MrBFlt *) SafeRealloc ((void *) rateMultiplier[u->index], n5 * sizeof (MrBFlt));			
				for (j=n4; j<nEvents[a->index]; j++)
					{
					position[u->index][j-n4] = (position[a->index][j] * (v4+v5) - v4) / v5;
					rateMultiplier[u->index][j-n4] = rateMultiplier[a->index][j];
					}
				if (n4 > 0)
					{
					position[a->index] = (MrBFlt *) SafeRealloc ((void *) position[a->index], n4 * sizeof (MrBFlt));
					rateMultiplier[a->index] = (MrBFlt *) SafeRealloc ((void *) rateMultiplier[a->index], n4 * sizeof (MrBFlt));
					for (j=0; j<n4; j++)
						position[a->index][j] *= ((v4+v5) / v4);
					}
				else
					{
					free (position[a->index]);
					free (rateMultiplier[a->index]);
					position[a->index] = rateMultiplier[a->index] = NULL;
					}
				nEvents[a->index] = n4;
                }
			else
				{
				for (j=0; j<nEvents[a->index]; j++)
					position[a->index][j] *= ((v4+v5) / v4);
				}

            /* adjust proposal ratio for length change in v branch*/
			(*lnProposalRatio) += n3 * log (v3new / v3);

			/* adjust prior ratio for length change */
			lambda = *GetParamVals (modelSettings[subParm->relParts[0]].cppRate, chain, state[chain]);
			(*lnPriorRatio) += lambda * (v3 - v3new);

			/* update effective branch lengths */
			if (UpdateCppEvolLengths (subParm, oldA, chain) == ERROR)
                {
                abortMove = YES;
                return (NO_ERROR);
                }
			if (UpdateCppEvolLengths (subParm, u, chain) == ERROR)
                {
                abortMove = YES;
                return (NO_ERROR);
                }
            }	/* end cpp events parameter */
		else if (subParm->paramType == P_TK02BRANCHRATES)
			{
            /* get relevant parameters */
            nu = *GetParamVals (modelSettings[subParm->relParts[0]].tk02var, chain, state[chain]);
			tk02Rate = GetParamVals (subParm, chain, state[chain]);
			brlens = GetParamSubVals (subParm, chain, state[chain]);

            /* no proposal ratio effect */

            /* adjust prior ratio */
			(*lnPriorRatio) -= LnProbTK02LogNormal(tk02Rate[u->anc->index], nu*(a->length+u->length), tk02Rate[a->index]);
			(*lnPriorRatio) += LnProbTK02LogNormal(tk02Rate[a->anc->index], nu*a->length, tk02Rate[a->index]);
			(*lnPriorRatio) += LnProbTK02LogNormal(tk02Rate[v->anc->index], nu*v->length, tk02Rate[v->index]);
			(*lnPriorRatio) += LnProbTK02LogNormal(tk02Rate[u->anc->index], nu*u->length, tk02Rate[u->index]);

			/* adjust effective branch lengths */
            brlens[a->index] = a->length * (tk02Rate[a->index] + tk02Rate[a->anc->index]) / 2.0;
			brlens[v->index] = v->length * (tk02Rate[v->index] + tk02Rate[v->anc->index]) / 2.0;
			brlens[u->index] = u->length * (tk02Rate[u->index] + tk02Rate[u->anc->index]) / 2.0;
            }	/* end tk02 branch rate parameter */
		else if (subParm->paramType == P_IGRBRANCHLENS)
			{
            /* get relevant parameters */
			igrvar = *GetParamVals (modelSettings[subParm->relParts[0]].igrvar, chain, state[chain]);
			igrRate = GetParamVals (subParm, chain, state[chain]);
			brlens = GetParamSubVals (subParm, chain, state[chain]);

            /* adjust prior ratio for old branch length */
			(*lnPriorRatio) -= LnProbTruncGamma ((a->length+u->length)/igrvar, 1.0/igrvar, brlens[a->index], minB, maxB);

            /* adjust effective branch lengths and rates; use random number from above to subdivide  */
            /* we just rearrange brlens values; Hastings ratio not worked out yet for alternative */
			brlens [v->index] = brlens[v->index];   /* keep this branch length the same */
            igrRate[v->index] = brlens[v->index] / v->length;
            // brlens [u->index] = (brlens[a->index] - 2.0*minB) * y + minB;   /* y is random number from above */
            // brlens [a->index] = (brlens[a->index] - 2.0*minB) * (1.0 - y) + minB;
            igrRate[u->index] = brlens[u->index] / u->length;
            igrRate[a->index] = brlens[a->index] / a->length;
            if (brlens[u->index] < minB || brlens[u->index] > maxB ||
                brlens[a->index] < minB || brlens[a->index] > maxB)
                {
                abortMove = YES;
                return (NO_ERROR);
                }

            /* adjust prior ratio for new branch lengths */
			(*lnPriorRatio) += LnProbTruncGamma (a->length/igrvar, 1.0/igrvar, brlens[a->index], minB, maxB);
			(*lnPriorRatio) += LnProbTruncGamma (v->length/igrvar, 1.0/igrvar, brlens[v->index], minB, maxB);
			(*lnPriorRatio) += LnProbTruncGamma (u->length/igrvar, 1.0/igrvar, brlens[u->index], minB, maxB);

            /* adjust proposal ratio (prop. to ratio between new and old brlen that is being split) */
            /* when we rearrange effective brlens, the proposal ratio is 1; the ratio below is NOT the correct Hastings ratio for the alternative update */
            // (*lnProposalRatio) += log ((brlens[a->index] + brlens[u->index] - 2.0*minB) / (brlens[oldA->index] - 2.0*minB));

            /*The following if (*lnPriorRatio != *lnPriorRatio) should be removed if LnProbTruncGamma() would be made more exact and would never return -infinity */
            if (*lnPriorRatio != *lnPriorRatio)
                {
                abortMove=YES;
                return (NO_ERROR);
                }
            }   /* end igr branch rate parameter */
        }	/* next subparameter */

    /* set tiprobs update flags */
	a->upDateTi = YES;
	u->upDateTi = YES;
	v->upDateTi = YES;

	/* set flags for update of cond likes from u and down to root */
	p = u;
	while (p->anc != NULL)
		{
		p->upDateCl = YES; 
		p = p->anc;
		}

	/* calculate proposal ratio for tree change */
	if (topologyHasChanged == YES)
		{
		(*lnProposalRatio) += log ((newBrlen - 2.0*minV) / (oldBrlen - 2.0*minV));
		if (isStartLocked == NO && isStopLocked == YES)
			(*lnProposalRatio) += log (2.0 * (1.0 - extensionProb));
		else if (isStartLocked == YES && isStopLocked == NO)
			(*lnProposalRatio) -= log (2.0 * (1.0 - extensionProb));
		}

#	if defined (DEBUG_ExtSPRClock)
	ShowNodes (t->root, 2, YES);
	printf ("After\nProposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  a: %d  b: %d\n",v->index, u->index, a->index, b->index);
	printf ("No. nodes moved in root subtree: %d\n",nRootNodes);
	printf ("Has topology changed? %d\n",topologyHasChanged);
#	endif

    return (NO_ERROR);
	
}





int Move_ExtSS (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* Change branch lengths and topology (potentially) using Subtree Swapping (unrooted) 
	   with extension probability.

	   This move type picks two subtrees and swaps their position. Like the SPR and TBR,
	   it is a superset of the NNI but there are some interesting differences. With the
	   SPR and TBR, it is not possible to go between all five-tip trees in a single
	   step. For instance, going from ((1,2),3,(4,5)) to ((1,5),3,(4,2)) requires two
	   steps. The SS move can go between all pairs of five-tip trees in a single step.
	   Some six-tip tree pairs will require two steps though.

       Unlike the published version of the move (Lakner et al, Syst Bio), this version
       does _not_ multiply all branch lengths between the subtrees.
	   
	   */
	
	int			i, numFree, topologyHasChanged, nCrownNodes, nRootNodes, directionLeft, directionUp, 
				isVPriorExp, moveInRoot;
	MrBFlt		m, x, tuning, maxV, minV, extensionProb, brlensExp=0.0;
	TreeNode	*p, *q, *a, *b, *c, *d, *u, *v;
	Tree		*t;
	ModelParams *mp;

    (*lnPriorRatio) = (*lnProposalRatio) = 0.0;

    /* these parameters should be possible to set by user */
	extensionProb = mvp[0];	/* extension probability */
	tuning = mvp[1];        /* Larget & Simon's tuning parameter lambda */
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* max and min brlen */
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}

	topologyHasChanged = NO;

	/* unmark all tree */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		p->marked = NO;
		}

	/* pick a branch */
	do
		{
		p = t->allDownPass[(int)(RandomNumber(seed)*t->nNodes)];
		} while (p->anc == NULL);
		
	/* set up pointers for nodes around the picked branch */
	v = p;
	u = p->anc;

	/* check the possible move directions */
	numFree = 0;
	if (v->left != NULL && v->left->isLocked == NO)
		numFree ++;
	if (v->right != NULL && v->right->isLocked == NO)
		numFree++;
	if (u->anc != NULL && u->isLocked == NO)
		numFree++;
	if (u->left == v)
		{
		if (u->right != NULL && u->right->isLocked == NO)
			numFree++;
		}
	else
		{
		if (u->left != NULL && u->left->isLocked == NO)
			numFree++;
		}

	/* select one of them randomly */
	i = (int) (RandomNumber (seed) * numFree) + 1;
	numFree = 0;
	a = b = c = d = p;
	directionLeft = directionUp = moveInRoot = NO;
	if (v->left != NULL && v->left->isLocked == NO)
		{
		numFree ++;
		if (i == numFree)
			{
			moveInRoot = NO;
			directionLeft = YES;
			c = v->left;
			d = v;
			}
		}
	if (v->right != NULL && v->right->isLocked == NO)
		{
		numFree ++;
		if (i == numFree)
			{
			moveInRoot = NO;
			directionLeft = NO;
			c = v->right;
			d = v;
			}
		}
	if (u->anc != NULL && u->isLocked == NO)
		{
		numFree ++;
		if (i == numFree)
			{
			moveInRoot = YES;
			directionUp = NO;
			a = u->anc;
			b = u;
			}
		}
	if (u->left == v)
		{
		if (u->right != NULL && u->right->isLocked == NO)
			{
			numFree ++;
			if (i == numFree)
				{
				moveInRoot = YES;
				directionUp = YES;
				a = u->right;
				b = u;
				}
			}
		}
	else
		{
		if (u->left != NULL && u->left->isLocked == NO)
			{
			numFree ++;
			if (i == numFree)
				{
				moveInRoot = YES;
				directionUp = YES;
				a = u->left;
				b = u;
				}
			}
		}

#	if defined (DEBUG_ExtSS)
	printf ("Before:\n");
	ShowNodes (t->root, 2, NO);
	printf ("v: %d  u: %d  c: %d  d: %d  a: %d  b: %d\n",v->index, u->index, 
		c->index, d->index, a->index, b->index);
	printf ("directionUp = %d -- directionLeft = %d -- moveInRoot = %d\n", directionUp, directionLeft, moveInRoot);
	getchar();
#	endif
	
	/* move around and potentially swap in root subtree */
	nRootNodes = 0;
	if (moveInRoot == YES)
		{
		for (nRootNodes=0; nRootNodes==0 || RandomNumber(seed)<extensionProb; nRootNodes++) 
			{
			if (directionUp == YES) 
				{	/* going up tree */
				if (a->left == NULL || a->isLocked == YES)
					break;		/* can't go further */
				topologyHasChanged = YES;
				b = a;
				if (RandomNumber(seed) < 0.5)
					a = a->left;
				else
					a = a->right;
				}
			else 
				{	/* going down tree */
				if (a->anc == NULL || a->isLocked == YES)
					break;		/* can't go further */
				topologyHasChanged = YES;
				b->marked = YES;

				if (RandomNumber(seed) < 0.5) 
					{
					directionUp = YES; /* switch direction */
					/* find sister of a */
					if (a->left == b) 
						{
						b = a;
						a = a->right;
						}
					else 
						{  
						b = a;
						a = a->left;
						}
					}	
				else 
					{	/* continue down */
					b = a;
					a = a->anc;
					}
				}
			}
		/* swap the root subtrees */
		if (nRootNodes > 0)
			{
			if (directionUp == YES)
				{
				v->anc = b;
				a->anc = u;
				if (b->left == a)
					b->left = v;
				else if (b->right == a)
					b->right = v;
				if (u->left == v)
					u->left = a;
				else
					u->right = a;
				}
			else
				{
				/* rotate the nodes from b to u*/
				p = b;
				q = a;
				x = b->length;
				while (p->left->marked == YES || p->right->marked == YES)
					{					
					if (p->left->marked == YES) 
						{
						/* rotate p anticlockwise - prepare pointers for move left */
						p->anc = p->left;  /* the root will be in the direction we are heading */
						p->left = p->right;
						p->right = q;
						}
					else 
						{
						/* rotate p clockwise - prepare pointers for move right */
						p->anc = p->right;	/* the root will be in the direction we are heading */
						p->right = p->left;
						p->left = q;  
						}
					/* OK - let's move!; p->anc points in the right direction
					don't forget to move the branch lengths as well */
					q = p;
					p = p->anc;
					q->length = p->length;
					q->upDateTi = YES;
					}
				/* rotations finished, take care of u */
				if (u->left == v)
					u->left = u->anc;
				else
					u->right = u->anc;
				u->length = x;
				/* now swap the subtrees of u and b */
				if (a->left == b)
					a->left = u;
				else
					a->right = u;
				u->anc = a;
				v->anc = b;
				if (b->left == a)
					b->left = v;
				else
					b->right = v;
				}
			}
		}

	/* move around and potentially swap in crown subtree */
	nCrownNodes = 0;
	if (moveInRoot == NO)		
		{
		x = v->length;	/* save v length in case there is a move */
		for (nCrownNodes=0; nCrownNodes==0 || RandomNumber(seed)<extensionProb; nCrownNodes++) 
			{
			if (c->left == NULL || c->isLocked == YES)
				break;	/* can't go further */

			topologyHasChanged = YES;
			
			/* prepare d for move */
			d->anc = c;
			d->length = c->length;
			d->upDateTi = YES;
			d->upDateCl = YES;
			if (d->isLocked == YES)
				{
				c->isLocked = YES;
				d->isLocked = NO;
				c->lockID = d->lockID;
				d->lockID = -1;
				}
			
			/* go left or right with equal probability */
			if (RandomNumber(seed) < 0.5) 
				{
				/* rotate c anticlockwise - prepare pointers for move left */
				c->anc = c->left;  /* the root will be in the direction we are heading */
				c->left = c->right;
				c->right = d;
				}
			else 
				{
				/* rotate c clockwise - prepare pointers for move right */
				c->anc = c->right;	/* the root will be in the direction we are heading */
				c->right = c->left;
				c->left = d;
				}
			/* OK - let's move!; c->anc points in the right direction */
			d = c;
			c = c->anc;
			}

		/* swap the crown subtrees */
		if (nCrownNodes > 0)
			{
			d->anc = u;
			d->length = x;
			if (u->left == v)
				u->left = d;
			else
				u->right = d;

			c->anc = v;
			if (directionLeft == YES)
				v->left = c;
			else
				v->right = c;
			}
		}

	/* modify branch lengths */
	if (nCrownNodes > 0)
		{
		p = c;
		q = d;
		}
	else if (nRootNodes > 0)
		{
		if (directionUp == YES)
			{
			p = v;
			q = a;
			}
		else
			{
			p = v;
			q = u;
			}
		}
	else
		{
		p = v;
		if (RandomNumber(seed) < 0.5)
			{
			if (RandomNumber(seed) < 0.5)
				q = u;
			else
				{
				if (u->left == v)
					q = u->right;
				else
					q = u->left;
				}
			}
		else
			{
			if (RandomNumber(seed) < 0.5)
				q = v->left;
			else
				q = v->right;
			}
		}

	if (p != NULL)
		{
		m = p->length;
		x = m * exp(tuning * (RandomNumber(seed) - 0.5));
		while (x < minV || x > maxV)
			{
			if (x < minV)
				x = minV * minV / x;
			else if (x > maxV)
				x = maxV * maxV / x;
			}
		p->length = x;
		p->upDateTi = YES;

		/* update proposal and prior ratio based on length modification */
		(*lnProposalRatio) += log (x / m);
		if (isVPriorExp == YES)
			(*lnPriorRatio) += brlensExp * (m - x);
		}

	if (q != NULL && q->anc != NULL)
		{
		m = q->length;
		x = m * exp(tuning * (RandomNumber(seed) - 0.5));
		while (x < minV || x > maxV)
			{
			if (x < minV)
				x = minV * minV / x;
			else if (x > maxV)
				x = maxV * maxV / x;
			}
		q->length = x;
		q->upDateTi = YES;

		/* update proposal and prior ratio based on length modification */
		(*lnProposalRatio) += log (x / m);
		if (isVPriorExp == YES)
			(*lnPriorRatio) += brlensExp * (m - x);
		}

	/* set flags for update of cond likes from v and down to root */
	p = v;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	if (topologyHasChanged == YES)
		{
		/* set flags for update of cond likes from u and down to root */
		p = u;
		while (p->anc != NULL)
			{
			p->upDateCl = YES;
			p = p->anc;
			}
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}

#	if defined (DEBUG_ExtSS)
	printf ("After:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
	printf ("Proposal ratio: %f\n",exp(*lnProposalRatio));
	printf ("v: %d  u: %d  c: %d  d: %d  a: %d  b: %d\n",v->index, u->index, 
		c->index, d->index, a->index, b->index);
	printf ("No. nodes moved in root subtree: %d\n",nRootNodes);
	printf ("No. nodes moved in crown subtree: %d\n",nCrownNodes);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	printf ("directionUp = %d -- directionLeft = %d\n", directionUp, directionLeft);
	getchar();
#	endif

	return (NO_ERROR);
	
}





int Move_ExtSSClock (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* Change branch lengths and topology (potentially) using SS-type move 
	   with extension probability (rather than window, attachment rate or similar). */

	/* This move picks a branch at random. It then moves away from this branch, one 
	   one node at a time, with a probability determined by the extensionProb parameter.
       The process stops when a tip is reached or when a move further upwards would break
       the clock assumption. When the extension process stops, the subtrees supported by
       the two chosen branches are swapped. Since 2010-11-01, the move is Metropolized for
       increased efficiency. */
	
	int		    i, *nEvents, numFreeOld, numFreeNew;
	MrBFlt		x, oldALength, oldCLength, extensionProb, igrvar, *igrRate,
			    lambda, *tk02Rate, *brlens, nu, ran, cumulativeProb, forwardProb,
                backwardProb, minV, maxV, minB, maxB;
    TreeNode	*p, *q, *a, *c;
	Tree		*t;
	ModelParams *mp;
	ModelInfo	*m;
	Param		*subParm;

    extensionProb = mvp[0];	/* extension probability */

	(*lnProposalRatio) = (*lnPriorRatio) = 0.0;

	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* get model params and model info */
	mp = &modelParams[param->relParts[0]];
	m = &modelSettings[param->relParts[0]];
	
    /* get min and max brlens in relative time and subst units */
    minV = BRLENS_MIN;
    maxV = BRLENS_MAX;
    minB = RELBRLENS_MIN;
    maxB = RELBRLENS_MAX;

    /* calculate the number of free nodes */
    numFreeOld = t->nNodes-2;
    if (t->nConstraints > 1)
        {
        numFreeOld = 0;
        for (i=0; i<t->nNodes-2; i++)
            {
    		p = t->allDownPass[i];
            if (p->anc->left == p)
                q = p->anc->right;
            else
                q = p->anc->left;
            if (p->anc->isLocked == NO || q->isLocked == NO)
                numFreeOld++;
            }
        }

    /* pick a branch */
	do
		{
		p = t->allDownPass[(int)(RandomNumber(seed)*(t->nNodes - 2))];
        if (p->anc->left == p)
            q = p->anc->right;
        else
            q = p->anc->left;
		} while (p->anc->isLocked == YES && q->isLocked == YES);    /* choose subtree that can be swapped */

	/* set up pointers for nodes around the picked branch */
	a = p;
    if (p->anc->left == p)
        q = p->anc->right;
    else
        q = p->anc->left;
    if (p->anc->anc->left == p->anc)
        c = p->anc->anc->right;
    else
        c = p->anc->anc->left;

	/* record branch length */
	oldALength = a->length;

    /* reset scratch variables */
    for (i=0; i<t->nNodes-1; i++)
        {
        p = t->allDownPass[i];
        p->x = -1;
        p->y = NO;
        }

    /* calculate distance from picked node */
    p = a->anc;
    p->x = 0;
    while (p->isLocked == NO && p->anc != NULL)
        {
        p->anc->x = p->x + 1;
        p = p->anc;
        }
    for (i=t->nIntNodes-2; i>=0; i--)
        {
        p = t->intDownPass[i];
        if (p->x < 0 && p->anc->x >= 0 && p != a && p->isLocked == NO)
            p->x = p->anc->x + 1;
        }

    /* mark the free nodes and calculate the total score */
    cumulativeProb = 0.0; 
    for (i=0; i<t->nNodes-2; i++)
        {
        p = t->allDownPass[i];
        if (p != a && p->anc->x > 0 && a->anc->nodeDepth > p->nodeDepth + minV && p->anc->nodeDepth > a->nodeDepth + minV)
            {
            p->y = YES;
            p->d = pow(0.5 * extensionProb, p->anc->x);
            cumulativeProb += p->d;
            }
        else
            p->d = 0.0;
        }

    /* find the target node */
    ran = RandomNumber(seed) * cumulativeProb;
    x = 0.0;
    for (i=0; i<t->nNodes-2; i++)
        {
        p = t->allDownPass[i];
        if (p->y == YES)
            {
            x += p->d;
            if (x > ran)
                break;
            }
        }
    if (i == t->nNodes - 2)
        {
        abortMove = YES;
        return (NO_ERROR);
        }

    /* record first forward prob */
    forwardProb = p->d / cumulativeProb;

    /* record partner swap branch */
    c = p;
    oldCLength = c->length;

    /* calculate second forward prob */

    /* reset scratch variables */
    for (i=0; i<t->nNodes-1; i++)
        {
        p = t->allDownPass[i];
        p->x = -1;
        p->y = NO;
        }

    /* calculate distance from picked node */
    p = c->anc;
    p->x = 0;
    while (p->isLocked == NO && p->anc != NULL)
        {
        p->anc->x = p->x + 1;
        p = p->anc;
        }
    for (i=t->nIntNodes-1; i>=0; i--)
        {
        p = t->intDownPass[i];
        if (p->x < 0 && p != c && p->anc->x >= 0 && p->isLocked == NO)
            p->x = p->anc->x + 1;
        }

    /* mark the free nodes and calculate the total score */
    cumulativeProb = 0.0; 
    for (i=0; i<t->nNodes-2; i++)
        {
        p = t->allDownPass[i];
        if (p != c && p->anc->x > 0 && c->anc->nodeDepth > p->nodeDepth + minV && p->anc->nodeDepth > c->nodeDepth + minV)
            {
            p->y = YES;
            p->d = pow(0.5 * extensionProb, p->anc->x);
            cumulativeProb += p->d;
            }
        else
            p->d = 0.0;
        }

    /* now we can calculate second forward prob */
    forwardProb += a->d / cumulativeProb;

    /* swap subtrees */
	if (a->anc->left == a)
		a->anc->left = c;
	else
		a->anc->right = c;
	if (c->anc->left == c)
        c->anc->left = a;
    else
        c->anc->right = a;
    p = a->anc;
    a->anc = c->anc;
    c->anc = p;
    a->length = a->anc->nodeDepth - a->nodeDepth;
    c->length = c->anc->nodeDepth - c->nodeDepth;

	/* get down pass sequence */
	GetDownPass (t);

    /* set tiprobs update flags */
	a->upDateTi = YES;
	c->upDateTi = YES;

	/* set flags for update of cond likes from a->anc and down to root */
	p = a->anc;
	while (p->anc != NULL)
		{
		p->upDateCl = YES; 
		p = p->anc;
		}

	/* set flags for update of cond likes from c->anc and down to root */
	p = c->anc;
	while (p->anc != NULL)
		{
		p->upDateCl = YES; 
		p = p->anc;
		}

	/* adjust prior ratio for clock tree */
	if (LogClockTreePriorRatio(param, chain, &x) == ERROR)
        return (ERROR);
    (*lnPriorRatio) += x;

    /* calculate first backward prob */

    /* reset scratch variables */
    for (i=0; i<t->nNodes-1; i++)
        {
        p = t->allDownPass[i];
        p->x = -1;
        p->y = NO;
        }

    /* calculate distance from picked node */
    p = a->anc;
    p->x = 0;
    while (p->isLocked == NO && p->anc != NULL)
        {
        p->anc->x = p->x + 1;
        p = p->anc;
        }
    for (i=t->nIntNodes-1; i>=0; i--)
        {
        p = t->intDownPass[i];
        if (p->x < 0 && p != a && p->anc->x >= 0 && p->isLocked == NO)
            p->x = p->anc->x + 1;
        }

    /* mark the free nodes and calculate the total score */
    cumulativeProb = 0.0; 
    for (i=0; i<t->nNodes-2; i++)
        {
        p = t->allDownPass[i];
        if (p != a && p->anc->x > 0 && a->anc->nodeDepth > p->nodeDepth + minV && p->anc->nodeDepth > a->nodeDepth + minV)
            {
            p->y = YES;
            p->d = pow(0.5 * extensionProb, p->anc->x);
            cumulativeProb += p->d;
            }
        else
            p->d = 0.0;
        }

    /* calculate first backward prob */
    backwardProb = c->d / cumulativeProb;

    /* calculate second backward prob */

    /* reset scratch variables */
    for (i=0; i<t->nNodes-1; i++)
        {
        p = t->allDownPass[i];
        p->x = -1;
        p->y = NO;
        }

    /* calculate distance from picked node */
    p = c->anc;
    p->x = 0;
    while (p->isLocked == NO && p->anc != NULL)
        {
        p->anc->x = p->x + 1;
        p = p->anc;
        }
    for (i=t->nIntNodes-1; i>=0; i--)
        {
        p = t->intDownPass[i];
        if (p->x < 0 && p != c && p->anc->x >= 0 && p->isLocked == NO)
            p->x = p->anc->x + 1;
        }

    /* mark the free nodes and calculate the total score */
    cumulativeProb = 0.0; 
    for (i=0; i<t->nNodes-2; i++)
        {
        p = t->allDownPass[i];
        if (p != c && p->anc->x > 0 && c->anc->nodeDepth > p->nodeDepth + minV && p->anc->nodeDepth > c->nodeDepth + minV)
            {
            p->y = YES;
            p->d = pow(0.5 * extensionProb, p->anc->x);
            cumulativeProb += p->d;
            }
        else
            p->d = 0.0;
        }

    /* calculate second backward prob */
    backwardProb += a->d / cumulativeProb;

    /* now we can calculate proposal ratio */
    (*lnProposalRatio) += log (backwardProb / forwardProb);

    /* adjust for number of free nodes */
    numFreeNew = t->nNodes-2;
    if (t->nConstraints > 1)
        {
        numFreeNew = 0;
        for (i=0; i<t->nNodes-2; i++)
            {
    		p = t->allDownPass[i];
            if (p->anc->left == p)
                q = p->anc->right;
            else
                q = p->anc->left;
            if (p->anc->isLocked == NO || q->isLocked == NO)
                numFreeNew++;
            }
        (*lnProposalRatio) += log(numFreeOld / numFreeNew);
        }

    /* adjust proposal and prior ratio for relaxed clock models */
	for (i=0; i<param->subParams[0]->nSubParams; i++)
        {
        subParm = param->subParams[0]->subParams[i];
        if (subParm->paramType == P_CPPEVENTS)
			{
			nEvents = subParm->nEvents[2*chain+state[chain]];
			lambda = *GetParamVals (modelSettings[subParm->relParts[0]].cppRate, chain, state[chain]);

            /* proposal ratio */
            (*lnProposalRatio) += nEvents[a->index] * log (a->length / oldALength);
		    (*lnProposalRatio) += nEvents[c->index] * log (c->length / oldCLength);

            /* prior ratio: no effect because tree length is the same */

            /* update effective evolutionary lengths */
            if (UpdateCppEvolLengths (subParm, a, chain) == ERROR || UpdateCppEvolLengths (subParm, c, chain) == ERROR)
                {
                abortMove = YES;
                return (NO_ERROR);
                }
			}
		else if (subParm->paramType == P_TK02BRANCHRATES)
			{
			nu = *GetParamVals (modelSettings[subParm->relParts[0]].tk02var, chain, state[chain]);
			tk02Rate = GetParamVals (subParm, chain, state[chain]);
			brlens = GetParamSubVals (subParm, chain, state[chain]);

            /* no proposal ratio effect */

            /* prior ratio and update of effective evolutionary lengths */
			(*lnPriorRatio) -= LnProbTK02LogNormal (tk02Rate[c->anc->index], nu*oldALength, tk02Rate[a->index]);
			(*lnPriorRatio) += LnProbTK02LogNormal (tk02Rate[a->anc->index], nu*a->length, tk02Rate[a->index]);
            (*lnPriorRatio) -= LnProbTK02LogNormal (tk02Rate[a->anc->index], nu*oldCLength, tk02Rate[c->index]);
		    (*lnPriorRatio) += LnProbTK02LogNormal (tk02Rate[c->anc->index], nu*c->length, tk02Rate[c->index]);
			brlens[a->index] = a->length * (tk02Rate[a->index] + tk02Rate[a->anc->index])/2.0;
			brlens[c->index] = c->length * (tk02Rate[c->index] + tk02Rate[c->anc->index])/2.0;
			}
		else if (subParm->paramType == P_IGRBRANCHLENS)
			{
            /* get relevant parameters */
            igrvar = *GetParamVals (modelSettings[subParm->relParts[0]].igrvar, chain, state[chain]);
            igrRate = GetParamVals (subParm, chain, state[chain]);
			brlens = GetParamSubVals (subParm, chain, state[chain]);

            /* adjust for prior (part 1) */
            (*lnPriorRatio) -= LnProbTruncGamma (oldALength/igrvar, 1.0/igrvar, brlens[a->index], minB, maxB);
            (*lnPriorRatio) -= LnProbTruncGamma (oldCLength/igrvar, 1.0/igrvar, brlens[c->index], minB, maxB);

            /* keep b lens constant, adjusting rates (one of many possibilities) */
            igrRate[a->index] = brlens[a->index] / a->length;
            igrRate[c->index] = brlens[c->index] / c->length;

            /* adjust for prior (part 2) */
            (*lnPriorRatio) += LnProbTruncGamma (a->length/igrvar, 1.0/igrvar, brlens[a->index], minB, maxB);
            (*lnPriorRatio) += LnProbTruncGamma (c->length/igrvar, 1.0/igrvar, brlens[c->index], minB, maxB);
            /*The following if (*lnPriorRatio != *lnPriorRatio) should be removed if LnProbTruncGamma() would be made more exact and would never return -infinity */
            if (*lnPriorRatio != *lnPriorRatio)
                {
                abortMove=YES;
                return (NO_ERROR);
                }
            }
		}
	
    assert(*lnPriorRatio == *lnPriorRatio);

    return (NO_ERROR);
	
}





int Move_ExtTBR (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* Change branch lengths and topology (potentially) using TBR (unrooted) 
	   with extension probability (rather than window). */

	/* this move type picks a branch and two "danglies", modifies their length
	   independently according to the method of Larget & Simon (1999: MBE); it then
	   moves the danglies away from their original position one node at a time with
	   a probability determined by the extensionProb parameter

	   when the danglies are moved, their direction is changed
	   this "reflection" is necessary to enable the back move

	   This move type has been tested on all combinations of rooted and unrooted,
	   constrained and unconstrained trees */
	
	int			i, j, topologyHasChanged, nCrownNodes, nRootNodes, directionLeft, directionUp, 
				isVPriorExp, alwaysMoveRoot, isCrownStartConstrained, isRootStartConstrained,
                isStopConstrained;
	MrBFlt		m, x, y, tuning, maxV, minV, extensionProb, brlensExp=0.0;
	TreeNode	*p, *a, *b, *c, *d, *u, *v;
	Tree		*t;
	ModelParams *mp;

	/* these parameters should be possible to set by user */
	extensionProb = mvp[0];	/* extension probability */
	tuning = mvp[1];        /* Larget & Simon's tuning parameter lambda */
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* max and min brlen */
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}

	topologyHasChanged = NO;

#	if defined (DEBUG_ExtTBR)
	printf ("Before:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
#	endif
	
	/* pick an internal branch */
	do
		{
		p = t->intDownPass[(int)(RandomNumber(seed)*t->nIntNodes-1)];
        if (p->anc->left == p)
            a = p->anc->right;
        else
            a = p->anc->left;
        i = j = 0;
        if (a->isLocked == YES || a->left == NULL)
            i++;
        if (p->anc->isLocked == YES || p->anc->anc->anc == NULL)
            i++;
        if (p->left->isLocked == YES || p->left->left == NULL)
            j++;
        if (p->right->isLocked == YES || p->right->left == NULL)
            j++;
		} while (i == 2 && j == 2);

    /* determine whether to move first step unconditionally in root or in crown */
    if (j == 2)
        alwaysMoveRoot = YES;
    else if (i == 2)
        alwaysMoveRoot = NO;
    else if (RandomNumber(seed) < 0.5)
        alwaysMoveRoot = YES;
    else
        alwaysMoveRoot = NO;

    /* determine any starting constraints */
    isCrownStartConstrained = isRootStartConstrained = NO;
    if (i >= 1)
        isRootStartConstrained = YES;
    if (j >= 1)
        isCrownStartConstrained = YES;

    /* set up pointers for nodes around the picked branch */
	/* cut the tree into crown, root and attachment part */
	/* change the relevant lengths in the attachment part */
	/* the lengths of a and v are automatically contained in the */
	/* "attachment" part but the length of c has to be stored in x */
	v = p;
	u = p->anc;

	/* set up pointers for crown part */
	/* also determine direction of move in crown part */
	if (v->right->left == NULL || v->right->isLocked == YES)
        directionLeft = YES;
    else if (v->left->left == NULL || v->left->isLocked == YES)
        directionLeft = NO;
    else if (RandomNumber(seed) < 0.5)
        directionLeft = YES;
    else
        directionLeft = NO;
    if (directionLeft == YES)
        {
		c = v->left;
		d = v->right;
		}
	else
		{
		c = v->right;
		d = v->left;
		}

	/* cut and reconnect crown part */
	c->anc = d;
	d->anc = c;
	
	/* record c length and adjust with multiplier using reflection */
	m = c->length;
	x = c->length * exp(tuning * (RandomNumber(seed) - 0.5));		/* save the modified dangling branch for later use */
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	
	/* calculate proposal and prior ratio based on length modification */
	(*lnProposalRatio) = log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) = brlensExp * (m - x);

	/* record v length and adjust with multiplier using reflection*/
	m = v->length;
	v->length *= exp(tuning * (RandomNumber(seed) - 0.5));
	while (v->length < minV || v->length > maxV)
		{
		if (v->length < minV)
			v->length = minV * minV / v->length;
		else if (v->length > maxV)
			v->length = maxV * maxV / v->length;
		}
	v->upDateTi = YES;

	/* adjust proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (v->length / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - v->length);

	/* mark nodes in root part */
	/* also determine direction of move in root part */
	if (u->left == v)
		a = u->right;
	else
		a = u->left;
	b = u->anc;
	if (u->anc->anc == NULL || u->isLocked == YES)
        directionUp = YES;
    else if (a->left == NULL || a->isLocked == YES)
        directionUp = NO;
    else if (RandomNumber(seed) < 0.5)
		directionUp = YES;
	else
        directionUp = NO;
    if (directionUp == NO)
        {
        /* switch a and b */
        b = a;
		a = u->anc;
		}

	/* cut root part */
	/* store branch to be modified in u->length */
	if (directionUp == NO) 
		{
		b->anc = a;
		if (a->left == u)
			a->left = b;
		else
			a->right = b;
		}
	else 
		{
		a->anc = b;
		if (b->left == u)
			b->left = a;
		else
			b->right = a;
		y = a->length;
		a->length = u->length;
		u->length = y;
		a->upDateTi = YES;
		}

	/* adjust length of branch to be modified */
	/* if it is not the root branch of a rooted tree */
	if (t->isRooted == NO || u->anc->anc != NULL) 
		{
		m = u->length;
		u->length *= exp(tuning * (RandomNumber(seed) - 0.5));
		while (u->length < minV || u->length > maxV)
			{
			if (u->length < minV)
				u->length = minV * minV / u->length;
			else if (u->length > maxV)
				u->length = maxV * maxV / u->length;
			}

		/* adjust proposal and prior ratio based on length modification */
		(*lnProposalRatio) += log (u->length / m);
		if (isVPriorExp == YES)
			(*lnPriorRatio) += brlensExp * (m - u->length);
		}
	u->upDateTi = YES;
		
	/* move around in root subtree */
	for (nRootNodes=0; (alwaysMoveRoot == YES && nRootNodes == 0) || RandomNumber(seed)<extensionProb; nRootNodes++) 
		{
		if (directionUp == YES) 
			{	/* going up tree */
			if (a->left == NULL || a->isLocked == YES)
				break;		/* can't go further */
			topologyHasChanged = YES;
			b = a;
			if (RandomNumber(seed) < 0.5)
				a = a->left;
			else
				a = a->right;
			if (u->isLocked == YES)
				{
				b->isLocked = YES;
				u->isLocked = NO;
				b->lockID = u->lockID;
				u->lockID = 0;
				}
			}
		else 
			{	/* going down tree */
			if (a->anc == NULL || u->isLocked == YES)
				break;		/* can't go further */
			topologyHasChanged = YES;
			if (RandomNumber(seed)<0.5) 
				{
				directionUp = YES; /* switch direction */
				/* find sister of a */
				if (a->left == b) 
					{
					b = a;
					a = a->right;
					}
				else 
					{  
					b = a;
					a = a->left;
					}
				/* as long as we are moving upwards
				the cond likes to update will be
				flagged by the last pass from u to the root */
				}	
			else 
				{	/* continue down */
				b = a;
				a = a->anc;
				b->upDateCl = YES; 
				if (b->isLocked == YES)
					{
					u->isLocked = YES;
					b->isLocked = NO;
					u->lockID = b->lockID;
					b->lockID = 0;
					}
				}
			}
		}

	/* adjust proposal ratio for root move if unbalanced */
	isStopConstrained = NO;
    if (directionUp == YES) 
		{
		if (a->left == NULL || a->isLocked == YES)
			isStopConstrained = YES;
		}
	else 
		{
		if (a->anc  == NULL || u->isLocked == YES)
			isStopConstrained = YES;
		}
    if (nRootNodes > 0)
        {
        if (isRootStartConstrained == YES && isStopConstrained == NO)
            (*lnProposalRatio) -= log (2.0 * (log(1.0 - extensionProb)));
        else if (isRootStartConstrained == NO && isStopConstrained == YES)
            (*lnProposalRatio) += log (2.0 * (log(1.0 - extensionProb)));
        }

	/* move around in crown subtree */
	for (nCrownNodes=0; (alwaysMoveRoot == NO && nCrownNodes == 0) || RandomNumber(seed)<extensionProb; nCrownNodes++) 
		{
		if (c->left == NULL || c->isLocked == YES)
			break;	/* can't go further */
		topologyHasChanged = YES;
		if (RandomNumber(seed) < 0.5) 
			{
			/* rotate c anticlockwise - prepare pointers for move left */
			c->anc = c->left;  /* the root will be in the direction we are heading */
			c->left = c->right;
			c->right = d;
			}
		else 
			{
			/* rotate c clockwise - prepare pointers for move right */
			c->anc = c->right;	/* the root will be in the direction we are heading */
			c->right = c->left;
			c->left = d;  
			}
		/* OK - let's move!; c->anc points in the right direction
		don't forget to move the branch lengths as well */
		d = c;
		c = c->anc;
		d->length = c->length;
		d->upDateCl = YES; 
		d->upDateTi = YES;
		}

	/* adjust proposal ratio for crown move if unbalanced */
    isStopConstrained = NO;
    if (c->left == NULL || c->isLocked == YES)
		isStopConstrained = YES;
    if (nCrownNodes > 0)
        {
        if (isCrownStartConstrained == YES && isStopConstrained == NO)
            (*lnProposalRatio) -= log (2.0 * (log(1.0 - extensionProb)));
        else if (isCrownStartConstrained == NO && isStopConstrained == YES)
            (*lnProposalRatio) += log (2.0 * (log(1.0 - extensionProb)));
        }

	/* combine the subtrees */
	c->anc = v;
	d->anc = v;
	if (directionLeft == YES) 
		{
		v->left = c;
		v->right = d;
		}
	else 
		{
		v->left = d;
		v->right = c;
		}

	/* the dangling branch is inserted in reverted position
	   such that the back move will be possible
	   if we have moved around in crown subtree
	   otherwise it is left in its original position */
	if (nCrownNodes > 0)
		{
		d->length = x;
		d->upDateTi = YES;
		}
	else
		{
		c->length = x;
		c->upDateTi = YES;
		}	

	if (directionUp == YES) 
		{
		u->anc = b;
		if (u->left == v)
			u->right = a;
		else 
			u->left = a;
		a->anc = u;
		if (b->left == a)
			b->left = u;
		else
			b->right = u;
		/* the dangling branch is contained in u->length
		   and will automatically be inserted in the right position
		   to enable the back move regardless of whether it was
		   initially directed upwards or downwards
		   BUT if we haven't moved in root subtree, it is advantageous (necessary
		   for rooted trees) to avoid switching branches, which occurs otherwise
		   if directionUp == YES */
		if (nRootNodes == 0) 
			{
			x = u->length;
			u->length = a->length;
			a->length = x;
			a->upDateTi = YES;
			u->upDateTi = NO;	/* u retains its old length */
			}
		}
	else 
		{
		u->anc = a;
		if (u->left == v)
			u->right = b;
		else 
			u->left = b;
		b->anc = u;
		if (a->left == b)
			a->left = u;
		else
			a->right = u;
		/* the modified branch contained in u->length will have
		   to be moved to b->length to enable back move
		   BUT if we haven't moved, it is better to keep it in place
		   (necessary for rooted trees) */
		if (nRootNodes > 0) 
			{
			x = u->length;
			u->length = b->length;
			b->length = x;
			b->upDateTi = YES;
			}
		}
		
	/* set flags for update of cond likes from v and down to root */
	p = v;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}

	/* flag whether topology has changed */
    if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

#	if defined (DEBUG_ExtTBR)
	printf ("After:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  c: %d  d: %d  a: %d  b: %d\n",v->index, u->index, 
		c->index, d->index, a->index, b->index);
	printf ("No. nodes moved in root subtree: %d\n",nRootNodes);
	printf ("No. nodes moved in crown subtree: %d\n",nCrownNodes);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

	gNodeMoves = nCrownNodes + nRootNodes;
#	endif

#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in output tree to eTBR\n");
		getchar();
		}
#endif

    assert (nCrownNodes > 0 || nRootNodes > 0);

	return (NO_ERROR);
	
}





int Move_ExtTBR1 (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* Change branch lengths and topology (potentially) using TBR (unrooted) 
	   with extension probability (rather than window). */

	/* this move type picks a branch and two "danglies", modifies their length
	   independently according to the method of Larget & Simon (1999: MBE); it then
	   moves the danglies away from their original position one node at a time with
	   a probability determined by the extensionProb parameter

	   when the danglies are moved, their direction is changed
	   this "reflection" is necessary to enable the back move

	   This move type has been tested on all combinations of rooted and unrooted,
	   constrained and unconstrained trees */
	
	int			topologyHasChanged, nCrownNodes, nRootNodes, directionLeft, directionUp, 
				isVPriorExp;
	MrBFlt		m, x, y, tuning, maxV, minV, extensionProb, brlensExp=0.0;
	TreeNode	*p, *a, *b, *c, *d, *u, *v, *brlenNode[7];
	Tree		*t;
	ModelParams *mp;

	/* these parameters should be possible to set by user */
	extensionProb = mvp[0];	/* extension probability */
	tuning = mvp[1];        /* Larget & Simon's tuning parameter lambda */
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);
#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in input tree to eTBR1\n");
		getchar();
		}
#endif

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* max and min brlen */
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}

	topologyHasChanged = NO;

#	if defined (DEBUG_ExtTBR)
	printf ("Before:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
#	endif
	
	/* pick an internal branch */
	do
		{
		p = t->intDownPass[(int)(RandomNumber(seed)*t->nIntNodes)];
		} while (p->anc->anc == NULL);
		
	/* set up pointers for nodes around the picked branch */
	/* cut the tree into crown, root and attachment part */
	/* change the relevant lengths in the attachment part */
	/* the lengths of a and v are automatically contained in the */
	/* "attachment" part but the length of c has to be stored in x */
	v = p;
	u = p->anc;

	/* store brlen node */
	brlenNode[3] = v;

	/* set up pointers for crown part */
	/* this also determines direction of move in crown part */
	if (RandomNumber(seed) < 0.5)
		{
		c = v->left;
		d = v->right;
		directionLeft = YES;
		}
	else
		{
		c = v->right;
		d = v->left;
		directionLeft = NO;
		}

	/* store brlen nodes and brlen to move */
	brlenNode[0] = d;
	brlenNode[1] = c;
	x = c->length;

	/* cut and reconnect crown part */
	c->anc = d;
	d->anc = c;
	
	/* mark nodes in root part */
	/* also determines direction of move in root part */
	if (RandomNumber(seed) < 0.5)
		{
		if (u->left == v)
			a = u->right;
		else
			a = u->left;
		b = u->anc;
		directionUp = YES;
		}
	else
		{
		if (u->left == v)
			b = u->right;
		else
			b = u->left;
		a = u->anc;
		directionUp = NO;
		}

	/* store brlen nodes */
	if (directionUp == YES)
		{
		brlenNode[4] = u;
		brlenNode[5] = a;
		}
	else
		{
		brlenNode[4] = b;
		brlenNode[5] = u;
		}

	/* cut root part*/
	/* store branch to move in u->length */
	if (directionUp == NO) 
		{
		b->anc = a;
		if (a->left == u)
			a->left = b;
		else
			a->right = b;
		}
	else 
		{
		a->anc = b;
		if (b->left == u)
			b->left = a;
		else
			b->right = a;
		y = a->length;
		a->length = u->length;
		u->length = y;
		a->upDateTi = YES;
		u->upDateTi = YES;
		}

	/* adjust proposal ratio for backward move in root subtree
	   if starting from interior, unconstrained branch
	   double test needed to capture the case of no move */
	if (directionUp == NO)
		{
		if (b->left != NULL && b->isLocked == NO &&
			a->anc  != NULL && u->isLocked == NO)
			(*lnProposalRatio) += log(1.0 - extensionProb);
		}
	else
		{
		if (a->left != NULL && a->isLocked == NO &&
			b->anc  != NULL && b->isLocked == NO)
			(*lnProposalRatio) += log(1.0 - extensionProb);
		}

	/* adjust proposal ratio for backward move in crown subtree
	   if starting from interior, unconstrained branch
	   double test is needed to capture the case of no move */
	if (c->left != NULL && c->isLocked == NO && 
		d->left != NULL && d->isLocked == NO)
		(*lnProposalRatio) += log(1.0 - extensionProb);

	/* move around in root subtree */
	for (nRootNodes=0; RandomNumber(seed)<extensionProb; nRootNodes++) 
		{
		if (directionUp == YES) 
			{	/* going up tree */
			if (a->left == NULL || a->isLocked == YES)
				break;		/* can't go further */
			topologyHasChanged = YES;
			b = a;
			if (RandomNumber(seed) < 0.5)
				a = a->left;
			else
				a = a->right;
			if (u->isLocked == YES)
				{
				b->isLocked = YES;
				u->isLocked = NO;
				b->lockID = u->lockID;
				u->lockID = 0;
				}
			}
		else 
			{	/* going down tree */
			if (a->anc == NULL || u->isLocked == YES)
				break;		/* can't go further */
			topologyHasChanged = YES;
			if (RandomNumber(seed)<0.5) 
				{
				directionUp = YES; /* switch direction */
				/* find sister of a */
				if (a->left == b) 
					{
					b = a;
					a = a->right;
					}
				else 
					{  
					b = a;
					a = a->left;
					}
				/* as long as we are moving upwards
				the cond likes to update will be
				flagged by the last pass from u to the root */
				}	
			else 
				{	/* continue down */
				b = a;
				a = a->anc;
				b->upDateCl = YES; 
				if (b->isLocked == YES)
					{
					u->isLocked = YES;
					b->isLocked = NO;
					u->lockID = b->lockID;
					b->lockID = 0;
					}
				}
			}
		}

	/* store brlen nodes */
	if (nRootNodes > 0)
		{
		if (directionUp == YES)
			{
			brlenNode[6] = a;
			brlenNode[5] = u;
			}
		else
			{
			brlenNode[6] = u;
			brlenNode[5] = b;
			}
		}

	/* adjust proposal ratio for forward move if stop branch is interior & unconstrained
	   test of both ends makes sure that no adjustment is made if no move was made */
	if (directionUp == YES) 
		{
		if (a->left != NULL && a->isLocked == NO &&
			b->anc  != NULL && b->isLocked == NO) 
			(*lnProposalRatio) -= log(1.0 - extensionProb);
		}
	else 
		{
		if (a->anc  != NULL && u->isLocked == NO &&
			b->left != NULL && b->isLocked == NO)
			(*lnProposalRatio) -= log(1.0 - extensionProb);
		}

	/* move around in crown subtree */
	for (nCrownNodes=0; RandomNumber(seed)<extensionProb; nCrownNodes++) 
		{
		if (c->left == NULL || c->isLocked == YES)
			break;	/* can't go further */
		topologyHasChanged = YES;
		if (RandomNumber(seed) < 0.5) 
			{
			/* rotate c anticlockwise - prepare pointers for move left */
			c->anc = c->left;  /* the root will be in the direction we are heading */
			c->left = c->right;
			c->right = d;
			}
		else 
			{
			/* rotate c clockwise - prepare pointers for move right */
			c->anc = c->right;	/* the root will be in the direction we are heading */
			c->right = c->left;
			c->left = d;  
			}
		/* OK - let's move!; c->anc points in the right direction
		don't forget to move the branch lengths as well */
		d = c;
		c = c->anc;
		d->length = c->length;
		d->upDateCl = YES; 
		d->upDateTi = YES;
		}

	/* store brlen nodes */
	if (nCrownNodes > 0)
		{
		brlenNode[2] = c;
		brlenNode[1] = d;
		}

	/* adjust proposal ratio for forward move if stop branch is interior & unconstrained
	   double test makes sure that no adjustment is made if no move was made */
	if (c->left != NULL && c->isLocked == NO &&
		d->left != NULL && d->isLocked == NO)
		(*lnProposalRatio) -= log(1.0 - extensionProb);

	/* combine the subtrees */
	c->anc = v;
	d->anc = v;
	if (directionLeft == YES) 
		{
		v->left = c;
		v->right = d;
		}
	else 
		{
		v->left = d;
		v->right = c;
		}

	/* the dangling branch is inserted in reverted position
	   such that the back move will be possible
	   if we have moved around in crown subtree
	   otherwise it is left in its original position */
	if (nCrownNodes > 0)
		{
		d->length = x;
		d->upDateTi = YES;
		}
	else
		{
		c->length = x;
		}	

	if (directionUp == YES) 
		{
		u->anc = b;
		if (u->left == v)
			u->right = a;
		else 
			u->left = a;
		a->anc = u;
		if (b->left == a)
			b->left = u;
		else
			b->right = u;
		/* the dangling branch is contained in u->length
		   and will automatically be inserted in the right position
		   to enable the back move regardless of whether it was
		   initially directed upwards or downwards
		   BUT if we haven't moved in root subtree, it is advantageous (necessary
		   for rooted trees) to avoid switching branches, which occurs otherwise
		   if directionUp == YES */
		if (nRootNodes == 0) 
			{
			x = u->length;
			u->length = a->length;
			a->length = x;
			a->upDateTi = NO;
			u->upDateTi = NO;
			}
		}
	else 
		{
		u->anc = a;
		if (u->left == v)
			u->right = b;
		else 
			u->left = b;
		b->anc = u;
		if (a->left == b)
			a->left = u;
		else
			a->right = u;
		/* the modified branch contained in u->length will have
		   to be moved to b->length to enable back move
		   BUT if we haven't moved, it is better to keep it in place
		   (necessary for rooted trees) */
		if (nRootNodes > 0) 
			{
			x = u->length;
			u->length = b->length;
			b->length = x;
			b->upDateTi = YES;
			u->upDateTi = YES;
			}
		}
	
	/* modify branch lengths */
	/* first modify length of middle branch */
	m = brlenNode[3]->length;
	x = m * exp(tuning * (RandomNumber(seed) - 0.5));		/* save the modified dangling branch for later use */
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	brlenNode[3]->length = x;
	brlenNode[3]->upDateTi = YES;

	/* update proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - x);

	/* if no move in crown, then select randomly, otherwise always the moved branch */
	if (nCrownNodes == 0 && RandomNumber (seed) < 0.5)
		p = brlenNode[0];
	else
		p = brlenNode[1];

	/* modify branch length */
	m = p->length;
	x = m * exp(tuning * (RandomNumber(seed) - 0.5));
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	p->length = x;
	p->upDateTi = YES;

	/* update proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - x);	
		
	/* if no move in root, then select randomly, otherwise always the moved branch;
	   note that the code above does not give reliable brlenNode[4] pointer when initial
	   direction of move in root tree is UP and there has been some move in the root tree
	   -- this is unimportant for this move but IS important for other TBR moves */
	if (nRootNodes == 0 && RandomNumber(seed) < 0.5)
		p = brlenNode[4];
	else
		p = brlenNode[5];

	/* modify branch length but not if 'root' branch in rooted tree */
	if (t->isRooted == NO || p->anc->anc != NULL)
		{
		m = p->length;
		x = m * exp(tuning * (RandomNumber(seed) - 0.5));
		while (x < minV || x > maxV)
			{
			if (x < minV)
				x = minV * minV / x;
			else if (x > maxV)
				x = maxV * maxV / x;
			}
		p->length = x;
		p->upDateTi = YES;

		/* update proposal and prior ratio based on length modification */
		(*lnProposalRatio) += log (x / m);
		if (isVPriorExp == YES)
			(*lnPriorRatio) += brlensExp * (m - x);	
		}

	/* set flags for update of cond likes from v and down to root */
	p = v;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}

#	if defined (DEBUG_ExtTBR)
	printf ("After:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  c: %d  d: %d  a: %d  b: %d\n",v->index, u->index, 
		c->index, d->index, a->index, b->index);
	printf ("No. nodes moved in root subtree: %d\n",nRootNodes);
	printf ("No. nodes moved in crown subtree: %d\n",nCrownNodes);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

	gNodeMoves = nCrownNodes + nRootNodes;
#	endif

#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in output tree to eTBR1\n");
		getchar();
		}
#endif

	return (NO_ERROR);
	
}





int Move_ExtTBR2 (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* Change branch lengths and topology (potentially) using TBR (unrooted) 
	   with extension probability (rather than window). */

	/* this move type picks a branch and two "danglies", modifies their length
	   independently according to the method of Larget & Simon (1999: MBE); it then
	   moves the danglies away from their original position one node at a time with
	   a probability determined by the extensionProb parameter

	   when the danglies are moved, their direction is changed
	   this "reflection" is necessary to enable the back move

	   This move type has been tested on all combinations of rooted and unrooted,
	   constrained and unconstrained trees */
	
	int			topologyHasChanged, nCrownNodes, nRootNodes, directionLeft, directionUp, 
				isVPriorExp;
	MrBFlt		m, x, y, tuning, maxV, minV, extensionProb, brlensExp=0.0;
	TreeNode	*p, *a, *b, *c, *d, *u, *v, *brlenNode[7];
	Tree		*t;
	ModelParams *mp;

	memset(brlenNode, 0, sizeof(TreeNode *)*7);

	/* these parameters should be possible to set by user */
	extensionProb = mvp[0];	/* extension probability */
	tuning = mvp[1];        /* Larget & Simon's tuning parameter lambda */
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);
#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in input tree to eTBR2\n");
		getchar();
		}
#endif

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* max and min brlen */
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}

	topologyHasChanged = NO;

#	if defined (DEBUG_ExtTBR)
	printf ("Before:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
#	endif
	
	/* pick an internal branch */
	do
		{
		p = t->intDownPass[(int)(RandomNumber(seed)*t->nIntNodes)];
		} while (p->anc->anc == NULL);
		
	/* set up pointers for nodes around the picked branch */
	/* cut the tree into crown, root and attachment part */
	/* change the relevant lengths in the attachment part */
	/* the lengths of a and v are automatically contained in the */
	/* "attachment" part but the length of c has to be stored in x */
	v = p;
	u = p->anc;

	/* store brlen node */
	brlenNode[3] = v;

	/* set up pointers for crown part */
	/* this also determines direction of move in crown part */
	if (RandomNumber(seed) < 0.5)
		{
		c = v->left;
		d = v->right;
		directionLeft = YES;
		}
	else
		{
		c = v->right;
		d = v->left;
		directionLeft = NO;
		}

	/* store brlen nodes and brlen to move */
	brlenNode[0] = d;
	brlenNode[1] = c;
	x = c->length;

	/* cut and reconnect crown part */
	c->anc = d;
	d->anc = c;
	
	/* mark nodes in root part */
	/* also determines direction of move in root part */
	if (RandomNumber(seed) < 0.5)
		{
		if (u->left == v)
			a = u->right;
		else
			a = u->left;
		b = u->anc;
		directionUp = YES;
		}
	else
		{
		if (u->left == v)
			b = u->right;
		else
			b = u->left;
		a = u->anc;
		directionUp = NO;
		}

	/* store brlen nodes */
	if (directionUp == YES)
		{
		brlenNode[4] = u;
		brlenNode[5] = a;
		}
	else
		{
		brlenNode[4] = b;
		brlenNode[5] = u;
		}

	/* cut root part*/
	/* store branch to be move in u->length */
	if (directionUp == NO) 
		{
		b->anc = a;
		if (a->left == u)
			a->left = b;
		else
			a->right = b;
		}
	else 
		{
		a->anc = b;
		if (b->left == u)
			b->left = a;
		else
			b->right = a;
		y = a->length;
		a->length = u->length;
		u->length = y;
		a->upDateTi = YES;
		u->upDateTi = YES;
		}

	/* adjust proposal ratio for backward move in root subtree
	   if starting from interior, unconstrained branch
	   double test needed to capture the case of no move */
	if (directionUp == NO)
		{
		if (b->left != NULL && b->isLocked == NO &&
			a->anc  != NULL && u->isLocked == NO)
			(*lnProposalRatio) += log(1.0 - extensionProb);
		}
	else
		{
		if (a->left != NULL && a->isLocked == NO &&
			b->anc  != NULL && b->isLocked == NO)
			(*lnProposalRatio) += log(1.0 - extensionProb);
		}

	/* adjust proposal ratio for backward move in crown subtree
	   if starting from interior, unconstrained branch
	   double test is needed to capture the case of no move */
	if (c->left != NULL && c->isLocked == NO && 
		d->left != NULL && d->isLocked == NO)
		(*lnProposalRatio) += log(1.0 - extensionProb);

	/* move around in root subtree */
	for (nRootNodes=0; RandomNumber(seed)<extensionProb; nRootNodes++) 
		{
		if (directionUp == YES) 
			{	/* going up tree */
			if (a->left == NULL || a->isLocked == YES)
				break;		/* can't go further */
			topologyHasChanged = YES;
			b = a;
			if (RandomNumber(seed) < 0.5)
				a = a->left;
			else
				a = a->right;
			if (u->isLocked == YES)
				{
				b->isLocked = YES;
				u->isLocked = NO;
				b->lockID = u->lockID;
				u->lockID = 0;
				}
			}
		else 
			{	/* going down tree */
			if (a->anc == NULL || u->isLocked == YES)
				break;		/* can't go further */
			topologyHasChanged = YES;
			if (RandomNumber(seed)<0.5) 
				{
				directionUp = YES; /* switch direction */
				/* find sister of a */
				if (a->left == b) 
					{
					b = a;
					a = a->right;
					}
				else 
					{  
					b = a;
					a = a->left;
					}
				/* as long as we are moving upwards
				the cond likes to update will be
				flagged by the last pass from u to the root */
				}	
			else 
				{	/* continue down */
				b = a;
				a = a->anc;
				b->upDateCl = YES; 
				if (b->isLocked == YES)
					{
					u->isLocked = YES;
					b->isLocked = NO;
					u->lockID = b->lockID;
					b->lockID = 0;
					}
				}
			}
		}

	/* store brlen nodes */
	if (nRootNodes > 0)
		{
		if (directionUp == YES)
			{
			brlenNode[6] = a;
			brlenNode[5] = u;
			}
		else
			{
			brlenNode[6] = u;
			brlenNode[5] = b;
			}
		}

	/* adjust proposal ratio for forward move if stop branch is interior & unconstrained
	   test of both ends makes sure that no adjustment is made if no move was made */
	if (directionUp == YES) 
		{
		if (a->left != NULL && a->isLocked == NO &&
			b->anc  != NULL && b->isLocked == NO) 
			(*lnProposalRatio) -= log(1.0 - extensionProb);
		}
	else 
		{
		if (a->anc  != NULL && u->isLocked == NO &&
			b->left != NULL && b->isLocked == NO)
			(*lnProposalRatio) -= log(1.0 - extensionProb);
		}

	/* move around in crown subtree */
	for (nCrownNodes=0; RandomNumber(seed)<extensionProb; nCrownNodes++) 
		{
		if (c->left == NULL || c->isLocked == YES)
			break;	/* can't go further */
		topologyHasChanged = YES;
		if (RandomNumber(seed) < 0.5) 
			{
			/* rotate c anticlockwise - prepare pointers for move left */
			c->anc = c->left;  /* the root will be in the direction we are heading */
			c->left = c->right;
			c->right = d;
			}
		else 
			{
			/* rotate c clockwise - prepare pointers for move right */
			c->anc = c->right;	/* the root will be in the direction we are heading */
			c->right = c->left;
			c->left = d;  
			}
		/* OK - let's move!; c->anc points in the right direction
		don't forget to move the branch lengths as well */
		d = c;
		c = c->anc;
		d->length = c->length;
		d->upDateCl = YES; 
		d->upDateTi = YES;
		}

	/* store brlen nodes */
	if (nCrownNodes > 0)
		{
		brlenNode[2] = c;
		brlenNode[1] = d;
		}

	/* adjust proposal ratio for forward move if stop branch is interior & unconstrained
	   double test makes sure that no adjustment is made if no move was made */
	if (c->left != NULL && c->isLocked == NO &&
		d->left != NULL && d->isLocked == NO)
		(*lnProposalRatio) -= log(1.0 - extensionProb);

	/* combine the subtrees */
	c->anc = v;
	d->anc = v;
	if (directionLeft == YES) 
		{
		v->left = c;
		v->right = d;
		}
	else 
		{
		v->left = d;
		v->right = c;
		}

	/* the dangling branch is inserted in reverted position
	   such that the back move will be possible
	   if we have moved around in crown subtree
	   otherwise it is left in its original position */
	if (nCrownNodes > 0)
		{
		d->length = x;
		d->upDateTi = YES;
		}
	else
		{
		c->length = x;
		}	

	if (directionUp == YES) 
		{
		u->anc = b;
		if (u->left == v)
			u->right = a;
		else 
			u->left = a;
		a->anc = u;
		if (b->left == a)
			b->left = u;
		else
			b->right = u;
		/* the dangling branch is contained in u->length
		   and will automatically be inserted in the right position
		   to enable the back move regardless of whether it was
		   initially directed upwards or downwards
		   BUT if we haven't moved in root subtree, it is advantageous (necessary
		   for rooted trees) to avoid switching branches, which occurs otherwise
		   if directionUp == YES */
		if (nRootNodes == 0) 
			{
			x = u->length;
			u->length = a->length;
			a->length = x;
			a->upDateTi = NO;
			u->upDateTi = NO;
			}
		}
	else 
		{
		u->anc = a;
		if (u->left == v)
			u->right = b;
		else 
			u->left = b;
		b->anc = u;
		if (a->left == b)
			a->left = u;
		else
			a->right = u;
		/* the modified branch contained in u->length will have
		   to be moved to b->length to enable back move
		   BUT if we haven't moved, it is better to keep it in place
		   (necessary for rooted trees) */
		if (nRootNodes > 0) 
			{
			x = u->length;
			u->length = b->length;
			b->length = x;
			b->upDateTi = YES;
			u->upDateTi = YES;
			}
		}
	
	/* modify branch lengths */
	/* first modify length of middle branch */
	m = brlenNode[3]->length;
	x = m * exp(tuning * (RandomNumber(seed) - 0.5));		/* save the modified dangling branch for later use */
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	brlenNode[3]->length = x;
	brlenNode[3]->upDateTi = YES;

	/* update proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - x);

	/* if no move in crown, then select randomly, otherwise always the moved branch */
	if (nCrownNodes == 0)
		{
		if (RandomNumber (seed) < 0.5)
			p = brlenNode[0];
		else
			p = brlenNode[1];
		}
	else
		{
		/* swap starting branches */
		if (RandomNumber (seed) < 0.5)
			{
			x = brlenNode[0]->length;
			brlenNode[0]->length = brlenNode[1]->length;
			brlenNode[1]->length = x;
			brlenNode[0]->upDateTi = YES;
			}
		/* swap ending branches */
		if (RandomNumber (seed) < 0.5)
			{
			x = brlenNode[1]->length;
			brlenNode[1]->length = brlenNode[2]->length;
			brlenNode[2]->length = x;
			brlenNode[2]->upDateTi = YES;
			brlenNode[1]->upDateTi = YES;
			p = brlenNode[2];
			}
		else
			p = brlenNode[1];
		}

	/* modify branch length */
	m = p->length;
	x = m * exp(tuning * (RandomNumber(seed) - 0.5));
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	p->length = x;
	p->upDateTi = YES;

	/* update proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - x);	
		
	/* if no move in root, then select randomly, otherwise always the moved branch */
	if (nRootNodes == 0)
		{
		if (RandomNumber(seed) < 0.5)
			p = brlenNode[4];
		else
			p = brlenNode[5];
		}
	else
		{
		/* swap starting branches */
		if (RandomNumber(seed) < 0.5 && (t->isRooted == NO || brlenNode[4]->anc->anc != NULL))
			{
			x = brlenNode[4]->length;
			brlenNode[4]->length = brlenNode[5]->length;
			brlenNode[5]->length = x;
			brlenNode[4]->upDateTi = YES;			
			}
		/* swap ending branches */
		if (RandomNumber(seed) < 0.5 && (t->isRooted == NO || brlenNode[6]->anc->anc != NULL))
			{
			x = brlenNode[5]->length;
			brlenNode[5]->length = brlenNode[6]->length;
			brlenNode[5]->length = x;
			brlenNode[5]->upDateTi = YES;
			brlenNode[6]->upDateTi = YES;
			p = brlenNode[6];
			}
		else
			p = brlenNode[5];
		}
	
	/* modify branch length but not if 'root' branch in rooted tree */
	if (t->isRooted == NO || p->anc->anc != NULL)
		{
		m = p->length;
		x = m * exp(tuning * (RandomNumber(seed) - 0.5));
		while (x < minV || x > maxV)
			{
			if (x < minV)
				x = minV * minV / x;
			else if (x > maxV)
				x = maxV * maxV / x;
			}
		p->length = x;
		p->upDateTi = YES;

		/* update proposal and prior ratio based on length modification */
		(*lnProposalRatio) += log (x / m);
		if (isVPriorExp == YES)
			(*lnPriorRatio) += brlensExp * (m - x);	
		}

	/* set flags for update of cond likes from v and down to root */
	p = v;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}

#	if defined (DEBUG_ExtTBR)
	printf ("After:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  c: %d  d: %d  a: %d  b: %d\n",v->index, u->index, 
		c->index, d->index, a->index, b->index);
	printf ("No. nodes moved in root subtree: %d\n",nRootNodes);
	printf ("No. nodes moved in crown subtree: %d\n",nCrownNodes);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

	gNodeMoves = nCrownNodes + nRootNodes;
#	endif

#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in output tree to eTBR2\n");
		getchar();
		}
#endif

	return (NO_ERROR);
	
}





int Move_ExtTBR3 (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* Change branch lengths and topology (potentially) using TBR (unrooted) 
	   with extension probability (rather than window). */

	/* this move type picks a branch and two "danglies", modifies their length
	   independently according to the method of Larget & Simon (1999: MBE); it then
	   moves the danglies away from their original position one node at a time with
	   a probability determined by the extensionProb parameter

	   when the danglies are moved, their direction is changed
	   this "reflection" is necessary to enable the back move

	   This move type has been tested on all combinations of rooted and unrooted,
	   constrained and unconstrained trees */
	
	int			topologyHasChanged, nCrownNodes, nRootNodes, directionLeft, directionUp, 
				isVPriorExp, i;
	MrBFlt		m, x, y, tuning, maxV, minV, extensionProb, brlensExp=0.0, brlen[3];
	TreeNode	*p, *a, *b, *c, *d, *u, *v, *brlenNode[7];
	Tree		*t;
	ModelParams *mp;


	brlenNode[2] = NULL;
	brlenNode[6] = NULL;

	/* these parameters should be possible to set by user */
	extensionProb = mvp[0];	/* extension probability */
	tuning = mvp[1];        /* Larget & Simon's tuning parameter lambda */
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);
#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in input tree to eTBR3\n");
		getchar();
		}
#endif

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* max and min brlen */
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}

	topologyHasChanged = NO;

#	if defined (DEBUG_ExtTBR)
	printf ("Before:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
#	endif
	
	/* pick an internal branch */
	do
		{
		p = t->intDownPass[(int)(RandomNumber(seed)*t->nIntNodes)];
		} while (p->anc->anc == NULL);
		
	/* set up pointers for nodes around the picked branch */
	/* cut the tree into crown, root and attachment part */
	/* change the relevant lengths in the attachment part */
	/* the lengths of a and v are automatically contained in the */
	/* "attachment" part but the length of c has to be stored in x */
	v = p;
	u = p->anc;

	/* store brlen node */
	brlenNode[3] = v;

	/* set up pointers for crown part */
	/* this also determines direction of move in crown part */
	if (RandomNumber(seed) < 0.5)
		{
		c = v->left;
		d = v->right;
		directionLeft = YES;
		}
	else
		{
		c = v->right;
		d = v->left;
		directionLeft = NO;
		}

	/* store brlen nodes and brlen to move */
	brlenNode[0] = d;
	brlenNode[1] = c;
	x = c->length;

	/* cut and reconnect crown part */
	c->anc = d;
	d->anc = c;
	
	/* mark nodes in root part */
	/* also determines direction of move in root part */
	if (RandomNumber(seed) < 0.5)
		{
		if (u->left == v)
			a = u->right;
		else
			a = u->left;
		b = u->anc;
		directionUp = YES;
		}
	else
		{
		if (u->left == v)
			b = u->right;
		else
			b = u->left;
		a = u->anc;
		directionUp = NO;
		}

	/* store brlen nodes */
	if (directionUp == YES)
		{
		brlenNode[4] = u;
		brlenNode[5] = a;
		}
	else
		{
		brlenNode[4] = b;
		brlenNode[5] = u;
		}

	/* cut root part*/
	/* store branch to be move in u->length */
	if (directionUp == NO) 
		{
		b->anc = a;
		if (a->left == u)
			a->left = b;
		else
			a->right = b;
		}
	else 
		{
		a->anc = b;
		if (b->left == u)
			b->left = a;
		else
			b->right = a;
		y = a->length;
		a->length = u->length;
		u->length = y;
		a->upDateTi = YES;
		u->upDateTi = YES;
		}

	/* adjust proposal ratio for backward move in root subtree
	   if starting from interior, unconstrained branch
	   double test needed to capture the case of no move */
	if (directionUp == NO)
		{
		if (b->left != NULL && b->isLocked == NO &&
			a->anc  != NULL && u->isLocked == NO)
			(*lnProposalRatio) += log(1.0 - extensionProb);
		}
	else
		{
		if (a->left != NULL && a->isLocked == NO &&
			b->anc  != NULL && b->isLocked == NO)
			(*lnProposalRatio) += log(1.0 - extensionProb);
		}

	/* adjust proposal ratio for backward move in crown subtree
	   if starting from interior, unconstrained branch
	   double test is needed to capture the case of no move */
	if (c->left != NULL && c->isLocked == NO && 
		d->left != NULL && d->isLocked == NO)
		(*lnProposalRatio) += log(1.0 - extensionProb);

	/* move around in root subtree */
	for (nRootNodes=0; RandomNumber(seed)<extensionProb; nRootNodes++) 
		{
		if (directionUp == YES) 
			{	/* going up tree */
			if (a->left == NULL || a->isLocked == YES)
				break;		/* can't go further */
			topologyHasChanged = YES;
			b = a;
			if (RandomNumber(seed) < 0.5)
				a = a->left;
			else
				a = a->right;
			if (u->isLocked == YES)
				{
				b->isLocked = YES;
				u->isLocked = NO;
				b->lockID = u->lockID;
				u->lockID = 0;
				}
			}
		else 
			{	/* going down tree */
			if (a->anc == NULL || u->isLocked == YES)
				break;		/* can't go further */
			topologyHasChanged = YES;
			if (RandomNumber(seed)<0.5) 
				{
				directionUp = YES; /* switch direction */
				/* find sister of a */
				if (a->left == b) 
					{
					b = a;
					a = a->right;
					}
				else 
					{  
					b = a;
					a = a->left;
					}
				/* as long as we are moving upwards
				the cond likes to update will be
				flagged by the last pass from u to the root */
				}	
			else 
				{	/* continue down */
				b = a;
				a = a->anc;
				b->upDateCl = YES; 
				if (b->isLocked == YES)
					{
					u->isLocked = YES;
					b->isLocked = NO;
					u->lockID = b->lockID;
					b->lockID = 0;
					}
				}
			}
		}

	/* store brlen nodes */
	if (nRootNodes > 0)
		{
		if (directionUp == YES)
			{
			brlenNode[6] = a;
			brlenNode[5] = u;
			}
		else
			{
			brlenNode[6] = u;
			brlenNode[5] = b;
			}
		}

	/* adjust proposal ratio for forward move if stop branch is interior & unconstrained
	   test of both ends makes sure that no adjustment is made if no move was made */
	if (directionUp == YES) 
		{
		if (a->left != NULL && a->isLocked == NO &&
			b->anc  != NULL && b->isLocked == NO) 
			(*lnProposalRatio) -= log(1.0 - extensionProb);
		}
	else 
		{
		if (a->anc  != NULL && u->isLocked == NO &&
			b->left != NULL && b->isLocked == NO)
			(*lnProposalRatio) -= log(1.0 - extensionProb);
		}

	/* move around in crown subtree */
	for (nCrownNodes=0; RandomNumber(seed)<extensionProb; nCrownNodes++) 
		{
		if (c->left == NULL || c->isLocked == YES)
			break;	/* can't go further */
		topologyHasChanged = YES;
		if (RandomNumber(seed) < 0.5) 
			{
			/* rotate c anticlockwise - prepare pointers for move left */
			c->anc = c->left;  /* the root will be in the direction we are heading */
			c->left = c->right;
			c->right = d;
			}
		else 
			{
			/* rotate c clockwise - prepare pointers for move right */
			c->anc = c->right;	/* the root will be in the direction we are heading */
			c->right = c->left;
			c->left = d;  
			}
		/* OK - let's move!; c->anc points in the right direction
		don't forget to move the branch lengths as well */
		d = c;
		c = c->anc;
		d->length = c->length;
		d->upDateCl = YES; 
		d->upDateTi = YES;
		}

	/* store brlen nodes */
	if (nCrownNodes > 0)
		{
		brlenNode[2] = c;
		brlenNode[1] = d;
		}

	/* adjust proposal ratio for forward move if stop branch is interior & unconstrained
	   double test makes sure that no adjustment is made if no move was made */
	if (c->left != NULL && c->isLocked == NO &&
		d->left != NULL && d->isLocked == NO)
		(*lnProposalRatio) -= log(1.0 - extensionProb);

	/* combine the subtrees */
	c->anc = v;
	d->anc = v;
	if (directionLeft == YES) 
		{
		v->left = c;
		v->right = d;
		}
	else 
		{
		v->left = d;
		v->right = c;
		}

	/* the dangling branch is inserted in reverted position
	   such that the back move will be possible
	   if we have moved around in crown subtree
	   otherwise it is left in its original position */
	if (nCrownNodes > 0)
		{
		d->length = x;
		d->upDateTi = YES;
		}
	else
		{
		c->length = x;
		}	

	if (directionUp == YES) 
		{
		u->anc = b;
		if (u->left == v)
			u->right = a;
		else 
			u->left = a;
		a->anc = u;
		if (b->left == a)
			b->left = u;
		else
			b->right = u;
		/* the dangling branch is contained in u->length
		   and will automatically be inserted in the right position
		   to enable the back move regardless of whether it was
		   initially directed upwards or downwards
		   BUT if we haven't moved in root subtree, it is advantageous (necessary
		   for rooted trees) to avoid switching branches, which occurs otherwise
		   if directionUp == YES */
		if (nRootNodes == 0) 
			{
			x = u->length;
			u->length = a->length;
			a->length = x;
			a->upDateTi = NO;
			u->upDateTi = NO;
			}
		}
	else 
		{
		u->anc = a;
		if (u->left == v)
			u->right = b;
		else 
			u->left = b;
		b->anc = u;
		if (a->left == b)
			a->left = u;
		else
			a->right = u;
		/* the modified branch contained in u->length will have
		   to be moved to b->length to enable back move
		   BUT if we haven't moved, it is better to keep it in place
		   (necessary for rooted trees) */
		if (nRootNodes > 0) 
			{
			x = u->length;
			u->length = b->length;
			b->length = x;
			b->upDateTi = YES;
			u->upDateTi = YES;
			}
		}
	
	/* modify branch lengths */
	/* first modify length of middle branch */
	m = brlenNode[3]->length;
	x = m * exp(tuning * (RandomNumber(seed) - 0.5));		/* save the modified dangling branch for later use */
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	brlenNode[3]->length = x;
	brlenNode[3]->upDateTi = YES;

	/* update proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - x);

	/* if no move then just change a random brlen
	   otherwise shuffle brlens randomly and change
	   one random brlen */
	if (nCrownNodes == 0)
		{
		if (RandomNumber (seed) < 0.5)
			p = brlenNode[0];
		else
			p = brlenNode[1];
		}
	else
		{
		/* select branches randomly */
		for (i=0; i<3; i++)
			brlen[i] = brlenNode[i]->length;
		x = RandomNumber (seed);
		if (x < 1.0 / 3.0)
			brlenNode[0]->length = brlen[0];
		else if (x < 2.0 / 3.0)
			{
			brlenNode[0]->length = brlen[1];
			brlen[1] = brlen[0];
			}
		else
			{
			brlenNode[0]->length = brlen[2];
			brlen[2] = brlen[0];
			}
		x = RandomNumber(seed);
		if (x < 0.5)
			{
			brlenNode[1]->length = brlen[1];
			brlenNode[2]->length = brlen[2];
			}
		else
			{
			brlenNode[1]->length = brlen[2];
			brlenNode[2]->length = brlen[1];
			}
		x = RandomNumber(seed);
		if (x < 1.0 / 3.0)
			p = brlenNode[0];
		else if (x < 2.0 / 3.0)
			p = brlenNode[1];
		else
			p = brlenNode[2];
		brlenNode[0]->upDateTi = YES;
		brlenNode[1]->upDateTi = YES;
		brlenNode[2]->upDateTi = YES;
		brlenNode[0]->anc->upDateCl = YES;
		brlenNode[1]->anc->upDateCl = YES;
		brlenNode[2]->anc->upDateCl = YES;
		}

	/* modify branch length */
	m = p->length;
	x = m * exp(tuning * (RandomNumber(seed) - 0.5));
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	p->length = x;
	p->upDateTi = YES;

	/* update proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - x);	

	/* if no move in root, then select randomly, otherwise always the moved branch */
	if (nRootNodes == 0)
		{
		if (RandomNumber(seed) < 0.5)
			p = brlenNode[4];
		else
			p = brlenNode[5];
		}
	else
		{
		/* select branches randomly */
		for (i=0; i<3; i++)
			brlen[i] = brlenNode[i+4]->length;
		x = RandomNumber (seed);
		if (x < 1.0 / 3.0)
			brlenNode[4]->length = brlen[0];
		else if (x < 2.0 / 3.0)
			{
			brlenNode[4]->length = brlen[1];
			brlen[1] = brlen[0];
			}
		else
			{
			brlenNode[4]->length = brlen[2];
			brlen[2] = brlen[0];
			}
		x = RandomNumber(seed);
		if (x < 0.5)
			{
			brlenNode[5]->length = brlen[1];
			brlenNode[6]->length = brlen[2];
			}
		else
			{
			brlenNode[5]->length = brlen[2];
			brlenNode[6]->length = brlen[1];
			}
		x = RandomNumber(seed);
		if (x < 1.0 / 3.0)
			p = brlenNode[4];
		else if (x < 2.0 / 3.0)
			p = brlenNode[5];
		else
			p = brlenNode[6];
		brlenNode[4]->upDateTi = YES;
		brlenNode[5]->upDateTi = YES;
		brlenNode[6]->upDateTi = YES;
		brlenNode[4]->anc->upDateCl = YES;
		brlenNode[5]->anc->upDateCl = YES;
		brlenNode[6]->anc->upDateCl = YES;
		}
	
	/* modify branch length but not if 'root' branch in rooted tree */
	if (t->isRooted == NO || p->anc->anc != NULL)
		{
		m = p->length;
		x = m * exp(tuning * (RandomNumber(seed) - 0.5));
		while (x < minV || x > maxV)
			{
			if (x < minV)
				x = minV * minV / x;
			else if (x > maxV)
				x = maxV * maxV / x;
			}
		p->length = x;
		p->upDateTi = YES;

		/* update proposal and prior ratio based on length modification */ 
		(*lnProposalRatio) += log (x / m);
		if (isVPriorExp == YES)
			(*lnPriorRatio) += brlensExp * (m - x);	
		}

	/* set flags for update of cond likes from v and down to root */
	p = v;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}
	
#	if defined (DEBUG_ExtTBR)
	printf ("After:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  c: %d  d: %d  a: %d  b: %d\n",v->index, u->index, 
		c->index, d->index, a->index, b->index);
	printf ("No. nodes moved in root subtree: %d\n",nRootNodes);
	printf ("No. nodes moved in crown subtree: %d\n",nCrownNodes);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

	gNodeMoves = nCrownNodes + nRootNodes;
#	endif

#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in output tree to eTBR3\n");
		getchar();
		}
#endif

	return (NO_ERROR);
	
}





int Move_ExtTBR4 (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* Change branch lengths and topology (potentially) using TBR (unrooted) 
	   with extension probability (rather than window). */

	/* this move type picks a branch and two "danglies", modifies their length
	   independently according to the method of Larget & Simon (1999: MBE); it then
	   moves the danglies away from their original position one node at a time with
	   a probability determined by the extensionProb parameter

	   when the danglies are moved, their direction is changed
	   this "reflection" is necessary to enable the back move

	   This move type has been tested on all combinations of rooted and unrooted,
	   constrained and unconstrained trees */
	
	int			topologyHasChanged, nCrownNodes, nRootNodes, directionLeft, directionUp, 
				isVPriorExp, i, mark[7], j, numNodes;
	MrBFlt		m, x, y, tuning, maxV, minV, extensionProb, brlensExp=0.0, brlen[7];
	TreeNode	*p, *a, *b, *c, *d, *u, *v, *brlenNode[7], *node[7];
	Tree		*t;
	ModelParams *mp;

	memset(brlenNode, 0, sizeof(TreeNode *)*7);

	/* these parameters should be possible to set by user */
	extensionProb = mvp[0];	/* extension probability */
	tuning = mvp[1];        /* Larget & Simon's tuning parameter lambda */
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);
#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in input tree to eTBR4\n");
		getchar();
		}
#endif

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* max and min brlen */
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}

	topologyHasChanged = NO;

#	if defined (DEBUG_ExtTBR)
	printf ("Before:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
#	endif
	
	/* pick an internal branch */
	do
		{
		p = t->intDownPass[(int)(RandomNumber(seed)*t->nIntNodes)];
		} while (p->anc->anc == NULL);
		
	/* set up pointers for nodes around the picked branch */
	/* cut the tree into crown, root and attachment part */
	/* change the relevant lengths in the attachment part */
	/* the lengths of a and v are automatically contained in the */
	/* "attachment" part but the length of c has to be stored in x */
	v = p;
	u = p->anc;

	/* store brlen node */
	brlenNode[3] = v;

	/* set up pointers for crown part */
	/* this also determines direction of move in crown part */
	if (RandomNumber(seed) < 0.5)
		{
		c = v->left;
		d = v->right;
		directionLeft = YES;
		}
	else
		{
		c = v->right;
		d = v->left;
		directionLeft = NO;
		}

	/* store brlen nodes and brlen to move */
	brlenNode[0] = d;
	brlenNode[1] = c;
	x = c->length;

	/* cut and reconnect crown part */
	c->anc = d;
	d->anc = c;
	
	/* mark nodes in root part */
	/* also determines direction of move in root part */
	if (RandomNumber(seed) < 0.5)
		{
		if (u->left == v)
			a = u->right;
		else
			a = u->left;
		b = u->anc;
		directionUp = YES;
		}
	else
		{
		if (u->left == v)
			b = u->right;
		else
			b = u->left;
		a = u->anc;
		directionUp = NO;
		}

	/* store brlen nodes */
	if (directionUp == YES)
		{
		brlenNode[4] = u;
		brlenNode[5] = a;
		}
	else
		{
		brlenNode[4] = b;
		brlenNode[5] = u;
		}

	/* cut root part*/
	/* store branch to be move in u->length */
	if (directionUp == NO) 
		{
		b->anc = a;
		if (a->left == u)
			a->left = b;
		else
			a->right = b;
		}
	else 
		{
		a->anc = b;
		if (b->left == u)
			b->left = a;
		else
			b->right = a;
		y = a->length;
		a->length = u->length;
		u->length = y;
		a->upDateTi = YES;
		u->upDateTi = YES;
		}

	/* adjust proposal ratio for backward move in root subtree
	   if starting from interior, unconstrained branch
	   double test needed to capture the case of no move */
	if (directionUp == NO)
		{
		if (b->left != NULL && b->isLocked == NO &&
			a->anc  != NULL && u->isLocked == NO)
			(*lnProposalRatio) += log(1.0 - extensionProb);
		}
	else
		{
		if (a->left != NULL && a->isLocked == NO &&
			b->anc  != NULL && b->isLocked == NO)
			(*lnProposalRatio) += log(1.0 - extensionProb);
		}

	/* adjust proposal ratio for backward move in crown subtree
	   if starting from interior, unconstrained branch
	   double test is needed to capture the case of no move */
	if (c->left != NULL && c->isLocked == NO && 
		d->left != NULL && d->isLocked == NO)
		(*lnProposalRatio) += log(1.0 - extensionProb);

	/* move around in root subtree */
	for (nRootNodes=0; RandomNumber(seed)<extensionProb; nRootNodes++) 
		{
		if (directionUp == YES) 
			{	/* going up tree */
			if (a->left == NULL || a->isLocked == YES)
				break;		/* can't go further */
			topologyHasChanged = YES;
			b = a;
			if (RandomNumber(seed) < 0.5)
				a = a->left;
			else
				a = a->right;
			if (u->isLocked == YES)
				{
				b->isLocked = YES;
				u->isLocked = NO;
				b->lockID = u->lockID;
				u->lockID = 0;
				}
			}
		else 
			{	/* going down tree */
			if (a->anc == NULL || u->isLocked == YES)
				break;		/* can't go further */
			topologyHasChanged = YES;
			if (RandomNumber(seed)<0.5) 
				{
				directionUp = YES; /* switch direction */
				/* find sister of a */
				if (a->left == b) 
					{
					b = a;
					a = a->right;
					}
				else 
					{  
					b = a;
					a = a->left;
					}
				/* as long as we are moving upwards
				the cond likes to update will be
				flagged by the last pass from u to the root */
				}	
			else 
				{	/* continue down */
				b = a;
				a = a->anc;
				b->upDateCl = YES; 
				if (b->isLocked == YES)
					{
					u->isLocked = YES;
					b->isLocked = NO;
					u->lockID = b->lockID;
					b->lockID = 0;
					}
				}
			}
		}

	/* store brlen nodes */
	if (nRootNodes > 0)
		{
		if (directionUp == YES)
			{
			brlenNode[6] = a;
			brlenNode[5] = u;
			}
		else
			{
			brlenNode[6] = u;
			brlenNode[5] = b;
			}
		}

	/* adjust proposal ratio for forward move if stop branch is interior & unconstrained
	   test of both ends makes sure that no adjustment is made if no move was made */
	if (directionUp == YES) 
		{
		if (a->left != NULL && a->isLocked == NO &&
			b->anc  != NULL && b->isLocked == NO) 
			(*lnProposalRatio) -= log(1.0 - extensionProb);
		}
	else 
		{
		if (a->anc  != NULL && u->isLocked == NO &&
			b->left != NULL && b->isLocked == NO)
			(*lnProposalRatio) -= log(1.0 - extensionProb);
		}

	/* move around in crown subtree */
	for (nCrownNodes=0; RandomNumber(seed)<extensionProb; nCrownNodes++) 
		{
		if (c->left == NULL || c->isLocked == YES)
			break;	/* can't go further */
		topologyHasChanged = YES;
		if (RandomNumber(seed) < 0.5) 
			{
			/* rotate c anticlockwise - prepare pointers for move left */
			c->anc = c->left;  /* the root will be in the direction we are heading */
			c->left = c->right;
			c->right = d;
			}
		else 
			{
			/* rotate c clockwise - prepare pointers for move right */
			c->anc = c->right;	/* the root will be in the direction we are heading */
			c->right = c->left;
			c->left = d;  
			}
		/* OK - let's move!; c->anc points in the right direction
		don't forget to move the branch lengths as well */
		d = c;
		c = c->anc;
		d->length = c->length;
		d->upDateCl = YES; 
		d->upDateTi = YES;
		}

	/* store brlen nodes */
	if (nCrownNodes > 0)
		{
		brlenNode[2] = c;
		brlenNode[1] = d;
		}

	/* adjust proposal ratio for forward move if stop branch is interior & unconstrained
	   double test makes sure that no adjustment is made if no move was made */
	if (c->left != NULL && c->isLocked == NO &&
		d->left != NULL && d->isLocked == NO)
		(*lnProposalRatio) -= log(1.0 - extensionProb);

	/* combine the subtrees */
	c->anc = v;
	d->anc = v;
	if (directionLeft == YES) 
		{
		v->left = c;
		v->right = d;
		}
	else 
		{
		v->left = d;
		v->right = c;
		}

	/* the dangling branch is inserted in reverted position
	   such that the back move will be possible
	   if we have moved around in crown subtree
	   otherwise it is left in its original position */
	if (nCrownNodes > 0)
		{
		d->length = x;
		d->upDateTi = YES;
		}
	else
		{
		c->length = x;
		}	

	if (directionUp == YES) 
		{
		u->anc = b;
		if (u->left == v)
			u->right = a;
		else 
			u->left = a;
		a->anc = u;
		if (b->left == a)
			b->left = u;
		else
			b->right = u;
		/* the dangling branch is contained in u->length
		   and will automatically be inserted in the right position
		   to enable the back move regardless of whether it was
		   initially directed upwards or downwards
		   BUT if we haven't moved in root subtree, it is advantageous (necessary
		   for rooted trees) to avoid switching branches, which occurs otherwise
		   if directionUp == YES */
		if (nRootNodes == 0) 
			{
			x = u->length;
			u->length = a->length;
			a->length = x;
			a->upDateTi = NO;
			u->upDateTi = NO;
			}
		}
	else 
		{
		u->anc = a;
		if (u->left == v)
			u->right = b;
		else 
			u->left = b;
		b->anc = u;
		if (a->left == b)
			a->left = u;
		else
			a->right = u;
		/* the modified branch contained in u->length will have
		   to be moved to b->length to enable back move
		   BUT if we haven't moved, it is better to keep it in place
		   (necessary for rooted trees) */
		if (nRootNodes > 0) 
			{
			x = u->length;
			u->length = b->length;
			b->length = x;
			b->upDateTi = YES;
			u->upDateTi = YES;
			}
		}
	
	/* modify branch lengths */
	/* first collect branches and branch lengths */
	node[0] = brlenNode[0];
	node[1] = brlenNode[1];
	node[2] = brlenNode[3];
	
	numNodes = 3;
	if (t->isRooted == NO || brlenNode[4]->anc->anc != NULL)
		node[numNodes++] = brlenNode[4];
	if (t->isRooted == NO || brlenNode[5]->anc->anc != NULL)
		node[numNodes++] = brlenNode[5];

	if (nCrownNodes > 0)
		node[numNodes++] = brlenNode[2];

	if (nRootNodes > 0 && (t->isRooted == NO || brlenNode[6]->anc->anc != NULL))
		node[numNodes++] = brlenNode[6];
	
	for (i=0; i<numNodes; i++)
		{
		brlen[i] = node[i]->length;
		}

	/* shuffle all lengths */
	for (i=0; i<numNodes; i++)
		{
		j = i + (int) (RandomNumber (seed) * (numNodes - i));
		x = brlen[j];
		brlen[j] = brlen[i];
		brlen[i] = x;
		}

	/*	randomly modify some of them */
	for (i=0; i<numNodes; i++)
		mark[i] = 0;

	for (i=0; i<3; i++)
		{
		do {
			j = (int) (RandomNumber (seed) * numNodes);
		} while (mark[j] == 1);

		mark[j] = 1;

		m = brlen[j];
		x = m * exp(tuning * (RandomNumber(seed) - 0.5));
		while (x < minV || x > maxV)
			{
			if (x < minV)
				x = minV * minV / x;
			else if (x > maxV)
				x = maxV * maxV / x;
			}
		brlen[j] = x;

		/* update proposal and prior ratio based on length modification */
		(*lnProposalRatio) += log (x / m);
		if (isVPriorExp == YES)
			(*lnPriorRatio) += brlensExp * (m - x);
		}
		
	/* put branch lengths back */
	for (i=0; i<numNodes; i++)
		{
		node[i]->length = brlen[i];
		node[i]->upDateTi = YES;
		node[i]->upDateCl = YES;
		}

	/* set flags for update of cond likes from v and down to root */
	p = v;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}
	
#	if defined (DEBUG_ExtTBR)
	printf ("After:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  c: %d  d: %d  a: %d  b: %d\n",v->index, u->index, 
		c->index, d->index, a->index, b->index);
	printf ("No. nodes moved in root subtree: %d\n",nRootNodes);
	printf ("No. nodes moved in crown subtree: %d\n",nCrownNodes);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

	gNodeMoves = nCrownNodes + nRootNodes;
#	endif

#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in input tree to eTBR4\n");
		getchar();
		}
#endif

	return (NO_ERROR);
	
}





/*----------------------------------------------------------------
|
|	Move_GeneRate_Dir: Change gene rate multiplier using Dirichlet
|      proposal.
|
----------------------------------------------------------------*/
int Move_GeneRate_Dir (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, nRates;
	MrBFlt		alphaPi, *value, *subValue, numSites, *alphaDir, x, y, sum,
				*dirParm, *oldRate, *newRate;

    /* allocate memory */
    dirParm = (MrBFlt *) SafeCalloc (3*(numTopologies-1), sizeof(MrBFlt));
    oldRate = dirParm + numCurrentDivisions;
    newRate = dirParm + 2*numCurrentDivisions;

    /* get so called alphaPi parameter */
	alphaPi = mvp[0];

	/* get number of rates */
	nRates = param->nValues;

	/* get pointer to rates and number of uncompressed chars */
	value = GetParamVals(param, chain, state[chain]);
	subValue = GetParamSubVals(param, chain, state[chain]);

	/* get Dirichlet parameters */
	alphaDir = subValue + nRates;

	/* calculate old ratesum proportions */
	numSites = 0.0;
	for (i=0; i<nRates; i++)
		numSites += value[i] * subValue[i];		/* numSites should be equal to the number of sites */
	for (i=0; i<nRates; i++)
		oldRate[i] = value[i] * subValue[i] / numSites;
	
	/* multiply old ratesum proportions with some large number to get new values close to the old ones */
	for (i=0; i<nRates; i++)
		dirParm[i] = oldRate[i] * alphaPi;
	
	/* get new values */
	DirichletRandomVariable (dirParm, newRate, nRates, seed);

	/* check new values */
	sum = 0.0;
	for (i=0; i<nRates; i++)
		{
		if (newRate[i] < DIR_MIN)
			newRate[i] = DIR_MIN;
		sum += newRate[i];
		}
	for (i=0; i<nRates; i++)
		newRate[i] /= sum;

	/* calculate and copy new rate ratio values back */
	for (i=0; i<nRates; i++)
		value[i] = newRate[i] * (numSites / subValue[i]);
	
	/* get proposal ratio */
	sum = 0.0;
	for (i=0; i<nRates; i++)
		sum += newRate[i]*alphaPi;
	x = LnGamma(sum);
	for (i=0; i<nRates; i++)
		x -= LnGamma(newRate[i]*alphaPi);
	for (i=0; i<nRates; i++)
		x += (newRate[i]*alphaPi-1.0)*log(oldRate[i]);
	sum = 0.0;
	for (i=0; i<nRates; i++)
		sum += oldRate[i]*alphaPi;
	y = LnGamma(sum);
	for (i=0; i<nRates; i++)
		y -= LnGamma(oldRate[i]*alphaPi);
	for (i=0; i<nRates; i++)
		y += (oldRate[i]*alphaPi-1.0)*log(newRate[i]);
	(*lnProposalRatio) = x - y;

	/* get prior ratio */
	x = y = 0.0;
	for (i=0; i<nRates; i++)
		x += (alphaDir[i]-1.0)*log(newRate[i]);
	for (i=0; i<nRates; i++)
		y += (alphaDir[i]-1.0)*log(oldRate[i]);
	(*lnPriorRatio) = x - y;

	/* Set update flags for all partitions that share the rate multiplier. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
		
	/* may need to hit update flag for cijks when you have a covarion model */
	for (i=0; i<param->nRelParts; i++)
		if (modelSettings[param->relParts[i]].nCijkParts > 1)
			modelSettings[param->relParts[i]].upDateCijk = YES;

    free (dirParm);

    return (NO_ERROR);

}





int Move_GammaShape_M (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* change gamma shape parameter using multiplier */
	
	int			i, isAPriorExp, isValidA;
	MrBFlt		oldA, newA, minA, maxA, alphaExp=0.0, ran, factor, tuning, *gammaRates;
	ModelParams *mp;

	/* get tuning parameter */
	tuning = mvp[0];

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* get minimum and maximum values for alpha */
	if (param->paramId == SHAPE_UNI)
		{
		minA = mp->shapeUni[0];
		maxA = mp->shapeUni[1];
		if (minA < MIN_SHAPE_PARAM)
			minA = MIN_SHAPE_PARAM;
		if (maxA > MAX_SHAPE_PARAM)
			maxA = MAX_SHAPE_PARAM;
		isAPriorExp = NO;
		}
	else
		{
		minA = MIN_SHAPE_PARAM;
		maxA = MAX_SHAPE_PARAM;
		alphaExp = mp->shapeExp;
		isAPriorExp = YES;
		}

	/* get old value of alpha */
	oldA = *GetParamVals(param, chain, state[chain]);

	/* change value for alpha */
	ran = RandomNumber(seed);
	factor = exp(tuning * (ran - 0.5));
	newA = oldA * factor;

	/* check validity */
	isValidA = NO;
	do
		{
		if (newA < minA)
			newA = minA * minA / newA;
		else if (newA > maxA)
			newA = maxA * maxA / newA;
		else
			isValidA = YES;
		} while (isValidA == NO);

	/* get proposal ratio */
	*lnProposalRatio = log(newA / oldA);
	
	/* get prior ratio */
	if (isAPriorExp == NO)
		*lnPriorRatio = 0.0;
	else
		*lnPriorRatio = -alphaExp * (newA - oldA);
	
	/* copy new alpha value back */
	*GetParamVals(param, chain, state[chain]) = newA;
	
	/* now, update gamma category information */
	gammaRates = GetParamSubVals (param, chain, state[chain]);
	if (DiscreteGamma (gammaRates, newA, newA, mp->numGammaCats, 0) == ERROR)
		return (ERROR);

	/* Set update flags for all partitions that share this alpha. Note that the conditional 
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
		
	/* We need to update flags when we have a covarion model */
	for (i=0; i<param->nRelParts; i++)
		if (modelSettings[param->relParts[i]].nCijkParts > 1)
			modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);

}





int Move_Growth (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			    isGPriorExp, isGPriorNorm, isValidG;
	MrBFlt	        oldG, newG, window, minG=0.0, maxG=0.0, growthExp=0.0, ran, oldLnPrior, 
                    newLnPrior, curTheta, growthMu=0.0, growthVar=0.0, x, y, clockRate;
	ModelParams 	        *mp;
	ModelInfo		*m;
	Tree			*t;

	/* get size of window, centered on current growth value */
	window = mvp[0];

	/* get model params */
	m = &modelSettings[param->relParts[0]];
	mp = &modelParams[param->relParts[0]];
	curTheta = *(GetParamVals (m->popSize, chain, state[chain]));
    curTheta *= *(GetParamVals (m->clockRate, chain, state[chain]));
    if (!strcmp(mp->ploidy, "Diploid"))
        curTheta *= 4.0;
    else if (!strcmp(mp->ploidy, "Zlinked"))
        curTheta *= 3.0;
    else
        curTheta *= 2.0;
	
	/* get minimum and maximum values for growth */
	isGPriorExp = isGPriorNorm = NO;
	if (param->paramId == GROWTH_UNI)
		{
		minG = mp->growthUni[0];
		maxG = mp->growthUni[1];
		}
	else if (param->paramId == GROWTH_EXP)
		{
		minG = 0.0;
		maxG = GROWTH_MAX;
		growthExp = mp->growthExp;
		isGPriorExp = YES;
		}
	else if (param->paramId == GROWTH_NORMAL)
		{
		minG = GROWTH_MIN;
		maxG = GROWTH_MAX;
		growthMu  = mp->growthNorm[0];
		growthVar = mp->growthNorm[1];
		isGPriorNorm = YES;
		}

	/* get old value of theta */
	newG = oldG = *GetParamVals(param, chain, state[chain]);
	if (newG < minG)
		newG = oldG = minG;

	/* change value for theta */
	ran = RandomNumber(seed);
	if( maxG-minG >window )
		{
		window = maxG-minG;
		}
	newG = oldG + window * (ran - 0.5);
	
	/* check that new value is valid */
	isValidG = NO;
	do
		{
		if (newG < minG)
			newG = 2* minG - newG;
		else if (newG > maxG)
			newG = 2 * maxG - newG;
		else
			isValidG = YES;
		} while (isValidG == NO);

	/* get proposal ratio */
	*lnProposalRatio = 0.0;
	
	/* get prior ratio */
	t         = GetTree(modelSettings[param->relParts[0]].brlens,chain,state[chain]);
    clockRate = *(GetParamVals(m->clockRate, chain, state[chain]));
	if (LnCoalescencePriorPr (t, clockRate, &oldLnPrior, curTheta, oldG) == ERROR)
		{
		MrBayesPrint ("%s   Problem calculating prior for birth-death process\n", spacer);
		return (ERROR);
		}
	if (LnCoalescencePriorPr (t, clockRate, &newLnPrior, curTheta, newG) == ERROR)
		{
		MrBayesPrint ("%s   Problem calculating prior for birth-death process\n", spacer);
		return (ERROR);
		}
	if (isGPriorExp == NO && isGPriorNorm == NO)
		*lnPriorRatio = newLnPrior - oldLnPrior;
	else if (isGPriorExp == YES)
		*lnPriorRatio = -growthExp * (newG - oldG) + (newLnPrior - oldLnPrior);
	else if (isGPriorNorm == YES)
		{
		x = log(1.0) - log(growthVar) - 0.5 * log(2.0 * 3.14) - 0.5 * ((newG - growthMu) / growthVar) * ((newG - growthMu) / growthVar);
		y = log(1.0) - log(growthVar) - 0.5 * log(2.0 * 3.14) - 0.5 * ((oldG - growthMu) / growthVar) * ((oldG - growthMu) / growthVar);
		*lnPriorRatio = x - y;
		}
				
	/* copy new theta value back */
	*GetParamVals(param, chain, state[chain]) = newG;

	return (NO_ERROR);

}





int Move_IgrBranchLen (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* move one IGR relaxed clock branch length using multiplier */

	int			i;
	MrBFlt		newBrlen, oldBrlen, tuning, minB, maxB, igrvar, *igrRate, *brlens;
	TreeNode	*p = NULL;
	ModelParams *mp;
	ModelInfo	*m;
	Tree		*t;
	TreeNode	*q;

	/* get the tuning parameter */
	tuning = mvp[0];
	
	/* get the model parameters */
	mp = &modelParams[param->relParts[0]];
	m = &modelSettings[param->relParts[0]];

    /* get the TK02 branch rate and effective branch length data */
	igrRate = GetParamVals (param, chain, state[chain]);
	brlens = GetParamSubVals (param, chain, state[chain]);

	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* get minimum and maximum branch length */
	minB = RELBRLENS_MIN;
	maxB = RELBRLENS_MAX;
	
	/* randomly pick a length */
	i = (int) (RandomNumber(seed) * (t->nNodes - 2));
	p = t->allDownPass[i];

	/* find new effective branch length */
	oldBrlen = brlens[p->index];
	newBrlen = oldBrlen * (exp ((0.5 - RandomNumber (seed)) * tuning));

	/* reflect if necessary */
	while (newBrlen < minB || newBrlen > maxB)
		{
		if (newBrlen < minB)
			newBrlen = minB * minB / newBrlen;
		if (newBrlen > maxB)
			newBrlen = maxB * maxB / newBrlen;
		}

    /* set new branch length and rate */
    brlens [p->index] = newBrlen;
    igrRate[p->index] = newBrlen / p->length;

    /* calculate prior ratio */
    igrvar = *GetParamVals (m->igrvar, chain, state[chain]);
    (*lnPriorRatio) -= LnProbTruncGamma (p->length/igrvar, 1.0/igrvar, oldBrlen, minB, maxB);
    (*lnPriorRatio) += LnProbTruncGamma (p->length/igrvar, 1.0/igrvar, newBrlen, minB, maxB);

    /*The following if (*lnPriorRatio != *lnPriorRatio) should be removed if LnProbTruncGamma() would be made more exact and would never return -infinity */
    if (*lnPriorRatio != *lnPriorRatio)
        {
        abortMove=YES;
        return (NO_ERROR);
        }

	/* calculate proposal ratio */
	(*lnProposalRatio) = log (newBrlen / oldBrlen);

    /* set update of transition probability */
    p->upDateTi = YES;

	/* set update of cond likes down to root */
	q = p->anc;
	while (q->anc != NULL)
		{
		q->upDateCl = YES;
		q = q->anc;
		}

	return (NO_ERROR);
	
}





int Move_IgrVar (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* move the shape parameter of the scaled gamma distribution of rate
       variation across tip-to-root paths in the igr relaxed clock model using multiplier */

	int			i, j;
	MrBFlt		oldIgrvar, newIgrvar, minIgrvar, maxIgrvar, tuning, *brlens;
	ModelInfo	*m;
	Model		*mp;
	TreeNode	*p;
	Tree		*t;

	/* get tuning parameter */
	tuning = mvp[0];

	/* get model settings */
	m = &modelSettings[param->relParts[0]];
	mp = &modelParams[param->relParts[0]];

	/* get the min and max values */
	minIgrvar = IGRVAR_MIN;
	maxIgrvar = IGRVAR_MAX;
	if (!strcmp(mp->igrvarPr,"Uniform"))
		{
		minIgrvar = mp->igrvarUni[0];
		maxIgrvar = mp->igrvarUni[1];
		}
	
	/* get the igr variance */
	oldIgrvar = *GetParamVals (param, chain, state[chain]);

	/* set new value */
	newIgrvar = oldIgrvar * exp ((0.5 - RandomNumber(seed))*tuning);
	
	/* reflect if necessary */
	while (newIgrvar < minIgrvar || newIgrvar > maxIgrvar)
		{
		if (newIgrvar < minIgrvar)
			newIgrvar = minIgrvar * minIgrvar / newIgrvar;
		if (newIgrvar > maxIgrvar)
			newIgrvar = maxIgrvar * maxIgrvar / newIgrvar;
		}
	
	/* store new value */
	(*GetParamVals (param, chain, state[chain])) = newIgrvar;

	/* calculate prior ratio */
	for (i=0; i<param->nSubParams; i++)
		{
		brlens = GetParamSubVals (param->subParams[i], chain, state[chain]);
		t = GetTree (param->subParams[i], chain, state[chain]);
		for (j=0; j<t->nNodes-2; j++)
			{
			p = t->allDownPass[j];
			(*lnPriorRatio) -= LnProbTruncGamma  (p->length/oldIgrvar, 1.0/oldIgrvar, brlens[p->index], RELBRLENS_MIN, RELBRLENS_MAX);
			(*lnPriorRatio) += LnProbTruncGamma (p->length/newIgrvar, 1.0/newIgrvar, brlens[p->index], RELBRLENS_MIN, RELBRLENS_MAX);
			}
		}

	/* take prior on Igrvar into account */
	if (!strcmp(mp->igrvarPr,"Exponential"))
		(*lnPriorRatio) += mp->igrvarExp * (oldIgrvar - newIgrvar);
	
	/* calculate proposal ratio */
	(*lnProposalRatio) = log (newIgrvar / oldIgrvar);

	/* we do not need to update likelihoods */
	for (i=0; i<param->nRelParts; i++)
		{
		modelSettings[param->relParts[i]].upDateCl = NO;
		}

	return (NO_ERROR);
	
}





/*----------------------------------------------------------------
|
|	Move_Local: This proposal mechanism changes the topology and
|      branch lengths of an unrooted tree using the LOCAL mech-
|      anism described by Larget & Simon (1999):
|
|      Larget, B. L., and D. L. Simon. 1999. Markov chain 
|         Monte Carlo algorithms for the Bayesian analysis 
|         of phylogenetic trees. Molecular Biology and 
|         Evolution 16:750-759.
|
|      Programmed by FR 2001-10-14 and partly rewritten 2002-02-21
|      for more elegance and the ability to deal with rooted trees.
|	   Support for locked nodes added 2004-01-12 based on mb v2.01.
|	   Calculation of the Hastings ratio corrected 2004-07-01.
|	   Boundary conditions correctly taken care of 2004-09-29.
|	   NB! An alternative to reflection is to skip moves, which might
|          be better for the LOCAL given the complexity of taking
|		   the boundary conditions into account
|
----------------------------------------------------------------*/
int Move_Local (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{
	
	int			topologyHasChanged, isVPriorExp, directionUp, moveX;
	MrBFlt		oldM, newM, x, y, newX, newY,
				tuning, minV, maxV, brlensExp=0.0;
	TreeNode	*v, *u, *a, *b, *c, *d;
	Tree		*t;
	ModelParams *mp;

	tuning = mvp[0]; /* Larget & Simon's tuning parameter lambda */
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);
#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in input tree to LOCAL\n");
		getchar();
		}
#endif

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* max and min brlen */
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}

	topologyHasChanged = NO;

#	if defined (DEBUG_LOCAL)
	printf ("Before:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
#	endif
	
	/* pick an internal branch */
	do
		{
		v = t->intDownPass[(int)(RandomNumber(seed)*t->nIntNodes)];
		} while (v->anc->anc == NULL);
		
	/* set up pointers for crown part */
	if (RandomNumber(seed) < 0.5)
		{
		c = v->left;
		d = v->right;
		}
	else
		{
		c = v->right;
		d = v->left;
		}

	/* set up pointers for root part */
	u = v->anc;
	if (RandomNumber(seed) < 0.5 || (t->isRooted == YES && u->anc->anc == NULL))
		{
		directionUp = YES;
		if (u->left == v)
			a = u->right;
		else
			a = u->left;
		b = u->anc;
		}
	else
		{
		directionUp = NO;
		if (u->left == v)
			b = u->right;
		else
			b = u->left;
		a = u->anc;
		}

	/* store old and new path length as well as old x and y */
	oldM = c->length + v->length;
	if (directionUp == YES)
		{
		oldM += a->length;
		x = a->length;
		}
	else
		{
		oldM += u->length;
		x = u->length;
		}

	y = x + v->length;

	/* pick dangly to move */
	if (RandomNumber(seed) < 0.5)
		moveX = YES;
	else
		moveX = NO;

	/* find new m value */
	newM = exp(tuning * (RandomNumber(seed) - 0.5)) * oldM;

	/* pick dangly to move and
	   pick new attachment point */
	if (moveX == YES)
		{
		/* choose new x */

		/* first update y */
		newY = y * (newM / oldM);

		/* find reinsertion point */
		if (v->isLocked == YES) 
			{
			newX = RandomNumber(seed) *  newY;
			}
		else
			{
			newX = RandomNumber(seed) * newM;
			}
		}
	else
		{
		/* choose new y */

		/* first update x */
		newX = x * (newM / oldM);

		/* find reinsertion point */
		if (v->isLocked == YES)
			{
			newY = RandomNumber(seed) * (newM - newX) + newX;
			}
		else
			{
			newY = RandomNumber(seed) * newM;
			}
		}

	/* adjust proposal and prior ratio based on length modification */
	/* and insertion mechanism */	
	(*lnProposalRatio) += 3.0 * log (newM / oldM);
	if (isVPriorExp == YES)
		(*lnPriorRatio) = brlensExp * (oldM - newM);

	/* make topology move if necessary and then set branch lengths */
	if (newX > newY)
		{
		/* check if we need to abort */
		if (newY < minV || newY > maxV || (newX-newY) < minV || (newX-newY) > maxV || (newM-newX) < minV || (newM-newX) > maxV)
			{
			abortMove = YES;
			return NO_ERROR;
			}

		/* topology has changed */
		topologyHasChanged = YES;
		/* detach v and d */
		/* this scheme differs from that used by Larget and Simon but is more
		   convenient because it avoids tree rotations */
		if (u->left == v)
			u->left = c;
		else
			u->right = c;
		c->anc = u;
		if (directionUp == YES)
			{
			/* place v and d below a */
			if (v->left == d)
				v->right = a;
			else
				v->left = a;
			a->anc = v;
			if (u->left == a)
				u->left = v;
			else
				u->right = v;
			/* v->anc is already u */
			/* adjust lengths */
			c->length = newM - newX;
			v->length = newX - newY;
			a->length = newY;
			}
		else
			{
			/* place v and d below u */
			if (u->isLocked == YES)
				{
				v->isLocked = YES;
				u->isLocked = NO;
				v->lockID = u->lockID;
				u->lockID = 0;
				}
			if (v->left == d)
				v->right = u;
			else
				v->left = u;
			u->anc = v;
			v->anc = a;
			if (a->left == u)
				a->left = v;
			else
				a->right = v;
			/* adjust lengths */
			c->length = newM - newX;
			u->length = newX - newY;
			v->length = newY;
			}
		}
	else
		{
		/* check if we need to abort */
		if (newX < minV || newX > maxV || (newY-newX) < minV || (newY-newX) > maxV || (newM-newY) < minV || (newM-newY) > maxV)
			{
			abortMove = YES;
			return NO_ERROR;
			}

		/* topology has not changed */
		c->length = newM - newY;
		v->length = newY - newX;
		if (directionUp == YES)
			a->length = newX;
		else
			u->length = newX;
		}
				
	/* set update of transition probs */
	c->upDateTi = YES;
	v->upDateTi = YES;
	if (directionUp == YES)
		a->upDateTi = YES;
	else
		u->upDateTi = YES;
		
	/* set flags for update of cond likes from v and u down to root */
	v->upDateCl = YES; 
 	u->upDateCl = YES; 
	if (directionUp == YES)
		v = b;
	else
		v = a;
	while (v->anc != NULL)
		{
		v->upDateCl = YES; 
		v = v->anc;
		}

	/* get downpass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}
		
#	if defined (DEBUG_LOCAL)
	printf ("After:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  c: %d  d: %d  a: %d  b: %d\n",v->index, u->index, 
		c->index, d->index, a->index, b->index);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;
#	endif

#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in output tree of LOCAL\n");
		getchar();
		}
#endif

	return (NO_ERROR);
	
}





/*----------------------------------------------------------------
|
|	Move_LocalClock: This proposal mechanism changes the topology and
|      branch lengths of a rooted tree using the LOCAL (clock) mech-
|      anism described by Larget & Simon (1999):
|
|      Larget, B. L., and D. L. Simon. 1999. Markov chain 
|         Monte Carlo algorithms for the Bayesian analysis 
|         of phylogenetic trees. Molecular Biology and 
|         Evolution 16:750-759.
|
|      Programmed by JH 2002-07-07
|	   Modified by FR 2004-05-22 to handle locked and dated
|			trees
|      Modified by FR 2005-11-09 to take care of erroneous
|           Hastings ratio. The fix implemented here results in
|           a move that does not change tree height.
|
----------------------------------------------------------------*/
int Move_LocalClock (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{
	
	int				i, topologyHasChanged, vIsRoot, aSister, bSister, cSister, *nEvents;
	MrBFlt			x, y, tuning, minV, maxV, h1, h2, h3, h[3], tempD, ran, distUv, distCv,
                    oldALength, oldBLength, oldCLength, oldULength, oldVLength, lambda, nu,
                    *tk02Rate=NULL, *brlens, oldTreeLength, newTreeLength;
#if 0   /* test */
	MrBFlt			newDepth, oldDepth, factor, diff;
#endif
    TreeNode		*u, *v, *w=NULL, *a, *b, *c, *deepestChild, *p;
	Tree			*t;
	ModelParams		*mp;
    Param           *subParm;

    /* tuning parameter ("lambda" in Larget and Simon, 1999) */
	tuning = mvp[0];
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* get model params */
	mp = &modelParams[param->relParts[0]];
			
	/* min brlen */
	minV = BRLENS_MIN;

	/* max brlen */
	maxV = BRLENS_MAX;

#if defined (DEBUG_LOCAL)
	/* check branch lengths and node depths */
	for (i=0; i<t->nNodes-2; i++) {
		p = t->allDownPass[i];
		if (p->length < minV) {
			printf ("%s   ERROR when entering LocalClock: node %d has length %lf", spacer, p->index, p->length);
			return ERROR;
		}
		if (p->nodeDepth >= p->anc->nodeDepth) {
			printf ("%s   ERROR when entering LocalClock: node %d has depth %lf larger than its ancestor %d depth %lf", spacer, p->index, p->nodeDepth, p->anc->index, p->anc->nodeDepth);
			return ERROR;
		}
	}
#endif

	topologyHasChanged = NO;

#	if defined (DEBUG_LOCAL)
	printf ("Before:\n");
	ShowNodes (t->root, 2, YES);
#	endif

	/* set up pointers */
	do
		{
		u = t->intDownPass[(int)(RandomNumber(seed)*(t->nIntNodes-1))];
		} while (u->anc->anc == NULL);
	v = u->anc;
	a = u->left;
	b = u->right;
	if (v->left == u)
		c = v->right;
	else
		c = v->left;
	vIsRoot = NO;
	if (v->anc->anc != NULL)
		w = v->anc;
	else
		vIsRoot = YES;
    
    oldALength = a->length;
    oldBLength = b->length;
    oldCLength = c->length;
    oldVLength = v->length;
    oldULength = u->length;
    oldTreeLength = TreeLength (param, chain);
		
	/* get distances from root of move (w or v) to nodes a, b, and c */
	if (vIsRoot == NO)
		h1 = h2 = h3 = v->length;
	else
		h1 = h2 = h3 = 0.0;
	h1 += u->length + a->length;
	h2 += u->length + b->length;
	h3 += c->length;
	h[0] = h1;
	h[1] = h2;
	h[2] = h3;
	
	/* we also need the distances between u <-> v and c <-> v to calculate the hastings' term */
	distUv = u->length;
	distCv = c->length;
		
	/* sort distances (simply make three comparisons and swap values, if necessary) */
	if (h[0] > h[1])
		{
		tempD = h[1];
		h[1] = h[0];
		h[0] = tempD;
		}
	if (h[0] > h[2])
		{
		tempD = h[2];
		h[2] = h[0];
		h[0] = tempD;
		}
	if (h[1] > h[2])
		{
		tempD = h[2];
		h[2] = h[1];
		h[1] = tempD;
		}
		
	/* Find the child node (a, b, or c) that is closest to the root (i.e., has smallest h_i; i=1,2,3). This
	   part deals with the possibility that some of the nodes are at the same nodeDepth and randomly assigns
	   a node to be deepest in case of ties. */
	if (AreDoublesEqual (h1, h2, 0.00000001) == YES && AreDoublesEqual (h1, h3, 0.00000001) == YES && AreDoublesEqual (h2, h3, 0.00000001) == YES)
		{
		ran = RandomNumber(seed);
		if (ran < 0.33333333)
			deepestChild = a;
		else if (ran > 0.66666666)
			deepestChild = b;
		else
			deepestChild = c;
		}
	else if (AreDoublesEqual (h1, h2, 0.00000001) == YES && AreDoublesEqual (h1, h3, 0.00000001) == NO && AreDoublesEqual (h2, h3, 0.00000001) == NO)
		{
		if (h1 < h3)
			{
			ran = RandomNumber(seed);
			if (ran < 0.5)
				deepestChild = a;
			else
				deepestChild = b;
			}
		else
			deepestChild = c;
		}
	else if (AreDoublesEqual (h1, h2, 0.00000001) == NO && AreDoublesEqual (h1, h3, 0.00000001) == YES && AreDoublesEqual (h2, h3, 0.00000001) == NO)
		{
		if (h1 < h2)
			{
			ran = RandomNumber(seed);
			if (ran < 0.5)
				deepestChild = a;
			else
				deepestChild = c;
			}
		else
			deepestChild = b;
		}
	else if (AreDoublesEqual (h1, h2, 0.00000001) == NO && AreDoublesEqual (h1, h3, 0.00000001) == NO && AreDoublesEqual (h2, h3, 0.00000001) == YES)
		{
		if (h2 < h1)
			{
			ran = RandomNumber(seed);
			if (ran < 0.5)
				deepestChild = b;
			else
				deepestChild = c;
			}
		else
			deepestChild = a;
		}
	else
		{
		if (h1 < h2 && h1 < h3)
			deepestChild = a;
		else if (h2 < h1 && h2 < h3)
			deepestChild = b;
		else
			deepestChild = c;
		}
	
	/* get x and y */
	/* for most of the branches, the proposal ratio is 0.0 so it makes sense to set this first */
	(*lnProposalRatio) = 0.0;
	if (u->isDated == YES && v->isDated == YES)
		{
		/* this proposal is wasted, change nothing */
		if (vIsRoot == NO)
			{
			y = v->length;
			x = y + u->length;
			}
		else
			{
			y = 0.0;
			x = u->length;
			}
		}
	else if (u->isDated == YES && v->isDated == NO)
		{
		/* we can only change the position of v */
		if (vIsRoot == NO)
			{
			/* the upper limit of v's height is determined either by u-length + v->length or by c->length + v->length (h[0]) */
			x = v->length + u->length;
			if (x > h[0])
				x = h[0];
			y = RandomNumber(seed) * x;
			}
		else
			{
			/* v is root: we leave tree height unchanged so we cannot change anything */
			x = u->length;
			y = 0.0;
			}
		}
	else if (u->isDated == NO && v->isDated == YES)
		{
		/* we can only change the position of u */
		if (vIsRoot == NO)
			y = v->length;
		else
			y = 0.0;
		if (u->isLocked == YES)
			{
			if (h1 > h2)
				{
				x = y + RandomNumber(seed) * (h2 - y);
				}
			else
				{
				x = y + RandomNumber(seed) * (h1 - y);
				}
			}
		else
			{
			x = y + RandomNumber(seed) * (h[1] - y);
			}
		}
	/* if we reach the statements down here, neither u nor v is dated */
	else if (u->isLocked == YES)
		{
		if (h1 > h2)
			{
			y = RandomNumber(seed) * h[0];
			x = y + RandomNumber(seed) * (h2 - y);
			}
		else
			{
			y = RandomNumber(seed) * h[0];
			x = y + RandomNumber(seed) * (h1 - y);
			}
		}
	else if (vIsRoot == NO)
		{
		/* this is the standard variant for nonroot v */
		x = RandomNumber(seed) * h[1];
		y = RandomNumber(seed) * h[0];
		}
	else
		{
		/* this is the standard variant when v is the root */
        /*oldDepth = t->root->left->nodeDepth;
          factor = exp((RandomNumber(seed) - 0.5) * 2.0 * log(1.2));
          t->root->left->nodeDepth = newDepth =  factor * h[0] - h[0] + oldDepth;
          adjust h[0], h[1], and h[2] 
          diff = newDepth - oldDepth;
          h[0] += diff;
          h[1] += diff;
          h[2] += diff;*/
        /* set y to 0.0 and select new x */
        y = 0.0;
        x = RandomNumber(seed) * h[1];
        /* Adjust proposal ratio. We deal with topology bias below. Note that this
           proposal ratio is very different from what appeared in Larget and Simon */
        /*(*lnProposalRatio) += (t->nIntNodes-1) * log(oldDepth / newDepth);*/
        /*(*lnProposalRatio) += 2.0 * log (factor);*/
		}
		
	/* decide which topology we will construct (cSister is what we started with) */
	aSister = bSister = cSister = NO;
	/* if u is locked then we cannot change topology */
	if (u->isLocked == YES)
		cSister = YES;
	else if (MaximumValue (x, y) < h[0])
		{
		ran = RandomNumber(seed);
		if (ran < 0.33333333)
			aSister = YES;
		else if (ran > 0.66666666)
			bSister = YES;
		else 
			cSister = YES;
		}
	else
		{
		if (deepestChild == a)
			aSister = YES;
		else if (deepestChild == b)
			bSister = YES;
		else 
			cSister = YES;
		}
	
	/* adjust lengths of nodes u and v */
	u->length = MaximumValue (x, y) - MinimumValue (x, y);
	v->length = MinimumValue (x, y);
	if (vIsRoot == NO)
		v->nodeDepth = w->nodeDepth - v->length;
	u->nodeDepth = v->nodeDepth - u->length;
	
	/* adjust pointers and lengths of nodes a, b, and c */
	topologyHasChanged = NO;
	if (cSister == YES)
		{
		if (v->left == u)
			v->right = c;
		else
			v->left = c;
		u->left = a;
		u->right = b;
		a->anc = b->anc = u;
		c->anc = v;
		a->length = u->nodeDepth - a->nodeDepth;
		b->length = u->nodeDepth - b->nodeDepth;
		c->length = v->nodeDepth - c->nodeDepth;
		}
	else if (bSister == YES)
		{
		if (v->left == u)
			v->right = b;
		else
			v->left = b;
		u->left = a;
		u->right = c;
		a->anc = c->anc = u;
		b->anc = v;
		a->length = u->nodeDepth - a->nodeDepth;
		b->length = v->nodeDepth - b->nodeDepth;
		c->length = u->nodeDepth - c->nodeDepth;
		topologyHasChanged = YES;
		}
	else
		{
		if (v->left == u)
			v->right = a;
		else
			v->left = a;
		u->left = b;
		u->right = c;
		b->anc = c->anc = u;
		a->anc = v;
		a->length = v->nodeDepth - a->nodeDepth;
		b->length = u->nodeDepth - b->nodeDepth;
		c->length = u->nodeDepth - c->nodeDepth;
		topologyHasChanged = YES;
		}

	/* check that all branch lengths are good */
	if (a->length < 0.0 && b->length < 0.0 && c->length < 0.0 && u->length < 0.0 && v->length < 0.0)
        {
        abortMove = YES;
        return NO_ERROR;
        }

	/* calculate the proposal ratio due to asymmetric topology changes */
	if (u->isLocked == NO)
		{
		if (v->isDated == YES || vIsRoot == YES)
			{
			if (distUv > distCv && MaximumValue (x, y) < h[0])
				(*lnProposalRatio) += log(3.0);
			else if (distUv < distCv && MaximumValue (x, y) > h[0])
				(*lnProposalRatio) += log(1.0 / 3.0);
			}
		else
			{
			/* note that Larget and Simon did not have the correct Hastings ratio
			   for this case */
			if (distUv > distCv && MaximumValue (x, y) < h[0])
				(*lnProposalRatio) += log(3.0 / 2.0);
			else if (distUv < distCv && MaximumValue (x, y) > h[0])
				(*lnProposalRatio) += log(2.0 / 3.0);
			}
		}

	/* set update of transition probs */
	a->upDateTi = b->upDateTi = c->upDateTi = u->upDateTi = YES;
	if (vIsRoot == NO)
		v->upDateTi = YES;

	/* set flags for update of cond likes from u down to root */
	p = u;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}
		
	/* get downpass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		GetDownPass (t);
		
	/* adjust proposal and prior ratio for relaxed clock models */
    newTreeLength = TreeLength(param, chain);
    for (i=0; i<param->subParams[0]->nSubParams; i++)
		{
		subParm = param->subParams[0]->subParams[i];
		if (subParm->paramType == P_CPPEVENTS)
			{
			nEvents = subParm->nEvents[2*chain+state[chain]];
			lambda = *GetParamVals (modelSettings[subParm->relParts[0]].cppRate, chain, state[chain]);
			/* proposal ratio */
            (*lnProposalRatio) += nEvents[a->index] * log (a->length / oldALength);
            (*lnProposalRatio) += nEvents[b->index] * log (b->length / oldBLength);
			(*lnProposalRatio) += nEvents[c->index] * log (c->length / oldCLength);
			(*lnProposalRatio) += nEvents[u->index] * log (u->length / oldULength);
			if (v->anc->anc != NULL && v->isDated == NO)
                (*lnProposalRatio) += nEvents[v->index] * log (v->length / oldVLength);
 			/* prior ratio */
			(*lnPriorRatio) += lambda * ((oldTreeLength - newTreeLength)/t->root->left->nodeDepth);
			/* update effective evolutionary lengths */
			if (v->anc->anc == NULL || v->isDated == YES)
                {
                if (UpdateCppEvolLengths (subParm, v->left, chain) == ERROR ||
                    UpdateCppEvolLengths (subParm, v->right, chain) == ERROR)
                    {
                    abortMove = YES;
                    return (NO_ERROR);
                    }
                }
            else
                {
                if (UpdateCppEvolLengths (subParm, v, chain) == ERROR)
                    {
                    abortMove = YES;
                    return (NO_ERROR);
                    }
                }
			}
		else if (subParm->paramType == P_TK02BRANCHRATES)
			{
			nu = *GetParamVals (modelSettings[subParm->relParts[0]].tk02var, chain, state[chain]);
			nu /= t->root->left->nodeDepth;		/* variance increase measured relative to tree height */
			tk02Rate = GetParamVals (subParm, chain, state[chain]);
			brlens = GetParamSubVals (subParm, chain, state[chain]);
			/* no proposal ratio effect */
			/* prior ratio and update of effective evolutionary lengths */
    		(*lnPriorRatio) -= LnProbLogNormal (tk02Rate[u->index], nu*oldALength, tk02Rate[a->index]);
    		(*lnPriorRatio) += LnProbLogNormal (tk02Rate[u->index], nu*u->left->length, tk02Rate[u->left->index]);
    		(*lnPriorRatio) -= LnProbLogNormal (tk02Rate[u->index], nu*oldBLength, tk02Rate[b->index]);
    		(*lnPriorRatio) += LnProbLogNormal (tk02Rate[u->index], nu*u->right->length, tk02Rate[u->right->index]);
            (*lnPriorRatio) -= LnProbLogNormal (tk02Rate[v->index], nu*oldCLength, tk02Rate[c->index]);
            (*lnPriorRatio) -= LnProbLogNormal (tk02Rate[v->index], nu*oldULength, tk02Rate[u->index]);
			(*lnPriorRatio) += LnProbLogNormal (tk02Rate[v->index], nu*v->left->length, tk02Rate[v->left->index]);
			(*lnPriorRatio) += LnProbLogNormal (tk02Rate[v->index], nu*v->right->length, tk02Rate[v->right->index]);
            brlens[a->index] = a->length * (tk02Rate[a->index] + tk02Rate[a->anc->index])/2.0;
            brlens[b->index] = a->length * (tk02Rate[a->index] + tk02Rate[a->anc->index])/2.0;
    		brlens[c->index] = c->length * (tk02Rate[c->index] + tk02Rate[c->anc->index])/2.0;
    		brlens[u->index] = u->length * (tk02Rate[u->index] + tk02Rate[u->anc->index])/2.0;
    		if (v->anc->anc != NULL && v->isDated == NO)
                {
        		(*lnPriorRatio) -= LnProbLogNormal (tk02Rate[w->index], nu*oldVLength, tk02Rate[v->index]);
        		(*lnPriorRatio) += LnProbLogNormal (tk02Rate[w->index], nu*v->length, tk02Rate[v->index]);
        		brlens[v->index] = v->length * (tk02Rate[v->index] + tk02Rate[v->anc->index])/2.0;
                }
			}
		}

    /* calculate and adjust prior ratio for clock tree */
    if (LogClockTreePriorRatio (param, chain, &x) == ERROR)
        return (ERROR);
    (*lnPriorRatio) += x;
	
#	if defined (DEBUG_LOCAL)
	printf ("After:\n");
	ShowNodes (t->root, 2, YES);
	printf ("Has topology changed? %d\n",topologyHasChanged);
#	endif
	
#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;
#	endif

#if defined (DEBUG_LOCAL)
	/* check branch lengths and node depths */
	for (i=0; i<t->nNodes-2; i++) {
		p = t->allDownPass[i];
		if (p->length < minV) {
			printf ("%s   ERROR when leaving LocalClock: node %d has length %lf", spacer, p->index, p->length);
			return ERROR;
		}
		if (p->nodeDepth >= p->anc->nodeDepth) {
			printf ("%s   ERROR when leaving LocalClock: node %d has depth %lf larger than its ancestor %d depth %lf", spacer, p->index, p->nodeDepth, p->anc->index, p->anc->nodeDepth);
			return ERROR;
		}
	}
#endif

	return (NO_ERROR);
	
}





#if 0
/*--------------------------------------------------------------------
|
|	Move_LSPR: Change topology using move based on likelihood scores
|
|--------------------------------------------------------------------*/
int Move_LSPR (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* Change branch lengths and topology (potentially) using SPR-type move 
	   biased according to likelihood scores. */

	/* TODO: Make this work for constrained trees */
	
	int		    i, j, n, division, topologyHasChanged, isVPriorExp, nNodes;
	SafeLong	*pA, *pV, *pP;
	MrBFlt		x, minV, maxV, brlensExp, minLength=0.0, curLength=0.0, length = 0.0,
		        cumulativeProb, warpFactor, sum, ran, tuning, increaseProb, decreaseProb,
				divFactor, nStates, rateMult, temp;
	CLFlt       *nSitesOfPat, *globalNSitesOfPat, *tempCondLikes, **tempCondLikePtr;
	TreeNode	*p, *q, *a, *b, *u, *v, *c=NULL, *d, *candidateNodes[20], *vLeft, *vRight;
	Tree		*t;
	ModelParams *mp;
	ModelInfo	*m = NULL;

	temp = mvp[0];		/* tuning parameter determining how heavily to weight according to likelihood scores */
	var = mvp[1];		/* variance of lognormal for proposing branch lengths */
	increaseProb = decreaseProb = mvp[2];	/* reweighting probabilities */

	(*lnProposalRatio) = (*lnPriorRatio) = 0.0;

	/* get model params and model info */
	mp = &modelParams[param->relParts[0]];
	m = &modelSettings[param->relParts[0]];
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* max and min brlen */
	brlensExp = 0.0;
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}

#if defined (DEBUG_CONSTRAINTS)
	CheckConstraints (t);
#endif

#	if defined (DEBUG_MLSPR)
	printf ("Before:\n");
	ShowNodes (t->root, 2, YES);
	getchar();
#	endif
	
	/* set topologyHasChanged to NO */
	topologyHasChanged = NO;
	
	/* reset node variables that will be used */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		p->marked = NO;
		p->x = 0;
		p->d = 0.0;
		}

	/* pick a random branch */
	do
		{
		p = t->allDownPass[(int)(RandomNumber(seed)*(t->nNodes - 1))];
		} while (p->anc->anc == NULL || p->anc->isLocked == YES);
		
	/* set up pointers for nodes around the picked branch */
	v = p;
	u = p->anc;
	if (u->left == v)
		a = u->right;
	else
		a = u->left;
	b = u->anc;
	vLeft = v->left;
	vRight = vRight;

	/* store the branch lengths */
	aLength = a->length;
	uLength = u->length;
	vLength = v->length;
	if (v->left != NULL)
		{
		vLeftLength = v->left->length;
		vRightLength = v->right->length;
		}
	else
		vLeftLength = vRightLength = 0.0;

	/* get the ML branch lengths */
	/* set initial branch lengths */
	/* cycle through using Newton Raphson and reoptimization a fixed number of iterations */
	for (i=0; i<5; i++)
		{
		}
	
	/* get variance of lognormal */

	
	/* clip tree */
	a->anc = b;
	if (b->left == u)
		b->left = a;
	else
		b->right = a;

	/* count distance to root */
	q = b;
	nNodes = 0;
	while (q->anc != NULL)
		{
		nNodes++;
		q = q->anc;
		}
	
	/* allocate space for temporary cond likes and condlike pointers */
	tempCondLikes = (CLFlt *) SafeCalloc (nNodes*m->numChars*m->numModelStates, sizeof (CLFlt));
	tempCondLikePtr = (CLFlt **) SafeCalloc (nNodes, sizeof (CLFlt *)));
	if (!tempCondLikes || !tempCondLikePtr)
		{
		free (tempCondLikes);
		free (tempCondLikePtr);
		return (ERROR);
		}

	/* shift pointers over */
	q = b;
	j = 0;
	while (q->anc != NULL)
		{
		tempCondLikePtr[j] = m->condLike[chain][q->index][q->clSpace];
		m->condLike[chain][q->index][q->clSpace] = tempCondLikes + j*m->numChars*m->numModelStates; 
		j++;
		q = q->anc;
		}

	/* set length to 0.1 for now; test ML brlen later */
	aLength = a->length;
	a->length = 0.1;
	uLength = u->length;
	u->length = 0.1;
	vLength = v->length;
	v->length = 0.1;

	/* get downpass cond likes for the root part */
	q = b;
	while (q->anc != NULL)
		m->condLikeDown (q, division, chain);

	/* get final pass cond likes for the root part */
	GetLikeFPRootPath (a);

	/* get downpass parsimony states for the crown part */
	GetParsDP (t, v, chain);

	/* mark all nodes in the root part of the tree */
	t->root->left->marked = YES;
	for (i=t->nNodes-3; i>=0; i--)
		{
		p = t->allDownPass[i];
		if (p->anc->marked == YES && p != u)
			p->marked = YES;
		}

	/* find number of site patterns and modify randomly */
	globalNSitesOfPat = numSitesOfPat + ((chainId[chain] % chainParams.numChains) * numCompressedChars) + m->compCharStart;
	nSitesOfPat = (CLFlt *) SafeCalloc (numCompressedChars, sizeof(CLFlt));
	if (!nSitesOfPat)
		{
		MrBayesPrint ("%s   Problem allocating nSitesOfPat in Move_MLSPR\n", spacer);
		free (tempCondLikes);
		free (tempCondLikePtr);
		return (ERROR);
		}
	for (i=0; i<numCompressedChars; i++)
		{
		nSitesOfPat[i] = globalNSitesOfPat[i];
		for (j=0; j<globalNSitesOfPat[i]; j++)
			{
			ran = RandomNumber (seed);
			if (ran < decreaseProb)
				nSitesOfPat[i]--;
			else if (ran > 1.0 - increaseProb)
				nSitesOfPat[i]++;
			}
		}

	/* cycle through the possibilities and record ln likelihood of each in p->d */
	minLength = 0.0;
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->marked == NO)
			continue;
		/* find the parsimony length */
		p->d = 0.0;
		for (n=0; n<t->nRelParts; n++)
			{
			division = t->relParts[n];
			
			/* Find model settings */
			m = &modelSettings[division];

			nStates = m->numModelStates;
			if (m->dataType == STANDARD)
				nStates = 2;
			rateMult = GetRate(division, chain);

			divFactor = warpFactor + log(nStates-1) - log (3) - log(rateMult);

			/* find downpass parsimony sets for the node and its environment */
			pP   = parsPtr[chain][p->index]        + m->parsMatrixStart + Bit(division, p->clSpace       )     * parsMatrixRowSize;
			pA   = parsPtr[chain][p->anc->index]   + m->parsMatrixStart + Bit(division, p->anc->clSpace  )     * parsMatrixRowSize;
			pV   = parsPtr[chain][v->index]        + m->parsMatrixStart + Bit(division, v->clSpace       )     * parsMatrixRowSize;
		
			length = 0.0;
			for (j=0; j<m->numChars; j++)
				{
				x = (pP[j] | pA[j]) & pV[j];
				if (x == 0)
					length += nSitesOfPat[j];
				}
			p->d += divFactor * length;
			}
		if (i == 0)
			minLength = p->d;
		else if (p->d < minLength)
			minLength = p->d;
		if (p == a)
			curLength = p->d;
		}

	/* find the sum given the warp factor */
	sum = 0.0;
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->marked == YES)
			{
			p->d = exp (minLength - p->d);
			sum += p->d;
			}
		}

	/* generate a random uniform */
	ran = RandomNumber (seed);

	/* select the appropriate reattachment point */
	cumulativeProb = 0.0;
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->marked == YES)
			{
			c = p;
			cumulativeProb += p->d / sum;
			if (cumulativeProb > ran)
				break;
			}
		}
	if (c->marked != YES)
		{
		printf ("Could not select node\n");
		getchar();
		}

	/* calculate the proposal ratio */
	if (c == a)
		(*lnProposalRatio) = 0.0;
	else
		(*lnProposalRatio) = c->d - curLength;

	/* reattach */
	d = c->anc;
	c->anc = u;
	if (u->left == v)
		u->right = c;
	else
		u->left = c;
	if (d->left == c)
		d->left = u;
	else
		d->right = u;
	u->anc = d;

	/* reassign branch lengths */
	if (c != a)
		{
		topologyHasChanged = YES;
		if (RandomNumber(seed) < 0.5)
			{
			x = u->length;
			u->length = a->length;
			a->length = x;
			}
		if (RandomNumber(seed) < 0.5)
			{
			x = c->length;
			c->length = u->length;
			u->length = x;
			}
		/* hit c length with multiplier (a and u dealt with below) */
		x = c->length * exp(tuning * (RandomNumber(seed) - 0.5));
		while (x < minV || x > maxV)
			{
			if (x < minV)
				x = minV * minV / x;
			else if (x > maxV)
				x = maxV * maxV / x;
			}
		/* calculate proposal and prior ratio based on length modification */
		(*lnProposalRatio) += log (x / c->length);
		if (isVPriorExp == YES)
			(*lnPriorRatio) += brlensExp * (c->length - x);
		c->length = x;
		}
	
	/* hit a length with multiplier (even if no topology change was made) */
	x = a->length * exp(tuning * (RandomNumber(seed) - 0.5));
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}

	/* calculate proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / a->length);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (a->length - x);
	a->length = x;

	/* hit u length with multiplier (even if no topology change was made) */
	x = u->length * exp(tuning * (RandomNumber(seed) - 0.5));
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}

	/* calculate proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / u->length);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (u->length - x);
	u->length = x;

	/* set tiprobs update flags */
	a->upDateTi = YES;
	u->upDateTi = YES;
	c->upDateTi = YES;	/* could be same as a but that does not matter */

	/* set flags for update of cond likes from u and down to root */
	p = u;
	while (p->anc != NULL)
		{
		p->upDateCl = YES; 
		p = p->anc;
		}

	/* set flags for update of cond likes from b and down to root */
	p = b;
	while (p->anc != NULL && p->upDateCl == NO)
		{
		p->upDateCl = YES; 
		p = p->anc;
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}

	free (nSitesOfPat);

#	if defined (DEBUG_ParsSPR)
	printf ("After:\n");
	ShowNodes (t->root, 2, YES);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  a: %d  b: %d\n",v->index, u->index, a->index, b->index);
	printf ("No. nodes moved in root subtree: %d\n",nRootNodes);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

	gNodeMoves = nRootNodes;
#	endif

#if defined DEBUG_CONSTRAINTS
	CheckConstraints (t);
#endif

	return (NO_ERROR);

}





/* change topology using MLSPR1 */
int Move_MLSPR1 (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* Change branch lengths and topology (potentially) using SPR-type move 
	   biased according to likelihood scores. */

	/* TODO: Make this work for constrained trees */
	
	int		    i, j, n, division, topologyHasChanged, isVPriorExp, nNodes;
	SafeLong	*pA, *pV, *pP;
	MrBFlt		x, minV, maxV, brlensExp, minLength=0.0, curLength=0.0, length = 0.0,
		        cumulativeProb, warpFactor, sum, ran, tuning, increaseProb, decreaseProb,
				divFactor, nStates, rateMult, temp;
	CLFlt       *nSitesOfPat, *globalNSitesOfPat, *tempCondLikes, **tempCondLikePtr;
	TreeNode	*p, *q, *a, *b, *u, *v, *c=NULL, *d, *candidateNodes[20], *vLeft, *vRight;
	Tree		*t;
	ModelParams *mp;
	ModelInfo	*m = NULL;

	temp = mvp[0];		/* tuning parameter determining how heavily to weight according to likelihood scores */
	var = mvp[1];		/* variance of lognormal for proposing branch lengths */
	increaseProb = decreaseProb = mvp[2];	/* reweighting probabilities */

	(*lnProposalRatio) = (*lnPriorRatio) = 0.0;

	/* get model params and model info */
	mp = &modelParams[param->relParts[0]];
	m = &modelSettings[param->relParts[0]];
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* max and min brlen */
	brlensExp = 0.0;
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}

#if defined (DEBUG_CONSTRAINTS)
	CheckConstraints (t);
#endif

#	if defined (DEBUG_MLSPR)
	printf ("Before:\n");
	ShowNodes (t->root, 2, YES);
	getchar();
#	endif
	
	/* set topologyHasChanged to NO */
	topologyHasChanged = NO;
	
	/* reset node variables that will be used */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		p->marked = NO;
		p->x = 0;
		p->d = 0.0;
		}

	/* pick a random branch */
	do
		{
		p = t->allDownPass[(int)(RandomNumber(seed)*(t->nNodes - 1))];
		} while (p->anc->anc == NULL || p->anc->isLocked == YES);
		
	/* set up pointers for nodes around the picked branch */
	v = p;
	u = p->anc;
	if (u->left == v)
		a = u->right;
	else
		a = u->left;
	b = u->anc;
	vLeft = v->left;
	vRight = vRight;

	/* store the branch lengths */
	aLength = a->length;
	uLength = u->length;
	vLength = v->length;
	if (v->left != NULL)
		{
		vLeftLength = v->left->length;
		vRightLength = v->right->length;
		}
	else
		vLeftLength = vRightLength = 0.0;

	/* save DP cond likes */
	/* count distance to root */
	q = b;
	nNodes = 0;
	while (q->anc != NULL)
		{
		nNodes++;
		q = q->anc;
		}
	
	/* allocate space for temporary cond likes and condlike pointers */
	tempCondLikes = (CLFlt *) SafeCalloc (nNodes*m->numChars*m->numModelStates, sizeof (CLFlt));
	tempCondLikePtr = (CLFlt **) SafeCalloc (nNodes, sizeof (CLFlt *)));
	if (!tempCondLikes || !tempCondLikePtr)
		{
		free (tempCondLikes);
		free (tempCondLikePtr);
		return (ERROR);
		}

	/* shift pointers over */
	q = b;
	j = 0;
	while (q->anc != NULL)
		{
		tempCondLikePtr[j] = m->condLike[chain][q->index][q->clSpace];
		m->condLike[chain][q->index][q->clSpace] = tempCondLikes + j*m->numChars*m->numModelStates; 
		j++;
		q = q->anc;
		}
	
	/* get cond like uppass up to b */
	getLikeUPRootPath (t, b);

	/* get ML branch lengths */
	NRBrlenOptimizer (t, v, 5, 3);

	/* cycle through using Newton Raphson and reoptimization a fixed number of iterations */
	for (i=0; i<numIterations; i++)
		{
		if (v->left != NULL)
			{
			getBaseLikeUpLeft (t, v);	/* store instead of DP */
			NewtonRaphsonBrlen (t, v->left, chain);
			getBaseLikeUpRight (t, v);
			GetNewtonRaphsonBrlen (t, v->right, chain);
			m->CondLikeDown (v);
			}
		if (u->left == v)
			getBaseLikeUpLeft (t, u);
		else
			getBaseLikeUpRight (t, u);
		NewtonRaphsonBrlen (t, v, chain);
		if (u->left == v)
			getBaseLikeUpRight (t, u);
		else
			getBaseLikeUpLeft (t, u);
		NewtonRaphsonBrlen (t, a->length, chain);
		m->CondLikeDown (t, u);
		if (b->left == u)
			getBaseLikeUpLeft (t, b);
		else
			getBaseLikeUpRight (t, b);
		NewtonRaphsonBrlen (t, u->length, chain);
		getLikeUp(t, u);
		getLikeUp(t, v);
		}
	
	/* get variance of lognormal for forward move */
	f = log (a->length) - log (aLength);
	fvar = f*f;
	f = log (v->length) - log (vLength);
	fvar += f*f;
	f = log (u->length) - log (uLength);
	fvar += f*f;
	if (v->left != NULL)
		{
		f = log (v->left->length) - log (vLeftLength);
		fvar += f*f;
		f = log (v->right->length) - log (vRightLength);
		fvar += f*f;
		fvar /= 5.0;
		}
	else
		fvar /= 3.0;

	/* clip tree */
	a->anc = b;
	if (b->left == u)
		b->left = a;
	else
		b->right = a;

	/* get ML branch length for a */
	NewtonRaphsonBrlen (t, a, chain, 3);

	/* propose new length for a */
	f = PointNormal(RandomNumber(seed));
	f *= fvar;
	f += log (a->length);
	a->length = f;

	/* get downpass cond likes for the root part */
	q = b;
	while (q->anc != NULL)
		m->condLikeDown (q, division, chain);

	/* get uppass cond likes for the root part */
	GetLikeUp (t, t->root->left);

	/* cycle through the possibilities and record ln likelihood of each in p->d */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->marked == NO)
			continue;
		/* attach crown tree here */
		pLength = p->length;
		/* find ml branch lengths */
		NewtonRaphsonBrlens5 (t, v, chain, 5, 3);
		/* find score */
		m->CondLikeDown (t, v);
		m->CondLikeRoot (t, u);
		m->Likelihood (t, u, &lnL);
		p->d = lnL * warp;
		if (i == 0)
			maxLnL = p->d;
		else if (p->d > maxLnL)
			maxLnL = p->d;
		if (p == a)
			curLnL = p->d;
		/* detach crown tree */
		/* restore p->length */
		p->length = pLength;
		}

	/* find the sum given the warp factor */
	sum = 0.0;
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->marked == YES)
			{
			p->d = exp (maxLnL - p->d);
			sum += p->d;
			}
		}

	/* generate a random uniform */
	ran = RandomNumber (seed);

	/* select the appropriate reattachment point */
	cumulativeProb = 0.0;
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->marked == YES)
			{
			c = p;
			cumulativeProb += p->d / sum;
			if (cumulativeProb > ran)
				break;
			}
		}
	if (c->marked != YES)
		{
		printf ("Could not select node\n");
		getchar();
		}

	/* calculate the proposal ratio based on biased reattachment */
	if (c == a)
		(*lnProposalRatio) = 0.0;
	else
		(*lnProposalRatio) = (maxLnL - log(c->d)) - curLnL;

	/* reattach */
	if (c != a)
		topologyHasChanged = YES;
	d = c->anc;
	c->anc = u;
	if (u->left == v)
		u->right = c;
	else
		u->left = c;
	if (d->left == c)
		d->left = u;
	else
		d->right = u;
	u->anc = d;

	/* optimize branch lengths */
	NewtonRaphsonBrlens5 (t, v, chain, 5, 5);

	/* calculate variance of lognormal for back move */
	f = log (a->length) - log (aLength);
	fvarNew = f*f;
	f = log (v->length) - log (vLength);
	fvarNew += f*f;
	f = log (u->length) - log (uLength);
	fvarNew += f*f;
	if (v->left != NULL)
		{
		f = log (v->left->length) - log (vLeftLength);
		fvarNew += f*f;
		f = log (v->right->length) - log (vRightLength);
		fvarNew += f*f;
		fvarNew /= 5.0;
		}
	else
		fvarNew /= 3.0;
	
	/* draw new branch lengths */
	c->length = fvar * PointNormal(RandomNumber(seed)) + log(c->length);
	u->length = fvar * PointNormal(RandomNumber(seed)) + log(u->length);
	v->length = fvar * PointNormal(RandomNumber(seed)) + log(v->length);
	if (v->left != NULL)
		{
		v->left->length = fvar * PointNormal(RandomNumber(seed)) + log(v->left->length);
		v->right->length = fvar * PointNormal(RandomNumber(seed)) + log(v->right->length);
		}

	/* calculate proposal ratio for branch lengths */

	/* set tiprobs update flags */
	a->upDateTi = YES;
	u->upDateTi = YES;
	c->upDateTi = YES;	/* could be same as a but that does not matter */
	v->upDateTi = YES;
	if (v->left != NULL)
		{
		v->left->upDateTi = YES;
		v->right->upDateTi = YES;
		}

	/* set flags for update of cond likes from v and down to root */
	q = v;
	while (q->anc != NULL)
		{
		q->upDateCl = YES; 
		q = q->anc;
		}

	/* set flags for update of cond likes from b and down to root */
	q = b;
	while (q->anc != NULL && q->upDateCl == NO)
		{
		q->upDateCl = YES; 
		q = q->anc;
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}

	/* restore old conditional likelihoods */
	

#	if defined (DEBUG_MLSPR)
	printf ("After:\n");
	ShowNodes (t->root, 2, YES);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  a: %d  b: %d\n",v->index, u->index, a->index, b->index);
	printf ("No. nodes moved in root subtree: %d\n",nRootNodes);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

	gNodeMoves = nRootNodes;
#	endif

#if defined DEBUG_CONSTRAINTS
	CheckConstraints (t);
#endif

	return (NO_ERROR);

}
#endif





/* change topology using NNI move */
int Move_NNI (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	TreeNode	*p, *u, *v, *a, *b, *c;
	Tree		*t;
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* pick an internal branch */
	do
		{
		p = t->intDownPass[(int)(RandomNumber(seed)*t->nIntNodes)];
		} while (p->anc->anc == NULL || p->isLocked == YES);
		
	/* set up area of rearrangement */
	u = p;
	v = u->anc;
	a = u->left;
	b = u->right;
	if (v->left == u)
		c = v->right;
	else
		c = v->left;
		
	/* change topology */
	if (RandomNumber(seed) < 0.5)
		{
		if (v->left == u)
			v->right = b;
		else
			v->left = b;
		u->left = a;
		u->right = c;
		a->anc = c->anc = u;
		b->anc = v;
		}
	else
		{
		if (v->left == u)
			v->right = a;
		else
			v->left = a;
		u->left = b;
		u->right = c;
		b->anc = c->anc = u;
		a->anc = v;
		}

	/* set update of parsimony sets */
	while (p->anc != NULL)
		{
		p->upDateCl = YES; 
		p = p->anc;
		}
	
	GetDownPass(t);
	
	return (NO_ERROR);

}





/* change clock tree using nni */
int Move_NNIClock (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)
{

	/* Change clock tree using NNI move */
	
	int		    i, *nEvents, numFreeOld, numFreeNew;
	MrBFlt		minV, maxV, minB, maxB, x, lambda, *tk02Rate=NULL,
				*brlens, *igrRate=NULL, igrvar=0.0, nu=0.0, oldALength, oldCLength;
	TreeNode	*p, *q, *a, *b, *c, *u, *v;
	Tree		*t;
	ModelParams *mp;
	ModelInfo	*m = NULL;
	Param		*subParm;

    /* no tuning parameter */

    /* make absolutely sure the proposal ratio and prior ratio are reset */
    (*lnProposalRatio) = (*lnPriorRatio) = 0.0;

	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* get model params and model info */
	mp = &modelParams[param->relParts[0]];
	m = &modelSettings[param->relParts[0]];
	
    /* get min and max branch lengths in relative time and substitution units */
    minV = BRLENS_MIN;
    maxV = BRLENS_MAX;
    minB = RELBRLENS_MIN;
    maxB = RELBRLENS_MAX;

#	if defined (DEBUG_NNIClock)
	printf ("Before:\n");
	ShowNodes (t->root, 2, YES);
	getchar();
#	endif
	
    /* count number of free interior branches */
    numFreeOld = 0;
    for (i=0; i<t->nIntNodes-1; i++)
        {
        p = t->intDownPass[i];
        if (p->anc->left == p)
            q = p->anc->right;
        else
            q = p->anc->left;
        if (p->isLocked == NO && p->nodeDepth >= q->nodeDepth + minV)
            numFreeOld++;
        }

    /* In extremely constrained trees, it might be impossible to change the tree before nodes have changed in position */
    if (numFreeOld == 0)
        {
        abortMove = YES;
        return (NO_ERROR);
        }

	/* pick an interior branch, around which it is possible to make an NNI */
	do
		{
		p = t->intDownPass[(int)(RandomNumber(seed)*(t->nIntNodes-1))];
        if (p->anc->left == p)
            q = p->anc->right;
        else
            q = p->anc->left;
		} while (p->isLocked == YES || p->nodeDepth < q->nodeDepth + minV);
		
    /* set up pointers for nodes around the picked branch */
	if (RandomNumber(seed) < 0.5)
        {
        a = p->left;
        b = p->right;
        }
    else
        {
        b = p->left;
        a = p->right;
        }
    v = p;
	u = p->anc;
	if (u->left == v)
		c = u->right;
	else
		c = u->left;

    /* record branch lengths */
    oldALength = a->length;
    oldCLength = c->length;
    
    /* make topology change */
    a->anc = u;
    c->anc = v;
    if (v->left == a)
        v->left = c;
    else
        v->right = c;
    if (u->left == c)
        u->left = a;
    else
        u->right = a;

    /* adjust branch lengths */
    a->length = u->nodeDepth - a->nodeDepth;
    c->length = v->nodeDepth - c->nodeDepth;
    assert (a->length > minV);
    assert (c->length > minV);

	/* no reassignment of CPP events or branch rates necessary */

	/* set tiprobs update flags */
    a->upDateTi = YES;
    c->upDateTi = YES;

	/* set flags for update of cond likes from v and down to root */
	p = v;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* get down pass sequence */
	GetDownPass (t);

    /* count number of free interior branches after the move */
    numFreeNew = 0;
    for (i=0; i<t->nIntNodes-1; i++)
        {
        p = t->intDownPass[i];
        if (p->anc->left == p)
            q = p->anc->right;
        else
            q = p->anc->left;
        if (p->isLocked == NO && p->nodeDepth >= q->nodeDepth + minV)
            numFreeNew++;
        }
        
    /* get proposal ratio if number of free branches has changed */
    if (numFreeNew != numFreeOld)
        (*lnProposalRatio) = log((MrBFlt)numFreeOld / (MrBFlt)numFreeNew);

    /* calculate and adjust prior ratio for clock trees */
    x = 0.0;
    if (LogClockTreePriorRatio(param, chain, &x) == ERROR)
        return (ERROR);
    (*lnPriorRatio) += x;

	/* adjust proposal and prior ratio for relaxed clock models */
	for (i=0; i<param->subParams[0]->nSubParams; i++)
		{
		subParm = param->subParams[0]->subParams[i];
		if (subParm->paramType == P_CPPEVENTS)
			{
			nEvents = subParm->nEvents[2*chain+state[chain]];
			lambda = *GetParamVals (modelSettings[subParm->relParts[0]].cppRate, chain, state[chain]);

            /* proposal ratio */
            (*lnProposalRatio) += nEvents[a->index] * log (a->length / oldALength);
		    (*lnProposalRatio) += nEvents[c->index] * log (c->length / oldCLength);

            /* prior ratio: no effect because tree length is the same */

            /* update effective evolutionary lengths */
            if (UpdateCppEvolLengths (subParm, a, chain) == ERROR || UpdateCppEvolLengths (subParm, c, chain) == ERROR)
                {
                abortMove = YES;
                return (NO_ERROR);
                }
			}
		else if (subParm->paramType == P_TK02BRANCHRATES)
			{
			nu = *GetParamVals (modelSettings[subParm->relParts[0]].tk02var, chain, state[chain]);
			tk02Rate = GetParamVals (subParm, chain, state[chain]);
			brlens = GetParamSubVals (subParm, chain, state[chain]);

            /* no proposal ratio effect */

            /* prior ratio and update of effective evolutionary lengths */
			(*lnPriorRatio) -= LnProbTK02LogNormal (tk02Rate[v->index], nu*oldALength, tk02Rate[a->index]);
			(*lnPriorRatio) += LnProbTK02LogNormal (tk02Rate[u->index], nu*a->length, tk02Rate[a->index]);
            (*lnPriorRatio) -= LnProbTK02LogNormal (tk02Rate[u->index], nu*oldCLength, tk02Rate[c->index]);
		    (*lnPriorRatio) += LnProbTK02LogNormal (tk02Rate[v->index], nu*c->length, tk02Rate[c->index]);
			brlens[a->index] = a->length * (tk02Rate[a->index] + tk02Rate[a->anc->index])/2.0;
			brlens[c->index] = c->length * (tk02Rate[c->index] + tk02Rate[c->anc->index])/2.0;
			}
		else if (subParm->paramType == P_IGRBRANCHLENS)
			{
            /* get relevant parameters */
            igrvar = *GetParamVals (modelSettings[subParm->relParts[0]].igrvar, chain, state[chain]);
            igrRate = GetParamVals (subParm, chain, state[chain]);
			brlens = GetParamSubVals (subParm, chain, state[chain]);

            /* adjust for prior (part 1) */
            (*lnPriorRatio) -= LnProbTruncGamma (oldALength/igrvar, 1.0/igrvar, brlens[a->index], minB, maxB);
            (*lnPriorRatio) -= LnProbTruncGamma (oldCLength/igrvar, 1.0/igrvar, brlens[c->index], minB, maxB);

            /* keep b lens constant, adjusting rates (one of many possibilities) */
            igrRate[a->index] = brlens[a->index] / a->length;
            igrRate[c->index] = brlens[c->index] / c->length;

            /* adjust for prior (part 2) */
            (*lnPriorRatio) += LnProbTruncGamma (a->length/igrvar, 1.0/igrvar, brlens[a->index], minB, maxB);
            (*lnPriorRatio) += LnProbTruncGamma (c->length/igrvar, 1.0/igrvar, brlens[c->index], minB, maxB);
            /*The following if (*lnPriorRatio != *lnPriorRatio) should be removed if LnProbTruncGamma() would be made more exact and would never return -infinity */
            if (*lnPriorRatio != *lnPriorRatio)
                {
                abortMove=YES;
                return (NO_ERROR);
                }
            }
		}
	
#	if defined (DEBUG_NNIClock)
	printf ("After:\n");
	ShowNodes (t->root, 2, YES);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  a: %d  b: %d\n",v->index, u->index, a->index, b->index);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

	return (NO_ERROR);
	
}





/* change topology with unlinked brlens using NNI */
int Move_NNI_Hetero (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, brIndex, moveType;
	TreeNode	*p, *u, *v, *a, *b, *c;
	Tree		*t;
	ModelParams *mp;
	
	(*lnPriorRatio) = (*lnProposalRatio) = 0.0;
		
	/* get first tree */
	t = GetTree (param, chain, state[chain]);

	/* pick an internal branch */
	do
		{
		brIndex = (int) (RandomNumber(seed) * t->nIntNodes);
		p = t->intDownPass[brIndex];
		} while (p->anc->anc == NULL || p->isLocked == YES);
		
	/* decide on how to change the tree */
	if (RandomNumber(seed) < 0.5)
		moveType = 0;
	else
        moveType = 1;
	
	/* cycle through trees */
	for (i=0; i<param->nSubParams; i++)
		{
		/* get model params */
		mp = &modelParams[param->relParts[0]];
				
		/* get tree */
		t = GetTree (param->subParams[i], chain, state[chain]);

		/* find p */
		p = t->intDownPass[brIndex];

		/* set up area of rearrangement */
		u = p;
		v = u->anc;
		a = u->left;
		b = u->right;
		if (v->left == u)
			c = v->right;
		else
			c = v->left;

		/* change topology */
		if (moveType == 0)
			{
			if (v->left == u)
				v->right = b;
			else
				v->left = b;
			u->left = a;
			u->right = c;
			a->anc = c->anc = u;
			b->anc = v;
			}
		else if (moveType == 1)
			{
			if (v->left == u)
				v->right = a;
			else
				v->left = a;
			u->left = b;
			u->right = c;
			b->anc = c->anc = u;
			a->anc = v;
			}

		/* set update of ti probs */
		a->upDateTi = YES;
		b->upDateTi = YES;
		c->upDateTi = YES;
		u->upDateTi = YES;
		v->upDateTi = YES;
		
		/* set update of conditional likelihoods */
		while (p->anc != NULL)
			{
			p->upDateCl = YES; 
			p = p->anc;
			}

		/* reset tree downpass sequences */
		GetDownPass(t);

		}
	
	return (NO_ERROR);

}





/*-----------------------------------------------------------------------------------
|
|	Move_NodeSlider: move the position of one node without changing topology
|
-------------------------------------------------------------------------------------*/

int Move_NodeSlider (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{
	MrBFlt		tuning, maxV, minV, oldM, newM, brlensPrExp=0.0, newMin, newMax, oldMin, oldMax;
	TreeNode	*p, *q;
	ModelParams *mp;
	Tree		*t;

	tuning = mvp[0]; /* Larget & Simon's tuning parameter lambda */

	mp = &modelParams[param->relParts[0]];

	/* max and min brlen (time) */
	if (param->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensPrExp = mp->brlensExp;
		}
    
	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* pick an interior branch */
	do
		{
		p = t->intDownPass[(int)(RandomNumber(seed)*t->nIntNodes)];
		} while (p->anc == NULL || (t->isRooted == YES && p->anc->anc == NULL));

	/* pick one descendant branch */
	if (RandomNumber(seed) < 0.5)
		q = p->left;
	else
		q = p->right;
	
	/* determine new length */
	oldM = (q->length + p->length);
	newM = oldM * exp(tuning * (RandomNumber(seed) - 0.5));
	while (newM < 2.0 * minV || newM > 2.0 * maxV)
		{
		if (newM < 2.0 * minV)
			newM = 4.0 * minV * minV / newM;
		else if (newM > 2.0 * maxV)
			newM = 4.0 * maxV * maxV / newM;
		}

	/* determine new lengths of p and q */
	newMin = minV > newM - maxV ? minV : newM - maxV;
	newMax = maxV < newM - minV ? maxV : newM - minV;
	oldMin = minV > oldM - maxV ? minV : oldM - maxV;
	oldMax = maxV < oldM - minV ? maxV : oldM - minV;

	q->length = newMin + RandomNumber(seed) * (newMax - newMin);
	p->length = newM - q->length;

	/* set flags for update of transition probabilities at p and q */
	p->upDateTi = YES;
	q->upDateTi = YES;
	p->upDateCl = YES;

	/* set flags for update of cond likes from p->anc and down to root */
	while (p->anc->anc != NULL)
		{
		p = p->anc;
		p->upDateCl = YES;
		}

	/* calculate proposal ratio */
	(*lnProposalRatio) = log(newM / oldM) + log ((newMax - newMin) / (oldMax - oldMin));

	/* update prior if exponential prior on branch lengths */
	if (param->paramId == BRLENS_EXP)
		(*lnPriorRatio) = brlensPrExp * (oldM - newM);

	return (NO_ERROR);
	
}





/*-----------------------------------------------------------------------------------
|
|	Move_NodeSliderClock: Move the position of one (root or nonroot) node in clock tree.
|      In calibrated trees, we need to move also calibrated terminal nodes.
|
-------------------------------------------------------------------------------------*/
    
int Move_NodeSliderClock (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{
	int			i, *nEvents;
	MrBFlt	    window, minDepth, maxDepth, oldDepth, newDepth,
				oldLeftLength=0.0, oldRightLength=0.0, x, clockRate,
				oldPLength=0.0, lambda=0.0, nu=0.0, igrvar=0.0, *brlens=NULL, *tk02Rate=NULL, *igrRate=NULL;
	TreeNode	*p, *q;
	ModelParams	*mp;
	ModelInfo	*m;
	Tree		*t;
	Param		*subParm;

	window = mvp[0]; /* window size */
 
	m = &modelSettings[param->relParts[0]];
	mp = &modelParams[param->relParts[0]];

	/* get tree */
	t = GetTree (param, chain, state[chain]);

    /* get clock rate */
    if (m->clockRate == NULL)
        clockRate = 1.0;
    else
        clockRate = *GetParamVals(m->clockRate, chain, state[chain]);

    /* check whether or not we can change root */
    if (!strcmp(mp->clockPr, "Uniform") &&
        ((!strcmp(mp->treeAgePr, "Fixed") && t->root->left->isDated == NO) ||
         (t->root->left->isDated == YES && t->root->left->calibration->prior == fixed)))
        i = t->nNodes - 2;
    else
        i = t->nNodes - 1;

    /* pick a node that can be changed in position */
	do
		{
		p = t->allDownPass[(int)(RandomNumber(seed)*i)];
		} while ((p->left == NULL && p->isDated == NO) || (p->isDated == YES && p->calibration->prior == fixed));
    assert (p->anc != NULL);

#if defined (DEBUG_CSLIDER)
	printf ("Before node slider (clock):\n");
	printf ("Picked branch with index %d and depth %f\n", p->index, p->nodeDepth);
	if (p->anc->anc == NULL)
		printf ("Old clock rate: %f\n", clockRate);
	ShowNodes (t->root, 0, t->isRooted);
	getchar();
#endif

	/* store values needed later for prior calculation (relaxed clocks) */
	oldPLength = p->length;
	if (p->left != NULL)
        {
        oldLeftLength = p->left->length;
	    oldRightLength = p->right->length;
        }
    else
        oldLeftLength = oldRightLength = 0.0;

	/* determine lower and upper bound */
	if (p->left == NULL)
        minDepth = 0.0;
    else
        {
		minDepth = p->left->nodeDepth + BRLENS_MIN;
		if (p->right->nodeDepth + BRLENS_MIN > minDepth)
			minDepth = p->right->nodeDepth + BRLENS_MIN;
        }
	if (p->anc->anc == NULL)
        maxDepth = TREEHEIGHT_MAX;
	else
    	maxDepth = p->anc->nodeDepth - BRLENS_MIN;
	
    if (p->isDated == YES)
		{
		if (p->calibration->prior == uniform)
			{
			if (p->calibration->max * clockRate < maxDepth)
				maxDepth = p->calibration->max * clockRate;
			if (p->calibration->min * clockRate > minDepth)
				minDepth = p->calibration->min * clockRate;
			}
		else /* if (p->calibration->prior == offsetExponential) */
			{
            assert(p->calibration->prior == offsetExponential);
			if (p->calibration->offset * clockRate > minDepth)
				minDepth = p->calibration->offset * clockRate;
			}
		}
		
    /* abort if impossible */
	if (minDepth >= maxDepth)
		{
		abortMove = YES;
		return (NO_ERROR);
		}

    /* save some reflection time */
    if( maxDepth-minDepth < window )
		{
		window = maxDepth-minDepth;
		}

	/* pick the new node depth */
    oldDepth = p->nodeDepth;
	newDepth = oldDepth + (RandomNumber (seed) - 0.5) * window;
 
    /* reflect the new node depth */
    while (newDepth < minDepth || newDepth > maxDepth)
		{
		if (newDepth < minDepth)
			newDepth = 2.0 * minDepth - newDepth;
		if (newDepth > maxDepth)
			newDepth = 2.0 * maxDepth - newDepth;
		}

	p->nodeDepth = newDepth;

	/* determine new branch lengths around p and set update of transition probabilities */
	if (p->left != NULL)
		{
		p->left->length = p->nodeDepth - p->left->nodeDepth;
        assert (p->left->length >= BRLENS_MIN);
		p->left->upDateTi = YES;
		p->right->length = p->nodeDepth - p->right->nodeDepth;
        assert (p->right->length >= BRLENS_MIN);
		p->right->upDateTi = YES;
		}
	if (p->anc->anc != NULL)
        {
        p->length = p->anc->nodeDepth - p->nodeDepth;
        assert (p->length >= BRLENS_MIN);
	    p->upDateTi = YES;
        }

    /* adjust age of p if dated */
    if (p->isDated == YES)
        {
        p->age = p->nodeDepth / clockRate;
        }

    /* set flags for update of cond likes from p and down to root */
	q = p;
	while (q->anc != NULL)
		{
		q->upDateCl = YES;
		q = q->anc;
		}

	/* calculate proposal ratio */
    (*lnProposalRatio) = 0.0;

    /* calculate and adjust prior ratio for clock tree */
    if (LogClockTreePriorRatio (param, chain, &x) == ERROR)
        return (ERROR);
    (*lnPriorRatio) += x;

    /* adjust proposal and prior ratio for relaxed clock models */
	for (i=0; i<param->nSubParams; i++)
		{
		subParm = param->subParams[i];
		if (subParm->paramType == P_CPPEVENTS)
			{
			nEvents = subParm->nEvents[2*chain+state[chain]];
			lambda = *GetParamVals (modelSettings[subParm->relParts[0]].cppRate, chain, state[chain]);
			/* proposal ratio */
			if (p->left != NULL)
                {
                (*lnProposalRatio) += nEvents[p->left->index ] * log (p->left->length  / oldLeftLength);
			    (*lnProposalRatio) += nEvents[p->right->index] * log (p->right->length / oldRightLength);
                }
			if (p->anc->anc != NULL)
                (*lnProposalRatio) += nEvents[p->index] * log (p->length / oldPLength);

            /* prior ratio */
			if (p->anc->anc == NULL) // two branches changed in same direction
                (*lnPriorRatio) += lambda * (2.0 * (oldDepth - newDepth));
            else if (p->left != NULL) // two branches changed in one direction, one branch in the other direction
                (*lnPriorRatio) += lambda * (oldDepth - newDepth);
            else /* if (p->left == NULL) */ // one branch changed
                (*lnPriorRatio) += lambda * (newDepth - oldDepth);

            /* update effective evolutionary lengths */
			if (UpdateCppEvolLengths (subParm, p, chain) == ERROR)
                {
                abortMove = YES;
                return (NO_ERROR);
                }
			}
		else if (subParm->paramType == P_TK02BRANCHRATES)
			{
			nu = *GetParamVals (modelSettings[subParm->relParts[0]].tk02var, chain, state[chain]);
			tk02Rate = GetParamVals (subParm, chain, state[chain]);
			brlens = GetParamSubVals (subParm, chain, state[chain]);

            /* no proposal ratio effect */

            /* prior ratio */
            if (p->left != NULL)
                {
                (*lnPriorRatio) -= LnProbTK02LogNormal (tk02Rate[p->index], nu*oldLeftLength, tk02Rate[p->left->index]);
			    (*lnPriorRatio) -= LnProbTK02LogNormal (tk02Rate[p->index], nu*oldRightLength, tk02Rate[p->right->index]);
    			(*lnPriorRatio) += LnProbTK02LogNormal (tk02Rate[p->index], nu*p->left->length, tk02Rate[p->left->index]);
    			(*lnPriorRatio) += LnProbTK02LogNormal (tk02Rate[p->index], nu*p->right->length, tk02Rate[p->right->index]);
                }
            if (p->anc->anc != NULL)
                {
			    (*lnPriorRatio) -= LnProbTK02LogNormal (tk02Rate[p->anc->index], nu*oldPLength, tk02Rate[p->index]);
			    (*lnPriorRatio) += LnProbTK02LogNormal (tk02Rate[p->anc->index], nu*p->length, tk02Rate[p->index]);
                }

            /* update effective evolutionary lengths */
			if (p->left != NULL)
                {
                brlens[p->left->index] = p->left->length * (tk02Rate[p->left->index]+tk02Rate[p->index])/2.0;
			    brlens[p->right->index] = p->right->length * (tk02Rate[p->right->index]+tk02Rate[p->index])/2.0;
                }
            if (p->anc != NULL)
    			brlens[p->index] = p->length * (tk02Rate[p->index]+tk02Rate[p->anc->index])/2.0;
			}
		else if (subParm->paramType == P_IGRBRANCHLENS)
			{
			igrvar = *GetParamVals (modelSettings[subParm->relParts[0]].igrvar, chain, state[chain]);
			igrRate = GetParamVals (subParm, chain, state[chain]);
			brlens = GetParamSubVals (subParm, chain, state[chain]);
			
            if (p->left != NULL)
                {
                (*lnPriorRatio) -= LnProbTruncGamma (oldLeftLength   /igrvar, 1.0/igrvar, brlens[p->left->index ], RELBRLENS_MIN, RELBRLENS_MAX);
			    (*lnPriorRatio) -= LnProbTruncGamma (oldRightLength  /igrvar, 1.0/igrvar, brlens[p->right->index], RELBRLENS_MIN, RELBRLENS_MAX);
                }
            if (p->anc->anc != NULL)
    			(*lnPriorRatio) -= LnProbTruncGamma (oldPLength/igrvar, 1.0/igrvar, brlens[p->index], RELBRLENS_MIN, RELBRLENS_MAX);

            if (p->left != NULL)
                {
                brlens[p->left->index ] = igrRate[p->left->index ] * p->left->length;
                brlens[p->right->index] = igrRate[p->right->index] * p->right->length;
                if (brlens[p->left->index] < RELBRLENS_MIN || brlens[p->left->index] > RELBRLENS_MAX ||
                    brlens[p->right->index] < RELBRLENS_MIN || brlens[p->right->index] > RELBRLENS_MAX)
                    {
                    abortMove = YES;
                    return (NO_ERROR);
                    }
                (*lnProposalRatio) += log(p->left->length  / oldLeftLength);
                (*lnProposalRatio) += log(p->right->length / oldRightLength);
                }
            if (p->anc->anc != NULL)
                {
                brlens[p->index] = igrRate[p->index] * p->length;
                if (brlens[p->index] < RELBRLENS_MIN || brlens[p->index] > RELBRLENS_MAX)
                    {
                    abortMove = YES;
                    return (NO_ERROR);
                    }
                (*lnProposalRatio) += log(p->length / oldPLength);
                }
            
            if (p->left != NULL)
                {
                (*lnPriorRatio) += LnProbTruncGamma (p->left->length /igrvar, 1.0/igrvar, brlens[p->left->index ], RELBRLENS_MIN, RELBRLENS_MAX);
			    (*lnPriorRatio) += LnProbTruncGamma (p->right->length/igrvar, 1.0/igrvar, brlens[p->right->index], RELBRLENS_MIN, RELBRLENS_MAX);
                }
            if (p->anc->anc != NULL)
    			(*lnPriorRatio) += LnProbTruncGamma (p->length /igrvar, 1.0/igrvar, brlens[p->index], RELBRLENS_MIN, RELBRLENS_MAX);

            /*The following if (*lnPriorRatio != *lnPriorRatio) should be removed if LnProbTruncGamma() would be made more exact and would never return -infinity */
            if (*lnPriorRatio != *lnPriorRatio)
                {
                abortMove=YES;
                return (NO_ERROR);
                }
            }          
		}

#if defined (DEBUG_CSLIDER)
	printf ("After node slider (clock):\n");
	printf ("Old depth: %f -- New depth: %f -- LnPriorRatio %f -- LnProposalRatio %f\n",
		oldDepth, newDepth, (*lnPriorRatio), (*lnProposalRatio));
	ShowNodes (t->root, 0, t->isRooted);
	getchar();
#endif

    return (NO_ERROR);
	
}





int Move_Nu (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* move the variance of the TK02 relaxed clock lognormal using multiplier */

	int			i, j;
	MrBFlt		oldNu, newNu, minNu, maxNu, tuning, *tk02Rate;
	ModelInfo	*m;
	Model		*mp;
	TreeNode	*p;
	Tree		*t;

	/* get tuning parameter */
	tuning = mvp[0];

	/* get model settings */
	m = &modelSettings[param->relParts[0]];
	mp = &modelParams[param->relParts[0]];

	/* get the min and max values */
	minNu = TK02VAR_MIN;
	maxNu = TK02VAR_MAX;
	if (!strcmp(mp->tk02varPr,"Uniform"))
		{
		minNu = mp->tk02varUni[0];
		maxNu = mp->tk02varUni[1];
		}
	
	/* get the TK02 lognormal variance */
	oldNu = *GetParamVals (param, chain, state[chain]);

	/* set new value */
	newNu = oldNu * exp ((0.5 - RandomNumber(seed))*tuning);
	
	/* reflect if necessary */
	while (newNu < minNu || newNu > maxNu)
		{
		if (newNu < minNu)
			newNu = minNu * minNu / newNu;
		if (newNu > maxNu)
			newNu = maxNu * maxNu / newNu;
		}
	
	/* store new value */
	(*GetParamVals (param, chain, state[chain])) = newNu;

	/* calculate prior ratio */
	for (i=0; i<param->nSubParams; i++)
		{
		tk02Rate = GetParamVals (param->subParams[i], chain, state[chain]);
		t = GetTree (param->subParams[i], chain, state[chain]);
		for (j=0; j<t->nNodes-2; j++)
			{
			p = t->allDownPass[j];
			(*lnPriorRatio) -= LnProbTK02LogNormal (tk02Rate[p->anc->index], oldNu*p->length, tk02Rate[p->index]);
			(*lnPriorRatio) += LnProbTK02LogNormal (tk02Rate[p->anc->index], newNu*p->length, tk02Rate[p->index]);
			}
		}

	/* take prior on nu into account */
	if (!strcmp(mp->tk02varPr,"Exponential"))
		(*lnPriorRatio) += mp->tk02varExp * (oldNu - newNu);
	
	/* calculate proposal ratio */
	(*lnProposalRatio) = log (newNu / oldNu);

	/* we do not need to update likelihoods */
	for (i=0; i<param->nRelParts; i++)
		{
		modelSettings[param->relParts[i]].upDateCl = NO;
		}

	return (NO_ERROR);
	
}





/*----------------------------------------------------------------
|
|	Move_Omega: Change the nonysnonymous/synonymous rate ratio
|      Note that this is appropriate when omegavar=equal
|
----------------------------------------------------------------*/
int Move_Omega (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* change omega using sliding window */
	
	int			i, isValidO;
	MrBFlt		oldO, newO, window, minO, maxO, ran, *alphaDir, oldPropRatio, newPropRatio, x, y;
	ModelParams	*mp;

	/* get size of window, centered on current omega value */
	window = mvp[0];
	
	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* get minimum and maximum values for omega */
	minO = KAPPA_MIN;
	maxO = KAPPA_MAX;

	/* get old value of omega */
	oldO = *GetParamVals(param, chain, state[chain]);

	/* get Dirichlet parameters */
	alphaDir = mp->tRatioDir;

	/* change value for omega */
	ran = RandomNumber(seed);
	if( maxO-minO > window )
		{
		window = maxO-minO;
		}
	newO = oldO + window * (ran - 0.5);
	
	/* check that new value is valid */
	isValidO = NO;
	do
		{
		if (newO < minO)
			newO = 2.0 * minO - newO;
		else if (newO > maxO)
			newO = 2.0 * maxO - newO;
		else
			isValidO = YES;
		} while (isValidO == NO);

	/* get proposal ratio */
	*lnProposalRatio = 0.0;
	
	/* get prior ratio from Dirichlet */
	oldPropRatio = oldO / (oldO + 1.0);
	newPropRatio = newO / (newO + 1.0);
	x = ((alphaDir[0] - 1.0) * log(newPropRatio)) + ((alphaDir[1] - 1.0) * log (1.0 - newPropRatio));
	y = ((alphaDir[0] - 1.0) * log(oldPropRatio)) + ((alphaDir[1] - 1.0) * log (1.0 - oldPropRatio));
	(*lnPriorRatio) = x - y;
	
	/* copy new omega value back */
	*GetParamVals(param, chain, state[chain]) = newO;

	/* Set update flags for all partitions that share this kappa. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);

	/* Set update flags for cijks for all affected partitions. If this is a simple 4 X 4 model,
	   we don't take any hit, because we will never go into a general transition probability
	   calculator. However, for covarion, doublet, and codon models, we do want to update
	   the cijk flag. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);

}





/*----------------------------------------------------------------
|
|	Move_Omega_M: Change the nonysnonymous/synonymous rate ratio
|      using multiplier. Note that this is appropriate when
|      omegavar=equal
|
----------------------------------------------------------------*/
int Move_Omega_M (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* change omega using multiplier */
	
	int			i, isValidO;
	MrBFlt		oldO, newO, minO, maxO, tuning, ran, factor, *alphaDir, oldPropRatio, newPropRatio, x, y;
	ModelParams	*mp;

	/* get model params */
	mp = &modelParams[param->relParts[0]];

	/* get tuning parameter */
	tuning = mvp[0];

	/* get minimum and maximum values for omega */
	minO = KAPPA_MIN;
	maxO = KAPPA_MAX;

	/* get old value of omega */
	oldO = *GetParamVals(param, chain, state[chain]);

	/* get Dirichlet parameters */
	alphaDir = mp->omegaDir;

	/* change value for omega */
	ran = RandomNumber(seed);
	factor = exp(tuning * (ran - 0.5));
	newO = oldO * factor;
	
	/* check that new value is valid */
	isValidO = NO;
	do
		{
		if (newO < minO)
			newO = minO * minO / newO;
		else if (newO > maxO)
			newO = maxO * maxO / newO;
		else
			isValidO = YES;
		} while (isValidO == NO);

	/* get proposal ratio */
	*lnProposalRatio = log(newO / oldO);
	
	/* get prior ratio from Dirichlet */
	oldPropRatio = oldO / (oldO + 1.0);
	newPropRatio = newO / (newO + 1.0);
	x = ((alphaDir[0] - 1.0) * log(newPropRatio)) + ((alphaDir[1] - 1.0) * log (1.0 - newPropRatio));
	y = ((alphaDir[0] - 1.0) * log(oldPropRatio)) + ((alphaDir[1] - 1.0) * log (1.0 - oldPropRatio));
	(*lnPriorRatio) = x - y;
	
	/* copy new omega value back */
	*GetParamVals(param, chain, state[chain]) = newO;

	/* Set update flags for all partitions that share this omega. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);

	/* Set update flags for cijks for all affected partitions. If this is a simple 4 X 4 model,
	   we don't take any hit, because we will never go into a general transition probability
	   calculator. However, for covarion, doublet, and codon models, we do want to update
	   the cijk flag. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);

}





/*----------------------------------------------------------------
|
|	Move_OmegaBeta_M: Change parameters of the beta distribution
|      using multiplier for the M10 model. Note that this is 
|      appropriate when omegavar=M10
|
----------------------------------------------------------------*/
int Move_OmegaBeta_M (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, isValidVal, whichParam;
	MrBFlt		oldVal, newVal, minVal, maxVal, *vals, *subVals, tuning, ran, factor;
	ModelParams	*mp;
	
	/* do we pick alpha or beta of the Beta distribution to change */
	if (RandomNumber(seed) < 0.5)
		whichParam = 0;
	else
		whichParam = 1;

	/* get model params */
	mp = &modelParams[param->relParts[0]];

	/* get tuning parameter */
	tuning = mvp[0];

	/* get minimum and maximum values for omega */
	minVal = 0.05;
	maxVal = 100.0;

	/* get old value of omega */
	vals = GetParamVals(param, chain, state[chain]);
	subVals = GetParamSubVals(param, chain, state[chain]);
	oldVal = subVals[mp->numM10BetaCats + mp->numM10GammaCats + 4 + whichParam];

	/* change value for alpha/beta */
	ran = RandomNumber(seed);
	factor = exp(tuning * (ran - 0.5));
	newVal = oldVal * factor;
	
	/* check that new value is valid */
	isValidVal = NO;
	do
		{
		if (newVal < minVal)
			newVal = minVal * minVal / newVal;
		else if (newVal > maxVal)
			newVal = maxVal * maxVal / newVal;
		else
			isValidVal = YES;
		} while (isValidVal == NO);

	/* get proposal ratio */
	*lnProposalRatio = log(newVal / oldVal);
	
	/* get prior ratio */
	if (!strcmp(mp->m10betapr, "Exponential"))
		(*lnPriorRatio) = (log(mp->m10betaExp) - newVal * mp->m10betaExp) - (log(mp->m10betaExp) - oldVal * mp->m10betaExp);
	else
		(*lnPriorRatio) = 0.0;
	
	/* copy new omega value back */
	subVals[mp->numM10BetaCats + mp->numM10GammaCats + 4 + whichParam] = newVal;
	
	/* update the omega values */
	BetaBreaks (subVals[mp->numM10BetaCats + mp->numM10GammaCats + 4], subVals[mp->numM10BetaCats + mp->numM10GammaCats + 5], &vals[0], mp->numM10BetaCats);

	/* Set update flags for all partitions that share this kappa. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);

	/* Set update flags for cijks for all affected partitions. If this is a simple 4 X 4 model,
	   we don't take any hit, because we will never go into a general transition probability
	   calculator. However, for covarion, doublet, and codon models, we do want to update
	   the cijk flag. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);

}





/*----------------------------------------------------------------
|
|	Move_OmegaGamma_M: Change parameters of the gamma distribution
|      using multiplier for the M10 model. Note that this is 
|      appropriate whenomegavar=M10
|
----------------------------------------------------------------*/
int Move_OmegaGamma_M (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, isValidVal, whichParam;
	MrBFlt		oldVal, newVal, minVal, maxVal, *vals, *subVals, tuning, ran, factor, quantile95;
	ModelParams	*mp;
	
	/* do we pick alpha or beta of the Gamma distribution to change */
	if (RandomNumber(seed) < 0.5)
		whichParam = 0;
	else
		whichParam = 1;

	/* get model params */
	mp = &modelParams[param->relParts[0]];

	/* get tuning parameter */
	tuning = mvp[0];

	/* get minimum and maximum values for omega */
	minVal = 0.05;
	maxVal = 100.0;

	/* get values */
	vals = GetParamVals(param, chain, state[chain]);
	subVals = GetParamSubVals(param, chain, state[chain]);
	oldVal = subVals[mp->numM10BetaCats + mp->numM10GammaCats + 6 + whichParam];

	/* change value for alpha/beta */
	do
		{
		ran = RandomNumber(seed);
		factor = exp(tuning * (ran - 0.5));
		newVal = oldVal * factor;
		
		/* check that new value is valid */
		isValidVal = NO;
		do
			{
			if (newVal < minVal)
				newVal = minVal * minVal / newVal;
			else if (newVal > maxVal)
				newVal = maxVal * maxVal / newVal;
			else
				isValidVal = YES;
			} while (isValidVal == NO);

		/* check that the distribution does not go too far to the right */
		if (whichParam == 0)
			quantile95 = QuantileGamma (0.95, newVal, subVals[mp->numM10BetaCats + mp->numM10GammaCats + 7]);
		else
			quantile95 = QuantileGamma (0.95, subVals[mp->numM10BetaCats + mp->numM10GammaCats + 6], newVal);

		} while (quantile95 > 100.0);
		
	/* get proposal ratio */
	*lnProposalRatio = log(newVal / oldVal);
	
	/* get prior ratio */
	if (!strcmp(mp->m10gammapr, "Exponential"))
		(*lnPriorRatio) = (log(mp->m10gammaExp) - newVal * mp->m10gammaExp) - (log(mp->m10gammaExp) - oldVal * mp->m10gammaExp);
	else
		(*lnPriorRatio) = 0.0;
	
	/* copy new value back */
	subVals[mp->numM10BetaCats + mp->numM10GammaCats + 6 + whichParam] = newVal;
	
	/* update the omega values */
	if (DiscreteGamma (&vals[mp->numM10BetaCats], subVals[mp->numM10BetaCats + mp->numM10GammaCats + 6], subVals[mp->numM10BetaCats + mp->numM10GammaCats + 7], mp->numM10GammaCats, 0) == ERROR)
		return (ERROR);
	for (i=0; i<mp->numM10GammaCats; i++)
		vals[mp->numM10BetaCats + i] += 1.0;

	/* Set update flags for all partitions that share this kappa. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);

	/* Set update flags for cijks for all affected partitions. If this is a simple 4 X 4 model,
	   we don't take any hit, because we will never go into a general transition probability
	   calculator. However, for covarion, doublet, and codon models, we do want to update
	   the cijk flag. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);

}





int Move_OmegaCat (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, localNumCats, numBetaAndGammaCats;
	MrBFlt		dirichletParameters[3], *newSubVals, *oldSubVals, *newFreqs, *oldFreqs, *priorParams, sum, alpha, x, y;
	ModelParams	*mp;

	/* get model params */
	mp = &modelParams[param->relParts[0]];

	/* how many categories are there */
	localNumCats = 3;
	numBetaAndGammaCats = 0;
	if (!strcmp(mp->omegaVar, "M10"))
		{
		localNumCats = 2;
		numBetaAndGammaCats = mp->numM10BetaCats + mp->numM10GammaCats;
		}
		
	/* get the values we need */
	newSubVals = GetParamSubVals (param, chain, state[chain]);
	oldSubVals = GetParamSubVals (param, chain, state[chain] ^ 1);
	if (!strcmp(mp->omegaVar, "M10"))
		{
		newFreqs = newSubVals + numBetaAndGammaCats;
		oldFreqs = oldSubVals + numBetaAndGammaCats;
		priorParams = newSubVals + (numBetaAndGammaCats + 2);
		}
	else
		{
		newFreqs = newSubVals + 0;
		oldFreqs = oldSubVals + 0;
		priorParams = newFreqs + 3;
		}

	/* get parameter of proposal mechanism */
	alpha = mvp[0];

	/* multiply old values with some large number to get new values close to the old ones */
	for (i=0; i<localNumCats; i++)
		dirichletParameters[i] = oldFreqs[i] * alpha;

	/* get the new category frequencies */
	DirichletRandomVariable (dirichletParameters, newFreqs, localNumCats, seed);
	sum = 0.0;
	for (i=0; i<localNumCats; i++)
		{
		if (newFreqs[i] < 0.0001)
			newFreqs[i] = 0.0001;
		sum += newFreqs[i];
		}
	for (i=0; i<localNumCats; i++)
		newFreqs[i] /= sum;
		
	/* and get the new frequencies of the omega values, if we have another
	   distribution for omega too */
	if (!strcmp(mp->omegaVar, "M10"))
		{
		for (i=0; i<mp->numM10BetaCats; i++)
			newSubVals[i] = newFreqs[0] / mp->numM10BetaCats;
		for (i=mp->numM10BetaCats; i<mp->numM10BetaCats+mp->numM10GammaCats; i++)
			newSubVals[i] = newFreqs[1] / mp->numM10GammaCats;
		}	

	/* get proposal ratio */
	sum = 0.0;
	for (i=0; i<localNumCats; i++)
		sum += newFreqs[i]*alpha;
	x = LnGamma(sum);
	for (i=0; i<localNumCats; i++)
		x -= LnGamma(newFreqs[i]*alpha);
	for (i=0; i<localNumCats; i++)
		x += (newFreqs[i]*alpha-1.0)*log(oldFreqs[i]);
	sum = 0.0;
	for (i=0; i<localNumCats; i++)
		sum += oldFreqs[i]*alpha;
	y = LnGamma(sum);
	for (i=0; i<localNumCats; i++)
		y -= LnGamma(oldFreqs[i]*alpha);
	for (i=0; i<localNumCats; i++)
		y += (oldFreqs[i]*alpha-1.0)*log(newFreqs[i]);
	(*lnProposalRatio) = x - y;

	/* get prior ratio */
	x = y = 0.0;        /* ignore the gamma part, it is identical */
	for (i=0; i<localNumCats; i++)
		x += (priorParams[i]-1.0)*log(newFreqs[i]);
	for (i=0; i<localNumCats; i++)
		y += (priorParams[i]-1.0)*log(oldFreqs[i]);
	(*lnPriorRatio) = x - y;
		
	/* Set update flags for all partitions that share this omega. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);

	/* Set update flags for cijks for all affected partitions. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);
	
}





/*----------------------------------------------------------------
|
|	Move_OmegaM3: Change the nonysnonymous/synonymous rate ratio
|      of one class of the M3 model
|
----------------------------------------------------------------*/
int Move_OmegaM3 (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, isValidO, whichOmega;
	MrBFlt		newO, window, minO, maxO, ran, *value, *oldValue, x, y;
	ModelParams *mp;

	/* get size of window, centered on current omega value */
	window = mvp[0];

	/* get model params */
	mp = &modelParams[param->relParts[0]];

	/* get old value of omega */
	value = GetParamVals(param, chain, state[chain]);
    oldValue = GetParamVals(param, chain, state[chain]^1);
	whichOmega = (int) (RandomNumber(seed)*3.0);
	
	/* get minimum and maximum values for omega */
	if (whichOmega == 0)
        minO = 0.0;
    else
        minO = value[whichOmega-1];
    if (whichOmega == 2)
        maxO = OMEGA_MAX;
    else
    	maxO = value[whichOmega+1];

	/* change value for omega */
	ran = RandomNumber(seed);
	 if( maxO-minO < window )
		{
		window = maxO-minO;
		}
	newO = oldValue[whichOmega] + window * (ran - 0.5);
	
	/* check that new value is valid */
	isValidO = NO;
	do
		{
		if (newO < minO)
			newO = 2* minO - newO;
		else if (newO > maxO)
			newO = 2 * maxO - newO;
		else
			isValidO = YES;
		} while (isValidO == NO);

	/* copy new omega value back */
	value[whichOmega] = newO;

	/* get proposal ratio */
	*lnProposalRatio = 0.0;
	
    /* get prior ratio */
	x = LogOmegaPrior (value[0], value[1], value[2]);
	y = LogOmegaPrior (oldValue[0], oldValue[1], oldValue[2]);
    *lnPriorRatio = x - y;

	/* Set update flags for all partitions that share this omega. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);

	/* Set update flags for cijks for all affected partitions. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);

}





/*----------------------------------------------------------------
|
|	Move_OmegaNeu: Change the nonysnonymous/synonymous rate ratio
|      for neutral sites
|
----------------------------------------------------------------*/
int Move_OmegaNeu (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, isOPriorExp, isValidO;
	MrBFlt		oldO, newO, window, minO, maxO, ran, *value, x, y;
	ModelParams *mp;

	/* get size of window, centered on current omega value */
	window = mvp[0];

	/* get model params */
	mp = &modelParams[param->relParts[0]];

	/* get old value of omega */
	value = GetParamVals(param, chain, state[chain]);
	newO = oldO = value[1];

	/* get minimum and maximum values for omega */
	minO = value[0];
	maxO = value[2];
	
	/* the only way we would be updating the middle category (omega2) is
	   if we have an exponential prior on all three omegas */
	isOPriorExp = YES;

	/* change value for omega */
	ran = RandomNumber(seed);
	if( maxO-minO < window )
		{
		window = maxO-minO;
		}
	newO = oldO + window * (ran - 0.5);
	
	/* check that new value is valid */
	isValidO = NO;
	do
		{
		if (newO < minO)
			newO = 2 * minO - newO;
		else if (newO > maxO)
			newO = 2 * maxO - newO;
		else
			isValidO = YES;
		} while (isValidO == NO);

	/* get proposal ratio */
	*lnProposalRatio = 0.0;
	
	/* copy new omega value back */
	value[1] = newO;

	/* get prior ratio */
	if (isOPriorExp == NO)
		{
		*lnPriorRatio = 0.0;
		}
	else
		{
		x = LogOmegaPrior (value[0], newO, value[2]);
		y = LogOmegaPrior (value[0], oldO, value[2]);
		*lnPriorRatio = x - y;
		}

	/* Set update flags for all partitions that share this omega. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);

	/* Set update flags for cijks for all affected partitions. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);

}





/*----------------------------------------------------------------
|
|	Move_OmegaPos: Change the nonysnonymous/synonymous rate ratio
|      for positively selected sites
|
----------------------------------------------------------------*/
int Move_OmegaPos (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, isValidO, omegaUni, omegaExp1, omegaExp2;
	MrBFlt		oldO, newO, window, minO=0.0, maxO=0.0, ran, *value, x, y;
	ModelParams *mp;

	/* get size of window, centered on current omega value */
	window = mvp[0];

	/* get model params */
	mp = &modelParams[param->relParts[0]];

	/* get old value of omega */
	value = GetParamVals(param, chain, state[chain]);
	newO = oldO = value[2];
	
	/* determine prior for omega */
	omegaUni = omegaExp1 = omegaExp2 = NO;
	if (param->paramId == OMEGA_BUD || param->paramId == OMEGA_BUF || param->paramId == OMEGA_FUD || param->paramId == OMEGA_FUF)
		omegaUni = YES;
	else if (param->paramId == OMEGA_BED || param->paramId == OMEGA_BEF || param->paramId == OMEGA_FED || param->paramId == OMEGA_FEF)
		omegaExp1 = YES;
	else if (param->paramId == OMEGA_ED || param->paramId == OMEGA_EF)
		omegaExp2 = YES;
		
	/* get minimum and maximum values for omega */
	if (omegaUni == YES)
		{
		minO = mp->ny98omega3Uni[0];
		if (minO < value[1])
			minO = value[1];
		maxO = mp->ny98omega3Uni[1];
		if (maxO > KAPPA_MAX)
			maxO = KAPPA_MAX;
		}
	else if (omegaExp1 == YES || omegaExp2 == YES)
		{
		minO = value[1];
		maxO = KAPPA_MAX;
		}

	/* change value for omega */
	ran = RandomNumber(seed);
	if( maxO-minO < window )
		{
		window = maxO-minO;
		}
	newO = oldO + window * (ran - 0.5);
	
	/* check that new value is valid */
	isValidO = NO;
	do
		{
		if (newO < minO)
			newO = 2* minO - newO;
		else if (newO > maxO)
			newO = 2 * maxO - newO;
		else
			isValidO = YES;
		} while (isValidO == NO);

	/* get proposal ratio */
	*lnProposalRatio = 0.0;
	
	/* copy new omega value back */
	value[2] = newO;

	/* get prior ratio (part 2) */
	if (omegaUni == YES)
		{
		*lnPriorRatio = 0.0;
		}
	else if (omegaExp1 == YES)
		{
        *lnPriorRatio = mp->ny98omega3Exp * (oldO - newO);
		}
	else if (omegaExp2 == YES)
		{
		x = LogOmegaPrior (value[0], value[1], newO);
		y = LogOmegaPrior (value[0], value[1], oldO);
		*lnPriorRatio = x - y;
		}

	/* Set update flags for all partitions that share this omega. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);

	/* Set update flags for cijks for all affected partitions. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);

}





/*----------------------------------------------------------------
|
|	Move_OmegaPur: Change the nonysnonymous/synonymous rate ratio
|      for purifying selection sites
|
----------------------------------------------------------------*/
int Move_OmegaPur (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, isOPriorExp, isValidO;
	MrBFlt		oldO, newO, window, minO, maxO, ran, *value, x, y;
	ModelParams *mp;

	/* get size of window, centered on current omega value */
	window = mvp[0];

	/* get model params */
	mp = &modelParams[param->relParts[0]];

	/* get old value of omega */
	value = GetParamVals(param, chain, state[chain]);
	newO = oldO = value[0];
	
	/* get minimum and maximum values for omega */
	minO = 0.0;
	maxO = value[1];
	
	/* get prior for omega */
	if (param->paramId == OMEGA_BUD || param->paramId == OMEGA_BUF || param->paramId == OMEGA_BED || 
		param->paramId == OMEGA_BEF || param->paramId == OMEGA_BFD || param->paramId == OMEGA_BFF) 
		isOPriorExp = NO;
	else
		isOPriorExp = YES;

	/* change value for omega */
	ran = RandomNumber(seed);
	if( maxO-minO < window )
		{
		window = maxO-minO;
		}
	newO = oldO + window * (ran - 0.5);
	
	/* check that new value is valid */
	isValidO = NO;
	do
		{
		if (newO < minO)
			newO = 2* minO - newO;
		else if (newO > maxO)
			newO = 2 * maxO - newO;
		else
			isValidO = YES;
		} while (isValidO == NO);

	/* get proposal ratio */
	*lnProposalRatio = 0.0;
	
	/* copy new omega value back */
	value[0] = newO;

	/* get prior ratio (part 2) */
	if (isOPriorExp == NO)
		{
		*lnPriorRatio = 0.0;
		}
	else
		{
		x = LogOmegaPrior (newO, value[1], value[2]);
		y = LogOmegaPrior (oldO, value[1], value[2]);
		*lnPriorRatio = x - y;
		}

	/* Set update flags for all partitions that share this omega. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);

	/* Set update flags for cijks for all affected partitions. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);

}





/*----------------------------------------------------------------
|
|	Move_ParsEraser1: This proposal mechanism changes the topology and
|      branch lengths of an unrooted tree. A randomly chosen region of
|      the tree is erased. Parsimony is used to guide the selection of
|	   a new topology for the erased part of the tree. The parsimony
|      branch lengths are used to guide the proposal of new branch
|      lengths. This variant (1) uses exhaustive enumeration.
|
|      Programmed by FR 2004-10-23--
|
----------------------------------------------------------------*/
int Move_ParsEraser1 (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, j, isVPriorExp, nSubTerminals, nEmbeddedTrees;
	MrBFlt		alphaPi, warp, minV, maxV, minP, maxP, brlensExp=0.0, newM, oldM, maxLen,
				*brlensCur, *brlensNew, *parslensCur, *parslensNew,
				curLength, newLength, lnJacobian, lnRandomRatio, alpha[2], prob[2],
				minLenCur, minLenNew, f;
	TreeNode	*p=NULL;
	Tree		*t, *subtree, *subtree1, memTree[2];
	ModelParams *mp;
	ModelInfo	*m;
	TreeInfo	tInfo;

	/* set pointers to NULL */
	subtree = subtree1 = NULL;
	brlensCur = NULL;
	for (i=0; i<2; i++)
		{
		memTree[i].allDownPass = NULL;
		memTree[i].intDownPass = NULL;
		memTree[i].nodes = NULL;
		}
	tInfo.leaf = NULL;

	/* Set alpha Pi for Dirichlet p generator */
	alphaPi = mvp[0];
	alphaPi = 0.05;
	
	/* Set the parsimony warp factor */
	warp = mvp[1];
	warp = 0.2;
	
	/* Set the number of terminals (nSubTerminals, column 3) in erased tree */
	/* Erased Nodes => Leaves => Terminals => Embedded trees => Embedded histories => New trees
                  2 => 3      => 4         => 2              => 2 = 2!             => 3 = 1*3
                  3 => 4      => 5         => 5              => 6 = 3!             => 15 = 1*3*5
				  4 => 5      => 6         => 14             => 24 = 4!            => 105 = 1*3*5*7
				  5 => 6      => 7         => 42             => 120 = 5!           => 945 = 1*3*5*7*9
				  etc				*/	
	nSubTerminals = (int) (RandomNumber (seed) * 4) + 4;
	nSubTerminals = 7;

	/* initialize log prior and log proposal probabilities */
	*lnPriorRatio = *lnProposalRatio = 0.0;
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* max and min brlen */
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}
	minP = 3.0 * ((1.0 / 4.0) - ((1.0 / 4.0) * exp (-4.0 * minV / 3.0)));
	maxP = 3.0 * ((1.0 / 4.0) - ((1.0 / 4.0) * exp (-4.0 * maxV / 3.0)));
			
	/* allocate some memory for this move */
	brlensCur = (MrBFlt *) SafeMalloc (8 * nSubTerminals * sizeof (MrBFlt));
	if (!brlensCur)
		{
		MrBayesPrint ("%s   ERROR: Could not allocate brlensCur\n", spacer);
		goto errorExit;
		}
	brlensNew = brlensCur + 2*nSubTerminals;
	parslensCur = brlensCur + 4 * nSubTerminals;
	parslensNew = brlensCur + 6 * nSubTerminals;

	subtree = &memTree[0];
	subtree->nNodes = 2 * nSubTerminals - 2;
	subtree->nIntNodes = nSubTerminals - 2;
	subtree->nodes = (TreeNode *) SafeCalloc (subtree->nNodes, sizeof (TreeNode));
	subtree->allDownPass = (TreeNode **) SafeCalloc (subtree->nNodes, sizeof (TreeNode *));
	subtree->intDownPass = (TreeNode **) SafeCalloc (subtree->nIntNodes, sizeof (TreeNode *));
	if (!subtree->nodes || !subtree->intDownPass || !subtree->allDownPass)
		{
		MrBayesPrint ("%s   ERROR: Could not allocate subtree\n", spacer);
		goto errorExit;
		}

	subtree1 = &memTree[1];
	subtree1->nNodes = 2 * nSubTerminals - 2;
	subtree1->nIntNodes = nSubTerminals - 2;
	subtree1->nodes = (TreeNode *) SafeCalloc (subtree1->nNodes, sizeof (TreeNode));
	subtree1->allDownPass = (TreeNode **) SafeCalloc (subtree1->nNodes, sizeof (TreeNode *));
	subtree1->intDownPass = (TreeNode **) SafeCalloc (subtree1->nIntNodes, sizeof (TreeNode *));
	if (!subtree1->nodes || !subtree1->intDownPass || !subtree1->allDownPass)
		{
		MrBayesPrint ("%s   ERROR: Could not allocate subtree1\n", spacer);
		goto errorExit;
		}

	tInfo.leaf = (TreeNode **) SafeCalloc (t->nNodes, sizeof(TreeNode *));
	if (!tInfo.leaf)
		{
		MrBayesPrint ("%s   ERROR: Could not allocate tInfo.leaf\n", spacer);
		goto errorExit;
		}
	tInfo.vertex = tInfo.leaf + t->nNodes - t->nIntNodes;

	/* Select a random embedded subtree with nSubTerminals terminals */
	if (GetRandomEmbeddedSubtree (t, nSubTerminals, seed, &nEmbeddedTrees) == ERROR)
		{
		MrBayesPrint ("%s   ERROR: Could not get subtree\n", spacer);
		goto errorExit;
		}

	/* Set update flags (We'd better do it before the marked nodes disappear) */
	for (i=0; i<t->nIntNodes; i++)
		{
		p = t->intDownPass[i];
		if (p->marked == YES)
			{
			p->upDateCl = YES; 
			p->upDateTi = YES;
			}
		else if (p->left->upDateCl == YES || p->right->upDateCl == YES)
		        p->upDateCl = YES; 
		}

	/* Fill in subtrees */
	CopyTreeToSubtree (t, subtree);	
	CopyTreeToSubtree (t, subtree1);

	/* Calculate downstates and upstate of root node of subtree */
	GetParsDP (t, t->root->left, chain);
	for (i=0; i<t->nIntNodes; i++)
		{
		p = t->intDownPass[i];
		if (p->marked == YES && p->anc->marked == NO)
			break;
		}
	GetParsimonySubtreeRootstate (t, p->anc, chain);

	/* Get parsimony length of current tree */
	curLength = GetParsimonyLength (subtree, chain);
	
	/* Get the Markov and parsimony branch lengths of the current subtree */
	GetParsimonyBrlens (subtree, chain, parslensCur);
	for (i=0; i<subtree->nNodes-1; i++)
		brlensCur[i] = subtree->allDownPass[i]->length;

	/* Calculate parsimony score of all trees relative to shortest tree (1.0) */
	tInfo.totalScore = 0.0;
	tInfo.stopScore = -1.0;
	tInfo.minScore = curLength;
	tInfo.warp = warp;
	ExhaustiveParsimonySearch (subtree, chain, &tInfo);
		
	/* Choose one of these trees randomly based on its score */
	tInfo.stopScore = RandomNumber(seed) * tInfo.totalScore;
	tInfo.totalScore = 0.0;
	ExhaustiveParsimonySearch (subtree1, chain, &tInfo);
	/* ShowNodes (subtree1->root, 0 , NO); */
	/* getchar(); */

	/* Get length of that tree */

	newLength = GetParsimonyLength (subtree1, chain);

	/* Get the parsimony branch lengths of the new subtree */
	GetParsimonyBrlens (subtree1, chain, parslensNew);

	/* Find the maximum length of a branch */
	maxLen = 0.0;
	for (i=0; i<t->nRelParts; i++)
		{
		j = t->relParts[i];
		m = &modelSettings[j];
		maxLen += m->numUncompressedChars;
		}
	
	/* Find the Markov branch lengths of the new subtree */
	/* Calculate Jacobian and prob ratio for the Dirichlet random number generator */
	lnJacobian = lnRandomRatio = 0.0;
	minLenCur = minLenNew = 0.0;
	for (i=0; i<subtree1->nNodes-1; i++)
		{
		minLenCur += parslensCur[i];
		minLenNew += parslensNew[i];
		}
	for (i=0; i<subtree1->nNodes-1; i++)
		{
		p = subtree1->allDownPass[i];
		f = newLength / minLenNew;
		alpha[0] = parslensNew[i] * f * alphaPi + 1.0;
		alpha[1] = (maxLen - parslensNew[i] * f) * alphaPi + 1.0;
		DirichletRandomVariable (alpha, prob, 2, seed);
		if (prob[0] >= maxP || prob[0] <= minP)
			{
			abortMove = YES;
			return NO_ERROR;
			}

		p->length = (-3.0 / 4.0) * log (1.0 - 4.0 * prob[0] / 3.0);
		lnJacobian += (-4.0 * brlensCur[i] / 3.0) - log (1.0 - 4.0 * prob[0] / 3.0);
		lnRandomRatio -= log (pow (prob[0], alpha[0] - 1.0) * pow (prob[1], alpha[1] - 1.0));
		f = curLength / minLenNew;
		alpha[0] = parslensCur[i] * f * alphaPi + 1.0;
		alpha[1] = (maxLen - parslensCur[i] * f) * alphaPi + 1.0;
		prob[0] = 3.0 * ((1.0 / 4.0) - ((1.0 / 4.0) * exp (-4.0 * brlensCur[i] / 3.0)));
		prob[1] = 1.0 - prob[0];
		lnRandomRatio += log (pow (prob[0], alpha[0] - 1.0) * pow (prob[1], alpha[1] - 1.0));
		}

	/* Store the new Markov branch lengths */
	for (i=0; i<subtree1->nNodes-1; i++)
		brlensNew[i] = subtree1->allDownPass[i]->length;

	/* Calculate the proposal ratio */
	(*lnProposalRatio) = lnJacobian + lnRandomRatio + log (warp/3.0) * (curLength - newLength) + log (1.0-warp) * (newLength - curLength);

	/* Calculate the prior ratio */
	if (isVPriorExp == YES)
		{
		newM = oldM = 0.0;
		for (i=0; i<subtree->nNodes-1; i++)
			{
			oldM += brlensCur[i];
			newM += brlensNew[i];
			}
		(*lnPriorRatio) += brlensExp * (oldM - newM);
		}

	/* Copy subtree into tree */
	CopySubtreeToTree (subtree1, t);
	/* ShowNodes (subtree1->root, 0, NO); */
	/* ShowNodes (t->root, 0, NO); */

	/* Update node sequences */
	GetDownPass (t);
	
	/* correct for difference in number of embedded subtrees */
	if (GetRandomEmbeddedSubtree (t, nSubTerminals, seed, &i) == ERROR)
		{
		MrBayesPrint ("%s   Could not count number of subtrees in Move_ParsEraser1\n", spacer);
		goto errorExit;
		}
	if (i != nEmbeddedTrees)
		(*lnProposalRatio) += log ((MrBFlt) nEmbeddedTrees / (MrBFlt) i);

	/* Free memory allocated for this move */
	free (subtree->allDownPass);
	free (subtree->intDownPass);
	free (subtree->nodes);
	free (subtree1->allDownPass);
	free (subtree1->intDownPass);
	free (subtree1->nodes);
	free (brlensCur);
	free (tInfo.leaf);

	return (NO_ERROR);

errorExit:

	free (subtree->allDownPass);
	free (subtree->intDownPass);
	free (subtree->nodes);
	free (subtree1->allDownPass);
	free (subtree1->intDownPass);
	free (subtree1->nodes);
	free (brlensCur);
	free (tInfo.leaf);

	return (ERROR);

}





int Move_ParsSPR (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* Change branch lengths and topology (potentially) using SPR-type move 
	   biased according to parsimony scores. */

	int		    i, j, n, division, topologyHasChanged, isVPriorExp;
	SafeLong	*pA, *pV, *pP, y[2];
	MrBFlt		x, minV, maxV, brlensExp, minLength=0.0, curLength=0.0, length = 0.0,
		        cumulativeProb, warpFactor, sum, ran, tuning, increaseProb, decreaseProb,
				divFactor, nStates, rateMult, v_typical;
	CLFlt       *nSitesOfPat, *nSites, *globalNSitesOfPat;
	TreeNode	*p, *q, *a, *b, *u, *v, *c=NULL, *d;
	Tree		*t;
	ModelParams *mp;
	ModelInfo	*m = NULL;

	warpFactor = mvp[0];	                /* tuning parameter determining how heavily to weight according to parsimony scores */
	tuning = mvp[1];		                /* multiplier tuning parameter */
	increaseProb = decreaseProb = mvp[2];	/* reweighting probabilities */
    v_typical = 0.05;                       /* typical branch length for conversion of parsimony score to log prob ratio */

	(*lnProposalRatio) = (*lnPriorRatio) = 0.0;

	/* get model params and model info */
	mp = &modelParams[param->relParts[0]];
	m = &modelSettings[param->relParts[0]];
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* max and min brlen */
	brlensExp = 0.0;
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}

#if defined (DEBUG_CONSTRAINTS)
	CheckConstraints (t);
#endif

#	if defined (DEBUG_ParsSPR)
	printf ("Before:\n");
	ShowNodes (t->root, 2, YES);
	getchar();
#	endif
	
	/* set topologyHasChanged to NO */
	topologyHasChanged = NO;
	
	/* reset node variables that will be used */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		p->marked = NO;
		p->d = 0;
		}

	/* pick a random branch, making sure it can move either up or down */
	do
		{
		p = t->allDownPass[(int)(RandomNumber(seed)*(t->nNodes - 2))];
		if (p->anc->left == p)
			q = p->anc->right;
		else
			q = p->anc->left;
		} while ((p->anc->anc->anc == NULL || p->anc->isLocked == YES) && (q->left == NULL || q->isLocked == YES));
		
	/* set up pointers for nodes around the picked branch */
	v = p;
	u = p->anc;
	if (u->left == v)
		a = u->right;
	else
		a = u->left;
	b = u->anc;

	/* clip tree */
	a->anc = b;
	if (b->left == u)
		b->left = a;
	else
		b->right = a;

	/* get final parsimony states for the root part */
	GetParsDP (t, t->root->left, chain);
	GetParsFP (t, t->root->left, chain);

	/* get downpass parsimony states for the crown part */
	GetParsDP (t, v, chain);

	/* mark all nodes in the root part of the tree, taking constraints into account */
	/* first mark a */
	a->marked = YES;
	/* then move down towards root */
	if (u->isLocked == NO)
		{
		p = a->anc;
        while( p->anc != NULL)
            {
            p->marked = YES;
            if( p->isLocked == YES )
                break;
			p = p->anc;
			}
		}

	/* finally move up */
	for (i=t->nNodes-2; i>=0; i--)
		{
		p = t->allDownPass[i];
		if (p->marked == NO && p->anc->marked == YES && p->anc->isLocked == NO && p != u)
			p->marked = YES;
		}		

	/* find number of site patterns and modify randomly */
	globalNSitesOfPat = numSitesOfPat + ((chainId[chain] % chainParams.numChains) * numCompressedChars) + m->compCharStart;
	nSitesOfPat = (CLFlt *) SafeCalloc (numCompressedChars, sizeof(CLFlt));
	if (!nSitesOfPat)
		{
		MrBayesPrint ("%s   Problem allocating nSitesOfPat in Move_ParsSPR\n", spacer);
		return (ERROR);
		}
	for (i=0; i<numCompressedChars; i++)
		{
		nSitesOfPat[i] = globalNSitesOfPat[i];
		for (j=0; j<globalNSitesOfPat[i]; j++)
			{
			ran = RandomNumber (seed);
			if (ran < decreaseProb)
				nSitesOfPat[i]--;
			else if (ran > 1.0 - increaseProb)
				nSitesOfPat[i]++;
			}
		}

	/* cycle through the possibilities and record the parsimony length of each in p->d */
	minLength = -1.0;
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->marked == NO)
			continue;
		/* find the parsimony length */
		p->d = 0.0;
		for (n=0; n<t->nRelParts; n++)
			{
			division = t->relParts[n];
			
			/* Find model settings */
			m = &modelSettings[division];

			/* find nStates and ratemult */
			nStates = m->numModelStates;
			if (m->dataType == STANDARD)
				nStates = 2;
			rateMult = GetRate(division, chain);

			/* find nSitesOfPat */
			nSites = nSitesOfPat + m->compCharStart;

			/* get division warp factor */
			divFactor = - (warpFactor * log((1.0/nStates) - exp(-(nStates/(nStates-1)*v_typical*rateMult))/nStates));

			/* find downpass parsimony sets for the node and its environment */
			pP   = m->parsSets[p->index     ];
			pA   = m->parsSets[p->anc->index];
			pV   = m->parsSets[v->index     ];
		
			length = 0.0;
            if (m->nParsIntsPerSite == 1)
                {
		        for (j=0; j<m->numChars; j++)
			        {
			        y[0] = (pP[j] | pA[j]) & pV[j];
			        if (y[0] == 0)
				        length += nSites[j];
			        }
                }
            else /* if (m->nParsIntsPerSite == 2) */
                {
                for (j=0; j<2*m->numChars; j+=2)
		            {
			        y[0] = (pP[j] | pA[j]) & pV[j];
			        y[1] = (pP[j+1] | pA[j+1]) & pV[j+1];
			        if ((y[0] | y[1]) == 0)
                        length += nSites[j/2];
			        }
                }
			p->d += divFactor * length;
			}
		if (minLength < 0.0)
			minLength = p->d;
		else if (p->d < minLength)
			minLength = p->d;
		if (p == a)
			curLength = p->d;
		}

	/* find the sum given the warp factor */
	sum = 0.0;
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->marked == YES)
			{
			p->d = exp (minLength - p->d);
			if (p != a)
                sum += p->d;
			}
		}

	/* generate a random uniform */
	ran = RandomNumber (seed);

	/* select the appropriate reattachment point */
	cumulativeProb = 0.0;
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->marked == YES && p != a)
			{
			c = p;
			cumulativeProb += p->d / sum;
			if (cumulativeProb > ran)
				break;
			}
		}

    /* calculate the proposal ratio */
	(*lnProposalRatio) = log ( (a->d /(sum - c->d + a->d)) / (c->d / sum) );

	/* reattach */
	d = c->anc;
	c->anc = u;
	if (u->left == v)
		u->right = c;
	else
		u->left = c;
	if (d->left == c)
		d->left = u;
	else
		d->right = u;
	u->anc = d;

	/* transfer lock if necessary */
	if (c != a)
		{
		/* if u is locked, then we have moved upwards and need
		   to leave the u lock behind */
		if (u->isLocked == YES)
			{
			u->isLocked = NO;
			a->isLocked = YES;
			a->lockID = u->lockID;
			u->lockID = -1;
			}
		/* if c is on root path and locked, we need to transfer
		   lock to u */
		p = b;
		while (p != NULL)
			{
			if (p == c)
				break;
			p = p->anc;
			}
		if (p == c && c->isLocked == YES)
			{
			u->isLocked = YES;
			u->lockID = c->lockID;
			c->isLocked = NO;
			c->lockID = -1;
			}
		}

	/* reassign branch lengths */
	if (c != a)
		{
		topologyHasChanged = YES;
		p = c;
        while (p->anc->anc != NULL)
            {
            if (p == a)
                break;
            p = p->anc;
            }
        if (p == a)
			{
			/* c is descendant to a so move a->length and not u->length */
            x = u->length;
			u->length = a->length;
			a->length = x;
			}
		p = a;
        while (p->anc->anc != NULL)
            {
            if (p == c)
                break;
            p = p->anc;
            }
		if (p == c)
			{
            /* c is ancestor to a so insert above instead of below */
			x = c->length;
			c->length = u->length;
			u->length = x;
			}
		/* hit c length with multiplier (a and u dealt with below) */
		x = c->length * exp(tuning * (RandomNumber(seed) - 0.5));
		while (x < minV || x > maxV)
			{
			if (x < minV)
				x = minV * minV / x;
			else if (x > maxV)
				x = maxV * maxV / x;
			}
		/* calculate proposal and prior ratio based on length modification */
		(*lnProposalRatio) += log (x / c->length);
		if (isVPriorExp == YES)
			(*lnPriorRatio) += brlensExp * (c->length - x);
		c->length = x;
		}
	
	/* hit a length with multiplier (even if no topology change was made) */
	x = a->length * exp(tuning * (RandomNumber(seed) - 0.5));
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}

	/* calculate proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / a->length);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (a->length - x);
	a->length = x;

	/* hit u length with multiplier (even if no topology change was made) */
	x = u->length * exp(tuning * (RandomNumber(seed) - 0.5));
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}

	/* calculate proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / u->length);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (u->length - x);
	u->length = x;

	/* set tiprobs update flags */
	a->upDateTi = YES;
	u->upDateTi = YES;
	c->upDateTi = YES;	/* could be same as a but that does not matter */

	/* set flags for update of cond likes from u and down to root */
	p = u;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* set flags for update of cond likes from b and down to root */
	p = b;
	while (p->anc != NULL && p->upDateCl == NO)
		{
		p->upDateCl = YES; 
		p = p->anc;
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}

	/* flag whether topology change was proposed */
    if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

	free (nSitesOfPat);

#	if defined (DEBUG_ParsSPR)
	printf ("After:\n");
	ShowNodes (t->root, 2, YES);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  a: %d  b: %d\n",v->index, u->index, a->index, b->index);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

	gNodeMoves = nRootNodes;
#	endif

#if defined DEBUG_CONSTRAINTS
	CheckConstraints (t);
#endif

	return (NO_ERROR);

}





int Move_ParsSPRClock (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* Change branch lengths and topology (potentially) using SPR-type move, 
	   parsimony-biased */

	/* This move picks a branch and then chooses a reattachment point based on
       the parsimony score. On the ending branch, the attachment point is reinserted
       randomly along the branch (below the minimum age of the node). Since 2010-11-02
       the move is Metropolized to improve efficiency. */
	
	int		    i, j, n, division, n1=0, n2=0, n3=0, n4=0, n5=0, *nEvents;
    SafeLong    *pA, *pV, *pP, y[2];
	MrBFlt		x, newPos, oldBrlen=0.0, newBrlen=0.0, v1=0.0, v2=0.0, v3=0.0, v4=0.0, v5=0.0,
                v3new=0.0, lambda, *tk02Rate=NULL, **position=NULL, **rateMultiplier=NULL, *brlens,
                igrvar, *igrRate, nu, origProp, newProp, minLength=0.0, curLength=0.0, length = 0.0,
		        cumulativeProb, warpFactor, sum, ran, increaseProb, decreaseProb,
				divFactor, nStates, rateMult, v_typical, minV, maxV, minB, maxB;
	CLFlt       *nSitesOfPat, *nSites, *globalNSitesOfPat;
	TreeNode	*p, *a, *b, *u, *v, *c=NULL, *d, *oldA;
	Tree		*t;
	ModelParams *mp;
	ModelInfo	*m = NULL;
	Param		*subParm;

	warpFactor = mvp[0];	/* tuning parameter determining how heavily to weight according to parsimony scores */
	increaseProb = decreaseProb = mvp[1];	/* reweighting probabilities */
    v_typical = 0.05;       /* typical branch length for converting parsimony scores to log prob ratios */

	(*lnProposalRatio) = (*lnPriorRatio) = 0.0;

	/* get tree */
	t = GetTree (param, chain, state[chain]);

	/* get model params and model info */
	mp = &modelParams[param->relParts[0]];
	m = &modelSettings[param->relParts[0]];
	
    /* get min and max brlen in relative time and subst units */
    minV = BRLENS_MIN;
    maxV = BRLENS_MAX;
    minB = RELBRLENS_MIN;
    maxB = RELBRLENS_MAX;

#	if defined (DEBUG_ParsSPRClock)
	printf ("Before:\n");
	ShowNodes (t->root, 2, YES);
	getchar();
#	endif
	
	/* pick a branch */
	do
		{
		p = t->allDownPass[(int)(RandomNumber(seed)*(t->nNodes - 1))];
		} while (p->anc->anc == NULL || p->anc->isLocked == YES || p->anc->anc->anc == NULL);
		
    /* set up pointers for nodes around the picked branch */
	v = p;
	u = p->anc;
	if (u->left == v)
		a = u->right;
	else
		a = u->left;
	b = u->anc;
    oldA = a;

	/* record branch length for insertion in back move */
	if (v->nodeDepth > a->nodeDepth)
		oldBrlen = b->nodeDepth - v->nodeDepth;
	else
		oldBrlen = b->nodeDepth - a->nodeDepth;

	v1 = a->length;
	v2 = u->length;
	v3 = v->length;
    origProp = u->length / oldBrlen;
    
    /* reassign events for CPP */
	for (i=0; i<param->subParams[0]->nSubParams; i++)
		{
		subParm = param->subParams[0]->subParams[i];
		if (subParm->paramType == P_CPPEVENTS)
			{
			nEvents = subParm->nEvents[2*chain+state[chain]];
			position = subParm->position[2*chain+state[chain]];
			rateMultiplier = subParm->rateMult[2*chain+state[chain]];
			n1 = nEvents[a->index];
			n2 = nEvents[u->index];
			n3 = nEvents[v->index];
			if (n2 > 0)
				{
				position[a->index] = (MrBFlt *) SafeRealloc ((void *) position[a->index], (n1+n2) * sizeof (MrBFlt));
				rateMultiplier[a->index] = (MrBFlt *) SafeRealloc ((void *) rateMultiplier[a->index], (n1+n2) * sizeof (MrBFlt));
				}
			for (j=0; j<n1; j++)
				position[a->index][j] *= v1 / (v1+v2);
			for (j=n1; j<n1+n2; j++)
				{
				position[a->index][j] = (position[u->index][j-n1] * v2 + v1) / (v1+v2);
				rateMultiplier[a->index][j] = rateMultiplier[u->index][j-n1];
				}
			nEvents[a->index] = n1+n2;
			nEvents[u->index] = 0;
			if (n2 > 0)
				{
				free (position[u->index]);
				free (rateMultiplier[u->index]);
				position[u->index] = rateMultiplier[u->index] = NULL;
				}
			/* adjust effective branch lengths */
			brlens = GetParamSubVals (subParm, chain, state[chain]);
			brlens[a->index] += brlens[u->index];	/* only change in effective branch lengths so far */
			}	/* end CPP events parm */
		else if (subParm->paramType == P_TK02BRANCHRATES)
			{
			/* adjust prior ratio */
			nu = *GetParamVals (modelSettings[subParm->relParts[0]].tk02var, chain, state[chain]);
			tk02Rate = GetParamVals (subParm, chain, state[chain]);
			(*lnPriorRatio) -= LnProbTK02LogNormal(tk02Rate[a->anc->index], nu*a->length, tk02Rate[a->index]);
			(*lnPriorRatio) -= LnProbTK02LogNormal(tk02Rate[v->anc->index], nu*v->length, tk02Rate[v->index]);
			(*lnPriorRatio) -= LnProbTK02LogNormal(tk02Rate[u->anc->index], nu*u->length, tk02Rate[u->index]);
			(*lnPriorRatio) += LnProbTK02LogNormal(tk02Rate[u->anc->index], nu*(a->length+u->length), tk02Rate[a->index]);
			/* adjust effective branch lengths */
			brlens = GetParamSubVals (subParm, chain, state[chain]);
			brlens[a->index] = ((tk02Rate[a->index] + tk02Rate[b->index]) / 2.0)*(a->length + u->length);
			}	/* end tk02 branch rate parameter */
        else if (subParm->paramType == P_IGRBRANCHLENS)
            {
            igrvar = *GetParamVals (modelSettings[subParm->relParts[0]].igrvar, chain, state[chain]);
            igrRate = GetParamVals (subParm, chain, state[chain]);
			brlens = GetParamSubVals (subParm, chain, state[chain]);

             /* adjust prior ratio for old branches */
            (*lnPriorRatio) -= LnProbTruncGamma(a->length/igrvar, 1.0/igrvar, brlens[a->index], minB, maxB);
			(*lnPriorRatio) -= LnProbTruncGamma(v->length/igrvar, 1.0/igrvar, brlens[v->index], minB, maxB);
			(*lnPriorRatio) -= LnProbTruncGamma(u->length/igrvar, 1.0/igrvar, brlens[u->index], minB, maxB);

            /* adjust effective branch lengths and rates */
            /* we move brens[u->index] to new location; Hastings ratio of alternative not worked out yet */
            // brlens[a->index] += brlens[u->index];
            igrRate[a->index] = brlens[a->index] / (a->length + u->length); /* times not changed yet */
    
            /* adjust prior ratio for new branch lengths */
			(*lnPriorRatio) += LnProbTruncGamma((a->length+u->length)/igrvar, 1.0/igrvar, brlens[a->index], minB, maxB);

            /*The following if (*lnPriorRatio != *lnPriorRatio) should be removed if LnProbTruncGamma() would be made more exact and would never return -infinity */
            if (*lnPriorRatio != *lnPriorRatio)
                {
                abortMove=YES;
                return (NO_ERROR);
                }
            }
		}	/* next subparameter */

    /* cut tree */
	a->anc = b;
	if (b->left == u)
		b->left = a;
	else
		b->right = a;
	a->length += u->length;
	a->upDateTi = YES;

	/* get final parsimony states for the root part */
	GetParsDP (t, t->root->left, chain);
	GetParsFP (t, t->root->left->left, chain);
    GetParsFP (t, t->root->left->right, chain);

	/* get downpass parsimony states for the crown part */
	GetParsDP (t, v, chain);

	/* reset node variables that will be used */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		p->marked = NO;
		p->d = 0.0;
		}

	/* mark all nodes in the root part of the tree, taking constraints into account */
    /* first mark a */
    a->marked = YES;
    
    /* then move down towards root taking constraints into account */
    p = b;
	while (p->isLocked == NO && p->anc->anc != NULL)
        {
        p->marked = YES;
		p = p->anc;
		}

    /* make sure sister of last node is marked because it will 
       not otherwise be marked in the uppass */
    p->left->marked = YES;
    p->right->marked = YES;

	/* finally move up */
	for (i=t->nNodes-2; i>=0; i--)
		{
		p = t->allDownPass[i];
		if (p->marked == NO && p->anc->marked == YES && p->anc->isLocked == NO && p != u &&
            p->anc->nodeDepth > v->nodeDepth + minV)
			p->marked = YES;
		}		
    
	/* find number of site patterns and modify randomly */
	globalNSitesOfPat = numSitesOfPat + ((chainId[chain] % chainParams.numChains) * numCompressedChars) + m->compCharStart;
	nSitesOfPat = (CLFlt *) SafeCalloc (numCompressedChars, sizeof(CLFlt));
	if (!nSitesOfPat)
		{
		MrBayesPrint ("%s   Problem allocating nSitesOfPat in Move_ParsSPRClock\n", spacer);
		return (ERROR);
		}
	for (i=0; i<numCompressedChars; i++)
		{
		nSitesOfPat[i] = globalNSitesOfPat[i];
		for (j=0; j<globalNSitesOfPat[i]; j++)
			{
			ran = RandomNumber (seed);
			if (ran < decreaseProb)
				nSitesOfPat[i]--;
			else if (ran > 1.0 - increaseProb)
				nSitesOfPat[i]++;
			}
		}

	/* cycle through the possibilities and record the parsimony length of each in p->d */
	minLength = - 1.0;
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->marked == NO)
			continue;
		/* find the parsimony length */
		p->d = 0.0;
		for (n=0; n<t->nRelParts; n++)
			{
			division = t->relParts[n];
			
			/* Find model settings */
			m = &modelSettings[division];

			/* find nStates and ratemult */
			nStates = m->numModelStates;
			if (m->dataType == STANDARD)
				nStates = 2;
			rateMult = GetRate(division, chain);

			/* find nSitesOfPat */
			nSites = nSitesOfPat + m->compCharStart;

			/* get division warp factor */
			divFactor = - (warpFactor * log((1.0/nStates) - exp(-(nStates/(nStates-1)*v_typical*rateMult))/nStates));

			/* find downpass parsimony sets for the node and its environment */
			pP   = m->parsSets[p->index     ];
            pA   = m->parsSets[p->anc->index];
			pV   = m->parsSets[v->index     ];
            
			length = 0.0;
            if (m->nParsIntsPerSite == 1)
                {
		        for (j=0; j<m->numChars; j++)
			        {
			        y[0] = (pP[j] | pA[j]) & pV[j];
			        if (y[0] == 0)
				        length += nSites[j];
			        }
                }
            else /* if (m->nParsIntsPerSite == 2) */
                {
                for (j=0; j<2*m->numChars; j+=2)
		            {
			        y[0] = (pP[j] | pA[j]) & pV[j];
			        y[1] = (pP[j+1] | pA[j+1]) & pV[j+1];
			        if ((y[0] | y[1]) == 0)
                        length += nSites[j/2];
			        }
                }
			p->d += divFactor * length;
			p->d += divFactor * length;
			}
		if (minLength < 0.0)
			minLength = p->d;
		else if (p->d < minLength)
			minLength = p->d;
		if (p == a)
			curLength = p->d;
		}

	/* find the sum given the warp factor */
	sum = 0.0;
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->marked == YES)
			{
			p->d = exp (minLength - p->d);
            if (p != a)
    			sum += p->d;
			}
		}

	/* generate a random uniform */
	ran = RandomNumber (seed);

	/* select the appropriate reattachment point (not a!) */
	cumulativeProb = 0.0;
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->marked == YES && p != a)
			{
			c = p;
			cumulativeProb += p->d / sum;
			if (cumulativeProb > ran)
				break;
			}
		}

    /* calculate the proposal ratio */
	(*lnProposalRatio) = log ( (a->d /(sum - c->d + a->d)) / (c->d / sum) );

	/* reattach u */
	d = c->anc;
	c->anc = u;
    if (u->left == v)
		u->right = c;
	else
		u->left = c;
	u->anc = d;
	if (d->left == c)
		d->left = u;
	else
		d->right = u;

	/* insert u randomly on branch below c */
	if (c->nodeDepth > v->nodeDepth)
		x = d->nodeDepth - c->nodeDepth;
	else
		x = d->nodeDepth - v->nodeDepth;
    newBrlen = x;

    if (x < 2.0 * minV)
        {
        abortMove = YES;
        free (nSitesOfPat);
        return (NO_ERROR);
        }
	newProp = RandomNumber(seed);
    newPos = newProp * (x - 2.0 * minV);

	/* adjust lengths */
	u->nodeDepth = d->nodeDepth - newPos - minV;
    u->length = d->nodeDepth - u->nodeDepth;
    c->length = u->nodeDepth - c->nodeDepth;
	v->length = u->nodeDepth - v->nodeDepth;
	
	v3new = v->length;
	v4 = c->length;
	v5 = u->length;

    /* reassign events for CPP and adjust prior and proposal ratios for relaxed clock models */
	for (i=0; i<param->subParams[0]->nSubParams; i++)
		{
		subParm = param->subParams[0]->subParams[i];
		if (subParm->paramType == P_CPPEVENTS)
			{
			nEvents = subParm->nEvents[2*chain+state[chain]];
			position = subParm->position[2*chain+state[chain]];
			rateMultiplier = subParm->rateMult[2*chain+state[chain]];
			for (j=0; j<nEvents[c->index]; j++)
				{
				if (position[c->index][j] > v4 / (v4+v5))
					break;
				}
			n4 = j;
			n5 = nEvents[c->index] - j;
			nEvents[u->index] = n5;
			if (n5 > 0)
				{
				position[u->index] = (MrBFlt *) SafeRealloc ((void *) position[u->index], n5 * sizeof (MrBFlt));
				rateMultiplier[u->index] = (MrBFlt *) SafeRealloc ((void *) rateMultiplier[u->index], n5 * sizeof (MrBFlt));			
				for (j=n4; j<nEvents[c->index]; j++)
					{
					position[u->index][j-n4] = (position[c->index][j] * (v4+v5) - v4) / v5;
					rateMultiplier[u->index][j-n4] = rateMultiplier[c->index][j];
					}
				if (n4 > 0)
					{
					position[c->index] = (MrBFlt *) SafeRealloc ((void *) position[c->index], n4 * sizeof (MrBFlt));
					rateMultiplier[c->index] = (MrBFlt *) SafeRealloc ((void *) rateMultiplier[c->index], n4 * sizeof (MrBFlt));
					for (j=0; j<n4; j++)
						position[c->index][j] *= ((v4+v5) / v4);
					}
				else
					{
					free (position[c->index]);
					free (rateMultiplier[c->index]);
					position[c->index] = rateMultiplier[c->index] = NULL;
					}
				nEvents[c->index] = n4;
				}
			else
				{
				for (j=0; j<nEvents[c->index]; j++)
					position[c->index][j] *= ((v4+v5) / v4);
				}

			/* adjust proposal ratio */
			(*lnProposalRatio) += n3 * log (v3new / v3);

			/* adjust prior ratio */
			lambda = *GetParamVals (modelSettings[subParm->relParts[0]].cppRate, chain, state[chain]);
			(*lnPriorRatio) += lambda * (v3 - v3new);

			/* update effective branch lengths */
			if (UpdateCppEvolLengths (subParm, a, chain) == ERROR)
                {
                abortMove = YES;
                free (nSitesOfPat);
                return (NO_ERROR);
                }

            if (UpdateCppEvolLengths (subParm, u, chain) == ERROR)
                {
                abortMove = YES;
                free (nSitesOfPat);
                return (NO_ERROR);
                }
			}	/* end cpp events parameter */
		else if (subParm->paramType == P_TK02BRANCHRATES)
			{
			/* adjust prior ratio */
			nu = *GetParamVals (modelSettings[subParm->relParts[0]].tk02var, chain, state[chain]);
			tk02Rate = GetParamVals (subParm, chain, state[chain]);
			(*lnPriorRatio) -= LnProbTK02LogNormal(tk02Rate[u->anc->index], nu*(c->length+u->length), tk02Rate[c->index]);
			(*lnPriorRatio) += LnProbTK02LogNormal(tk02Rate[c->anc->index], nu*c->length, tk02Rate[c->index]);
			(*lnPriorRatio) += LnProbTK02LogNormal(tk02Rate[v->anc->index], nu*v->length, tk02Rate[v->index]);
			(*lnPriorRatio) += LnProbTK02LogNormal(tk02Rate[u->anc->index], nu*u->length, tk02Rate[u->index]);

			/* adjust effective branch lengths */
			brlens = GetParamSubVals (subParm, chain, state[chain]);
			brlens[c->index] = c->length * (tk02Rate[c->index] + tk02Rate[c->anc->index]) / 2.0;
			brlens[v->index] = v->length * (tk02Rate[v->index] + tk02Rate[v->anc->index]) / 2.0;
			brlens[u->index] = u->length * (tk02Rate[u->index] + tk02Rate[u->anc->index]) / 2.0;
			}	/* end tk02 branch rate parameter */
		else if (subParm->paramType == P_IGRBRANCHLENS)
			{
            /* get relevant parameters */
			igrvar = *GetParamVals (modelSettings[subParm->relParts[0]].igrvar, chain, state[chain]);
			igrRate = GetParamVals (subParm, chain, state[chain]);
			brlens = GetParamSubVals (subParm, chain, state[chain]);

            /* adjust prior ratio for old branch length */
			(*lnPriorRatio) -= LnProbTruncGamma ((c->length+u->length)/igrvar, 1.0/igrvar, brlens[c->index], minB, maxB);

            /* adjust effective branch lengths and rates */
            /* we use the old values, just rearrange them; Hastings ratio of alternative not worked out yet */
			brlens [v->index] = brlens[v->index];   /* keep this branch length the same */
            igrRate[v->index] = brlens[v->index] / v->length;
            // brlens [u->index] = brlens[c->index] * newProp;
            // brlens [c->index] = brlens[c->index] - brlens[u->index];
            igrRate[u->index] = brlens[u->index] / u->length;
            igrRate[c->index] = brlens[c->index] / c->length;
            if (brlens[u->index] < minB || brlens[u->index] > maxB ||
                brlens[c->index] < minB || brlens[c->index] > maxB)
                {
                free (nSitesOfPat);
                abortMove = YES;
                return (NO_ERROR);
                }

            /* adjust prior ratio for new branch lengths */
			(*lnPriorRatio) += LnProbTruncGamma (c->length/igrvar, 1.0/igrvar, brlens[c->index], minB, maxB);
			(*lnPriorRatio) += LnProbTruncGamma (v->length/igrvar, 1.0/igrvar, brlens[v->index], minB, maxB);
			(*lnPriorRatio) += LnProbTruncGamma (u->length/igrvar, 1.0/igrvar, brlens[u->index], minB, maxB);

            /* adjust proposal ratio */
            /* when we just rearrange old values, the proposal ratio is 1; the ratio below is NOT the correct one for the alternative update */
            // (*lnProposalRatio) += log ((brlens[c->index] + brlens[u->index]) / brlens[a->index]);

            /*The following if (*lnPriorRatio != *lnPriorRatio) should be removed if LnProbTruncGamma() would be made more exact and would never return -infinity */
            if (*lnPriorRatio != *lnPriorRatio)
                {
                abortMove=YES;
                return (NO_ERROR);
                }
            }   /* end igr branch rate parameter */
		}	/* next subparameter */

	/* set tiprobs update flags */
	c->upDateTi = YES;
	u->upDateTi = YES;
	v->upDateTi = YES;

	/* set flags for update of cond likes from u and down to root */
	p = u;
	while (p->anc != NULL)
		{
		p->upDateCl = YES; 
		p = p->anc;
		}

	/* set flags for update of cond likes from b and down to root */
	p = b;
	while (p->anc != NULL)
		{
		p->upDateCl = YES; 
		p = p->anc;
		}

	/* get down pass sequence */
	GetDownPass (t);

	/* calculate proposal ratio for tree change */
	(*lnProposalRatio) += log ((newBrlen - 2.0*minV) / (oldBrlen - 2.0*minV));

	/* calculate and adjust prior ratio for clock tree */
    if (LogClockTreePriorRatio (param, chain, &x) == ERROR)
        {
        free (nSitesOfPat);
        return (ERROR);
        }
    (*lnPriorRatio) += x;

#	if defined (DEBUG_ParsSPRClock)
	printf ("After:\n");
	ShowNodes (t->root, 2, YES);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
    printf ("v: %d  u: %d  a: %d  b: %d c: %d\n",v->index, u->index, a->index, b->index, c->index);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

	free (nSitesOfPat);
    return (NO_ERROR);
	
}





int Move_Pinvar (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* change proportion of invariable sites (pInvar) */

	int				i, c, isValidP, *rateCat, nGammaCats;
	MrBFlt			oldP, newP, window, minP, maxP, ran, lnInvarRatio, lnVarRatio;
	CLFlt			*nSitesOfPat;
	ModelParams		*mp;
	ModelInfo		*m;

	/* get size of window, centered on current pInvar value */
	window = mvp[0];

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* get minimum and maximum values for pInvar */
	minP = mp->pInvarUni[0];
	maxP = mp->pInvarUni[1];

	/* get old value of pInvar */
	newP = oldP = *GetParamVals(param, chain, state[chain]);

	/* change value for pInvar */
	ran = RandomNumber(seed);
	if( maxP-minP < window )
		{
		window = maxP-minP;
		}

	newP = oldP + window * (ran - 0.5);

	/* check validity */
	isValidP = NO;
	do
		{
		if (newP < minP)
			newP = 2* minP - newP;
		else if (newP > maxP)
			newP = 2 * maxP - newP;
		else
			isValidP = YES;
		} while (isValidP == NO);

	/* get proposal ratio */
	*lnProposalRatio = 0.0;
	
	/* get prior ratio */
	*lnPriorRatio = 0.0;
	lnInvarRatio = log(newP) - log(oldP);
	lnVarRatio = log(1.0-newP) - log(1.0-oldP);
	for (i=0; i<param->nRelParts; i++)
		{
		m = &modelSettings[param->relParts[i]];
		if (m->gibbsGamma == YES)
			{
			/* find rate category index and number of gamma categories */
			rateCat = m->tiIndex + chain * m->numChars;
			nGammaCats = m->numGammaCats;

			/* find nSitesOfPat */
			nSitesOfPat = numSitesOfPat + ((chainId[chain] % chainParams.numChains)*numCompressedChars) + m->compCharStart;
			
			/* loop over characters */
			for (c=0; c<m->numChars; c++)
				{
				if (rateCat[c] < nGammaCats)
					*lnPriorRatio += lnVarRatio * nSitesOfPat[c];
				else
					*lnPriorRatio += lnInvarRatio * nSitesOfPat[c];
				}
			}
		}
	
	/* copy new pInvar value back */
	*GetParamVals(param, chain, state[chain]) = newP;

	/* Set update flags for all partitions that share this pInvar. Note that the conditional
	   likelihood update flags for divisions have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
	
	/* However, you do need to update cijk flags if this is a covarion model */
	/* TO DO */
	
	return (NO_ERROR);

}





int Move_PopSizeM (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int				isNPriorExp, isValidN, valIndex;
	MrBFlt			*valPtr, oldN, newN, tuning, minN, maxN, ran, oldLnPrior, newLnPrior, growth,
                    oldT, newT, clockRate;
	ModelParams 	*mp;
	ModelInfo		*m;
	Tree			*t;

	/* get multiplier tuning parameter */
	tuning = mvp[0];

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
    /* get model settings */
    m = &modelSettings[param->relParts[0]];

	/* get minimum and maximum values for population size */
	if (param->paramId == POPSIZE_UNI)
		{
		minN = mp->popSizeUni[0];
		maxN = mp->popSizeUni[1];
		isNPriorExp = NO;
		}
	else
		{
		minN = 0.0001;
		maxN = 10000000;
		}

    /* get pointer to value to be changed */
    valIndex = (int)(RandomNumber(seed) * param->nValues);
    valPtr   = GetParamVals(param, chain, state[chain]);
    valPtr += valIndex;

	/* get old value of population size */
	newN = oldN = *valPtr;

    /* get old prior for species tree coalescence */
    if (m->brlens->paramId == BRLENS_CLOCK_SPCOAL)
        {
        oldLnPrior = LnSpeciesTreeProb(chain);
        }
    
    /* change value for theta */
	ran = RandomNumber(seed);
    newN = oldN * exp(tuning * (ran - 0.5));
	
	/* check that new value is valid */
	isValidN = NO;
	do
		{
		if (newN < minN)
			newN = 2* minN - newN;
		else if (newN > maxN)
			newN = 2 * maxN - newN;
		else
			isValidN = YES;
		} while (isValidN == NO);

    /* copy new population size value back */
	(*valPtr) = newN;

	/* get proposal ratio */
	*lnProposalRatio = log (newN / oldN);
	
	/* get prior ratio */
    if (m->brlens->paramId == BRLENS_CLOCK_SPCOAL)
        {
        newLnPrior = LnSpeciesTreeProb(chain);
        }
    else
        {
        t         = GetTree(modelSettings[param->relParts[0]].brlens,chain,state[chain]);
	    m         = &modelSettings[param->relParts[0]];
        clockRate = *GetParamVals(m->clockRate, chain, state[chain]);
	    if (!strcmp(mp->growthPr, "Fixed"))
		    growth = mp->growthFix;
	    else
		    growth = *(GetParamVals (m->growthRate, chain, state[chain]));
        oldT = oldN;
        newT = newN;
        if (!strcmp(mp->ploidy, "Diploid"))
            {
            newT *= 4.0;
            oldT *= 4.0;
            }
        else if (!strcmp(mp->ploidy, "Zlinked"))
            {
            newT *= 3.0;
            oldT *= 3.0;
            }
        else
            {
            newT *= 2.0;
            oldT *= 2.0;
            }
        clockRate = *(GetParamVals(m->clockRate, chain, state[chain]));
        newT *= clockRate;
        oldT *= clockRate;
	    if (LnCoalescencePriorPr (t, clockRate, &oldLnPrior, oldT, growth) == ERROR)
		    {
		    MrBayesPrint ("%s   Problem calculating prior for birth-death process\n", spacer);
		    return (ERROR);
		    }
	    if (LnCoalescencePriorPr (t, clockRate, &newLnPrior, newT, growth) == ERROR)
		    {
		    MrBayesPrint ("%s   Problem calculating prior for birth-death process\n", spacer);
		    return (ERROR);
		    }
        }

    (*lnPriorRatio) = param->LnPriorRatio(newN, oldN, param->priorParams);
    (*lnPriorRatio) += newLnPrior - oldLnPrior;

	return (NO_ERROR);

}





/* Generalized lognormal move for positive real random variables */
int Move_PosRealLognormal (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)
{
	int			i;
	MrBFlt		oldX, newX, minX, maxX, tuning, u, z;

	/* get tuning parameter */
	tuning = mvp[0];

	/* get minimum and maximum values for X */
	minX = param->min;
    maxX = param->max;

	/* get old value of X */
	newX = oldX = *GetParamVals(param, chain, state[chain]);

	/* change value of X */
	u = RandomNumber(seed);
	z = PointNormal(u);

    newX = exp (log(oldX) + z * tuning);
	
	/* check that new value is valid */
    if (newX < minX || newX > maxX) {
        abortMove = YES;
        return (NO_ERROR);
    }
    
	/* get proposal ratio */
	(*lnProposalRatio) = log (newX / oldX);
	
	/* get prior ratio */
	(*lnPriorRatio) = param->LnPriorRatio(newX, oldX, param->priorParams);
	
	/* copy new value back */
    (*GetParamVals(param, chain, state[chain])) = newX;

	/* Set update flags for tree nodes if relevant */
	if (param->affectsLikelihood == YES)
        {
        for (i=0; i<param->nRelParts; i++)
		    TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
        }

	return (NO_ERROR);
}





/* Generalized multiplier move for positive real random variables */
int Move_PosRealMultiplier (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)
{
	int			i, isValid;
	MrBFlt		oldX, newX, minX, maxX, tuning, ran, factor;

	/* get tuning parameter */
	tuning = mvp[0];

	/* get minimum and maximum values for X */
	minX = param->min;
    maxX = param->max;

	/* get old value of X */
	newX = oldX = *GetParamVals(param, chain, state[chain]);

	/* change value of X */
	ran = RandomNumber(seed);
	factor = exp(tuning * (ran - 0.5));
	newX = oldX * factor;
	
	/* check that new value is valid */
	isValid = NO;
	do
		{
		if (newX < minX)
			newX = minX * minX / newX;
		else if (newX > maxX)
			newX = maxX * maxX / newX;
		else
			isValid = YES;
		} while (isValid == NO);

	/* get proposal ratio */
	(*lnProposalRatio) = log (newX / oldX);
	
	/* get prior ratio */
	(*lnPriorRatio) = param->LnPriorRatio(newX, oldX, param->priorParams);
	
	/* copy new value back */
    *(GetParamVals(param, chain, state[chain])) = newX;

	/* Set update flags for tree nodes if relevant */
	if (param->affectsLikelihood == YES)
        {
        for (i=0; i<param->nRelParts; i++)
		    TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
        }

	return (NO_ERROR);
}





int Move_RanSPR1 (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* Change branch lengths and topology (potentially) using random SPR (unrooted) */

	/* This move type picks a random interior branch and another randomly chosen interior
	   or terminal branch. The path connecting these branches is found and the two subtrees
       are swapped along this path. This is the move studied in Lakner et al. (2008).
       
       This move is not yet safe for constrained trees. */
	
	int			i, topologyHasChanged, nCrownNodes, nRootNodes, directionLeft, directionUp, 
				isVPriorExp, moveInRoot, foundFirst;
	MrBFlt		m, x, y, tuning, maxV, minV, extensionProb, brlensExp=0.0;
	TreeNode	*p, *a, *b, *c, *d, *u, *v, *brlenNode[7], *q;
	Tree		*t;
	ModelParams *mp;


	/* these parameters should be possible to set by user */
	extensionProb = mvp[0];	/* extension probability */
	tuning = mvp[1];        /* Larget & Simon's tuning parameter lambda */
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);
#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in input tree to rSPR1\n");
		getchar();
		}
#endif

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* max and min brlen */
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}

	topologyHasChanged = NO;

#	if defined (DEBUG_RanSPR)
	printf ("Before:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
#	endif
	
	/* pick an internal branch */
	do
		{
		p = t->intDownPass[(int)(RandomNumber(seed)*t->nIntNodes)];
		} while (p->anc->anc == NULL);

	/* select another random branch */
	if (RandomNumber (seed) > extensionProb)
		q = p->left;
	else
		{
		do
			{
			q = t->allDownPass[(int)(RandomNumber(seed)*(t->nNodes - 1))];
			} while (q == p || q->anc == p || q == p->anc || q->anc == p->anc);
		}
	
	/* set up pointers for nodes around the picked branch */
	/* cut the tree into crown, root and attachment part */
	/* change the relevant lengths in the attachment part */
	/* the lengths of a and v are automatically contained in the */
	/* "attachment" part but the length of c has to be stored in x */
	v = p;
	u = p->anc;

	/* store brlen node */
	brlenNode[3] = v;

	/* mark crown subtree */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		p->x = 0;
		}
	v->x = 1;

	for (i=t->nNodes-2; i>=0; i--)
		{
		p = t->allDownPass[i];
		if (p->anc->x == 1)
			p->x = 1;
		}

	/* find the subtree */
	if (q->x == 1)
		moveInRoot = NO;
	else
		moveInRoot = YES;

	/* mark the path of the move */
	for (i=0; i<t->nNodes; i++)
		t->allDownPass[i]->marked = NO;

	if (moveInRoot == NO)
		{
		p = q;
		while (p != v)
			{
			p->marked = YES;
			p = p->anc;
			}
		v->marked = YES;
		}
	else
		{
		p = q;
		while (p != NULL)
			{
			p->marked = YES;
			p = p->anc;
			}
		foundFirst = NO;
		p = v;
		while (p != NULL)
			{
			if (p->marked == NO)
				p->marked = YES;
			else if (foundFirst == YES)
				p->marked = NO;
			else
				foundFirst = YES;
			p = p->anc;
			}
		}

	/* set up pointers for crown part */
	/* this also determines direction of move in crown part */
	if (v->left->marked == YES)
		{
		c = v->left;
		d = v->right;
		directionLeft = YES;
		}
	else
		{
		c = v->right;
		d = v->left;
		directionLeft = NO;
		}

	/* store brlen nodes and brlen to move */
	brlenNode[0] = d;
	brlenNode[1] = c;
	x = c->length;

	/* cut and reconnect crown part */
	c->anc = d;
	d->anc = c;
	
	/* mark nodes in root part */
	/* also determines direction of move in root part */
	if (u->anc->marked == NO)
		{
		if (u->left == v)
			a = u->right;
		else
			a = u->left;
		b = u->anc;
		directionUp = YES;
		}
	else
		{
		if (u->left == v)
			b = u->right;
		else
			b = u->left;
		a = u->anc;
		directionUp = NO;
		}

	/* store brlen nodes */
	if (directionUp == YES)
		{
		brlenNode[4] = u;
		brlenNode[5] = a;
		}
	else
		{
		brlenNode[4] = b;
		brlenNode[5] = u;
		}

	/* cut root part*/
	/* store branch to move in u->length */
	if (directionUp == NO) 
		{
		b->anc = a;
		if (a->left == u)
			a->left = b;
		else
			a->right = b;
		}
	else 
		{
		a->anc = b;
		if (b->left == u)
			b->left = a;
		else
			b->right = a;
		y = a->length;
		a->length = u->length;
		u->length = y;
		a->upDateTi = YES;
		u->upDateTi = YES;
		}

	/* move around in root subtree */
	nRootNodes = 0;
	if (moveInRoot == YES)
		{
		for (nRootNodes=0; a->marked == YES; nRootNodes++) 
			{
			if (directionUp == YES) 
				{
				/* going up tree */
				if (a->left == NULL)
					break;
				else if (a->left->marked == NO && a->right->marked == NO)
					break;		/* don't go further */
				topologyHasChanged = YES;
				b = a;
				if (a->left->marked == YES)
					a = a->left;
				else
					a = a->right;
				if (u->isLocked == YES)
					{
					b->isLocked = YES;
					u->isLocked = NO;
					b->lockID = u->lockID;
					u->lockID = 0;
					}
				}
			else 
				{
				/* going down tree */
				if (a->anc == NULL || u->isLocked == YES)
					break;		/* can't go further */
				topologyHasChanged = YES;
				if (a->anc->marked == NO) 
					{
					/* try switching direction */
					/* find sister of a */
					if (a->left == b) 
						{
						a = a->right;
						}
					else 
						{  
						a = a->left;
						}
					/* as long as we are moving upwards
					the cond likes to update will be
					flagged by the last pass from u to the root */
					if (a->marked == NO)
						{
						b = a->anc;
						b->upDateCl = YES;
						a = a->anc->anc;
						break;			/* go back and one node down, unsuccessful attempt */
						}
					else
						{
						b = a->anc;
						directionUp = YES;	/* successful attempt */
						}
					}	
				else 
					{	/* continue down */					
					b = a;
					a = a->anc;
					b->upDateCl = YES; 
					if (b->isLocked == YES)
						{
						u->isLocked = YES;
						b->isLocked = NO;
						u->lockID = b->lockID;
						b->lockID = 0;
						}
					}
				}
			}
		}

	/* store brlen nodes */
	if (nRootNodes > 0)
		{
		if (directionUp == YES)
			{
			brlenNode[6] = a;
			brlenNode[5] = u;
			}
		else
			{
			brlenNode[6] = u;
			brlenNode[5] = b;
			}
		}

	/* move around in crown subtree */
	nCrownNodes = 0;
	if (moveInRoot == NO)		
		{
		for (nCrownNodes=0; c->left != NULL; nCrownNodes++) 
			{
			if (c->left->marked == NO && c->right->marked == NO)
				break;	/* can't go further */
			topologyHasChanged = YES;
			if (c->left->marked == YES) 
				{
				/* rotate c anticlockwise - prepare pointers for move left */
				c->anc = c->left;  /* the root will be in the direction we are heading */
				c->left = c->right;
				c->right = d;
				}
			else 
				{
				/* rotate c clockwise - prepare pointers for move right */
				c->anc = c->right;	/* the root will be in the direction we are heading */
				c->right = c->left;
				c->left = d;  
				}
			/* OK - let's move!; c->anc points in the right direction
			don't forget to move the branch lengths as well */
			d = c;
			c = c->anc;
			d->length = c->length;
			d->upDateCl = YES; 
			d->upDateTi = YES;
			}
		}

	/* store brlen nodes */
	if (nCrownNodes > 0)
		{
		brlenNode[2] = c;
		brlenNode[1] = d;
		}

	/* combine the subtrees */
	c->anc = v;
	d->anc = v;
	if (directionLeft == YES) 
		{
		v->left = c;
		v->right = d;
		}
	else 
		{
		v->left = d;
		v->right = c;
		}

	/* the dangling branch is inserted in reverted position
	   such that the back move will be possible
	   if we have moved around in crown subtree
	   otherwise it is left in its original position */
	if (nCrownNodes > 0)
		{
		d->length = x;
		d->upDateTi = YES;
		}
	else
		{
		c->length = x;
		}	

	if (directionUp == YES) 
		{
		u->anc = b;
		if (u->left == v)
			u->right = a;
		else 
			u->left = a;
		a->anc = u;
		if (b->left == a)
			b->left = u;
		else
			b->right = u;
		/* the dangling branch is contained in u->length
		   and will automatically be inserted in the right position
		   to enable the back move regardless of whether it was
		   initially directed upwards or downwards
		   BUT if we haven't moved in root subtree, it is advantageous (necessary
		   for rooted trees) to avoid switching branches, which occurs otherwise
		   if directionUp == YES */
		if (nRootNodes == 0) 
			{
			x = u->length;
			u->length = a->length;
			a->length = x;
			a->upDateTi = NO;
			u->upDateTi = NO;
			}
		}
	else 
		{
		u->anc = a;
		if (u->left == v)
			u->right = b;
		else 
			u->left = b;
		b->anc = u;
		if (a->left == b)
			a->left = u;
		else
			a->right = u;
		/* the modified branch contained in u->length will have
		   to be moved to b->length to enable back move
		   BUT if we haven't moved, it is better to keep it in place
		   (necessary for rooted trees) */
		if (nRootNodes > 0) 
			{
			x = u->length;
			u->length = b->length;
			b->length = x;
			b->upDateTi = YES;
			u->upDateTi = YES;
			}
		}
	
	/* modify branch lengths */
	/* first modify length of middle branch */
	m = brlenNode[3]->length;
	x = m * exp(tuning * (RandomNumber(seed) - 0.5));		/* save the modified dangling branch for later use */
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	brlenNode[3]->length = x;
	brlenNode[3]->upDateTi = YES;

	/* update proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - x);

	/* if no move in crown, then select randomly, otherwise always the moved branch */
	if (nCrownNodes == 0 && RandomNumber (seed) < 0.5)
		p = brlenNode[0];
	else
		p = brlenNode[1];

	/* modify branch length */
	m = p->length;
	x = m * exp(tuning * (RandomNumber(seed) - 0.5));
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	p->length = x;
	p->upDateTi = YES;

	/* update proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - x);	
		
	/* if no move in root, then select randomly, otherwise always the moved branch */
	if (nRootNodes == 0 && RandomNumber(seed) < 0.5)
		p = brlenNode[4];
	else
		p = brlenNode[5];
	
	/* modify branch length but not if 'root' branch in rooted tree */
	if (t->isRooted == NO || p->anc->anc != NULL)
		{
		m = p->length;
		x = m * exp(tuning * (RandomNumber(seed) - 0.5));
		while (x < minV || x > maxV)
			{
			if (x < minV)
				x = minV * minV / x;
			else if (x > maxV)
				x = maxV * maxV / x;
			}
		p->length = x;
		p->upDateTi = YES;

		/* update proposal and prior ratio based on length modification */
		(*lnProposalRatio) += log (x / m);
		if (isVPriorExp == YES)
			(*lnPriorRatio) += brlensExp * (m - x);	
		}

	/* set flags for update of cond likes from v and down to root */
	p = v;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}

#	if defined (DEBUG_RanSPR)
	printf ("After:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  c: %d  d: %d  a: %d  b: %d q: %d\n",v->index, u->index, 
		c->index, d->index, a->index, b->index, q->index);
	printf ("No. nodes moved in root subtree: %d\n",nRootNodes);
	printf ("No. nodes moved in crown subtree: %d\n",nCrownNodes);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

	gNodeMoves = nCrownNodes + nRootNodes;
#	endif

#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in output tree to rSPR1\n");
		getchar();
		}
#endif

	return (NO_ERROR);
	
}





int Move_RanSPR2 (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* This move is like Move_RanSPR1, except that branches are chosen with equal probability in two subtrees
       defined by the initially chosen interior branch */
	
	int			i, topologyHasChanged, nCrownNodes, nRootNodes, directionLeft, directionUp, 
				isVPriorExp, moveInRoot, foundFirst;
	MrBFlt		m, x, y, tuning, maxV, minV, extensionProb, brlensExp=0.0;
	TreeNode	*p, *a, *b, *c, *d, *u, *v, *brlenNode[7], *q;
	Tree		*t;
	ModelParams *mp;

	/* these parameters should be possible to set by user */
	extensionProb = mvp[0];	/* extension probability */
	tuning = mvp[1];        /* Larget & Simon's tuning parameter lambda */
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);
#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in input tree to rSPR2\n");
		getchar();
		}
#endif

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* max and min brlen */
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}

	topologyHasChanged = NO;

#	if defined (DEBUG_RanSPR)
	printf ("Before:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
#	endif
	
	/* pick an internal branch */
	do
		{
		p = t->intDownPass[(int)(RandomNumber(seed)*t->nIntNodes)];
		} while (p->anc->anc == NULL);
		
	/* set up pointers for nodes around the picked branch */
	/* cut the tree into crown, root and attachment part */
	/* change the relevant lengths in the attachment part */
	/* the lengths of a and v are automatically contained in the */
	/* "attachment" part but the length of c has to be stored in x */
	v = p;
	u = p->anc;

	/* store brlen node */
	brlenNode[3] = v;

	/* mark crown subtree */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->left == NULL)
			p->x = 1;
		else if (p->right != NULL)
			p->x = p->left->x + p->right->x;
		p->marked = NO;
		}
	v->marked = YES;

	for (i=t->nNodes-2; i>=0; i--)
		{
		p = t->allDownPass[i];
		if (p->anc->marked == YES)
			p->marked = YES;
		}

	/* find the subtree */
	if (v->x <= 2)
		moveInRoot = YES;
	else if (t->nNodes - t->nIntNodes - v->x <= 2)
		moveInRoot = NO;
	else if (RandomNumber(seed) < 0.5)
		moveInRoot = NO;
	else
		moveInRoot = YES;

	/* find the attachment point */
	if (RandomNumber (seed) > extensionProb)
		{
		q = v->left;
		moveInRoot = NO;
		}
	else
		{
		do
			{
			q = t->allDownPass[(int)(RandomNumber(seed)*(t->nNodes-1))];
			} while (q == v || q->anc == v || q == v->anc || q->anc == v->anc ||
				(moveInRoot == NO && q->marked == NO) || (moveInRoot == YES && q->marked == YES));
		}
	
	/* mark the path of the move */
	for (i=0; i<t->nNodes; i++)
		t->allDownPass[i]->marked = NO;

	if (moveInRoot == NO)
		{
		p = q;
		while (p != v)
			{
			p->marked = YES;
			p = p->anc;
			}
		v->marked = YES;
		}
	else
		{
		p = q;
		while (p != NULL)
			{
			p->marked = YES;
			p = p->anc;
			}
		foundFirst = NO;
		p = v;
		while (p != NULL)
			{
			if (p->marked == NO)
				p->marked = YES;
			else if (foundFirst == YES)
				p->marked = NO;
			else
				foundFirst = YES;
			p = p->anc;
			}
		}

	/* set up pointers for crown part */
	/* this also determines direction of move in crown part */
	if (v->left->marked == YES)
		{
		c = v->left;
		d = v->right;
		directionLeft = YES;
		}
	else
		{
		c = v->right;
		d = v->left;
		directionLeft = NO;
		}

	/* store brlen nodes and brlen to move */
	brlenNode[0] = d;
	brlenNode[1] = c;
	x = c->length;

	/* cut and reconnect crown part */
	c->anc = d;
	d->anc = c;
	
	/* mark nodes in root part */
	/* also determines direction of move in root part */
	if (u->anc->marked == NO)
		{
		if (u->left == v)
			a = u->right;
		else
			a = u->left;
		b = u->anc;
		directionUp = YES;
		}
	else
		{
		if (u->left == v)
			b = u->right;
		else
			b = u->left;
		a = u->anc;
		directionUp = NO;
		}

	/* store brlen nodes */
	if (directionUp == YES)
		{
		brlenNode[4] = u;
		brlenNode[5] = a;
		}
	else
		{
		brlenNode[4] = b;
		brlenNode[5] = u;
		}

	/* cut root part*/
	/* store branch to move in u->length */
	if (directionUp == NO) 
		{
		b->anc = a;
		if (a->left == u)
			a->left = b;
		else
			a->right = b;
		}
	else 
		{
		a->anc = b;
		if (b->left == u)
			b->left = a;
		else
			b->right = a;
		y = a->length;
		a->length = u->length;
		u->length = y;
		a->upDateTi = YES;
		u->upDateTi = YES;
		}

	/* move around in root subtree */
	nRootNodes = 0;
	if (moveInRoot == YES)
		{
		for (nRootNodes=0; a->marked == YES; nRootNodes++) 
			{
			if (directionUp == YES) 
				{
				/* going up tree */
				if (a->left == NULL)
					break;
				else if (a->left->marked == NO && a->right->marked == NO)
					break;		/* don't go further */
				topologyHasChanged = YES;
				b = a;
				if (a->left->marked == YES)
					a = a->left;
				else
					a = a->right;
				if (u->isLocked == YES)
					{
					b->isLocked = YES;
					u->isLocked = NO;
					b->lockID = u->lockID;
					u->lockID = 0;
					}
				}
			else 
				{
				/* going down tree */
				if (a->anc == NULL || u->isLocked == YES)
					break;		/* can't go further */
				topologyHasChanged = YES;
				if (a->anc->marked == NO) 
					{
					/* try switching direction */
					/* find sister of a */
					if (a->left == b) 
						{
						a = a->right;
						}
					else 
						{  
						a = a->left;
						}
					/* as long as we are moving upwards
					the cond likes to update will be
					flagged by the last pass from u to the root */
					if (a->marked == NO)
						{
						b = a->anc;
						b->upDateCl = YES;
						a = a->anc->anc;
						break;			/* go back and one node down, unsuccessful attempt */
						}
					else
						{
						b = a->anc;
						directionUp = YES;	/* successful attempt */
						}
					}	
				else 
					{	/* continue down */					
					b = a;
					a = a->anc;
					b->upDateCl = YES; 
					if (b->isLocked == YES)
						{
						u->isLocked = YES;
						b->isLocked = NO;
						u->lockID = b->lockID;
						b->lockID = 0;
						}
					}
				}
			}
		}

	/* store brlen nodes */
	if (nRootNodes > 0)
		{
		if (directionUp == YES)
			{
			brlenNode[6] = a;
			brlenNode[5] = u;
			}
		else
			{
			brlenNode[6] = u;
			brlenNode[5] = b;
			}
		}

	/* move around in crown subtree */
	nCrownNodes = 0;
	if (moveInRoot == NO)		
		{
		for (nCrownNodes=0; c->left != NULL; nCrownNodes++) 
			{
			if (c->left->marked == NO && c->right->marked == NO)
				break;	/* can't go further */
			topologyHasChanged = YES;
			if (c->left->marked == YES) 
				{
				/* rotate c anticlockwise - prepare pointers for move left */
				c->anc = c->left;  /* the root will be in the direction we are heading */
				c->left = c->right;
				c->right = d;
				}
			else 
				{
				/* rotate c clockwise - prepare pointers for move right */
				c->anc = c->right;	/* the root will be in the direction we are heading */
				c->right = c->left;
				c->left = d;  
				}
			/* OK - let's move!; c->anc points in the right direction
			don't forget to move the branch lengths as well */
			d = c;
			c = c->anc;
			d->length = c->length;
			d->upDateCl = YES; 
			d->upDateTi = YES;
			}
		}

	/* store brlen nodes */
	if (nCrownNodes > 0)
		{
		brlenNode[2] = c;
		brlenNode[1] = d;
		}

	/* combine the subtrees */
	c->anc = v;
	d->anc = v;
	if (directionLeft == YES) 
		{
		v->left = c;
		v->right = d;
		}
	else 
		{
		v->left = d;
		v->right = c;
		}

	/* the dangling branch is inserted in reverted position
	   such that the back move will be possible
	   if we have moved around in crown subtree
	   otherwise it is left in its original position */
	if (nCrownNodes > 0)
		{
		d->length = x;
		d->upDateTi = YES;
		}
	else
		{
		c->length = x;
		}	

	if (directionUp == YES) 
		{
		u->anc = b;
		if (u->left == v)
			u->right = a;
		else 
			u->left = a;
		a->anc = u;
		if (b->left == a)
			b->left = u;
		else
			b->right = u;
		/* the dangling branch is contained in u->length
		   and will automatically be inserted in the right position
		   to enable the back move regardless of whether it was
		   initially directed upwards or downwards
		   BUT if we haven't moved in root subtree, it is advantageous (necessary
		   for rooted trees) to avoid switching branches, which occurs otherwise
		   if directionUp == YES */
		if (nRootNodes == 0) 
			{
			x = u->length;
			u->length = a->length;
			a->length = x;
			a->upDateTi = NO;
			u->upDateTi = NO;
			}
		}
	else 
		{
		u->anc = a;
		if (u->left == v)
			u->right = b;
		else 
			u->left = b;
		b->anc = u;
		if (a->left == b)
			a->left = u;
		else
			a->right = u;
		/* the modified branch contained in u->length will have
		   to be moved to b->length to enable back move
		   BUT if we haven't moved, it is better to keep it in place
		   (necessary for rooted trees) */
		if (nRootNodes > 0) 
			{
			x = u->length;
			u->length = b->length;
			b->length = x;
			b->upDateTi = YES;
			u->upDateTi = YES;
			}
		}
	
	/* modify branch lengths */
	/* first modify length of middle branch */
	m = brlenNode[3]->length;
	x = m * exp(tuning * (RandomNumber(seed) - 0.5));		/* save the modified dangling branch for later use */
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	brlenNode[3]->length = x;
	brlenNode[3]->upDateTi = YES;

	/* update proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - x);

	/* if no move in crown, then select randomly, otherwise always the moved branch */
	if (nCrownNodes == 0 && RandomNumber (seed) < 0.5)
		p = brlenNode[0];
	else
		p = brlenNode[1];

	/* modify branch length */
	m = p->length;
	x = m * exp(tuning * (RandomNumber(seed) - 0.5));
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	p->length = x;
	p->upDateTi = YES;

	/* update proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - x);	
		
	/* if no move in root, then select randomly, otherwise always the moved branch */
	if (nRootNodes == 0 && RandomNumber(seed) < 0.5)
		p = brlenNode[4];
	else
		p = brlenNode[5];
	
	/* modify branch length but not if 'root' branch in rooted tree */
	if (t->isRooted == NO || p->anc->anc != NULL)
		{
		m = p->length;
		x = m * exp(tuning * (RandomNumber(seed) - 0.5));
		while (x < minV || x > maxV)
			{
			if (x < minV)
				x = minV * minV / x;
			else if (x > maxV)
				x = maxV * maxV / x;
			}
		p->length = x;
		p->upDateTi = YES;

		/* update proposal and prior ratio based on length modification */
		(*lnProposalRatio) += log (x / m);
		if (isVPriorExp == YES)
			(*lnPriorRatio) += brlensExp * (m - x);	
		}

	/* set flags for update of cond likes from v and down to root */
	p = v;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}

#	if defined (DEBUG_RanSPR)
	printf ("After:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  c: %d  d: %d  a: %d  b: %d q: %d\n",v->index, u->index, 
		c->index, d->index, a->index, b->index, q->index);
	printf ("No. nodes moved in root subtree: %d\n",nRootNodes);
	printf ("No. nodes moved in crown subtree: %d\n",nCrownNodes);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

	gNodeMoves = nCrownNodes + nRootNodes;
#	endif

#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in output tree to rSPR2\n");
		getchar();
		}
#endif

	return (NO_ERROR);
	
}





int Move_RanSPR3 (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* This is a random SPR move controlled by a window defined by a certain node distance radius,
       within which the random subtree swapping occurs */
	
	int			i, topologyHasChanged, nCrownNodes, nRootNodes, directionLeft, directionUp, 
				isVPriorExp, moveInRoot, foundFirst, windowDiameter, numWindowNodes, newNumWindowNodes;
	MrBFlt		m, x, y, tuning, maxV, minV, moveProb, brlensExp=0.0;
	TreeNode	*p, *a, *b, *c, *d, *u, *v, *brlenNode[7], *q, *windowNode[120];
	Tree		*t;
	ModelParams *mp;

	/* these parameters should be possible to set by user */
	moveProb = mvp[0];	/* extension probability */
	tuning = mvp[1];        /* Larget & Simon's tuning parameter lambda */
	windowDiameter = 4;		/* window diameter in number of nodes away from the cut branch */
							/* set it to a value between 1 and 4 (above 4 requires more space in windowNode) */
	/* get tree */
	t = GetTree (param, chain, state[chain]);
#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in input tree to rSPR3\n");
		getchar();
		}
#endif

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* max and min brlen */
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}

	topologyHasChanged = NO;

#	if defined (DEBUG_RanSPR)
	printf ("Before:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
#	endif
	
	/* pick an internal branch */
	do
		{
		p = t->intDownPass[(int)(RandomNumber(seed)*t->nIntNodes)];
		} while (p->anc->anc == NULL);
		
	/* set up pointers for nodes around the picked branch */
	/* cut the tree into crown, root and attachment part */
	/* change the relevant lengths in the attachment part */
	/* the lengths of a and v are automatically contained in the */
	/* "attachment" part but the length of c has to be stored in x */
	v = p;
	u = p->anc;

	/* store brlen node */
	brlenNode[3] = v;

	/* mark distance of nodes from the node v */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		p->x = -1;
		}
	
	v->x = 0;
	u->x = 0;

	/* downpass */
	for (p=u; p->anc!= NULL; p=p->anc)
		{
		p->anc->x = p->x+1;
		}
		
	/* uppass */
	for (i=t->nNodes-2; i>=0; i--)
		{
		p = t->allDownPass[i];
		if (p->x < 0)
			p->x = p->anc->x + 1;
		}
		
	/* now collect nodes */
	for (i=numWindowNodes=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->x >= 2 && p->x <= windowDiameter+1)
			windowNode[numWindowNodes++] = p;
		}
	if (numWindowNodes > 120)
		{
		printf ("error\n");
		ShowNodes (t->root, 0, t->isRooted);
		for (i=0; i<t->nNodes; i++)
			printf ("%d\t%d\n", t->allDownPass[i]->index, t->allDownPass[i]->x);
		getchar();
		}

	/* find the attachment point */
	if (RandomNumber (seed) > moveProb)
		{
		q = v->left;
		moveInRoot = NO;
		}
	else
		{
		q = windowNode[(int)(RandomNumber(seed)*numWindowNodes)];
		}
	
	/* mark crown subtree */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		p->marked = NO;
		}
	v->marked = YES;

	for (i=t->nNodes-2; i>=0; i--)
		{
		p = t->allDownPass[i];
		if (p->anc->marked == YES)
			p->marked = YES;
		}

	/* find the subtree */
	if (q->marked == YES)
		moveInRoot = NO;
	else
		moveInRoot = YES;

	/* mark the path of the move */
	for (i=0; i<t->nNodes; i++)
		t->allDownPass[i]->marked = NO;

	if (moveInRoot == NO)
		{
		p = q;
		while (p != v)
			{
			p->marked = YES;
			p = p->anc;
			}
		v->marked = YES;
		}
	else
		{
		p = q;
		while (p != NULL)
			{
			p->marked = YES;
			p = p->anc;
			}
		foundFirst = NO;
		p = v;
		while (p != NULL)
			{
			if (p->marked == NO)
				p->marked = YES;
			else if (foundFirst == YES)
				p->marked = NO;
			else
				foundFirst = YES;
			p = p->anc;
			}
		}

	/* set up pointers for crown part */
	/* this also determines direction of move in crown part */
	if (v->left->marked == YES)
		{
		c = v->left;
		d = v->right;
		directionLeft = YES;
		}
	else
		{
		c = v->right;
		d = v->left;
		directionLeft = NO;
		}

	/* store brlen nodes and brlen to move */
	brlenNode[0] = d;
	brlenNode[1] = c;
	x = c->length;

	/* cut and reconnect crown part */
	c->anc = d;
	d->anc = c;
	
	/* mark nodes in root part */
	/* also determines direction of move in root part */
	if (u->anc->marked == NO)
		{
		if (u->left == v)
			a = u->right;
		else
			a = u->left;
		b = u->anc;
		directionUp = YES;
		}
	else
		{
		if (u->left == v)
			b = u->right;
		else
			b = u->left;
		a = u->anc;
		directionUp = NO;
		}

	/* store brlen nodes */
	if (directionUp == YES)
		{
		brlenNode[4] = u;
		brlenNode[5] = a;
		}
	else
		{
		brlenNode[4] = b;
		brlenNode[5] = u;
		}

	/* cut root part*/
	/* store branch to move in u->length */
	if (directionUp == NO) 
		{
		b->anc = a;
		if (a->left == u)
			a->left = b;
		else
			a->right = b;
		}
	else 
		{
		a->anc = b;
		if (b->left == u)
			b->left = a;
		else
			b->right = a;
		y = a->length;
		a->length = u->length;
		u->length = y;
		a->upDateTi = YES;
		u->upDateTi = YES;
		}

	/* move around in root subtree */
	nRootNodes = 0;
	if (moveInRoot == YES)
		{
		for (nRootNodes=0; a->marked == YES; nRootNodes++) 
			{
			if (directionUp == YES) 
				{
				/* going up tree */
				if (a->left == NULL)
					break;
				else if (a->left->marked == NO && a->right->marked == NO)
					break;		/* don't go further */
				topologyHasChanged = YES;
				b = a;
				if (a->left->marked == YES)
					a = a->left;
				else
					a = a->right;
				if (u->isLocked == YES)
					{
					b->isLocked = YES;
					u->isLocked = NO;
					b->lockID = u->lockID;
					u->lockID = 0;
					}
				}
			else 
				{
				/* going down tree */
				if (a->anc == NULL || u->isLocked == YES)
					break;		/* can't go further */
				topologyHasChanged = YES;
				if (a->anc->marked == NO) 
					{
					/* try switching direction */
					/* find sister of a */
					if (a->left == b) 
						{
						a = a->right;
						}
					else 
						{  
						a = a->left;
						}
					/* as long as we are moving upwards
					the cond likes to update will be
					flagged by the last pass from u to the root */
					if (a->marked == NO)
						{
						b = a->anc;
						b->upDateCl = YES;
						a = a->anc->anc;
						break;			/* go back and one node down, unsuccessful attempt */
						}
					else
						{
						b = a->anc;
						directionUp = YES;	/* successful attempt */
						}
					}	
				else 
					{	/* continue down */					
					b = a;
					a = a->anc;
					b->upDateCl = YES; 
					if (b->isLocked == YES)
						{
						u->isLocked = YES;
						b->isLocked = NO;
						u->lockID = b->lockID;
						b->lockID = 0;
						}
					}
				}
			}
		}

	/* store brlen nodes */
	if (nRootNodes > 0)
		{
		if (directionUp == YES)
			{
			brlenNode[6] = a;
			brlenNode[5] = u;
			}
		else
			{
			brlenNode[6] = u;
			brlenNode[5] = b;
			}
		}

	/* move around in crown subtree */
	nCrownNodes = 0;
	if (moveInRoot == NO)		
		{
		for (nCrownNodes=0; c->left != NULL; nCrownNodes++) 
			{
			if (c->left->marked == NO && c->right->marked == NO)
				break;	/* can't go further */
			topologyHasChanged = YES;
			if (c->left->marked == YES) 
				{
				/* rotate c anticlockwise - prepare pointers for move left */
				c->anc = c->left;  /* the root will be in the direction we are heading */
				c->left = c->right;
				c->right = d;
				}
			else 
				{
				/* rotate c clockwise - prepare pointers for move right */
				c->anc = c->right;	/* the root will be in the direction we are heading */
				c->right = c->left;
				c->left = d;  
				}
			/* OK - let's move!; c->anc points in the right direction
			don't forget to move the branch lengths as well */
			d = c;
			c = c->anc;
			d->length = c->length;
			d->upDateCl = YES; 
			d->upDateTi = YES;
			}
		}

	/* store brlen nodes */
	if (nCrownNodes > 0)
		{
		brlenNode[2] = c;
		brlenNode[1] = d;
		}

	/* combine the subtrees */
	c->anc = v;
	d->anc = v;
	if (directionLeft == YES) 
		{
		v->left = c;
		v->right = d;
		}
	else 
		{
		v->left = d;
		v->right = c;
		}

	/* the dangling branch is inserted in reverted position
	   such that the back move will be possible
	   if we have moved around in crown subtree
	   otherwise it is left in its original position */
	if (nCrownNodes > 0)
		{
		d->length = x;
		d->upDateTi = YES;
		}
	else
		{
		c->length = x;
		}	

	if (directionUp == YES) 
		{
		u->anc = b;
		if (u->left == v)
			u->right = a;
		else 
			u->left = a;
		a->anc = u;
		if (b->left == a)
			b->left = u;
		else
			b->right = u;
		/* the dangling branch is contained in u->length
		   and will automatically be inserted in the right position
		   to enable the back move regardless of whether it was
		   initially directed upwards or downwards
		   BUT if we haven't moved in root subtree, it is advantageous (necessary
		   for rooted trees) to avoid switching branches, which occurs otherwise
		   if directionUp == YES */
		if (nRootNodes == 0) 
			{
			x = u->length;
			u->length = a->length;
			a->length = x;
			a->upDateTi = NO;
			u->upDateTi = NO;
			}
		}
	else 
		{
		u->anc = a;
		if (u->left == v)
			u->right = b;
		else 
			u->left = b;
		b->anc = u;
		if (a->left == b)
			a->left = u;
		else
			a->right = u;
		/* the modified branch contained in u->length will have
		   to be moved to b->length to enable back move
		   BUT if we haven't moved, it is better to keep it in place
		   (necessary for rooted trees) */
		if (nRootNodes > 0) 
			{
			x = u->length;
			u->length = b->length;
			b->length = x;
			b->upDateTi = YES;
			u->upDateTi = YES;
			}
		}
	
	/* modify branch lengths */
	/* first modify length of middle branch */
	m = brlenNode[3]->length;
	x = m * exp(tuning * (RandomNumber(seed) - 0.5));		/* save the modified dangling branch for later use */
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	brlenNode[3]->length = x;
	brlenNode[3]->upDateTi = YES;

	/* update proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - x);

	/* if no move in crown, then select randomly, otherwise always the moved branch */
	if (nCrownNodes == 0 && RandomNumber (seed) < 0.5)
		p = brlenNode[0];
	else
		p = brlenNode[1];

	/* modify branch length */
	m = p->length;
	x = m * exp(tuning * (RandomNumber(seed) - 0.5));
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	p->length = x;
	p->upDateTi = YES;

	/* update proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - x);	
		
	/* if no move in root, then select randomly, otherwise always the moved branch */
	if (nRootNodes == 0 && RandomNumber(seed) < 0.5)
		p = brlenNode[4];
	else
		p = brlenNode[5];
	
	/* modify branch length but not if 'root' branch in rooted tree */
	if (t->isRooted == NO || p->anc->anc != NULL)
		{
		m = p->length;
		x = m * exp(tuning * (RandomNumber(seed) - 0.5));
		while (x < minV || x > maxV)
			{
			if (x < minV)
				x = minV * minV / x;
			else if (x > maxV)
				x = maxV * maxV / x;
			}
		p->length = x;
		p->upDateTi = YES;

		/* update proposal and prior ratio based on length modification */
		(*lnProposalRatio) += log (x / m);
		if (isVPriorExp == YES)
			(*lnPriorRatio) += brlensExp * (m - x);	
		}

	/* set flags for update of cond likes from v and down to root */
	p = v;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}

	/* calculate new number of nodes */
	if (topologyHasChanged == YES)
		{
	    /* first, mark distance of nodes from the new position of node v */
		for (i=0; i<t->nNodes; i++)
			{
			p = t->allDownPass[i];
			p->x = -1;
			}
	
		v->x = 0;
		v->anc->x = 0;

		/* downpass */
		for (p=u; p->anc!= NULL; p=p->anc)
			{
			p->anc->x = p->x+1;
			}
		
		/* uppass */
		for (i=t->nNodes-2; i>=0; i--)
			{
			p = t->allDownPass[i];
			if (p->x < 0)
				p->x = p->anc->x + 1;
			}
		
		/* now count nodes */
		for (i=newNumWindowNodes=0; i<t->nNodes; i++)
			{
			p = t->allDownPass[i];
			if (p->x >= 2 && p->x <= windowDiameter+1)
				newNumWindowNodes++;
			}

		/* update proposal ratio */
		(*lnProposalRatio) += log (newNumWindowNodes / numWindowNodes);
		}

#	if defined (DEBUG_RanSPR)
	printf ("After:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  c: %d  d: %d  a: %d  b: %d q: %d\n",v->index, u->index, 
		c->index, d->index, a->index, b->index, q->index);
	printf ("No. nodes moved in root subtree: %d\n",nRootNodes);
	printf ("No. nodes moved in crown subtree: %d\n",nCrownNodes);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

	gNodeMoves = nCrownNodes + nRootNodes;
#	endif

#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in output tree to rSPR3\n");
		getchar();
		}
#endif

	return (NO_ERROR);
	
}





int Move_RanSPR4 (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* This move is like Move_RanSPR3, except that it swaps branches in subtrees with equal probabilities */
	
	int			i, topologyHasChanged, nCrownNodes, nRootNodes, directionLeft, directionUp, 
				isVPriorExp, moveInRoot, foundFirst, windowDiameter, numWindowNodes, newNumWindowNodes;
	MrBFlt		m, x, y, tuning, maxV, minV, moveProb, brlensExp=0.0;
	TreeNode	*p, *a, *b, *c, *d, *u, *v, *brlenNode[7], *q, *windowNode[120];
	Tree		*t;
	ModelParams *mp;

	/* these parameters should be possible to set by user */
	moveProb = mvp[0];	/* extension probability */
	tuning = mvp[1];        /* Larget & Simon's tuning parameter lambda */
	windowDiameter = 4;		/* window diameter in number of nodes away from the cut branch */
							/* set it to a value between 1 and 4 (above 4 requires more space in windowNode) */
	/* get tree */
	t = GetTree (param, chain, state[chain]);
#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in input tree to rSPR4\n");
		getchar();
		}
#endif

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* max and min brlen */
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0] > BRLENS_MIN ? mp->brlensUni[0] : BRLENS_MIN;
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}

	topologyHasChanged = NO;

#	if defined (DEBUG_RanSPR)
	printf ("Before:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
#	endif
	
	/* pick an internal branch */
	do
		{
		p = t->intDownPass[(int)(RandomNumber(seed)*t->nIntNodes)];
		} while (p->anc->anc == NULL);
		
	/* set up pointers for nodes around the picked branch */
	/* cut the tree into crown, root and attachment part */
	/* change the relevant lengths in the attachment part */
	/* the lengths of a and v are automatically contained in the */
	/* "attachment" part but the length of c has to be stored in x */
	v = p;
	u = p->anc;

	/* store brlen node */
	brlenNode[3] = v;

	/* mark distance of nodes from the node v */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		p->x = -1;
		}
	
	v->x = 0;
	u->x = 0;

	/* downpass */
	for (p=u; p->anc!= NULL; p=p->anc)
		{
		p->anc->x = p->x+1;
		}
		
	/* uppass */
	for (i=t->nNodes-2; i>=0; i--)
		{
		p = t->allDownPass[i];
		if (p->x < 0)
			p->x = p->anc->x + 1;
		}
		
	/* mark crown part of tree */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		p->marked = NO;
		}
	v->marked = YES;
	for (i=t->nNodes-2; i>=0; i--)
		{
		p = t->allDownPass[i];
		if (p->anc->marked == YES)
			p->marked = YES;
		}

	/* count number of root and crownnodes */
	for (i=nRootNodes=nCrownNodes=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->x >= 2 && p->x <= windowDiameter+1)
			{
			if (p->marked == YES)
				nCrownNodes++;
			else
				nRootNodes++;
			}
		}

	/* choose subtree */
	if (nCrownNodes == 0)
		moveInRoot = YES;
	else if (nRootNodes == 0)
		moveInRoot = NO;
	else if (RandomNumber (seed) < 0.5)
		moveInRoot = YES;
	else
		moveInRoot = NO;
	nRootNodes = nCrownNodes = 0;

	/* now collect nodes */
	for (i=numWindowNodes=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->x >= 2 && p->x <= windowDiameter+1 &&
			((moveInRoot == YES && p->marked == NO) || (moveInRoot == NO && p->marked == YES)))
			windowNode[numWindowNodes++] = p;
		}
	if (numWindowNodes > 120)
		{
		printf ("error\n");
		ShowNodes (t->root, 0, t->isRooted);
		for (i=0; i<t->nNodes; i++)
			printf ("%d\t%d\n", t->allDownPass[i]->index, t->allDownPass[i]->x);
		getchar();
		}

	/* find the attachment point */
	if (RandomNumber (seed) > moveProb)
		{
		q = v->left;
		moveInRoot = NO;
		}
	else
		{
		q = windowNode[(int)(RandomNumber(seed)*numWindowNodes)];
		}
	
	/* mark crown subtree */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		p->marked = NO;
		}
	v->marked = YES;

	for (i=t->nNodes-2; i>=0; i--)
		{
		p = t->allDownPass[i];
		if (p->anc->marked == YES)
			p->marked = YES;
		}

	/* mark the path of the move */
	for (i=0; i<t->nNodes; i++)
		t->allDownPass[i]->marked = NO;

	if (moveInRoot == NO)
		{
		p = q;
		while (p != v)
			{
			p->marked = YES;
			p = p->anc;
			}
		v->marked = YES;
		}
	else
		{
		p = q;
		while (p != NULL)
			{
			p->marked = YES;
			p = p->anc;
			}
		foundFirst = NO;
		p = v;
		while (p != NULL)
			{
			if (p->marked == NO)
				p->marked = YES;
			else if (foundFirst == YES)
				p->marked = NO;
			else
				foundFirst = YES;
			p = p->anc;
			}
		}

	/* set up pointers for crown part */
	/* this also determines direction of move in crown part */
	if (v->left->marked == YES)
		{
		c = v->left;
		d = v->right;
		directionLeft = YES;
		}
	else
		{
		c = v->right;
		d = v->left;
		directionLeft = NO;
		}

	/* store brlen nodes and brlen to move */
	brlenNode[0] = d;
	brlenNode[1] = c;
	x = c->length;

	/* cut and reconnect crown part */
	c->anc = d;
	d->anc = c;
	
	/* mark nodes in root part */
	/* also determines direction of move in root part */
	if (u->anc->marked == NO)
		{
		if (u->left == v)
			a = u->right;
		else
			a = u->left;
		b = u->anc;
		directionUp = YES;
		}
	else
		{
		if (u->left == v)
			b = u->right;
		else
			b = u->left;
		a = u->anc;
		directionUp = NO;
		}

	/* store brlen nodes */
	if (directionUp == YES)
		{
		brlenNode[4] = u;
		brlenNode[5] = a;
		}
	else
		{
		brlenNode[4] = b;
		brlenNode[5] = u;
		}

	/* cut root part*/
	/* store branch to move in u->length */
	if (directionUp == NO) 
		{
		b->anc = a;
		if (a->left == u)
			a->left = b;
		else
			a->right = b;
		}
	else 
		{
		a->anc = b;
		if (b->left == u)
			b->left = a;
		else
			b->right = a;
		y = a->length;
		a->length = u->length;
		u->length = y;
		a->upDateTi = YES;
		u->upDateTi = YES;
		}

	/* move around in root subtree */
	nRootNodes = 0;
	if (moveInRoot == YES)
		{
		for (nRootNodes=0; a->marked == YES; nRootNodes++) 
			{
			if (directionUp == YES) 
				{
				/* going up tree */
				if (a->left == NULL)
					break;
				else if (a->left->marked == NO && a->right->marked == NO)
					break;		/* don't go further */
				topologyHasChanged = YES;
				b = a;
				if (a->left->marked == YES)
					a = a->left;
				else
					a = a->right;
				if (u->isLocked == YES)
					{
					b->isLocked = YES;
					u->isLocked = NO;
					b->lockID = u->lockID;
					u->lockID = 0;
					}
				}
			else 
				{
				/* going down tree */
				if (a->anc == NULL || u->isLocked == YES)
					break;		/* can't go further */
				topologyHasChanged = YES;
				if (a->anc->marked == NO) 
					{
					/* try switching direction */
					/* find sister of a */
					if (a->left == b) 
						{
						a = a->right;
						}
					else 
						{  
						a = a->left;
						}
					/* as long as we are moving upwards
					the cond likes to update will be
					flagged by the last pass from u to the root */
					if (a->marked == NO)
						{
						b = a->anc;
						b->upDateCl = YES;
						a = a->anc->anc;
						break;			/* go back and one node down, unsuccessful attempt */
						}
					else
						{
						b = a->anc;
						directionUp = YES;	/* successful attempt */
						}
					}	
				else 
					{	/* continue down */					
					b = a;
					a = a->anc;
					b->upDateCl = YES; 
					if (b->isLocked == YES)
						{
						u->isLocked = YES;
						b->isLocked = NO;
						u->lockID = b->lockID;
						b->lockID = 0;
						}
					}
				}
			}
		}

	/* store brlen nodes */
	if (nRootNodes > 0)
		{
		if (directionUp == YES)
			{
			brlenNode[6] = a;
			brlenNode[5] = u;
			}
		else
			{
			brlenNode[6] = u;
			brlenNode[5] = b;
			}
		}

	/* move around in crown subtree */
	nCrownNodes = 0;
	if (moveInRoot == NO)		
		{
		for (nCrownNodes=0; c->left != NULL; nCrownNodes++) 
			{
			if (c->left->marked == NO && c->right->marked == NO)
				break;	/* can't go further */
			topologyHasChanged = YES;
			if (c->left->marked == YES) 
				{
				/* rotate c anticlockwise - prepare pointers for move left */
				c->anc = c->left;  /* the root will be in the direction we are heading */
				c->left = c->right;
				c->right = d;
				}
			else 
				{
				/* rotate c clockwise - prepare pointers for move right */
				c->anc = c->right;	/* the root will be in the direction we are heading */
				c->right = c->left;
				c->left = d;  
				}
			/* OK - let's move!; c->anc points in the right direction
			don't forget to move the branch lengths as well */
			d = c;
			c = c->anc;
			d->length = c->length;
			d->upDateCl = YES; 
			d->upDateTi = YES;
			}
		}

	/* store brlen nodes */
	if (nCrownNodes > 0)
		{
		brlenNode[2] = c;
		brlenNode[1] = d;
		}

	/* combine the subtrees */
	c->anc = v;
	d->anc = v;
	if (directionLeft == YES) 
		{
		v->left = c;
		v->right = d;
		}
	else 
		{
		v->left = d;
		v->right = c;
		}

	/* the dangling branch is inserted in reverted position
	   such that the back move will be possible
	   if we have moved around in crown subtree
	   otherwise it is left in its original position */
	if (nCrownNodes > 0)
		{
		d->length = x;
		d->upDateTi = YES;
		}
	else
		{
		c->length = x;
		}	

	if (directionUp == YES) 
		{
		u->anc = b;
		if (u->left == v)
			u->right = a;
		else 
			u->left = a;
		a->anc = u;
		if (b->left == a)
			b->left = u;
		else
			b->right = u;
		/* the dangling branch is contained in u->length
		   and will automatically be inserted in the right position
		   to enable the back move regardless of whether it was
		   initially directed upwards or downwards
		   BUT if we haven't moved in root subtree, it is advantageous (necessary
		   for rooted trees) to avoid switching branches, which occurs otherwise
		   if directionUp == YES */
		if (nRootNodes == 0) 
			{
			x = u->length;
			u->length = a->length;
			a->length = x;
			a->upDateTi = NO;
			u->upDateTi = NO;
			}
		}
	else 
		{
		u->anc = a;
		if (u->left == v)
			u->right = b;
		else 
			u->left = b;
		b->anc = u;
		if (a->left == b)
			a->left = u;
		else
			a->right = u;
		/* the modified branch contained in u->length will have
		   to be moved to b->length to enable back move
		   BUT if we haven't moved, it is better to keep it in place
		   (necessary for rooted trees) */
		if (nRootNodes > 0) 
			{
			x = u->length;
			u->length = b->length;
			b->length = x;
			b->upDateTi = YES;
			u->upDateTi = YES;
			}
		}
	
	/* modify branch lengths */
	/* first modify length of middle branch */
	m = brlenNode[3]->length;
	x = m * exp(tuning * (RandomNumber(seed) - 0.5));		/* save the modified dangling branch for later use */
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	brlenNode[3]->length = x;
	brlenNode[3]->upDateTi = YES;

	/* update proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - x);

	/* if no move in crown, then select randomly, otherwise always the moved branch */
	if (nCrownNodes == 0 && RandomNumber (seed) < 0.5)
		p = brlenNode[0];
	else
		p = brlenNode[1];

	/* modify branch length */
	m = p->length;
	x = m * exp(tuning * (RandomNumber(seed) - 0.5));
	while (x < minV || x > maxV)
		{
		if (x < minV)
			x = minV * minV / x;
		else if (x > maxV)
			x = maxV * maxV / x;
		}
	p->length = x;
	p->upDateTi = YES;

	/* update proposal and prior ratio based on length modification */
	(*lnProposalRatio) += log (x / m);
	if (isVPriorExp == YES)
		(*lnPriorRatio) += brlensExp * (m - x);	
		
	/* if no move in root, then select randomly, otherwise always the moved branch */
	if (nRootNodes == 0 && RandomNumber(seed) < 0.5)
		p = brlenNode[4];
	else
		p = brlenNode[5];
	
	/* modify branch length but not if 'root' branch in rooted tree */
	if (t->isRooted == NO || p->anc->anc != NULL)
		{
		m = p->length;
		x = m * exp(tuning * (RandomNumber(seed) - 0.5));
		while (x < minV || x > maxV)
			{
			if (x < minV)
				x = minV * minV / x;
			else if (x > maxV)
				x = maxV * maxV / x;
			}
		p->length = x;
		p->upDateTi = YES;

		/* update proposal and prior ratio based on length modification */
		(*lnProposalRatio) += log (x / m);
		if (isVPriorExp == YES)
			(*lnPriorRatio) += brlensExp * (m - x);	
		}

	/* set flags for update of cond likes from v and down to root */
	p = v;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}

	/* calculate new number of nodes */
	if (topologyHasChanged == YES)
		{
	    /* first, mark distance of nodes from the new position of node v */
		for (i=0; i<t->nNodes; i++)
			{
			p = t->allDownPass[i];
			p->x = -1;
			}
	
		v->x = 0;
		v->anc->x = 0;

		/* downpass */
		for (p=u; p->anc!= NULL; p=p->anc)
			{
			p->anc->x = p->x+1;
			}
		
		/* uppass */
		for (i=t->nNodes-2; i>=0; i--)
			{
			p = t->allDownPass[i];
			if (p->x < 0)
				p->x = p->anc->x + 1;
			}
		
		/* mark crown part of tree */
		for (i=0; i<t->nNodes; i++)
			{
			p = t->allDownPass[i];
			p->marked = NO;
			}
		v->marked = YES;
		for (i=t->nNodes-2; i>=0; i--)
			{
			p = t->allDownPass[i];
			if (p->anc->marked == YES)
				p->marked = YES;
			}

		/* now count nodes */
		for (i=newNumWindowNodes=0; i<t->nNodes; i++)
			{
			p = t->allDownPass[i];
			if (p->x >= 2 && p->x <= windowDiameter+1 &&
				((moveInRoot == YES && p->marked == NO) || (moveInRoot == NO && p->marked == YES)))
				newNumWindowNodes++;
			}

		/* update proposal ratio */
		(*lnProposalRatio) += log (newNumWindowNodes / numWindowNodes);
		}

#	if defined (DEBUG_RanSPR)
	printf ("After:\n");
	ShowNodes (t->root, 2, NO);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  c: %d  d: %d  a: %d  b: %d q: %d\n",v->index, u->index, 
		c->index, d->index, a->index, b->index, q->index);
	printf ("No. nodes moved in root subtree: %d\n",nRootNodes);
	printf ("No. nodes moved in crown subtree: %d\n",nCrownNodes);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

	gNodeMoves = nCrownNodes + nRootNodes;
#	endif

#if defined DEBUG_CONSTRAINTS
	if (CheckConstraints (t) == ERROR)
		{
		printf ("Constraint error in output tree to rSPR4\n");
		getchar();
		}
#endif

	return (NO_ERROR);
	
}





/*----------------------------------------------------------------
|
|	Move_RateMult_Dir: Change rate multiplier using Dirichlet
|      proposal.
|
----------------------------------------------------------------*/
int Move_RateMult_Dir (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, nRates;
	MrBFlt		alphaPi, *value, *subValue, numSites, *alphaDir, x, y, sum,
				*dirParm, *oldRate, *newRate;

    /* allocate memory */
    dirParm = (MrBFlt *) SafeCalloc (3*numCurrentDivisions, sizeof(MrBFlt));
    oldRate = dirParm + numCurrentDivisions;
    newRate = dirParm + 2*numCurrentDivisions;

	/* get number of rates */
	nRates = param->nValues;

	/* get pointer to rates and number of uncompressed chars */
	value = GetParamVals(param, chain, state[chain]);
	subValue = GetParamSubVals(param, chain, state[chain]);

	/* get Dirichlet parameters */
	alphaDir = subValue + nRates;

	/* calculate old ratesum proportions */
	numSites = 0.0;
	for (i=0; i<nRates; i++)
		numSites += value[i] * subValue[i];		/* numSites should be equal to the number of sites */
	for (i=0; i<nRates; i++)
		oldRate[i] = value[i] * subValue[i] / numSites;
	
    /* get alphaPi tuning parameter */
    alphaPi = mvp[0] * numSites;

    /* multiply old ratesum proportions with some large number to get new values close to the old ones */
	for (i=0; i<nRates; i++)
		dirParm[i] = oldRate[i] * alphaPi;
	
	/* get new values */
	DirichletRandomVariable (dirParm, newRate, nRates, seed);

	/* check new values */
	sum = 0.0;
	for (i=0; i<nRates; i++)
		{
		if (newRate[i] < DIR_MIN)
			newRate[i] = DIR_MIN;
		sum += newRate[i];
		}
	for (i=0; i<nRates; i++)
		newRate[i] /= sum;

	/* calculate and copy new rate ratio values back */
	for (i=0; i<nRates; i++)
		value[i] = newRate[i] * (numSites / subValue[i]);
	
	/* get proposal ratio */
	sum = 0.0;
	for (i=0; i<nRates; i++)
		sum += newRate[i]*alphaPi;
	x = LnGamma(sum);
	for (i=0; i<nRates; i++)
		x -= LnGamma(newRate[i]*alphaPi);
	for (i=0; i<nRates; i++)
		x += (newRate[i]*alphaPi-1.0)*log(oldRate[i]);
	sum = 0.0;
	for (i=0; i<nRates; i++)
		sum += oldRate[i]*alphaPi;
	y = LnGamma(sum);
	for (i=0; i<nRates; i++)
		y -= LnGamma(oldRate[i]*alphaPi);
	for (i=0; i<nRates; i++)
		y += (oldRate[i]*alphaPi-1.0)*log(newRate[i]);
	(*lnProposalRatio) = x - y;

	/* get prior ratio */
	x = y = 0.0;
	for (i=0; i<nRates; i++)
		x += (alphaDir[i]-1.0)*log(newRate[i]);
	for (i=0; i<nRates; i++)
		y += (alphaDir[i]-1.0)*log(oldRate[i]);
	(*lnPriorRatio) = x - y;

	/* Set update flags for all partitions that share the rate multiplier. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
		
	/* may need to hit update flag for cijks when you have a covarion model */
	for (i=0; i<param->nRelParts; i++)
		if (modelSettings[param->relParts[i]].nCijkParts > 1)
			modelSettings[param->relParts[i]].upDateCijk = YES;

    free (dirParm);

    return (NO_ERROR);

}





/*----------------------------------------------------------------
|
|	Move_RateMult_Slider: Change rate multiplier using slider
|      proposal.
|
----------------------------------------------------------------*/
int Move_RateMult_Slider (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, indexI, indexJ, nRates;
	MrBFlt		delta, *value, *subValue, sum, *alphaDir, x, numSites,
				oldRateProps[2], newRateProps[2], min, max;

	/* get number of rates */
	nRates = param->nValues;

	/* get pointer to rates and number of uncompressed chars */
	value = GetParamVals(param, chain, state[chain]);
	subValue = GetParamSubVals(param, chain, state[chain]);

	/* get Dirichlet prior parameters */
	alphaDir = subValue + nRates;

    /* randomly select two rates */
    indexI = (int) (RandomNumber(seed) * nRates);
    indexJ = (int) (RandomNumber(seed) * (nRates - 1));
    if (indexJ == indexI)
        indexJ = nRates - 1;

    /* get number of sites */
    numSites = 0;
    for (i=0; i<nRates; i++)
        numSites += subValue[i];

	/* calculate old ratesum proportions */
    sum = value[indexI] * subValue[indexI] + value[indexJ] * subValue[indexJ];
	oldRateProps[0] = value[indexI] * subValue[indexI] / sum;
	oldRateProps[1] = value[indexJ] * subValue[indexJ] / sum;
	
    /* get delta tuning parameter */
    delta = mvp[0];

    /* reflect */
    min = DIR_MIN / sum;
    max = 1.0 - min;

    x = oldRateProps[0] + delta * (RandomNumber(seed) - 0.5);
	while (x < min || x > max)
        {
        if (x < min)
			x = 2.0 * min - x;
		if (x > max)
            x = 2.0 * max - x;
		}
    
	/* set the new values */
    newRateProps[0] = x;
    newRateProps[1] = 1.0 - x;
    value[indexI] = newRateProps[0] * sum / subValue[indexI];
    value[indexJ] = newRateProps[1] * sum / subValue[indexJ];

	/* get proposal ratio */
	(*lnProposalRatio) = 0.0;

	/* get prior ratio */
	(*lnPriorRatio)  = (alphaDir[indexI]-1.0)*(log(newRateProps[0] * sum / numSites) - log(oldRateProps[0] * sum / numSites));
	(*lnPriorRatio) += (alphaDir[indexJ]-1.0)*(log(newRateProps[1] * sum / numSites) - log(oldRateProps[1] * sum / numSites));

	/* Set update flags for all partitions that share the rate multiplier. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
		
	/* may need to hit update flag for cijks when you have a covarion model */
	for (i=0; i<param->nRelParts; i++)
		if (modelSettings[param->relParts[i]].nCijkParts > 1)
			modelSettings[param->relParts[i]].upDateCijk = YES;

    return (NO_ERROR);

}





/*----------------------------------------------------------------
|
|	Move_Revmat_Dir: Change rate matrix using Dirichlet proposal
|      mechanism.
|
----------------------------------------------------------------*/
int Move_Revmat_Dir (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* change revMat using Dirichlet proposal */
	
	int			    i, nRates, isValid;
	MrBFlt		    oldRate[200], newRate[200], dirParm[200], *value, sum, x, y, *alphaDir, alphaPi;
	ModelParams     *mp;
    ModelInfo       *m;

	/* get model params and settings */
	mp = &modelParams[param->relParts[0]];
	m  = &modelSettings[param->relParts[0]];

	/* get rates and nRates */
	value = GetParamVals(param, chain, state[chain]);
	nRates = param->nValues;

	/* get so called alpha_pi parameter and adjust for number of components */
	alphaPi = mvp[0] * nRates;

	/* get Dirichlet parameters */
	if (m->dataType == PROTEIN)
		alphaDir = mp->aaRevMatDir;
	else
		alphaDir = mp->revMatDir;

	/* copy old rates */
	for (i=0; i<nRates; i++)
		oldRate[i] = value[i];
	
	/* multiply old ratesum props with some large number to get new values close to the old ones */
	for (i=0; i<nRates; i++)
		dirParm[i] = oldRate[i] * alphaPi;
	
	/* get new values */
	isValid = NO;
    do {
        DirichletRandomVariable (dirParm, newRate, nRates, seed);
    	isValid = YES;
        for (i=0; i<nRates; i++)
            {
            if (newRate[i] < RATE_MIN)
                {
                isValid = NO;
                break;
                }
            }
        } while (isValid == NO);

	/* copy new rate ratio values back */
	for (i=0; i<nRates; i++)
		{
		value[i] = newRate[i];
		}
	
	/* get proposal ratio */
	sum = 0.0;
	for (i=0; i<nRates; i++)
		sum += newRate[i]*alphaPi;
	x = LnGamma(sum);
	for (i=0; i<nRates; i++)
		x -= LnGamma(newRate[i]*alphaPi);
	for (i=0; i<nRates; i++)
		x += (newRate[i]*alphaPi-1.0)*log(oldRate[i]);
	sum = 0.0;
	for (i=0; i<nRates; i++)
		sum += oldRate[i]*alphaPi;
	y = LnGamma(sum);
	for (i=0; i<nRates; i++)
		y -= LnGamma(oldRate[i]*alphaPi);
	for (i=0; i<nRates; i++)
		y += (oldRate[i]*alphaPi-1.0)*log(newRate[i]);
	(*lnProposalRatio) = x - y;

	/* get prior ratio */
	x = y = 0.0;
	for (i=0; i<nRates; i++)
		x += (alphaDir[i]-1.0)*log(newRate[i]);
	for (i=0; i<nRates; i++)
		y += (alphaDir[i]-1.0)*log(oldRate[i]);
	(*lnPriorRatio) = x - y;

	/* Set update flags for all partitions that share this revmat. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
		
	/* Set update flags for cijks for all affected partitions */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);

}





/*----------------------------------------------------------------
|
|	Move_Revmat_DirMix: Dirichlet proposal for REVMAT_MIX. From
|      Huelsenbeck et al. (2004), but note that the prior density
|      is different in that paper because they set the rate sum
|      to 6, not to 1.
|
----------------------------------------------------------------*/
int Move_Revmat_DirMix (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, j, k, *growthFxn, nRates, isValid, groupSize[6];
	MrBFlt		*value, dirParm[6], newRate[6], oldRate[6], alphaPi, symDir, sum, x, y;
	ModelParams *mp;
    ModelInfo   *m;

	/* get model params and settings */
	mp = &modelParams[param->relParts[0]];
	m  = &modelSettings[param->relParts[0]];

	/* get growthFunction and nRates */
    value     = GetParamVals (param, chain, state[chain]);
	growthFxn = GetParamIntVals (param, chain, state[chain]);
    nRates    = GetKFromGrowthFxn(growthFxn);

    /* we can't do anything if there is only one rate */
    if (nRates == 1)
        {
        abortMove = YES;
        return (NO_ERROR);
        }

    /* extract unique rates from value vector */
    for (i=0; i<nRates; i++)
        oldRate[i] = 0.0;
    for (i=0; i<6; i++)
        oldRate[growthFxn[i]] += value[i];

	/* get so called alpha_pi parameter and adjust for number of components */
	alphaPi = mvp[0] * nRates;

    /* get symmetric dirichlet parameter */
    symDir  = mp->revMatSymDir;

	/* multiply old ratesum props with some large number to get new values close to the old ones */
	for (i=0; i<nRates; i++)
		dirParm[i] = oldRate[i] * alphaPi;
	
	/* get new values */
	isValid = NO;
    do {
        DirichletRandomVariable (dirParm, newRate, nRates, seed);
    	isValid = YES;
        for (i=0; i<nRates; i++)
            {
            if (newRate[i] < RATE_MIN)
                {
                isValid = NO;
                break;
                }
            }
        } while (isValid == NO);

	/* copy new unique rate ratio values back into the value array */
	for (i=0; i<nRates; i++)
        {
        k = 0;
        for (j=i; j<6; j++)
            {
            if (growthFxn[j] == i)
                k++;
            }
        for (j=i; j<6; j++)
            {
            if (growthFxn[j] == i)
                value[j] = newRate[i] / (MrBFlt) k;
            }
        }
	
	/* get proposal ratio */
	sum = 0.0;
	for (i=0; i<nRates; i++)
		sum += newRate[i]*alphaPi;
	x = LnGamma(sum);
	for (i=0; i<nRates; i++)
		x -= LnGamma(newRate[i]*alphaPi);
	for (i=0; i<nRates; i++)
		x += (newRate[i]*alphaPi-1.0)*log(oldRate[i]);
	sum = 0.0;
	for (i=0; i<nRates; i++)
		sum += oldRate[i]*alphaPi;
	y = LnGamma(sum);
	for (i=0; i<nRates; i++)
		y -= LnGamma(oldRate[i]*alphaPi);
	for (i=0; i<nRates; i++)
		y += (oldRate[i]*alphaPi-1.0)*log(newRate[i]);
	(*lnProposalRatio) = x - y;

    /* get group sizes, needed for prior ratio */
    for (i=0; i<nRates; i++)
        groupSize[i] = 0;
    for (i=0; i<6; i++)
        groupSize[growthFxn[i]]++;

	/* get prior ratio */
	x = y = 0.0;
	for (i=0; i<nRates; i++)
		x += (groupSize[i]*symDir-1.0)*log(newRate[i]);
	for (i=0; i<nRates; i++)
		y += (groupSize[i]*symDir-1.0)*log(oldRate[i]);
	(*lnPriorRatio) = x - y;

	/* Set update flags for all partitions that share this revmat. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
		
	/* Set update flags for cijks for all affected partitions */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

    return (NO_ERROR);

}





/*----------------------------------------------------------------
|
|	Move_Revmat_Slider: Change rate matrix using sliding window
|       move. Choose a pair of rates (e.g. r(A<>C), and r(A<>G)) at
|       random and denote them rA, and rB. Let oldProp = rA/(rA + rB)
|       and newProp = oldProp + delta(U - 0.5), where U is a uniform
|       random variable on the interval (0, 1] and delta is a tuning
|       parameter. Values that fall outside the boundaries are reflected
|       back in. Then set new_rA = newProp*(rA+rB) and new_rB =
|       (1-newProp)*(piA+piB). The Hastings ratio of this move is 1.0.
|
----------------------------------------------------------------*/
int Move_Revmat_Slider (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, j, nRates, isValid;
	MrBFlt		delta, *newRate, *oldRate, *priorAlpha, x, y, sum, min, max;
	ModelParams *mp;
    ModelInfo   *m;

	/* get model params and settings */
	mp = &modelParams[param->relParts[0]];
    m  = &modelSettings[param->relParts[0]];

	/* get Dirichlet parameters */
	if (m->dataType == PROTEIN)
		priorAlpha = mp->aaRevMatDir;
	else
		priorAlpha = mp->revMatDir;

    /* get the values we need */
	nRates = param->nValues;
	newRate = GetParamVals (param, chain, state[chain]);
	oldRate = GetParamVals (param, chain, state[chain] ^ 1);

	/* get window size */
	delta = mvp[0];

	/* choose a pair to change */
	i = (int) (RandomNumber(seed) * nRates);
    j = (int) (RandomNumber(seed) * (nRates-1));
    if (i == j)
        j = nRates-1;
    
    /* find new proportion */
    sum = oldRate[i] + oldRate[j];

    /* reflect */
    isValid = NO;
    min = RATE_MIN / sum;
    max = 1.0 - min;

	x   = oldRate[i] / sum;
	if( delta > max-min ) /* we do it to avoid following long while loop in case if delta is high */
		{
		delta = max-min;
		}
    y = x + delta * (RandomNumber(seed) - 0.5);
	do {
		if (y < min)
			y = 2.0 * min - y;
		else if (y > max)
            y = 2.0 * max - y;
        else
			isValid = YES;
		} while (isValid == NO);

	/* set the new values */
    newRate[i] = y * sum;
    newRate[j] = sum - newRate[i];

	/* get proposal ratio */
	*lnProposalRatio = 0.0;

	/* get prior ratio */
	/* (the Gamma part of the prior is the same) */
	x = (priorAlpha[i]-1.0)*log(newRate[i]);
	x += (priorAlpha[j]-1.0)*log(newRate[j]);
	y = (priorAlpha[i]-1.0)*log(oldRate[i]);
	y += (priorAlpha[j]-1.0)*log(oldRate[j]);
	(*lnPriorRatio) = x - y;

    /* Set update for entire tree */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
		
	/* Set update flags for cijks for all affected partitions. If this is a simple 4 X 4 model,
	   we don't take any hit, because we will never go into a general transition probability
	   calculator. However, for many models we do want to update the cijk flag, as the transition
	   probability matrices require diagonalizing the rate matrix. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);

}





/*----------------------------------------------------------------
|
|	Move_Revmat_SplitMerge1: Split or merge rates of rate matrix.
|      See Huelsenbeck et al. (2004). Note that the prior used
|      here is different from theirs. Also, a Beta proposal is
|      used instead of a uniform to propose new rate proportions.
|
----------------------------------------------------------------*/
int Move_Revmat_SplitMerge1 (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, j, k, index_i, index_j, n_i, n_j, foundFirstI, foundFirstJ,
                *newGrowthFxn, *oldGrowthFxn, nOldRates, nNewRates, merge,
                groupSize[6], nCompositeRates;
	MrBFlt		R, R_i, R_j, *newValue, *oldValue, newRate[6], oldRate[6], symDir,
                prob_split, prob_merge, dirParm[2], rateProps[2], x, alphaPi;
	ModelParams *mp;
    ModelInfo   *m;

	/* get model params and settings */
	mp = &modelParams[param->relParts[0]];
    m  = &modelSettings[param->relParts[0]];

    /* get the values we need */
    oldValue     = GetParamVals(param, chain, state[chain] ^ 1);
    newValue     = GetParamVals(param, chain, state[chain]);
    oldGrowthFxn = GetParamIntVals(param, chain, state[chain] ^ 1);
    newGrowthFxn = GetParamIntVals (param, chain, state[chain]);
    nOldRates    = GetKFromGrowthFxn(oldGrowthFxn);
    symDir       = mp->revMatSymDir;
    alphaPi      = mvp[0];      /* tuning parameter alpha */

    /* get the old rates */
    for (i=0; i<nOldRates; i++)
        oldRate[i] = 0.0;
    for (i=0; i<6; i++)
        oldRate[oldGrowthFxn[i]] += oldValue[i];

    /* decide whether to split or merge */
    if (nOldRates == 1)
        merge = NO;
    else if (nOldRates == 6)
        merge = YES;
    else if (RandomNumber(seed) < 0.5)
        merge = YES;
    else
        merge = NO;

    /* now split or merge */
    R = R_i = R_j = 0.0;
    if (merge == YES)
        {
        /* merge two rates */
        nNewRates = nOldRates - 1;

        /* determine split and merge probs */
        if (nNewRates == 1)
            prob_split = 1.0;
        else
            prob_split = 0.5;
        if (nOldRates == 6)
            prob_merge = 1.0;
        else
            prob_merge = 0.5;

        /* select two rates randomly */
        index_i = (int) (RandomNumber(seed) * nOldRates);
        index_j = (int) (RandomNumber(seed) * (nOldRates - 1));
        if (index_j == index_i)
            index_j = nOldRates - 1;

        /* make sure index_i is lower index */
        if (index_i > index_j)
            {
            i = index_i;
            index_i = index_j;
            index_j = i;
            }

        /* find group sizes */
        n_i = n_j = 0;
        for (i=0; i<6; i++)
            {
            if (oldGrowthFxn[i] == index_i)
                n_i++;
            else if (oldGrowthFxn[i] == index_j)
                n_j++;
            }

        /* adjust growth function */
        for (i=0; i<6; i++)
            {
            if (oldGrowthFxn[i] == index_j)
                newGrowthFxn[i] = index_i;
            else if (oldGrowthFxn[i] > index_j)
                newGrowthFxn[i] = oldGrowthFxn[i] - 1;
            else
                newGrowthFxn[i] = oldGrowthFxn[i];
            }

        /* find the new rates */
        for (i=0; i<nNewRates; i++)
            {
            if (i == index_i)
                newRate[i] = (oldRate[index_i] + oldRate[index_j]);
            else if (i < index_j)
                newRate[i] = oldRate[i];
            else if (i >= index_j)
                newRate[i] = oldRate[i+1];
            }

        /* copy new unique rate values back into the value array */
        for (i=0; i<nNewRates; i++)
            {
            k = 0;
            for (j=i; j<6; j++)
                {
                if (newGrowthFxn[j] == i)
                    k++;
                }
            for (j=i; j<6; j++)
                {
                if (newGrowthFxn[j] == i)
                    newValue[j] = newRate[i] / (MrBFlt) k;
                }
            }

        /* get the new and old rates (sum over parts) */
        R_i = oldRate[index_i];
        R_j = oldRate[index_j];
        R   = R_i + R_j;

        /* check group sizes after merge (before split in back move) */
        for (i=0; i<nNewRates; i++)
            groupSize[i] = 0;
        for (i=0; i<6; i++)
            groupSize[newGrowthFxn[i]]++;
        nCompositeRates = 0;
        for (i=0; i<nNewRates; i++)
            {
            if (groupSize[i] > 1)
                nCompositeRates++;
            }

        /* calculate prior ratio (different in the paper) */
        (*lnPriorRatio) = LnGamma(n_i * symDir) + LnGamma(n_j * symDir) - LnGamma ((n_i + n_j) * symDir);
        (*lnPriorRatio) += ((n_i + n_j) * symDir - 1.0) * log(R) - (n_i * symDir - 1.0) * log(R_i) - (n_j * symDir - 1.0) * log(R_j);

        /* calculate proposal ratio */
        (*lnProposalRatio) = log ( (prob_split / prob_merge) * ((nOldRates * (nOldRates - 1)) / (2.0 * nCompositeRates)) * (1.0 / ((pow(2, n_i + n_j - 1) - 1))) );

        /* adjust for Beta proposal in back move */
        dirParm[0] = alphaPi * n_i;
        dirParm[1] = alphaPi * n_j;
        rateProps[0] = R_i / R;
        rateProps[1] = R_j / R;
	    x  = LnGamma(dirParm[0] + dirParm[1]);
        x -= LnGamma(dirParm[0]);
        x -= LnGamma(dirParm[1]);
        x += (dirParm[0] - 1.0) * log(rateProps[0]);
        x += (dirParm[1] - 1.0) * log(rateProps[1]);
        (*lnProposalRatio) += x;

        /* Jacobian for the rate proportion */
        (*lnProposalRatio) -= log(R);
        }
    else
        {
        /* split two rates */
        nNewRates = nOldRates + 1;

        /* determine split and merge probs */
        if (nNewRates == 6)
            prob_merge = 1.0;
        else
            prob_merge = 0.5;
        if (nOldRates == 1)
            prob_split = 1.0;
        else
            prob_split = 0.5;

        /* check group sizes before split */
        for (i=0; i<nOldRates; i++)
            groupSize[i] = 0;
        for (i=0; i<6; i++)
            groupSize[oldGrowthFxn[i]]++;
        nCompositeRates = 0;
        for (i=0; i<nOldRates; i++)
            {
            if (groupSize[i] > 1)
                nCompositeRates++;
            }

        /* randomly select a rate with two or more components to split */
        k = (int) (RandomNumber(seed) * nCompositeRates);

        for (i=j=0; i<nOldRates; i++)
            {
            if (groupSize[i] > 1)
                {
                if (k == j)
                    break;
                j++;
                }
            }
        assert (i < nOldRates && groupSize[i] > 1);
        index_i = i; 

        /* adjust growth function */
        do {
            foundFirstI = foundFirstJ = NO;
            k = 0;
            index_j = -1;
            for (i=0; i<6; i++)
                {
                if (oldGrowthFxn[i] == index_i)
                    {
                    if (foundFirstI == NO)
                        {
                        newGrowthFxn[i] = index_i;
                        foundFirstI = YES;
                        }
                    else
                        {
                        if (RandomNumber(seed) < 0.5)
                            {
                            if (foundFirstJ == NO)
                                {
                                foundFirstJ = YES;
                                index_j = k + 1;    /* one more than previous max */
                                newGrowthFxn[i] = index_j;
                                }
                            else
                                {
                                newGrowthFxn[i] = index_j;
                                }
                            }
                        else
                            newGrowthFxn[i] = index_i;
                        }
                    }
                else if (foundFirstJ == YES && oldGrowthFxn[i] >= index_j)
                    newGrowthFxn[i] = oldGrowthFxn[i] + 1;
                else
                    newGrowthFxn[i] = oldGrowthFxn[i];
                if (foundFirstJ == NO && oldGrowthFxn[i] > k)
                    k = oldGrowthFxn[i];
                }
            } while (foundFirstJ == NO);

        /* find group sizes */
        n_i = n_j = 0;
        for (i=0; i<6; i++)
            {
            if (newGrowthFxn[i] == index_i)
                n_i++;
            else if (newGrowthFxn[i] == index_j)
                n_j++;
            }

        /* find old rate */
        R = oldRate[index_i];

        /* propose new rates */
        dirParm[0] = alphaPi * n_i;
        dirParm[1] = alphaPi * n_j;
        do {
            DirichletRandomVariable(dirParm, rateProps, 2, seed);
            R_i = rateProps[0] * R;
            R_j = rateProps[1] * R;
        }   while (R_i/n_i < RATE_MIN || R_j/n_j < RATE_MIN);

        /* set the new rates */
        for (i=0; i<nNewRates; i++)
            {
            if (i == index_i)
                newRate[i] = R_i;
            else if (i == index_j)
                newRate[i] = R_j;
            else if (i > index_j)
                newRate[i] = oldRate[i-1];
            else
                newRate[i] = oldRate[i];
            }

        /* copy new unique rate values back into the value array */
        for (i=0; i<nNewRates; i++)
            {
            k = 0;
            for (j=i; j<6; j++)
                {
                if (newGrowthFxn[j] == i)
                    k++;
                }
            for (j=i; j<6; j++)
                {
                if (newGrowthFxn[j] == i)
                    newValue[j] = newRate[i] / (MrBFlt) k;
                }
            }

        /* calculate prior ratio (different in the paper) */
        (*lnPriorRatio) = LnGamma((n_i + n_j) * symDir) - LnGamma(n_i * symDir) - LnGamma(n_j * symDir);
        (*lnPriorRatio) += (n_i * symDir - 1.0) * log(R_i) + (n_j * symDir - 1.0) * log(R_j) - ((n_i + n_j) * symDir - 1.0) * log(R);;

        /* calculate proposal ratio */
        (*lnProposalRatio) = log ( (prob_merge / prob_split) * ((2.0 * nCompositeRates) / (nNewRates * (nNewRates - 1))) * ((pow(2, n_i + n_j - 1) - 1)) );
        
        /* adjust for Beta proposal */
	    x  = LnGamma(dirParm[0] + dirParm[1]);
        x -= LnGamma(dirParm[0]);
        x -= LnGamma(dirParm[1]);
        x += (dirParm[0] - 1.0) * log(rateProps[0]);
        x += (dirParm[1] - 1.0) * log(rateProps[1]);
        (*lnProposalRatio) -= x;

        /* Jacobian for rate proportion */
        (*lnProposalRatio) += log (R);
        }

#if defined (DEBUG_SPLITMERGE)
    if (*lnPriorRatio != *lnPriorRatio)
        {
        printf ("prob_merge=%f prob_split=%f nCompositeRates=%d nOldRates=%d nNewRates=%d\n", prob_merge, prob_split, nCompositeRates, nOldRates, nNewRates);
        printf ("merge=%s n_i=%d n_j=%d rateProps[0]=%f R=%f R_i=%f R_j=%f\n", merge == NO ? "NO" : "YES", n_i, n_j, rateProps[0], R, R_i, R_j);
        printf ("Old rates={%f,%f,%f,%f,%f,%f}\n", oldValue[0], oldValue[1], oldValue[2], oldValue[3], oldValue[4], oldValue[5]);
        printf ("Old growth fxn={%d,%d,%d,%d,%d,%d}\n", oldGrowthFxn[0], oldGrowthFxn[1], oldGrowthFxn[2], oldGrowthFxn[3], oldGrowthFxn[4], oldGrowthFxn[5]);
        printf ("New rates={%f,%f,%f,%f,%f,%f}\n", newValue[0], newValue[1], newValue[2], newValue[3], newValue[4], newValue[5]);
        printf ("New growth fxn={%d,%d,%d,%d,%d,%d}\n", newGrowthFxn[0], newGrowthFxn[1], newGrowthFxn[2], newGrowthFxn[3], newGrowthFxn[4], newGrowthFxn[5]);
        printf ("lnPriorRatio=%f  lnProposalRatio=%f\n", *lnPriorRatio, *lnProposalRatio);
        getchar();
        }
#endif

    /* Set update flags for all partitions that share this revmat. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
		
	/* Set update flags for cijks for all affected partitions */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

    return (NO_ERROR);

}





/*----------------------------------------------------------------
|
|	Move_Revmat_SplitMerge2: Componentwise split or merge move.
|
----------------------------------------------------------------*/
int Move_Revmat_SplitMerge2 (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, k, n_i, n_j, index_i, index_j, groupIndex_i, groupIndex_j,
                *newGrowthFxn, *oldGrowthFxn;
	MrBFlt		R_i, R_j, r_j, alphaPi, *newValue, *oldValue, symDir,
                dirParm[2], rateProps[2], x;
	ModelParams *mp;
    ModelInfo   *m;

	/* get model params and settings */
	mp = &modelParams[param->relParts[0]];
    m  = &modelSettings[param->relParts[0]];

    /* get the values we need */
    oldValue     = GetParamVals(param, chain, state[chain] ^ 1);
    newValue     = GetParamVals(param, chain, state[chain]);
    oldGrowthFxn = GetParamIntVals(param, chain, state[chain] ^ 1);
    newGrowthFxn = GetParamIntVals (param, chain, state[chain]);
    symDir       = mp->revMatSymDir;
    alphaPi      = mvp[0];      /* tuning parameter */

    /* pick two component rates at random without replacement */
    index_i = (int) (RandomNumber(seed) * 6);
    index_j = (int) (RandomNumber(seed) * 5);
    if (index_j == index_i)
        index_j = 5;
    groupIndex_i = oldGrowthFxn[index_i];
    groupIndex_j = oldGrowthFxn[index_j];

    if (oldGrowthFxn[index_i] != oldGrowthFxn[index_j])
        {
        /* the rates are different, so merge them */

        /* calculate n_i, n_j, R_i and R_j before merge */
        n_i = n_j = 0;
        R_i = R_j = 0.0;
        for (i=0; i<6; i++)
            {
            if (oldGrowthFxn[i] == groupIndex_i)
                {
                n_i++;
                R_i += oldValue[i];
                }
            if (oldGrowthFxn[i] == groupIndex_j)
                {
                n_j++;
                R_j += oldValue[i];
                }
            }

        /* merge component rates by adding j to i */
        newGrowthFxn[index_j] = oldGrowthFxn[index_i];

        /* select a new rate for r_j */
        if (n_j == 1)
            r_j = oldValue[index_j];
        else
            {
            dirParm[0] = alphaPi * 1;
            dirParm[1] = alphaPi * (n_j - 1);
            do
                {
                DirichletRandomVariable(dirParm, rateProps, 2, seed);
                r_j = rateProps[0] * R_j;
                } while( R_j - r_j < RATE_MIN );
            }

        /* update new growth function */
        UpdateGrowthFxn(newGrowthFxn);

        /* we divide R_i + r_j equally among components of merged group,
           and R_j - r_j equally among split group */
        for (i=0; i<6; i++)
            {
            if (oldGrowthFxn[i] == oldGrowthFxn[index_i] || i == index_j)
                newValue[i] = (R_i + r_j) / (MrBFlt)(n_i + 1);
            else if (oldGrowthFxn[i] == oldGrowthFxn[index_j])
                newValue[i] = (R_j - r_j) / (MrBFlt)(n_j - 1);
            else
                newValue[i] = oldValue[i];
            }

        /* calculate prior ratio */
        if (n_j > 1)
            {
            /* no category disappeared */
            (*lnPriorRatio) += LnGamma (n_i * symDir) + LnGamma(n_j * symDir);
            (*lnPriorRatio) -= LnGamma((n_i +1)* symDir) + LnGamma((n_j-1) * symDir);
            (*lnPriorRatio) += ((n_i + 1) * symDir - 1.0) * log(R_i + r_j) + ((n_j - 1) * symDir - 1.0) * log(R_j - r_j);
            (*lnPriorRatio) -= (n_i * symDir - 1.0) * log(R_i) + (n_j * symDir - 1.0) * log(R_j);
            }
        else
            {
            /* j category disappeared */
            (*lnPriorRatio) += LnGamma (n_i * symDir) + LnGamma(n_j * symDir);
            (*lnPriorRatio) -= LnGamma((n_i +1)* symDir);
            (*lnPriorRatio) += ((n_i + 1) * symDir - 1.0) * log(R_i + r_j);
            (*lnPriorRatio) -= (n_i * symDir - 1.0) * log(R_i) + (n_j * symDir - 1.0) * log(R_j);
            }

        /* calculate proposal ratio; this is the probability of choosing the right category for rate j when splitting */
        k = GetKFromGrowthFxn(newGrowthFxn);
        (*lnProposalRatio) = log (1.0 / k);

        /* adjust for Beta proposal in back move */
        dirParm[0] = alphaPi * 1;
        dirParm[1] = alphaPi * n_i;
        rateProps[0] = r_j / (R_i + r_j);
        rateProps[1] = 1.0 - rateProps[0];
	    x  = LnGamma(dirParm[0] + dirParm[1]);
        x -= LnGamma(dirParm[0]);
        x -= LnGamma(dirParm[1]);
        x += (dirParm[0] - 1.0) * log(rateProps[0]);
        x += (dirParm[1] - 1.0) * log(rateProps[1]);
        (*lnProposalRatio) += x;

        /* adjust for Beta proposal in forward move */
        if (n_j > 1)
            {
            dirParm[0] = alphaPi * 1;
            dirParm[1] = alphaPi * n_j;
            rateProps[0] = r_j / R_j;
            rateProps[1] = 1.0 - rateProps[0];
	        x  = LnGamma(dirParm[0] + dirParm[1]);
            x -= LnGamma(dirParm[0]);
            x -= LnGamma(dirParm[1]);
            x += (dirParm[0] - 1.0) * log(rateProps[0]);
            x += (dirParm[1] - 1.0) * log(rateProps[1]);
            (*lnProposalRatio) -= x;
            }

        /* Jacobian */
        (*lnProposalRatio) -= log (R_i + r_j);
        if (n_j > 1)
            (*lnProposalRatio) += log (R_j);
        }
    else
        {
        /* split component rates because they are the same */

        /* split component rates by selecting new group for j from (0,K), with j starting a new group if index becomes the same */
        k = GetKFromGrowthFxn(oldGrowthFxn);
        newGrowthFxn[index_j] = (int) (RandomNumber(seed) * k);
        if (newGrowthFxn[index_j] == oldGrowthFxn[index_j])
            newGrowthFxn[index_j] = k + 1;

        /* update growth function and group indices */
        UpdateGrowthFxn(newGrowthFxn);
        groupIndex_i = newGrowthFxn[index_i];
        groupIndex_j = newGrowthFxn[index_j];

        /* calculate n_i, n_j, R_i and R_j after split */
        n_i = n_j = 0;
        R_i = R_j = 0.0;
        for (i=0; i<6; i++)
            {
            if (i == index_j)
                {
                R_i += oldValue[i];
                n_i++;
                }
            else if (newGrowthFxn[i] == groupIndex_i)
                {
                n_i++;
                R_i += oldValue[i];
                }
            else if (newGrowthFxn[i] == groupIndex_j)
                {
                n_j++;
                R_j += oldValue[i];
                }
            }

        /* select a new rate for r_j */
        dirParm[0] = alphaPi * 1;
        dirParm[1] = alphaPi * (n_i - 1);
        do
            {
            DirichletRandomVariable(dirParm, rateProps, 2, seed);
            r_j = rateProps[0] * R_i;
            }   while ( R_i-r_j < RATE_MIN );

        /* update n_i, n_j, R_i and R_j after split */
        n_i -= 1;
        n_j += 1;
        R_i -= r_j;
        R_j += r_j;

        /* we divide R_i equally among remaining components of split group,
           and R_j equally among new or expanded group */
        for (i=0; i<6; i++)
            {
            if (newGrowthFxn[i] == groupIndex_i)
                newValue[i] = R_i / (MrBFlt)(n_i);
            else if (newGrowthFxn[i] == groupIndex_j)
                newValue[i] = R_j / (MrBFlt)(n_j);
            else
                newValue[i] = oldValue[i];
            }

        /* calculate prior ratio */
        if (n_j > 1)
            {
            /* no new category created by split */
            (*lnPriorRatio) += LnGamma((n_i +1)* symDir) + LnGamma((n_j-1) * symDir);
            (*lnPriorRatio) -= LnGamma (n_i * symDir) + LnGamma(n_j * symDir);
            (*lnPriorRatio) += (n_i * symDir - 1.0) * log(R_i) + (n_j * symDir - 1.0) * log(R_j);
            (*lnPriorRatio) -= ((n_i + 1) * symDir - 1.0) * log(R_i + r_j) + ((n_j - 1) * symDir - 1.0) * log(R_j - r_j);
            }
        else
            {
            /* new category created by split */
            (*lnPriorRatio) += LnGamma((n_i +1)* symDir);
            (*lnPriorRatio) -= LnGamma (n_i * symDir) + LnGamma(n_j * symDir);
            (*lnPriorRatio) += (n_i * symDir - 1.0) * log(R_i) + (n_j * symDir - 1.0) * log(R_j);
            (*lnPriorRatio) -= ((n_i + 1) * symDir - 1.0) * log(R_i + r_j);
            }

        /* calculate proposal ratio; this is one over the probability of choosing the right category for rate j when splitting */
        k = GetKFromGrowthFxn(oldGrowthFxn);
        (*lnProposalRatio) = log (k);

        /* adjust for Beta proposal in back move */
        if (n_j > 1)
            {
            dirParm[0] = alphaPi * 1;
            dirParm[1] = alphaPi * (n_j - 1);
            rateProps[0] = r_j / R_j;
            rateProps[1] = 1.0 - rateProps[0];
	        x  = LnGamma(dirParm[0] + dirParm[1]);
            x -= LnGamma(dirParm[0]);
            x -= LnGamma(dirParm[1]);
            x += (dirParm[0] - 1.0) * log(rateProps[0]);
            x += (dirParm[1] - 1.0) * log(rateProps[1]);
            (*lnProposalRatio) += x;
            }

        /* adjust for Beta proposal in forward move */
        dirParm[0] = alphaPi * 1;
        dirParm[1] = alphaPi * n_i;
        rateProps[0] = r_j / (R_i + r_j);
        rateProps[1] = 1.0 - rateProps[0];
        x  = LnGamma(dirParm[0] + dirParm[1]);
        x -= LnGamma(dirParm[0]);
        x -= LnGamma(dirParm[1]);
        x += (dirParm[0] - 1.0) * log(rateProps[0]);
        x += (dirParm[1] - 1.0) * log(rateProps[1]);
        (*lnProposalRatio) -= x;

        /* Jacobian */
        (*lnProposalRatio) += log (R_i + r_j);
        if (n_j > 1)
            (*lnProposalRatio) -= log (R_j);
        }

    /* Set update flags for all partitions that share this revmat. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
		
	/* Set update flags for cijks for all affected partitions */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

    return (NO_ERROR);

}





int Move_Speciation (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* change speciation rate using sliding window */
	
	int			isLPriorExp, isValidL;
	MrBFlt		oldL, newL, window, minL, maxL, lambdaExp=0.0, ran, sR, eR, sF, oldLnPrior, newLnPrior,
                clockRate;
	char		*sS;
	ModelParams *mp;
	ModelInfo	*m;
	Tree		*t;

	/* get size of window, centered on current lambda value */
	window = mvp[0];

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* get extinction rate */
	m = &modelSettings[param->relParts[0]];
	eR = *(GetParamVals (m->extinctionRates, chain, state[chain]));
	
	/* get minimum and maximum values for lambda - mu */
    if (param->paramId == SPECRATE_UNI)
		{
		minL = mp->speciationUni[0];
		maxL = mp->speciationUni[1];
		isLPriorExp = NO;
		}
	else
		{
		minL = 0.0;
		maxL = KAPPA_MAX;
		lambdaExp = mp->speciationExp;
		isLPriorExp = YES;
		}

	/* get old value of lambda - mu */
	newL = oldL = *GetParamVals(param, chain, state[chain]);

	/* change value for lambda - mu */
	ran = RandomNumber(seed);
	if( maxL-minL < window )
		{
		window = maxL-minL;
		}
	newL = oldL + window * (ran - 0.5);
	
	/* check that new value is valid */
	isValidL = NO;
	do
		{
		if (newL < minL)
			newL = 2* minL - newL;
		else if (newL > maxL)
			newL = 2 * maxL - newL;
		else
			isValidL = YES;
		} while (isValidL == NO);

	/* get proposal ratio */
	*lnProposalRatio = 0.0;
	
	/* calculate prior ratio */
	t         = GetTree(modelSettings[param->relParts[0]].brlens,chain,state[chain]);
	sS        = mp->sampleStrat;
	sF        = mp->sampleProb;
	sR        = oldL;
    clockRate = *(GetParamVals(m->clockRate, chain, state[chain]));
	if (LnBirthDeathPriorPr (t, clockRate, &oldLnPrior, sR, eR, sS, sF) == ERROR)
		{
		MrBayesPrint ("%s   Problem calculating prior for birth-death process\n", spacer);
		return (ERROR);
		}
	sR = newL;
	if (LnBirthDeathPriorPr (t, clockRate, &newLnPrior, sR, eR, sS, sF) == ERROR)
		{
		MrBayesPrint ("%s   Problem calculating prior for birth-death process\n", spacer);
		return (ERROR);
		}
	if (isLPriorExp == NO)
		*lnPriorRatio = newLnPrior - oldLnPrior;
	else
		*lnPriorRatio = -lambdaExp * (newL - oldL) + (newLnPrior - oldLnPrior);
	
	/* copy new lambda - mu value back */
	*GetParamVals(param, chain, state[chain]) = newL;

	return (NO_ERROR);
	
}





int Move_Speciation_M (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* change speciation rate using multiplier */
	
	int			isLPriorExp, isValidL;
	MrBFlt		oldL, newL, minL, maxL, lambdaExp=0.0, ran, sR, eR, sF, oldLnPrior, newLnPrior,
				tuning, factor, clockRate;
	char		*sS;
	ModelParams *mp;
	ModelInfo	*m;
	Tree		*t;

	/* get tuning parameter */
	tuning = mvp[0];

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* get extinction rate */
	m = &modelSettings[param->relParts[0]];
	eR = *(GetParamVals (m->extinctionRates, chain, state[chain]));
	
	/* get minimum and maximum values for lambda - mu */
    if (param->paramId == SPECRATE_UNI)
		{
		minL = mp->speciationUni[0];
		maxL = mp->speciationUni[1];
		isLPriorExp = NO;
		}
	else
		{
		minL = 0.0;
		maxL = KAPPA_MAX;
		lambdaExp = mp->speciationExp;
		isLPriorExp = YES;
		}

	/* get old value of lambda - mu */
	newL = oldL = *GetParamVals(param, chain, state[chain]);

	/* change value for lambda - mu */
	ran = RandomNumber(seed);
	factor = exp(tuning * (ran - 0.5));
	newL = oldL * factor;
	
	/* check that new value is valid */
	isValidL = NO;
	do
		{
		if (newL < minL)
			newL = minL * minL / newL;
		else if (newL > maxL)
			newL = maxL * maxL / newL;
		else
			isValidL = YES;
		} while (isValidL == NO);

	/* get proposal ratio */
	*lnProposalRatio = log (newL / oldL);
	
	/* calculate prior ratio */
	t        = GetTree(modelSettings[param->relParts[0]].brlens,chain,state[chain]);
	sS       = mp->sampleStrat;
	sF       = mp->sampleProb;
	sR       = oldL;
    clockRate = *GetParamVals(m->clockRate, chain, state[chain]);
	if (LnBirthDeathPriorPr (t, clockRate, &oldLnPrior, sR, eR, sS, sF) == ERROR)
		{
		MrBayesPrint ("%s   Problem calculating prior for birth-death process\n", spacer);
		return (ERROR);
		}
	sR = newL;
	if (LnBirthDeathPriorPr (t, clockRate, &newLnPrior, sR, eR, sS, sF) == ERROR)
		{
		MrBayesPrint ("%s   Problem calculating prior for birth-death process\n", spacer);
		return (ERROR);
		}
	if (isLPriorExp == NO)
		*lnPriorRatio = newLnPrior - oldLnPrior;
	else
		*lnPriorRatio = -lambdaExp * (newL - oldL) + (newLnPrior - oldLnPrior);
	
	/* copy new lambda - mu value back */
	*GetParamVals(param, chain, state[chain]) = newL;

	return (NO_ERROR);
	
}





/*----------------------------------------------------------------
|
|	Move_SPRClock: This proposal mechanism changes the topology and
|      branch lengths of a rooted tree. 
|
|      Programmed by JH 2002-11-18
|
----------------------------------------------------------------*/
int Move_SPRClock (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{


	int				i, stopLoop, topologyHasChanged, direction=0, nTipsOnSideA=0, nTipsOnSideB=0, whichTip, tempI, isPathTerminusRoot=0;
	MrBFlt			attachmentRate, lnProbForward, lnProbReverse, dist=0.0, pathLength=0.0, pathLengthA=0.0, pathLengthB=0.0,
					oldAttachmentDepth=0.0, newAttachmentDepth=0.0, newD, oldD, oldCeiling=0.0, newCeiling=0.0, alphaPi, x, y, sum, len, baseOfPath=0.0,
					dirichletParameters[2], oldProportions[2], newProportions[2], newPathLengthA, newPathLengthB;
	TreeNode		*p, *q, *nodeToMove=NULL, *nodeToDetach=NULL, *oldAttachmentNode=NULL, *newAttachmentNode=NULL, *pathEndA=NULL, *pathEndB=NULL;
	Tree			*t;
	ModelParams 	*mp;
	
	/* Parameters used in this move. */
	alphaPi = mvp[0];              /* Dirichlet parameter.                           */
	attachmentRate = mvp[1];       /* The parameter of the exponential distribution. */
	
	/* Set the proposal ratio. */
	lnProbForward = lnProbReverse = (*lnProposalRatio) = 0.0;
	
	/* Set the prior ratio. */
	(*lnPriorRatio) = 0.0;
	
	/* Get the tree. */
	t = GetTree (param, chain, state[chain]);

#	if defined (DEBUG_SPRCLOCK)
	for (i=0; i<0; i++)
		RandomNumber(seed);
	printf ("Before:\n");
	ShowNodes (t->root, 2, YES);
#	endif

	/* get model params */
	mp = &modelParams[param->relParts[0]];

    /* Pick a branch to move and get pointers to nodes in area of rearrangement. */
	stopLoop = NO;
	do
		{
		nodeToMove = t->allDownPass[(int)(RandomNumber(seed)*t->nNodes)];
		if (nodeToMove->anc != NULL)
			if (nodeToMove->anc->anc != NULL)
				stopLoop = YES;
		} while (stopLoop == NO);
	nodeToDetach = nodeToMove->anc;
	if (nodeToMove->anc->left == nodeToMove)
		oldAttachmentNode = nodeToMove->anc->right;
	else
		oldAttachmentNode = nodeToMove->anc->left;

	/* Pick two tips to be the ends of the path. */
	nTipsOnSideA = nTipsOnSideB = 0;
	pathEndA = pathEndB = NULL;
	for (i=t->nNodes-1; i>=0; i--)
		{
		p = t->allDownPass[i];
		p->marked = NO;
		if (p == nodeToDetach)
			p->marked = YES;
		else if (p == nodeToMove)
			p->marked = 2;
			
		if (p->anc != NULL)
			{
			if (p != nodeToMove && p->anc->marked == YES)
				p->marked = YES;
			else if (p->anc->marked == 2)
				p->marked = 2;
			}
		if (p->left == NULL && p->right == NULL && p->marked == YES)
			nTipsOnSideA++;
		else if (p->left == NULL && p->right == NULL && p->marked == NO)
			{
			if (p != nodeToMove)
				nTipsOnSideB++;
			}
		}
	nTipsOnSideB++;
	whichTip = (int)(RandomNumber(seed)*nTipsOnSideA);
	tempI = 0;
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->left == NULL && p->right == NULL && p->marked == YES)
			{
			if (tempI == whichTip)
				{
				pathEndA = p;
				break;
				}
			tempI++;
			}
		}
	whichTip = (int)(RandomNumber(seed)*nTipsOnSideB);
	if (whichTip == 0)
		pathEndB = t->root;
	else
		{
		tempI = 1;
		for (i=0; i<t->nNodes; i++)
			{
			p = t->allDownPass[i];
			if (p->left == NULL && p->right == NULL && p->marked == NO && p != nodeToMove)
				{
				if (tempI == whichTip)
					{
					pathEndB = p;
					break;
					}
				tempI++;
				}
			}
		}
	isPathTerminusRoot = NO;
	if (pathEndB == t->root)
		isPathTerminusRoot = YES;
	if (pathEndA == NULL || pathEndB == NULL)
		{
		MrBayesPrint ("%s   Problem getting path ends in SPRClock\n", spacer);
		goto errorExit;
		}
	else if (pathEndA == t->root)
		{
		MrBayesPrint ("%s   Path end A should not be the root\n", spacer);
		goto errorExit;
		}
				
	/* Mark the nodes on the path. */
	pathLength = baseOfPath = 0.0;
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		p->marked = NO;
		if (p == pathEndA || p == pathEndB)
			p->marked = YES;
		if (p->left != NULL && p->right != NULL)
			{
			if (p->left->marked == YES && p->right->marked == NO)
				p->marked = YES;
			else if (p->left->marked == NO && p->right->marked == YES)
				p->marked = YES;
			else if (p->left->marked == YES && p->right->marked == YES)
				baseOfPath = p->nodeDepth;
			}
		if (p->marked == YES)
			pathLength += p->length;
		}	

	/* Get length of path above nodeToDetach */
	pathLengthA = oldAttachmentNode->anc->nodeDepth;
	if (isPathTerminusRoot == NO)
		{
		pathLength = 2.0 * baseOfPath;
		pathLengthB = 2.0 * baseOfPath - pathLengthA;
		}
	else
		{
		pathLength = 0.0;
		pathLengthB = 0.0;
		}
	
	/* Readjust time of node to be moved and lengths of branches above the node-to-move. Also,
	   get the old and new ceilings. */
	oldAttachmentDepth = oldAttachmentNode->anc->nodeDepth;
	if (nodeToMove->left == NULL && nodeToMove->right == NULL)
		{
		oldD = newD = 0.0;
		(*lnProposalRatio) += 0.0;
		}
	else
		{
		if (nodeToMove->left->length < nodeToMove->right->length)
			oldD = nodeToMove->left->length;
		else
			oldD = nodeToMove->right->length;
		len = oldD + nodeToMove->length;
		oldProportions[0] = oldD / len;
		oldProportions[1] = 1.0 - oldProportions[0];
		dirichletParameters[0] = oldProportions[0] * alphaPi;
		dirichletParameters[1] = oldProportions[1] * alphaPi;
		DirichletRandomVariable (dirichletParameters, newProportions, 2, seed);
		for (i=0; i<2; i++)
			if (newProportions[i] < 0.01)
				newProportions[i] = 0.01;
		sum = newProportions[0] + newProportions[1];
		newProportions[0] /= sum;
		newProportions[1] /= sum;
		sum = newProportions[0]*alphaPi + newProportions[1]*alphaPi;
		x = LnGamma(sum) - LnGamma(newProportions[0]*alphaPi) -  LnGamma(newProportions[1]*alphaPi);
		x += (newProportions[0]*alphaPi-1.0)*log(oldProportions[0]) + (newProportions[1]*alphaPi-1.0)*log(oldProportions[1]);
		sum = oldProportions[0]*alphaPi + oldProportions[1]*alphaPi;
		y = LnGamma(sum) - LnGamma(oldProportions[0]*alphaPi) - LnGamma(oldProportions[1]*alphaPi);
		y += (oldProportions[0]*alphaPi-1.0)*log(newProportions[0]) + (oldProportions[1]*alphaPi-1.0)*log(newProportions[1]);
		(*lnProposalRatio) += x - y;
		newD = newProportions[0] * len;
		/*printf ("%1.10lf %1.10lf %1.10lf %1.10lf \n", oldProportions[0], oldProportions[1], newProportions[0], newProportions[1]);*/
		}
	oldCeiling = nodeToMove->nodeDepth;
	newCeiling = oldCeiling + (newD - oldD);
	nodeToMove->nodeDepth = newCeiling;
	if (nodeToMove->left != NULL)
		nodeToMove->left->length = nodeToMove->nodeDepth - nodeToMove->left->nodeDepth;
	if (nodeToMove->right != NULL)
		nodeToMove->right->length = nodeToMove->nodeDepth - nodeToMove->right->nodeDepth;
	
	/* pick a direction to slide the node in */
	if (RandomNumber(seed) < 0.5)
		direction = UP;
	else
		direction = DOWN;
		
	/* pick the distance to move the node */
	if (direction == UP)
		{
		len = pathLengthA - newCeiling;
		
		do
			{
			dist = -(1.0 / attachmentRate) * log(1.0 - RandomNumber(seed) * (1.0 - exp(-attachmentRate*len)));
			if (dist > len)
				{
				MrBayesPrint ("%s   Problem with new attachment point (%lf %lf)\n", spacer, len, dist);
				goto errorExit;
				}
			newAttachmentDepth = oldAttachmentDepth - dist;
			} while (oldAttachmentDepth - dist < newCeiling);
			
		lnProbForward += log(attachmentRate) - attachmentRate*dist - log(1.0 - exp(-attachmentRate*len));
		newPathLengthA = pathLengthA - dist;
		newPathLengthB = pathLengthB + dist;
		if (isPathTerminusRoot == NO)
			{
			len = pathLengthB - oldCeiling;
			lnProbReverse += log(attachmentRate) - attachmentRate*dist - log(1.0 - exp(-attachmentRate*len));
			}
		else
			{
			lnProbReverse += log(attachmentRate) - attachmentRate*dist;
			}
		}
	else
		{
		if (isPathTerminusRoot == NO)
			{
			len = pathLengthB - newCeiling;
			dist = -(1.0 / attachmentRate) * log(1.0 - RandomNumber(seed) * (1.0 - exp(-attachmentRate*len)));
			if (dist > len)
				{
				MrBayesPrint ("%s   Problem with new attachment point\n", spacer);
				goto errorExit;
				}
			lnProbForward += log(attachmentRate) - attachmentRate*dist - log(1.0 - exp(-attachmentRate*len));
			}
		else
			{
			dist = -(1.0 / attachmentRate) * log(1.0 - RandomNumber(seed));
			lnProbForward += log(attachmentRate) - attachmentRate*dist;
			}
		newPathLengthA = pathLengthA + dist;
		newPathLengthB = pathLengthB - dist;
		len = newPathLengthA - oldCeiling;
		lnProbReverse += log(attachmentRate) - attachmentRate*dist - log(1.0 - exp(-attachmentRate*len));
		}
	
	/* figure out the new attachment depth */
	if (direction == UP)
		{
		/* figured out above */
		}
	else	
		{
		if (isPathTerminusRoot == NO)
			{
			if (oldAttachmentDepth + dist < baseOfPath)
				newAttachmentDepth = oldAttachmentDepth + dist;
			else
				{
				dist -= baseOfPath - oldAttachmentDepth;
				newAttachmentDepth = baseOfPath - dist;
				}
			}
		else
			{
			newAttachmentDepth = oldAttachmentDepth + dist;
			}		
		}
	if (newAttachmentDepth < newCeiling)
		{
		MrBayesPrint ("%s   Problem with new attachment point 1 (dist = %1.10lf len = %lf\n", spacer, dist, len);
		goto errorExit;
		}
		
	/* find the new attachment node */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->anc != NULL)
			{
			if (p->anc->anc != NULL)
				{
				if (p->marked == YES && p->nodeDepth < newAttachmentDepth && p->anc->nodeDepth > newAttachmentDepth)
					{
					newAttachmentNode = p;
					break;
					}
				}
			else
				{
				if (p->marked == YES && p->nodeDepth < newAttachmentDepth)
					{
					newAttachmentNode = p;
					break;
					}
				}
			}
		}	

#	if defined (DEBUG_SPRCLOCK)
	printf ("nodeToMove        = %d\n", nodeToMove->index);
	printf ("nodeToDetach      = %d\n", nodeToDetach->index);
	printf ("oldAttachmentNode = %d\n", oldAttachmentNode->index);
	printf ("nTipsOnSideA      = %d\n", nTipsOnSideA);
	printf ("nTipsOnSideB      = %d\n", nTipsOnSideB);
	printf ("pathLength        = %lf\n", pathLength);
	printf ("pathLengthA       = %lf\n", pathLengthA);
	printf ("baseOfPath        = %lf\n", baseOfPath);
	if (isPathTerminusRoot == NO)
		printf ("pathLengthB       = %lf\n", pathLengthB);
	else
		printf ("pathLengthB       = infinity\n");
	if (pathEndA != NULL)
		printf ("pathEndA          = %d\n", pathEndA->index);
	if (pathEndB != NULL)
		printf ("pathEndB          = %d\n", pathEndB->index);
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		printf ("%4d -- %d\n", p->index, p->marked);
		}
	printf ("oldCeiling        = %lf\n", oldCeiling);
	printf ("newCeiling        = %lf\n", newCeiling);
	if (direction == UP)
		printf ("dist up           = %lf\n", dist);
	else
		printf ("dist down         = %lf\n", dist);
	printf ("oldAttachmentDepth= %lf\n", oldAttachmentDepth);
	printf ("newAttachmentDepth= %lf\n", newAttachmentDepth);
	printf ("newAttachmentNode = %d\n", newAttachmentNode->index);
#	endif
			
	/* Check to see if the topology of the tree has changed. */
	if (newAttachmentNode == oldAttachmentNode || newAttachmentNode == nodeToDetach)
		topologyHasChanged = NO;
	else
		topologyHasChanged = YES;

	/* Make the rearrangement by detaching and reattaching the subtree. */
	if (topologyHasChanged == NO)
		{
		p = nodeToDetach->anc;
		nodeToDetach->nodeDepth = newAttachmentDepth;
		nodeToDetach->length = p->nodeDepth - nodeToDetach->nodeDepth;
		nodeToMove->length = nodeToDetach->nodeDepth - nodeToMove->nodeDepth;
		newAttachmentNode->length = newAttachmentNode->anc->nodeDepth - newAttachmentNode->nodeDepth;
		oldAttachmentNode->length = oldAttachmentNode->anc->nodeDepth - oldAttachmentNode->nodeDepth;
		if (newAttachmentNode->anc->anc == NULL)
			nodeToDetach->length = 0.0;
		}
	else
		{
		p = nodeToDetach->anc;
		if (p->left == nodeToDetach)
			p->left = oldAttachmentNode;
		else
			p->right = oldAttachmentNode;
		oldAttachmentNode->anc = p;
		oldAttachmentNode->length += nodeToDetach->length;
		nodeToDetach->left = nodeToDetach->right = nodeToDetach->anc = NULL;
		nodeToDetach->length = 0.0;
		nodeToDetach->nodeDepth = newAttachmentDepth;
		p = newAttachmentNode->anc;
		if (p->left == newAttachmentNode)
			{
			p->left = nodeToDetach;
			nodeToDetach->anc = p;
			nodeToDetach->left = newAttachmentNode;
			newAttachmentNode->anc = nodeToDetach;
			nodeToDetach->right = nodeToMove;
			nodeToMove->anc = nodeToDetach;
			}
		else
			{
			p->right = nodeToDetach;
			nodeToDetach->anc = p;
			nodeToDetach->right = newAttachmentNode;
			newAttachmentNode->anc = nodeToDetach;
			nodeToDetach->left = nodeToMove;
			nodeToMove->anc = nodeToDetach;
			}
		nodeToDetach->length = p->nodeDepth - nodeToDetach->nodeDepth;
		nodeToMove->length = nodeToDetach->nodeDepth - nodeToMove->nodeDepth;
		newAttachmentNode->length = nodeToDetach->nodeDepth - newAttachmentNode->nodeDepth;
		if (newAttachmentNode->anc->anc == NULL)
			nodeToDetach->length = 0.0;
		}
	
	/* Get the downpass sequence for the new tree if the topology has changed. */
	if (topologyHasChanged == YES)
		GetDownPass (t);
		
	/* Calculate another term in the proposal ratio */
	if (topologyHasChanged == YES)
		{
		lnProbForward += log(1.0 / nTipsOnSideA) + log(1.0 / nTipsOnSideB);

		nTipsOnSideA = nTipsOnSideB = 0;
		for (i=t->nNodes-1; i>=0; i--)
			{
			p = t->allDownPass[i];
			p->marked = NO;
			if (p == nodeToDetach)
				p->marked = YES;
			else if (p == nodeToMove)
				p->marked = 2;
				
			if (p->anc != NULL)
				{
				if (p != nodeToMove && p->anc->marked == YES)
					p->marked = YES;
				else if (p->anc->marked == 2)
					p->marked = 2;
				}
			if (p->left == NULL && p->right == NULL && p->marked == YES)
				nTipsOnSideA++;
			else if (p->left == NULL && p->right == NULL && p->marked == NO)
				{
				if (p != nodeToMove)
					nTipsOnSideB++;
				}
			}
		nTipsOnSideB++;
		lnProbReverse += log(1.0 / nTipsOnSideA) + log(1.0 / nTipsOnSideB);
		}

	/* Update proposal ratio. */
	(*lnProposalRatio) += lnProbReverse + lnProbForward;

	/* Set flags for update of transition probabilities. */
	oldAttachmentNode->upDateTi = YES;
	nodeToDetach->upDateTi = YES;
	nodeToMove->upDateTi = YES;
	newAttachmentNode->upDateTi = YES;
	if (nodeToMove->left != NULL && nodeToMove->right != NULL)
		nodeToMove->left->upDateTi = nodeToMove->right->upDateTi = YES;
		
	/* readjust branch lengths if they are too small */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->left != NULL && p->right != NULL && p->anc != NULL)
			{
			if (p->nodeDepth - p->left->nodeDepth < BRLENS_MIN || p->nodeDepth - p->right->nodeDepth < BRLENS_MIN)
				{
				if (p->left->nodeDepth > p->right->nodeDepth)
					p->nodeDepth = p->left->nodeDepth + BRLENS_MIN;
				else
					p->nodeDepth = p->right->nodeDepth + BRLENS_MIN;
				p->left->length  = p->nodeDepth - p->left->nodeDepth;
				p->right->length = p->nodeDepth - p->right->nodeDepth;
				p->length = p->anc->nodeDepth - p->nodeDepth;
				p->upDateTi = p->left->upDateTi = p->right->upDateTi = YES;
				q = p;
				while (q->anc != NULL)
					{
					q->upDateCl = YES;
					q = q->anc;
					}
				}
			}
		}

	/* check all of the branch lengths */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->anc != NULL)
			{
			if (p->anc->anc != NULL)
				{
				if (p->length < 0.0)
					{
					MrBayesPrint ("%s   Negative branch length in SPR clock\n", spacer);
					goto errorExit;
					}
				}
			}
		}
		
	/* Set flags for update of conditional likelihoods. */
	p = oldAttachmentNode->anc;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}
	p = nodeToMove;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* calculate prior ratio for clock trees */
	if (LogClockTreePriorRatio (param, chain, lnPriorRatio) == ERROR)
        return (ERROR);

#	if defined (DEBUG_SPRCLOCK)
	printf ("After:\n");
	ShowNodes (t->root, 2, YES);
	getchar();
#	endif

	return (NO_ERROR);
	
	errorExit:
		printf ("Before:\n");
		ShowNodes (t->root, 2, YES);
		printf ("nodeToMove        = %d\n", nodeToMove->index);
		printf ("nodeToDetach      = %d\n", nodeToDetach->index);
		printf ("oldAttachmentNode = %d\n", oldAttachmentNode->index);
		printf ("nTipsOnSideA      = %d\n", nTipsOnSideA);
		printf ("nTipsOnSideB      = %d\n", nTipsOnSideB);
		printf ("pathLength        = %lf\n", pathLength);
		printf ("pathLengthA       = %lf\n", pathLengthA);
		printf ("baseOfPath        = %lf\n", baseOfPath);
		if (isPathTerminusRoot == NO)
			printf ("pathLengthB       = %lf\n", pathLengthB);
		else
			printf ("pathLengthB       = infinity\n");
		if (pathEndA != NULL)
			printf ("pathEndA          = %d\n", pathEndA->index);
		if (pathEndB != NULL)
			printf ("pathEndB          = %d\n", pathEndB->index);
		for (i=0; i<t->nNodes; i++)
			{
			p = t->allDownPass[i];
			printf ("%4d -- %d\n", p->index, p->marked);
			}
		printf ("oldCeiling        = %lf\n", oldCeiling);
		printf ("newCeiling        = %lf\n", newCeiling);
		if (direction == UP)
			printf ("dist up           = %lf\n", dist);
		else
			printf ("dist down         = %lf\n", dist);
		printf ("oldAttachmentDepth= %lf\n", oldAttachmentDepth);
		printf ("newAttachmentDepth= %lf\n", newAttachmentDepth);
		printf ("newAttachmentNode = %d\n", newAttachmentNode->index);
		return (ERROR);

}





int Move_Statefreqs (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* change pi */
	int			i, nStates, isValid;
	MrBFlt		dirichletParameters[64], *newPi, *oldPi, *priorAlpha, sum, alphaPi, x, y;

	/* get the values we need */
	nStates = param->nSubValues;
	priorAlpha = GetParamVals(param, chain, state[chain]);
	newPi = GetParamSubVals (param, chain, state[chain]);
	oldPi = GetParamSubVals (param, chain, state[chain] ^ 1);
		
	/* tuning parameter */
	alphaPi = mvp[0]*nStates;

	/* multiply old values with some large number to get new values close to the old ones */
	for (i=0; i<nStates; i++)
		dirichletParameters[i] = oldPi[i] * alphaPi;

    do {
        DirichletRandomVariable (dirichletParameters, newPi, nStates, seed);
        isValid = YES;
        for (i=0; i<nStates; i++)
            {
		    if (newPi[i] < PI_MIN)
                {
                isValid = NO;
                break;
                }
            }
		} while (isValid == NO);

	/* get proposal ratio */
	sum = 0.0;
	for (i=0; i<nStates; i++)
		sum += newPi[i]*alphaPi;
	x = LnGamma(sum);
	for (i=0; i<nStates; i++)
		x -= LnGamma(newPi[i]*alphaPi);
	for (i=0; i<nStates; i++)
		x += (newPi[i]*alphaPi-1.0)*log(oldPi[i]);
	sum = 0.0;
	for (i=0; i<nStates; i++)
		sum += oldPi[i]*alphaPi;
	y = LnGamma(sum);
	for (i=0; i<nStates; i++)
		y -= LnGamma(oldPi[i]*alphaPi);
	for (i=0; i<nStates; i++)
		y += (oldPi[i]*alphaPi-1.0)*log(newPi[i]);
	(*lnProposalRatio) = x - y;

	/* get prior ratio */
	y = x = 0.0;					/* the Gamma part of the prior is the same */
	for (i=0; i<nStates; i++)
		x += (priorAlpha[i]-1.0)*log(newPi[i]);
	for (i=0; i<nStates; i++)
		y += (priorAlpha[i]-1.0)*log(oldPi[i]);
	(*lnPriorRatio) = x - y;
		
	/* Touch the entire tree */
    for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
		
	/* Set update flags for cijks for all affected partitions. If this is a simple 4 X 4 model,
	   we don't take any hit, because we will never go into a general transition probability
	   calculator. However, for many models we do want to update the cijk flag, as the transition
	   probability matrices require diagonalizing the rate matrix. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);
	
}





/*----------------------------------------------------------------
|
|	Move_Statefreqs_Slider: Change state frequencies using Slider proposal
|       mechanism.
|       Choose pairs of the parameter values (e.g. pi(A), and pi(G)) at
|       random and denote them piA, and piB. Let oldProp = piA/(piA + piB)
|       and newProp = oldProp + delta(U - 0.5), where U is a uniform random variable
|       on the interval (0, 1] and delta is a tuning parameter. Values
|       that fall outside the boundaries are reflected back in. Then
|       set newPiA = newProp*(piA+piB) and newPiB = (1-newProp)*(piA+piB).
|       The Hastings ratio of this move is 1.0.
|
----------------------------------------------------------------*/
int Move_Statefreqs_Slider (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, j, nStates, isValid;
	MrBFlt		delta, *newPi, *oldPi, *priorAlpha, x, y, sum, min, max;
	ModelParams *mp;

	/* get model params */
	mp = &modelParams[param->relParts[0]];

	/* get the values we need */
	nStates = param->nSubValues;
	priorAlpha = GetParamVals(param, chain, state[chain]);
	newPi = GetParamSubVals (param, chain, state[chain]);
	oldPi = GetParamSubVals (param, chain, state[chain] ^ 1);

	/* get window size */
	delta = mvp[0];

	/* choose a pair to change */
	i = (int) (RandomNumber(seed) * nStates);
    j = (int) (RandomNumber(seed) * (nStates-1));
    if (i == j)
        j = nStates-1;
    
    /* find new proportion */
    sum = oldPi[i] + oldPi[j];

    /* reflect */
    isValid = NO;
    min = PI_MIN / sum;
    max = 1.0 - min;

	x   = oldPi[i] / sum;
	if( delta > max-min ) /* we do it to avoid following long while loop in case if delta is high */
		{
		delta = max-min;
		}
    y = x + delta * (RandomNumber(seed) - 0.5);

	do {
		if (y < min)
			y = 2.0 * min - y;
		else if (y > max)
            y = 2.0 * max - y;
        else
			isValid = YES;
		} while (isValid == NO);

	/* set the new values */
    newPi[i] = y * sum;
    newPi[j] = sum - newPi[i];

	/* get proposal ratio */
	*lnProposalRatio = 0.0;

	/* get prior ratio */
	/* (the Gamma part of the prior is the same) */
	x = (priorAlpha[i]-1.0)*log(newPi[i]);
	x += (priorAlpha[j]-1.0)*log(newPi[j]);
	y = (priorAlpha[i]-1.0)*log(oldPi[i]);
	y += (priorAlpha[j]-1.0)*log(oldPi[j]);
	(*lnPriorRatio) = x - y;

    /* Set update for entire tree */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
		
	/* Set update flags for cijks for all affected partitions. If this is a simple 4 X 4 model,
	   we don't take any hit, because we will never go into a general transition probability
	   calculator. However, for many models we do want to update the cijk flag, as the transition
	   probability matrices require diagonalizing the rate matrix. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);

}





int Move_StatefreqsSymDirMultistate (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* change state freqs of multistate characters */
	/* ideally, we would let the likelihood calculator deal with only the affected character
	   but we do not have the mechanism for doing that in the current version of mrbayes, so
	   take the hit of updating all chars of the morph partition(s). */
	int		i, nStates, charIndex;
	MrBFlt	dirichletParameters[10], symDirAlphai, *newPi, *oldPi, sum, alphaPi, x, y;
	Model	*mp;

	/* tuning parameters */
	alphaPi = mvp[0];

	/* get model paramaters */
	mp = &modelParams[param->relParts[0]];

	/* select one character at random */
	charIndex = (int) (RandomNumber (seed) * param->nSympi);
	
	/* get the values we need */
	symDirAlphai = *GetParamVals(param, chain, state[chain]);
	newPi = GetParamStdStateFreqs (param, chain, state[chain]);
	oldPi = GetParamStdStateFreqs (param, chain, state[chain] ^ 1);
	newPi += 2 * mp->numBetaCats;
	oldPi += 2 * mp->numBetaCats;
	for (i=0; i<charIndex; i++)
		{
		oldPi += param->sympinStates[i];
		newPi += param->sympinStates[i];
		}
	nStates = param->sympinStates[charIndex];
	
	/* multiply old values with some large number to get new values close to the old ones */
	for (i=0; i<nStates; i++)
		dirichletParameters[i] = oldPi[i] * alphaPi;

	DirichletRandomVariable (dirichletParameters, newPi, nStates, seed);

	sum = 0.0;
	for (i=0; i<nStates; i++)
		{
		if (newPi[i] < 0.0001)
			newPi[i] = 0.0001;
		sum += newPi[i];
		}
	for (i=0; i<nStates; i++)
		newPi[i] /= sum;

	/* get proposal ratio */
	sum = 0.0;
	for (i=0; i<nStates; i++)
		sum += newPi[i]*alphaPi;
	x = LnGamma(sum);
	for (i=0; i<nStates; i++)
		x -= LnGamma(newPi[i]*alphaPi);
	for (i=0; i<nStates; i++)
		x += (newPi[i]*alphaPi-1.0)*log(oldPi[i]);
	sum = 0.0;
	for (i=0; i<nStates; i++)
		sum += oldPi[i]*alphaPi;
	y = LnGamma(sum);
	for (i=0; i<nStates; i++)
		y -= LnGamma(oldPi[i]*alphaPi);
	for (i=0; i<nStates; i++)
		y += (oldPi[i]*alphaPi-1.0)*log(newPi[i]);
	(*lnProposalRatio) = x - y;

	/* get prior ratio */
	y = x = 0.0;	/* the Gamma part of the prior is the same */
	for (i=0; i<nStates; i++)
		x += (symDirAlphai-1.0)*log(newPi[i]);
	for (i=0; i<nStates; i++)
		y += (symDirAlphai-1.0)*log(oldPi[i]);
	(*lnPriorRatio) = x - y;
		
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
		
	/* Set update flags for cijks for all affected partitions. Only cijks for the changed character 
	   actually need to be updated but we can't do that in the current version of the program. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);
	
}





int Move_SwitchRate (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* change switch rate of covarion model using sliding window */
	
	int			i, isSPriorExp, isValidS, whichRate;
	MrBFlt		oldS, newS, window, minS, maxS, sExp=0.0, ran, *value;
	ModelParams *mp;

	/* decide which switching rate to change */
	if (RandomNumber(seed) < 0.5)
		whichRate = 0;
	else
		whichRate = 1;
		
	/* get size of window, centered on current switching rates value */
	window = mvp[0];

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* get minimum and maximum values for switching rate */
	if (param->paramId == SWITCH_UNI)
		{
		minS = mp->covswitchUni[0];
		maxS = mp->covswitchUni[1];
		isSPriorExp = NO;
		}
	else
		{
		minS = 0.01;
		maxS = KAPPA_MAX;
		sExp = mp->covswitchExp;
		isSPriorExp = YES;
		}

	/* get old value of switching rate */
	value = GetParamVals(param, chain, state[chain]);
	newS = oldS = value[whichRate];

	/* change value for switching rate */
	ran = RandomNumber(seed);
	if( maxS-minS < window )
		{
		window = maxS-minS;
		}
	newS = oldS + window * (ran - 0.5);
	
	/* check that new value is valid */
	isValidS = NO;
	do
		{
		if (newS < minS)
			newS = 2* minS - newS;
		else if (newS > maxS)
			newS = 2 * maxS - newS;
		else
			isValidS = YES;
		} while (isValidS == NO);

	/* get proposal ratio */
	*lnProposalRatio = 0.0;
	
	/* get prior ratio */
	if (isSPriorExp == NO)
		*lnPriorRatio = 0.0;
	else
		*lnPriorRatio = -sExp * (newS - oldS);
	
	/* copy new switching rate value back */
	value[whichRate] = newS;

	/* Set update flags for all partitions that share this switching rate. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);

	/* Set update flags for cijks for all affected partitions. If this is a simple 4 X 4 model,
	   we don't take any hit, because we will never go into a general transition probability
	   calculator. However, for covarion, doublet, and codon models, we do want to update
	   the cijk flag. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);

}





int Move_SwitchRate_M (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* change switch rate of covarion model using multiplier */

	int			i, isSPriorExp, isValidS, whichRate;
	MrBFlt		oldS, newS, minS, maxS, sExp=0.0, tuning, ran, factor, *value;
	ModelParams *mp;

	/* decide which switching rate to change */
	if (RandomNumber(seed) < 0.5)
		whichRate = 0;
	else
		whichRate = 1;
		
	/* get tuning parameter */
	tuning = mvp[0];

	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* get minimum and maximum values for switching rate */
	if (param->paramId == SWITCH_UNI)
		{
		minS = mp->covswitchUni[0];
		maxS = mp->covswitchUni[1];
		isSPriorExp = NO;
		}
	else
		{
		minS = 0.01;
		maxS = KAPPA_MAX;
		sExp = mp->covswitchExp;
		isSPriorExp = YES;
		}

	/* get old value of switching rate */
	value = GetParamVals(param, chain, state[chain]);
	newS = oldS = value[whichRate];

	/* change value for switching rate */
	ran = RandomNumber(seed);
	factor = exp(tuning * (ran - 0.5));
	newS = oldS * factor;
	
	/* check that new value is valid */
	isValidS = NO;
	do
		{
		if (newS < minS)
			newS = minS * minS / newS;
		else if (newS > maxS)
			newS = maxS * maxS / newS;
		else
			isValidS = YES;
		} while (isValidS == NO);

	/* get proposal ratio */
	*lnProposalRatio = log (newS / oldS);
	
	/* get prior ratio */
	if (isSPriorExp == NO)
		*lnPriorRatio = 0.0;
	else
		*lnPriorRatio = -sExp * (newS - oldS);
	
	/* copy new switching rate value back */
	value[whichRate] = newS;

	/* Set update flags for all partitions that share this switching rate. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);

	/* Set update flags for cijks for all affected partitions. If this is a simple 4 X 4 model,
	   we don't take any hit, because we will never go into a general transition probability
	   calculator. However, for covarion, doublet, and codon models, we do want to update
	   the cijk flag. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);

}




int Move_Tratio_Dir (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* change tratio using Dirichlet proposal */
	
	int			i;
	MrBFlt		oldK, alphaPi, *alphaDir, oldProp[2], newProp[2], dirParm[2], sum, x, y;
	ModelParams	*mp;

	/* get model params */
	mp = &modelParams[param->relParts[0]];

	/* get so called alphaPi parameter */
	alphaPi = mvp[0];

	/* get old value of kappa */
	oldK = *GetParamVals(param, chain, state[chain]);

	/* get Dirichlet parameters */
	alphaDir = mp->tRatioDir;

	/* calculate old ratesum proportions */
	oldProp[0] = oldK / (oldK + 1.0);
	oldProp[1] = 1.0 - oldProp[0];
	
	/* multiply old ratesum props with some large number to get new values close to the old ones */
	dirParm[0] = oldProp[0] * alphaPi;
	dirParm[1] = oldProp[1] * alphaPi;
	
	/* get new values */
	DirichletRandomVariable (dirParm, newProp, 2, seed);

	sum = 0.0;
	for (i=0; i<2; i++)
		{
		if (newProp[i] < DIR_MIN)
			newProp[i] = DIR_MIN;
		sum += newProp[i];
		}
	for (i=0; i<2; i++)
		newProp[i] /= sum;

	/* calculate and copy new kappa value back */
	*GetParamVals(param, chain, state[chain]) = newProp[0] / newProp[1];

	/* get proposal ratio */
	sum = 0.0;
	for (i=0; i<2; i++)
		sum += newProp[i]*alphaPi;
	x = LnGamma(sum);
	for (i=0; i<2; i++)
		x -= LnGamma(newProp[i]*alphaPi);
	for (i=0; i<2; i++)
		x += (newProp[i]*alphaPi-1.0)*log(oldProp[i]);
	sum = 0.0;
	for (i=0; i<2; i++)
		sum += oldProp[i]*alphaPi;
	y = LnGamma(sum);
	for (i=0; i<2; i++)
		y -= LnGamma(oldProp[i]*alphaPi);
	for (i=0; i<2; i++)
		y += (oldProp[i]*alphaPi-1.0)*log(newProp[i]);
	(*lnProposalRatio) = x - y;

	/* get prior ratio */
	x = y = 0.0;
	for (i=0; i<2; i++)
		x += (alphaDir[i]-1.0)*log(newProp[i]);
	for (i=0; i<2; i++)
		y += (alphaDir[i]-1.0)*log(oldProp[i]);
	(*lnPriorRatio) = x - y;
		
	/* Set update flags for all partitions that share this kappa. Note that the conditional
	   likelihood update flags have been set before we even call this function. */
	for (i=0; i<param->nRelParts; i++)
		TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);

	/* Set update flags for cijks for all affected partitions. If this is a simple 4 X 4 model,
	   we don't take any hit, because we will never go into a general transition probability
	   calculator. However, for covarion, doublet, and codon models, we do want to update
	   the cijk flag. */
	for (i=0; i<param->nRelParts; i++)
		modelSettings[param->relParts[i]].upDateCijk = YES;

	return (NO_ERROR);

}




/* Code added by Jeremy Brown and modified by Maxim Teslenko */
int Move_TreeLen (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	/* change all branch lengths */

	MrBFlt		begin_tl, treescaler, tuning, maxV, minV, brlensPrExp=0.0;
	TreeNode	*p;
	ModelParams *mp;
	Tree		*t;
	int i,branch_counter;


	tuning = mvp[0]; /* Larget & Simon's tuning parameter lambda */

	mp = &modelParams[param->relParts[0]];

    /* max and min brlen */
	if (param->paramId == BRLENS_UNI)
		{
		minV = mp->brlensUni[0];
		maxV = mp->brlensUni[1];
		}
	else
		{
		minV = BRLENS_MIN;
		maxV = BRLENS_MAX;
		brlensPrExp = mp->brlensExp;
		}

	/* get tree */
	t = GetTree (param, chain, state[chain]);

    assert(t->isRooted == NO);

#if defined (DEBUG_CONSTRAINTS)
    if (CheckConstraints(t) == ERROR) {
        printf ("Constraint error in input tree to treelen multiplier\n");
        getchar();
        }
#endif

	treescaler = exp(tuning * (RandomNumber(seed) - 0.5));
	
	begin_tl = 0.0;
	branch_counter=0;

	for (i=0; i<t->nNodes; i++)
	    {
		p = t->allDownPass[i];
		if (p->anc != NULL)
		    {
            if(p->length*treescaler < minV || p->length*treescaler > maxV)
                {
                abortMove = YES;
                return NO_ERROR;
                }
		    begin_tl += p->length;
		    branch_counter++;				
		    }
	    }
    assert(branch_counter==t->nNodes-1);
	
	/* iterate scaling over all branches */
	for (i=0; i < t->nNodes; i++)
	    {
		p = t->allDownPass[i];
 		if ( p->anc != NULL )
		    {
			/* set new length */
			p->length *= treescaler;

			/* set flags for update of transition probabilities at p */
			p->upDateTi = YES;
            p->anc->upDateCl = YES; 
		    }
	    }




	/* calculate proposal ratio */
	(*lnProposalRatio) = branch_counter * log(treescaler); 


	/* update prior if exponential prior on branch lengths */
	if (param->paramId == BRLENS_EXP)
		(*lnPriorRatio) = brlensPrExp * (begin_tl*( 1 - treescaler));

	return (NO_ERROR);
	
}




/*-----------------------------------------------------------------------------------
|
|	Move_TreeStretch: Shrink or grow a clock tree
|
-------------------------------------------------------------------------------------*/
int Move_TreeStretch (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{
	int			i, j, *nEvents, numChangedNodes;
	MrBFlt	    minV, maxV, minB, maxB, tuning, factor, lambda=0.0, nu=0.0, igrvar=0.0,
                *brlens=NULL, *tk02Rate=NULL, *igrRate=NULL;
	TreeNode	*p, *q;
	ModelParams	*mp;
	ModelInfo	*m;
	Tree		*t, *oldT;
	Param		*subParm;

	tuning = mvp[0]; /* Larget & Simon tuning parameter lambda */
 
	m = &modelSettings[param->relParts[0]];
	mp = &modelParams[param->relParts[0]];

	/* get trees */
	t = GetTree (param, chain, state[chain]);
    oldT = GetTree (param, chain, 1^state[chain]);

    /* min and max branch lengths in relative time and substitution units */
    minV = BRLENS_MIN;
    maxV = BRLENS_MAX;
    minB = RELBRLENS_MIN;
    maxB = RELBRLENS_MAX;

    /* determine multiplication factor */
    factor = exp(tuning * (RandomNumber(seed) - 0.5));

    /* multiply all branch lengths and node depths by this factor  */
    numChangedNodes = 0;
    for (i=0; i<t->nNodes-1; i++)
        {
        p = t->allDownPass[i];
        if ((p->isDated == NO && p->left != NULL && !(p->anc->anc == NULL && param->paramId == BRLENS_CLOCK_UNI && !strcmp(mp->treeAgePr,"Fixed"))) ||
            (p->isDated == YES && p->calibration->prior != fixed))
            {
            if ((p->isDated == YES && p->calibration->prior == offsetExponential && p->age*factor < p->calibration->offset) ||
                (p->isDated == YES && p->calibration->prior == uniform &&
                (p->age*factor < p->calibration->min || p->age*factor > p->calibration->max)))
                {
                abortMove = YES;
                return (NO_ERROR);
                }
            numChangedNodes++;
            p->nodeDepth *= factor;
            if (p->isDated == YES)
                p->age *= factor;
            if (p->left != NULL) 
                {
                p->left ->length = p->nodeDepth - p->left ->nodeDepth;
                p->right->length = p->nodeDepth - p->right->nodeDepth;
                }
            /* we change our own node length here, in case the ancestor cannot be moved */
            if (p->anc->anc != NULL)
                p->length = p->anc->nodeDepth - p->nodeDepth;
            }
        }

    /* check that all branch lengths are proper, which need not be the case */
    for (i=0; i<t->nNodes-2; i++)
        {
        p = t->allDownPass[i];
        if (p->length < minV || p->length > maxV)
            {
            abortMove = YES;
            return NO_ERROR;
            }
        }

    /* calculate proposal ratio */
    (*lnProposalRatio) = numChangedNodes * log(factor);

    /* calculate prior ratio */
    if (LogClockTreePriorRatio(param, chain, lnPriorRatio) == ERROR)
        return ERROR;

    /* adjust proposal and prior ratio for relaxed clock models */
	for (i=0; i<param->nSubParams; i++)
		{
        subParm = param->subParams[i];
		if (subParm->paramType == P_CPPEVENTS)
			{
			nEvents = subParm->nEvents[2*chain+state[chain]];
			lambda = *GetParamVals (modelSettings[subParm->relParts[0]].cppRate, chain, state[chain]);
			/* proposal ratio */
			for (j=0; j<t->nNodes-2; j++)
                {
                p = t->allDownPass[j];
                q = oldT->allDownPass[j];
                (*lnProposalRatio) += nEvents[p->index ] * log (p->length  / q->length);
                }
			/* prior ratio */
            (*lnPriorRatio) += lambda * (TreeLen(oldT) - TreeLen(t));
			/* update effective evolutionary lengths */
			if (UpdateCppEvolLengths (subParm, t->root->left, chain) == ERROR)
                {
                abortMove = YES;
                return (NO_ERROR);
                }
			}
        else if (subParm->paramType == P_TK02BRANCHRATES)
			{
			nu = *GetParamVals (modelSettings[subParm->relParts[0]].tk02var, chain, state[chain]);
			tk02Rate = GetParamVals (subParm, chain, state[chain]);
			brlens = GetParamSubVals (subParm, chain, state[chain]);

            /* no proposal ratio effect */

            /* prior ratio and update of brlens */
			for (j=0; j<t->nNodes-2; j++)
                {
                p = t->allDownPass[j];
                q = oldT->allDownPass[j];
                (*lnPriorRatio) -= LnProbTK02LogNormal (tk02Rate[q->anc->index], nu*q->length, tk02Rate[q->index]);
    			(*lnPriorRatio) += LnProbTK02LogNormal (tk02Rate[p->anc->index], nu*p->length, tk02Rate[p->index]);
                brlens[p->index] = p->length * (tk02Rate[p->anc->index]+tk02Rate[p->index])/2.0;
                }
			}
		else if (subParm->paramType == P_IGRBRANCHLENS)
			{
			igrvar = *GetParamVals (modelSettings[subParm->relParts[0]].igrvar, chain, state[chain]);
			igrRate = GetParamVals (subParm, chain, state[chain]);
			brlens = GetParamSubVals (subParm, chain, state[chain]);
			
			/* prior ratio and update of igr branch lengths and rates (stretched in the same way as tree) */
            for (j=0; j<t->nNodes-2; j++)
                {
                p = t->allDownPass[j];
                q = oldT->allDownPass[j];
                (*lnPriorRatio) -= LnProbTruncGamma (q->length/igrvar, 1.0/igrvar, brlens[q->index], minB, maxB);
                brlens[p->index] *= p->length / q->length;
    			if (brlens[p->index] < minB || brlens[p->index] > maxB)
                    {
                    abortMove = YES;
                    return (NO_ERROR);
                    }
                (*lnPriorRatio) += LnProbTruncGamma (p->length/igrvar, 1.0/igrvar, brlens[p->index], minB, maxB);
                (*lnProposalRatio) += log(p->length / q->length);
                igrRate[p->index] = brlens[p->index] / p->length;
                }

            /*The following if (*lnPriorRatio != *lnPriorRatio) should be removed if LnProbTruncGamma() would be made more exact and would never return -infinity */
            if (*lnPriorRatio != *lnPriorRatio)
                {
                abortMove=YES;
                return (NO_ERROR);
                }
            }
		}

    TouchAllTreeNodes(m, chain);

#if defined (DEBUG_TREESTRETCH)
	printf ("After treestretch:\n");
	printf ("Old tree height: %f -- New tree height: %f -- lnPriorRatio = %f -- lnProposalRatio = %f\n",
		oldT->root->left->nodeDepth, t->root->left->nodeDepth, (*lnPriorRatio), (*lnProposalRatio));
#endif

    return (NO_ERROR);
	
}





/*----------------------------------------------------------------
|
|	Move_UnrootedSlider: This proposal mechanism changes the topology and
|      branch lengths of an unrooted tree. 
|
|      Programmed by JH 2003-08-13
|
----------------------------------------------------------------*/
int Move_UnrootedSlider (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)

{

	int			i, topologyHasChanged, isVPriorExp, isBranchAnc, direction=0, stopPathGen, moveToWhichPath, stopLoop;
	MrBFlt		tuning, expParam, minV, maxV, brlensExp=0.0, pathLength, pathLength1, pathLength2, oldM, newM, dist, sum, excess;
	TreeNode	*v, *w, *p, *q, *a, *b, *c, *d, *newAttachmentNode;
	Tree		*t;
	ModelParams *mp;

	/* set the tuning parameter */
	tuning = mvp[0];
	
	/* set the exponential parameter */
	expParam = mvp[1];
	
	/* get tree */
	t = GetTree (param, chain, state[chain]);
#	if defined (DEBUG_UNROOTED_SLIDER)
	MrBayesPrint ("Before:\n");
	ShowNodes (t->root, 3, NO);
#	endif

	/* initialize log prior and log proposal probabilities */
	*lnPriorRatio = *lnProposalRatio = 0.0;
	
	/* get model params */
	mp = &modelParams[param->relParts[0]];
	
	/* max brlen */
	if (param->subParams[0]->paramId == BRLENS_UNI)
		{
		maxV = mp->brlensUni[1];
		isVPriorExp = NO;
		}
	else
		{
		maxV = BRLENS_MAX;
		brlensExp = mp->brlensExp;
		isVPriorExp = YES;
		}
		
	/* min brlen */
	minV = BRLENS_MIN;
	
	/* Calculate log prior probability before the branch lengths of the tree have 
	   been changed. */
	if (isVPriorExp == YES)
		{
		for (i=0; i<t->nNodes; i++)
			{
			p = t->allDownPass[i];
			if (p->anc != NULL)
				*lnPriorRatio -= log(brlensExp) - brlensExp * p->length;
			}
		}

	/* Pick a branch. This branch is marked at the top as "v" and at the bottom as "w". 
	   We also note whether the branch is the ancestral one, or not. Finally, this branch
	   will eventually have its length changed via a Larget & Simon type of contraction/
	   expansion. */
	do
		{
		v = t->allDownPass[(int)(RandomNumber(seed) * t->nNodes)];
		} while (v->anc == NULL);
	w = v->anc;
	if (w->anc == NULL)
		isBranchAnc = YES;
	else
		isBranchAnc = NO;
#	if defined (DEBUG_UNROOTED_SLIDER)
	MrBayesPrint ("v=%d w=%d isBranchAnc=%d\n", v->index, w->index, isBranchAnc);
#	endif

	/* mark path */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		p->marked = NO;
		p->x = p->y = 0;
		}
	v->marked = w->marked = YES;
	for (i=0; i<2; i++)
		{
		if (isBranchAnc == NO)
			{
			if (i == 0)
				direction = DOWN;
			else
				direction = UP;
			p = w;
			}
		else
			{
			direction = UP;
			p = v;
			}
		stopPathGen = NO;
		do
			{
			p->marked = YES;
			p->x = i + 1;
			if (direction == DOWN && p->anc != NULL)
				{
				p = p->anc;
				}
			else if (direction == DOWN && p->anc == NULL)
				{
				stopPathGen = YES;
				}
			else if (direction == UP && (p->left != NULL && p->right != NULL))
				{
				if (p->left->marked == NO && p->right->marked == NO)
					{
					if (RandomNumber(seed) < 0.5)
						p = p->left;
					else
						p = p->right;
					}
				else if (p->left->marked == NO && p->right->marked == YES)
					p = p->left;
				else if (p->left->marked == YES && p->right->marked == NO)
					p = p->right;
				else
					{
					MrBayesPrint ("%s   ERROR: All nodes above are marked\n", spacer);
					return (ERROR);
					}
				}
			else if (direction == UP && (p->left == NULL || p->right == NULL))
				{
				stopPathGen = YES;
				}
			else
				{
				MrBayesPrint ("%s   ERROR: Should not be here in UnrootedNodeSlider\n", spacer);
				return (ERROR);
				}
			if (direction == DOWN && stopPathGen == NO)
				if (RandomNumber(seed) < 0.5)
					direction = UP;
			} while (stopPathGen == NO);
		}
	if (isBranchAnc == NO)
		{
		v->marked = NO;
		w->marked = YES;
		v->x = 0;
		w->x = w->anc->x;
		}
	else
		{
		v->marked = w->marked = NO;
		v->x = w->x = 0;
		}
	for (i=0; i<t->nNodes; i++) /* mark any kinks in the path by setting p->y = 1 */
		{
		p = t->allDownPass[i];
		if (p != v && p != w && p->left != NULL && p->right != NULL)
			{
			if (p->x > 0)
				{
				if (p->left->x == p->right->x && p->x == p->left->x)
					{
					p->marked = NO;
					p->y = 1;
					}
				}
			}
		}
#	if defined (DEBUG_UNROOTED_SLIDER)
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->marked == YES || p->x > 0)
			printf ("%4d %4d %4d \n", p->index, p->marked, p->x);
		}
#	endif
		
	/* Calculate the path lengths on the two sides of
	   the branch designated with v-w. */
	pathLength1 = pathLength2 = 0.0;
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p->marked == YES && p->y == 0)
			{
			if (p->x == 1)
				pathLength1 += p->length;
			else if (p->x == 2)
				pathLength2 += p->length;
			else
				{
				MrBayesPrint ("%s   ERROR: Marked node should have x=1 or x=2\n", spacer);
				return (ERROR);
				}
			}
		}
#	if defined (DEBUG_UNROOTED_SLIDER)
	printf ("pathLength1=%lf pathLength2=%lf\n", pathLength1, pathLength2);
#	endif
		
	/* Change the length of branch marked by v and w. While we are at it, we
	   mark this branch for update of the transition probability (the branch
	   changed its length, so the transition probabilities will be different).
	   We will also mark all of the branches on a path from v to the root as
	   in need of updating for the conditional likelihoods. */
	oldM = v->length;
	newM = oldM * exp(tuning * (RandomNumber(seed) - 0.5));
	if (newM < minV)
		newM = minV;
	else if (newM > maxV)
		newM = maxV;
	v->length = newM;
	v->upDateTi = YES;
	MarkClsBelow (v);

	/* Here we calculate the first part of the proposal ratio. We are changing the length of
	   the branch marked at the top by node v and at the bottom by node w. The length is
	   changed by multiplying the old branch length by e^(tuning * (r - 1/2)); that is, we
	   use the Larget & Simon type of move. The proposal ratio is given as: */
	*lnProposalRatio += log(newM) - log(oldM);
	
	/* Pick a direction to slide the branch in. */
	moveToWhichPath = 1;
	if (RandomNumber(seed) < 0.5)
		moveToWhichPath = 2;
		
	/* Pick an amount to slide. We slide the branch an exponentially-distributed amount
	   from its starting position. We condition on the length of the path in the direction
	   we are sliding. Hence, the probability density for sliding the branch is
	   
	   f(x) = expParam * exp(expParam * x) / (1.0 - exp(expParam * pathLength) 
	   
	   where x is the amount to slide, expParam is the parameter of the exponential
	   distribution, and pathLength is the length of the path in direction we are sliding. */
	if (moveToWhichPath == 1)
		pathLength = pathLength1;
	else
		pathLength = pathLength2;
	dist = -(1.0 / expParam) * log(1.0 - RandomNumber(seed) * (1.0 - exp(-expParam * pathLength)));
#	if defined (DEBUG_UNROOTED_SLIDER)
	printf ("dist=%lf pathLength=%lf\n", dist, pathLength);
#	endif
	
	/* Find the new attachment branch. This is a pain in the neck. */
	if (isBranchAnc == NO)
		p = w;
	else
		p = v;
	stopLoop = NO;
	sum = 0.0;
	do
		{
		q = NULL;
		if (p->left != NULL)
			if (p->left->x == moveToWhichPath)
				{
				q = p->left;
				direction = UP;
				}
		if (p->right != NULL)
			if (p->right->x == moveToWhichPath)
				{
				if (q == NULL)
					{
					q = p->right;
					direction = UP;
					}
				else
					{
					MrBayesPrint ("%s   ERROR: At least two inappropriately marked nodes\n", spacer);
					return (ERROR);
					}
				}
		if (p->anc != NULL)
			if (p->anc->x == moveToWhichPath)
				{
				if (q == NULL)
					{
					q = p->anc;
					direction = DOWN;
					}
				else
					{
					MrBayesPrint ("%s   ERROR: At least two inappropriately marked nodes\n", spacer);
					return (ERROR);
					}
				}
		if (q == NULL)
			{
			MrBayesPrint ("%s   ERROR: Could not find an appropriately marked node\n", spacer);
			return (ERROR);
			}
			
		excess = dist - sum;
		if (direction == UP)
			sum += q->length;
		else if (direction == DOWN && p->y == 0)
			sum += p->length;
		p->x = 0;
		if (sum > dist)
			{
			stopLoop = YES;
			if (direction == UP)
				p = q;
			}
		else
			p = q;

		} while (stopLoop == NO);
	newAttachmentNode = p;
	
	/* Decide whether the topology of the tree has changed. If we are sliding
	   the branch below w, then the topology has not changed if newAttachmentNode =
	   w. If we are sliding the branch above w, then the topology does not change
	   if newAttachmentNode->anc = w. Note that if the branch we are sliding
	   is the ancestral one, then the topology does not change if 
	   newAttachmentNode->anc = v. */
	topologyHasChanged = YES;
	if (isBranchAnc == NO)
		{
		if (newAttachmentNode->anc != NULL)
			if (newAttachmentNode->anc == w)
				topologyHasChanged = NO;
		if (newAttachmentNode == w)
			topologyHasChanged = NO;
		}
	else
		{
		if (newAttachmentNode->anc != NULL)
			if (newAttachmentNode->anc == v)
				topologyHasChanged = NO;
		}
		
	/* Move the branch to the new attachment point. We need to keep track of a lot
	   of pointers, and also make certain to mark updates for conditional likelihoods
	   and transition probabilities on the fly. */
	if (isBranchAnc == NO)
		{
		if (topologyHasChanged == YES)
			{
			b = w->anc;
			if (w->left == v)
				a = w->right;
			else
				a = w->left;
			if (b->left == w)
				{
				b->left = a;
				a->anc = b;
				a->length += w->length;
				}
			else
				{
				b->right = a;
				a->anc = b;
				a->length += w->length;
				}
			a->upDateTi = YES;
			MarkClsBelow (a);
				
			if (newAttachmentNode->anc == NULL)
				{
				MrBayesPrint ("%s   ERROR: This isn't right!\n", spacer);
				return (ERROR);
				}
			else
				q = newAttachmentNode->anc;
			if (q->left == newAttachmentNode)
				{
				q->left = w;
				w->anc = q;
				w->left = newAttachmentNode;
				w->right = v;
				p->anc = v->anc = w;
				}
			else
				{
				q->right = w;
				w->anc = q;
				w->right = newAttachmentNode;
				w->left = v;
				newAttachmentNode->anc = v->anc = w;
				}
			w->length = excess;
			newAttachmentNode->length -= excess;
			if (newAttachmentNode->length < 0.0)
				{
				MrBayesPrint ("%s   ERROR: Negative branch length on p\n", spacer);
				return (ERROR);
				}
			if (w->length < 0.0)
				{
				MrBayesPrint ("%s   ERROR: Negative branch length on w\n", spacer);
				return (ERROR);
				}
			newAttachmentNode->upDateTi = YES;
			w->upDateTi = YES;
			MarkClsBelow (v);
			}
		else
			{
			if (w->left == v)
				a = w->right;
			else
				a = w->left;
			if (newAttachmentNode == w)
				{
				w->length -= excess;
				a->length += excess;
				}
			else
				{
				w->length += excess;
				a->length -= excess;
				}
			if (w->length < 0.0)
				{
				MrBayesPrint ("%s   ERROR: Negative branch length on w (2)\n", spacer);
				return (ERROR);
				}
			if (a->length < 0.0)
				{
				MrBayesPrint ("%s   ERROR: Negative branch length on a\n", spacer);
				return (ERROR);
				}
			a->upDateTi = YES;
			w->upDateTi = YES;
			MarkClsBelow (a);
			}
		}
	else
		{
		if (topologyHasChanged == YES)
			{
			for (i=0; i<t->nNodes; i++)
				{
				p = t->allDownPass[i];
				p->marked = NO;
				}
			p = newAttachmentNode;
			while (p != v && p->anc != NULL)
				{
				p->marked = YES;
				p = p->anc;
				}
			do
				{
				if (v->left == NULL || v->right == NULL)
					{
					MrBayesPrint ("%s   ERROR: v->left or v->right is null\n", spacer);
					return (ERROR);
					}
				if (v->left->marked == YES && v->right->marked == NO)
					{
					a = v->left;
					b = v->right;
					}
				else if (v->left->marked == NO && v->right->marked == YES)
					{
					a = v->right;
					b = v->left;
					}
				else if (v->left->marked == YES && v->right->marked == YES)
					{
					MrBayesPrint ("%s   ERROR: v->left and v->right are marked\n", spacer);
					return (ERROR);
					}
				else
					{
					MrBayesPrint ("%s   ERROR: v->left and v->right are not marked\n", spacer);
					return (ERROR);
					}
				if (a->left == NULL || a->right == NULL)
					{
					MrBayesPrint ("%s   ERROR: a's descendents should not be null\n", spacer);
					return (ERROR);
					}
				if (a->left->marked == YES && a->right->marked == NO)
					{
					c = a->right;
					d = a->left;
					}
				else if (a->left->marked == NO && a->right->marked == YES)
					{
					c = a->left;
					d = a->right;
					}
				else
					{
					MrBayesPrint ("%s   ERROR: one of a's descendents should be marked\n", spacer);
					return (ERROR);
					}
				
				v->left = d;
				v->right = a;
				a->anc = d->anc = v;
				a->left = c;
				a->right = b;
				b->anc = c->anc = a;
				a->marked = NO;
				b->length += a->length;
				if (d == newAttachmentNode)
					{
					d->length -= excess;
					a->length = excess;
					}
				else
					{
					d->length *= 0.5;
					a->length = d->length;
					}
				b->upDateTi = YES;
				d->upDateTi = YES;
				a->upDateTi = YES;
				a->upDateCl = YES; 
				v->upDateCl = YES; 
				} while (v->left != newAttachmentNode && v->right != newAttachmentNode);
			}
		else
			{
			if (v->left == newAttachmentNode)
				a = v->right;
			else
				a = v->left;
			newAttachmentNode->length -= excess;
			a->length += excess;
			newAttachmentNode->upDateTi = YES;
			a->upDateTi = YES;
			v->upDateCl = YES;
			}
		}
		
	/* Here we calculate the second part of the proposal ratio. Note that after changing the length
	   of the selected node (the proposal ratio for this part is taken care of in part 1), that
	   we then (1) choose a direction to slide the node and (2) decide on an amount to slide, then sliding
	   the node the appropriate amount. In part 1, we choose each direction with probability 1/2. Because
	   the forward and backward move will contain this 1/2, they cancel out in the Hasting's ratio, and
	   we ignore this part of the move from here on. However, the second part is more complicated. We
	   slide the node an exponentially distributed amount, conditional on not sliding the node past
	   the tip (that is, the amount we slide cannot be larger than the path in that direction). I think
	   that the following correctly accounts for this move. */
	if (moveToWhichPath == 1)
		{
		*lnProposalRatio += ( log(expParam) - expParam * dist - log(1.0 - exp(-expParam * (pathLength2 + dist))) ) - 
							( log(expParam) - expParam * dist - log(1.0 - exp(-expParam * pathLength1)) );
		}
	else
		{
		*lnProposalRatio += ( log(expParam) - expParam * dist - log(1.0 - exp(-expParam * (pathLength1 + dist))) ) - 
							( log(expParam) - expParam * dist - log(1.0 - exp(-expParam * pathLength2)) );
		}

	/* get downpass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		GetDownPass (t);
		}
#	if defined (DEBUG_UNROOTED_SLIDER)
	MrBayesPrint ("After:\n");
	ShowNodes (t->root, 3, NO);
#	endif

	/* Calculate log prior probability after the branch lengths of the tree have 
	   been changed. */
	if (isVPriorExp == YES)
		{
		for (i=0; i<t->nNodes; i++)
			{
			p = t->allDownPass[i];
			if (p->anc != NULL)
				*lnPriorRatio += log(brlensExp) - brlensExp * p->length;
			}
		}
				
	return (NO_ERROR);

}





/*------------------------------------------------------------------------
|
|	NewtonRaphsonBrlen: Find one maximum likelihood branch length using
|	   the Newton-Raphson method. This function assumes that the tree is
|	   a non-clock tree. For clock trees, you have to optimize the node
|	   depths instead.
|
------------------------------------------------------------------------*/
int NewtonRaphsonBrlen (Tree *t, TreeNode *p, int chain)

{
	int			c, i, j, s, k, n, d, division, nIterations, maxNumIterations,
				index, *rateCat, r;
	MrBFlt		vOld, *pi, *cijk, *eigenValues, *catRate, baseRate, length, theRate, tolerance,
				expLambdaV[64], pInvar=0.0, likeI=0.0, sum=0.0, sum1, sum2, beta, w, v, x, y, expBetaV,
				expWV, kappa, bigPi, *ptr;
	CLFlt		*nSitesOfPat, *clP, *clA, *tiP, *tiP1, *tiP2, like, like1, like2, CLsum, CLsum1, CLsum2,
				freq, sumLike1, sumLike2, *lnScaler=NULL, *clInvar=NULL;
	ModelInfo	*m;

	/* TODO: Standard model (also check RES for ascertainment bias) */
	tolerance = 0.001;
	maxNumIterations = 5;
	
	nIterations = 0;
	do {
		/* reset f'(v) and f''(v) sums */
		sumLike1 = sumLike2 = 0.0;
		
		/* cycle over character partitions */
		for (d=0; d<t->nRelParts; d++)
			{
			division = t->relParts[d];

			/* get pointer to model */
			m = &modelSettings[division];
			
			/* get number of model states */
			n = m->numModelStates;
			
			/* find conditional likelihoods */
			clP = m->condLikes[m->condLikeIndex[chain][p->index     ]];
            clA = m->condLikes[m->condLikeIndex[chain][p->anc->index]];
            
			/* get state frequencies */
			pi = GetParamSubVals (m->stateFreq, chain, state[chain]);
	
			/* get base rate */
			theRate = 1.0;
			baseRate = GetRate (division, chain);

			/* get category rates */
			if (m->shape == NULL)
				catRate = &theRate;
			else
				catRate = GetParamSubVals (m->shape, chain, state[chain]);
	
			/* find category frequencies and some additional stuff for the invar model */
			if (m->pInvar == NULL)
				freq =  (CLFlt) (1.0 /  m->numGammaCats);
			else
				{
				/* invariable sites model */
				pInvar = * GetParamVals(m->pInvar, chain, state[chain]);
				freq = (CLFlt) ((1.0 - pInvar) /  m->numGammaCats);
				baseRate /= (1.0 - pInvar);
				clInvar = m->invCondLikes;
				lnScaler = m->scalers[m->siteScalerIndex[chain]];
                }

			/* find the branch lengths times any correction factor to make them
			   in terms of expected number of substitutions per character */
			length = p->length;
			if (m->dataType == DNA || m->dataType == RNA)
				{
				if (m->nucModelId == NUCMODEL_DOUBLET)
					length *= 2.0;
				else if (m->nucModelId == NUCMODEL_CODON)
					length *= 3.0;
				}

			/* find nSitesOfPat */
			nSitesOfPat = numSitesOfPat + ((chainId[chain] % chainParams.numChains)*numCompressedChars) + m->compCharStart;
			
			/* get tiProbs for current length; use the scratch location */
            FlipTiProbsSpace(m, chain, p->index);
			m->TiProbs (p, division, chain);
            tiP = m->tiProbs[m->tiProbsIndex[chain][p->index]];
            FlipTiProbsSpace(m, chain, p->index);

			/* allocate space for first and second derivatives */
            tiP1 = (CLFlt *) SafeCalloc (2*m->tiProbLength, sizeof (CLFlt));
			if (!tiP1)
				return (ERROR);
			tiP2 = tiP1 + m->tiProbLength;
			
			/* calculate first and second derivatives of P(v): P'(v) and P''(v) */
			index = 0;
			if (m->TiProbs == &TiProbs_Fels || m->TiProbs == &TiProbs_Res)
				{
				/* calculate beta */
				sum = 0.0;
				for (i=0; i<m->numModelStates; i++)
					for (j=i+1; j<m->numModelStates; j++)
						sum += pi[i]*pi[j];
				beta = 0.5 / sum;

				/* calculate derivatives */
				for (k=0; k<m->numGammaCats; k++)
					{
					v = length * catRate[k] * baseRate;
					expBetaV = exp (- beta * v);
					for (i=0; i<m->numModelStates; i++)
						{
						for (j=0; j<m->numModelStates; j++)
							{
							if (i == j)
								{
								x = - beta * (1.0 - pi[j]) * expBetaV;
								tiP1[index] = (CLFlt) x;
								tiP2[index] = (CLFlt) (- beta * x);
								}
							else
								{
								x = beta * pi[j] * expBetaV;
								tiP1[index] = (CLFlt) x;
								tiP2[index] = (CLFlt) (- beta * x);
								}
							index++;
							}
						}
					}
				}
			else if (m->TiProbs == &TiProbs_Hky)
				{
				/* get kappa */
				kappa =  *GetParamVals (m->tRatio, chain, state[chain]);
	
				/* calculate beta */
				sum = 0.0;
				for (i=0; i<m->numModelStates; i++)
					{
					for (j=i+1; j<m->numModelStates; j++)
						{
						if (j - i == 2)
							sum += kappa * pi[i] * pi[j];
						else
							sum += pi[i] * pi[j];
						}
					}
				beta = 0.5 / sum;

				/* calculate derivatives */
				for (k=0; k<m->numGammaCats; k++)
					{
					v = length * catRate[k] * baseRate;
					expBetaV = exp (- beta * v);
					for (i=0; i<m->numModelStates; i++)
						{
						for (j=0; j<m->numModelStates; j++)
							{
							s = (j + 2) % 4;
							bigPi = pi[j] + pi[s];
							w = (1.0 + bigPi * (kappa - 1.0)) * beta;
							expWV = exp (- w * v);
							if (i == j)
								{
								x = - beta * ((pi[j]/bigPi) - pi[j]) * expBetaV;
								y = - w * (pi[s]/bigPi) * expWV;
								tiP1[index] = (CLFlt) (x + y);
								tiP2[index] = (CLFlt) (- beta * x - w * y);
								}
							else if (abs(i-j) == 2)
								{
								x = - beta * pi[j] * ((pi[j]/bigPi) - pi[j]) * expBetaV;
								y = w * (pi[j]/bigPi) * expWV;
								tiP1[index] = (CLFlt) (x + y);
								tiP2[index] = (CLFlt) (- beta * x - w * y);
								}
							else
								{
								x = beta * pi[j] * expBetaV;
								tiP1[index] = (CLFlt) x;
								tiP2[index] = (CLFlt) (- beta * x);
								}
							index++;
							}
						}
					}
				}
			else if (m->TiProbs == &TiProbs_Gen || m->TiProbs == &TiProbs_GenCov)
				{
				/* get eigenvalues and cijk pointers */
				eigenValues = m->cijks[m->cijkIndex[chain]];
				cijk        = eigenValues + (2 * n);

				/* calculate P'(v) and P''(v) */
				for (k=0; k<m->numGammaCats; k++)
					{
					v = length * catRate[k];
					for (s=0; s<n; s++)
						expLambdaV[s] =  exp(eigenValues[s] * v);
					ptr = cijk;
					for (i=0; i<n; i++)
						{
						for (j=0; j<n; j++)
							{
							sum1 = sum2 = 0.0;
							for(s=0; s<n; s++)
								{
								if (fabs(eigenValues[s]) > 0.000001)
									{
									x = eigenValues[s] * (*ptr++) * expLambdaV[s];
									sum1 += x;
									sum2 += eigenValues[s] * x;
									}
								else
									ptr += n;
								}
							tiP1[index] = (CLFlt) ((sum1 < 0.0) ? 0.0 : sum);
							tiP2[index] = (CLFlt) ((sum2 < 0.0) ? 0.0 : sum);
							index++;
							}
						}
					}
				}
			else if (m->TiProbs == &TiProbs_GenCov)
				{
				/* get eigenvalues and cijk pointers */
				eigenValues = m->cijks[m->cijkIndex[chain]];
				cijk        = eigenValues + (2 * n);

				/* calculate P'(v) and P''(v) */
				for (k=0; k<m->numTiCats; k++)
					{
					if (m->numGammaCats > 1)
						v = length * catRate[k];
					else
						v = length;
					for (s=0; s<n; s++)
						expLambdaV[s] =  exp(eigenValues[s] * v);
					for (i=0; i<n; i++)
						{
						for (j=0; j<n; j++)
							{
							sum1 = sum2 = 0.0;
							for(s=0; s<n; s++)
								{
								if (fabs(eigenValues[s]) > 0.000001)
									{
									x = eigenValues[s] * (*cijk++) * expLambdaV[s];
									sum1 += x;
									sum2 += eigenValues[s] * x;
									}
								}
							tiP1[index] = (CLFlt) ((sum1 < 0.0) ? 0.0 : sum);
							tiP2[index] = (CLFlt) ((sum2 < 0.0) ? 0.0 : sum);
							index++;
							}
						}
					/* get new eigenvalues and cijks */
					eigenValues += m->cijkLength / m->nCijkParts;
					cijk         = eigenValues + 2 * n;
					}
				}
			/* calculate f(v), f'(v) and f''(v) for this partition */
			/* note that the scalers are irrelevant because they disappear when
			   we take the derivative of the log likelihood */
			if (m->gibbsGamma == YES)
				{
				/* find rate category index */
				rateCat = m->tiIndex + chain*m->numChars;
				for (c=0; c<m->numChars; c++)
					{
					like = like1 = like2 = 0.0;
					r = rateCat[c];
					if (r < m->numGammaCats)
						{
						index = r*m->numModelStates*m->numModelStates;
						for (j=0; j<n; j++)
							{
							CLsum = CLsum1 = CLsum2 = 0.0;
							for (i=0; i<n; i++, index++)
								{
								CLsum += clP[i] * tiP[index];
								CLsum1 += clP[i] * tiP1[index];
								CLsum2 += clP[i] * tiP2[index];
								}
							like += CLsum * (CLFlt) pi[j] * clA[j];
							like1 += CLsum1 * (CLFlt) pi[j] * clA[j];
							like2 += CLsum2 * (CLFlt) pi[j] * clA[j];
							}
						like *= freq;
						sumLike1 += nSitesOfPat[c] * (like1 / like);
						sumLike2 += nSitesOfPat[c] * (like2 * like - like1 * like1) / (like * like);
						}
					clP += n;
					}
				}
			else
				{
				for (c=0; c<m->numChars; c++)
					{
					like = like1 = like2 = 0.0;
					index = 0;
					for (k=0; k<m->numTiCats; k++)
						{
						for (j=0; j<n; j++)
							{
							CLsum = CLsum1 = CLsum2 = 0.0;
							for (i=0; i<n; i++, index++)
								{
								CLsum += clP[i] * tiP[index];
								CLsum1 += clP[i] * tiP1[index];
								CLsum2 += clP[i] * tiP2[index];
								}
							like += CLsum * (CLFlt) pi[j] * clA[j];
							like1 += CLsum1 * (CLFlt) pi[j] * clA[j];
							like2 += CLsum2 * (CLFlt) pi[j] * clA[j];
							}
						clP += n;
						}
					like *= freq;
					if (m->pInvar != NULL)
						{
						/* get right like; like1 and like2 not affected */;
						for (i=0; i<n; i++)
							likeI += (*clInvar++) * pi[i];
						likeI *= pInvar;
						if (lnScaler[c] < -200.0)
							{
							/* we are not going to be able to exponentiate the scaling factor */
							if (likeI > 1E-70)
								{
								/* forget about like; it is going to be insignificant compared to likeI */
								like = (CLFlt) likeI;
								}
							else
								{
								/* treat likeI as if 0.0, that is, ignore it completely */
								like = like;
								}
							}
						else	/* take both likeI and like into account */
							like = like + (CLFlt) (likeI * exp (-lnScaler[c]));
 						}
					sumLike1 += nSitesOfPat[c] * (like1 / like);
					sumLike2 += nSitesOfPat[c] * (like2 * like - like1 * like1) / (like * like);
					}
				}
			free (tiP1);
			}
		vOld = p->length;
		p->length -= sumLike2 / sumLike1;
		nIterations++;
		} while (fabs(p->length - vOld) > tolerance && nIterations < maxNumIterations);

	return (NO_ERROR);

}





void NodeToNodeDistances (Tree *t, TreeNode *fromNode)

{

	int				i;
	TreeNode		*p;
	
	/* set all distances to 0.0 and also set marks on all nodes to NO */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		p->x = NO;
		p->d = 0.0;
		}
		
	/* find distances, and mark path, below "fromNode" */
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		if (p == fromNode)
			{
			p->x = YES;
			}
		if (p->left != NULL && p->right != NULL && p->anc != NULL)
			{
			if (p->left->x == YES)
				{
				p->x = YES;
				p->d = p->left->d + p->left->length;
				}
			else if (p->right->x == YES)
				{
				p->x = YES;
				p->d = p->right->d + p->right->length;
				}
			}
		}
		
	/* find all other distances */
	for (i=t->nNodes-1; i>=0; i--)
		{
		p = t->allDownPass[i];
		if (p->anc == NULL)
			{
			if (p == fromNode)
				p->d = 0.0;
			else
				p->d = p->left->d + p->left->length;
			}
		else
			{
			if (p->x == NO)
				{
				p->d = p->anc->d + p->length;
				}
			}
		}

}





int NumCppEvents (Param *p, int chain)
{
	int			i, *nEvents, sumEvents;

	nEvents = p->nEvents[2*chain+state[chain]];
	
	sumEvents = 0;
	for (i=0; i<2*numLocalTaxa-2; i++)
		sumEvents += nEvents[i];

	return (sumEvents);
}





/*----------------------------------------------------------------------
|
|	OpenNewMBPrintFile: Open a file the first time for printing
|
------------------------------------------------------------------------*/
FILE *OpenNewMBPrintFile (char *fileName)

{

	int		overWrite;
	FILE    *fp;

	/* Open file, use noWarn to determine if the user should be prompted
	   to have the file over-written or appended. */
	if (noWarn == YES)
		{
		/* overwrite or append file, if already present */		
		if ((fp = TestOpenTextFileR(fileName)) != NULL)
			{
			SafeFclose (&fp);
			if (autoOverwrite == NO) 
				{
				MrBayesPrint ("%s   Appending to file \"%s\"\n", spacer, fileName); 
				return (OpenTextFileA(fileName));
				}
			else 
				MrBayesPrint ("%s   Overwriting file \"%s\"\n", spacer, fileName);		
			}
			return (OpenTextFileW(fileName));
		}	
	else
		{
		/* prompt user if file is already present */
		if ((fp = TestOpenTextFileR(fileName)) != NULL)
			{
			SafeFclose (&fp);
			MrBayesPrint ("\n");
			MrBayesPrint ("%s   File \"%s\" already exists\n", spacer, fileName);
			overWrite = WantTo ("Overwrite information in this file");
			
			if (overWrite == YES)
				{
				MrBayesPrint ("%s   Overwriting file \"%s\"\n", spacer, fileName);
				return (OpenTextFileW(fileName));
				}
			else
				{
				MrBayesPrint ("%s   Appending to file \"%s\"\n", spacer, fileName);
				return (OpenTextFileA(fileName));
				}
			}

		else
			{
			/* file is not present */
			return (OpenTextFileW(fileName));
			}
		}
}





int PickProposal (SafeLong *seed, int chainIndex)

{
	
	MrBFlt		ran;
	int			i;

	ran = RandomNumber (seed);
	
	for (i=0; usedMoves[i]->cumProposalProb[chainIndex] <= ran; i++)
		;
		
	return i;

}





int PosSelProbs (TreeNode *p, int division, int chain)

{

	int				c, j, k, nStates;
	MrBFlt			catLike, like[100], *bs, *omegaCatFreq, *omega,
					posProb, *ps, sum;
	CLFlt			*clP;
	ModelInfo		*m;
	
	m = &modelSettings[division];

	/* number of states */
	nStates = m->numModelStates;

	/* find conditional likelihood pointer */
	clP = m->condLikes[m->condLikeIndex[chain][p->index]];
    
	/* find base frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);
	
	/* find category frequencies */
	omegaCatFreq = GetParamSubVals (m->omega, chain, state[chain]);
	
	/* get category omegas */
	omega = GetParamVals (m->omega, chain, state[chain]);

	/* find posSelProbs */
	ps = posSelProbs + m->compCharStart;
	for (c=m->numDummyChars; c<m->numChars; c++)
		{
		sum = 0.0;
		for (k=0; k<m->numOmegaCats; k++)
			{
			like[k] = 0.0;
			catLike = 0.0;
			for (j=0; j<nStates; j++)
				catLike += clP[j] * bs[j];
			like[k] = catLike * omegaCatFreq[k];
			sum += like[k];
			clP += nStates;
			}
		posProb = 0.0;
		for (k=0; k<m->numOmegaCats; k++)
			{
			if (omega[k] > 1.0)
				posProb += like[k] / sum;
			}
		ps[c] = posProb;
		}

	return NO_ERROR;
	
}





int SiteOmegas (TreeNode *p, int division, int chain)

{

	int				c, j, k, nStates;
	MrBFlt			catLike, like[100], *bs, *omegaCatFreq, *omega,
					siteOmega, *ps, sum;
	CLFlt			*clP;
	ModelInfo		*m;
	
	m = &modelSettings[division];

	/* number of states */
	nStates = m->numModelStates;

	/* find conditional likelihood pointer */
	clP = m->condLikes[m->condLikeIndex[chain][p->index]];
	
	/* find base frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);
	
	/* find category frequencies */
	omegaCatFreq = GetParamSubVals (m->omega, chain, state[chain]);
	
	/* get category omegas */
	omega = GetParamVals (m->omega, chain, state[chain]);

	/* find posSelProbs */
	ps = posSelProbs + m->compCharStart;
	for (c=m->numDummyChars; c<m->numChars; c++)
		{
		sum = 0.0;
		for (k=0; k<m->numOmegaCats; k++)
			{
			like[k] = 0.0;
			catLike = 0.0;
			for (j=0; j<nStates; j++)
				catLike += clP[j] * bs[j];
			like[k] = catLike * omegaCatFreq[k];
			sum += like[k];
			clP += nStates;
			}
		siteOmega = 0.0;
		for (k=0; k<m->numOmegaCats; k++)
			{
			siteOmega += (like[k]/sum) * omega[k];
			}
		ps[c] = siteOmega;
		}

	return NO_ERROR;
	
}





/*----------------------------------------------------------------------
|
|	PreparePrintFiles: Prepare .t, .p, and .mcmc files for printing
|
------------------------------------------------------------------------*/
int PreparePrintFiles (void)

{

	int			i, k, n, previousResults, oldAutoOverwrite, oldNoWarn;
	char		localFileName[100], fileName[220], bkupName[220];
    FILE        *tempFile;

#if defined (MPI_ENABLED)
	if (proc_id != 0)
		return (NO_ERROR);
#endif

    oldNoWarn        = noWarn;
    oldAutoOverwrite = autoOverwrite;

    /* Allocate space for file pointers */
	n = chainParams.numRuns;

	if (memAllocs[ALLOC_FILEPOINTERS] == YES)
		{
		MrBayesPrint ("%s   File pointers already allocated in PreparePrintFiles\n", spacer);
		return ERROR;
		}
	fpMcmc = NULL;
    fpSS = NULL;
	fpParm = NULL;
	fpTree = NULL;	
	fpParm = (FILE **) SafeCalloc (n, sizeof (FILE *));	
	if (fpParm == NULL)
		{
		MrBayesPrint ("%s   Could not allocate fpParm in PreparePrintFiles\n", spacer);
		return ERROR;
		}
	memAllocs[ALLOC_FILEPOINTERS] = YES;
	fpTree = (FILE ***) SafeCalloc (n, sizeof (FILE **));	
	if (fpTree == NULL)
		{
		MrBayesPrint ("%s   Could not allocate fpTree in PreparePrintFiles\n", spacer);
		return ERROR;
		}
	fpTree[0] = (FILE **) SafeCalloc (numTrees*n, sizeof (FILE *));
	if (fpTree[0] == NULL)
		{
		MrBayesPrint ("%s   Could not allocate fpTree[0] in PreparePrintFiles\n", spacer);
		return ERROR;
		}
	for (i=1; i<n; i++)
		fpTree[i] = fpTree[0] + i*numTrees;

	/* Get root of local file name */
	strcpy (localFileName, chainParams.chainFileName);

	/* Prepare the .mcmc file */
    if (noWarn == NO)
        {
        previousResults = NO;
        if (chainParams.mcmcDiagn == YES)
    		{
		    sprintf (fileName, "%s.mcmc", localFileName);
		    if ((tempFile = TestOpenTextFileR(fileName)) != NULL)
                {
                fclose(tempFile);
    			previousResults = YES;
		        }
            }
	    for (n=0; n<chainParams.numRuns; n++)
		    {
		    k = n;

		    if (chainParams.numRuns == 1)
			    sprintf (fileName, "%s.p", localFileName);
		    else
			    sprintf (fileName, "%s.run%d.p", localFileName, n+1);
		    if ((tempFile = TestOpenTextFileR(fileName)) != NULL)
                {
                fclose(tempFile);
    			previousResults = YES;
		        }

    		for (i=0; i<numTrees; i++)
			    {
			    if (numTrees == 1 && chainParams.numRuns == 1)
				    sprintf (fileName, "%s.t", localFileName);
			    else if (numTrees > 1 && chainParams.numRuns == 1)
				    sprintf (fileName, "%s.tree%d.t", localFileName, i+1);
    			else if (numTrees == 1 && chainParams.numRuns > 1)
	    			sprintf (fileName, "%s.run%d.t", localFileName, n+1);
		    	else
			    	sprintf (fileName, "%s.tree%d.run%d.t", localFileName, i+1, n+1);
    			if ((tempFile = TestOpenTextFileR(fileName)) != NULL)
                    {
                    fclose(tempFile);
    			    previousResults = YES;
		            }
    			}
	    	}
        if (previousResults == YES)
            {
            MrBayesPrint("\n");
            MrBayesPrint("%s   There are results from a previous run saved using the same filename(s).\n", spacer);
            if (WantTo("Do you want to overwrite these results") == YES)
                {
                MrBayesPrint("\n");
                noWarn = YES;
                autoOverwrite = YES;
                }
            else
                {
                MrBayesPrint("\n");
                MrBayesPrint("%s   Please specify a different file name before running the mcmc analysis.\n", spacer);
                MrBayesPrint("%s      You can do that using 'mcmc filename=<name>'. You can also move or\n", spacer);
                MrBayesPrint("%s      rename the old result files.\n", spacer);
                return ERROR;
                }
            }
        }

    /* Prepare the .p and .t files */
	for (n=0; n<chainParams.numRuns; n++)
		{
		k = n;

		if (chainParams.numRuns == 1)
			sprintf (fileName, "%s.p", localFileName);
		else
			sprintf (fileName, "%s.run%d.p", localFileName, n+1);
		if ((fpParm[k] = OpenNewMBPrintFile (fileName)) == NULL)
            {
            noWarn = oldNoWarn;
            autoOverwrite = oldAutoOverwrite;
			return (ERROR);
            }

		for (i=0; i<numTrees; i++)
			{
			if (numTrees == 1 && chainParams.numRuns == 1)
				sprintf (fileName, "%s.t", localFileName);
			else if (numTrees > 1 && chainParams.numRuns == 1)
				sprintf (fileName, "%s.tree%d.t", localFileName, i+1);
			else if (numTrees == 1 && chainParams.numRuns > 1)
				sprintf (fileName, "%s.run%d.t", localFileName, n+1);
			else
				sprintf (fileName, "%s.tree%d.run%d.t", localFileName, i+1, n+1);
			if ((fpTree[k][i] = OpenNewMBPrintFile (fileName)) == NULL)
                {
                noWarn = oldNoWarn;
                autoOverwrite = oldAutoOverwrite;
			    return (ERROR);
                }
			}
		}

	/* Prepare the .mcmc file */
	if (chainParams.mcmcDiagn == YES)
		{
		sprintf (fileName, "%s.mcmc", chainParams.chainFileName);
		if ((fpMcmc = OpenNewMBPrintFile (fileName)) == NULL)
            {
            noWarn = oldNoWarn;
            autoOverwrite = oldAutoOverwrite;
			return (ERROR);
            }
		}

    /* Prepare the .ss file */
	if ( chainParams.isSS == YES )
		{
		sprintf (fileName, "%s.ss", chainParams.chainFileName);
		if ((fpSS = OpenNewMBPrintFile (fileName)) == NULL)
            {
            noWarn = oldNoWarn;
            autoOverwrite = oldAutoOverwrite;
			return (ERROR);
            }
		}



    /* Remove previous chekpoint file if present */
    sprintf (fileName, "%s%s.ckp", workingDir, chainParams.chainFileName);
    strcpy (bkupName, fileName);
    strcat (bkupName, "~");
    remove (bkupName);
    rename (fileName, bkupName);

    return (NO_ERROR);
}





/*----------------------------------------------------------------
|
|	PrintAncStates_Bin: print ancestral states after final pass
|		Binary model with or without rate variation
|
-----------------------------------------------------------------*/
int PrintAncStates_Bin (TreeNode *p, int division, int chain)

{

	int				c, i, k;
	MrBFlt			*bs, freq;
	CLFlt			*clFP, *cL, sum, **clP;
	char			*tempStr;
	int             tempStrSize = TEMPSTRSIZE;
	ModelInfo		*m;
	
	tempStr = (char *) SafeMalloc((size_t) (tempStrSize * sizeof(char)));
	if (!tempStr)
		{
		MrBayesPrint ("%s   Problem allocating tempString (%d)\n", spacer, tempStrSize * sizeof(char));
		return (ERROR);
		}

	/* find model settings for this division */
	m = &modelSettings[division];

	/* find state frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);
	
	/* find frequencies of rate categories */
	freq =  1.0 /  m->numGammaCats;
	
	/* find the conditional likelihoods from the final pass */
    clFP = m->condLikes[m->condLikeScratchIndex[p->index]];

    clP = m->clP;
    for (k=0; k<m->numGammaCats; k++)
        {
        clP[k] =  clFP;
        clFP += m->numChars * m->numModelStates;
        }

	/* find the preallocated working space */
	cL = m->ancStateCondLikes;
	
	/* cycle over the compressed characters */
	for (c=0; c<m->numChars; c++)
		{
		cL[0] = cL[1] = 0.0;
		for (k=0; k<m->numGammaCats; k++)
			{
			cL[0] += clP[k][0];
			cL[1] += clP[k][1];
            clP[k]+=2;
			}
		cL[0] *= (CLFlt) (bs[0] * freq);
		cL[1] *= (CLFlt) (bs[1] * freq);
		sum = cL[0] + cL[1];
        assert(cL[0]==cL[0]);
        assert(cL[1]==cL[1]);
        assert(sum<9999999999999999999999999999999.0);
		cL[0] /= sum;
		cL[1] /= sum;
        assert(cL[0]==cL[0]);
        assert(cL[1]==cL[1]);
		cL += 2;
		}

	/* print the resulting conditional likelihoods cycling over uncompressed chars */
	for (c=0; c<numChar; c++)
		{
		if (charInfo[c].isExcluded == YES || partitionId[c][partitionNum] != division+1)
			continue;
		i = compCharPos[c] - m->compCharStart;
		cL = m->ancStateCondLikes + (i*2);
        SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(cL[0]));
		if (AddToPrintString (tempStr) == ERROR) return (ERROR);
        SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(cL[1]));
		if (AddToPrintString (tempStr) == ERROR) return (ERROR);
		}

	free (tempStr);
	return NO_ERROR;	

}




/*----------------------------------------------------------------
|
|	PrintAncStates_Gen: print ancestral states after final pass
|		General model with or without rate variation
|
-----------------------------------------------------------------*/
int PrintAncStates_Gen (TreeNode *p, int division, int chain)

{

	int				c, i, k, nStates, hasPInvar, nGammaCats;
	const int		*rateCat;
	MrBFlt			*bsVals;
	CLFlt			*cL, sum, pInvar=0.0, freq, f, bs[64];
	const CLFlt		*clFP, *clInvar=NULL, *lnScaler, **clP;
	char			*tempStr, *printedChar;
	int             tempStrSize = TEMPSTRSIZE;
	ModelInfo		*m;
	
	tempStr = (char *) SafeMalloc((size_t) (tempStrSize * sizeof(char)));
    if (!tempStr )
		{
		MrBayesPrint ("%s   Problem allocating tempString (%d)\n", spacer, tempStrSize * sizeof(char));
		return (ERROR);
		}

    if (!strcmp(modelParams[division].nucModel,"Codon") || !strcmp(modelParams[division].nucModel,"Protein") || !strcmp(modelParams[division].nucModel,"Doublet"))
        {
        assert(modelParams[division].dataType == DNA || modelParams[division].dataType == RNA);/*Note that we can have matrix with Protein datatype which is not and should not be covered here */
        printedChar = (char *) SafeMalloc (numChar*sizeof(char));
        }
    else
        {
        printedChar = NULL;
        }

        
	/* find model settings for this division */
	m = &modelSettings[division];

	/* find number of states */
	nStates = m->numModelStates;
	
	/* find state frequencies */
	bsVals = GetParamSubVals (m->stateFreq, chain, state[chain]);
	for (i=0; i<nStates; i++)
		bs[i] = (CLFlt) bsVals[i];

	/* find invar cond likes */
	if (m->pInvar == NULL)
		hasPInvar = NO;
	else
		{
		hasPInvar = YES;
		clInvar = m->invCondLikes;
		pInvar = (CLFlt) *GetParamVals (m->pInvar, chain, state[chain]); 
		}

	/* find number of rate categories */
	nGammaCats = m->numGammaCats;

	/* find frequencies of rate categories (only relevant if gibbsGamma == NO) */
	freq = ((CLFlt)1.0 - pInvar) / nGammaCats;
	
	/* find site scaler */
	lnScaler = m->scalers[m->siteScalerIndex[chain]];
    
	/* find rate category index */
	rateCat = m->tiIndex + chain*m->numChars;

	/* find the conditional likelihoods from the final pass */
    clFP = m->condLikes[m->condLikeScratchIndex[p->index]];
    
	/* find the preallocated working space */
	cL = m->ancStateCondLikes;
	
    /* cycle over the compressed characters */
	if (m->gibbsGamma == YES)
		{
		for (c=0; c<m->numChars; c++)
			{
			sum = 0.0;
			if (rateCat[c] < nGammaCats)
				{
				for (i=0; i<nStates; i++)
					{
					cL[i] = *(clFP++) * bs[i];
					sum += cL[i];
					}
				clInvar += nStates;
				}
			else
				{
				for (i=0; i<nStates; i++)
					{
					cL[i] = *(clInvar++) * bs[i];
					sum += cL[i];
					}
				clFP += nStates;
				}
			for (i=0; i<nStates; i++)
				cL[i] /= sum;
			cL += nStates;
			}
		}
	else
		{
        /* find conditional likelihood pointers */
        clP = (const CLFlt**)m->clP;
        for (k=0; k<m->numGammaCats; k++)
            {
            clP[k] = clFP;
            clFP += m->numChars * m->numModelStates;
            }
		for (c=0; c<m->numChars; c++)
			{
			for (i=0; i<nStates; i++)
				cL[i] = 0.0;
			for (k=0; k<nGammaCats; k++)
				{
				for (i=0; i<nStates; i++)
					cL[i] += *(clP[k]++);
				}
			for (i=0; i<nStates; i++)
				cL[i] *= bs[i];

			if (hasPInvar == YES)
				{
				sum = 0.0;
				for (i=0; i<nStates; i++)
					sum += clInvar[i];
				if (sum > 0.0)
					{
					if (lnScaler[c] < -100.0)
						{
						/* only invar cond likes are relevant */
						for (i=0; i<nStates; i++)
							cL[i] = clInvar[i] * bs[i] * pInvar;
						}
					else
						{
						f = (CLFlt) exp(lnScaler[c]) * freq;
						for (i=0; i<nStates; i++)
							cL[i] = clInvar[i] * bs[i] * pInvar + cL[i] * f;
						}
					}
				clInvar += nStates;
				}
			
			sum = 0.0;
			for (i=0; i<nStates; i++)
				sum += cL[i];
			for (i=0; i<nStates; i++)
				cL[i] /= sum;
			cL += nStates;
			}
		}


	/* print the resulting conditional likelihoods cycling over uncompressed chars */
    if( printedChar )
        for (c=0; c<numChar; c++)
            printedChar[c] = NO;

    for (c=0; c<numChar; c++)
		{
		if (charInfo[c].isExcluded == YES || partitionId[c][partitionNum] != division+1 || (printedChar &&
            printedChar[c] == YES))
			continue;
		i = compCharPos[c] - m->compCharStart;
		cL = m->ancStateCondLikes + (i*nStates);
        if( printedChar )
            {
            for (i=c+1; i<numChar; i++)
                if (charInfo[c].charId == charInfo[i].charId)
                    printedChar[i] = YES;
            }
		for (i=0; i<nStates; i++)
			{
			SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(cL[i]));
			if (AddToPrintString (tempStr) == ERROR) return (ERROR);
			}
		}
	free (tempStr);
    free (printedChar);
	return NO_ERROR;	

}




/*----------------------------------------------------------------
|
|	PrintAncStates_NUC4: print ancestral states after final pass
|		4-state nucleotide model with or without rate variation
|
-----------------------------------------------------------------*/
int PrintAncStates_NUC4 (TreeNode *p, int division, int chain)

{

	int				c, i, k, *rateCat, hasPInvar, nGammaCats;
	MrBFlt			*bsVals;
	CLFlt			*cL, sum, pInvar=0.0, bs[4], freq, f;
	const CLFlt		*clFP, *clInvar=NULL, *lnScaler,**clP;
	char			*tempStr;
	int             tempStrSize = TEMPSTRSIZE;
	ModelInfo		*m;
	
	tempStr = (char *) SafeMalloc((size_t) (tempStrSize * sizeof(char)));
	if (!tempStr)
		{
		MrBayesPrint ("%s   Problem allocating tempString (%d)\n", spacer, tempStrSize * sizeof(char));
		return (ERROR);
		}

	/* find model settings for this division */
	m = &modelSettings[division];

	/* find state frequencies */
	bsVals = GetParamSubVals (m->stateFreq, chain, state[chain]);
	bs[A] = (CLFlt) bsVals[A];
	bs[C] = (CLFlt) bsVals[C];
	bs[G] = (CLFlt) bsVals[G];
	bs[T] = (CLFlt) bsVals[T];

	/* find invar cond likes */
	if (m->pInvar == NULL)
		hasPInvar = NO;
	else
		{
		hasPInvar = YES;
		clInvar = m->invCondLikes;
		pInvar = (CLFlt) *GetParamVals (m->pInvar, chain, state[chain]); 
		}


	/* find number of rate categories */
	nGammaCats = m->numGammaCats;

	/* find frequencies of rate categories (only relevant if gibbsGamma == NO) */
	if (hasPInvar == NO)
		freq =  (CLFlt) 1.0 /  nGammaCats;
	else
		freq = ((CLFlt)1.0 - pInvar) / nGammaCats;
	
	/* find site scaler */
	lnScaler = m->scalers[m->siteScalerIndex[chain]];
	
	/* find rate category index */
	rateCat = m->tiIndex + chain*m->numChars;

	/* find the conditional likelihoods from the final pass */
    clFP = m->condLikes[m->condLikeScratchIndex[p->index]];
    
	/* find the preallocated working space */
	cL = m->ancStateCondLikes;
	
	/* cycle over the compressed characters */
	if (m->gibbsGamma == YES)
		{
		for (c=0; c<m->numChars; c++)
			{
			if (rateCat[c] < nGammaCats)
				{
				cL[A] = clFP[A] * (CLFlt) bs[A];
				cL[C] = clFP[C] * (CLFlt) bs[C];
				cL[G] = clFP[G] * (CLFlt) bs[G];
				cL[T] = clFP[T] * (CLFlt) bs[T];
				}
			else
				{
				cL[A] = clInvar[A] * (CLFlt) bs[A];
				cL[C] = clInvar[C] * (CLFlt) bs[C];
				cL[G] = clInvar[G] * (CLFlt) bs[G];
				cL[T] = clInvar[T] * (CLFlt) bs[T];
				}
			sum = cL[A] + cL[C] + cL[G] + cL[T];
			cL[A] /= sum;
			cL[C] /= sum;
			cL[G] /= sum;
			cL[T] /= sum;
			clInvar += 4;
			clFP += 4;
			cL += 4;
			}
		}
	else
		{
        /* find conditional likelihood pointers */
        clP = (const CLFlt**)m->clP;
        for (k=0; k<m->numGammaCats; k++)
            {
            clP[k] = clFP;
            clFP += m->numChars * m->numModelStates;
            }

		for (c=0; c<m->numChars; c++)
			{
			cL[A] = cL[C] = cL[G] = cL[T] = 0.0;
			for (k=0; k<nGammaCats; k++)
				{
				cL[A] += clP[k][A];
				cL[C] += clP[k][C];
				cL[G] += clP[k][G];
				cL[T] += clP[k][T];
				clP[k] += 4;
				}
			cL[A] *= bs[A];
			cL[C] *= bs[C];
			cL[G] *= bs[G];
			cL[T] *= bs[T];
			if (hasPInvar == YES)
				{
				sum = clInvar[A] + clInvar[C] + clInvar[G] + clInvar[T];
				if (sum > 0.0)
					{
					if (lnScaler[c] < -100.0)
						{
						/* only invar cond likes are relevant */
						cL[A] = clInvar[A] * bs[A] * pInvar;
						cL[C] = clInvar[C] * bs[C] * pInvar;
						cL[G] = clInvar[G] * bs[G] * pInvar;
						cL[T] = clInvar[T] * bs[T] * pInvar;
						}
					else
						{
						f = (CLFlt)exp(lnScaler[c]) * freq;
						cL[A] = clInvar[A] * bs[A] * pInvar + cL[A] * f;
						cL[C] = clInvar[C] * bs[C] * pInvar + cL[C] * f;
						cL[G] = clInvar[G] * bs[G] * pInvar + cL[G] * f;
						cL[T] = clInvar[T] * bs[T] * pInvar + cL[T] * f;
						}
					}
				clInvar += 4;
				}
			sum = cL[A] + cL[C] + cL[G] + cL[T];
			cL[A] /= sum;
			cL[C] /= sum;
			cL[G] /= sum;
			cL[T] /= sum;
			cL += 4;
			}
		}

	/* print the resulting conditional likelihoods cycling over uncompressed chars */
	for (c=0; c<numChar; c++)
		{
		if (charInfo[c].isExcluded == YES || partitionId[c][partitionNum] != division+1)
			continue;
		i = compCharPos[c] - m->compCharStart;
		cL = m->ancStateCondLikes + (i*4);
		SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(cL[A]));
		if (AddToPrintString (tempStr) == ERROR) return ERROR;
		SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(cL[C]));
		if (AddToPrintString (tempStr) == ERROR) return ERROR;
		SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(cL[G]));
		if (AddToPrintString (tempStr) == ERROR) return ERROR;
		SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(cL[T]));
		if (AddToPrintString (tempStr) == ERROR) return ERROR;
		}
	free (tempStr);
	return NO_ERROR;	

}




/*----------------------------------------------------------------
|
|	PrintAncStates_Std: print ancestral states after final pass
|		Standard model with or without rate variation
|
-----------------------------------------------------------------*/
int PrintAncStates_Std (TreeNode *p, int division, int chain)

{

	int				c, i, j, k, s, nStates, numReps;
	MrBFlt			*bsBase, *bs, freq;
	CLFlt			*clFP, *cL, sum,** clP;
	char			*tempStr;
	int			    tempStrSize = TEMPSTRSIZE;
	ModelInfo		*m;
	
	tempStr = (char *) SafeMalloc((size_t) (tempStrSize * sizeof(char)));
	if (!tempStr)
		{
		MrBayesPrint ("%s   Problem allocating tempString (%d)\n", spacer, tempStrSize * sizeof(char));
		return (ERROR);
		}

	/* find model settings for this division */
	m = &modelSettings[division];

	/* find state frequencies, base index */
	bsBase = GetParamStdStateFreqs (m->stateFreq, chain, state[chain]);
	
	/* find the conditional likelihoods from the final pass */
    clFP = m->condLikes[m->condLikeScratchIndex[p->index]];

    numReps=0;
	for (c=0; c<m->numChars; c++)
		{
		if ( m->nStates[c] == 2 )
				numReps += m->numBetaCats * 2;
			else
				numReps += m->nStates[c];
		}

    /* find conditional likelihood pointers */
    clP = m->clP;
    for (k=0; k<m->numGammaCats; k++)
        {
        clP[k] = clFP;
        clFP += numReps;
        }

	/* find the preallocated working space */
	cL = m->ancStateCondLikes;
	
	/* cycle over the compressed characters */
	for (c=0; c<m->numChars; c++)
		{
		nStates = m->nStates[c];
        bs = bsBase + m->bsIndex[c];

		for (s=0; s<nStates; s++)
			cL[s] = 0.0;

        if (nStates == 2)
            {
            freq = 1.0 / (m->numBetaCats * m->numGammaCats);
	        for (i=0; i<m->numBetaCats; i++)
                {
                for (k=0; k<m->numGammaCats; k++)
			        {
		            for (s=0; s<nStates; s++)
			            cL[s] += clP[k][s] * (CLFlt)(bs[s] * freq);
    		        clP[k] += nStates;
                    }
                bs += nStates;
		        }
           }
        else
            {
            freq = 1.0 / (m->numGammaCats);
            for (k=0; k<m->numGammaCats; k++)
		        {
	            for (s=0; s<nStates; s++)
		            cL[s] += clP[k][s] * (CLFlt)(bs[s] * freq);
		        clP[k] += nStates;
                }
	        }

		sum = 0.0;
		for (s=0; s<nStates; s++)
			sum += cL[s];

        assert (sum != 0.0);

        for (s=0; s<nStates; s++) 
			cL[s] /= sum;

		cL += nStates;
		}

	/* print the resulting conditional likelihoods cycling over uncompressed chars */
	for (c=0; c<numChar; c++)
		{
		if (charInfo[c].isExcluded == YES || partitionId[c][partitionNum] != division+1)
			continue;
		
		k = compCharPos[c] - m->compCharStart;
		for (i=j=0; i<k; i++)
			j += m->nStates[i];
		cL = m->ancStateCondLikes + j;

		for (i=0; i<m->nStates[k]; i++)
			{
			SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(cL[i]));
			if (AddToPrintString (tempStr) == ERROR) return (ERROR);
			}
		}
	free (tempStr);
	return NO_ERROR;	

}



/*-----------------------------------------------------------------------
|
|	PrintCheckPoint: Print checkpoint to file
|
------------------------------------------------------------------------*/
int PrintCheckPoint (int gen)

{
	int			i, j, k, k1, nErrors=0, run, chn, nValues, tempStrSize = TEMPSTRSIZE, hasEvents, *intValue;
	char		bkupFileName[220], oldBkupFileName[220], ckpFileName[220], *tempString=NULL;
	MrBFlt		*value, clockRate;
	Param		*p = NULL, *subParm = NULL;
	Tree		*t;
	FILE		*fp = NULL;
    MCMCMove    *mv;
	/*ModelInfo	*m = NULL;*/

#if defined (MPI_ENABLED)
	int			sumErrors=0,ierror;
    MrBFlt      r, sum;
#endif

	/* allocate tempString */
	if ((tempString = (char *) SafeCalloc (tempStrSize, sizeof(char))) == NULL)
		nErrors++;

#if defined (MPI_ENABLED)
	if (proc_id == 0)
		{
#endif
	if (nErrors == 0)
		{
		/* figure out check-point file names */
        sprintf(ckpFileName, "%s%s.ckp", workingDir, chainParams.chainFileName);
		strcpy (bkupFileName, ckpFileName);
		strcat (bkupFileName, "~");
		strcpy (oldBkupFileName, bkupFileName);
		strcat (oldBkupFileName, "~");

		/* shift check-point files */
		remove (oldBkupFileName);
		rename (bkupFileName, oldBkupFileName);
		rename (ckpFileName, bkupFileName);

		/* create new ckp file */
		if ((fp = OpenTextFileW (ckpFileName)) == NULL)
			{
			MrBayesPrint ("%s   Problem opening checkpoint file\n", spacer);
			free (tempString);
			nErrors++;
			}
		}
	
#if defined (MPI_ENABLED)
	} /* end of if(proc_id == 0)*/
#endif

    ERROR_TEST2("",free(tempString),return(ERROR));

    /* write file header */
    MrBayesPrintf (fp, "#NEXUS\n[run stamp:%s]\n[generation: %d]\n", stamp, gen);

    if( chainParams.isSS == YES)
        {
        /* dump to .ckp file current step contribution */
        MrBayesPrintf (fp, "[SsAcumulators:");
#       if defined (MPI_ENABLED)

        for (j=0; j<chainParams.numRuns ; j++)
            {
            if( stepAcumulatorSS[j]==0 )
                r=0;
            else
                r = log( stepAcumulatorSS[j] ) + stepScalerSS[j];
            ierror = MPI_Reduce (&r,&sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
            if (ierror != MPI_SUCCESS)
                {
                MrBayesPrint ("%s   Problem with MPI_Reduce\n", spacer);
                return ERROR;
                }
            if(proc_id == 0 )
                {
                MrBayesPrintf (fp, " %.4f", sum);
                }
            }
#	    else
        for (j=0; j<chainParams.numRuns ; j++)
            {
            MrBayesPrintf (fp, " %.4f", log( stepAcumulatorSS[j] ) + stepScalerSS[j]);
            }
#       endif
        MrBayesPrintf (fp, "]\n");
        }

#if defined (MPI_ENABLED)
if (proc_id == 0)
	{
#endif
    MrBayesPrintf (fp, "\nbegin trees;\n\ttranslate\n");

    /* remove old bkup file ('~~') */
    remove (oldBkupFileName);

    /* write translate block */
	for (i=0; i<numLocalTaxa; i++)
		{
		if (i == numLocalTaxa - 1)
			MrBayesPrintf (fp, "      %2d %s;\n", i+1, localTaxonNames[i]);
		else
			MrBayesPrintf (fp, "      %2d %s,\n", i+1, localTaxonNames[i]);
		}
   
#if defined (MPI_ENABLED)
    }
#endif

	/* allocate space for print string */
	printStringSize = tempStrSize;
	printString = (char *) SafeCalloc ((size_t)printStringSize, sizeof(char));
	if (!printString)
		nErrors++;
	else
		strcpy(printString,"");


    ERROR_TEST2("Memory allocation error",free(tempString),return(ERROR));
    /*
#	if defined (MPI_ENABLED)
	MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
	if (sumErrors > 0)
		{
		MrBayesPrint ("%s   Memory allocation error on at least one processor\n", spacer);
		free (tempString);
		return ERROR;
		}
#	else
	if (nErrors > 0)
		{
		free (tempString);
		return ERROR;
		}
#	endif
*/
	/* print trees */
	for (i=0; i<numParams; i++)
		{
		p = &params[i];
		if (p->paramType != P_BRLENS && p->paramType != P_TOPOLOGY && p->paramType != P_SPECIESTREE)
			continue;
		if (p->paramType == P_TOPOLOGY && p->subParams[0] != p)
			continue;
        hasEvents = NO;
        for (j=0; j<numLocalChains; j++)
			{
			t = GetTree (p, j, state[j]);
            /* write the tree preamble */
			if (nErrors == 0 && SafeSprintf (&tempString, &tempStrSize, "\ttree %s", t->name) == ERROR)
				nErrors++;
			if (nErrors == 0 && AddToPrintString (tempString) == ERROR)
				nErrors++;
            if (p->paramType == P_BRLENS && p->nSubParams > 0)
                {
                for (k=0; k<p->nSubParams; k++)
                    {
                    subParm = p->subParams[k];
                    if (subParm->paramType == P_CPPEVENTS)
                        {
                        hasEvents = YES;
                    	if (SafeSprintf (&tempString, &tempStrSize, " [&E %s]", subParm->name) == ERROR) nErrors++;
    	                if (nErrors == 0 && AddToPrintString (tempString) == ERROR) nErrors++;
                        }
                    if (nErrors == 0 && (subParm->paramType == P_CPPEVENTS || subParm->paramType == P_TK02BRANCHRATES ||
                                         subParm->paramType == P_IGRBRANCHLENS))
                        {
            	        if (SafeSprintf (&tempString, &tempStrSize, " [&B %s]", subParm->name) == ERROR) nErrors++;
	                    if (nErrors == 0 && AddToPrintString (tempString) == ERROR) nErrors++;
                        }
                    }
                }
            if (p->paramType == P_SPECIESTREE)
                {
                subParm = modelSettings[p->relParts[0]].popSize;
                if (subParm->nValues > 1)
                    {
                	if (SafeSprintf (&tempString, &tempStrSize, " [&N %s]", subParm->name) == ERROR) nErrors++;
	                if (nErrors == 0 && AddToPrintString (tempString) == ERROR) nErrors++;
                    }
                }
            
            if (t->isRooted == YES && t->isClock == NO)
    	        SafeSprintf (&tempString, &tempStrSize, " = ");
            else if (t->isRooted == YES && t->isClock == YES)
                {
                clockRate = *GetParamVals(modelSettings[p->relParts[0]].clockRate, j, state[j]);
    	        SafeSprintf (&tempString, &tempStrSize, " = [&R] [&clockrate = %s] ", MbPrintNum(clockRate));
                }
            else /* if (t->isRooted == NO) */
    	        SafeSprintf (&tempString, &tempStrSize, " = ");
            if (nErrors == 0 && AddToPrintString (tempString) == ERROR) nErrors++;
            /* write the tree in (extended) Newick format */
			if (nErrors == 0)
				{
				if (p->paramType == P_TOPOLOGY)
					WriteTreeToPrintString (p, j, t->root->left, NO, t->isRooted);
				else if (hasEvents == NO)
					WriteTreeToPrintString (p, j, t->root->left, YES, t->isRooted);
				else
					WriteEventTreeToPrintString (t->root->left, j, p, YES);
				if (AddToPrintString (";\n") == ERROR)
					nErrors++;
				}
			}
		MrBayesPrintf (fp, "%s", printString);
#if defined (MPI_ENABLED)
		MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
		if (sumErrors > 0)
			{
			MrBayesPrint ("%s   Print error on at least one processor\n", spacer);
            goto errorExit;
			}
		if (PrintMPISlaves(fp) == ERROR)
            goto errorExit;
#else
		if (nErrors > 0)
            goto errorExit;
#endif
		strcpy (printString, "");
		strcpy (tempString, "");
		}
	MrBayesPrintf (fp, "end;\n\n");

	/* start startvals block */
	MrBayesPrintf (fp,"begin mrbayes;\n");
	MrBayesPrintf (fp, "\tstartvals\n");

	/* first print topology values */
	for (i=0; i<numParams; i++)
		{
		p = &params[i];
		if (p->paramType == P_TOPOLOGY)
			{
			for (j=0; j<numLocalChains; j++)
				{
				t = GetTree (p, j, state[j]);
				run = (chainId[j] / chainParams.numChains) + 1;
				chn = (chainId[j] % chainParams.numChains) + 1;
				if (nErrors == 0 && SafeSprintf (&tempString, &tempStrSize, "\t\t%s(%d,%d)=%s\n", p->name, run, chn, t->name) == ERROR)
					nErrors++;
				if (nErrors == 0 && AddToPrintString (tempString) == ERROR)
					nErrors++;
				}
			MrBayesPrintf (fp, "%s", printString);
#	if defined (MPI_ENABLED)
			MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
			if (sumErrors > 0)
				{
				MrBayesPrint ("%s   Print error on at least one processor\n", spacer);
				goto errorExit;
				}
			if (PrintMPISlaves(fp) == ERROR)
				goto errorExit;
#	else
			if (nErrors > 0)
				goto errorExit;
#	endif
			strcpy (printString, "");
			strcpy (tempString, "");
			}
		}

	/* now print branch lengths and relaxed clock parameters */
	for (i=0; i<numParams; i++)
		{
		p = &params[i];
		if (p->paramType == P_BRLENS)
			{
			for (j=0; j<numLocalChains; j++)
				{
				t = GetTree (p, j, state[j]);
				run = (chainId[j] / chainParams.numChains) + 1;
				chn = (chainId[j] % chainParams.numChains) + 1;
				if (nErrors == 0 && SafeSprintf (&tempString, &tempStrSize, "\t\t%s(%d,%d)=%s\n", p->name, run, chn, t->name) == ERROR)
					nErrors++;
				if (nErrors == 0 && AddToPrintString (tempString) == ERROR)
					nErrors++;
				for (k=0; k<p->nSubParams; k++)
					{
					if (nErrors == 0 && SafeSprintf (&tempString, &tempStrSize, "\t\t%s(%d,%d)=%s\n", p->subParams[k]->name, run, chn, t->name) == ERROR)
						nErrors++;
					if (nErrors == 0 && AddToPrintString (tempString) == ERROR)
						nErrors++;
					}
				}
			MrBayesPrintf (fp, "%s", printString);
#	if defined (MPI_ENABLED)
			MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
			if (sumErrors > 0)
				{
				MrBayesPrint ("%s   Print error on at least one processor\n", spacer);
				goto errorExit;
				}
			if (PrintMPISlaves(fp) == ERROR)
				goto errorExit;
#	else
			if (nErrors > 0)
				goto errorExit;
#	endif
			strcpy (printString, "");
			strcpy (tempString, "");
			}
		}

	/* now print species tree and population size parameters */
	for (i=0; i<numParams; i++)
		{
		p = &params[i];
		if (p->paramType == P_SPECIESTREE)
			{
			for (j=0; j<numLocalChains; j++)
				{
				t = GetTree (p, j, state[j]);
				run = (chainId[j] / chainParams.numChains) + 1;
				chn = (chainId[j] % chainParams.numChains) + 1;
				if (nErrors == 0 && SafeSprintf (&tempString, &tempStrSize, "\t\t%s(%d,%d)=%s\n", p->name, run, chn, t->name) == ERROR)
					nErrors++;
				if (nErrors == 0 && AddToPrintString (tempString) == ERROR)
					nErrors++;
                if (modelSettings[p->relParts[0]].popSize->nValues > 1)
				if (nErrors == 0 && SafeSprintf (&tempString, &tempStrSize, "\t\t%s(%d,%d)=%s\n", modelSettings[p->relParts[0]].popSize->name, run, chn, t->name) == ERROR)
					nErrors++;
				if (nErrors == 0 && AddToPrintString (tempString) == ERROR)
					nErrors++;
				}
			MrBayesPrintf (fp, "%s", printString);
#	if defined (MPI_ENABLED)
			MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
			if (sumErrors > 0)
				{
				MrBayesPrint ("%s   Print error on at least one processor\n", spacer);
				goto errorExit;
				}
			if (PrintMPISlaves(fp) == ERROR)
				goto errorExit;
#	else
			if (nErrors > 0)
				goto errorExit;
#	endif
			strcpy (printString, "");
			strcpy (tempString, "");
			}
		}

	/* now print param values */
	for (i=0; i<numPrintParams; i++)
		{
		p = printParam[i];
		for (j=0; j<numLocalChains; j++)
			{
			run = (chainId[j] / chainParams.numChains) + 1;
			chn = (chainId[j] % chainParams.numChains) + 1;
			if (p->paramType == P_PI && modelSettings[p->relParts[0]].dataType != STANDARD)
				{
				value = GetParamSubVals (p, j, state[j]);
				nValues = p->nSubValues;
				}
			else
				{
				value = GetParamVals (p, j, state[j]);
				nValues = p->nValues;
				}
			if (nErrors == 0 && SafeSprintf (&tempString, &tempStrSize, "\t\t%s(%d,%d)=(%.15le", p->name, run, chn, value[0]) == ERROR)
				nErrors++;
            if (nErrors == 0 && AddToPrintString (tempString) == ERROR)
				nErrors++;
			for (k=1; k<nValues; k++)
				{
				if (nErrors==0 && SafeSprintf (&tempString, &tempStrSize, ",%.15le", value[k]) == ERROR)
					nErrors++;
				if (nErrors == 0 && AddToPrintString (tempString) == ERROR)
					nErrors++;
				}
            /* print int values if present */
            if (p->nIntValues > 0)
				{
				intValue = GetParamIntVals (p, j, state[j]);
                nValues  = p->nIntValues;
                for (k=0; k<nValues; k++)
				    {
    			    if (nErrors==0 && SafeSprintf (&tempString, &tempStrSize, ",%d", intValue[k]) == ERROR)
	    		        nErrors++;
		    		if (nErrors == 0 && AddToPrintString (tempString) == ERROR)
			    	    nErrors++;
                    }
                }
            /* print extra params for symdir multistate */
            if (p->nSympi > 0)
				{
				value = GetParamStdStateFreqs (p, j, state[j]);
                if (p->hasBinaryStd == YES)
                    value += 2 * modelSettings[p->relParts[0]].numBetaCats;
                for (k=0; k<p->nSympi; k++)
				    {
                    for (k1=0; k1<p->sympinStates[k]; k1++)
                        {
    				    if (nErrors==0 && SafeSprintf (&tempString, &tempStrSize, ",%.15le", *value++) == ERROR)
	    				    nErrors++;
		    		    if (nErrors == 0 && AddToPrintString (tempString) == ERROR)
			    		    nErrors++;
                        }
                    }
                }
            /* print extra params for omega */
            if (p->paramType == P_OMEGA)
				{
				value = GetParamSubVals (p, j, state[j]);
				nValues = p->nSubValues/2;
			    for (k=0; k<nValues; k++)
				    {
				    if (nErrors==0 && SafeSprintf (&tempString, &tempStrSize, ",%.15le", value[k]) == ERROR)
					    nErrors++;
				    if (nErrors == 0 && AddToPrintString (tempString) == ERROR)
					    nErrors++;
                    }
                }
			if (nErrors == 0 && AddToPrintString (")\n") == ERROR)
				nErrors++;
			}
		MrBayesPrintf (fp, "%s", printString);
#if defined (MPI_ENABLED)
		MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
		if (sumErrors > 0)
			{
			MrBayesPrint ("%s   Print error on at least one processor\n", spacer);
			goto errorExit;
			}
		if (PrintMPISlaves(fp) == ERROR)
			goto errorExit;
#else
		if (nErrors > 0)
			goto errorExit;
#endif
		strcpy (printString, "");
		strcpy (tempString, "");
		}
    /* end startvals statement */
	MrBayesPrintf (fp, "\t;\n");

	/* print tuning parameters of moves */
	MrBayesPrintf (fp, "\tpropset\n");
	for (i=0; i<numUsedMoves; i++)
		{
		mv = usedMoves[i];
        if (mv->moveType->Autotune == NULL)
            continue;   /* tuning parameter(s) do not change */
		for (j=0; j<numLocalChains; j++)
			{
			run = (chainId[j] / chainParams.numChains) + 1;
			chn = (chainId[j] % chainParams.numChains) + 1;
			/* format is:   <move_name>$<tuning_param_name>(<run>,<chain>)=<number> */
			if (nErrors == 0 && SafeSprintf (&tempString, &tempStrSize, "\t\t%s$%s(%d,%d)=%.15le\n",
                mv->name, mv->moveType->shortTuningName[0], run, chn, mv->tuningParam[chainId[j]][0]) == ERROR)
				nErrors++;
            if (nErrors == 0 && AddToPrintString (tempString) == ERROR)
				nErrors++;
			}
		MrBayesPrintf (fp, "%s", printString);
#if defined (MPI_ENABLED)
		MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
		if (sumErrors > 0)
			{
			MrBayesPrint ("%s   Print error on at least one processor\n", spacer);
			goto errorExit;
			}
		if (PrintMPISlaves(fp) == ERROR)
			goto errorExit;
#else
		if (nErrors > 0)
			goto errorExit;
#endif
		strcpy (printString, "");
		strcpy (tempString, "");
		}

    /* end propset statement */
	MrBayesPrintf (fp, "\t;\n"); 
    
    /* end mrbayes block */
	MrBayesPrintf (fp, "end;\n\n");

	SafeFclose (&fp);
	free (tempString);
	free (printString);
	printStringSize = 0;
	return (NO_ERROR);

errorExit:
	free (tempString);
	free (printString);
	printString = NULL;
	printStringSize = 0;
    SafeFclose (&fp);
    return (ERROR);
}





/*----------------------------------------------------------------------
|
|	PrintMCMCDiagnosticsToFile: Print acceptance ratios, swapping
|      frequencies, and convergence diagnostics to file.
|
------------------------------------------------------------------------*/
int PrintMCMCDiagnosticsToFile (int curGen)

{

	int			i, j, n;
	MCMCMove	*theMove;
    char        *diagnstat;

    /* Simply print header if curGen == 0 */
    if (curGen == 0)
		{
		MrBayesPrintf (fpMcmc, "[LEGEND:]\n");
        MrBayesPrintf (fpMcmc, "[ID: %s]\n", stamp);
		MrBayesPrintf (fpMcmc, "[   Gen                --  Generation]\n");
		if (chainParams.allChains == YES)
			MrBayesPrintf (fpMcmc, "[   <name1>(<name2>)$acc_run2_chn3 --  Acceptance rate of move <name1> changing parameter <name2> in run 2, chain 3]\n");
		else /* if (chainParams.allChains == NO) */
			MrBayesPrintf (fpMcmc, "[   <name1>(<name2>)$acc_run2      --  Acceptance rate of move <name1> changing parameter 1 in run 2]\n");
		if (chainParams.numChains > 1 && chainParams.numRuns > 1)
			MrBayesPrintf (fpMcmc, "[   Swap(1<>2)$acc_run3            --  Acceptance rate of swaps between chains 1 and 2 in run 3]\n");
		else if (chainParams.numChains > 1 && chainParams.numRuns == 1)
			MrBayesPrintf (fpMcmc, "[   Swap(1<>2)$acc                 --  Acceptance rate of swaps between chains 1 and 2]\n");
		if (chainParams.diagnStat == AVGSTDDEV)
            diagnstat = "Average";
        else
            diagnstat = "Maximum";
        if (chainParams.numRuns > 1 && numTopologies == 1 && chainParams.allComps == NO)
			MrBayesPrintf (fpMcmc, "[   StdDev(s)                      --  %s standard deviation of split frequencies]\n", diagnstat);
		else if (chainParams.numRuns > 1 && numTopologies == 1 && chainParams.allComps == YES)
			MrBayesPrintf (fpMcmc, "[   StdDev(s)(run1-run2)           --  %s standard deviation of split frequencies between runs 1 and 2]\n", diagnstat);
		else if (chainParams.numRuns > 1 && numTopologies > 1 && chainParams.allComps == NO)
			MrBayesPrintf (fpMcmc, "[   StdDev(s.tree1)                --  %s standard deviation of split frequencies for topology 1]\n", diagnstat);
		else if (chainParams.numRuns > 1 && numTopologies > 1 && chainParams.allComps == YES)
			MrBayesPrintf (fpMcmc, "[   StdDev(s.tree1)(run1-run2)     --  %s standard deviation of split frequencies between runs 1 and 2 for topology 1]\n", diagnstat);

		MrBayesPrintf (fpMcmc, "Gen");
		for (n=0; n<chainParams.numRuns; n++)
			{
			if (chainParams.allChains == YES)
				{
				for (i=0; i<chainParams.numChains; i++)
					{
					for (j=0; j<numUsedMoves; j++)
						{
						theMove = usedMoves[j];
						MrBayesPrintf (fpMcmc, "\t%s(%s)$acc_run%d_chn%d", theMove->moveType->shortName,
                                theMove->parm->name, n+1, i+1);
                        if (theMove->moveType->Autotune != NULL && chainParams.autotune == YES)
						    MrBayesPrintf (fpMcmc, "\t%s(%s)$%s_run%d_chn%d", theMove->moveType->shortName,
                                theMove->parm->name, theMove->moveType->shortTuningName[0], n+1, i+1);
						}
					}
				}
			else
				{
				for (i=0; i<numUsedMoves; i++)
					{
					theMove = usedMoves[i];
					if (chainParams.numRuns == 1)
                        {
						MrBayesPrintf (fpMcmc, "\t%s(%s)$acc", theMove->moveType->shortName, theMove->parm->name);
                        if (theMove->moveType->Autotune != NULL && chainParams.autotune == YES)
						    MrBayesPrintf (fpMcmc, "\t%s(%s)$%s", theMove->moveType->shortName, theMove->parm->name, theMove->moveType->shortTuningName[0]);
                        }
					else
                        {
						MrBayesPrintf (fpMcmc, "\t%s(%s)$acc_run%d", theMove->moveType->shortName, theMove->parm->name, n+1);
                        if (theMove->moveType->Autotune != NULL && chainParams.autotune == YES)
						    MrBayesPrintf (fpMcmc, "\t%s(%s)$%s_run%d", theMove->moveType->shortName, theMove->parm->name, theMove->moveType->shortTuningName[0], n+1);
                        }
					}
				}
			if (chainParams.numChains > 1)
				{
				for (i=0; i<chainParams.numChains; i++)
					{
					for (j=i+1; j<chainParams.numChains; j++)
						{
						if (chainParams.numRuns == 1)
							MrBayesPrintf (fpMcmc, "\tSwap(%d<>%d)$acc", i+1, j+1);
						else
							MrBayesPrintf (fpMcmc, "\tSwap(%d<>%d)$acc(%d)", i+1, j+1, n+1);
						}
					}
				}
			}

		if (chainParams.numRuns > 1)
			{
			for (n=0; n<numTopologies; n++)
				{
				if (numTopologies == 1)
                    {
                    if (chainParams.diagnStat == AVGSTDDEV)
					    MrBayesPrintf (fpMcmc, "\tAvgStdDev(s)");
                    else
					    MrBayesPrintf (fpMcmc, "\tMaxStdDev(s)");
                    }
				else
                    {
                    if (chainParams.diagnStat == AVGSTDDEV)
					    MrBayesPrintf (fpMcmc, "\tAvgStdDev(s.tree%d)", n+1);
                    else
					    MrBayesPrintf (fpMcmc, "\tMaxStdDev(s.tree%d)", n+1);
                    }

				if (chainParams.allComps == YES)
					{
					for (i=0; i<chainParams.numRuns; i++)
						{
						for (j=i+1; j<chainParams.numRuns; j++)
							{
				            if (numTopologies == 1)
                                {
                                if (chainParams.diagnStat == AVGSTDDEV)
					                MrBayesPrintf (fpMcmc, "\tAvgStdDev(s)(run%d_run%d)", i+1,j+1);
                                else
					                MrBayesPrintf (fpMcmc, "\tMaxStdDev(s)(run%d_run%d)", i+1, j+1);
                                }
				            else
                                {
                                if (chainParams.diagnStat == AVGSTDDEV)
					                MrBayesPrintf (fpMcmc, "\tAvgStdDev(s.tree%d)(run%d_run%d)", n+1, i+1, j+1);
                                else
					                MrBayesPrintf (fpMcmc, "\tMaxStdDev(s.tree%d)(run%d_run%d)", n+1, i+1, j+1);
                                }
							}
						}
					}
				}
			}
		MrBayesPrintf (fpMcmc, "\n");
		fflush (fpMcmc);
		return (NO_ERROR);
		}

#if defined (MPI_ENABLED)
	/* Reassemble info if MPI version */
    if (ReassembleMoveInfo() == ERROR)
		return (ERROR);
	if (chainParams.numChains > 1 && ReassembleSwapInfo() == ERROR)
		return (ERROR);
	if (proc_id != 0)
        return (NO_ERROR);
#endif

	MrBayesPrintf (fpMcmc, "%d", curGen);

	for (n=0; n<chainParams.numRuns; n++)
		{
		if (chainParams.allChains == YES)
			{
			for (j=n*chainParams.numChains; j<(n+1)*chainParams.numChains; j++)
				{
				for (i=0; i<numUsedMoves; i++)
					{
					theMove = usedMoves[i];
					if (theMove->nBatches[j] < 1)
						MrBayesPrintf (fpMcmc, "\tNA");
					else
						MrBayesPrintf (fpMcmc, "\t%.6f", theMove->lastAcceptanceRate[j]);
                    if (theMove->moveType->Autotune != NULL)
                        MrBayesPrintf (fpMcmc, "\t%.6e", theMove->tuningParam[j][0]);
					}
				}
			}
		else
			{
			j = n*chainParams.numChains;
			for (i=0; i<numUsedMoves; i++)
				{
				theMove = usedMoves[i];
				if (theMove->nBatches[j] < 1)
					MrBayesPrintf (fpMcmc, "\tNA");
				else
					MrBayesPrintf (fpMcmc, "\t%.6f", theMove->lastAcceptanceRate[j]);
                if (theMove->moveType->Autotune != NULL)
                    MrBayesPrintf (fpMcmc, "\t%.6e", theMove->tuningParam[j][0]);
				}
			}
		if (chainParams.numChains > 1)
			{
			for (i=0; i<chainParams.numChains; i++)
				{
				for (j=i+1; j<chainParams.numChains; j++)
					{
					MrBayesPrintf (fpMcmc, "\t%.6f", (MrBFlt) swapInfo[n][i][j] / (MrBFlt) swapInfo[n][j][i]);
					}
				}
			}
		}

	if (chainParams.numRuns > 1)
		{
		for (n=0; n<numTopologies; n++)
			{
			if (chainParams.relativeBurnin == NO && curGen < chainParams.chainBurnIn * chainParams.sampleFreq)
				MrBayesPrintf (fpMcmc, "\tNA");
			else
				{
                if (chainParams.diagnStat == AVGSTDDEV)
    				MrBayesPrintf (fpMcmc, "\t%.6f", chainParams.stat[n].avgStdDev);
                else
    				MrBayesPrintf (fpMcmc, "\t%.6f", chainParams.stat[n].max);
				}
			if (chainParams.allComps == YES)
				{
				for (i=0; i<chainParams.numRuns; i++)
					{
					for (j=i+1; j<chainParams.numRuns; j++)
						{
						if (chainParams.relativeBurnin == NO && curGen < chainParams.chainBurnIn * chainParams.sampleFreq)
							MrBayesPrintf (fpMcmc, "\tNA");
                        else if (chainParams.diagnStat == AVGSTDDEV)
							MrBayesPrintf (fpMcmc, "\t%.6f", chainParams.stat[n].pair[i][j] / chainParams.stat[n].pair[j][i]);
                        else /*if (chainParams.diagnStat == MAXSTDDEV) */
							MrBayesPrintf (fpMcmc, "\t%.6f", chainParams.stat[n].pair[i][j]);
						}
					}
				}
			}
		}

	MrBayesPrintf (fpMcmc, "\n");
	fflush (fpMcmc);

#if defined MPI_ENABLED
    /* Redistribute the move info in the parallel version, so that
       swapping occurs correctly; only necessary on processor 0 */
    RedistributeMoveInfo();
#endif

    return (NO_ERROR);
}





/*-----------------------------------------------------------------------
|
|	PrintMPISlaves: Print strings from MPI slave nodes
|
------------------------------------------------------------------------*/
#if defined (MPI_ENABLED)
int PrintMPISlaves (FILE *fp)
{
    char        *s=NULL;
	int	        i, len, lenS=0, ierror, nErrors, sumErrors, tag;
	MPI_Status	status;

	nErrors = sumErrors = tag = 0;
    if (proc_id==0)
        {
        s = (char *) SafeCalloc (100, sizeof(char));
        if (s!=NULL)
            lenS = 100;
        else
            lenS = 0;
        }

	for (i=1; i<num_procs; i++)
		{
		/* communicate length */
		if (proc_id == 0)
			{
			/* receive size */
			ierror = MPI_Recv (&len, 1, MPI_INT, i, tag, MPI_COMM_WORLD, &status);
			if (ierror != MPI_SUCCESS)
				{
				MrBayesPrint ("%s   Problem receiving string length from proc_id = %d\n", spacer, i);
				nErrors++;
				}
			}
		else if (proc_id == i)
			{
			/* send size */
			len = strlen(printString);
			ierror = MPI_Send (&len, 1, MPI_INT, 0, tag, MPI_COMM_WORLD);
			if (ierror != MPI_SUCCESS)
				{
				printf ("%s   Problem sending string length from proc_id = %d\n", spacer, i);
				nErrors++;
				}
			}
		/* reallocate string s on processor 0 if necessary */
		if (nErrors == 0 && proc_id == 0 && len+5 > strlen(s))
			{
			if ((s = (char *) SafeRealloc ((void *)s, (size_t)((len+5)*sizeof(char)))) == NULL)
				{
				MrBayesPrint ("%s   Problem reallocating %d chars to string 's' on proc 0 in PrintMPISlaves()\n", spacer, len+5);
				nErrors++;
				}
			}
		/* communicate and print string */
		if (nErrors == 0)
			{
			if (proc_id == 0)
				{
				/* receive string */
				ierror = MPI_Recv (s, len+1, MPI_CHAR, i, tag, MPI_COMM_WORLD, &status);
				if (ierror != MPI_SUCCESS)
					{
					MrBayesPrint ("%s   Problem receiving printString from proc_id = %d\n", spacer, i);
					nErrors++;
					}
				/* print string */
				if (nErrors == 0)
                    MrBayesPrintf (fp, "%s", s);
				}
			else if (proc_id == i)
				{
				/* send string */
				ierror = MPI_Send (printString, len+1, MPI_CHAR, 0, tag, MPI_COMM_WORLD);
				if (ierror != MPI_SUCCESS)
					{
					printf ("%s   Problem sending printString from proc_id = %d\n", spacer, i);
					nErrors++;
					}
				}
			}
		if (nErrors > 0)
			break;
		}

    if (proc_id == 0)
        {
        free (s);
        s = NULL;
        }

	MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
	if (sumErrors > 0)
		{
		MrBayesPrint ("%s   Problem with the printing in PrintMPISlaves().\n", spacer);
		return (ERROR);
		}

	return (NO_ERROR);
}
#endif





/*----------------------------------------------------------------------
|
|	PrintParamValues: print parameter values and subvalues for param
|
----------------------------------------------------------------------*/
void PrintParamValues (Param *p, int chain, char *s)

{
	
	int			j;
	MrBFlt		*value0, *value1;
	
	if (p == NULL)
		MrBayesPrint ("%s   %s = NULL\n", spacer, s);
	else
		{
		if (p->nValues > 0)
			{
			value0 = GetParamVals (p, chain, 0);
			value1 = GetParamVals (p, chain, 1);
			for (j=0; j<p->nValues; j++)
				MrBayesPrint ("%s   hyper [%s] = (%lf %lf)\n", spacer, s, value0[j], value1[j]);
			}
		if (p->nSubValues > 0)
			{
			value0 = GetParamSubVals (p, chain, 0);
			value1 = GetParamSubVals (p, chain, 1);
			for (j=0; j<p->nSubValues; j++)
				MrBayesPrint ("%s   %s = (%lf %lf)\n", spacer, s, value0[j], value1[j]);
			}
		}
	MrBayesPrint ("\n\n");

	return;

}





/*----------------------------------------------------------------------
|
|	PrintParsMatrix: Print parsimony (bitset) matrix
|		using hexadecimal representation
|
|
------------------------------------------------------------------------*/
int PrintParsMatrix (void)

{

	int				i, j=0, k, c, d, printWidth, nextColumn, nChars, inputChar;
	SafeLong		x, y;
	char			ch;
	ModelInfo		*m;
	ModelParams		*mp;

	printWidth = 79;

	for (d=0; d<numCurrentDivisions; d++)
		{
		MrBayesPrint ("\nParsimony (bitset) matrix for division %d\n\n", d+1);

		m = &modelSettings[d];
		mp = &modelParams[d];

		nChars = 1 + (int) (log((1 << m->numStates) - 1) / log(16));
	
        for (c=0; c<m->numChars; c++)
			{
			MrBayesPrint ("Parsimony sets for character %d -- \n", (c / m->nParsIntsPerSite));
			for (i=0; i<numTaxa; i++)
				{
				MrBayesPrint ("%-10.10s   ", taxaNames[i]);
                j = c*m->nParsIntsPerSite;
				for (nextColumn=13; nextColumn < printWidth; nextColumn+=nChars + 1)
					{
					if (j >= m->numChars*m->nParsIntsPerSite)
						break;
					x = m->parsSets[i][j];
					for (k=8 - nChars; k<8; k++)
						{
						y = (x >> (4* (7 - k))) & 15;
#ifdef PAUL
						if (y > 16) DEBUG("y is too big %ld\n",y);
#endif
						if (y < 10)
							ch = (char) y + '0';
						else
							ch = (char) y - 10 + 'A';
						MrBayesPrint("%c", ch);
						}
					MrBayesPrint(" ");
                    j++;
					}
				MrBayesPrint ("\n");
				}
			MrBayesPrint("\n");
			printf ("Do you want to stop (y/n)?\n");
			inputChar = getchar();
			if (inputChar == 'y' || inputChar == 'Y')
				return NO_ERROR;
			else
				MrBayesPrint ("\n");
			}
		}	/* next division */

	return NO_ERROR;

}





/*------------------------------------------------------------------
|
|	PrintSiteRates_Gen: general n-state models with rate variation
|
-------------------------------------------------------------------*/

int PrintSiteRates_Gen (TreeNode *p, int division, int chain)

{
	int				c, j, k, nStates, hasPInvar;
	MrBFlt			freq, siteLike, invLike, catLike, pInvar=0.0, *bs,
					*catRate, baseRate;
	MrBFlt			s01, s10, probOn, probOff, *swr, covBF[40];
	CLFlt			*lnScaler, *clP, *siteRates, *clInvar=NULL;
	char			*tempStr;
	int             tempStrSize = TEMPSTRSIZE;
	ModelInfo		*m;
	
	tempStr = (char *) SafeMalloc((size_t) (tempStrSize * sizeof(char)));
	if (!tempStr)
		{
		MrBayesPrint ("%s   Problem allocating tempString (%d)\n", spacer, tempStrSize * sizeof(char));
		return (ERROR);
		}

	/* find model settings and nStates, pInvar, invar cond likes */
	m = &modelSettings[division];
	nStates = m->numModelStates;
	if (m->pInvar == NULL)
		{
		hasPInvar = NO;
		}
	else
		{
		hasPInvar = YES;
		pInvar =  *(GetParamVals (m->pInvar, chain, state[chain]));
		clInvar = m->invCondLikes;
		}

	/* find conditional likelihood pointer */
	clP = m->condLikes[m->condLikeIndex[chain][p->index]];
    
	/* use scratch space for root node for temporary calculations */
    siteRates = m->condLikes[m->condLikeScratchIndex[p->index]];
    
	/* find site scaler */
    lnScaler = m->scalers[m->siteScalerIndex[chain]];
    
	/* find base frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);

	/* if covarion model, adjust base frequencies */
	if (m->switchRates != NULL)
		{
		/* find the stationary frequencies */
		swr = GetParamVals(m->switchRates, chain, state[chain]);
		s01 = swr[0];
		s10 = swr[1];
		probOn = s01 / (s01 + s10);
		probOff = 1.0 - probOn;

		/* now adjust the base frequencies; on-state stored first in cond likes */
		for (j=0; j<nStates/2; j++)
			{
			covBF[j] = bs[j] * probOn;
			covBF[j+nStates/2] = bs[j] * probOff;
			}

		/* finally set bs pointer to adjusted values */
		bs = covBF;
		}

	/* find category frequencies */
	if (hasPInvar == NO)
		freq =  1.0 /  m->numGammaCats;
	else
		freq =  (1.0 - pInvar) /  m->numGammaCats;

	/* get rate multipliers (for gamma & partition specific rates) */
	baseRate =  GetRate (division, chain);
	
	/* compensate for invariable sites */
	if (hasPInvar == YES)
		baseRate /= ( 1.0 - pInvar);
		
	/* get category rates */
	catRate = GetParamSubVals (m->shape, chain, state[chain]);

	/* loop over characters */
	if (hasPInvar == NO)
		{
		/* no invariable category */
		for (c=0; c<m->numChars; c++)
			{
			siteLike = 0.0;
			siteRates[c] = 0.0;
			for (k=0; k<m->numGammaCats; k++)
				{
				catLike = 0.0;
				for (j=0; j<nStates; j++)
					catLike += (*(clP++)) * bs[j];
				siteRates[c] += (CLFlt) (catLike * catRate[k]);
				siteLike += catLike;
				}
			siteRates[c] *= (CLFlt) (baseRate / siteLike);	/* category frequencies and site scaler cancel out */
			}
		}
	else
		{
		/* has invariable category */
		for (c=0; c<m->numChars; c++)
			{
			siteLike = invLike = 0.0;
			siteRates[c] = 0.0;
			for (k=0; k<m->numGammaCats; k++)
				{
				catLike = 0.0;
				for (j=0; j<nStates; j++)
					catLike += (*(clP++)) * bs[j];
				siteRates[c] += (CLFlt) (catLike * catRate[k]);
				siteLike += catLike;
				}
			siteLike *= freq;
			siteRates[c] *= (CLFlt) freq;
			for (j=0; j<nStates; j++)
				invLike += (*(clInvar++)) * bs[j];
			siteLike += (invLike /  exp (lnScaler[c]) * pInvar);
			/* we do not need to add the invariable category into siteRates before rescaling because the rate is 0.0 */
			siteRates[c] *= (CLFlt) (baseRate / siteLike);	/* site scaler cancels out; category frequencies dealt with above */
			}
		}
		
	/* print the resulting site rates cycling over uncompressed chars */
	for (c=0; c<numChar; c++)
		{
		if (charInfo[c].isExcluded == YES || partitionId[c][partitionNum] != division+1)
			continue;
		j = compCharPos[c] - m->compCharStart;
        SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(siteRates[j]));
		if (AddToPrintString (tempStr) == ERROR) return (ERROR);
		}

	free (tempStr);
	return NO_ERROR;
	
}





/*------------------------------------------------------------------
|
|	PrintSiteRates_Std: standard model with rate variation
|
-------------------------------------------------------------------*/

int PrintSiteRates_Std (TreeNode *p, int division, int chain)

{
	int				c, j, k, nStates;
	MrBFlt			siteLike, catLike, *bs, *catRate, baseRate;
	CLFlt			*clP, *siteRates;
	char			*tempStr;
	int             tempStrSize = TEMPSTRSIZE;
	ModelInfo		*m;
	
	tempStr = (char *) SafeMalloc((size_t) (tempStrSize * sizeof(char)));
	if (!tempStr)
		{
		MrBayesPrint ("%s   Problem allocating tempString (%d)\n", spacer, tempStrSize * sizeof(char));
		return (ERROR);
		}

	/* find model settings */
	m = &modelSettings[division];

	/* find conditional likelihood pointer */
    clP = m->condLikes[m->condLikeIndex[chain][p->index]];
	
	/* use scratch space for root node for temporary calculations */
	siteRates = m->condLikes[m->condLikeScratchIndex[p->index]];
	
	/* find base frequencies */
	bs = GetParamSubVals (m->stateFreq, chain, state[chain]);

	/* get rate multiplier */
	baseRate =  GetRate (division, chain);
	
	/* get category rates */
	catRate = GetParamSubVals (m->shape, chain, state[chain]);

	/* loop over characters */
	for (c=0; c<m->numChars; c++)
		{
		siteLike = 0.0;
		siteRates[c] = 0.0;
		nStates = m->nStates[c];
		for (k=0; k<m->numGammaCats; k++)
			{
			catLike = 0.0;
			for (j=0; j<nStates; j++)
				catLike += (*(clP++)) * bs[j];
			siteRates[c] += (CLFlt) (catLike * catRate[k]);
			siteLike += catLike;
			}
		siteRates[c] *= (CLFlt)(baseRate / siteLike);	/* category frequencies and site scaler cancel out */
		}
		
	/* print the resulting site rates cycling over uncompressed chars */
	for (c=0; c<numChar; c++)
		{
		if (charInfo[c].isExcluded == YES || partitionId[c][partitionNum] != division+1)
			continue;
		j = compCharPos[c] - m->compCharStart;
        SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(siteRates[j]));
		if (AddToPrintString (tempStr) == ERROR) return (ERROR);
		}

	free (tempStr);
	return NO_ERROR;

}





int PrintStates (int curGen, int coldId)

{

	int				d, i, j, k, k1, compressedCharPosition, *printedChar=NULL, origAlignmentChars[3];
	char			*partString=NULL, stateString[4];
	MrBFlt			*st, *sst, sum;
	Param			*p;
	ModelInfo		*m;
	Tree			*tree;
	TreeNode		*node;
	ModelParams		*mp;
	char            *tempStr;
	int             tempStrSize;

	/* allocate the print string */
	printStringSize = tempStrSize = TEMPSTRSIZE;
	printString = (char *)SafeMalloc((size_t) (printStringSize * sizeof(char)));
	tempStr = (char *) SafeMalloc((size_t) (tempStrSize * sizeof(char)));

	if (!printString)
		{
		MrBayesPrint ("%s   Problem allocating printString (%d)\n", spacer, printStringSize * sizeof(char));
		goto errorExit;
		}
	if (!tempStr)
		{
		MrBayesPrint ("%s   Problem allocating tempString (%d)\n", spacer, tempStrSize * sizeof(char));
		goto errorExit;
		}
	
	*printString = '\0';
	*tempStr = '\0';

	/* Allocate memory, temporarily, in case we infer positive selection probs, site omegas, or site rates */
	if (inferPosSel == YES || inferSiteOmegas == YES)
		{
		if (memAllocs[ALLOC_POSSELPROBS] == YES)
			{
			MrBayesPrint ("%s   posSelProbs not free in PrintStates\n", spacer);
			goto errorExit;
			}
		posSelProbs = (MrBFlt *)SafeMalloc((size_t) (numCompressedChars * sizeof(MrBFlt)));
		if (!posSelProbs)
			{
			MrBayesPrint ("%s   Problem allocating posSelProbs (%d)\n", spacer, numCompressedChars * sizeof(MrBFlt));
			goto errorExit;
			}
		for (i=0; i<numCompressedChars; i++)
			posSelProbs[i] =  -10.0;
		memAllocs[ALLOC_POSSELPROBS] = YES;
		}
	if (inferPosSel == YES || inferSiteOmegas == YES || inferSiteRates == YES || inferAncStates == YES)
		{
		printedChar = (int *)SafeMalloc((size_t) (numChar * sizeof(int)));
		if (!printedChar)
			{
			MrBayesPrint ("%s   Problem allocating printedChar (%d)\n", spacer, numChar * sizeof(int));
			goto errorExit;
			}
		for (i=0; i<numChar; i++)
			printedChar[i] = NO;
		}

	/* Set up the header to the file. */
	if (curGen == 0)
		{
		SafeSprintf (&tempStr, &tempStrSize, "[ID: %s]\n", stamp);
		if (AddToPrintString (tempStr) == ERROR) goto errorExit;
		SafeSprintf (&tempStr, &tempStrSize, "Gen\t");
		if (AddToPrintString (tempStr) == ERROR) goto errorExit;
		SafeSprintf (&tempStr, &tempStrSize, "LnL");
		if (AddToPrintString (tempStr) == ERROR) goto errorExit;

		/* print tree lengths or heights for all trees */
		for (i=0; i<numParams; i++)
			{
			p = &params[i];

			if (p->paramType == P_BRLENS)
				{
				tree = GetTree (p, coldId, state[coldId]);
				if (tree->isRooted == YES)
					{
					if (FillRelPartsString(p, &partString) == YES)
						SafeSprintf (&tempStr, &tempStrSize, "\tTH%s\tTL%s", partString, partString);
					else
						SafeSprintf (&tempStr, &tempStrSize, "\tTH\tTL");
					}
				else
                    {
                    if (FillRelPartsString(p, &partString) == YES)
					    SafeSprintf (&tempStr, &tempStrSize, "\tTL%s", partString);
				    else
					    SafeSprintf (&tempStr, &tempStrSize, "\tTL");
                    }

				if (AddToPrintString (tempStr) == ERROR) goto errorExit;
				}
			}

		/* print # events for cpp model */
		for (i=0; i<numPrintTreeParams; i++)
			{
			p = printTreeParam[i];
			if (p->paramType == P_BRLENS)
				{
				for (j=0; j<p->nSubParams; j++)
					{
					if (p->subParams[j]->paramType == P_CPPEVENTS)
						{
						if (FillRelPartsString(p->subParams[j], &partString) == YES)
							SafeSprintf (&tempStr, &tempStrSize, "\tn_CPP%s", partString);
						else
							SafeSprintf (&tempStr, &tempStrSize, "\tn_CPP");
						if (AddToPrintString (tempStr) == ERROR) goto errorExit;
						}
					}
				}
			}

		/* print substitution model parameters header */
		for (i=0; i<numPrintParams; i++)
			{
			p = printParam[i];
			SafeSprintf (&tempStr, &tempStrSize, "\t%s", p->paramHeader);
			if (AddToPrintString (tempStr) == ERROR) goto errorExit;
			}
			
		if (inferSiteRates == YES)
			{
			for (i=0; i<numChar; i++)
				printedChar[i] = NO;
	
			for (i=0; i<numChar; i++)
				{ 
				if (charInfo[i].isExcluded == YES)
					continue;
				if (printedChar[i] == YES)
					continue;
				d = partitionId[i][partitionNum] - 1;
				m = &modelSettings[d];
				mp = &modelParams[d];
				if (m->printSiteRates == YES)
					{
					if (m->nCharsPerSite == 1)
						{
						SafeSprintf (&tempStr, &tempStrSize, "\tr(%d)", i+1);
						if (AddToPrintString (tempStr) == ERROR) goto errorExit;
						}
					else
						{
						origAlignmentChars[0] = i;
						k = 1;
						for (j=i+1; j<numChar; j++)
							{
							if (compCharPos[i] == compCharPos[j])
								{
								if (k > m->nCharsPerSite)
									return (ERROR);
								origAlignmentChars[k++] = j;
								printedChar[j] = YES;
								}
							}
						if (k != m->nCharsPerSite)
							return (ERROR);
						SafeSprintf (&tempStr, &tempStrSize, "\tr(%d,", origAlignmentChars[0]);
						if (AddToPrintString (tempStr) == ERROR) goto errorExit;
						for (j=1; j<k-1; j++)
							{
							SafeSprintf (&tempStr, &tempStrSize, "%d,", origAlignmentChars[j]);
							if (AddToPrintString (tempStr) == ERROR) goto errorExit;
							}
						SafeSprintf (&tempStr, &tempStrSize, "%d)", origAlignmentChars[k-1]);
						if (AddToPrintString (tempStr) == ERROR) goto errorExit;
						}
					}
				}
			}

       if (inferPosSel == YES)
            {
			for (i=0; i<numChar; i++)
				printedChar[i] = NO;
            for (d=0; d<numCurrentDivisions; d++)
                {
				m = &modelSettings[d];
				tree = GetTree(m->brlens, coldId, state[coldId]);
				if (m->printPosSel == YES)
					{
					if (PosSelProbs (tree->root->left, d, coldId) == ERROR)
						goto errorExit;
					}
				}
            /*for (i=0; i<numChar; i++)
				printf ("%4d -- %3d %3d\n", i, compCharPos[i], compColPos[i]);*/
			for (i=0; i<numChar; i++)
				{
				compressedCharPosition = compCharPos[i];
				if (posSelProbs[compressedCharPosition] >= 0.0 && printedChar[i] == NO && charInfo[i].isExcluded == NO)
					{
					for (j=k=0; j<numChar; j++)
						{
						if (charInfo[j].charId == charInfo[i].charId)
							{
							origAlignmentChars[k++] = j;
							printedChar[j] = YES;
							}
						}
					SafeSprintf (&tempStr, &tempStrSize, "\tpr+(%d,%d,%d)", origAlignmentChars[0]+1, origAlignmentChars[1]+1, origAlignmentChars[2]+1);
					if (AddToPrintString (tempStr) == ERROR) goto errorExit;
					}
				}	
			for (i=0; i<numChar; i++)
				printedChar[i] = NO;
			}
			
		if (inferSiteOmegas == YES)
			{
			for (i=0; i<numChar; i++)
				printedChar[i] = NO;
			for (d=0; d<numCurrentDivisions; d++)
				{
				m = &modelSettings[d];
				tree = GetTree(m->brlens, coldId, state[coldId]);
				if (m->printSiteOmegas == YES)
					{
					if (SiteOmegas (tree->root->left, d, coldId) == ERROR)
						goto errorExit;
					}
				}
			/*for (i=0; i<numChar; i++)
				printf ("%4d -- %3d %3d\n", i, compCharPos[i], compColPos[i]);*/
			for (i=0; i<numChar; i++)
				{
				compressedCharPosition = compCharPos[i];
				if (posSelProbs[compressedCharPosition] >= 0.0 && printedChar[i] == NO && charInfo[i].isExcluded == NO)
					{
					for (j=k=0; j<numChar; j++)
						{
						if (charInfo[j].charId == charInfo[i].charId)
							{
							origAlignmentChars[k++] = j;
							printedChar[j] = YES;
							}
						}
					SafeSprintf (&tempStr, &tempStrSize, "\tomega(%d,%d,%d)", origAlignmentChars[0]+1, origAlignmentChars[1]+1, origAlignmentChars[2]+1);
					if (AddToPrintString (tempStr) == ERROR) goto errorExit;
					}
				}	
			for (i=0; i<numChar; i++)
				printedChar[i] = NO;
			}
			
		if (inferAncStates == YES)
			{
            for (j=0; j<numChar; j++)
                printedChar[j] = NO;
            for (d=0; d<numCurrentDivisions; d++)
                {
				m = &modelSettings[d];
				mp = &modelParams[d];
                if ( m->printAncStates != YES )
                    continue;
    			for (j=0; j<numChar; j++)
    				{ 
                    if (partitionId[j][partitionNum] - 1 != d ||
                        charInfo[j].isExcluded == YES || printedChar[j] == YES)
    					continue;
					for (i=0; i<numDefinedConstraints; i++)
						{
                        if (mp->activeConstraints[i] == NO || definedConstraintsType[i] != HARD )
                            continue;
						if (mp->dataType == STANDARD)
							{
							for (k=0; k<m->nStates[compCharPos[j] - m->compCharStart]; k++)
								{
								SafeSprintf (&tempStr, &tempStrSize, "\tp(%c){%d@%s}", m->StateCode(k), j+1, constraintNames[i]);
								if (AddToPrintString (tempStr) == ERROR) goto errorExit;
								}
							}
                        else if ((mp->dataType == DNA || mp->dataType == RNA) && !strcmp(mp->nucModel,"Codon"))
                            {
					        origAlignmentChars[0] = j+1;
                            k1 = 1;
                            for (k=j+1; k<numChar; k++)
						        {
						        if (charInfo[k].charId == charInfo[j].charId)
							        {
							        origAlignmentChars[k1++] = k+1;
							        printedChar[k] = YES;
							        }
						        }
							for (k=0; k<m->numStates; k++)
								{
                                State_CODON(stateString, k, d);
								SafeSprintf (&tempStr, &tempStrSize, "\tp(%s){%d,%d,%d@%s}",
                                    stateString,
                                    origAlignmentChars[0],
                                    origAlignmentChars[1],
                                    origAlignmentChars[2],
                                    constraintNames[i]);
								if (AddToPrintString (tempStr) == ERROR) goto errorExit;
								}
							}
                        else if ((mp->dataType == DNA || mp->dataType == RNA) && !strcmp(mp->nucModel,"Doublet"))
                            {
					        origAlignmentChars[0] = j+1;
                            k1 = 1;
                            for (k=j+1; k<numChar; k++)
						        {
						        if (charInfo[k].charId == charInfo[j].charId)
							        {
							        origAlignmentChars[k1++] = k+1;
							        printedChar[k] = YES;
							        }
						        }
							for (k=0; k<m->numStates; k++)
								{
                                State_DOUBLET(stateString, k);
								SafeSprintf (&tempStr, &tempStrSize, "\tp(%s){%d,%d@%s}",
                                    stateString,
                                    origAlignmentChars[0],
                                    origAlignmentChars[1],
                                    constraintNames[i]);
								if (AddToPrintString (tempStr) == ERROR) goto errorExit;
								}
                            }
                        else if ((mp->dataType == DNA || mp->dataType == RNA) && !strcmp(mp->nucModel,"Protein"))
                            {
					        origAlignmentChars[0] = j+1;
                            k1 = 1;
                            for (k=j+1; k<numChar; k++)
						        {
						        if (charInfo[k].charId == charInfo[j].charId)
							        {
							        origAlignmentChars[k1++] = k+1;
							        printedChar[k] = YES;
							        }
						        }
							for (k=0; k<m->numStates; k++)
								{
								SafeSprintf (&tempStr, &tempStrSize, "\tp(%c){%d,%d,%d@%s}",
                                    m->StateCode(k),
                                    origAlignmentChars[0],
                                    origAlignmentChars[1],
                                    origAlignmentChars[2],
                                    constraintNames[i]);
								if (AddToPrintString (tempStr) == ERROR) goto errorExit;
								}
							}
                        else
							{
							for (k=0; k<m->numStates; k++)
								{
								SafeSprintf (&tempStr, &tempStrSize, "\tp(%c){%d@%s}", m->StateCode(k), j+1, constraintNames[i]);
								if (AddToPrintString (tempStr) == ERROR) goto errorExit;
								}
							}
						}
					}
				}
			}
			
		SafeSprintf (&tempStr, &tempStrSize, "\n");
		if (AddToPrintString (tempStr) == ERROR) goto errorExit;
		}
		
	/* now print parameter values */
	SafeSprintf (&tempStr, &tempStrSize, "%d", curGen);
	if (AddToPrintString (tempStr) == ERROR) goto errorExit;
    SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(curLnL[coldId]));
	if (AddToPrintString (tempStr) == ERROR) goto errorExit;

	/* print tree lengths or heights for all trees */
	for (i=0; i<numParams; i++)
		{
		p = &params[i];

		if (p->paramType == P_BRLENS)
			{
			tree = GetTree (p, coldId, state[coldId]);
			if (tree->isClock == NO)
                {
                SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(TreeLength(p, coldId)));
			    if (AddToPrintString (tempStr) == ERROR) goto errorExit;
                }
			else
                {
				SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(tree->root->left->nodeDepth));
			    if (AddToPrintString (tempStr) == ERROR) goto errorExit;
				SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(TreeLength(p, coldId)));
			    if (AddToPrintString (tempStr) == ERROR) goto errorExit;
                }
			}
		}

	/* print # cpp events */
	for (i=0; i<numParams; i++)
		{
		p = &params[i];

		if (p->paramType == P_BRLENS)
			{	
			for (j=0; j<p->nSubParams; j++)
				{
				if (p->subParams[j]->paramType == P_CPPEVENTS)
					{
					SafeSprintf (&tempStr, &tempStrSize, "\t%d", NumCppEvents(p->subParams[j],coldId));
					if (AddToPrintString (tempStr) == ERROR) goto errorExit;
					}
				}
			}
		}

	/* print ordinary parameters */
	for (i=0; i<numPrintParams; i++)
		{
		p = printParam[i];

		/* get model params and settings */
		mp = &modelParams[p->relParts[0]];
        m  = &modelSettings[p->relParts[0]];
		
		st  = GetParamVals (p, coldId, state[coldId]);
		sst = GetParamSubVals (p, coldId, state[coldId]);

		if (p->paramId == SYMPI_EXP_MS || p->paramId == SYMPI_UNI_MS || p->paramId == SYMPI_FIX_MS)
			{
			/* We print symmetric dirichlet alpha value if not fixed and then multistate character state frequencies */
            if (p->paramId != SYMPI_FIX_MS)
                {
                SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(st[0]));
                if (AddToPrintString (tempStr) == ERROR) goto errorExit;
                }
            sst = GetParamStdStateFreqs (p, coldId, state[coldId]);
            if (p->hasBinaryStd == YES)
                sst += 2 * m->numBetaCats;
			for (j=0; j<p->nSympi; j++)
				{
                for (k=0; k<p->sympinStates[j]; k++)
                    {
				    SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(*sst++));
    				if (AddToPrintString (tempStr) == ERROR) goto errorExit;
                    }
				}
			}
		else if (p->paramType == P_PI)
			{
			/* We print the subvalues if we are dealing with state frequencies (state frequencies are held in subvalues). */
			for (j=0; j<p->nSubValues; j++)
				{
				SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(sst[j]));
				if (AddToPrintString (tempStr) == ERROR) goto errorExit;
				}
			}
		else if (p->paramType == P_TRATIO && !strcmp(mp->tratioFormat,"Dirichlet"))
			{
			SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(st[0] / (1.0 + st[0])));
			if (AddToPrintString (tempStr) == ERROR) goto errorExit;
			SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(1.0 / (1.0 + st[0])));
			if (AddToPrintString (tempStr) == ERROR) goto errorExit;
			}
		else if (p->paramType == P_REVMAT)
            {
            if (!strcmp(mp->revmatFormat,"Ratio"))
			    {
			    sum = st[p->nValues-1];
			    for (j=0; j<p->nValues; j++)
				    {
				    SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(st[j] / sum));
				    if (AddToPrintString (tempStr) == ERROR) goto errorExit;
				    }
			    }
            else
                {
                /* we already have rate proportions */
			    for (j=0; j<p->nValues; j++)
				    {
				    SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(st[j]));
				    if (AddToPrintString (tempStr) == ERROR) goto errorExit;
				    }
                }
            if (p->paramId == REVMAT_MIX)
                {
                /* add model index and k for nst=mixed */
			    SafeSprintf (&tempStr, &tempStrSize, "\t%d", FromGrowthFxnToIndex(GetParamIntVals(p, coldId, state[coldId])));
			    if (AddToPrintString (tempStr) == ERROR) goto errorExit;
			    SafeSprintf (&tempStr, &tempStrSize, "\t%d", GetKFromGrowthFxn(GetParamIntVals(p, coldId, state[coldId])));
			    if (AddToPrintString (tempStr) == ERROR) goto errorExit;
                }
            }
		else if (p->paramType == P_RATEMULT)
			{
			if (!strcmp(mp->ratemultFormat,"Ratio"))
				{
				for (j=0; j<p->nValues; j++)
					{
					SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(sst[j + p->nValues]));
					if (AddToPrintString (tempStr) == ERROR) goto errorExit;
					}
				}
			else if (!strcmp(mp->ratemultFormat, "Dirichlet"))
				{
				sum = 0.0;
				for (j=0; j<p->nValues; j++)
					sum += sst[j + p->nValues];
				for (j=0; j<p->nValues; j++)
					{
					SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(sst[j + p->nValues] / sum));
					if (AddToPrintString (tempStr) == ERROR) goto errorExit;
					}
				}
			else
				{
				for (j=0; j<p->nValues; j++)
					{
					SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(st[j]));
					if (AddToPrintString (tempStr) == ERROR) goto errorExit;
					}
				}
			}
		else if (p->paramType == P_AAMODEL)
			{
			for (j=0; j<p->nValues; j++)
				{
				SafeSprintf (&tempStr, &tempStrSize, "\t%d", (int)st[j]);
				if (AddToPrintString (tempStr) == ERROR) goto errorExit;
				}
			}
		else
			{
            /* run of the mill parameter */
			for (j=0; j<p->nValues; j++)
				{
				SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(st[j]));
				if (AddToPrintString (tempStr) == ERROR) goto errorExit;
				}
			}

        if (p->paramType == P_OMEGA && p->paramId != OMEGA_DIR && p->paramId != OMEGA_FIX && p->paramId != OMEGA_FFF && p->paramId != OMEGA_FF && p->paramId != OMEGA_10FFF)
			{
			/* OK, we also need to print subvalues for the category frequencies in a NY98-like model. */
			if (!strcmp(mp->omegaVar, "M10"))
				{
				for (j=0; j<4; j++)
					{
					SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(sst[mp->numM10BetaCats + mp->numM10GammaCats + 4 + j]));
					if (AddToPrintString (tempStr) == ERROR) goto errorExit;
					}
				for (j=0; j<2; j++)
					{
					SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(sst[mp->numM10BetaCats + mp->numM10GammaCats + j]));
					if (AddToPrintString (tempStr) == ERROR) goto errorExit;
					}
				}
			else
				{
				for (j=0; j<3; j++)
					{
					SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(sst[j]));
					if (AddToPrintString (tempStr) == ERROR) goto errorExit;
					}
				}
			}
		}
		
    /* if user wants site rates, we print those here */
	if (inferSiteRates == YES)
		{
		for (d=0; d<numCurrentDivisions; d++)
			{
			m = &modelSettings[d];
			if (m->printSiteRates == YES)
				{
				mp = &modelParams[d];
				tree = GetTree (m->brlens, coldId, state[coldId]);
				node = tree->root->left;
				m->PrintSiteRates (node, d, coldId);
				}
			}
		}			

    /* If the user wants to infer sites that are under positive selection, then we need to print out the posterior
	   probability that each site is a positively selected one here. */
	if (inferPosSel == YES)
		{
		/* loop over the divisions, calculating the probability of being in the positively
		   selected class for each relevant partition */
		for (d=0; d<numCurrentDivisions; d++)
			{
			m = &modelSettings[d];
			tree = GetTree(m->brlens, coldId, state[coldId]);
			if (m->Likelihood == &Likelihood_NY98)
				{
				if (PosSelProbs (tree->root->left, d, coldId) == ERROR)
					{
					goto errorExit;
					}
				}
			}

		/* print the probabilities for the appropriate sites in the original alignment */
		for (i=0; i<numChar; i++)
			printedChar[i] = NO;
		for (i=0; i<numChar; i++)
			{
			compressedCharPosition = compCharPos[i];
			if (posSelProbs[compressedCharPosition] >= 0.0 && printedChar[i] == NO && charInfo[i].isExcluded == NO)
				{
				for (j=k=0; j<numChar; j++)
					{
					if (charInfo[j].charId == charInfo[i].charId)
						{
						origAlignmentChars[k++] = j;
						printedChar[j] = YES;
						}
					}
				SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(posSelProbs[compressedCharPosition]));
				if (AddToPrintString (tempStr) == ERROR) goto errorExit;
				/*printf ("%4d -> (%3d,%3d,%3d) %1.25le\n", i, origAlignmentChars[0]+1, origAlignmentChars[1]+1, origAlignmentChars[2]+1, posSelProbs[compressedCharPosition]);*/
				}
			}
		}
	 
	/* If the user wants omega values for each site, we print those here. */
	if (inferSiteOmegas == YES)
		{
		/* loop over the divisions, calculating the omega value for each site */
		for (d=0; d<numCurrentDivisions; d++)
			{
			m = &modelSettings[d];
			tree = GetTree(m->brlens, coldId, state[coldId]);
			if (m->Likelihood == &Likelihood_NY98)
				{
				if (SiteOmegas (tree->root->left, d, coldId) == ERROR)
					{
					goto errorExit;
					}
				}
			}


		/* print the site omegas for the appropriate sites in the original alignment */
        /* note that we use posSelProbs to pass values between SiteOmegas and this function */
		for (i=0; i<numChar; i++)
			printedChar[i] = NO;
		for (i=0; i<numChar; i++)
			{
			compressedCharPosition = compCharPos[i];
			if (posSelProbs[compressedCharPosition] >= 0.0 && printedChar[i] == NO && charInfo[i].isExcluded == NO)
				{
				for (j=k=0; j<numChar; j++)
					{
					if (charInfo[j].charId == charInfo[i].charId)
						{
						origAlignmentChars[k++] = j;
						printedChar[j] = YES;
						}
					}
				SafeSprintf (&tempStr, &tempStrSize, "\t%s", MbPrintNum(posSelProbs[compressedCharPosition]));
				if (AddToPrintString (tempStr) == ERROR) goto errorExit;
				/*printf ("%4d -> (%3d,%3d,%3d) %1.25le\n", i, origAlignmentChars[0]+1, origAlignmentChars[1]+1, origAlignmentChars[2]+1, posSelProbs[compressedCharPosition]);*/
				}
			}
		}
	 
	/* free memory for positive selection probs or site omegas */
	if (inferPosSel == YES || inferSiteOmegas == YES)
        {
        if (memAllocs[ALLOC_POSSELPROBS] == YES)
		    free (posSelProbs);
	    memAllocs[ALLOC_POSSELPROBS] = NO;
	    free (printedChar);
        }

	/* if user wants ancestral states for constrained nodes, we obtain and print those here */
	if (inferAncStates == YES)
		{
		for (d=0; d<numCurrentDivisions; d++)
			{
			m = &modelSettings[d];
			if (m->printAncStates == YES)
				{
				mp = &modelParams[d];
				tree = GetTree (m->brlens, coldId, state[coldId]);
				for (i=j=tree->nIntNodes - 1; i>=0; i--)
					{
					node = tree->intDownPass[i];
					m->CondLikeUp (node, d, coldId);
					}
                for (k=0; k<numDefinedConstraints; k++)
					{
                    if (mp->activeConstraints[k] == NO || definedConstraintsType[k] != HARD )
                        continue;
                    for (i=tree->nIntNodes-1; i>=0; i--)
						{
						node = tree->intDownPass[i];
						if (node->isLocked == YES && k == node->lockID)
							m->PrintAncStates (node, d, coldId);
						}
					}
				}
			}
		}			

	SafeSprintf (&tempStr, &tempStrSize, "\n");
	if (AddToPrintString (tempStr) == ERROR) goto errorExit;
	
	free (tempStr);
    SafeFree ((void **)&partString);
	
	return (NO_ERROR);
	
	errorExit:
		if (printedChar)
			free (printedChar);
		if (memAllocs[ALLOC_POSSELPROBS] == YES)
			free (posSelProbs);
		memAllocs[ALLOC_POSSELPROBS] = NO;
        free (tempStr);
        SafeFree ((void **)&partString);
		return (ERROR);
	
}





/*----------------------------------------------------------------------
|
|   PrintStatesToFiles: Print trees and model parameters to files. We
|      only come into this function if it is the first cycle of the chain
|      or if we hit a cycle number evenly divisible by the sample frequency,
|      or this is the last cycle of the chain.
|
------------------------------------------------------------------------*/
int PrintStatesToFiles (int curGen)

{

	int				i, j, chn, coldId, runId;
    MrBFlt          clockRate;
	Tree			*tree=NULL;
	Param			*param;
#	if defined (MPI_ENABLED)
	int				id, x, doesThisProcHaveId, procWithChain, ierror, tag, nErrors, sumErrors;
	MPI_Status 		status;
#	endif

#	if !defined (MPI_ENABLED)

	/* print parameter values and trees (single-processor version) */
	for (chn=0; chn<numLocalChains; chn++)
		{
		if ((chainId[chn] % chainParams.numChains) == 0)
			{
			coldId = chn;
			runId = chainId[chn] / chainParams.numChains;

			/* print parameter values */
			if (PrintStates (curGen, coldId) == ERROR)
				return (ERROR);
			fprintf (fpParm[runId], "%s", printString);
			fflush (fpParm[runId]);
			free(printString);

			/* print trees */
			for (i=0; i<numPrintTreeParams; i++)
				{
				param = printTreeParam[i];
                tree = GetTree(param, coldId, state[coldId]);
				if (param->paramType == P_TOPOLOGY)
					{
					if (PrintTree (curGen, param, coldId, NO, 0.0) == ERROR)
						return (ERROR);
					}
				else
					{
                    if (tree->isClock == YES)
                        clockRate = *GetParamVals(modelSettings[tree->relParts[0]].clockRate, coldId, state[coldId]);
                    else
                        clockRate = 0.0;
                    if (PrintTree (curGen, param, coldId, YES, clockRate) == ERROR)
                        return (ERROR);
					}

				MrBayesPrintf (fpTree[runId][i], "%s", printString);
				fflush (fpTree[runId][i]);
				free(printString);

				if (chainParams.mcmcDiagn == YES && chainParams.numRuns > 1)
					{
					if (chainParams.relativeBurnin == YES || curGen >= chainParams.chainBurnIn * chainParams.sampleFreq)
						{
						j = printTreeTopologyIndex[i];
						if (j<numTopologies)
							{
							if (AddTreeToPartitionCounters (tree, i, runId) == ERROR)
								return ERROR;
							if (chainParams.relativeBurnin == YES && chainParams.saveTrees == YES && (noWarn == NO || curGen <= chainParams.stopTreeGen))
								{
								ResetTopologyFromTree (chainParams.dtree, tree);
								if (AddToTreeList (&chainParams.treeList[numTopologies*runId+j], chainParams.dtree) == ERROR)
									return (ERROR);
								}
							}
						}
					}
				}
			}
		}
#	else
	/* print parameter values and trees (parallel version) */
	
	/* Wait for all of the processors to get to this point before starting the printing. */
	ierror = MPI_Barrier (MPI_COMM_WORLD);
	if (ierror != MPI_SUCCESS)
		{
		MrBayesPrint ("%s   Problem at chain barrier.\n", spacer);
		return ERROR;
		}
	tag = nErrors = 0;
		
	/* Loop over runs. */
	for (runId=0; runId<chainParams.numRuns; runId++)
		{
		/* Get the ID of the chain we want to print. Remember, the ID's should be numbered
		   0, 1, 2, ..., numChains X numRuns. Chains numbered 0, numChains, 2 X numChains, ...
		   are cold. */
		id = runId * chainParams.numChains;
		
		/* Does this processor have the chain? */
		doesThisProcHaveId = NO;
		coldId = 0;
		for (chn=0; chn<numLocalChains; chn++)
			{
			if (chainId[chn] == id)
				{
				doesThisProcHaveId = YES;
				coldId = chn;
				break;
				}
			}
		
		/* Tell all the processors which has the chain we want to print. We do this using the MPI_AllReduce
		   function. If the processor does not have the chain, then it initializes x = 0. If it does
		   have the chain, then x = proc_id. When the value of x is summed over all the processors, the sum
		   should be the proc_id of the processor with the chain. Possible values are 0, 1, 2, num_procs-1. 
		   Note that every processor knows procWithChain because we are using MPI_Allreduce, instead of MPI_Reduce. */
		x = 0;
		if (doesThisProcHaveId == YES)
			x = proc_id;
		ierror = MPI_Allreduce (&x, &procWithChain, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
		if (ierror != MPI_SUCCESS)
			{
			MrBayesPrint ("%s   Problem finding processor with chain to print.\n", spacer);
			return (ERROR);
			}

		/* ****************************************************************************************************/
		/* print parameter values *****************************************************************************/
		
		/* Fill printString with the contents to be printed on proc_id = 0. Note
		   that printString is allocated in the function. */
		if (doesThisProcHaveId == YES)
			{
			if (PrintStates (curGen, coldId) == ERROR)
				nErrors++;
			}
		MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
		if (sumErrors > 0)
			{
			MrBayesPrint ("%s   Problem with PrintStates.\n", spacer);
			return ERROR;
			}
		
		/* First communication: Send/receive the length of the printString. */
		if (proc_id == 0 || proc_id == procWithChain)
			{
			if (procWithChain != 0)
				{
				if (proc_id == procWithChain)
					{
					/* Find out how large the string is, and send the information to proc_id = 0. */
					ierror = MPI_Send (&printStringSize, 1, MPI_LONG, 0, tag, MPI_COMM_WORLD);
					if (ierror != MPI_SUCCESS)
						nErrors++;
					}
				else
					{
					/* Receive the length of the string from proc_id = procWithChain, and then allocate
					   printString to be that length. */
					ierror = MPI_Recv (&printStringSize, 1, MPI_LONG, procWithChain, tag, MPI_COMM_WORLD, &status);
					if (ierror != MPI_SUCCESS)
						{
						MrBayesPrint ("%s   Problem receiving printStringSize from proc_id = %d\n", spacer, procWithChain);
						nErrors++;
						}
					printString = (char *)SafeMalloc((size_t) (printStringSize * sizeof(char)));
					if (!printString)
						{
						MrBayesPrint ("%s   Problem allocating printString (%d)\n", spacer, printStringSize * sizeof(char));
						nErrors++;
						}
					strcpy (printString, "");
					}
				}
			}
		MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
		if (sumErrors > 0)
			{
			MrBayesPrint ("%s   Problem with first communication (states).\n", spacer);
			return ERROR;
			}

		/* Second communication: Send/receive the printString. */
		if (proc_id == 0 || proc_id == procWithChain)
			{
			if (procWithChain != 0)
				{					
				if (proc_id == procWithChain)
					{
					/* Send the printString to proc_id = 0. After we send the string to proc_id = 0, we can
					   free it. */
					ierror = MPI_Send (&printString[0], printStringSize, MPI_CHAR, 0, tag, MPI_COMM_WORLD);
					if (ierror != MPI_SUCCESS)
						nErrors++;
					free(printString);
					}
				else
					{
					/* Receive the printString from proc_id = procWithChain. */
					ierror = MPI_Recv (&printString[0], printStringSize, MPI_CHAR, procWithChain, tag, MPI_COMM_WORLD, &status);
					if (ierror != MPI_SUCCESS)
						{
						MrBayesPrint ("%s   Problem receiving printString from proc_id = %d\n", spacer, procWithChain);
						nErrors++;
						}
					}
				}
			}
		MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
		if (sumErrors > 0)
			{
			MrBayesPrint ("%s   Problem with second communication (states).\n", spacer);
			return ERROR;
			}

		/* Print the string with the parameter information if we are proc_id = 0. */
		if (proc_id == 0)
			{
			fprintf (fpParm[runId], "%s", printString);
			fflush (fpParm[runId]);
			free(printString);
			}


		/* ****************************************************************************************************/
		/* print trees ****************************************************************************************/

    	for (i=0; i<numPrintTreeParams; i++)
			{
			/* Print trees to file. */

			/* Fill printString with the contents to be printed on proc_id = 0. Note
			   that printString is allocated in the function. */
			if (doesThisProcHaveId == YES)
				{
                param = printTreeParam[i];
                tree = GetTree(param, coldId, state[coldId]);
                if (param->paramType == P_TOPOLOGY)
					{
					if (tree->isClock == YES)
                        clockRate = *GetParamVals(modelSettings[tree->relParts[0]].clockRate, coldId, state[coldId]);
                    else
                        clockRate = 0.0;
			        if (PrintTree (curGen, param, coldId, NO, clockRate) == ERROR)
				        nErrors++;
					}
				else
					{
					if (tree->isClock == YES)
                        clockRate = *GetParamVals(modelSettings[tree->relParts[0]].clockRate, coldId, state[coldId]);
                    else
                        clockRate = 0.0;
					if (PrintTree (curGen, param, coldId, YES, clockRate) == ERROR)
						nErrors++;
					}
				}
			MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
			if (sumErrors > 0)
				{
				MrBayesPrint ("%s   Problem with printing trees.\n", spacer);
				return ERROR;
				}
				
			/* First communication: Send/receive the length of the printString. */
			if (proc_id == 0 || proc_id == procWithChain)
				{
				if (procWithChain != 0)
					{
					if (proc_id == procWithChain)
						{
						/* Find out how large the string is, and send the information to proc_id = 0. */
						ierror = MPI_Send (&printStringSize, 1, MPI_LONG, 0, tag, MPI_COMM_WORLD);
						if (ierror != MPI_SUCCESS)
							nErrors++;
						}
					else
						{
						/* Receive the length of the string from proc_id = procWithChain, and then allocate
						   printString to be that length. */
						ierror = MPI_Recv (&printStringSize, 1, MPI_LONG, procWithChain, tag, MPI_COMM_WORLD, &status);
						if (ierror != MPI_SUCCESS)
							{
							MrBayesPrint ("%s   Problem receiving printStringSize from proc_id = %d\n", spacer, procWithChain);
							nErrors++;
							}
						printString = (char *)SafeMalloc((size_t) (printStringSize * sizeof(char)));
						if (!printString)
							{
							MrBayesPrint ("%s   Problem allocating printString (%d)\n", spacer, printStringSize * sizeof(char));
							nErrors++;
							}
						strcpy (printString, "");
						}
					}
				}
			MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
			if (sumErrors > 0)
				{
				MrBayesPrint ("%s   Problem with first communication (states).\n", spacer);
				return ERROR;
				}

			/* Second communication: Send/receive the printString. */
			if (proc_id == 0 || proc_id == procWithChain)
				{
				if (procWithChain != 0)
					{					
					if (proc_id == procWithChain)
						{
						/* Send the printString to proc_id = 0. After we send the string to proc_id = 0, we can
						   free it. */
						ierror = MPI_Send (&printString[0], printStringSize, MPI_CHAR, 0, tag, MPI_COMM_WORLD);
						if (ierror != MPI_SUCCESS)
							nErrors++;
						free(printString);
						}
					else
						{
						/* Receive the printString from proc_id = procWithChain. */
						ierror = MPI_Recv (&printString[0], printStringSize, MPI_CHAR, procWithChain, tag, MPI_COMM_WORLD, &status);
						if (ierror != MPI_SUCCESS)
							{
							MrBayesPrint ("%s   Problem receiving printString from proc_id = %d\n", spacer, procWithChain);
							nErrors++;
							}
						}
					}
				}
			MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
			if (sumErrors > 0)
				{
				MrBayesPrint ("%s   Problem with second communication (states).\n", spacer);
				return ERROR;
				}

			/* Print the string with the parameter information if we are proc_id = 0. */
			if (proc_id == 0)
				{
				fprintf (fpTree[runId][i], "%s", printString);
				fflush (fpTree[runId][i]);
				j = printTreeTopologyIndex[i];
				if (j < numTopologies)
					{
                    char *s = NULL;
					StripComments (printString);
					/* if it is the first tree, we strip out the translate block first (twice)*/
					if (curGen==0) {
					  if (strtok (printString, ";")==NULL) /* get translate lock */
                                              return (ERROR);
					  if (strtok (NULL, ";")==NULL) 
                                              return (ERROR);
                                          if(strtok (NULL, "\n\t\r ")==NULL) /* get 'tree' */
                                              return (ERROR);
                                        } else {
                                            if(strtok (printString, "\n\t\r ")==NULL) /* get 'tree' */
                                                return (ERROR);
                                        }
					if(strtok (NULL, " =")==NULL)  /* get 'rep.xxxx' */
                        return (ERROR);
					if((s = strtok (NULL, " =;"))==NULL)  /* get Newick string */ 
                        return (ERROR);
                	if (chainParams.numRuns > 1 && chainParams.mcmcDiagn == YES)
                        {
                        ResetTopology (chainParams.dtree, s);
					    AddTreeToPartitionCounters (chainParams.dtree, j, runId);
					    if (chainParams.relativeBurnin == YES && chainParams.saveTrees == YES && (noWarn == NO || curGen <= chainParams.stopTreeGen))
							{
							if (AddToTreeList (&chainParams.treeList[runId*numTopologies+j], chainParams.dtree) == ERROR)
								return (ERROR);
							}
						}
					}
				free(printString);
				}
			}

		/* Have all of the chains wait here, until the string has been successfully printed on proc_id = 0. */
		ierror = MPI_Barrier (MPI_COMM_WORLD);
		if (ierror != MPI_SUCCESS)
			{
			MrBayesPrint ("%s   Problem at chain barrier.\n", spacer);
			return ERROR;
			}
		}
#	endif
		
	return (NO_ERROR);
	
}




int PrintSwapInfo (void)

{

	int			i, j, n, maxNumExchanges, len, maxLen, reweightingChars=0;
	char		*tempStr;
	int             tempStrSize;

	if (chainParams.numChains == 1)
		return NO_ERROR;

#	if defined (MPI_ENABLED)
	if (ReassembleSwapInfo() == ERROR)
		return ERROR;
	if (proc_id != 0)
		return NO_ERROR;
#	endif


	tempStrSize = TEMPSTRSIZE;
	tempStr = (char *) SafeMalloc((size_t) (tempStrSize * sizeof(char)));
	if (!tempStr)
		{
		MrBayesPrint ("%s   Problem allocating tempString (%d)\n", spacer, tempStrSize * sizeof(char));
		return (ERROR);
		}

	for (n=0; n<chainParams.numRuns; n++)
		{
		maxNumExchanges = 0;
		for (i=0; i<chainParams.numChains; i++)
			for (j=0; j<chainParams.numChains; j++)
				if (i > j && swapInfo[n][i][j] > maxNumExchanges)
					maxNumExchanges = swapInfo[n][i][j];
		SafeSprintf(&tempStr, &tempStrSize, "%d", maxNumExchanges);
		maxLen = (int) strlen(tempStr);
		if (maxLen < 4)
			maxLen = 4;
			
		reweightingChars = NO;
		if ((chainParams.weightScheme[0] + chainParams.weightScheme[1]) > 0.00001)
			reweightingChars = YES;

		if (chainParams.numRuns == 1)
			MrBayesPrint ("\n%s   Chain swap information:\n\n", spacer);
		else
			MrBayesPrint ("\n%s   Chain swap information for run %d:\n\n", spacer, n+1);

		MrBayesPrint ("%s          ", spacer);
		for (j=0; j<chainParams.numChains; j++)
			{
			SafeSprintf(&tempStr, &tempStrSize, "%d", j+1);
			len = (int) strlen(tempStr);
			MrBayesPrint ("%*c %d ", maxLen-len, ' ', j+1);
			}
		MrBayesPrint ("\n");
		
		MrBayesPrint ("%s        --", spacer);
		for (j=0; j<chainParams.numChains; j++)
			{
			MrBayesPrint ("--");
			for (i=0; i<maxLen; i++)
				MrBayesPrint ("-");
			}
		MrBayesPrint ("\n");
		
		for (i=0; i<chainParams.numChains; i++)
			{
			MrBayesPrint ("%s   %4d | ", spacer, i+1);
			for (j=0; j<chainParams.numChains; j++)
				{
				if (i < j)
					{
					if (swapInfo[n][j][i] <= 0)
						{
						MrBayesPrint ("%*c%s ", maxLen-3, ' ', " NA ");
						}
					else
						{
						SafeSprintf(&tempStr, &tempStrSize, "%1.2lf", (MrBFlt)swapInfo[n][i][j]/swapInfo[n][j][i]);
						len = (int) strlen(tempStr);
						MrBayesPrint ("%*c%1.2lf ", maxLen-len+1, ' ', (MrBFlt)swapInfo[n][i][j]/swapInfo[n][j][i]);
						}
					}
				else if (i == j)
					{
					MrBayesPrint ("%*c ", maxLen+1, ' ');
					}
				else
					{
					SafeSprintf(&tempStr, &tempStrSize, "%d", swapInfo[n][i][j]);
					len = (int) strlen(tempStr);
					MrBayesPrint ("%*c%d ", maxLen-len+1, ' ', swapInfo[n][i][j]);
					}
				}
			MrBayesPrint ("\n");
			}
		}

	MrBayesPrint ("\n%s   Upper diagonal: Proportion of successful state exchanges between chains\n", spacer);
	MrBayesPrint ("%s   Lower diagonal: Number of attempted state exchanges between chains\n", spacer);
		
	MrBayesPrint ("\n%s   Chain information:\n\n", spacer);
	MrBayesPrint ("%s     ID -- Heat ", spacer);
	if (reweightingChars == YES)
		MrBayesPrint ("%% Dn %% Up\n");
	else
		MrBayesPrint ("\n");
	
	MrBayesPrint ("%s    -----------", spacer);
	if (reweightingChars == YES)
		MrBayesPrint ("----------\n");
	else
		MrBayesPrint ("\n");
	for (i=0; i<chainParams.numChains; i++)
		{
		MrBayesPrint ("%s   %4d -- %1.2lf ", spacer, i+1, Temperature (i)/*1.0 / (1.0 + chainParams.chainTemp * i)*/);
		if (reweightingChars == YES)
			{
			if (i == 0)
				{
				MrBayesPrint ("  0%%   0%% (cold chain)\n");
				}
			else
				{
				SafeSprintf(&tempStr, &tempStrSize, "%d", (int)chainParams.weightScheme[0]);
				len = (int) strlen(tempStr);
				MrBayesPrint ("%*c%d%% ", 3-len, ' ', (int)chainParams.weightScheme[0]);
				SafeSprintf(&tempStr, &tempStrSize, "%d", (int)chainParams.weightScheme[1]);
				len = (int) strlen(tempStr);
				MrBayesPrint ("%*c%d%% \n", 3-len, ' ', (int)chainParams.weightScheme[1]);
				}
			}
		else
			{
			if (i == 0)
				MrBayesPrint (" (cold chain)\n");
			else
				MrBayesPrint ("\n");
			}
		}
	if (chainParams.userDefinedTemps == NO)
		{
		MrBayesPrint ("\n%s   Heat = 1 / (1 + T * (ID - 1))\n", spacer);
		MrBayesPrint ("%s      (where T = %1.2lf is the temperature and ID is the chain number)\n", spacer, chainParams.chainTemp);
		}
	if (reweightingChars == YES)
		MrBayesPrint ("%s   Reweighting increment = %1.2lf\n", spacer, chainParams.weightScheme[2]);
    MrBayesPrint ("\n");
		
	free (tempStr);
	return (NO_ERROR);
		
}




/*----------------------------------------------------------------------
|
|	PrintTermState: Print terminal state index matrix
|
------------------------------------------------------------------------*/
int PrintTermState (void)

{

	int				i, j=0, c, d, printWidth, nextColumn, nDigits, nReps;
	ModelInfo		*m;
	ModelParams		*mp;

	printWidth = 79;

	for (d=0; d<numCurrentDivisions; d++)
		{
		MrBayesPrint ("\nTerminal state index matrix for division %d\n\n", d+1);

		m = &modelSettings[d];
		mp = &modelParams[d];

		if (!strcmp(mp->covarionModel, "Yes"))
			nReps = 2;
		else
			nReps = 1;

		nDigits = 1 + (int)(log10(mp->nStates * mp->nStates * nReps));
	
		for (c=m->compCharStart; c<m->compCharStop; c=j)
			{
			for (i=0; i<numTaxa; i++)
				{
				MrBayesPrint ("%-10.10s   ", taxaNames[i]);
				j = c;
				for (nextColumn=13; nextColumn < printWidth; nextColumn+=nDigits + 1)
					{
					if (j >= m->compCharStop)
						break;
					MrBayesPrint ("%*d ",nDigits, m->termState[i][j-c]);
                    j++;
					}
				MrBayesPrint ("\n");
				}
			MrBayesPrint("\n");
			}
		}	/* next division */

	return NO_ERROR;

}





/*--------------------------------------------------
|
|	PrintTiProbs: This function is for debugging of
|		tiProbs; it will print a square matrix of
|		tiProbs, check row sums, and check for time
|		reversibility
|
---------------------------------------------------*/
void PrintTiProbs (CLFlt *tP, MrBFlt *bs, int nStates)

{
	int		i, j;
	CLFlt   *tiP, sum;

	tiP = tP;

	printf ("\nTransition matrix\n");
	for (i=0; i<nStates; i++)
		{
		printf ("\t%d", i);
		}
	printf ("\tsum\n");

	for (i=0; i<nStates; i++)
		{
		printf ("%d\t", i);
		sum = 0.0;
		for (j=0; j<nStates; j++)
			{
			printf ("\t%.6f",tP[j]);
			sum += tP[j];
			}
		printf ("\t%.6f\n",sum);
		tP += nStates;
		}

	printf ("\nStationary state frequencies\n");
    for (i=0; i<nStates; i++)
        printf("%d -- %f\n",i,bs[i]);
    
    printf ("\nTime reversibility\n");

	printf ("State 1\tState 2\tforward\tbackward\tabs diff\n");
	for (i=0; i<nStates; i++)
		{
		for (j=i+1; j<nStates; j++)
			{
			printf ("%d\t%d\t%.6f\t%.6f\t%.6f\n", i, j, tiP[i*nStates+j]*bs[i],
				tiP[j*nStates+i]*bs[j], fabs(tiP[i*nStates+j]*bs[i] - tiP[j*nStates+i]*bs[j]));
			}
		}

	getchar();
	return;
}





int PrintTopConvInfo (void)

{

	int			i, j, n, len, maxLen;
	char		*tempStr;
	int         tempStrSize;
	MrBFlt		maxNumPartitions;
	STATS		*stat;

	if (chainParams.numRuns == 1)
		return NO_ERROR;

#	if defined (MPI_ENABLED)
	if (proc_id != 0)
		return (NO_ERROR);
#	endif

	tempStrSize = TEMPSTRSIZE;
	tempStr = (char *) SafeMalloc((size_t) (tempStrSize * sizeof(char)));
	if (!tempStr)
		{
		MrBayesPrint ("%s   Problem allocating tempString (%d)\n", spacer, tempStrSize * sizeof(char));
		return (ERROR);
		}

	for (n=0; n<numTopologies; n++)
		{
		stat = &chainParams.stat[n];
		maxNumPartitions = 0.0;
		for (i=0; i<chainParams.numRuns; i++)
			for (j=0; j<chainParams.numRuns; j++)
				if (i > j && stat->pair[i][j] > maxNumPartitions)
					maxNumPartitions = stat->pair[i][j];
		SafeSprintf(&tempStr, &tempStrSize, "%d", (int) maxNumPartitions);
		maxLen = (int) strlen(tempStr);
		if (maxLen < 5)
			maxLen = 5;
		
		if (numTopologies == 1)
			{
			if (chainParams.diagnStat == AVGSTDDEV)
				MrBayesPrint ("%s   Pairwise average standard deviation of split frequencies (upper diagonal)\n", spacer);
			else
				MrBayesPrint ("%s   Pairwise maximum standard deviation of split frequencies (upper diagonal)\n", spacer);
			MrBayesPrint ("%s      and number of qualifying splits for each comparison (lower diagonal):\n\n", spacer);
			}
		else
			{
			if (chainParams.diagnStat == AVGSTDDEV)
				MrBayesPrint ("%s   Pairwise average standard deviation of split frequencies in topology %d (upper diagonal)\n", spacer, n);
			else
				MrBayesPrint ("%s   Pairwise maximum standard deviation of split frequencies in topology %d (upper diagonal)\n", spacer, n);
			MrBayesPrint ("%s      and number of qualifying splits for each comparison (lower diagonal):\n\n", spacer);
			}

		MrBayesPrint ("%s          ", spacer);
		for (j=0; j<chainParams.numRuns; j++)
			{
			SafeSprintf(&tempStr, &tempStrSize, "%d", j+1);
			len = (int) strlen(tempStr);
			MrBayesPrint ("%*c %d ", maxLen-len, ' ', j+1);
			}
		MrBayesPrint ("\n");
	
		MrBayesPrint ("%s        --", spacer);
		for (j=0; j<chainParams.numRuns; j++)
			{
			MrBayesPrint ("--");
			for (i=0; i<maxLen; i++)
				MrBayesPrint ("-");
			}
		MrBayesPrint ("\n");
	
		for (i=0; i<chainParams.numRuns; i++)
			{
			MrBayesPrint ("%s   %4d | ", spacer, i+1);
			for (j=0; j<chainParams.numRuns; j++)
				{
				if (i < j)
					{
                    if (chainParams.diagnStat == AVGSTDDEV)
					    SafeSprintf(&tempStr, &tempStrSize, "%1.3lf", stat->pair[i][j]/stat->pair[j][i]);
                    else /* if (chainParams.diagnStat == MAXSTDDEV) */
					    SafeSprintf(&tempStr, &tempStrSize, "%1.3lf", stat->pair[i][j]);
			        len = (int) strlen(tempStr);
			        MrBayesPrint ("%*c%1.3lf ", maxLen-len+1, ' ', tempStr);
					}
				else if (i == j)
					{
					MrBayesPrint ("%*c ", maxLen+1, ' ');
					}
				else
					{
					SafeSprintf(&tempStr, &tempStrSize, "%d", (int) stat->pair[i][j]);
					len = (int) strlen(tempStr);
					MrBayesPrint ("%*c%d ", maxLen-len+1, ' ', (int) stat->pair[i][j]);
					}
				}
			MrBayesPrint ("\n");
			}
	
		MrBayesPrint ("\n");
		}

	free (tempStr);
	return (NO_ERROR);
}


void PrintToScreen (int curGen, int startGen, time_t endingT, time_t startingT)
{

	int			i, chn, nHours, nMins, nSecs;
	MrBFlt		timePerGen;

#	if defined (MPI_ENABLED)
	int			numLocalColdChains, numFirstAndLastCold;
	
	if (curGen == 0)
		{
        if (chainParams.isSS == NO && chainParams.mcmcDiagn == YES && chainParams.numRuns > 1)
            {
            MrBayesPrint ("\n");
            if (chainParams.relativeBurnin == YES)
                MrBayesPrint ("%s   Using a relative burnin of %.1f %% for diagnostics\n", spacer, 100.0*chainParams.burninFraction);
            else
                MrBayesPrint ("%s   Using an absolute burnin of %d samples for diagnostics\n", spacer, chainParams.chainBurnIn);
            }
		MrBayesPrint ("\n");
		MrBayesPrint ("%s   Chain results (%d generations requested):\n\n", spacer, chainParams.numGen);
		}
	MrBayesPrint ("%s   %4d -- ", spacer, curGen);
	numLocalColdChains = numFirstAndLastCold = 0;
	for (chn=0; chn<numLocalChains; chn++)
		{
		if ((chainId[chn] % chainParams.numChains) == 0)
			{
			numLocalColdChains++;
			if (chn == 0 || chn == numLocalChains - 1)
				numFirstAndLastCold++;
			}
		}

	i = 1;
	for (chn=0; chn<numLocalChains; chn++)
		{
		if (i > chainParams.printMax)	
			{
			if (i == chainParams.printMax +1)
				{
				i++;
				if (numLocalColdChains > 0 && numLocalColdChains > numFirstAndLastCold)
					MrBayesPrint ("[...%d more local chains...] ", numLocalChains - chainParams.printMax);
				else
					MrBayesPrint ("(...%d more local chains...) ", numLocalChains - chainParams.printMax);
				continue;
				}
			else
				continue;
			}
		if ((chainId[chn] % chainParams.numChains) == 0)
			{
			i++;
			if (chainParams.printAll == YES)
				MrBayesPrint ("[%1.3lf] ", curLnL[chn]);
			else
				MrBayesPrint ("[%1.3lf] .. ", curLnL[chn]);
			}
		else if (chainParams.printAll == YES)
			{
			i++;
			MrBayesPrint ("(%1.3lf) ", curLnL[chn]);
			}
		if (chn < numLocalChains - 1 && (chainId[chn] / chainParams.numChains != chainId[chn+1] / chainParams.numChains))
			MrBayesPrint ("* ");
		}
		
	if (numLocalColdChains == chainParams.numRuns)
		MrBayesPrint ("(...%d remote chains...) ", (chainParams.numChains*chainParams.numRuns) - numLocalChains);
	else
		MrBayesPrint ("[...%d remote chains...] ", (chainParams.numChains*chainParams.numRuns) - numLocalChains);

	if (curGen > 0)
		{
		timePerGen = (MrBFlt) ((MrBFlt)(endingT-startingT)/(MrBFlt)(curGen-startGen));
		nSecs = (int)((chainParams.numGen - curGen) * timePerGen);
		nHours = nSecs / 3600;
		nSecs  = nSecs % 3600;
		nMins  = nSecs / 60; 
		nSecs  = nSecs % 60;
		MrBayesPrint ("-- %d:%0.2d:%0.2d", nHours, nMins, nSecs);
		}
	MrBayesPrint ("\n");
	fflush (stdout);
	
#	else

	if (curGen == 0)
		{
        if (chainParams.isSS == NO && chainParams.mcmcDiagn == YES && chainParams.numRuns > 1)
            {
            MrBayesPrint ("\n");
            if (chainParams.relativeBurnin == YES)
                MrBayesPrint ("%s   Using a relative burnin of %.1f %% for diagnostics\n", spacer, 100.0*chainParams.burninFraction);
            else
                MrBayesPrint ("%s   Using an absolute burnin of %d samples for diagnostics\n", spacer, chainParams.chainBurnIn);
            }
		MrBayesPrint ("\n");
		MrBayesPrint ("%s   Chain results (%d generations requested):\n\n", spacer, chainParams.numGen);
		}
	MrBayesPrint ("%s   %5d -- ", spacer, curGen);
	if (numLocalChains == 1)
		MrBayesPrint ("%1.3lf ", curLnL[0]);
	else
		{
		i = 0;
		for (chn=0; chn<numLocalChains; chn++)
			{
			if (i >= chainParams.printMax)
				{
				if (i == chainParams.printMax)
					MrBayesPrint (".. ");
				i++;
				continue;
				}
			if (chainParams.numChains == 1)
				{
				MrBayesPrint ("%1.3lf ", curLnL[chn]);
				i++;
				}
			else if (chainId[chn] % chainParams.numChains == 0)
				{
				if (chainParams.printAll == YES)
					MrBayesPrint ("[%1.3lf] ", curLnL[chn]);
				else
					MrBayesPrint ("[%1.3lf][%d] .. ", curLnL[chn], chn % chainParams.numChains + 1);
				i++;
				}
			else if (chainParams.printAll == YES)
				{
				MrBayesPrint ("(%1.3lf) ", curLnL[chn]);
				i++;
				}
			if (chn < numLocalChains - 1 && (chainId[chn] / chainParams.numChains != chainId[chn+1] / chainParams.numChains)
				&& i < chainParams.printMax - 1)
				MrBayesPrint ("* ");
			}
		}
		
	if (curGen > 0)
		{
		timePerGen = (MrBFlt) ((MrBFlt)(endingT-startingT)/(MrBFlt)(curGen-startGen));
		nSecs = (int)((chainParams.numGen - curGen) * timePerGen);
		nHours = nSecs / 3600;
		nSecs  = nSecs % 3600;
		nMins  = nSecs / 60; 
		nSecs  = nSecs % 60;
		MrBayesPrint ("-- %d:%0.2d:%0.2d", nHours, nMins, nSecs);
		}
	MrBayesPrint ("\n");
	
	fflush (stdout);
	
#	endif
		
}





int PrintTree (int curGen, Param *treeParam, int chain, int showBrlens, MrBFlt clockRate)

{

	int				i, tempStrSize;
	char			*tempStr;
    Tree            *tree;
	TreeNode		*p=NULL, *q;
    Param           *subParm;

	/* allocate the print string */
	printStringSize = 200;
	printString = (char *)SafeMalloc((size_t) (printStringSize * sizeof(char)));
	if (!printString)
		{
		MrBayesPrint ("%s   Problem allocating printString (%d)\n", spacer, printStringSize * sizeof(char));
		return (ERROR);
		}
	*printString = '\0';

	tempStrSize = TEMPSTRSIZE;
	tempStr = (char *) SafeMalloc((size_t) (tempStrSize * sizeof(char)));
	if (!tempStr)
		{
		MrBayesPrint ("%s   Problem allocating tempString (%d)\n", spacer, tempStrSize * sizeof(char));
		return (ERROR);
		}

    /* get tree */
    tree = GetTree(treeParam, chain, state[chain]);

    /* order the taxa */
	if (chainParams.orderTaxa == YES)
		{
		for (i=0; i<tree->nNodes-1; i++)
			{
			p = tree->allDownPass[i];
			if (p->left == NULL)
				{
				if (p->index == localOutGroup)
					p->x = -1;
				else
					p->x = p->index;
				}
			else if (p->left->x < p->right->x)
				p->x = p->left->x;
			else
				p->x = p->right->x;
			}
		for (i=0; i<tree->nIntNodes; i++)
			{
			if (p->left->x > p->right->x)
				{
				q = p->left;
				p->left = p->right;
				p->right = q;
				}
			}
		}
	
	/* print the translate block information and the top of the file */
	if (curGen == 0)
		{
		/* print #NEXUS and translation block information */
		SafeSprintf (&tempStr, &tempStrSize, "#NEXUS\n");
		if (AddToPrintString (tempStr) == ERROR) return(ERROR);
		SafeSprintf (&tempStr, &tempStrSize, "[ID: %s]\n", stamp);
		if (AddToPrintString (tempStr) == ERROR) return(ERROR);
		SafeSprintf (&tempStr, &tempStrSize, "[Param: tree");
		if (AddToPrintString (tempStr) == ERROR) return(ERROR);
		if (numCurrentDivisions == 1)
			{
			SafeSprintf (&tempStr, &tempStrSize, "]\n");
			if (AddToPrintString (tempStr) == ERROR) return(ERROR);
			}
		else if (numCurrentDivisions == tree->nRelParts)
			{
			SafeSprintf (&tempStr, &tempStrSize, "{all}]\n");
			if (AddToPrintString (tempStr) == ERROR) return(ERROR);
			}
		else
			{
			SafeSprintf (&tempStr, &tempStrSize, "{%d", tree->relParts[0]+1);
			if (AddToPrintString (tempStr) == ERROR) return(ERROR);
			for (i=1; i<tree->nRelParts; i++)
				{
				SafeSprintf (&tempStr, &tempStrSize, ",%d", tree->relParts[i]+1);
				if (AddToPrintString (tempStr) == ERROR) return(ERROR);
				}
			SafeSprintf (&tempStr, &tempStrSize, "}]\n");
			if (AddToPrintString (tempStr) == ERROR) return(ERROR);
			}
		SafeSprintf (&tempStr, &tempStrSize, "begin trees;\n");
		if (AddToPrintString (tempStr) == ERROR) return(ERROR);
		SafeSprintf (&tempStr, &tempStrSize, "   translate\n");
		if (AddToPrintString (tempStr) == ERROR) return(ERROR);
		if (treeParam->paramType == P_SPECIESTREE)
            {
            for (i=0; i<numSpecies; i++)
			    {
			    if (i != numSpecies - 1)
                    SafeSprintf (&tempStr, &tempStrSize, "      %2d %s,\n", i+1, speciesNameSets[speciespartitionNum].names[i]);
                else
		            SafeSprintf (&tempStr, &tempStrSize, "      %2d %s;\n", i+1, speciesNameSets[speciespartitionNum].names[i]);
                if (AddToPrintString (tempStr) == ERROR) return(ERROR);
			    }
            }
        else
            {
            for (i=0; i<numLocalTaxa; i++)
			    {
			    if (i != numLocalTaxa - 1)
                    SafeSprintf (&tempStr, &tempStrSize, "      %2d %s,\n", i+1, localTaxonNames[i]);
                else
		            SafeSprintf (&tempStr, &tempStrSize, "      %2d %s;\n", i+1, localTaxonNames[i]);
                if (AddToPrintString (tempStr) == ERROR) return(ERROR);
			    }
            }
		}
	
    /* write the tree preamble */
    if (SafeSprintf (&tempStr, &tempStrSize, "   tree gen.%d", curGen) == ERROR) return (ERROR);
    if (AddToPrintString (tempStr) == ERROR) return(ERROR);
    if (treeParam->paramType == P_BRLENS && treeParam->nSubParams > 0)
        {
        for (i=0; i<treeParam->nSubParams; i++)
            {
            subParm = treeParam->subParams[i];
            if (subParm->paramType == P_CPPEVENTS)
                {
                if (SafeSprintf (&tempStr, &tempStrSize, "[&E %s]", subParm->name) == ERROR) return (ERROR);
                if (AddToPrintString (tempStr) == ERROR) return(ERROR);
                }
            if (SafeSprintf (&tempStr, &tempStrSize, "[&B %s]", subParm->name) == ERROR) return (ERROR);
            if (AddToPrintString (tempStr) == ERROR) return(ERROR);
            }
        }
    subParm = modelSettings[treeParam->relParts[0]].popSize;
    if (treeParam->paramType == P_SPECIESTREE && subParm->nValues > 1)
        {
        if (SafeSprintf (&tempStr, &tempStrSize, "[&N %s]", subParm->name) == ERROR) return (ERROR);
        if (AddToPrintString (tempStr) == ERROR) return(ERROR);
        }

 	/* write the tree in (extended) Newick format */
    if (tree->isRooted == YES && tree->isCalibrated == NO)
    	SafeSprintf (&tempStr, &tempStrSize, " = [&R] ");
    else if (tree->isRooted == YES && tree->isCalibrated == YES)
        SafeSprintf (&tempStr, &tempStrSize, " = [&R] [&clockrate=%s] ", MbPrintNum(clockRate));
    else /* if (tree->isRooted == NO) */
    	SafeSprintf (&tempStr, &tempStrSize, " = [&U] ");
    if (AddToPrintString (tempStr) == ERROR) return(ERROR);
   	WriteTreeToPrintString (treeParam, chain, tree->root->left, showBrlens, tree->isRooted);
   	SafeSprintf (&tempStr, &tempStrSize, ";\n");
	if (AddToPrintString (tempStr) == ERROR) return(ERROR);

	free (tempStr); 
   	return (NO_ERROR);

}





/* Generalized normal move for real random variables */
int Move_RealNormal (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)
{
	int             i;
    MrBFlt			oldX, newX, tuning, minX, maxX, u, z;

	/* get tuning parameter */
	tuning = mvp[0];

	/* get minimum and maximum values for X */
    minX = param->min;
    maxX = param->max;

	/* get old value of X */
	newX = oldX = *GetParamVals(param, chain, state[chain]);

	/* change value */
	u = RandomNumber(seed);
    z = PointNormal(u);
	newX = oldX + z * tuning;
	
	/* check that new value is valid */
    if (newX < minX || newX > maxX)
		{
		abortMove = YES;
        return (NO_ERROR);
        }

	/* get proposal ratio */
	(*lnProposalRatio) = 0.0;
	
	/* get prior ratio */
	(*lnPriorRatio) = param->LnPriorRatio(newX, oldX, param->priorParams);

    /* copy new value back */
	*GetParamVals(param, chain, state[chain]) = newX;

	/* Set update flags for tree nodes if relevant */
	if (param->affectsLikelihood == YES)
        {
        for (i=0; i<param->nRelParts; i++)
		    TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
        }

	return (NO_ERROR);
}





/* Generalized slider move for real random variables */
int Move_RealSlider (Param *param, int chain, SafeLong *seed, MrBFlt *lnPriorRatio, MrBFlt *lnProposalRatio, MrBFlt *mvp)
{
	int				i, isValid;
	MrBFlt			oldX, newX, window, minX, maxX, u;

	/* get size of window, centered on current value */
	window = mvp[0];

	/* get minimum and maximum values for X */
    minX = param->min;
    maxX = param->max;

	/* get old value of X */
	newX = oldX = *GetParamVals(param, chain, state[chain]);

	/* change value */
	u = RandomNumber(seed);
	newX = oldX + window * (u - 0.5);
	
	/* check that new value is valid */
	isValid = NO;
	do
		{
		if (newX < minX)
			newX = 2* minX - newX;
		else if (newX > maxX)
			newX = 2 * maxX - newX;
		else
			isValid = YES;
		} while (isValid == NO);

	/* get proposal ratio */
	(*lnProposalRatio) = 0.0;
	
	/* get prior ratio */
	(*lnPriorRatio) = param->LnPriorRatio(newX, oldX, param->priorParams);

    /* copy new value back */
	*GetParamVals(param, chain, state[chain]) = newX;

	/* Set update flags for tree nodes if relevant */
	if (param->affectsLikelihood == YES)
        {
        for (i=0; i<param->nRelParts; i++)
		    TouchAllTreeNodes(&modelSettings[param->relParts[i]],chain);
        }

	return (NO_ERROR);
}





#if defined (MPI_ENABLED)
int ReassembleMoveInfo (void)
{
	int             i, n, ierror;
    double          x[7], sum[7];
	MCMCMove        *mv;

	for (n=0; n<numGlobalChains; n++)
        {
    	for (i=0; i<numUsedMoves; i++)
	        {
	        mv = usedMoves[i];

            /* collect counts */
            x[0] = mv->nAccepted[n];
            x[1] = mv->nTried[n];
            x[2] = mv->nBatches[n];
            x[3] = mv->nTotAccepted[n];
            x[4] = mv->nTotTried[n];
            x[5] = mv->lastAcceptanceRate[n];
            if (mv->moveType->Autotune != NULL)
                x[6]=mv->tuningParam[n][0];
	    	

            ierror = MPI_Allreduce (&x, &sum, 7, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
	        if (ierror != MPI_SUCCESS)
		        return (ERROR);

            if (proc_id == 0)
                {
                mv->nAccepted[n]          = (int)sum[0];
                mv->nTried[n]             = (int)sum[1];
                mv->nBatches[n]           = (int)sum[2];
                mv->nTotAccepted[n]       = (int)sum[3];
                mv->nTotTried[n]          = (int)sum[4];
                mv->lastAcceptanceRate[n] = (MrBFlt)sum[5];
                if (mv->moveType->Autotune != NULL)
                    mv->tuningParam[n][0]=(MrBFlt)sum[6];
                }
            }
        }

    return (NO_ERROR);
}





int ReassembleParamVals (int *curId)
{
    int             i, j, k, orderLen, nBrlens, lower, upper, numChainsForProc, proc, ierror, *y, *order, *id, *nEvents;
    MrBFlt          *x, *brlens, **position, **rateMult;
    MPI_Status      status;
    MPI_Request     request;
    Tree            *tree;
    Param           *p;

    extern MrBFlt   *paramValues;
    extern int      paramValsRowSize;
    extern int      intValsRowSize;

    for (i=0; i<numLocalChains; i++)
        curId[i] = chainId[i];

    numChainsForProc = numGlobalChains / num_procs;
	if (numGlobalChains % num_procs > 0)
		lower = upper = numChainsForProc+1;
	else
		lower = upper = numChainsForProc;

    for (proc=1; proc<num_procs; proc++, lower=upper)
		{
		if (proc < numGlobalChains % num_procs)
			upper += numChainsForProc+1;
		else
			upper += numChainsForProc;
        
        /* chain ids */
        if (proc_id == 0)
            {
	    id = curId + lower;
            ierror = MPI_Irecv (id, upper-lower, MPI_INT, proc, 0, MPI_COMM_WORLD, &request);
			if (ierror != MPI_SUCCESS)
				{
				return (ERROR);
				}
			ierror = MPI_Waitall (1, &request, &status);
			if (ierror != MPI_SUCCESS)
				{
				return (ERROR);
				}
            }
        else if (proc_id == proc)
            {
			id = curId;
            ierror = MPI_Isend (id, upper-lower, MPI_INT, 0, 0, MPI_COMM_WORLD, &request);
			if (ierror != MPI_SUCCESS)
				{
				return (ERROR);
				}
			ierror = MPI_Waitall (1, &request, &status);
			if (ierror != MPI_SUCCESS)
				{
				return (ERROR);
				}
            }
        
        /* chain states */
        if (proc_id == 0)
            {
            ierror = MPI_Irecv (state+lower, upper-lower, MPI_CHAR, proc, 0, MPI_COMM_WORLD, &request);
			if (ierror != MPI_SUCCESS)
				{
				return (ERROR);
				}
			ierror = MPI_Waitall (1, &request, &status);
			if (ierror != MPI_SUCCESS)
				{
				return (ERROR);
				}
            }
        else if (proc_id == proc)
            {
            ierror = MPI_Isend (state, upper-lower, MPI_CHAR, 0, 0, MPI_COMM_WORLD, &request);
			if (ierror != MPI_SUCCESS)
				{
				return (ERROR);
				}
			ierror = MPI_Waitall (1, &request, &status);
			if (ierror != MPI_SUCCESS)
				{
				return (ERROR);
				}
            }

        /* normal parameter values */
        if (proc_id == 0)
            {
            x = paramValues + 2*paramValsRowSize*lower;
            ierror = MPI_Irecv (x, paramValsRowSize*2*(upper-lower), MPI_DOUBLE, proc, 0, MPI_COMM_WORLD, &request);
            if (ierror != MPI_SUCCESS)
                {
                return (ERROR);
                }
            ierror = MPI_Waitall (1, &request, &status);
            if (ierror != MPI_SUCCESS)
				{
				return (ERROR);
				}
            if (intValsRowSize > 0)
                {
                y = intValues + 2*intValsRowSize*lower;
                ierror = MPI_Irecv (y, intValsRowSize*2*(upper-lower), MPI_INT, proc, 0, MPI_COMM_WORLD, &request);
                if (ierror != MPI_SUCCESS)
                    {
                    return (ERROR);
                    }
                ierror = MPI_Waitall (1, &request, &status);
                if (ierror != MPI_SUCCESS)
				    {
				    return (ERROR);
				    }
                }
            }
        else if (proc_id == proc)
            {
			x = paramValues;
            ierror = MPI_Isend (x, paramValsRowSize*2*(upper-lower), MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request);
			if (ierror != MPI_SUCCESS)
				{
				return (ERROR);
				}
			ierror = MPI_Waitall (1, &request, &status);
			if (ierror != MPI_SUCCESS)
				{
				return (ERROR);
				}
    		if (intValsRowSize > 0)
                {
                y = intValues;
                ierror = MPI_Isend (y, intValsRowSize*2*(upper-lower), MPI_INT, 0, 0, MPI_COMM_WORLD, &request);
			    if (ierror != MPI_SUCCESS)
				    {
				    return (ERROR);
				    }
			    ierror = MPI_Waitall (1, &request, &status);
			    if (ierror != MPI_SUCCESS)
				    {
				    return (ERROR);
				    }
                }
            }

        /* std state frequencies */
        if (stdStateFreqsRowSize > 0)
            {
            if (proc_id == 0)
                {
                x = stdStateFreqs + 2*stdStateFreqsRowSize*lower;
                ierror = MPI_Irecv (x, stdStateFreqsRowSize*2*(upper-lower), MPI_DOUBLE, proc, 0, MPI_COMM_WORLD, &request);
                if (ierror != MPI_SUCCESS)
                    {
                    return (ERROR);
                    }
                ierror = MPI_Waitall (1, &request, &status);
                if (ierror != MPI_SUCCESS)
			        {
			        return (ERROR);
			        }
                }
            else if (proc_id == proc)
                {
		        x = stdStateFreqs;
                ierror = MPI_Isend (x, stdStateFreqsRowSize*2*(upper-lower), MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request);
		        if (ierror != MPI_SUCCESS)
			        {
			        return (ERROR);
			        }
		        ierror = MPI_Waitall (1, &request, &status);
		        if (ierror != MPI_SUCCESS)
			        {
			        return (ERROR);
			        }
                }
            }
        
        /* mcmc trees */
        brlens = (MrBFlt *) SafeCalloc (2*numLocalTaxa, sizeof(MrBFlt));
        order  = (int *)    SafeCalloc (2*numLocalTaxa,   sizeof(int));
        for (i=lower; i<upper; i++)
            {
            for (j=0; j<numTrees; j++)
                {
                tree = GetTreeFromIndex(j,0,0);
                orderLen = 2*tree->nIntNodes - 1;
                nBrlens = tree->nNodes - 1;
                if (proc_id == 0)
                    {
		            tree = GetTreeFromIndex(j,i,state[i]);
			        ierror = MPI_Irecv (order, orderLen, MPI_INT, proc, 0, MPI_COMM_WORLD, &request);
			        if (ierror != MPI_SUCCESS)
				        {
				        return (ERROR);
				        }
			        ierror = MPI_Waitall (1, &request, &status);
			        if (ierror != MPI_SUCCESS)
				        {
				        return (ERROR);
				        }
                    ierror = MPI_Irecv (brlens, nBrlens, MPI_DOUBLE, proc, 0, MPI_COMM_WORLD, &request);
			        if (ierror != MPI_SUCCESS)
				        {
				        return (ERROR);
				        }
			        ierror = MPI_Waitall (1, &request, &status);
			        if (ierror != MPI_SUCCESS)
				        {
				        return (ERROR);
				        }
			        if (tree->isRooted == YES)
                        RetrieveRTreeWithIndices(tree, order, brlens);
                    else
                        {
                        RetrieveUTree(tree, order, brlens);
                        if (localOutGroup!=0)
                            MoveCalculationRoot(tree,localOutGroup);
                        }
                    /* since we only transferred some info, there are additional things we need to
                       consider, like constraints and calibrations; tree names are OK on proc 0 */
                    InitializeTreeCalibrations(tree);
                    CheckSetConstraints(tree);
                    SetDatedNodeAges(modelSettings[tree->relParts[0]].brlens, i, state[i]);
                    }
                else if (proc_id == proc)
                    {
        		    tree = GetTreeFromIndex(j,i-lower,state[i-lower]);
			        if (tree->isRooted == YES)
                        StoreRTreeWithIndices(tree, order, brlens);
                    else
                        StoreUTree(tree, order, brlens);
                    ierror = MPI_Isend (order, orderLen, MPI_INT, 0, 0, MPI_COMM_WORLD, &request);
			        if (ierror != MPI_SUCCESS)
				        {
				        return (ERROR);
				        }
			        ierror = MPI_Waitall (1, &request, &status);
			        if (ierror != MPI_SUCCESS)
				        {
				        return (ERROR);
				        }
                    ierror = MPI_Isend (brlens, nBrlens, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request);
			        if (ierror != MPI_SUCCESS)
				        {
				        return (ERROR);
				        }
			        ierror = MPI_Waitall (1, &request, &status);
			        if (ierror != MPI_SUCCESS)
				        {
				        return (ERROR);
				        }
                    }
                }
            }
        free (brlens);
        free (order);

        /* CPP event parameters */
        for(i=lower; i<upper; i++)
            {
            for (j=0; j<numParams; j++)
                {
                p = &params[j];
                if (p->paramType == P_CPPEVENTS)
                    {
                    if (proc_id == proc)
                        {
                        /* get pointers */
                        nEvents = p->nEvents[2*(i-lower)+state[i-lower]];
                        position = p->position[2*(i-lower)+state[i-lower]];
                        rateMult = p->rateMult[2*(i-lower)+state[i-lower]];

                        /* send number of events */
                        ierror = MPI_Isend (nEvents, 2*numLocalTaxa, MPI_INT, 0, 0, MPI_COMM_WORLD, &request);
                        if (ierror != MPI_SUCCESS)
                            return (ERROR);
                        ierror = MPI_Waitall (1, &request, &status);
                        if (ierror != MPI_SUCCESS)
                            return (ERROR);

                        /* send events and clear pointers */
                        for (k=0; k<2*numLocalTaxa; k++)
                            {
                            if (nEvents[k] > 0)
                                {
                                ierror = MPI_Isend (position[k], nEvents[k], MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);
                                ierror = MPI_Waitall (1, &request, &status);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);

                                ierror = MPI_Isend (rateMult[k], nEvents[k], MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);
                                ierror = MPI_Waitall (1, &request, &status);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);

                                free(position[k]);
                                free(rateMult[k]);
                                position[k] = NULL;
                                rateMult[k] = NULL;
                                nEvents[k] = 0;
                                }
                            }
                        }
                    else if (proc_id == 0)
                        {
                        /* find pointers */
                        nEvents = p->nEvents[2*i];
                        position = p->position[2*i];
                        rateMult = p->rateMult[2*i];

                        /* clear previous events */
                        for (k=0; k<2*numLocalTaxa; k++)
                            {
                            if (nEvents[k] > 0)
                                {
                                free (position[k]);
                                free (rateMult[k]);
                                position[k] = NULL;
                                rateMult[k] = NULL;
                                nEvents[k] = 0;
                                }
                            }

                        /* receive events */
                        ierror = MPI_Irecv (nEvents, 2*numLocalTaxa, MPI_INT, proc, 0, MPI_COMM_WORLD, &request);
                        if (ierror != MPI_SUCCESS)
                            return (ERROR);
                        ierror = MPI_Waitall (1, &request, &status);
                        if (ierror != MPI_SUCCESS)
                            return (ERROR);

                        for (k=0; k<2*numLocalTaxa; k++)
                            {
                            if (nEvents[k] > 0)
                                {
                                position[k] = (MrBFlt *) SafeCalloc (nEvents[k], sizeof(MrBFlt));
                                rateMult[k] = (MrBFlt *) SafeCalloc (nEvents[k], sizeof(MrBFlt));

                                ierror = MPI_Irecv (position[k], nEvents[k], MPI_DOUBLE, proc, 0, MPI_COMM_WORLD, &request);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);
                                ierror = MPI_Waitall (1, &request, &status);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);

                                ierror = MPI_Irecv (rateMult[k], nEvents[k], MPI_DOUBLE, proc, 0, MPI_COMM_WORLD, &request);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);
                                ierror = MPI_Waitall (1, &request, &status);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);
                                }
                            }
                        }
                    }
                }
            } 
        }

    return (NO_ERROR);
}





int ReassembleSwapInfo (void)
{
	int	i, j, n, x, sum, ierror;
	
	for (n=0; n<chainParams.numRuns; n++)
		{
		for (i=0; i<chainParams.numChains; i++)
			{
			for (j=0; j<chainParams.numChains; j++)
				{
				if (i != j)
					{
					if (proc_id == 0)
						x = 0;
					else
						x = swapInfo[n][i][j];
					ierror = MPI_Allreduce (&x, &sum, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
					if (ierror != MPI_SUCCESS)
						return (ERROR);
					if (proc_id == 0)
						swapInfo[n][i][j] += sum;
					else
						swapInfo[n][i][j] = 0;
					}
				}
			}
		}

	return (NO_ERROR);
}





int ReassembleTuningParams (void)
{
    int        i, j, k, lower, ierror;
    MrBFlt     *x, *sum;
    
    x = (MrBFlt *) SafeCalloc (2*numUsedMoves, sizeof(MrBFlt));
    sum = x + numUsedMoves;

    lower = numGlobalChains / num_procs;
    if (numGlobalChains % num_procs != 0)
        lower++;

    for (i=lower; i<numGlobalChains; i++)
        {
        for (j=0; j<numLocalChains; j++)
            {
            if (chainId[j] == i)
                break;
            }

        for (k=0; k<numUsedMoves; k++)
            {
            if (j != numLocalChains && usedMoves[k]->moveType->numTuningParams > 0) /* we have the tuning parameter of interest */
                x[k] = usedMoves[k]->tuningParam[i][0];
            else
                x[k] = 0.0;
            }

        ierror = MPI_Allreduce (x, sum, numUsedMoves, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
		if (ierror != MPI_SUCCESS)
            {
            free (x);
            return (ERROR);
            }

        if (proc_id == 0)
            {
            for (k=0; k<numUsedMoves; k++)
				{
				if (usedMoves[k]->moveType->numTuningParams > 0)
                	usedMoves[k]->tuningParam[i][0] = sum[k];
            	}
			}
        }

    free (x);
	return (NO_ERROR);
}





void RedistributeMoveInfo (void)

{
    int         i, j, k;
    MCMCMove    *mv;

    /* Leave if not processor 0, because then we already have the necessary info since
       it was not deleted in ReassembleMoveInfo */
    if (proc_id != 0)
        return;

    /* If we are processor 0, simply delete the unnecessary information */
    for (i=0; i<numGlobalChains; i++)
        {
        for (j=0; j<numLocalChains; j++)
            if (chainId[j] == i)
                break;
        
        if (j == numLocalChains)
            {
            /* we do not have this chain, so delete the move info */
            for (k=0; k<numUsedMoves; k++)
                {
                mv = usedMoves[k];

                /* reset counts */
                mv->nAccepted[i] = 0;
                mv->nTried[i] = 0;
                mv->nBatches[i] = 0;
                mv->nTotAccepted[i] = 0;
                mv->nTotTried[i] = 0;
                mv->lastAcceptanceRate[i] = 0;
		if (mv->moveType->Autotune != NULL)
                    mv->tuningParam[i][0]=0.0;            
                }
            }
        }
}





int RedistributeParamVals (void)
{
    int             i, j, k, orderLen, nBrlens, lower, upper, numChainsForProc, proc, ierror, *y, *order, *nEvents;
    MrBFlt          *x, *brlens, **position, **rateMult;
    MPI_Status      status;
    MPI_Request     request;
    Tree            *tree;
    Param           *p;

    extern MrBFlt   *paramValues;
    extern int      paramValsRowSize;
    extern int      intValsRowSize;

    numChainsForProc = numGlobalChains / num_procs;
    if (numGlobalChains % num_procs > 0)
        lower = upper = numChainsForProc+1;
    else
        lower = upper = numChainsForProc;

    for (proc=1; proc<num_procs; proc++, lower=upper)
        {
        if (proc < numGlobalChains % num_procs)
            upper += numChainsForProc+1;
        else
            upper += numChainsForProc;
        
        /* normal parameter values */
        if (proc_id == 0)
            {
            x = paramValues + 2*paramValsRowSize*lower;
            ierror = MPI_Isend (x, paramValsRowSize*2*(upper-lower), MPI_DOUBLE, proc, 0, MPI_COMM_WORLD, &request);
            if (ierror != MPI_SUCCESS)
                {
                return (ERROR);
                }
            ierror = MPI_Waitall (1, &request, &status);
            if (ierror != MPI_SUCCESS)
                {
                return (ERROR);
                }
            if (intValsRowSize > 0)
                {
                y = intValues + 2*intValsRowSize*lower;
                ierror = MPI_Isend (y, intValsRowSize*2*(upper-lower), MPI_INT, proc, 0, MPI_COMM_WORLD, &request);
                if (ierror != MPI_SUCCESS)
                    {
                    return (ERROR);
                    }
                ierror = MPI_Waitall (1, &request, &status);
                if (ierror != MPI_SUCCESS)
                    {
                    return (ERROR);
                    }
                }
            }
        else if (proc_id == proc)
            {
            x = paramValues;
            ierror = MPI_Irecv (x, paramValsRowSize*2*(upper-lower), MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request);
            if (ierror != MPI_SUCCESS)
                {
                return (ERROR);
                }
            ierror = MPI_Waitall (1, &request, &status);
            if (ierror != MPI_SUCCESS)
                {
                return (ERROR);
                }
            if (intValsRowSize > 0)
                {
                y = intValues;
                ierror = MPI_Irecv (y, intValsRowSize*2*(upper-lower), MPI_INT, 0, 0, MPI_COMM_WORLD, &request);
                if (ierror != MPI_SUCCESS)
                    {
                    return (ERROR);
                    }
                ierror = MPI_Waitall (1, &request, &status);
                if (ierror != MPI_SUCCESS)
                    {
                    return (ERROR);
                    }
                }
            }
        
        /* mcmc trees */
        brlens = (MrBFlt *) SafeCalloc (2*numLocalTaxa, sizeof(MrBFlt));
        order  = (int *)    SafeCalloc (2*numLocalTaxa,   sizeof(int));
        for (i=lower; i<upper; i++)
            {
            for (j=0; j<numTrees; j++)
                {
                tree = GetTreeFromIndex(j,0,0);
                orderLen = 2*tree->nIntNodes - 1;
                nBrlens = tree->nNodes - 1;
                if (proc_id == 0)
                    {
                    tree = GetTreeFromIndex(j,i,0);
                    if (tree->isRooted == YES)
                        StoreRTreeWithIndices(tree, order, brlens);
                    else
                        StoreUTree(tree, order, brlens);
					ierror = MPI_Isend (order, orderLen, MPI_INT, proc, 0, MPI_COMM_WORLD, &request);
                    if (ierror != MPI_SUCCESS)
                        {
                        return (ERROR);
                        }
                    ierror = MPI_Waitall (1, &request, &status);
                    if (ierror != MPI_SUCCESS)
                        {
                        return (ERROR);
                        }
                    ierror = MPI_Isend (brlens, nBrlens, MPI_DOUBLE, proc, 0, MPI_COMM_WORLD, &request);
                    if (ierror != MPI_SUCCESS)
                        {
                        return (ERROR);
                        }
                   ierror = MPI_Waitall (1, &request, &status);
                   if (ierror != MPI_SUCCESS)
                        {
                        return (ERROR);
                        }
                    }
                else if (proc_id == proc)
                    {
                    tree = GetTreeFromIndex(j,i-lower,0);
                    ierror = MPI_Irecv (order, orderLen, MPI_INT, 0, 0, MPI_COMM_WORLD, &request);
                    if (ierror != MPI_SUCCESS)
                        {
                        return (ERROR);
                        }
                    ierror = MPI_Waitall (1, &request, &status);
                    if (ierror != MPI_SUCCESS)
                        {
                        return (ERROR);
                        }
                    ierror = MPI_Irecv (brlens, nBrlens, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request);
                    if (ierror != MPI_SUCCESS)
                        {
                        return (ERROR);
                        }
                    ierror = MPI_Waitall (1, &request, &status);
                    if (ierror != MPI_SUCCESS)
                        {
                        return (ERROR);
                        }
                    if (tree->isRooted == YES)
                        RetrieveRTreeWithIndices(tree, order, brlens);
                    else
                        {    
                        RetrieveUTree(tree, order, brlens);
                        if (localOutGroup != 0)
                            MoveCalculationRoot(tree,localOutGroup);
                        }
                    /* since we only transferred some info, there are additional things we need to
                       consider, like names, constraints and calibrations */
                    InitializeTreeCalibrations(tree);
                    CheckSetConstraints(tree);
                    SetDatedNodeAges(modelSettings[tree->relParts[0]].brlens, i-lower, 0);
                    strcpy(tree->name, GetTreeFromIndex(j, i, 0)->name);
                    tree = GetTreeFromIndex(j,i-lower,1);
                    strcpy(tree->name, GetTreeFromIndex(j, i, 0)->name);
                    }
                }
            }
        free (brlens);
        free (order);

        /* CPP relaxed clock  parameters */
        for(i=lower; i<upper; i++)
            {
            for (j=0; j<numParams; j++)
                {
                p = &params[j];
                if (p->paramType == P_CPPEVENTS)
                    {
                    if (proc_id == 0)
                        {
                        /* get pointers */
                        nEvents = p->nEvents[2*i];
                        position = p->position[2*i];
                        rateMult = p->rateMult[2*i];

                        /* send number of events */
                        ierror = MPI_Isend (nEvents, 2*numLocalTaxa, MPI_INT, proc, 0, MPI_COMM_WORLD, &request);
                        if (ierror != MPI_SUCCESS)
                            return (ERROR);
                        ierror = MPI_Waitall (1, &request, &status);
                        if (ierror != MPI_SUCCESS)
                            return (ERROR);

                        /* send events and clear pointers */
                        for (k=0; k<2*numLocalTaxa; k++)
                            {
                            if (nEvents[k] > 0)
                                {
                                ierror = MPI_Isend (position[k], nEvents[k], MPI_DOUBLE, proc, 0, MPI_COMM_WORLD, &request);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);
                                ierror = MPI_Waitall (1, &request, &status);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);

                                ierror = MPI_Isend (rateMult[k], nEvents[k], MPI_DOUBLE, proc, 0, MPI_COMM_WORLD, &request);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);
                                ierror = MPI_Waitall (1, &request, &status);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);

                                free(position[k]);
                                free(rateMult[k]);
                                position[k] = NULL;
                                rateMult[k] = NULL;
                                nEvents[k] = 0;
                                }
                            }
                        }
                    else if (proc_id == proc)
                        {
                        /* find pointers */
                        nEvents = p->nEvents[2*(i-lower)];
                        position = p->position[2*(i-lower)];
                        rateMult = p->rateMult[2*(i-lower)];

                        /* clear previous events */
                        for (k=0; k<2*numLocalTaxa; k++)
                            {
                            if (nEvents[k] > 0)
                                {
                                free (position[k]);
                                free (rateMult[k]);
                                position[k] = NULL;
                                rateMult[k] = NULL;
                                nEvents[k] = 0;
                                }
                            }

                        /* receive events */
                        ierror = MPI_Irecv (nEvents, 2*numLocalTaxa, MPI_INT, 0, 0, MPI_COMM_WORLD, &request);
                        if (ierror != MPI_SUCCESS)
                            return (ERROR);
                        ierror = MPI_Waitall (1, &request, &status);
                        if (ierror != MPI_SUCCESS)
                            return (ERROR);
                        for (k=0; k<2*numLocalTaxa; k++)
                            {
                            if (nEvents[k] > 0)
                                {
                                position[k] = (MrBFlt *) SafeCalloc (nEvents[k], sizeof(MrBFlt));
                                rateMult[k] = (MrBFlt *) SafeCalloc (nEvents[k], sizeof(MrBFlt));

                                ierror = MPI_Irecv (position[k], nEvents[k], MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);
                                ierror = MPI_Waitall (1, &request, &status);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);

                                ierror = MPI_Irecv (rateMult[k], nEvents[k], MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &request);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);
                                ierror = MPI_Waitall (1, &request, &status);
                                if (ierror != MPI_SUCCESS)
                                    return (ERROR);
                                }
                            }
                       }
                   }
                }
            } 

        /* update evolutionary branch lengths or rates (because node indices have changed) */
        if (proc_id == proc)
            {
            for (i=0; i<upper-lower; i++)
                {
                for (j=0; j<numParams; j++)
                    {
                    p = &params[j];
                    if (p->paramType == P_CPPEVENTS)
                        {
                        tree = GetTree(p, i, 0);
                        UpdateCppEvolLengths (p, tree->root->left, i);
                        }
                    else if (p->paramType == P_TK02BRANCHRATES)
                        {
                        tree = GetTree (p, i, 0);
                        UpdateTK02EvolLengths (p, tree, i);
                        }
                    else if (p->paramType == P_IGRBRANCHLENS)
                        {
                        tree = GetTree(p, i, 0);
                        UpdateIgrBranchRates (p, tree, i);
                        }
                    }
                }
            }
        }

    return (NO_ERROR);
}





int RedistributeTuningParams (void)
{
    int	    i, j, k, lower, ierror;
    MrBFlt  *x, *sum;
    
    x = (MrBFlt *) SafeCalloc (2*numUsedMoves, sizeof(MrBFlt));
    sum = x + numUsedMoves;

    lower = numGlobalChains / num_procs;
    if (numGlobalChains % num_procs != 0)
        lower++;

    if(proc_id != 0 )
        {
        for (i=0; i<numGlobalChains; i++)
            {
            for (k=0; k<numUsedMoves; k++)
                                {
                                if (usedMoves[k]->moveType->numTuningParams > 0)
                        usedMoves[k]->tuningParam[i][0] = 0.0;
                                }
	    }
        }

    for (i=lower; i<numGlobalChains; i++)
        {
		for (j=0; j<numLocalChains; j++)
            {
            if (chainId[j] == i)
                break;
            }

        for (k=0; k<numUsedMoves; k++)
            {
			if (proc_id == 0 && usedMoves[k]->moveType->numTuningParams > 0) /* we have the tuning parameter of interest */
		{
                x[k] = usedMoves[k]->tuningParam[i][0];
		usedMoves[k]->tuningParam[i][0]=0.0;
		}
            else
                x[k] = 0.0;
	    }

        ierror = MPI_Allreduce (x, sum, numUsedMoves, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
        if (ierror != MPI_SUCCESS)
            {
            free (x);
            return (ERROR);
            }

        if (j != numLocalChains)   /* we have the chain of interest */
            {
            for (k=0; k<numUsedMoves; k++)
				{
				if (usedMoves[k]->moveType->numTuningParams > 0)
                	usedMoves[k]->tuningParam[i][0] = sum[k];
				}
            }
        }

    free (x);
	return (NO_ERROR);
}

#endif





/*----------------------------------------------------------------
|
|	RemoveNodeScalers: Remove node scalers
|
-----------------------------------------------------------------*/
int RemoveNodeScalers (TreeNode *p, int division, int chain)

{
	int				c;
	CLFlt			*scP, *lnScaler;
	ModelInfo		*m;
	
    m = &modelSettings[division];
    assert (m->scalersSet[chain][p->index] == YES);

    /* find scalers */
    scP = m->scalers[m->nodeScalerIndex[chain][p->index]];

    /* find site scalers */
    lnScaler = m->scalers[m->siteScalerIndex[chain]];

	/* remove scalers */
	for (c=0; c<m->numChars; c++)
		lnScaler[c] -= scP[c];

	return NO_ERROR;
	
}





#if defined (SSE_ENABLED)
/*----------------------------------------------------------------
|
|	RemoveNodeScalers_SSE: Remove node scalers, SSE code
|
-----------------------------------------------------------------*/
int RemoveNodeScalers_SSE (TreeNode *p, int division, int chain)

{
	int				c;
    __m128          *scP_SSE, *lnScaler_SSE;
	ModelInfo		*m;
	
    m = &modelSettings[division];
    assert (m->scalersSet[chain][p->index] == YES);

    /* find scalers */
    scP_SSE = (__m128*)(m->scalers[m->nodeScalerIndex[chain][p->index]]);

    /* find site scalers */
    lnScaler_SSE = (__m128*)(m->scalers[m->siteScalerIndex[chain]]);

	/* remove scalers */
	for (c=0; c<m->numSSEChars; c++)
        {
		lnScaler_SSE[c] = _mm_sub_ps(lnScaler_SSE[c], scP_SSE[c]);
        }

	return NO_ERROR;
	
}
#endif





/* RemovePartition: Remove a partition from the tree keeping track of partition frequencies */
int RemovePartition (PFNODE *r, SafeLong *p, int runId)
{
	int		i, comp;
	
	if (r == NULL)
		{
		return (ERROR);
		}
	else
		{
		for (i=0; i<nLongsNeeded; i++)
			{
			if (r->partition[i] != p[i])
				break;
			}
		
		if (i == nLongsNeeded)
			comp = 0;
		else if (r->partition[i] < p[i])
			comp = -1;
		else
			comp = 1;
		
		if (comp == 0)			/* match */
			{
			if (r->count[runId] == 0)
				return ERROR;
			else
				r->count[runId]--;
			}
		else if (comp < 0)		/* greater than -> into left subtree */
			{
			if ((RemovePartition (r->left, p, runId)) == ERROR)
				return ERROR;
			}
		else
			{
			/* less than -> into right subtree */
			if ((RemovePartition (r->right, p, runId)) == ERROR)
				return ERROR;
			}
		}

	return (NO_ERROR);
}





/* RemoveTreeFromPartitionCounters: Break a tree into partitions and remove those from counters */
int RemoveTreeFromPartitionCounters (Tree *tree, int treeId, int runId)
{
	int			i, j, nTaxa;
	TreeNode	*p;

    extern void ShowParts (FILE *,SafeLong *,int);

    if (tree->isRooted == YES)
        nTaxa = tree->nNodes - tree->nIntNodes - 1;
    else
        nTaxa = tree->nNodes - tree->nIntNodes;

    for (i=0; i<nTaxa; i++)
        {
        ClearBits(partition[i], nLongsNeeded);
        SetBit(i, partition[i]);
        }

	for (i=0; i<tree->nIntNodes-1; i++)
		{
        p = tree->intDownPass[i];
        assert(p->index >= tree->nNodes - tree->nIntNodes - (tree->isRooted == YES ? 1 : 0));
		for (j=0; j<nLongsNeeded; j++)
			{
			partition[p->index][j] = partition[p->left->index][j] | partition[p->right->index][j];
			}
		
		if ((RemovePartition (partFreqTreeRoot[treeId], partition[p->index], runId)) == ERROR)
			{
			MrBayesPrint ("%s   Could not remove partition %d in RemoveTreeFromPartitionCounters\n", spacer, p->index);
			ShowParts(stdout,partition[p->index],numLocalTaxa);
            return ERROR;
			}
		}

	return NO_ERROR;
}





/* RemoveTreeSamples: Remove tree samples from partition counters */
int RemoveTreeSamples (int from, int to)
{
	int		    i, j, k, longestLine, line;
	char	    c, *word, *s, *lineBuf=0;
	FILE	    *fp;
	Tree	    *t;
	TreeList	*treeList;
	char	    *tempStr;
	int         tempStrSize = TEMPSTRSIZE;

#	if defined (MPI_ENABLED)
	if (proc_id != 0)
		return (NO_ERROR);
#	endif

	tempStr = (char *) SafeMalloc((size_t) (tempStrSize * sizeof(char)));
	if (!tempStr)
		{
		MrBayesPrint ("%s   Problem allocating tempString (%d)\n", spacer, tempStrSize * sizeof(char));
		return (ERROR);
		}

	if (chainParams.saveTrees == YES)
		{
		for (i=0; i<numTopologies; i++)
			{
            t = chainParams.dtree;
			if (topologyParam[i]->tree[0]->isRooted == YES)
				t->isRooted = YES;
			else
				t->isRooted = NO;

			for (j=0; j<chainParams.numRuns; j++)
				{				
				treeList = &chainParams.treeList[j*numTopologies + i];
				
				for (k=from; k<=to; k++)
					{
					GetFromTreeList (treeList, t);
                    if (RemoveTreeFromPartitionCounters (t, i, j) == ERROR)
						{
						SafeFclose (&fp);
						free (tempStr);
						free (lineBuf);
						return (ERROR);
						}
					}
				}
			}
		}
	else
		{
		for (i=0; i<numTopologies; i++)
			{
			t = chainParams.dtree;

			for (j=0; j<chainParams.numRuns; j++)
				{
				if (numPrintTreeParams == 1)
                    {
                    if( chainParams.numRuns == 1 )
                        SafeSprintf(&tempStr, &tempStrSize, "%s.t", chainParams.chainFileName);
                    else
					    SafeSprintf(&tempStr, &tempStrSize, "%s.run%d.t", chainParams.chainFileName, j+1);
                    }
				else
                    {
                    if( chainParams.numRuns == 1 )
                        SafeSprintf(&tempStr, &tempStrSize, "%s.tree%d.t", chainParams.chainFileName, topologyPrintIndex[i]+1);
                    else
					    SafeSprintf(&tempStr, &tempStrSize, "%s.tree%d.run%d.t", chainParams.chainFileName, topologyPrintIndex[i]+1, j+1);
                    }

				if ((fp = OpenTextFileR (tempStr)) == NULL)
						{
						free (tempStr);
						return (ERROR);
						}
				
				if (from == 1)
					{
					longestLine = LongestLine(fp);
					lineBuf = (char *) SafeCalloc (longestLine+2,sizeof(char));
					fseek (fp, LastBlock(fp, lineBuf, longestLine), SEEK_SET);
					fseek (fp, FirstTree(fp, lineBuf, longestLine), SEEK_SET);
					fgetpos (fp, &chainParams.tFilePos[j*numTopologies+i]);
					free(lineBuf);
					lineBuf = NULL;
					}
				fsetpos (fp, &chainParams.tFilePos[j*numTopologies+i]);

				longestLine = 0;
				for (k=0; k<=to-from; k++)
					{
					line = 0;
					do {
						line++;
						} while ((c = fgetc(fp)) != '\r' && c != '\n');
					
					if (line > longestLine)
						longestLine = line;
					
					while ((c = fgetc(fp)) == '\r' || c == '\n')
						;
					}

				lineBuf = (char *) SafeCalloc (longestLine + 10, sizeof (char));
				if (!lineBuf)
					{
					SafeFclose (&fp);
					free (tempStr);
					return (ERROR);
					}
				fsetpos (fp, &chainParams.tFilePos[j*numTopologies+i]);
				/* The fsetpos and fgetpos pair are affected by writing to the file,
					at least on Windows systems. The effect is to put the subsequent
					fsetpos back a few positions. The following code will deal with this
					problem without affecting systems where this does not happen. */
				do { c = fgetc(fp);
				} while (c != 't');

				for (k=from; k<=to; k++)
					{
					if (fgets (lineBuf, longestLine + 5, fp) == NULL) 
						{
						free (tempStr);
						free (lineBuf);
						return ERROR;
						}

					word = strtok (lineBuf, " ");					
					for (s = strtok (NULL, ";"); *s != '('; s++)
						;
					
					StripComments (s);
					if (ResetTopology (t, s) == ERROR)
						{
						SafeFclose (&fp);
						free (tempStr);
						free (lineBuf);
						return (ERROR);
						}
					
					if (RemoveTreeFromPartitionCounters (t, i, j) == ERROR)
						{
						SafeFclose (&fp);
						free (tempStr);
						free (lineBuf);
						return (ERROR);
						}
					}
				fgetpos (fp, &chainParams.tFilePos[j*numTopologies+i]);
				free (lineBuf);
				SafeFclose (&fp);
				}
			}
		}

	/* remove unnecessary nodes from the tree holding partition counters */
	for (i=0; i<numTopologies; i++)
		{
		partFreqTreeRoot[i] = CompactTree (partFreqTreeRoot[i]);
		}

	free (tempStr);
	return (NO_ERROR);
}





int ReopenMBPrintFiles (void)
{
	int		i, k, n;
	char	fileName[120], localFileName[100];
	
	/* Get root of local file name */
	strcpy (localFileName, chainParams.chainFileName);

	/* Reopen the .p and .t files */
	for (n=0; n<chainParams.numRuns; n++)
		{
		k = n;

		if (chainParams.numRuns == 1)
			sprintf (fileName, "%s.p", localFileName);
		else
			sprintf (fileName, "%s.run%d.p", localFileName, n+1);

#		if defined (MPI_ENABLED)
		if (proc_id == 0)
#		endif
		if ((fpParm[k] = OpenTextFileA (fileName)) == NULL)
			return (ERROR);

		for (i=0; i<numTrees; i++)
			{
			if (numTrees == 1 && chainParams.numRuns == 1)
				sprintf (fileName, "%s.t", localFileName);
			else if (numTrees > 1 && chainParams.numRuns == 1)
				sprintf (fileName, "%s.tree%d.t", localFileName, i+1);
			else if (numTrees == 1 && chainParams.numRuns > 1)
				sprintf (fileName, "%s.run%d.t", localFileName, n+1);
			else
				sprintf (fileName, "%s.tree%d.run%d.t", localFileName, i+1, n+1);

#			if defined (MPI_ENABLED)
			if (proc_id == 0)
#			endif
			if ((fpTree[k][i] = OpenTextFileA (fileName)) == NULL)
				return (ERROR);
			}

		}

	/* Take care of the mpi procs that do not have a mcmc file */
#	if defined (MPI_ENABLED)
	if (proc_id != 0)
		return (NO_ERROR);
#	endif

	/* Reopen the .mcmc file */
	if (chainParams.mcmcDiagn == YES)
		{
		sprintf (fileName, "%s.mcmc", chainParams.chainFileName);

		if ((fpMcmc = OpenTextFileA (fileName)) == NULL)
			return (ERROR);
		}

	return (NO_ERROR);
}





int ConfirmAbortRun(void) 

{
    char c, line[100];
    int  ret=0, i;

    /* reset requestAbortRun */
    requestAbortRun = NO;

    MrBayesPrint("   Do you really want to stop the run (y/n)?");
	if( fgets (line,98,stdin) == NULL )
		{
		printf("Error in function: %s at line: %d in file: %s", __FUNCTION__, __LINE__, __FILE__);
		}
    for (i=0; (c=line[i])!='\0' && !isgraph(c); i++)
        ;
    if (c == 'y' || c == 'Y')
        ret=1;
    else 
        {
        MrBayesPrint("   Mcmc run continued ...\n\n");
        ret=0;
        }
    return ret;
}





/*-------------------------------------------------------------------
|
|	ResetChainIds: Make sure parameter values are swapped back 
|		at the end of a Metropolis-coupled MCMC run
|
--------------------------------------------------------------------*/
void ResetChainIds (void)
{
	int		j, k, k1, tempId, *curId, toChn, fromChn, *to, *from, *swap;
	Param	*p;
	MrBFlt  *fromVals, *toVals, *swapVals, **fromPosition, **toPosition,
		    **swapPosition, **fromRateMult, **toRateMult, **swapRateMult;
	Tree	*toTree, *fromTree, *swapTree;

    curId = (int *) SafeCalloc (numGlobalChains, sizeof(int));

#if defined (MPI_ENABLED)
    ReassembleParamVals(curId);
    ReassembleTuningParams();
    SetChainIds();
    if (proc_id != 0)
	{
        /* reset state */
        for (j=0; j<numLocalChains; j++)
            state[j] = 0;
        free (curId);
	return;
        }
#else
    for (j=0; j<numGlobalChains; j++)
        curId[j] = chainId[j];
    SetChainIds();
#endif
    
	for (toChn=0; toChn<numGlobalChains; toChn++)
		{
		if (curId[toChn] == toChn)
			{
			if (state[toChn] != 0)
				{
				CopyParams (toChn);
				CopyTrees (toChn);
				state[toChn] ^= 1;
				}
			continue;
			}

		/* we need to swap all values */
		/* first find the chain to swap with */
		for (j=toChn+1; j<numGlobalChains; j++)
			if (curId[j] == toChn)
				break;
		fromChn = j;

		/* normal params */
        CopyParams (toChn);
        CopyTrees (toChn);
        CopyParams (fromChn);
        CopyTrees (fromChn);

        for (j=0; j<numParams; j++)
			{
			p = &params[j];
            toVals = GetParamVals (p, toChn, 0);
			swapVals = GetParamVals (p, toChn, 1);
			fromVals = GetParamVals (p, fromChn, state[fromChn]);
			for (k=0; k<p->nValues; k++)
				{
				toVals[k] = fromVals[k];
				fromVals[k] = swapVals[k];
				}
			toVals = GetParamSubVals (p, toChn, 0);
			swapVals = GetParamSubVals (p, toChn, 1);
			fromVals = GetParamSubVals (p, fromChn, state[fromChn]);
			for (k=0; k<p->nSubValues; k++)
				{
				toVals[k] = fromVals[k];
				fromVals[k] = swapVals[k];
				}
            if (p->nStdStateFreqs > 0)
                {
                toVals = GetParamStdStateFreqs (p, toChn, 0);
			    swapVals = GetParamStdStateFreqs (p, toChn, 1);
			    fromVals = GetParamStdStateFreqs (p, fromChn, state[fromChn]);
			    for (k=0; k<p->nStdStateFreqs; k++)
                    {
				    toVals[k] = fromVals[k];
				    fromVals[k] = swapVals[k];
				    }
                }
            }

		/* mcmc trees */
		for (j=0; j<numTrees; j++)
			{
			toTree = GetTreeFromIndex(j, toChn, 0);
			swapTree = GetTreeFromIndex(j, toChn, 1);
			fromTree = GetTreeFromIndex(j, fromChn, state[fromChn]);
            CopyToTreeFromTree (toTree, fromTree);
            CopyToTreeFromTree (fromTree, swapTree);
            CopyToTreeFromTree (swapTree, toTree);
            swapTree = GetTreeFromIndex(j, fromChn, state[fromChn]^1);
            CopyToTreeFromTree (swapTree, fromTree);
			}
		/* CPP relaxed clock params */
		for (j=0; j<numParams; j++)
			{
			p = &params[j];
			if (p->paramType == P_CPPEVENTS)
				{
				to = p->nEvents[2*toChn];
				swap = p->nEvents[2*toChn+1];
				from = p->nEvents[2*fromChn+state[fromChn]];
				toPosition = p->position[2*toChn];
				swapPosition = p->position[2*toChn+1];
				fromPosition = p->position[2*fromChn+state[fromChn]];
				toRateMult = p->rateMult[2*toChn];
				swapRateMult = p->rateMult[2*toChn+1];
				fromRateMult = p->rateMult[2*fromChn+state[fromChn]];
				for (k=0; k<2*numLocalTaxa; k++)
					{
				    if (from[k] > 0)
                        {
                        toPosition[k] = (MrBFlt *) SafeRealloc ((void *)toPosition[k], from[k]*sizeof (MrBFlt));
						toRateMult[k] = (MrBFlt *) SafeRealloc ((void *)toRateMult[k], from[k]*sizeof (MrBFlt));
						for (k1=0; k1<from[k]; k1++)
							{
							toPosition[k][k1] = fromPosition[k][k1];
							toRateMult[k][k1] = fromRateMult[k][k1];
							}
                        }
                    else if (to[k] > 0)
                        {
                        free (toPosition[k]);
                        toPosition[k] = NULL;
                        free (toRateMult[k]);
                        toRateMult[k] = NULL;
                        }
                    to[k] = from[k];
                    if (swap[k] > 0)
                        {
                        fromPosition[k] = (MrBFlt *) SafeRealloc ((void *)fromPosition[k], swap[k]*sizeof (MrBFlt));
						fromRateMult[k] = (MrBFlt *) SafeRealloc ((void *)fromRateMult[k], swap[k]*sizeof (MrBFlt));
						for (k1=0; k1<swap[k]; k1++)
							{
							fromPosition[k][k1] = swapPosition[k][k1];
							fromRateMult[k][k1] = swapRateMult[k][k1];
							}
						}
                    else if (from[k] > 0)
                        {
                        free (fromPosition[k]);
                        fromPosition[k] = NULL;
                        free (fromRateMult[k]);
                        fromRateMult[k] = NULL;
                        }
					from[k] = swap[k];
					}
				}	
			}
		/* reset state of chain */
		state[toChn] = 0;

        /* make sure that the id is correct for the from chain */
        tempId = curId[toChn];
        curId[fromChn] = curId[toChn];
        curId[toChn] = tempId;
		}

	free (curId);

}





/* ResetFlips: Reset flipped cond likes etc after rejection */
void ResetFlips (int chain)
{
    int         d, i;
    ModelInfo   *m;
    TreeNode    *p;
    Tree        *tree;
#if defined (BEAGLE_ENABLED)
	int			*isScalerNode=NULL;
#endif    
    
    for (d=0; d<numCurrentDivisions; d++)
    {
        m = &modelSettings[d];
#if defined (BEAGLE_ENABLED)
		if ( m->useBeagle == YES )
			isScalerNode = m->isScalerNode[chain];
#endif
        if (m->upDateCl != YES)
            continue;
        
#if defined (BEAGLE_ENABLED)
		if( m->useBeagle == NO || 
			beagleScalingScheme == MB_BEAGLE_SCALE_ALWAYS ||
			m->rescaleBeagleAll == YES )
				{
				FlipSiteScalerSpace (m, chain);
				if (m->rescaleBeagleAll == YES )
					m->rescaleFreq[chain] = m->rescaleFreqOld;
				}
#else
		FlipSiteScalerSpace (m, chain);
#endif
			
        
        if (m->upDateCijk == YES && m->nCijkParts > 0)
            FlipCijkSpace (m, chain);
        
        /* cycle over tree */
        tree = GetTree (m->brlens, chain, state[chain]);
        for (i=0; i<tree->nNodes; i++)
            {
            p = tree->allDownPass[i];
            if (p->upDateTi == YES)
                FlipTiProbsSpace (m, chain, p->index);
            if (p->right != NULL)    /* do not flip terminals in case these flags are inappropriately set by moves */
			    {
                if (p->upDateCl == YES)
                    {
                    FlipCondLikeSpace (m, chain, p->index);
#if defined (BEAGLE_ENABLED)
					if( m->useBeagle == NO || 
						beagleScalingScheme == MB_BEAGLE_SCALE_ALWAYS ||
						( m->rescaleBeagleAll == YES && isScalerNode[p->index] == YES ))
							FlipNodeScalerSpace (m, chain, p->index);
#else
					FlipNodeScalerSpace (m, chain, p->index);
#endif
                    }
#if defined (BEAGLE_ENABLED)
                else if( m->rescaleBeagleAll == YES )
                    {
                    FlipCondLikeSpace (m, chain, p->index);
                    if( isScalerNode[p->index] == YES )
						FlipNodeScalerSpace (m, chain, p->index);
                    }
#endif
                }
            }
        
        /* division flag and tree node flags are reset when trees are copied */
    }
}






/*-------------------------------------------------------------------
|
|	ResetScalersPartition: reset scaler nodes of the given tree by appropriatly setting isScalerNode array.
| @param isScalerNode	is an array which gets set with information about scaler node. 
|						For each internal node isScalerNode[node->index] is set to YES if it has to be scaler node.
|						Note: Only internal nodes can become scaler nodes thus isScalerNode is set only for elemnts in interval [numLocalTaxa, numLocalTaxa+t->nIntNodes]
|
| @param rescaleFreq	effectively represent gabs between rescaling, higher number means more sparse choice of rescaling nodes 
|
--------------------------------------------------------------------*/
int ResetScalersPartition (int *isScalerNode, Tree* t, unsigned rescaleFreq)

{
	int			n;
	TreeNode	*p;
		
	/* set the node depth value of terminal nodes to zero; reset scalerNode */
	for (n=0; n<t->nNodes; n++)
		{
		p = t->allDownPass[n];
		if (p->left == NULL)
			p->x = 0;
		}

	/* loop over interior nodes */
	for (n=0; n<t->nIntNodes; n++)
		{
		p = t->intDownPass[n];
		assert( ((p->index - numLocalTaxa) >= 0) && ((p->index - numLocalTaxa) < t->nIntNodes) );
		p->x = p->left->x + p->right->x + 1;

		if (p->x > 2 * (int)rescaleFreq )
			{
			assert (p->left->left != NULL && p->right->left != NULL);
			isScalerNode[p->left->index] = YES;
			p->left->x = 0;
			isScalerNode[p->right->index] = YES;
			p->right->x = 0;
			p->x = 1;
			}
		else if (p->x > (int)rescaleFreq )
			{
			if (p->left->x > p->right->x)
				{
				assert (p->left->left != NULL);
				isScalerNode[p->left->index] = YES;
				p->left->x = 0;
				}
			else
				{
				assert (p->right->left != NULL);
				isScalerNode[p->right->index] = YES;
				p->right->x = 0;
				}
			p->x = p->left->x + p->right->x + 1;
			}
		else
			isScalerNode[p->index] = NO;
		}

	return NO_ERROR;
}





/*-------------------------------------------------------------------
|
|	ResetScalers: reset scaler nodes of all trees of all chains
|		This scheme ensures that minimally RESCALE_FREQ
|		unscaled interior nodes occur before rescaling is done
|
--------------------------------------------------------------------*/
int ResetScalers (void)
{
	int			i, n, chn;
	Tree		*t;
	TreeNode	*p;

#if defined (DEBUG_NOSCALING)
    return (NO_ERROR);
#endif

    for (chn=0; chn<numLocalChains; chn++)
		{
		for (i=0; i<numTrees; i++)
			{
			t = GetTreeFromIndex (i, chn, state[chn]);
		
			/* set the node depth value of terminal nodes to zero; reset scalerNode */
			for (n=0; n<t->nNodes; n++)
				{
				p = t->allDownPass[n];
                p->scalerNode = NO;
				if (p->left == NULL)
					p->x = 0;
				}

			/* loop over interior nodes */
			for (n=0; n<t->nIntNodes; n++)
				{
				p = t->intDownPass[n];

				p->x = p->left->x + p->right->x + 1;

				if (p->x > 2 * RESCALE_FREQ )
					{
                    assert (p->left->left != NULL && p->right->left != NULL);
					p->left->scalerNode = YES;
					p->left->x = 0;
					p->right->scalerNode = YES;
					p->right->x = 0;
					p->x = 1;
					}
				else if (p->x > RESCALE_FREQ )
					{
					if (p->left->x > p->right->x)
						{
                        assert (p->left->left != NULL);
						p->left->scalerNode = YES;
						p->left->x = 0;
						}
					else
						{
                        assert (p->right->left != NULL);
						p->right->scalerNode = YES;
						p->right->x = 0;
						}
					p->x = p->left->x + p->right->x + 1;
					}
				else
					p->scalerNode = NO;
				}
			}
		}

	return NO_ERROR;
}





void ResetSiteScalers (ModelInfo *m, int chain)
{
    int     c;
    CLFlt   *lnScaler;

#if defined (BEAGLE_ENABLED)
    if (m->useBeagle == YES)
        {
        beagleResetScaleFactors(m->beagleInstance, m->siteScalerIndex[chain]);
        return;
        }
#endif
    lnScaler = m->scalers[m->siteScalerIndex[chain]];
    for (c=0; c<m->numChars; c++)
        lnScaler[c] = 0.0;
}





/*----------------------------------------------------------------------
|
|	ReusePreviousResults: Save old .p, .t, .ss and .mcmc files with ~ extension,
|      then prepare new print files with the relevant old values added in
|      The number of samples is returned in numSamples
|
------------------------------------------------------------------------*/
int ReusePreviousResults (int *numSamples, int steps)

{

	int			i, k, n;
	char		localFileName[100], fileName[220], bkupName[220];

    (*numSamples) = 0;

#   if defined (MPI_ENABLED)
    if (proc_id != 0)
        return (NO_ERROR);
#   endif

    /* Allocate space for file pointers */
	n = chainParams.numRuns;

	if (memAllocs[ALLOC_FILEPOINTERS] == YES)
		{
		MrBayesPrint ("%s   File pointers already allocated in ReusePreviousResults\n", spacer);
		return ERROR;
		}
	fpMcmc = NULL;
    fpSS = NULL;
	fpParm = NULL;
	fpTree = NULL;	
	fpParm = (FILE **) SafeCalloc (n, sizeof (FILE *));	
	if (fpParm == NULL)
		{
		MrBayesPrint ("%s   Could not allocate fpParm in ReusePreviousResults\n", spacer);
		return ERROR;
		}
	memAllocs[ALLOC_FILEPOINTERS] = YES;
	fpTree = (FILE ***) SafeCalloc (n, sizeof (FILE **));	
	if (fpTree == NULL)
		{
		MrBayesPrint ("%s   Could not allocate fpTree in ReusePreviousResults\n", spacer);
		return ERROR;
		}
	fpTree[0] = (FILE **) SafeCalloc (numTrees*n, sizeof (FILE *));
	if (fpTree[0] == NULL)
		{
		MrBayesPrint ("%s   Could not allocate fpTree[0] in ReusePreviousResults\n", spacer);
		return ERROR;
		}
	for (i=1; i<n; i++)
		fpTree[i] = fpTree[0] + i*numTrees;

	/* Get root of local file name */
	strcpy (localFileName, chainParams.chainFileName);

	/* Store old and prepare new .p and .t files */
	for (n=0; n<chainParams.numRuns; n++)
		{
		k = n;

        if (chainParams.numRuns == 1)
			sprintf (fileName, "%s%s.p", workingDir, localFileName);
		else
			sprintf (fileName, "%s%s.run%d.p", workingDir, localFileName, n+1);
		strcpy(bkupName,fileName);
        strcat(bkupName,"~");
        remove(bkupName);
        if (rename(fileName,bkupName) != 0)
            {
            MrBayesPrint ("%s   Could not rename file %s\n", spacer, fileName);
            return ERROR;
            }

        if ((fpParm[k] = OpenNewMBPrintFile (fileName+strlen(workingDir))) == NULL)
			return (ERROR);
        else if (CopyResults(fpParm[k],bkupName+strlen(workingDir),numPreviousGen) == ERROR)
            return (ERROR);

        for (i=0; i<numTrees; i++)
			{
			if (numTrees == 1 && chainParams.numRuns == 1)
				sprintf (fileName, "%s%s.t", workingDir, localFileName);
			else if (numTrees > 1 && chainParams.numRuns == 1)
				sprintf (fileName, "%s%s.tree%d.t", workingDir, localFileName, i+1);
			else if (numTrees == 1 && chainParams.numRuns > 1)
				sprintf (fileName, "%s%s.run%d.t", workingDir, localFileName, n+1);
			else
				sprintf (fileName, "%s%s.tree%d.run%d.t", workingDir, localFileName, i+1, n+1);
		    strcpy(bkupName,fileName);
            strcat(bkupName,"~");
            remove(bkupName);
            if (rename(fileName,bkupName) != 0)
                {
                MrBayesPrint ("%s   Could not rename file %s\n", spacer, fileName);
                return ERROR;
                }
			if ((fpTree[k][i] = OpenNewMBPrintFile (fileName+strlen(workingDir))) == NULL)
				return (ERROR);
            else if (CopyTreeResults(fpTree[k][i],bkupName+strlen(workingDir),numPreviousGen,numSamples) == ERROR)
                return (ERROR);
			}
		}

    /* Store old and prepare new .ss file */
	if (chainParams.isSS == YES)
		{
		sprintf (fileName, "%s%s.ss", workingDir, chainParams.chainFileName);
		strcpy(bkupName,fileName);
        strcat(bkupName,"~");
        remove(bkupName);
        if (rename(fileName,bkupName) != 0)
            {
            MrBayesPrint ("%s   Could not rename file %s\n", spacer, fileName);
            return ERROR;
            }
		if ((fpSS = OpenNewMBPrintFile (fileName+strlen(workingDir))) == NULL)
			return (ERROR);
        else if (CopyProcessSsFile(fpSS,bkupName+strlen(workingDir),steps,marginalLnLSS,splitfreqSS)==ERROR)
            return (ERROR);
		}

    /* Store old and prepare new .mcmc file */
	if (chainParams.mcmcDiagn == YES)
		{
		sprintf (fileName, "%s%s.mcmc", workingDir, chainParams.chainFileName);
		strcpy(bkupName,fileName);
        strcat(bkupName,"~");
        remove(bkupName);
        if (rename(fileName,bkupName) != 0)
            {
            MrBayesPrint ("%s   Could not rename file %s\n", spacer, fileName);
            return ERROR;
            }
		if ((fpMcmc = OpenNewMBPrintFile (fileName+strlen(workingDir))) == NULL)
			return (ERROR);
        else if (CopyResults(fpMcmc,bkupName+strlen(workingDir),numPreviousGen)==ERROR)
            return (ERROR);
		}

	return (NO_ERROR);
}





int RunChain (SafeLong *seed)

{
	
	int			i, j, n, chn, swapA=0, swapB=0, whichMove, acceptMove;
	int			lastDiagnostics;    // the sample no. when last diagnostic was performed
	int         removeFrom, removeTo=0;
	int 		stopChain, nErrors;
	MrBFlt		r=0.0, lnLikelihoodRatio, lnPriorRatio, lnProposalRatio, lnLike=0.0, lnPrior=0.0, f=0.0, CPUTime;
	MCMCMove	*theMove, *mv;
	time_t		startingT, endingT, stoppingT1, stoppingT2;
	clock_t		previousCPUTime, currentCPUTime;
    /* Stepping-stone sampling variables */
    int         run, samplesCountSS=0, stepIndexSS=0,numGenInStepSS=0, numGenOld, lastStepEndSS=0, numGenInStepBurninSS=0;
    MrBFlt      stepLengthSS=0,meanSS,varSS, *tempX;
    char        ckpFileName[220],bkupFileName[220];


#if defined (BEAGLE_ENABLED)
	int			ResetScalersNeeded;  //set to YES if we need to reset node->scalerNode, used in old style rescaling;
#ifndef NDEBUG
	int			beagleScalingSchemeOld;
#endif
	ModelInfo	*m;
	ResetScalersNeeded = NO;
    
	for (i=0; i<numCurrentDivisions; i++)
		{
		m = &modelSettings[i];
		if(m->useBeagle == NO || beagleScalingScheme == MB_BEAGLE_SCALE_ALWAYS )
			{
			ResetScalersNeeded =YES;
			break;
			}
		}
#endif

#				if defined (MPI_ENABLED)
	int			ierror, sumErrors;
	MrBFlt		best, sum=0.0;
	MPI_Status 	status;
#				endif
#				if defined (DEBUG_RUNCHAIN)
	ModelInfo	*m;
#				endif

	/* set nErrors to 0 */
	nErrors = 0;
	if (numLocalTaxa < 4)
		{
		for (i=0; i<numTrees; i++)
			if (GetTreeFromIndex(i, 0, 0)->isRooted == NO)
				break;
		if (i < numTrees && numLocalTaxa < 4)
			{
			MrBayesPrint ("%s   There must be at least four taxa in the analysis\n", spacer);
			return (ERROR);
			}
		else if (i == numTrees && numLocalTaxa < 3)
			{
			MrBayesPrint ("%s   There must be at least three taxa in the analysis\n", spacer);
			return (ERROR);
			}
		}

	/* Adjust default comparetree file name; we know now how many trees we have */
	if (numTrees > 1 && chainParams.numRuns > 1)
		sprintf (comptreeParams.comptFileName1, "%s.tree1.run1.t", chainParams.chainFileName);
	else if (numTrees > 1 && chainParams.numRuns == 1)
		sprintf (comptreeParams.comptFileName1, "%s.tree1.t", chainParams.chainFileName);
	else if (numTrees == 1 && chainParams.numRuns > 1)
		sprintf (comptreeParams.comptFileName1, "%s.run1.t", chainParams.chainFileName);
	else if (numTrees == 1 && chainParams.numRuns == 1)
		sprintf (comptreeParams.comptFileName1, "%s.t", chainParams.chainFileName);
	strcpy (comptreeParams.comptFileName2, comptreeParams.comptFileName1);

	/* allocate some memory for the chains */
	if (memAllocs[ALLOC_CURLNL] == YES)
		{
		MrBayesPrint ("%s   curLnL is already allocated\n", spacer);
		nErrors++;
		}
	else if ((curLnL = (MrBFlt *)SafeMalloc((size_t) (numLocalChains * sizeof(MrBFlt)))) == NULL)
		{
		MrBayesPrint ("%s   Problem allocating curLnL (%d)\n", spacer, numLocalChains * sizeof(MrBFlt));
		nErrors++;
		}
	else if ((maxLnL0 = (MrBFlt *) SafeCalloc (chainParams.numRuns * chainParams.numChains, sizeof(MrBFlt))) == NULL)
		{
		MrBayesPrint ("%s   Problem allocating maxLnL0\n", spacer, numLocalChains * sizeof(MrBFlt));
		free (curLnL);
		nErrors++;
		}
    else
		memAllocs[ALLOC_CURLNL] = YES;
#	if defined (MPI_ENABLED)
	MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
	if (sumErrors > 0)
		{
		MrBayesPrint ("%s   Memory allocation error on at least one processor\n", spacer);
		return ERROR;
		}
#	else
	if (nErrors > 0)
		return ERROR;
#	endif

	if (memAllocs[ALLOC_CURLNPR] == YES)
		{
		MrBayesPrint ("%s   curLnPr is already allocated\n", spacer);
		nErrors++;
		}
	else if ((curLnPr = (MrBFlt *)SafeMalloc((size_t) (numLocalChains * sizeof(MrBFlt)))) == NULL)
		{
		MrBayesPrint ("%s   Problem allocating curLnPr (%d)\n", spacer, numLocalChains * sizeof(MrBFlt));
		nErrors++;
		}
	else
		memAllocs[ALLOC_CURLNPR] = YES;
#	if defined (MPI_ENABLED)
	MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
	if (sumErrors > 0)
		{
		MrBayesPrint ("%s   Memory allocation error on at least one processor\n", spacer);
		return ERROR;
		}
#	else
	if (nErrors > 0)
		return ERROR;
#	endif

	if (memAllocs[ALLOC_CHAINID] == YES)
		{
		MrBayesPrint ("%s   chainId is already allocated\n", spacer);
		nErrors++;
		}
	else if ((chainId = (int *)SafeMalloc((size_t) (numLocalChains * sizeof(int)))) == NULL)
		{
		MrBayesPrint ("%s   Problem allocating chainId (%d)\n", spacer, numLocalChains * sizeof(int));
		nErrors++;
		}
	else
		memAllocs[ALLOC_CHAINID] = YES;
#	if defined (MPI_ENABLED)
	MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
	if (sumErrors > 0)
		{
		MrBayesPrint ("%s   Memory allocation error on at least one processor\n", spacer);
		return ERROR;
		}
#	else
	if (nErrors > 0)
		return ERROR;
#	endif

	if (memAllocs[ALLOC_SWAPINFO] == YES)
		{
		MrBayesPrint ("%s   swapInfo is already allocated\n", spacer);
		nErrors++;
		}
	else if ((swapInfo = (int ***) SafeCalloc (chainParams.numRuns, sizeof (int **))) == NULL)
		{
		MrBayesPrint ("%s   Problem allocating swapInfo\n", spacer);
		nErrors++;
		}
	else
		{
		for (n=0; n<chainParams.numRuns; n++)
			{
			swapInfo[n] = AllocateSquareIntegerMatrix (chainParams.numChains);
			if (!swapInfo[n])
				{
				MrBayesPrint ("%s   Problem allocating swapInfo[%d]\n", spacer, n);
				for (i=0; i<n; i++)
					free (swapInfo[i]);
				free (swapInfo);
				nErrors++;
				break;
				}
			}
		memAllocs[ALLOC_SWAPINFO] = YES;
		}
#	if defined (MPI_ENABLED)
	MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
	if (sumErrors > 0)
		{
		MrBayesPrint ("%s   Memory allocation error on at least one processor\n", spacer);
		return ERROR;
		}
#	else
	if (nErrors > 0)
		return ERROR;
#	endif

	for (n=0; n<chainParams.numRuns; n++)
		for (i=0; i<chainParams.numChains; i++)
			for (j=0; j<chainParams.numChains; j++)
				swapInfo[n][i][j] = 0;

	/* set up counters for topological convergence diagnostics */
	/* allocate tree used for some topological convergence diagnostics */
	if (chainParams.mcmcDiagn == YES && chainParams.numRuns > 1)
		{
		if (SetUpPartitionCounters () == ERROR)
			nErrors++;
#if defined (MPI_ENABLED)
		if (proc_id == 0)
			{
#endif
		if (chainParams.relativeBurnin == YES)
			{
			/* we have to remove trees later on */
			if (chainParams.saveTrees == YES)
				{
				if (chainParams.treeList)
					nErrors++;
				else 
					{
					chainParams.treeList = (TreeList *) SafeCalloc (chainParams.numRuns*numTopologies, sizeof (TreeList));
					if (!chainParams.treeList)
						nErrors++;
					}
				if (nErrors == 0)
					memAllocs[ALLOC_TREELIST] = YES;
				if (noWarn == YES)
					chainParams.stopTreeGen = (int) (chainParams.numGen * chainParams.burninFraction);
				else
					chainParams.stopTreeGen = chainParams.numGen;
				}
			else /* if (chainParams.saveTrees == NO) */
				{
				chainParams.tFilePos = (fpos_t*) SafeRealloc ((void *)chainParams.tFilePos, chainParams.numRuns*numTopologies*sizeof (fpos_t));
				if (!chainParams.tFilePos)
					nErrors++;
				else
					memAllocs[ALLOC_TFILEPOS] = YES;
				}
			}
#if defined (MPI_ENABLED)
			}
#endif
#		if defined (MPI_ENABLED)
		if (proc_id == 0)
			{
			if ((chainParams.stat = (STATS *) SafeCalloc (numTopologies, sizeof (STATS))) == NULL)
				nErrors++;
			else
				{
				memAllocs[ALLOC_STATS] = YES;
				for (i=0; i<numTopologies; i++)
					chainParams.stat[i].pair = NULL;
				}

			if ((chainParams.dtree = AllocateTree (numLocalTaxa)) == NULL)
				{
				nErrors++;
				}
			else
				memAllocs[ALLOC_DIAGNTREE] = YES;

            if (chainParams.allComps == YES)
				{
				for (i=0; i<numTopologies; i++)
					{
					if ((chainParams.stat[i].pair = AllocateSquareDoubleMatrix (chainParams.numRuns)) == NULL)
						{
						nErrors++;
						break;
						}
					}
				}
			}
		MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
		if (sumErrors > 0)
			{
			MrBayesPrint ("%s   Memory allocation error on at least one processor\n", spacer);
			return ERROR;
			}
#		else
		if ((chainParams.stat = (STATS *) SafeCalloc (numTopologies, sizeof (STATS))) == NULL)
			return ERROR;
		else
			{
			memAllocs[ALLOC_STATS] = YES;
			for (i=0; i<numTopologies; i++)
				chainParams.stat[i].pair = NULL;
			}
		if (chainParams.relativeBurnin == YES)
			{
			if ((chainParams.dtree = AllocateTree (numLocalTaxa)) == NULL)
				{
				MrBayesPrint ("%s   Could not allocate chainParams.dtree in RunChain\n", spacer);
				return ERROR;
				}
			else
				memAllocs[ALLOC_DIAGNTREE] = YES;
			}
		if (chainParams.allComps == YES)
			{
			for (i=0; i<numTopologies; i++)
				{
				if ((chainParams.stat[i].pair = AllocateSquareDoubleMatrix (chainParams.numRuns)) == NULL)
					{
					MrBayesPrint ("%s   Could not allocate chainParams.stat.pair in RunChain\n", spacer);
					return ERROR;
					}
				}
			}
#		endif
		}

	/* get chain IDs */
	SetChainIds ();
	
    /* distribute parameter starting values and tuning parameters for MPI version */
#if defined (MPI_ENABLED)
    RedistributeParamVals();
    RedistributeTuningParams();
#endif

#if defined (TIMING_ANALIZ)
    CPUCondLikeDown = 0;
    CPUScalers = 0;
    CPUScalersRemove = 0;
    CPUCondLikeRoot = 0;
    CPULilklihood = 0;
#endif

    /* initialize likelihoods and prior                  */
	/* touch everything and calculate initial cond likes */
#if defined (BEAGLE_ENABLED)
		if ( ResetScalersNeeded )
			ResetScalers();
#else
			ResetScalers();
#endif
	TouchAllPartitions ();
	for (chn=0; chn<numLocalChains; chn++)
		{
		if (chn % chainParams.numChains == 0)
			{
			if (chainParams.numRuns == 1)
				MrBayesPrint ("\n%s   Initial log likelihoods and log prior probs:\n", spacer);
			else
				MrBayesPrint ("\n%s   Initial log likelihoods and log prior probs for run %d:\n", spacer, chn / chainParams.numChains + 1);
			}
		TouchAllTrees (chn);
		TouchAllCijks (chn);
		curLnL[chn] = LogLike(chn);
		curLnPr[chn] = LogPrior(chn);
		for (i=0; i<numCurrentDivisions; i++)
			{
			if (modelSettings[i].gibbsGamma == YES)
				curLnL[chn] += GibbsSampleGamma (chn, i, seed);
			}
		MrBayesPrint ("%s      Chain %d -- %.6lf -- %.6lf\n", spacer, (chn % chainParams.numChains) + 1, curLnL[chn], curLnPr[chn]);
		}
     MrBayesPrint("\n");

#if defined (MPI_ENABLED)
	if (num_procs > 2)
		MrBayesPrint ("%s   There are %d more chains on other processor(s)\n\n", spacer, numGlobalChains - numLocalChains);
	else if (num_procs==2)
		MrBayesPrint ("%s   There are %d more chains on the other processor\n\n", spacer, numGlobalChains - numLocalChains);
#endif


    /*All steps are assumed to have the same length. */
    if ( chainParams.isSS == YES )
        {
        numGenInStepSS = ( chainParams.numGen - chainParams.burninSS*chainParams.sampleFreq )/ chainParams.numStepsSS;
        numGenInStepSS = chainParams.sampleFreq*(numGenInStepSS/chainParams.sampleFreq); /*make muliple of chainParams.sampleFreq*/
        numGenOld = chainParams.numGen;
        chainParams.numGen = (chainParams.burninSS * chainParams.sampleFreq + chainParams.numStepsSS*numGenInStepSS) ; 
        if(stepRelativeBurninSS==YES)
            numGenInStepBurninSS = ((int)(numGenInStepSS*chainParams.burninFraction / chainParams.sampleFreq))*chainParams.sampleFreq;
        else
            numGenInStepBurninSS = chainParams.chainBurnIn * chainParams.sampleFreq;
        MrBayesPrint ("\n");
        MrBayesPrint ("%s   Starting stepping-stone sampling to estimate marginal likelihood.         \n", spacer);
        MrBayesPrint ("%s   %d steps will be used with %d generations (%d samples) within each step.  \n", spacer, chainParams.numStepsSS, numGenInStepSS, numGenInStepSS/chainParams.sampleFreq );
        MrBayesPrint ("%s   Total of %d generations (%d samples) will be collected while first        \n", spacer, chainParams.numGen, chainParams.numGen/chainParams.sampleFreq );
        MrBayesPrint ("%s   %d generations (%d samples) will be discarded as initial burnin.          \n", spacer, chainParams.burninSS*chainParams.sampleFreq, chainParams.burninSS);
        MrBayesPrint ("%s   Additionally at the begining of each step %d generations (%d samples)     \n", spacer, numGenInStepBurninSS, numGenInStepBurninSS/chainParams.sampleFreq);
        MrBayesPrint ("%s   will be discarded as burnin.  \n", spacer);
        if(chainParams.startFromPriorSS==YES)
            MrBayesPrint ("%s   Sampling from prior to posterior, i.e. first step samples from prior. \n", spacer);
        else
            {
            MrBayesPrint ("%s   Sampling from posterior to prior, i.e. first step samples from close to\n", spacer);
            MrBayesPrint ("%s   posterior.                                                             \n", spacer);
            }
        if( numGenOld != chainParams.numGen)
            {
            MrBayesPrint ("%s   NOTE: Number of generation of each step is reduced to the closest multiple\n", spacer);
            MrBayesPrint ("%s   of sampling frequency. That is why, in total it will be taken %d gene-    \n", spacer, chainParams.numGen ); 
            MrBayesPrint ("%s   rations instead of requested %d.                                          \n", spacer, numGenOld ); 
            }
        MrBayesPrint ("\n");
        if( (numGenInStepSS-numGenInStepBurninSS)/chainParams.sampleFreq < 1  )
            {
            MrBayesPrint ("%s   There is less then one sample in each step of stepping-stone sampling.  \n", spacer);
            MrBayesPrint ("%s   Please adjust burnin, nuber of generations, sampling frequency or       \n", spacer);
            MrBayesPrint ("%s   numnber of step in order to allow at least one sample per step.         \n", spacer);
			return ERROR; /*All MPI run will return here since all of them have the same values*/
            }
        if( numPreviousGen==0 ||  numPreviousGen < chainParams.burninSS * chainParams.sampleFreq )
            {
            lastStepEndSS = chainParams.burninSS * chainParams.sampleFreq;
            stepIndexSS = chainParams.numStepsSS-1;
            if(numPreviousGen != 0)
                removeTo=(numPreviousGen/chainParams.sampleFreq)+1;
            if(chainParams.startFromPriorSS==YES)
                {
                //powerSS = BetaQuantile( chainParams.alphaSS, 1.0, (MrBFlt)(chainParams.numStepsSS-1-stepIndexSS)/(MrBFlt)chainParams.numStepsSS);
                powerSS = 0.0;
                stepLengthSS = BetaQuantile( chainParams.alphaSS, 1.0, (MrBFlt)(chainParams.numStepsSS-stepIndexSS)/(MrBFlt)chainParams.numStepsSS)-powerSS;
                }
            else
                {
                powerSS = BetaQuantile( chainParams.alphaSS, 1.0, (MrBFlt)stepIndexSS/(MrBFlt)chainParams.numStepsSS);
                stepLengthSS = 1.0-powerSS;
                }
            samplesCountSS=0;
            }
        else
            {
            stepIndexSS     = (numPreviousGen-chainParams.burninSS * chainParams.sampleFreq)/numGenInStepSS; /* for now it holds number of steps we fully complited*/
            lastStepEndSS   = chainParams.burninSS * chainParams.sampleFreq + stepIndexSS*numGenInStepSS;
            removeTo        = chainParams.burninSS + (stepIndexSS*numGenInStepSS+numGenInStepBurninSS)/chainParams.sampleFreq + 1;
            if(numPreviousGen < (removeTo-1)*chainParams.sampleFreq)
                removeTo=numPreviousGen/chainParams.sampleFreq+1;
            stepIndexSS     = chainParams.numStepsSS-1-stepIndexSS;
            if(chainParams.startFromPriorSS==YES)
                {
                powerSS = BetaQuantile( chainParams.alphaSS, 1.0, (MrBFlt)(chainParams.numStepsSS-1-stepIndexSS)/(MrBFlt)chainParams.numStepsSS);
                stepLengthSS = BetaQuantile( chainParams.alphaSS, 1.0, (MrBFlt)(chainParams.numStepsSS-stepIndexSS)/(MrBFlt)chainParams.numStepsSS)-powerSS;
                }
            else
                {
                powerSS         = BetaQuantile( chainParams.alphaSS, 1.0, (MrBFlt)stepIndexSS/(MrBFlt)chainParams.numStepsSS);
                stepLengthSS    = BetaQuantile( chainParams.alphaSS, 1.0, (MrBFlt)(stepIndexSS+1)/(MrBFlt)chainParams.numStepsSS)-powerSS;
                }
#ifdef SAMPLE_ALL_SS
            samplesCountSS  = (numPreviousGen-lastStepEndSS-numGenInStepBurninSS);
#else
            samplesCountSS  = (numPreviousGen-lastStepEndSS-numGenInStepBurninSS)/chainParams.sampleFreq;
#endif
            if( samplesCountSS < 0)
                samplesCountSS=0;

            MrBayesPrint("%s   Continue sampling step %d out of %d steps...\n",spacer, chainParams.numStepsSS-stepIndexSS, chainParams.numStepsSS );
            /*marginalLnLSS will be red from file and destributed to other MPI_proc later. stepScalerSS, stepAcumulatorSS are lready red and if(samplesCountSS!=0) they will be redestributed. */
            }

        if( samplesCountSS==0 ) /*in appended case it also can happened*/
            {
            for (run=0; run<chainParams.numRuns; run++)
                {
        	    marginalLnLSS[run] = 0.0;
        	    stepScalerSS[run] = 0.0;
        	    stepAcumulatorSS[run] = 0.0;
                }
 
            for (chn=0; chn<numLocalChains; chn++)
                {
                if (chainId[chn] % chainParams.numChains == 0)
                    {
                    run = chainId[chn] / chainParams.numChains;
                    stepScalerSS[run] = curLnL[chn]*stepLengthSS;
                    }
                }      
            }
        }



    /* Append to previous analysis if this is requested, otherwise just open new print files */
    if (chainParams.append == YES)
        {
#if defined (MPI_ENABLED)
	if (proc_id == 0) {
#endif

    /* We get the number of samples in i */
        if (ReusePreviousResults(&i, chainParams.numStepsSS-stepIndexSS-1) == ERROR)
            nErrors++;
        else if (chainParams.numRuns > 1)    /* we potentially need to add tree samples for conv diagn */
            {
            /* Add tree samples to partition counters */
            if ( chainParams.relativeBurnin == YES )
                {
                if( chainParams.isSS == NO )
                    {
                    if (numPreviousGen/(i-1) != chainParams.sampleFreq)
                        {
                        MrBayesPrint ("%s   You have to use the same sampling frequency as in the old run to use relative burnin\n", spacer);
                        nErrors++;
                        }
                    else
                        {
                        if (noWarn == YES)
                            {
                            /* We definitely know the final number of generations */
                            j = (chainParams.numGen/chainParams.sampleFreq)+1;
                            j = (int) (j*chainParams.burninFraction);
                            }
                        else /* User may extend chain so save all trees if saving trees */
                            j = i;
                        if (j < i)
                            {
                            if (AddTreeSamples(1,j,chainParams.saveTrees) == ERROR) nErrors++;
                            if (AddTreeSamples(j+1,i,NO) == ERROR) nErrors++; /*since we never need to remove trees from partition counter after total burnin we put NO in the last argument. */
                            }
                        else
                            {
                            if (AddTreeSamples(1,i,chainParams.saveTrees) == ERROR) nErrors++;
                            }
                        }
                    }
                else
                    {
                    if (numPreviousGen/(i-1) != chainParams.sampleFreq)
                        {
                        MrBayesPrint ("%s   You have to use the same sampling frequency as in the old run to append to the SS run\n", spacer);
                        nErrors++;
                        }
                    else
                        {
                        
                        if (setFilePositions(removeTo) == ERROR) nErrors++;
                        if (AddTreeSamples(removeTo+1,i,chainParams.saveTrees) == ERROR) nErrors++;
                        }
                    }
                }
            else if (chainParams.chainBurnIn < numPreviousGen)
                if (AddTreeSamples((int)(i*(chainParams.chainBurnIn/(MrBFlt)(numPreviousGen)))+1,i,chainParams.saveTrees) == ERROR) nErrors++;
            }
        if (nErrors == 0)
            {
            if (chainParams.isSS == NO && chainParams.mcmcDiagn == YES && chainParams.numRuns > 1)
                {
                MrBayesPrint ("\n");
                if (chainParams.relativeBurnin == YES)
                    MrBayesPrint ("%s   Using a relative burnin of %.1f %% for diagnostics\n", spacer, 100.0*chainParams.burninFraction);
                else
                    MrBayesPrint ("%s   Using an absolute burnin of %d samples for diagnostics\n", spacer, chainParams.chainBurnIn);
                }
            MrBayesPrint ("\n");
		    MrBayesPrint ("%s   Chain results (continued from previous run; %d generations requested):\n\n", spacer, chainParams.numGen);
            }
#if defined (MPI_ENABLED)
        }
#endif

        if (chainParams.autotune == YES)
            {
            for (i=0; i<numLocalChains; i++)
                {
                for (j=0; j<numUsedMoves; j++)
                    {
                    if (j==0)
                        f = usedMoves[j]->cumProposalProb[chainId[i]];
                    else
                        f = usedMoves[j]->cumProposalProb[chainId[i]] - usedMoves[j-1]->cumProposalProb[chainId[i]];
                    if (usedMoves[j]->targetRate[chainId[i]] > 0.0)
                        {
                        /* autotuned move; we assume it was perfectly tuned and start tuning from there at appropriate rate */
                        usedMoves[j]->nBatches[chainId[i]] = (int) (f*numPreviousGen/chainParams.tuneFreq);
                        usedMoves[j]->lastAcceptanceRate[chainId[i]] = usedMoves[j]->targetRate[chainId[i]];
                        }
                    else
                        {
                        /* not autotuned move; no previous batches will result in acceptance rate calculated from new samples */
                        usedMoves[j]->nBatches[chainId[i]] = 0;
                        usedMoves[j]->lastAcceptanceRate[chainId[i]] = 0.0;
                        }
                    }
                }
            }
#if defined (MPI_ENABLED)
        if ( chainParams.isSS == YES )
            {
            MPI_Bcast ( marginalLnLSS, chainParams.numRuns, MPI_DOUBLE, 0, MPI_COMM_WORLD);

            if( samplesCountSS != 0)
                {
                MPI_Bcast ( stepScalerSS, chainParams.numRuns, MPI_DOUBLE, 0, MPI_COMM_WORLD);
                MPI_Bcast ( stepAcumulatorSS, chainParams.numRuns, MPI_DOUBLE, 0, MPI_COMM_WORLD);
                }
            /*Set to zero all runs that we are not responsable for*/
            for (run=0; run<chainParams.numRuns; run++)
                {
                for (chn=0; chn<numLocalChains; chn++)
                    {
                    if (chainId[chn] % chainParams.numChains == 0 && run == chainId[chn] / chainParams.numChains )
                        break;
                    }
                if(chn<numLocalChains)
                    continue;

                marginalLnLSS[run] = 0.0;
    	        stepScalerSS[run] = 0.0;
    	        stepAcumulatorSS[run] = 0.0;    
                }
            }

        MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
        if (sumErrors > 0)
            {
            MrBayesPrint ("%s    Error appending to previous run\n", spacer);
            return ERROR;
            }            
#	else
        if (nErrors == 1)
	        {
	        MrBayesPrint ("%s    Error appending to previous run\n", spacer);
	        return ERROR;
	        }
#	endif
        }
    else
        {
        if (PreparePrintFiles() == ERROR)
		    nErrors++;
        }

#	if defined (MPI_ENABLED)
	MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
	if (sumErrors > 0)
		{
		MrBayesPrint ("%s   Error preparing print files on at least one processor\n", spacer);
        CloseMBPrintFiles();
		return ERROR;
		}
#	else
	if (nErrors > 0)
		{
		MrBayesPrint ("%s   Error preparing print files\n", spacer);
        CloseMBPrintFiles();
        return ERROR;
		}
#	endif

	if (chainParams.relativeBurnin == NO)
		lastDiagnostics = chainParams.chainBurnIn;
	else
		lastDiagnostics = 0;
	stopChain = NO;

	for (i=0; i<chainParams.numRuns; i++)
		maxLnL0[i] = -100000000.0;

	startingT=time(0);
	CPUTime = 0.0;
	previousCPUTime = clock();



    /* print headers and starting states */
    if( numPreviousGen==0 )
        {
        /* make sure we print headers */
		PrintToScreen(0, 0, time(0), startingT);
		if (PrintStatesToFiles (0) == ERROR)
			{
            MrBayesPrint("%s   Error in printing headers to files\n");
# if defined (MPI_ENABLED)
			nErrors++;
# else
			return ERROR;
# endif
			}
# if defined (MPI_ENABLED)
		MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
		if (sumErrors > 0)
            {
			MrBayesPrint ("%s   Aborting run.\n");
            return ERROR;
            }
# endif

        if( chainParams.mcmcDiagn == YES )
        {
            if (PrintMCMCDiagnosticsToFile (0) == ERROR)
                {
			    MrBayesPrint ("%s   Problem printing mcmc diagnostics headers to file\n", spacer);
# if defined (MPI_ENABLED)
			    nErrors++;
# else
                return (ERROR);
# endif
                }
# if defined (MPI_ENABLED)
            MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
		    if (sumErrors > 0)
			    {
                MrBayesPrint ("%s   Aborting run.\n");
			    return ERROR;
			    }
# endif
        
         if( chainParams.isSS == YES && chainParams.burninSS == 0 && chainParams.numRuns > 1 )
            { 
            /* Remove first sample (generation 0) from diagnostics */
            removeTo=1;
            if ( RemoveTreeSamples ( 1,1 ) == ERROR)
					{
             	  	 MrBayesPrint("%s   Problem removing tree samples\n");
#				      		  if defined (MPI_ENABLED)
		     		   nErrors++;
#	        	      		  else
		      		  return ERROR;
#                     		  endif
                	}
#               if defined (MPI_ENABLED)
            MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
            if (sumErrors > 0)
                {
	            MrBayesPrint ("%s   Aborting run.\n");
                return ERROR;
                }
#			    endif
            }
        }
        if( chainParams.isSS == YES)
            {
            if(chainParams.burninSS == 0 )
                MrBayesPrint("%s   Sampling step 1 out of %d steps...\n\n",spacer, chainParams.numStepsSS );

            /*Printing SS header*/
            MrBayesPrintf (fpSS, "[LEGEND: The file contains statistics on the Steppingstone Sampling. ]\n");
            MrBayesPrintf (fpSS, "[ID: %s]\n", stamp);
            MrBayesPrintf (fpSS, "[   Step                --  Index of the step ]\n");
            MrBayesPrintf (fpSS, "[   Power               --  At each step we sample from the distribution with density (Likelihood^Power)*Prior ]\n");
            MrBayesPrintf (fpSS, "[   runX                --  Contribution to the marginal log likelihood of run X, i.e. marginal log likelihood for run X is the sum across all steps in column runX.   ]\n");
            if (chainParams.diagnStat == AVGSTDDEV)
                MrBayesPrintf (fpSS, "[   aSplitX             --  Average standard deviation of split frequencies of tree X. -2.0 is printed if no diagnostics was requested. -1.0 is printed if there were no splits with frequency above minimum.]\n");
            else
                MrBayesPrintf (fpSS, "[   mSplitX             --  Maximal standard deviation of split frequencies of tree X. -2.0 is printed if no diagnostics was requested. -1.0 is printed if there were no splits with frequency above minimum.]\n");
            MrBayesPrintf (fpSS, "Step\tPower");
            for (j=0; j<chainParams.numRuns ; j++)
                MrBayesPrintf (fpSS, "\trun%d", j+1);
            if (chainParams.diagnStat == AVGSTDDEV)
                {
                for (j=0; j<numTopologies; j++)
                    MrBayesPrintf (fpSS, "\taSplit%d", j);
                }
            else
                {
                for (j=0; j<numTopologies; j++)
                    MrBayesPrintf (fpSS, "\tmSplit%d", j);
                }
            MrBayesPrintf (fpSS, "\n");
            }
    }

    for (n=numPreviousGen+1; n<=chainParams.numGen; n++) /* begin run chain */
		{
		currentCPUTime = clock();
		if (currentCPUTime - previousCPUTime > 10 * CLOCKS_PER_SEC)
			{
			CPUTime += (currentCPUTime - previousCPUTime) / (MrBFlt) (CLOCKS_PER_SEC);
			previousCPUTime = currentCPUTime;
			}

		/*! requestAbortRun is set by the signal handler when it receives a CTRL-C (serial version only) */
		if (requestAbortRun == YES && ConfirmAbortRun() == 1)
			return ABORT;

        /* Refresh scalers every SCALER_REFRESH_FREQ generations.                */
		/* It is done before copying so we know it will take effect immediately. */
		/* However, the actual scalers are recalculated only when really needed. */
#if defined (BEAGLE_ENABLED)
		if ( ResetScalersNeeded && n % SCALER_REFRESH_FREQ == 0)
			ResetScalers();
#else
		if (n % SCALER_REFRESH_FREQ == 0)
			ResetScalers();
#endif

        for (chn=0; chn<numLocalChains; chn++)
			{

            /* Do Gibbs resampling of rate categories for current state if time to do so */
			for (i=0; i<numCurrentDivisions; i++)
				{
				if (modelSettings[i].gibbsGamma == YES && n % modelSettings[i].gibbsFreq == 0)
					curLnL[chn] += GibbsSampleGamma (chn, i, seed);
				}

			/* First copy everything from current state of chain to new state.   */
			/* The global variable state[chain] gives state.                     */

            /* copy all touched trees and reset update flags                     */
			CopyTrees (chn);

            /* copy all model parameters */
			CopyParams (chn);

			/* shift the state of the chain to the new state */
			/* all calculations will be done on this state   */
			state[chn] ^= 1;  /* XORing with 1 switches between 0 and 1 */

#if ! defined (NDEBUG) && defined (DEBUG_SLOW)
            TouchAllTrees(chn);
            TouchAllPartitions();
			if (fabs((curLnL[chn]-(lnProposalRatio=LogLike(chn)))/curLnL[chn]) > 0.0001)
                puts("Liklihood of current state is not correct");
            ResetFlips(chn);
            state[chn] ^= 1;
            CopyTrees (chn);
            CopyParams (chn);
            state[chn] ^= 1;
#endif


            /* decide which move to make */
            whichMove = PickProposal(seed, chainId[chn]);
            theMove = usedMoves[whichMove];
#if defined SHOW_MOVE
            printf ("Making move '%s'\n", theMove->name);
#endif

#if defined (BEST_MPI_ENABLED)
            bestCycleGen = n % (numNonTreeMoves + numTreeMoves + numBestMoves);
            if (bestCycleGen < numNonTreeMoves)
                PickNonTreeProposal(seed, chainId[chn]);
            else if (bestCycleGen < numNonTreeMoves + numTreeMoves)
                PickTreeProposal(seed, chainId[chn]);
            else
                PickBestProposal(chainId[chn]);
#endif

            /* set prior and proposal ratios */
			lnProposalRatio = 0.0;
			lnPriorRatio = 0.0;

			/* reset abort move flag */
			abortMove = NO;
			
			/* Touch the relevant partitions       */
			/* as a service to the move functions. */
			for (i=0; i<theMove->parm->nRelParts; i++)
				modelSettings[theMove->parm->relParts[i]].upDateCl = YES;

			/* TouchAllPartitions(); */    /* for debugging copying shortcuts [SLOW!!]*/

            /* make move */
#if ! defined (NDEBUG)
            if (IsTreeConsistent(theMove->parm, chn, state[chn]) != YES)
                {
                printf ("IsTreeConsistent failed before move!\n");
                return ERROR;
                }
            if (theMove->parm->paramType == P_TOPOLOGY && DoesTreeSatisfyConstraints(GetTree (theMove->parm, chn, state[chn]))!=YES)
                {
                printf ("DEBUG ERROR: DoesTreeSatisfyConstraints failed before a move\n");
                return ERROR;
                }
#endif
			if ((theMove->moveFxn)(theMove->parm, chn, seed, &lnPriorRatio, &lnProposalRatio, theMove->tuningParam[chainId[chn]]) == ERROR)
				{
				MrBayesPrint ("%s   Error in move %s\n", spacer, theMove->name);
#				if defined (MPI_ENABLED)
				nErrors++;
#				else
				return ERROR;
#				endif
				}

            if (theMove->parm->paramType == P_TOPOLOGY && DoesTreeSatisfyConstraints(GetTree (theMove->parm, chn, state[chn]))!=YES)
                {
#if ! defined (NDEBUG)
            	if(DoesTreeSatisfyConstraints(GetTree (theMove->parm, chn, state[chn]))==ABORT)
            		{
            		printf ("DEBUG ERROR: After move '%s'\n", theMove->name);
            		}

#endif
                abortMove= YES;
                }

            /* calculate likelihood ratio */
            if (abortMove == NO)
				{
                lnLike = LogLike(chn);
                lnLikelihoodRatio = lnLike - curLnL[chn];
				lnPrior = curLnPr[chn] + lnPriorRatio;

#if ! defined (NDEBUG)
                /* We check various aspects of calculations in debug version of code */
                if (IsTreeConsistent(theMove->parm, chn, state[chn]) != YES)
                    {
                    printf ("DEBUG ERROR: IsTreeConsistent failed after move '%s'\n", theMove->name);
                    return ERROR;
                    }
                if (lnPriorRatio != lnPriorRatio)
                    {
                    printf ("DEBUG ERROR: Log prior ratio nan after move '%s'\n", theMove->name);
                    return ERROR;
                    }
                if (fabs((lnPrior-LogPrior(chn))/lnPrior) > 0.0001)
                    {
                        printf ("DEBUG ERROR: Log prior incorrect after move '%s' :%e :%e\n", theMove->name,lnPrior,LogPrior(chn));
                    return ERROR;
                    }
                ResetFlips(chn);
                TouchAllTrees(chn);
                if (fabs((lnLike-LogLike(chn))/lnLike) > 0.0001)
                    {
                    printf ("DEBUG ERROR: Log likelihood incorrect after move '%s'\n", theMove->name);
                    return ERROR;
                    }
                if (theMove->parm->paramType == P_TOPOLOGY && GetTree (theMove->parm, chn, state[chn])->isClock == YES && IsClockSatisfied (GetTree (theMove->parm, chn, state[chn]),0.001) == NO)
					{
					MrBayesPrint ("%s   Branch lengths of the tree does not satisfy to be a clock tree.\n", spacer);
					ShowNodes(GetTree (theMove->parm, chn, state[chn])->root,0,YES);
					return (ERROR);
					}
				
#endif

                /* heat */
                lnLikelihoodRatio *= Temperature (chainId[chn]);
				lnPriorRatio      *= Temperature (chainId[chn]);

                if( chainParams.isSS == YES )
                    lnLikelihoodRatio *= powerSS;

                /* calculate the acceptance probability */
				if (lnLikelihoodRatio + lnPriorRatio + lnProposalRatio < -100.0)
					r = 0.0;
				else if (lnLikelihoodRatio + lnPriorRatio + lnProposalRatio > 0.0)
					r = 1.0;
				else
					r = exp(lnLikelihoodRatio + lnPriorRatio + lnProposalRatio);
				}

			/* decide to accept or reject the move */
			acceptMove = NO;
			i = chainId[chn];
            theMove->nTried[i]++;
            theMove->nTotTried[i]++;
            if ( abortMove == NO && RandomNumber(seed) < r)
				{
				acceptMove = YES;
                theMove->nAccepted[i]++;
                theMove->nTotAccepted[i]++;
                }

            /* update the chain */
            if (acceptMove == NO)
				{
				/* the new state did not work out so shift chain back */
				if (abortMove == NO)
					ResetFlips(chn);
				state[chn] ^= 1;
#if defined (BEAGLE_ENABLED)
				if ( recalcScalers == YES )
					{
					recalculateScalers( chn );
					recalcScalers = NO;
					}
#endif
				}
			else
				{
				/* if the move is accepted then let the chain stay in the new state */
				/* store the likelihood and prior of the chain */
                curLnL[chn] = lnLike;
				curLnPr[chn] = lnPrior;
				}

            /* check if time to autotune */
            if (theMove->nTried[i] >= chainParams.tuneFreq)
                {
                theMove->lastAcceptanceRate[i] = (MrBFlt) theMove->nAccepted[i] / (MrBFlt) theMove->nTried[i];
                theMove->nTried[i] = 0;
                theMove->nAccepted[i] = 0;
                theMove->nBatches[i]++;
                if (chainParams.autotune == YES && theMove->moveType->Autotune != NULL)
                    {
                    theMove->moveType->Autotune(theMove->lastAcceptanceRate[i],
                                                theMove->targetRate[i],
                                                theMove->nBatches[i],
                                                &theMove->tuningParam[i][0],
                                                theMove->moveType->minimum[0],
                                                theMove->moveType->maximum[0]);
                    }
                }

            /*ShowValuesForChain (chn); */

			if (curLnL[chn] > maxLnL0[chainId[chn]])
				maxLnL0[chainId[chn]] = curLnL[chn];

            }


        /* attempt swap(s) Non-blocking for MPI if no swap with external process. */
		if (chainParams.numChains > 1 && n % chainParams.swapFreq == 0)
			{
			for (i = 0; i<chainParams.numRuns; i++)
				{
				for (j = 0; j<chainParams.numSwaps; j++)
				    GetSwappers (&swapA, &swapB, i);
				if (AttemptSwap (swapA, swapB, seed) == ERROR)
					{
					MrBayesPrint ("%s   Unsuccessful swap of states\n", spacer);
#					if defined (MPI_ENABLED)
					nErrors++;
#					else
					return ERROR;
#					endif
					}
				}
			}

        /* print information to screen . Non-blocking for MPI*/
        if ( n % chainParams.printFreq == 0)
            {
			PrintToScreen(n, numPreviousGen, time(0), startingT);
#if defined (TIMING_ANALIZ)
            MrBayesPrint ("%s   Time elapsed:%f CondlikeDownTime:%f CondLikeRoot:%f Lilklihood:%f ScalersTime:%f ScalersRemove:%f\n", spacer, CPUTime,CPUCondLikeDown/(MrBFlt) CLOCKS_PER_SEC,CPUCondLikeRoot/(MrBFlt) CLOCKS_PER_SEC,CPULilklihood/(MrBFlt) CLOCKS_PER_SEC, CPUScalers/(MrBFlt) CLOCKS_PER_SEC, CPUScalersRemove/(MrBFlt) CLOCKS_PER_SEC);
#endif
            }

        /* print information to files */
		/* this will also add tree samples to topological convergence diagnostic counters */
		if ( n == chainParams.numGen || n % chainParams.sampleFreq == 0)
			{
#			if defined (MPI_ENABLED)
			MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
			if (sumErrors > 0)
                {
				MrBayesPrint ("%s   Aborting run.\n");
                return ERROR;
                }
#			endif
			if (PrintStatesToFiles (n) == ERROR)
				{
                MrBayesPrint("%s   Error in printing states to files\n");
#				if defined (MPI_ENABLED)
				nErrors++;
#				else
				return ERROR;
#				endif
				}
#			if defined (MPI_ENABLED)
			MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
			if (sumErrors > 0)
                {
				MrBayesPrint ("%s   Aborting run.\n");
                return ERROR;
                }
#			endif
			}


        /* print mcmc diagnostics. Blocking for MPI*/
		if ( chainParams.mcmcDiagn == YES && ((n % chainParams.diagnFreq == 0 || n == chainParams.numGen)
                                             || ( chainParams.isSS == YES && ( n-lastStepEndSS ) % numGenInStepSS == 0 ) ) )
			{
			if (chainParams.numRuns > 1 && ((n > 0 && chainParams.relativeBurnin == YES && (chainParams.isSS == NO || (n > chainParams.burninSS * chainParams.sampleFreq && ( n-lastStepEndSS )> numGenInStepBurninSS ) ))
				                            || (n >= chainParams.chainBurnIn * chainParams.sampleFreq && chainParams.relativeBurnin == NO)))
				{
				/* we need some space for coming output */
				MrBayesPrint ("\n");
				/* remove tree samples if using burninpercentage */
				/* the following function returns immediately in MPI if proc_id != 0 */
				if (chainParams.relativeBurnin == YES && chainParams.isSS == NO )
					{
					removeFrom = removeTo;
					removeTo = (int)(chainParams.burninFraction * (n/chainParams.sampleFreq+1)); /* (n/chainParams.sampleFreq+1) is the current number of samples */
					if( removeFrom < removeTo )
						{
						if ( RemoveTreeSamples (removeFrom+1, removeTo ) == ERROR)
							{
                     	  	 MrBayesPrint("%s   Problem removing tree samples\n");
#				      		  if defined (MPI_ENABLED)
				     		   nErrors++;
#	        	      		  else
				      		  return ERROR;
#                     		  endif
                        	}
						}
#                   if defined (MPI_ENABLED)
			        MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
			        if (sumErrors > 0)
                        {
				        MrBayesPrint ("%s   Aborting run.\n");
                        return ERROR;
                        }
#			        endif
					}

				lastDiagnostics = (n/chainParams.sampleFreq)+1; /* +1 because we always have start tree sampled*/
				if ( chainParams.relativeBurnin == YES )
					{
					i = lastDiagnostics - removeTo;
					}
				else
					i = lastDiagnostics - chainParams.chainBurnIn;
#				if defined (MPI_ENABLED)
				if (proc_id == 0)
					{
#				endif
				/* calculate statistics */
				CalculateTopConvDiagn (i);
				/* output statistics */
				if (numTopologies == 1)
					{
                    f=-1.0;
                    if (chainParams.stat[0].numPartitions == 0)
                        {
    					MrBayesPrint ("%s   Average standard deviation of split frequencies: NA (no splits above min. frequency)\n", spacer);
                        }
					else if (chainParams.diagnStat == AVGSTDDEV)
                        {
						f = chainParams.stat[0].avgStdDev;
    					MrBayesPrint ("%s   Average standard deviation of split frequencies: %.6f\n", spacer, f);
                        }
					else
                        {
						f = chainParams.stat[0].max;
    					MrBayesPrint ("%s   Max standard deviation of split frequencies: %.6f\n", spacer, f);
                        }
                    if ( chainParams.isSS == YES )
                        splitfreqSS[chainParams.numStepsSS-stepIndexSS-1] = f;
					if (chainParams.stat[0].numPartitions > 0 && f <= chainParams.stopVal)
						stopChain = YES;
					if (n < chainParams.numGen - chainParams.printFreq && (chainParams.stopRule == NO || stopChain == NO))
						MrBayesPrint ("\n");
					}
				else
					{
					stopChain = YES;
					for (i=0; i<numTopologies; i++)
						{
                        f=-1.0;
                        if (chainParams.stat[i].numPartitions == 0)
                            {
    					    MrBayesPrint ("%s   Average standard deviation of split frequencies for topology %d: NA (no splits above min. frequency)\n", spacer, i+1);
                            }
						else if (chainParams.diagnStat == AVGSTDDEV)
                            {
							f = chainParams.stat[i].avgStdDev;
    						MrBayesPrint ("%s   Average standard deviation of split frequencies for topology %d: %.6f\n", spacer, i+1, f);
                            }
						else
                            {
							f = chainParams.stat[i].max;
    						MrBayesPrint ("%s   Max standard deviation of split frequencies for topology %d: %.6f\n", spacer, i+1, f);
                            }
                        if ( chainParams.isSS == YES )
                            splitfreqSS[i*chainParams.numStepsSS+chainParams.numStepsSS-stepIndexSS-1] = f;
                        if (chainParams.stat[i].numPartitions == 0 && f > chainParams.stopVal)
							stopChain = NO;
						}
					if (n < chainParams.numGen - chainParams.printFreq && (chainParams.stopRule == NO || stopChain == NO))
						MrBayesPrint ("\n");
					}
				if (chainParams.allComps == YES)
					PrintTopConvInfo ();
#				if defined (MPI_ENABLED)
					}
				ierror = MPI_Bcast (&stopChain, 1, MPI_INT, 0, MPI_COMM_WORLD);
				if (ierror != MPI_SUCCESS)
					{
					MrBayesPrint ("%s   Problem broadcasting stop value\n", spacer);
					nErrors++;
					}
#				endif
				}

            /* part of the following function needs to be performed by all MPI processors. Blocking for MPI. */
			if (PrintMCMCDiagnosticsToFile (n) == ERROR)
                {
				MrBayesPrint ("%s   Problem printing mcmc diagnostics to file\n", spacer);
#               if defined (MPI_ENABLED)
				nErrors++;
#               else
                return (ERROR);
#               endif
                }
#           if defined (MPI_ENABLED)
            MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
			if (sumErrors > 0)
				{
                MrBayesPrint ("%s   Aborting run.\n");
				return ERROR;
				}
#			endif
			}

        /* check if time to break because stopVal reached */
		if ( chainParams.isSS == NO && (chainParams.stopRule == YES && stopChain == YES ) )
			{
			MrBayesPrint ("\n%s   Analysis stopped because convergence diagnostic hit stop value.\n", spacer);
			break;
			}
			
		/* user may want to extend chain */
		if (chainParams.isSS == NO && ( n == chainParams.numGen && autoClose == NO ))
			{
			  stoppingT1 = time(0); 
			  currentCPUTime = clock();
			  CPUTime += (currentCPUTime - previousCPUTime) / (MrBFlt) CLOCKS_PER_SEC;
			  previousCPUTime = currentCPUTime;
			  chainParams.numGen += ExtendChainQuery ();
			  stoppingT2 = time(0);
			  startingT += (stoppingT2-stoppingT1);
			  previousCPUTime = clock();
			  /* timers should not be increased during the wait for a reply */
			}

        /* Do stepping sampling staf if needed */
        if ( chainParams.isSS == YES && n >= chainParams.burninSS*chainParams.sampleFreq )
            {
#ifndef SAMPLE_ALL_SS
            if(( n-lastStepEndSS ) % chainParams.sampleFreq == 0 )
#endif
                {
                if(  n > chainParams.burninSS*chainParams.sampleFreq &&  ( n-lastStepEndSS > numGenInStepBurninSS) )
                    { /* do sampling*/
                    for (chn=0; chn<numLocalChains; chn++)
		                {
                        if (chainId[chn] % chainParams.numChains == 0)
                            {
                            run = chainId[chn] / chainParams.numChains;
                            if( curLnL[chn]*stepLengthSS > stepScalerSS[run] + 200.0 )
                                {
                                // adjust scaler;
                                stepAcumulatorSS[run] /= exp( curLnL[chn]*stepLengthSS - 100.0 - stepScalerSS[run] ); 
                                stepScalerSS[run]= curLnL[chn]*stepLengthSS - 100.0;
                                }
                            stepAcumulatorSS[run] += exp( curLnL[chn]*stepLengthSS - stepScalerSS[run] );
                            }
                        }
                    samplesCountSS++;
                    }
                }

            if( ( n-lastStepEndSS ) == numGenInStepBurninSS )
                {
                /* Remove all previouse samples from diagnostics */
                if( chainParams.mcmcDiagn == YES && chainParams.numRuns > 1 )
                    {
				    removeFrom = removeTo;
				    removeTo = (int)(n/chainParams.sampleFreq); /* (n/chainParams.sampleFreq+1) is the current number of samples including 0 one*/
                    removeTo++;
				    if( removeFrom < removeTo )
					    {
					    if ( RemoveTreeSamples ( removeFrom+1, removeTo ) == ERROR)
						    {
                            nErrors++;
                            }
                        ERROR_TEST2("Problem removing tree samples",return(ERROR),);
                        }
                    }               
                } 

            if( ( n-lastStepEndSS ) % numGenInStepSS == 0 )      /* prepare sample of next step */
                {
                assert( n-lastStepEndSS <= numGenInStepSS );
                lastStepEndSS=n;

                if( n > chainParams.burninSS*chainParams.sampleFreq )
                    {
                    /* dump to file current step contribution */
                    MrBayesPrintf (fpSS, "%3d\t%.4f", chainParams.numStepsSS-stepIndexSS, powerSS);
#                   if defined (MPI_ENABLED)
    	            for (j=0; j<chainParams.numRuns ; j++)
			            {
                        if( stepAcumulatorSS[j]==0 )
                            r=0;
                        else
                            r = log( stepAcumulatorSS[j]/samplesCountSS ) + stepScalerSS[j];
			            ierror = MPI_Reduce (&r,&sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
			            if (ierror != MPI_SUCCESS)
				            {
				            MrBayesPrint ("%s   Problem with MPI_Reduce\n", spacer);
				            return ERROR;
				            }
	    	            if(proc_id == 0 )
	    		            {
	    		            MrBayesPrintf (fpSS, "\t%.6f", sum);
	    		            }
			            }
#			        else
                    for (j=0; j<chainParams.numRuns ; j++)
			            {
                        MrBayesPrintf (fpSS, "\t%.6f", log( stepAcumulatorSS[j]/samplesCountSS ) + stepScalerSS[j]);
                        }
#                   endif
                    if( chainParams.mcmcDiagn == YES && chainParams.numRuns > 1 )
                        {
					    for (i=0; i<numTopologies; i++)
						    {
                            MrBayesPrintf (fpSS, "\t%.6f",splitfreqSS[i*chainParams.numStepsSS+chainParams.numStepsSS-stepIndexSS-1]);
						    }
                        }
                    else{
                        for (i=0; i<numTopologies; i++)
						    {
                            MrBayesPrintf (fpSS, "\t-2.0");
						    }

                        }

                    MrBayesPrintf (fpSS, "\n");
                    fflush (fpSS);

                    stepIndexSS--;

                    if(chainParams.startFromPriorSS==YES)
                        {
                        powerSS = BetaQuantile( chainParams.alphaSS, 1.0, (MrBFlt)(chainParams.numStepsSS-1-stepIndexSS)/(MrBFlt)chainParams.numStepsSS);
                        stepLengthSS = BetaQuantile( chainParams.alphaSS, 1.0, (MrBFlt)(chainParams.numStepsSS-stepIndexSS)/(MrBFlt)chainParams.numStepsSS)-powerSS;
                        }
                    else
                        {
                        stepLengthSS = powerSS; 
                        powerSS = BetaQuantile ( chainParams.alphaSS, 1.0, (MrBFlt)stepIndexSS/(MrBFlt)chainParams.numStepsSS);
                        stepLengthSS -= powerSS;
                        }
                    if ( n != chainParams.numGen )
                        MrBayesPrint("%s   Sampling step %d out of %d steps...\n\n",spacer, chainParams.numStepsSS-stepIndexSS, chainParams.numStepsSS );
                    for (chn=0; chn<numLocalChains; chn++)
		                {
                        if (chainId[chn] % chainParams.numChains == 0)
                            {
                            run = chainId[chn] / chainParams.numChains;
                            if( samplesCountSS != 0 )
                                marginalLnLSS[run] += log( stepAcumulatorSS[run]/samplesCountSS ) + stepScalerSS[run];
                            stepScalerSS[run] = curLnL[chn]*stepLengthSS;
                            stepAcumulatorSS[run]=0.0;
                            }
                        }
                    samplesCountSS=0;
                    }
                else
                    {
                    MrBayesPrint("\n%s   Sampling step 1 out of %d steps...\n\n",spacer, chainParams.numStepsSS );
                    }

                    if( chainParams.backupCheckSS !=0 && (chainParams.numStepsSS-stepIndexSS-1)% chainParams.backupCheckSS == 0 )
                        {
                        /* print check-point file. Blocking for MPI*/

                        ERROR_TEST2("Error before printing checkpoint",return(ERROR),);
		                if (PrintCheckPoint (n) == ERROR)
                            {
			                nErrors++;
                            }
                        ERROR_TEST2("Error in printing checkpoint",return(ERROR),);
		               
#if defined (MPI_ENABLED)
	            if (proc_id == 0)
		                {
#endif
                                
		                /* figure out check-point file names */
                        sprintf (ckpFileName, "%s%s.ckp", workingDir, chainParams.chainFileName);
                        sprintf (bkupFileName,"%s.ss%d", ckpFileName,chainParams.numStepsSS-stepIndexSS);	                
                        if(rename (ckpFileName, bkupFileName)!=0)
                            {
                            MrBayesPrint ("%s   Could not rename file %s to %s\n", spacer, ckpFileName, bkupFileName);
                            return ERROR;
                            }
                        strcpy (bkupFileName, ckpFileName);
		                strcat (bkupFileName, "~");
                        rename (bkupFileName,ckpFileName);
#if defined (MPI_ENABLED)
	                    } /* end of if(proc_id == 0)*/
#endif
                        
                        }
                }             
            }


        /* print check-point file. Blocking for MPI*/
		if (chainParams.checkPoint == YES && (n % chainParams.checkFreq == 0))
			{
            ERROR_TEST2("Error before printing checkpoint",return(ERROR),);
			if (PrintCheckPoint (n) == ERROR)
                {
				nErrors++;
                }
            ERROR_TEST2("Error in printing checkpoint",return(ERROR),);
			}




		} /* end run chain */
	endingT = time(0);
	currentCPUTime = clock();
	CPUTime += (currentCPUTime - previousCPUTime) / (MrBFlt) CLOCKS_PER_SEC;

	CloseMBPrintFiles (); /* redundant because files closed in FreeChainMemory but kept here as a safeguard in case of future changes */

#if defined (BEAGLE_ENABLED)
#ifndef NDEBUG 
	ResetScalers ();
	beagleScalingSchemeOld = beagleScalingScheme;
	beagleScalingScheme = MB_BEAGLE_SCALE_ALWAYS;
	for (chn=0; chn<numLocalChains; chn++)
		{
		if (chn % chainParams.numChains == 0)
			{
			if (chainParams.numRuns == 1)
				MrBayesPrint ("%s   Final log likelihoods and log prior probs (stored and calculated):\n", spacer);
			else
				MrBayesPrint ("%s   Final log likelihoods and log prior probs for run %d (stored and calculated):\n", spacer, chn / chainParams.numChains + 1);
			}
		TouchAllPartitions();
        TouchAllTrees (chn);
		TouchAllCijks (chn);
		for (i=0; i<numCurrentDivisions; i++)
			{
			if (modelSettings[i].gibbsGamma == YES)
				curLnL[chn] += GibbsSampleGamma (chn, i, seed);
			}
		MrBayesPrint ("%s      Chain %d -- %.6lf -- %.6lf\n", spacer, (chn % chainParams.numChains) + 1, curLnL[chn], curLnPr[chn]);
		MrBayesPrint ("%s      Chain %d -- %.6lf -- %.6lf\n", spacer, (chn % chainParams.numChains) + 1, LogLike(chn), LogPrior(chn));
		}
	beagleScalingScheme = beagleScalingSchemeOld;
#endif
#endif

    /* Make sure current state is reset and values copied back to state 0.
	   Note that this can be tricky for Metropolis-coupled chains because
	   the chain ids may necessitate some swapping of values among chains. */
    ResetChainIds ();

	MrBayesPrint ("\n");
	if (difftime (endingT, startingT) > 3600.0)
		MrBayesPrint ("%s   Analysis completed in %d hours %d mins %d seconds\n", spacer, 
			  (int) (difftime(endingT, startingT)/3600), 
			  ((int) (difftime(endingT, startingT))%3600)/60, 
			  (int) (difftime(endingT, startingT))%60);
	else if (difftime (endingT, startingT) > 60.0)
		MrBayesPrint ("%s   Analysis completed in %d mins %d seconds\n", spacer, 
			  (int) (difftime(endingT, startingT)/60), 
			  (int) (difftime(endingT, startingT))%60);
	else if (difftime (endingT, startingT) > 2.0)
		MrBayesPrint ("%s   Analysis completed in %.0f seconds\n", spacer, 
			  difftime(endingT, startingT));
	else if (difftime (endingT, startingT) >= 1.0)
		MrBayesPrint ("%s   Analysis completed in 1 second\n", spacer);
	else
		MrBayesPrint ("%s   Analysis completed in less than 1 second\n", spacer);

#if defined (MPI_ENABLED)
	MrBayesPrint ("%s   Analysis used %1.2f seconds of CPU time on processor 0\n", spacer, (MrBFlt) CPUTime);
#else
	MrBayesPrint ("%s   Analysis used %1.2f seconds of CPU time\n", spacer, (MrBFlt) CPUTime);
#endif

#	if defined (MPI_ENABLED)
	/* find the best likelihoods across all of the processors */
	ierror = MPI_Barrier (MPI_COMM_WORLD);
	if (ierror != MPI_SUCCESS)
		{
		MrBayesPrint ("%s   Problem at chain barrier\n", spacer);
		return (ERROR);
		}
	for (j=0; j<numGlobalChains; j++)
		{
		best = maxLnL0[j];
		for (i=1; i<num_procs; i++)
			{
			if (proc_id == 0)
				{
				ierror = MPI_Recv (&maxLnL0[j], 1, MPI_DOUBLE, i, i, MPI_COMM_WORLD, &status);
				if (ierror != MPI_SUCCESS)
					{ 
					MrBayesPrint ("%s   Problem with MPI_Recv", spacer);
					return ERROR;
					}
				if (maxLnL0[j] > best)
					best = maxLnL0[j];
				}
			else if (proc_id == i)
				{
				ierror = MPI_Send (&maxLnL0[j], 1, MPI_DOUBLE, 0, i, MPI_COMM_WORLD);
				if (ierror != MPI_SUCCESS)
					{
					MrBayesPrint ("%s   Problem with MPI_Send\n", spacer);
					return ERROR;
					}
				}
			}
		maxLnL0[j] = best;
		}

	/* Collecting  marginal log likelihoods if SS is used */
    if ( chainParams.isSS == YES )
        {
    	for (j=0; j<chainParams.numRuns ; j++)
			{
			ierror = MPI_Reduce (&marginalLnLSS[j],&r, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
			if (ierror != MPI_SUCCESS)
				{
				MrBayesPrint ("%s   Problem with MPI_Send\n", spacer);
				return ERROR;
				}
	    	if(proc_id == 0 )
	    		{
	    		marginalLnLSS[j]=r;
	    		}
			}
        }
#	endif

	if (chainParams.numRuns == 1)
		{
		if (chainParams.numChains == 1)
			MrBayesPrint ("%s   Log likelihood of best state was %1.2lf\n", spacer, maxLnL0[0]);
		else
			MrBayesPrint ("%s   Log likelihood of best state for \"cold\" chain was %1.2lf\n", spacer, maxLnL0[0]);
		}
	else
		{
		for (j=0; j<chainParams.numRuns*chainParams.numChains; j++)
			{
			if (j % chainParams.numChains == 0)
				{
				if (chainParams.numChains == 1)
					MrBayesPrint ("%s   Likelihood of best state for run %d was %1.2lf\n", spacer, j/chainParams.numChains+1, maxLnL0[j/chainParams.numChains]);
				else
					MrBayesPrint ("%s   Likelihood of best state for \"cold\" chain of run %d was %1.2lf\n", spacer, j/chainParams.numChains+1, maxLnL0[j/chainParams.numChains]);
				}
			}
		}


    if ( chainParams.isSS == YES )
        {
        MrBayesPrint ("\n");
        MrBayesPrint ("%s   Marginal likelihood (in natural log units) estimated using stepping-stone sampling based on\n", spacer );
        MrBayesPrint ("%s   %d steps with %d generations (%d samples) within each step. \n\n", spacer, chainParams.numStepsSS, numGenInStepSS, numGenInStepSS/chainParams.sampleFreq );
        MrBayesPrint ("%s       Run   Marginal likelihood (ln)\n",spacer);
        MrBayesPrint ("%s       ------------------------------\n",spacer);
        for(j=0; j<chainParams.numRuns; j++)
            {
            MrBayesPrint ("%s       %3d    %9.2f   \n", spacer, j+1, marginalLnLSS[j] );
            }
        MrBayesPrint ("%s       ------------------------------\n",spacer);
        if(chainParams.numRuns>1)
            {
            MeanVarianceLog(marginalLnLSS,chainParams.numRuns,&meanSS,&varSS,NULL);
            MrBayesPrint ("%s       Mean:  %9.2f\n\n",spacer,meanSS);
            //MrBayesPrint ("%s       Mean:  %9.2lf  Scaled variance: %.2f of Marginal log likelihood estimates among runs.\n",spacer,meanSS,varSS-2*meanSS);
            //MrBayesPrint ("%s       Note: Scaled variance is given in log units and calculated as \"variance/mean^2\"\n",spacer);     
            }
        MrBayesPrint ("%s   More statistics on stepping-stone sampling is dumped to %s.ss file.\n", spacer, chainParams.chainFileName);

        if ( chainParams.mcmcDiagn == YES )
            {
            if ((tempX = (MrBFlt *) SafeCalloc (chainParams.numStepsSS, sizeof(MrBFlt))) == NULL)
                {
                nErrors++;
                }
            ERROR_TEST2("Problem allocating memory", return(ERROR),);

            for(i=0; i<chainParams.numStepsSS; i++)
                {
                tempX[i]=i+1;
                }
            MrBayesPrint ("\n");

            if( numTopologies > 1 )
                {
                if (chainParams.diagnStat == AVGSTDDEV)
                    MrBayesPrint ("   Plots of average standard deviation of split frequencies across steps for different topology.");
                else
                    MrBayesPrint ("   Plots of max standard deviation of split frequencies across steps for different topology.");
                }
            else
                {
                if (chainParams.diagnStat == AVGSTDDEV)
                    MrBayesPrint ("   Plot of average standard deviation of split frequencies across steps.");
                else
                    MrBayesPrint ("   Plot of max standard deviation of split frequencies across steps.");
                }
            MrBayesPrint ("\n");
            MrBayesPrint ("   Points at -1.0 (y-axis) indicate that there were no splits\n");
            MrBayesPrint ("   above minimum frequency for corresponding step.");
            if (numTopologies>1)
                {
                for(i=0; i<numTopologies; i++)
                    {
                    MrBayesPrint ("%s   Topology %d.\n", spacer, i+1);
                    PrintPlot (tempX, splitfreqSS+i*chainParams.numStepsSS, chainParams.numStepsSS);
                    }
                }
            else
                PrintPlot (tempX, splitfreqSS, chainParams.numStepsSS);

            free(tempX);
            }
        }

#	if defined (MPI_ENABLED)
	/* we need to collect the information on the number of accepted moves if
	   this is a parallel version */
	if (ReassembleMoveInfo() == ERROR)
		nErrors++;
	MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
	if (sumErrors > 0)
		{
		MrBayesPrint ("%s   ReassembleMoveInfo failed\n", spacer);
		return ERROR;
		}
#	endif

	/* print acceptance rates for the moves */
	for (j=0; j<chainParams.numChains*chainParams.numRuns; j++)
		{
		if (chainParams.numChains == 1)
			{
			if (chainParams.numRuns == 1)
				MrBayesPrint ("%s   Acceptance rates for the moves:\n", spacer);
			else
				MrBayesPrint ("%s   Acceptance rates for the moves in run %d:\n", spacer, j/chainParams.numChains+1);
			}
		else if (j % chainParams.numChains == 0)
			{
			if (chainParams.numRuns == 1)
				MrBayesPrint ("\n%s   Acceptance rates for the moves in the \"cold\" chain:\n", spacer);
			else
				MrBayesPrint ("\n%s   Acceptance rates for the moves in the \"cold\" chain of run %d:\n", spacer, j/chainParams.numChains+1);
			}
		else if (chainParams.allChains == YES)
			{
			if (chainParams.numRuns == 1)
				MrBayesPrint ("\n%s   Acceptance rates for the moves in chain %d (heated):\n\n", spacer, j+1);
			else
				MrBayesPrint ("\n%s   Acceptance rates for the moves in chain %d of run %d (heated):\n\n", spacer, j%chainParams.numChains+1, j/chainParams.numChains+1);
			}

		if (j % chainParams.numChains == 0 || chainParams.allChains == YES)
			{
			MrBayesPrint ("%s      With prob.   (last %d)   chain accepted proposals by move\n", spacer, chainParams.tuneFreq);

			for (i=0; i<numUsedMoves; i++)
				{
				mv = usedMoves[i];
				if (mv->nBatches[j] < 1)
					MrBayesPrint ("%s          NA           NA       %s\n",
					spacer, mv->name);
				else
					MrBayesPrint ("%s       %6.1f %%     (%3.0f %%)     %s\n", spacer,
					100.0*mv->nTotAccepted[j]/(MrBFlt)(mv->nTotTried[j]),
                    100.0*mv->lastAcceptanceRate[j],
					mv->name);
				}
			}
		}

#if defined MPI_ENABLED
    /* Redistribute move info in case it is needed in a follow-up run */
    RedistributeMoveInfo();
#endif
    
    /* output information on the success of the chain state swap proposals */
	if (PrintSwapInfo () == ERROR)
		nErrors++;
#	if defined (MPI_ENABLED)
	MPI_Allreduce (&nErrors, &sumErrors, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
	if (sumErrors > 0)
		{
		MrBayesPrint ("%s   PrintSwapInfo failed\n", spacer);
		return ERROR;
		}
#	else
	if (nErrors > 1)
		{
		MrBayesPrint ("%s   PrintSwapInfo failed\n", spacer);
		return ERROR;
		}
#	endif

#	if defined (MPI_ENABLED)
	if (proc_id != 0)
		return (NO_ERROR);
#	endif

	if ( chainParams.isSS == NO && (chainParams.numRuns > 1 && chainParams.mcmcDiagn == YES) )
		{
		f = 0.0;
		for (i=0; i<numTrees; i++)
			{
			if (chainParams.stat[i].avgStdDev > f)
				f = chainParams.stat[i].avgStdDev;
			}
		if (f > 0.10)
			{
			MrBayesPrint ("\n");
			MrBayesPrint ("%s   ************************* WARNING!! ************************************  \n", spacer);
			MrBayesPrint ("%s   MrBayes suspects that your runs have not converged because the tree       \n", spacer);
			MrBayesPrint ("%s   samples are very different (average standard deviation of split frequen-  \n", spacer);
			MrBayesPrint ("%s   cies larger than 0.10 (%1.2lf)). MrBayes suggests that you run the ana-   \n", spacer, f);
			MrBayesPrint ("%s   lysis longer or try to improve the MCMC sampling efficiency by fine-      \n", spacer);
			MrBayesPrint ("%s   tuning MCMC proposal or heating parameters.                               \n", spacer);
			}
		}


	return (NO_ERROR);
}





#define TARGETLENDELTA (100)

int SafeSprintf(char **target, int *targetLen, char *fmt, ...) {
    va_list    argp;
    int        retval;

    while (1) {
        /* try to print in the available space */
        va_start(argp, fmt);
#ifdef VISUAL
        retval = _vsnprintf(*target, *targetLen, fmt, argp);
#else
        /* With SGI IRIX this function returns 0. Allen Smith suggested using 
           _xpg5_vnsprintf, but this function needs a recent version of IRIX. 
           For now, I just allocate a large buffer for SGI, so there is no need for
           memory reallocation on this kind of machines */
        /* It appears to me that the reason for the bug is that the old version of
           this function relies on nonstandard return values for vsnprintf. With
           the current version of the code, SGI should do fine without special
           treatment.  FR  */
        retval = vsnprintf(*target, *targetLen, fmt, argp);
#endif
        va_end(argp);

        /* if it worked, retval will be in interval [0,*targetLen-1], else -1 or true length */
        if (retval > -1 && retval < *targetLen)
            return NO_ERROR;

        /* readjust length */
        if (retval > -1)     /* some C compilers will return true length in retval */
            *targetLen = retval + 1;     /* exactly what is needed */
	else                 /* some C compilers will return -1 on buffer overwrite */
            *targetLen += TARGETLENDELTA;

	/* reallocate target */
	*target = SafeRealloc ((void *)*target, *targetLen);
        if (*target == NULL)
            return ERROR;
        }
}





void SetChainIds (void)

{

	/* Fill <chainId[]> with the global chain number.
	   Ex. For proc_0, chain[0] = 0;
			 chain[1] = 1;
			 chain[2] = 2; (numchains = 3)
	   For proc_1, chain[0] = 3;
			 chain[1] = 4; (numchains = 2)
	   etc... 
	*/

#	if defined (MPI_ENABLED)

	int		i, proc, numChainsForProc, numGlobalChains;
	int 	id;
	int		remainder;

	/* calculate global number of chains */
	numGlobalChains = chainParams.numChains * chainParams.numRuns;
	
	/* there are <remainder> chains left over after
	   load balancing the chains */
	remainder = numGlobalChains % num_procs;

	/* get the number of chains handled by this proc */
	numChainsForProc = (int) (numGlobalChains / num_procs);

	/* we must distribute the remaining chains (causing
	   the chain load between procs to become unbalanced) */
	if (proc_id < remainder) 
		numChainsForProc++;

	/* NOTE: at this point, procs can have different number of numChainsForProc
	   (one more for chains < remainder, one less for procs larger than or equal
	   to the remainder) */

	id = 0;
	for (proc=0; proc<num_procs; proc++)
		{
		/* assign or increment chain id */
		if (proc == proc_id)
			{
			for (i=0; i<numChainsForProc; i++)
				chainId[i] = id++;
			}
		else
			{
			/* procs below the remainder have 1 more chain
			   than procs above */
			if (proc < remainder) 
				{
				for (i=0; i<(numGlobalChains / num_procs) + 1; i++)
					id++;
				}
			/* procs above the remainder have one less chain
			   than procs below */
			else
				{
				for (i=0; i<(numGlobalChains / num_procs); i++)
					id++;
				}
			}
		}
#	else

	int		chn;
	
	for (chn=0; chn<numLocalChains; chn++)
		chainId[chn] = chn;

#	endif
		
}




/* setFilePositions sets chainParams.tFilePos[] to point immidiatly after sampled tree in position "samplePos" for all .t files.  */
int setFilePositions (int samplePos)
{
	int	i, j, k, longestLine;
	SafeLong	lastBlock;
	char	*lineBuf;
	FILE	*fp;
	Tree	*t;
	char	*tempStr;
	int     tempStrSize = TEMPSTRSIZE;

#	if defined (MPI_ENABLED)
	if (proc_id != 0)
		return (NO_ERROR);
#	endif

	tempStr = (char *) SafeMalloc((size_t) (tempStrSize * sizeof(char)));
	if (!tempStr)
		{
		MrBayesPrint ("%s   Problem allocating tempString (%d)\n", spacer, tempStrSize * sizeof(char));
		return (ERROR);
		}

	for (i=0; i<numTopologies; i++)
		{
		t = chainParams.dtree;

		for (j=0; j<chainParams.numRuns; j++)
			{
			if (numPrintTreeParams == 1)
                {
                if( chainParams.numRuns == 1 )
                    SafeSprintf(&tempStr, &tempStrSize, "%s.t", chainParams.chainFileName);
                else
                    SafeSprintf(&tempStr, &tempStrSize, "%s.run%d.t", chainParams.chainFileName, j+1);
                }
			else
                {
                if( chainParams.numRuns == 1 )
				    SafeSprintf(&tempStr, &tempStrSize, "%s.tree%d.t", chainParams.chainFileName, i+1);
                else
                    SafeSprintf(&tempStr, &tempStrSize, "%s.tree%d.run%d.t", chainParams.chainFileName, i+1, j+1);
                }

			if ((fp = OpenBinaryFileR (tempStr)) == NULL) 
                {
                MrBayesPrint ("%s   Problem openning file %s.\n", spacer, tempStr);
			    free (tempStr);
				return (ERROR);
				}

			longestLine = LongestLine (fp);
			SafeFclose (&fp);

			if ((fp = OpenTextFileR (tempStr)) == NULL) 
			    {
				free (tempStr);
				return (ERROR);
			    }

			lineBuf = (char *) SafeCalloc (longestLine + 10, sizeof (char));
			if (!lineBuf)
				{
				SafeFclose (&fp);
                free (tempStr);
                return (ERROR);
				}

			lastBlock = LastBlock (fp, lineBuf, longestLine);
			fseek (fp, lastBlock, SEEK_SET);
            fseek (fp, FirstTree(fp, lineBuf, longestLine), SEEK_SET);


			for (k=0; k<samplePos; k++)
				{
				if (fgets (lineBuf, longestLine + 5, fp) == NULL) 
					{
                    MrBayesPrint ("%s   Not enough records in file %s.\n", spacer, tempStr);
                    SafeFclose (&fp);
					free (tempStr);
					free (lineBuf);
					return ERROR;
					}
				}
			fgetpos (fp, &chainParams.tFilePos[j*numTopologies+i]);

			SafeFclose (&fp);
			free (lineBuf);
			} /* next run */
		} /* next tree */
	free (tempStr);
	return (NO_ERROR);
}




/* SetFileNames: Set file names */
void SetFileNames (void)
{
    strcpy (sumtParams.sumtFileName, chainParams.chainFileName);
    strcpy (sumtParams.sumtOutfile, chainParams.chainFileName);
	strcpy (sumpParams.sumpFileName, chainParams.chainFileName);
	if (chainParams.numRuns == 1)
		sprintf (comptreeParams.comptFileName1, "%s.run1.t", chainParams.chainFileName);
	else /* if (chainParams.numRuns > 1) */
		sprintf (comptreeParams.comptFileName1, "%s.t", chainParams.chainFileName);
	strcpy (comptreeParams.comptFileName2, comptreeParams.comptFileName1);
	if (chainParams.numRuns == 1)
		sprintf (plotParams.plotFileName, "%s.run1.p", chainParams.chainFileName);
	else /* if (chainParams.numRuns > 1) */
		sprintf (plotParams.plotFileName, "%s.p", chainParams.chainFileName);
	if (chainParams.numRuns > 1)
		MrBayesPrint ("%s   Setting chain output file names to \"%s.run<i>.<p/t>\"\n", spacer, chainParams.chainFileName);
	else
		MrBayesPrint ("%s   Setting chain output file names to \"%s.<p/t>\"\n", spacer, chainParams.chainFileName);
}





/*----------------------------------------------------------------------------
|
|	SetLikeFunctions: This function will set up the pointers from each
|		data division to the relevant likelihood functions
|
-----------------------------------------------------------------------------*/
int SetLikeFunctions (void)

{
	
	int			i;

	ModelInfo	*m;

	/* couple divisions with likelihood functions */
	for (i=0; i<numCurrentDivisions; i++)
		{
		m = &modelSettings[i];
        m->useSSE= NO;
		
		if (m->dataType == DNA || m->dataType == RNA)
			{
			if (m->parsModelId == YES)
				{
				m->Likelihood = &Likelihood_Pars;
				}
			else
				{
				if (m->nucModelId == NUCMODEL_4BY4)
					{
					if (m->numModelStates > 4)
						{
						/* covariotide model */
						/* TODO: allow autocorrelated rates */
						if (m->gibbsGamma == YES)
							{
							m->CondLikeDown = &CondLikeDown_Gen_GibbsGamma;
							m->CondLikeRoot = &CondLikeRoot_Gen_GibbsGamma;
							m->CondLikeScaler = &CondLikeScaler_Gen_GibbsGamma;
							m->Likelihood = &Likelihood_Gen_GibbsGamma;
							}
						else
							{
							m->CondLikeDown = &CondLikeDown_Gen;
							m->CondLikeRoot = &CondLikeRoot_Gen;
							m->CondLikeScaler = &CondLikeScaler_Gen;
							m->Likelihood = &Likelihood_Gen;
							}
						if (m->correlation != NULL)
							m->Likelihood = &Likelihood_Adgamma;
						else
							m->Likelihood = &Likelihood_Gen;
						if (m->nCijkParts == 1)
							m->TiProbs = &TiProbs_Gen;
						else if (m->nCijkParts > 1)
							m->TiProbs = &TiProbs_GenCov;
						m->PrintAncStates = &PrintAncStates_NUC4;
						m->PrintSiteRates = &PrintSiteRates_Gen;

						}
					else
						{
#if defined (SSE_ENABLED)
					    if ( m->printAncStates == YES || m->printSiteRates == YES ||m->printPosSel ==YES ||m->printSiteOmegas==YES )
						    {
                            MrBayesPrint ("%s   Non-SSE version of conditional liklihood calculator will be used for devision %d due to request\n", spacer, i+1);
                            MrBayesPrint ("%s   of reprting 'ancestaral states', 'site rates', 'pos selection' or 'site omegas'.\n", spacer);
						    }

                        m->CondLikeUp = &CondLikeUp_NUC4;
						m->PrintAncStates = &PrintAncStates_NUC4;
						m->PrintSiteRates = &PrintSiteRates_Gen;

						if (m->gibbsGamma == YES)
							{
							m->CondLikeDown = &CondLikeDown_NUC4_GibbsGamma;
							m->CondLikeRoot = &CondLikeRoot_NUC4_GibbsGamma;
							m->CondLikeScaler = &CondLikeScaler_NUC4_GibbsGamma;
							}
						else if (m->correlation != NULL || m->printAncStates == YES || m->printSiteRates == YES ||m->printPosSel ==YES ||m->printSiteOmegas==YES)
							{
							m->CondLikeDown = &CondLikeDown_NUC4;
							m->CondLikeRoot = &CondLikeRoot_NUC4;
							m->CondLikeScaler = &CondLikeScaler_NUC4;
							}
                        else
                            {
                            m->useSSE= YES;
						    m->CondLikeDown = &CondLikeDown_NUC4_SSE;
						    m->CondLikeRoot = &CondLikeRoot_NUC4_SSE;
						    m->CondLikeScaler = &CondLikeScaler_NUC4_SSE;
                            /* Should be sse versions if we want to handel m->printAncStates == YES || inferSiteRates == YES.
                            For now just set to NULL for early error detection if functions anyway got called */
                            m->CondLikeUp = NULL;
	    					m->PrintAncStates = NULL;
		    				m->PrintSiteRates = NULL;
                            }

                        if (m->correlation != NULL)
							m->Likelihood = &Likelihood_Adgamma;
						else if (m->gibbsGamma == YES)
							m->Likelihood = &Likelihood_NUC4_GibbsGamma;
						else if (m->printAncStates == YES || inferSiteRates == YES)
                            m->Likelihood = &Likelihood_NUC4;
                        else
							m->Likelihood = &Likelihood_NUC4_SSE;
#else
						if (m->gibbsGamma == YES)
							{
							m->CondLikeDown = &CondLikeDown_NUC4_GibbsGamma;
							m->CondLikeRoot = &CondLikeRoot_NUC4_GibbsGamma;
							m->CondLikeScaler = &CondLikeScaler_NUC4_GibbsGamma;
							}
						else
							{
							m->CondLikeDown = &CondLikeDown_NUC4;
							m->CondLikeRoot = &CondLikeRoot_NUC4;
							m->CondLikeScaler = &CondLikeScaler_NUC4;
							}

                        if (m->correlation != NULL)
							m->Likelihood = &Likelihood_Adgamma;
						else if (m->gibbsGamma == YES)
							m->Likelihood = &Likelihood_NUC4_GibbsGamma;
						else
							m->Likelihood = &Likelihood_NUC4;

                        m->CondLikeUp = &CondLikeUp_NUC4;
						m->PrintAncStates = &PrintAncStates_NUC4;
						m->PrintSiteRates = &PrintSiteRates_Gen;
#endif

                        if (m->nst == 1)
							m->TiProbs = &TiProbs_Fels;
						else if (m->nst == 2)
							m->TiProbs = &TiProbs_Hky;
						else
							m->TiProbs = &TiProbs_Gen;
						m->StateCode = &StateCode_NUC4;

						}
					}
				else if (m->nucModelId == NUCMODEL_DOUBLET)
					{
					if (m->gibbsGamma == YES)
						{
						m->CondLikeDown = &CondLikeDown_Gen_GibbsGamma;
						m->CondLikeRoot = &CondLikeRoot_Gen_GibbsGamma;
						m->CondLikeScaler = &CondLikeScaler_Gen_GibbsGamma;
						m->Likelihood = &Likelihood_Gen_GibbsGamma;
						}
					else
						{
						m->CondLikeDown = &CondLikeDown_Gen;
						m->CondLikeRoot = &CondLikeRoot_Gen;
						m->CondLikeScaler = &CondLikeScaler_Gen;
						m->Likelihood = &Likelihood_Gen;
						}
					if (m->nst == 1)
						m->TiProbs = &TiProbs_Gen;
					else if (m->nst == 2)
						m->TiProbs = &TiProbs_Gen;
					else
						m->TiProbs = &TiProbs_Gen;
					m->CondLikeUp = &CondLikeUp_Gen;
					m->PrintAncStates = &PrintAncStates_Gen;
					m->PrintSiteRates = &PrintSiteRates_Gen;
					}
				else if (m->nucModelId == NUCMODEL_CODON)
					{
					/* codon models */
					if (m->numOmegaCats == 1)
						{
						if (m->gibbsGamma == YES)
							{
							m->CondLikeDown = &CondLikeDown_Gen_GibbsGamma;
							m->CondLikeRoot = &CondLikeRoot_Gen_GibbsGamma;
							m->CondLikeScaler = &CondLikeScaler_Gen_GibbsGamma;
							m->Likelihood = &Likelihood_Gen_GibbsGamma;
							}
						else
							{
                            m->CondLikeDown = &CondLikeDown_Gen;
					        m->CondLikeRoot = &CondLikeRoot_Gen;
					        m->CondLikeScaler = &CondLikeScaler_Gen;
						    m->Likelihood = &Likelihood_Gen;
#if defined (SSE_ENABLED)
                            
					        if ( m->printAncStates == YES || m->printSiteRates == YES ||m->printPosSel ==YES ||m->printSiteOmegas==YES )
						        {
                                MrBayesPrint ("%s   Non-SSE version of conditional liklihood calculator will be used for devision %d due to request\n", spacer, i+1);
                                MrBayesPrint ("%s   of reprting 'ancestaral states', 'site rates', 'pos selection' or 'site omegas'.\n", spacer);
						        }
                            else
                                {
                                m->useSSE= YES;
							    m->CondLikeDown = &CondLikeDown_Gen_SSE;
							    m->CondLikeRoot = &CondLikeRoot_Gen_SSE;
							    m->CondLikeScaler = &CondLikeScaler_Gen_SSE;
							    m->Likelihood = &Likelihood_Gen_SSE;
                                }
#endif
							}
						}
					else
						{
                        m->CondLikeDown   = &CondLikeDown_NY98;
						m->CondLikeRoot   = &CondLikeRoot_NY98;
						m->CondLikeScaler = &CondLikeScaler_NY98;
						m->Likelihood     = &Likelihood_NY98;
#if defined (SSE_ENABLED)

                         if ( m->printAncStates == YES || m->printSiteRates == YES ||m->printPosSel ==YES ||m->printSiteOmegas==YES )
						        {
						        MrBayesPrint ("%s   Non-SSE version of conditional liklihood calculator will be used for devision %d due to request\n", spacer, i+1);
                                MrBayesPrint ("%s   of reprting 'ancestaral states', 'site rates', 'pos selection' or 'site omegas'.\n", spacer);
						        }
                            else
                                {
                                m->useSSE= YES;
						        m->CondLikeDown   = &CondLikeDown_NY98_SSE;
						        m->CondLikeRoot   = &CondLikeRoot_NY98_SSE;
						        m->CondLikeScaler = &CondLikeScaler_NY98_SSE;
						        m->Likelihood     = &Likelihood_NY98_SSE;
                                }

#endif
						}
					m->TiProbs        = &TiProbs_Gen;
					if (m->nCijkParts > 1)
						m->TiProbs = &TiProbs_GenCov;
				    m->CondLikeUp = &CondLikeUp_Gen;
				    m->PrintAncStates = &PrintAncStates_Gen;
				    m->PrintSiteRates = &PrintSiteRates_Gen;
					}
				else /* if (m->nucModelId == NUCMODEL_AA) */
					{
					if (m->gibbsGamma == YES)
						{
						m->CondLikeDown = &CondLikeDown_Gen_GibbsGamma;
						m->CondLikeRoot = &CondLikeRoot_Gen_GibbsGamma;
						m->CondLikeScaler = &CondLikeScaler_Gen_GibbsGamma;
						m->Likelihood = &Likelihood_Gen_GibbsGamma;
						}
					else
						{
						m->CondLikeDown = &CondLikeDown_Gen;
						m->CondLikeRoot = &CondLikeRoot_Gen;
						m->CondLikeScaler = &CondLikeScaler_Gen;
						m->Likelihood = &Likelihood_Gen;
						}
					if (m->nCijkParts > 1)
						m->TiProbs = &TiProbs_GenCov;
					else
                        m->TiProbs = &TiProbs_Gen;
				    m->CondLikeUp = &CondLikeUp_Gen;
				    m->StateCode = &StateCode_AA;
				    m->PrintAncStates = &PrintAncStates_Gen;
				    m->PrintSiteRates = &PrintSiteRates_Gen;
					}
				}
			}
		else if (m->dataType == PROTEIN)
			{
			if (m->parsModelId == YES)
				{
				m->Likelihood = &Likelihood_Pars;
				}
			else
				{
				/* TODO:allow autocorrelated rates for covarion model */
				if (m->gibbsGamma == YES)
					{
					m->CondLikeDown = &CondLikeDown_Gen_GibbsGamma;
					m->CondLikeRoot = &CondLikeRoot_Gen_GibbsGamma;
					m->CondLikeScaler = &CondLikeScaler_Gen_GibbsGamma;
					m->Likelihood = &Likelihood_Gen_GibbsGamma;
					}
				else
					{
					m->CondLikeDown = &CondLikeDown_Gen;
					m->CondLikeRoot = &CondLikeRoot_Gen;
					m->CondLikeScaler = &CondLikeScaler_Gen;
					m->Likelihood = &Likelihood_Gen;
					}
				if (m->correlation != NULL)
					{
					if (m->gibbsGamma == YES)
						{
						MrBayesPrint ("%s   Adgamma model cannot be used with Gibbs sampling of rate categories\n", spacer);
						return (ERROR);
						}
					else
						m->Likelihood = &Likelihood_Adgamma;
					}
				m->TiProbs        = &TiProbs_Gen;
				if (m->numModelStates > 20 && m->nCijkParts == 1)
					m->TiProbs = &TiProbs_Gen;
				else if (m->numModelStates > 20 && m->nCijkParts > 1)
					m->TiProbs = &TiProbs_GenCov;
				m->CondLikeUp = &CondLikeUp_Gen;
				m->StateCode = &StateCode_AA;
				m->PrintAncStates = &PrintAncStates_Gen;
				m->PrintSiteRates = &PrintSiteRates_Gen;
				}
			}
		else if (m->dataType == RESTRICTION)
			{
			if (m->parsModelId == YES)
				{
				m->Likelihood = &Likelihood_Pars;
				}
			else
				{
                m->CondLikeDown   = &CondLikeDown_Bin;
				m->CondLikeRoot   = &CondLikeRoot_Bin;
				m->CondLikeScaler = &CondLikeScaler_Gen;
				m->Likelihood     = &Likelihood_Res;

#if defined (SSE_ENABLED)
                if ( m->printAncStates == YES || m->printSiteRates == YES ||m->printPosSel ==YES ||m->printSiteOmegas==YES )
			        {
			        MrBayesPrint ("%s   Non-SSE version of conditional liklihood calculator will be used for devision %d due to request\n", spacer, i+1);
                    MrBayesPrint ("%s   of reprting 'ancestaral states', 'site rates', 'pos selection' or 'site omegas'.\n", spacer);
			        }
                else
                    {
                    m->useSSE= YES;
	                m->CondLikeDown   = &CondLikeDown_Bin_SSE;
	                m->CondLikeRoot   = &CondLikeRoot_Bin_SSE;
	                m->CondLikeScaler = &CondLikeScaler_Gen_SSE;
	                m->Likelihood     = &Likelihood_Res_SSE;
                    }
#endif
				m->TiProbs        = &TiProbs_Res;
				m->CondLikeUp = &CondLikeUp_Bin;
				m->StateCode = &StateCode_Std;
				m->PrintAncStates = &PrintAncStates_Bin;
				m->PrintSiteRates = &PrintSiteRates_Gen;
				}
			}
		else if (m->dataType == STANDARD)
			{
			if (m->parsModelId == YES)
				{
				if (m->numModelStates == 2)
					{
					m->Likelihood = &Likelihood_Pars; /* this is much faster if number of states do not vary */
					m->numStates = 2;	/* this is needed for the parsimony calculator */
					}
				else
					m->Likelihood = &Likelihood_ParsStd;
				}
			else
				{
				m->CondLikeDown   = &CondLikeDown_Std;
				m->CondLikeRoot   = &CondLikeRoot_Std;
				m->CondLikeScaler = &CondLikeScaler_Std;
				m->Likelihood     = &Likelihood_Std;
				m->TiProbs        = &TiProbs_Std;
				m->CondLikeUp	  = &CondLikeUp_Std;
				m->StateCode	  = &StateCode_Std;
				m->PrintAncStates = &PrintAncStates_Std;
				m->PrintSiteRates = &PrintSiteRates_Std;
				}
			}		
		else if (m->dataType == CONTINUOUS)
			{
			
			}		
		else
			{
			MrBayesPrint ("%s   ERROR: Data should be one of these types!\n", spacer);
			return ERROR;
			}
		
		}

	return NO_ERROR;

}





/*----------------------------------------------------------------------------
|
|   ShowMoveSummary: Show summary of moves that will be used in MCMC sampling
|
-----------------------------------------------------------------------------*/
int ShowMoveSummary (void)

{
	int			i, run, chain, areRunsSame, areChainsSame, chainIndex;
	MCMCMove	*mv;
	MrBFlt		prob;
	
	/* first find out if the probabilities are different in different runs */			
	areRunsSame = YES;
	for (run=1; run<chainParams.numRuns; run++)
		{
		for (chain=0; chain<chainParams.numChains; chain++)
			{
			chainIndex = run*chainParams.numChains + chain;
			for (i=0; i<numUsedMoves; i++)
				{
				mv = usedMoves[i];
				if (AreDoublesEqual (mv->relProposalProb[chainIndex], mv->relProposalProb[chain], 0.000001) == NO)
					{
					areRunsSame = NO;
					break;
					}
				}
			if (areRunsSame == NO)
				break;
			}
		if (areRunsSame == NO)
			break;
		}

	/* now print values */
	for (run=0; run<chainParams.numRuns; run++)
		{
		if (areRunsSame == YES && run >= 1)
			break;

		/* find out if chains are different within this run */
		areChainsSame = YES;
		for (chain=1; chain<chainParams.numChains; chain++)
			{
			chainIndex = run*chainParams.numChains + chain;
			for (i=0; i<numUsedMoves; i++)
				{
				mv = usedMoves[i];
				if (AreDoublesEqual (mv->relProposalProb[chainIndex], mv->relProposalProb[chainIndex-chain], 0.000001) == NO)
					{
					areChainsSame = NO;
					break;
					}
				}
			if (areChainsSame == NO)
				break;
			}

		for (chain=0; chain<chainParams.numChains; chain++)
			{
			if (areChainsSame == YES && chain >= 1)
				break;
			
			/* now we can print the values */
            MrBayesPrint("\n");
			if (areRunsSame == YES && areChainsSame == YES)
				MrBayesPrint ("%s   The MCMC sampler will use the following moves:\n", spacer);
			else if (areRunsSame == NO && areChainsSame == YES)
				MrBayesPrint ("%s   The MCMC sampler will use the following moves for run %d:\n", spacer, run+1);
			else if (areRunsSame == YES && areChainsSame == NO)
				MrBayesPrint ("%s   The MCMC sampler will use the following moves for chain %d:\n", spacer, chain+1);
			else if (areRunsSame == NO && areChainsSame == NO)
				MrBayesPrint ("%s   The MCMC sampler will use the following moves for run %d, chain %d:\n", spacer, run+1, chain+1);

			chainIndex = run*chainParams.numChains + chain;
			MrBayesPrint ("%s      With prob.  Chain will use move\n", spacer);
			for (i=0; i<numUsedMoves; i++)
				{
				mv = usedMoves[i];
				prob = mv->cumProposalProb[chainIndex];
				if (i > 0)
					prob -= usedMoves[i-1]->cumProposalProb[chainIndex];
				if (AreDoublesEqual(prob,0.0,0.000001) == YES)
					continue;
				MrBayesPrint ("%s       %6.2f %%   %s\n", spacer, 100*prob, mv->name);
				}
			MrBayesPrint ("\n");
			}	/* next chain */
		}	/* next run */

	return (NO_ERROR);
}





int SetBinaryQMatrix (MrBFlt **a, int whichChain, int division)
{
	MrBFlt			scaler, *bs;
	ModelInfo		*m;
		
	/* set up pointers to the appropriate model information */
	m = &modelSettings[division];
	assert( m->numModelStates == 2 );

	bs = GetParamSubVals (m->stateFreq, whichChain, state[whichChain]);
	scaler = 1.0 / (2*bs[0]*bs[1]);
	a[0][0]= -bs[1]*scaler;
	a[0][1]=  bs[1]*scaler;
	a[1][0]=  bs[0]*scaler;
	a[1][1]= -bs[0]*scaler;

	return (NO_ERROR);
}





int SetNucQMatrix (MrBFlt **a, int n, int whichChain, int division, MrBFlt rateMult, MrBFlt *rA, MrBFlt *rS)
	
{

	register int	i, j, k;
	int				isTransition=0, nDiff, rtNum=0;
	MrBFlt			scaler, mult=0.0, probOn, sum, *swr, s01, s10, s[4][4], nonsyn, *rateValues=NULL, *bs, dN, dS;
	ModelInfo		*m;
	ModelParams 	*mp;
#if defined BEAGLE_ENABLED
    MrBFlt          trans;
#endif

	/* set up pointers to the appropriate model information */
	mp = &modelParams[division];
	m = &modelSettings[division];
	assert( m->numModelStates == n );

	/* All of the models that are set up in this function require the frequencies
	   of the nucleotides (or doublets or codons). They will also require either
	   a transition/transversion rate ratio or the GTR rate parameters. The 
	   "rateValues" will either be
	   
	      rateValues[0] = transtion/transversion rate (kappa)
	   
	   for nst=2 models or
	   
	      rateValues[0] = A <-> C rate
	      rateValues[1] = A <-> G rate
	      rateValues[2] = A <-> T rate
	      rateValues[3] = C <-> G rate
	      rateValues[4] = C <-> T rate
	      rateValues[5] = G <-> T rate
	      
	   for nst=6 models. */
	bs = GetParamSubVals (m->stateFreq, whichChain, state[whichChain]);
	if (m->nst == 2)
		{
		rateValues = GetParamVals(m->tRatio, whichChain, state[whichChain]);
#if defined (BEAGLE_ENABLED)
		/* transversions assumed to have rate 1.0; */
		trans = rateValues[0];
		if ( m->numModelStates == 4 )   /* code to satisfy Beagle */
			{
			rateValues = (MrBFlt *) SafeCalloc (6, sizeof(MrBFlt));
			rateValues[0] = rateValues[2] = rateValues[3] = rateValues[5] =1.0; /* Setting transversions */
			rateValues[1] = rateValues[4] = trans; /* Setting transitions */
			}
#endif
		}

    else if (m->nst == 6 || m->nst == NST_MIXED)
		rateValues = GetParamVals(m->revMat, whichChain, state[whichChain]);
#if defined (BEAGLE_ENABLED)
    else if (m->nst == 1 && m->numModelStates == 4)   /* code to satisfy Beagle */
        {
        rateValues = (MrBFlt *) SafeCalloc (6, sizeof(MrBFlt));
        for (i=0; i<6; i++)
            rateValues[i] = 1.0;
        }
#endif

	if (n == 4) 
		{
		/* 4 X 4 model:
		
		   Here, we set the rate matrix for the GTR model (Tavare, 1986). We
		   need not only the 6 rates for this model (rateValues), but also the 
		   base frequencies (bs). */
		    
		/* set diagonal of Q matrix to 0 */
		for (i=0; i<4; i++)
			a[i][i] = 0.0;

		/* initialize Q matrix */
		scaler = 0.0;
		for (i=0; i<4; i++)
			{
			for (j=i+1; j<4; j++)
				{
				if (i == 0 && j == 1)
					mult = rateValues[0];
				else if (i == 0 && j == 2)
					mult = rateValues[1];
				else if (i == 0 && j == 3)
					mult = rateValues[2];
				else if (i == 1 && j == 2)
					mult = rateValues[3];
				else if (i == 1 && j == 3)
					mult = rateValues[4];
				else if (i == 2 && j == 3)
					mult = rateValues[5];
				a[i][i] -= (a[i][j] = bs[j] * mult);
				a[j][j] -= (a[j][i] = bs[i] * mult);
				scaler += bs[i] * a[i][j];
				scaler += bs[j] * a[j][i];
				}
			}
			
		/* rescale Q matrix */
		scaler = 1.0 / scaler;
		for (i=0; i<4; i++)
			for (j=0; j<4; j++)
				a[i][j] *= scaler;
		}
	else if (n == 8) /* we have a 4 X 4 covarion model */
		{
		/* 8 X 8 covarion model:
		
		   Here, we set the rate matrix for the covarion model (Tuffley and
		   Steel, 1997). We need the rate parameters of the model 
		   (contained in rateValues), the frequencies of the four nucleotides,
		   and the switching rates to completely specify the rate matrix. We
		   first set up the 4 X 4 submatrix that represents changes (the upper
		   left portion of the 8 X 8 matrix). Note that if we have rate
		   variation across sites, that we need to deal with the multiplication
		   in the rate matrix (i.e., we cannot simply deal with rate variation
		   by multiplying the branch length by a rate multiplier as we can
		   with other models). Instead, we multiply the scaled rate matrix
		   by the rate multiplier. */

		/* Get the switching rates. The rate of off->on is s01 and the rate
		   of on->off is s10. The stationary probability of the switch process
		   is prob1 = s01/(s01+s10) and prob0 = s10/(s01+s10). */
		swr = GetParamVals (m->switchRates, whichChain, state[whichChain]);
		s01 = swr[0];
		s10 = swr[1];
		probOn = s01 / (s01 + s10);
		
		/* set matrix a to 0 */
		for (i=0; i<8; i++)
			for (j=0; j<8; j++)
				a[i][j] = 0.0;

		/* set up the 4 X 4 matrix representing substitutions (s[][]; upper left) */
		if (m->nst == 1)
			{
			scaler = 0.0;
			for (i=0; i<4; i++)
				{
				for (j=i+1; j<4; j++)
					{
					s[i][j] = bs[j];
					s[j][i] = bs[i];
					scaler += bs[i] * s[i][j] * probOn;
					scaler += bs[j] * s[j][i] * probOn;
					}
				}
			}
		else if (m->nst == 2)
			{
			scaler = 0.0;
			for (i=0; i<4; i++)
				{
				for (j=i+1; j<4; j++)
					{
					if ((i == 0 && j == 2) || (i == 2 && j == 0) || (i == 1 && j == 3) || (i == 3 && j == 1))
						mult = rateValues[0];
					else
						mult = 1.0;
					s[i][j] = bs[j] * mult;
					s[j][i] = bs[i] * mult;
					scaler += bs[i] * s[i][j] * probOn;
					scaler += bs[j] * s[j][i] * probOn;
					}
				}
			}
		else
			{
			scaler = 0.0;
			for (i=0; i<4; i++)
				{
				for (j=i+1; j<4; j++)
					{
					if (i == 0 && j == 1)
						mult = rateValues[0];
					else if (i == 0 && j == 2)
						mult = rateValues[1];
					else if (i == 0 && j == 3)
						mult = rateValues[2];
					else if (i == 1 && j == 2)
						mult = rateValues[3];
					else if (i == 1 && j == 3)
						mult = rateValues[4];
					else if (i == 2 && j == 3)
						mult = rateValues[5];

					s[i][j] = bs[j] * mult;
					s[j][i] = bs[i] * mult;
					scaler += bs[i] * s[i][j] * probOn;
					scaler += bs[j] * s[j][i] * probOn;
					}
				}
			}

		/* rescale off diagonal elements of s[][] matrix */
		scaler = 1.0 / scaler;
		for (i=0; i<4; i++)
			{
			for (j=0; j<4; j++)
				{
				if (i != j)
					s[i][j] *= scaler;
				}
			}
			
		/* now, scale s[][] by rate factor */
		for (i=0; i<4; i++)
			{
			for (j=0; j<4; j++)
				{
				if (i != j)
					s[i][j] *= rateMult;
				}
			}
			
		/* put in diagonal elements of s[][] */
		for (i=0; i<4; i++)
			{
			sum = 0.0;
			for (j=0; j<4; j++)
				{
				if (i != j)
					sum += s[i][j];
				}
			s[i][i] = -(sum + s10);
			}
				
		/* Now, put s[][] into top left portion of a matrix and fill in the
		   other parts of the matrix with the appropriate switching rates. */
		for (i=0; i<4; i++)
			for (j=0; j<4; j++)
				a[i][j] = s[i][j];
		for (i=4; i<8; i++)
			a[i][i] = -s01;
		a[0][4] = s10;
		a[1][5] = s10;
		a[2][6] = s10;
		a[3][7] = s10;
		a[4][0] = s01;
		a[5][1] = s01;
		a[6][2] = s01;
		a[7][3] = s01;
		
#		if 0
		for (i=0; i<8; i++)
			{
			for (j=0; j<8; j++)
				printf ("%1.10lf ", a[i][j]);
			printf ("\n");
			}
		for (i=0; i<4; i++)
			printf ("%lf ", bs[i]);
		printf ("\n");
		printf ("s01 = %lf s10 = %lf pi1 = %lf pi0 = %lf\n", s01, s10, probOn, 1-probOn);
#		endif
		}
	else if (n == 16) 
		{
		/* 16 X 16 doublet model:
		
		   We have a doublet model. The states are in the order AA, AC, AG, AT, CA, CC
		   CG, CT, GA, GC, GG, GT, TA, TC, TG, TT. The rate matrix is straight-forward
		   to set up. We simply multiply the rate parameter (e.g., the ti/tv rate
		   ratio) by the doublet frequencies. */
		   
		/* set diagonal of Q matrix to 0 */
		for (i=0; i<16; i++)
			a[i][i] = 0.0;

		if (m->nst == 1) /* F81-like doublet model */
			{
			scaler = 0.0;
			for (i=0; i<16; i++)
				{
				for (j=i+1; j<16; j++)
					{
					if (((doublet[i].first & doublet[j].first) == 0) && ((doublet[i].second & doublet[j].second) == 0))
						mult = 0.0;
					else
						mult = 1.0;					
					a[i][i] -= (a[i][j] = bs[j] * mult);
					a[j][j] -= (a[j][i] = bs[i] * mult);
					scaler += bs[i] * a[i][j];
					scaler += bs[j] * a[j][i];
					}
				}
			}
		else if (m->nst == 2) /* HKY-like doublet model */
			{
			scaler = 0.0;
			for (i=0; i<16; i++)
				{
				for (j=i+1; j<16; j++)
					{
					if (((doublet[i].first & doublet[j].first) == 0) && ((doublet[i].second & doublet[j].second) == 0))
						mult = 0.0;
					else
						{
						if ((doublet[i].first & doublet[j].first) == 0)
							{
							if ((doublet[i].first + doublet[j].first) == 5 || (doublet[i].first + doublet[j].first) == 10)
								mult = rateValues[0];
							else
								mult = 1.0;
							}
						else
							{
							if ((doublet[i].second + doublet[j].second) == 5 || (doublet[i].second + doublet[j].second) == 10)
								mult = rateValues[0];
							else
								mult = 1.0;
							}
						}				
					a[i][i] -= (a[i][j] = bs[j] * mult);
					a[j][j] -= (a[j][i] = bs[i] * mult);
					scaler += bs[i] * a[i][j];
					scaler += bs[j] * a[j][i];
					}
				}
			}
		else /* GTR-like doublet model */
			{
			scaler = 0.0;
			for (i=0; i<16; i++)
				{
				for (j=i+1; j<16; j++)
					{
					if (((doublet[i].first & doublet[j].first) == 0) && ((doublet[i].second & doublet[j].second) == 0))
						mult = 0.0;
					else
						{
						if ((doublet[i].first & doublet[j].first) == 0)
							{
							if ((doublet[i].first + doublet[j].first) == 3)
								mult = rateValues[0];
							else if ((doublet[i].first + doublet[j].first) == 5)
								mult = rateValues[1];
							else if ((doublet[i].first + doublet[j].first) == 9)
								mult = rateValues[2];
							else if ((doublet[i].first + doublet[j].first) == 6)
								mult = rateValues[3];
							else if ((doublet[i].first + doublet[j].first) == 10)
								mult = rateValues[4];
							else
								mult = rateValues[5];
							}
						else
							{
							if ((doublet[i].second + doublet[j].second) == 3)
								mult = rateValues[0];
							else if ((doublet[i].second + doublet[j].second) == 5)
								mult = rateValues[1];
							else if ((doublet[i].second + doublet[j].second) == 9)
								mult = rateValues[2];
							else if ((doublet[i].second + doublet[j].second) == 6)
								mult = rateValues[3];
							else if ((doublet[i].second + doublet[j].second) == 10)
								mult = rateValues[4];
							else
								mult = rateValues[5];
							}
						}				
					a[i][i] -= (a[i][j] = bs[j] * mult);
					a[j][j] -= (a[j][i] = bs[i] * mult);
					scaler += bs[i] * a[i][j];
					scaler += bs[j] * a[j][i];
					}
				}
			}
					
			
		/* rescale Q matrix */
		scaler = 1.0 / scaler;
		for (i=0; i<16; i++)
			for (j=0; j<16; j++)
				a[i][j] *= scaler;
		}
	else
		{
		/* 64(ish) X 64(ish) codon model:
		
		   Here, we set the rate matrix for the codon model (see Goldman and
		   Yang, 1994). Note that we can specifiy any general type of codon
		   model, with these constraints:
		   
		  	a[i][j] = 0                      -> if i and j differ at 2 or 3 nucleotides
		  	a[i][j] = rateValues[0] * bs[j]  -> if synonymous A <-> C change
		  	a[i][j] = rateValues[1] * bs[j]  -> if synonymous A <-> G change
		  	a[i][j] = rateValues[2] * bs[j]  -> if synonymous A <-> T change
		  	a[i][j] = rateValues[3] * bs[j]  -> if synonymous C <-> G change
		  	a[i][j] = rateValues[4] * bs[j]  -> if synonymous C <-> T change
		  	a[i][j] = rateValues[5] * bs[j]  -> if synonymous G <-> T change
		  	
		  	a[i][j] = rateValues[0] * nonsyn * bs[j]  -> if nonsynonymous A <-> C change
		  	a[i][j] = rateValues[1] * nonsyn * bs[j]  -> if nonsynonymous A <-> G change
		  	a[i][j] = rateValues[2] * nonsyn * bs[j]  -> if nonsynonymous A <-> T change
		  	a[i][j] = rateValues[3] * nonsyn * bs[j]  -> if nonsynonymous C <-> G change
		  	a[i][j] = rateValues[4] * nonsyn * bs[j]  -> if nonsynonymous C <-> T change
		  	a[i][j] = rateValues[5] * nonsyn * bs[j]  -> if nonsynonymous G <-> T change
		  	
		  Other models, such as the one used by Nielsen & Yang (1998) can be obtained
		  from this model by restricing transitions and transversions to have the same rate.
		  nonsyn is the nonsynonymous/synonymous rate ratio (often called the
		  dN/dS ratio). If we are in this part of the function, then we rely on it
		  being called with the "rateMult" parameter specifying the dN/dS ratio. Note
		  that the size of the matrix will never be 64 X 64 as we only consider changes
		  among coding triplets (i.e., we exclude the stop codons). */
		  
		/* get the nonsynonymous/synonymous rate ratio */
		nonsyn = rateMult; 
		
		/* set diagonal of Q matrix to 0 */
		for (i=0; i<n; i++)
			a[i][i] = 0.0;
			
		/* set dN and dS rates to zero */
		dN = dS = 0.0;

		if (m->nst == 1) /* F81-like codon model */
			{
			scaler = 0.0;
			for (i=0; i<n; i++)
				{
				for (j=i+1; j<n; j++)
					{
					nDiff = 0;
					for (k=0; k<3; k++)
						{
						if (mp->codonNucs[i][k] != mp->codonNucs[j][k])
							nDiff++;
						}
					if (nDiff > 1)
						{
						mult = 0.0;
						}
					else
						{
						if (mp->codonAAs[i] == mp->codonAAs[j])
							mult = 1.0;
						else
							mult = nonsyn;
						}
					
					a[i][i] -= (a[i][j] = bs[j] * mult);
					a[j][j] -= (a[j][i] = bs[i] * mult);
					if (mp->codonAAs[i] == mp->codonAAs[j])
						dS += (bs[i] * a[i][j] + bs[j] * a[j][i]);
					else
						dN += (bs[i] * a[i][j] + bs[j] * a[j][i]);
					scaler += bs[i] * a[i][j];
					scaler += bs[j] * a[j][i];
					}
				}
			}
		else if (m->nst == 2) /* HKY-like codon model */
			{
			scaler = 0.0;
			for (i=0; i<n; i++)
				{
				for (j=i+1; j<n; j++)
					{
					nDiff = 0;
					for (k=0; k<3; k++)
						{
						if (mp->codonNucs[i][k] != mp->codonNucs[j][k])
							{
							nDiff++;
							if ((mp->codonNucs[i][k] == 0 && mp->codonNucs[j][k] == 2) || (mp->codonNucs[i][k] == 2 && mp->codonNucs[j][k] == 0) ||
							    (mp->codonNucs[i][k] == 1 && mp->codonNucs[j][k] == 3) || (mp->codonNucs[i][k] == 3 && mp->codonNucs[j][k] == 1))
								isTransition = YES;
							else
								isTransition = NO;
							}
						}
					if (nDiff > 1)
						{
						mult = 0.0;
						}
					else
						{
						if (mp->codonAAs[i] == mp->codonAAs[j])
							mult = 1.0;
						else
							mult = nonsyn;
						if (isTransition == YES)
							mult *= rateValues[0];
						}
					
					a[i][i] -= (a[i][j] = bs[j] * mult);
					a[j][j] -= (a[j][i] = bs[i] * mult);
					if (mp->codonAAs[i] == mp->codonAAs[j])
						dS += (bs[i] * a[i][j] + bs[j] * a[j][i]);
					else
						dN += (bs[i] * a[i][j] + bs[j] * a[j][i]);
					scaler += bs[i] * a[i][j];
					scaler += bs[j] * a[j][i];
					}
				}
			}
		else /* GTR-like codon model */
			{
			scaler = 0.0;
			for (i=0; i<n; i++)
				{
				for (j=i+1; j<n; j++)
					{
					nDiff = 0;
					for (k=0; k<3; k++)
						{
						if (mp->codonNucs[i][k] != mp->codonNucs[j][k])
							{
							nDiff++;
							if ((mp->codonNucs[i][k] == 0 && mp->codonNucs[j][k] == 1) || (mp->codonNucs[i][k] == 1 && mp->codonNucs[j][k] == 0))
								rtNum = 0;
							else if ((mp->codonNucs[i][k] == 0 && mp->codonNucs[j][k] == 2) || (mp->codonNucs[i][k] == 2 && mp->codonNucs[j][k] == 0))
								rtNum = 1;
							else if ((mp->codonNucs[i][k] == 0 && mp->codonNucs[j][k] == 3) || (mp->codonNucs[i][k] == 3 && mp->codonNucs[j][k] == 0))
								rtNum = 2;
							else if ((mp->codonNucs[i][k] == 1 && mp->codonNucs[j][k] == 2) || (mp->codonNucs[i][k] == 2 && mp->codonNucs[j][k] == 1))
								rtNum = 3;
							else if ((mp->codonNucs[i][k] == 1 && mp->codonNucs[j][k] == 3) || (mp->codonNucs[i][k] == 3 && mp->codonNucs[j][k] == 1))
								rtNum = 4;
							else
								rtNum = 5;
							}
						}
					if (nDiff > 1)
						{
						mult = 0.0;
						}
					else
						{
						if (mp->codonAAs[i] == mp->codonAAs[j])
							mult = 1.0;
						else
							mult = nonsyn;
						if (rtNum == 0)
							mult *= rateValues[0];
						else if (rtNum == 1)
							mult *= rateValues[1];
						else if (rtNum == 2)
							mult *= rateValues[2];
						else if (rtNum == 3)
							mult *= rateValues[3];
						else if (rtNum == 4)
							mult *= rateValues[4];
						else
							mult *= rateValues[5];
						}
					
					a[i][i] -= (a[i][j] = bs[j] * mult);
					a[j][j] -= (a[j][i] = bs[i] * mult);
					if (mp->codonAAs[i] == mp->codonAAs[j])
						dS += (bs[i] * a[i][j] + bs[j] * a[j][i]);
					else
						dN += (bs[i] * a[i][j] + bs[j] * a[j][i]);
					scaler += bs[i] * a[i][j];
					scaler += bs[j] * a[j][i];
					}
				}
			}

		/* rescale Q matrix */
		if (m->nucModelId == NUCMODEL_CODON && m->numOmegaCats > 1)
			{
			/* If we have a positive selection model with multiple categories, then
			   we do not rescale the rate matrix until we have finished generating
			   all of the necessary rate matrices. The rescaling occurrs in 
			   UpDateCijk. */
			(*rA) = dN;
			(*rS) = dS;
			}
		else
			{
			scaler = 1.0 / scaler;
			for (i=0; i<n; i++)
				for (j=0; j<n; j++)
					a[i][j] *= scaler;
			(*rA) = (*rS) = 1.0;
			}			
		}

#	if 0
	for (i=0; i<n; i++)
		{
		for (j=0; j<n; j++)
			printf ("%0.5lf ", a[i][j]);
		printf ("\n");
		}
#	endif

#if defined (BEAGLE_ENABLED)
    if ( (m->nst == 1 || m->nst == 2) && m->numModelStates == 4)
        free (rateValues);
#endif

    return (NO_ERROR);
	
}

	



int SetProteinQMatrix (MrBFlt **a, int n, int whichChain, int division, MrBFlt rateMult)

{

	register int	i, j, k;
	int				aaModelID;
	MrBFlt			scaler, probOn, sum, *swr, s01, s10, *bs, *rt;
	ModelInfo		*m;
	ModelParams 	*mp;
		
	/* set up pointers to the appropriate model information */
	mp = &modelParams[division];
	m = &modelSettings[division];

	/* get amino acid model ID 
		AAMODEL_POISSON			0
		AAMODEL_JONES			1
		AAMODEL_DAY				2
		AAMODEL_MTREV			3
		AAMODEL_MTMAM			4
		AAMODEL_WAG				5
		AAMODEL_RTREV			6
		AAMODEL_CPREV           7
		AAMODEL_VT				8
		AAMODEL_BLOSUM			9
		AAMODEL_EQ			   10
		AAMODEL_GTR            11 */
		
	if (m->aaModelId >= 0)
		aaModelID = m->aaModelId;
	else
		aaModelID = (int)*GetParamVals(m->aaModel, whichChain, state[whichChain]);
	
	/* Make certain that we have either 20 or 40 states. Anything
	   else means we have a real problem. */
	if (n != 20 && n != 40)
		{
		MrBayesPrint ("%s   ERROR: There should be 20 or 40 states for the aa model\n");
		return (ERROR);
		}

	if (n == 20)
		{
		/* We have a run-of-the-mill amino acid model (i.e., 20 X 20). */
		if (aaModelID == AAMODEL_POISSON)
			{
			scaler = 1.0 / 19.0;
			for (i=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][j] = scaler;
					a[j][i] = scaler;
					}
				}
			for (i=0; i<20; i++)
				a[i][i] = -1.0;
			}
		else if (aaModelID == AAMODEL_EQ)
			{
			bs = GetParamSubVals (m->stateFreq, whichChain, state[whichChain]);
			for (i=0; i<20; i++)
				for (j=0; j<20; j++)
					a[i][j] = 0.0;
			scaler = 0.0;	
			for (i=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][i] -= (a[i][j] = bs[j]);
					a[j][j] -= (a[j][i] = bs[i]);
					scaler += bs[i] * a[i][j];
					scaler += bs[j] * a[j][i];
					}
				}
			scaler = 1.0 / scaler;
			for (i=0; i<20; i++)
				for (j=0; j<20; j++)
					a[i][j] *= scaler;
			}
		else if (aaModelID == AAMODEL_GTR)
			{
			bs = GetParamSubVals (m->stateFreq, whichChain, state[whichChain]);
			rt = GetParamVals (m->revMat, whichChain, state[whichChain]);
			for (i=0; i<20; i++)
				for (j=0; j<20; j++)
					a[i][j] = 0.0;
			scaler = 0.0;
			for (i=k=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][i] -= (a[i][j] = bs[j] * rt[k]);
					a[j][j] -= (a[j][i] = bs[i] * rt[k]);
					k++;
					}
				}
			for (i=0; i<20; i++)
				scaler += -(bs[i] * a[i][i]);
			for (i=0; i<20; i++)
				for (j=0; j<20; j++)
					a[i][j] /= scaler;
			}
		else if (aaModelID == AAMODEL_JONES)
			{
			for (i=0; i<20; i++)
				for (j=0; j<20; j++)
					a[i][j] = aaJones[i][j];
			}
		else if (aaModelID == AAMODEL_DAY)
			{
			for (i=0; i<20; i++)
				for (j=0; j<20; j++)
					a[i][j] = aaDayhoff[i][j];
			}
		else if (aaModelID == AAMODEL_MTREV)
			{
			for (i=0; i<20; i++)
				for (j=0; j<20; j++)
					a[i][j] = aaMtrev24[i][j];
			}
		else if (aaModelID == AAMODEL_MTMAM)
			{
			for (i=0; i<20; i++)
				for (j=0; j<20; j++)
					a[i][j] = aaMtmam[i][j];
			}
		else if (aaModelID == AAMODEL_RTREV)
			{
			for (i=0; i<20; i++)
				for (j=0; j<20; j++)
					a[i][j] = aartREV[i][j];
			}
		else if (aaModelID == AAMODEL_WAG)
			{
			for (i=0; i<20; i++)
				for (j=0; j<20; j++)
					a[i][j] = aaWAG[i][j];
			}
		else if (aaModelID == AAMODEL_CPREV)
			{
			for (i=0; i<20; i++)
				for (j=0; j<20; j++)
					a[i][j] = aacpREV[i][j];
			}
		else if (aaModelID == AAMODEL_VT)
			{
			for (i=0; i<20; i++)
				for (j=0; j<20; j++)
					a[i][j] = aaVt[i][j];
			}
		else if (aaModelID == AAMODEL_BLOSUM)
			{
			for (i=0; i<20; i++)
				for (j=0; j<20; j++)
					a[i][j] = aaBlosum[i][j];
			}
		else
			{
			MrBayesPrint ("%s   ERROR: Don't understand which amino acid model is needed\n");
			return (ERROR);
			}
#		if 0
		for (i=0; i<20; i++)
			{
			for (j=0; j<20; j++)
				printf ("%1.3lf ", a[i][j]);
			printf ("\n");
			}
#		endif
		}
	else
		{
		/* 40 X 40 covarion model:
		
		   We have a covarion model, and must set up the other quadrants. Note that if
		   we are at this point in the code, that we have already set up the upper left
		   portion of the 40 X 40 rate matrix. Note that if we have rate
		   variation across sites, that we need to deal with the multiplication
		   in the rate matrix (i.e., we cannot simply deal with rate variation
		   by multiplying the branch length by a rate multiplier as we can
		   with other models). Instead, we multiply the scaled rate matrix
		   by the rate multiplier. */

		/* Get the switching rates. The rate of off->on is s01 and the rate
		   of on->off is s10. The stationary probability of the switch process
		   is prob1 = s01/(s01+s10) and prob0 = s10/(s01+s10). */
		swr = GetParamVals (m->switchRates, whichChain, state[whichChain]);
		s01 = swr[0];
		s10 = swr[1];
		probOn = s01 / (s01 + s10);
		
		/* set matrix a[][] to 0 */
		for (i=0; i<40; i++)
			for (j=0; j<40; j++)
				a[i][j] = 0.0;	
				
		/* fill in upper-left sub matrix (where substitutions occur */
		if (aaModelID == AAMODEL_POISSON)
			{
			scaler = 0.0;
			for (i=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][j] = 0.05;
					a[j][i] = 0.05;
					scaler += 0.05 * a[i][j] * probOn;
					scaler += 0.05 * a[j][i] * probOn;
					}
				}
			}
		else if (aaModelID == AAMODEL_EQ)
			{
			bs = GetParamSubVals (m->stateFreq, whichChain, state[whichChain]);
			scaler = 0.0;
			for (i=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][j] = bs[j];
					a[j][i] = bs[i];
					scaler += bs[i] * a[i][j] * probOn;
					scaler += bs[j] * a[j][i] * probOn;
					}
				}
			}
		else if (aaModelID == AAMODEL_GTR)
			{
			bs = GetParamSubVals (m->stateFreq, whichChain, state[whichChain]);
			rt = GetParamVals (m->revMat, whichChain, state[whichChain]);
			for (i=0; i<20; i++)
				for (j=0; j<20; j++)
					a[i][j] = 0.0;
			scaler = 0.0;
			for (i=k=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][i] -= (a[i][j] = bs[j] * rt[k]);
					a[j][j] -= (a[j][i] = bs[i] * rt[k]);
					k++;
					}
				}
			for (i=0; i<20; i++)
				scaler += -(bs[i] * a[i][i]);
			for (i=0; i<20; i++)
				for (j=0; j<20; j++)
					a[i][j] /= scaler;
			for (i=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][j] = bs[j];
					a[j][i] = bs[i];
					scaler += bs[i] * a[i][j] * probOn;
					scaler += bs[j] * a[j][i] * probOn;
					}
				}
			}
		else if (aaModelID == AAMODEL_JONES)
			{
			scaler = 0.0;
			for (i=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][j] = aaJones[i][j];
					a[j][i] = aaJones[j][i];
					scaler += jonesPi[i] * a[i][j] * probOn;
					scaler += jonesPi[j] * a[j][i] * probOn;
					}
				}
			}
		else if (aaModelID == AAMODEL_DAY)
			{
			scaler = 0.0;
			for (i=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][j] = aaDayhoff[i][j];
					a[j][i] = aaDayhoff[j][i];
					scaler += dayhoffPi[i] * a[i][j] * probOn;
					scaler += dayhoffPi[j] * a[j][i] * probOn;
					}
				}
			}
		else if (aaModelID == AAMODEL_MTREV)
			{
			scaler = 0.0;
			for (i=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][j] = aaMtrev24[i][j];
					a[j][i] = aaMtrev24[j][i];
					scaler += mtrev24Pi[i] * a[i][j] * probOn;
					scaler += mtrev24Pi[j] * a[j][i] * probOn;
					}
				}
			}
		else if (aaModelID == AAMODEL_MTMAM)
			{
			scaler = 0.0;
			for (i=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][j] = aaMtmam[i][j];
					a[j][i] = aaMtmam[j][i];
					scaler += mtmamPi[i] * a[i][j] * probOn;
					scaler += mtmamPi[j] * a[j][i] * probOn;
					}
				}
			}
		else if (aaModelID == AAMODEL_RTREV)
			{
			scaler = 0.0;
			for (i=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][j] = aartREV[i][j];
					a[j][i] = aartREV[j][i];
					scaler += rtrevPi[i] * a[i][j] * probOn;
					scaler += rtrevPi[j] * a[j][i] * probOn;
					}
				}
			}
		else if (aaModelID == AAMODEL_WAG)
			{
			scaler = 0.0;
			for (i=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][j] = aaWAG[i][j];
					a[j][i] = aaWAG[j][i];
					scaler += wagPi[i] * a[i][j] * probOn;
					scaler += wagPi[j] * a[j][i] * probOn;
					}
				}
			}
		else if (aaModelID == AAMODEL_CPREV)
			{
			scaler = 0.0;
			for (i=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][j] = aacpREV[i][j];
					a[j][i] = aacpREV[j][i];
					scaler += cprevPi[i] * a[i][j] * probOn;
					scaler += cprevPi[j] * a[j][i] * probOn;
					}
				}
			}
		else if (aaModelID == AAMODEL_VT)
			{
			scaler = 0.0;
			for (i=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][j] = aaVt[i][j];
					a[j][i] = aaVt[j][i];
					scaler += vtPi[i] * a[i][j] * probOn;
					scaler += vtPi[j] * a[j][i] * probOn;
					}
				}
			}
		else if (aaModelID == AAMODEL_BLOSUM)
			{
			scaler = 0.0;
			for (i=0; i<20; i++)
				{
				for (j=i+1; j<20; j++)
					{
					a[i][j] = aaBlosum[i][j];
					a[j][i] = aaBlosum[j][i];
					scaler += blosPi[i] * a[i][j] * probOn;
					scaler += blosPi[j] * a[j][i] * probOn;
					}
				}
			}
		else
			{
			MrBayesPrint ("%s   ERROR: Don't understand which amino acid model is needed\n");
			return (ERROR);
			}

		/* rescale off diagonal elements of Q matrix */
		scaler = 1.0 / scaler;
		for (i=0; i<20; i++)
			{
			for (j=0; j<20; j++)
				{
				if (i != j)
					a[i][j] *= scaler;
				}
			}
			
		/* now, scale by rate factor */
		for (i=0; i<20; i++)
			{
			for (j=0; j<20; j++)
				{
				if (i != j)
					a[i][j] *= rateMult;
				}
			}
			
		/* put in diagonal elements */
		for (i=0; i<20; i++)
			{
			sum = 0.0;
			for (j=0; j<20; j++)
				{
				if (i != j)
					sum += a[i][j];
				a[i][i] = -(sum + s10);
				}
			}
				
		/* fill in the other three submatrices */
		for (i=20; i<40; i++)
			a[i][i] = -s01;
		for (i=0; i<20; i++)
			{
			a[i][20+i] = s10;
			a[20+i][i] = s01;
			}
					   
		}

	return (NO_ERROR);
	
}





int SetStdQMatrix (MrBFlt **a, int nStates, MrBFlt *bs, int cType)

{

	register int	i, j;
	MrBFlt			scaler;

	/* This function sets up ordered or unordered models for standard characters
	   with unequal stationary state frequencies. It requires the stationary
	   frequencies of the states (passed when calling the function). It also
	   needs to know the number of states and the type (ordered or unordered) 
	   of the character. */

	/* set Q matrix to 0 */
	for (i=0; i<nStates; i++)
        for (j=0; j<nStates; j++)
    		a[i][j] = 0.0;

	/* initialize Q matrix */
	scaler = 0.0;
	if (cType == UNORD)
		{
		/* unordered characters */
		for (i=0; i<nStates; i++)
			{
			for (j=0; j<nStates; j++)
				{
				if (i != j)
					{
					a[i][i] -= (a[i][j] = bs[j]);
					scaler += bs[i] * a[i][j];
					}
				}
			}
		}
	else
		{
		/* ordered characters */
		for (i=0; i<nStates; i++)
			{
			for (j=0; j<nStates; j++)
				{
				if (abs(i - j) == 1)
					{
					a[i][i] -= (a[i][j] = bs[j]);
					scaler += bs[i] * a[i][j];
					}
				}
			}
		}
		
	/* rescale Q matrix */
	for (i=0; i<nStates; i++)
		for (j=0; j<nStates; j++)
			a[i][j] /= scaler;

#	if defined DEBUG_SETSTDQMATRIX
	for (i=0; i<nStates; i++)
		{
		for (j=0; j<nStates; j++)
			printf ("%0.5lf ", a[i][j]);
		printf ("\n");
		}
#	endif

	return (NO_ERROR);
	
}





/*----------------------------------------------------------------------
|
|   SetUpPartitionCounters: Set up partitions and the root of the
|      partition frequency tree							
|
|----------------------------------------------------------------------*/
int SetUpPartitionCounters (void)
{
	int		i;
	
#	if defined (MPI_ENABLED)
	/* we only keep partition counters on proc 0 in the MPI version */
	if (proc_id != 0)
		return (NO_ERROR);
#	endif
	nLongsNeeded = 1 + (numLocalTaxa - 1) / nBitsInALong;
	
	if (memAllocs[ALLOC_PFCOUNTERS] == YES)
		{
		MrBayesPrint ("%s   ERROR: pfcounters not free in SetUpPartitionCounters\n", spacer);
		return ERROR;
		}
	partition = (SafeLong **) SafeCalloc (2*numLocalTaxa, sizeof (SafeLong *));
	if (partition == NULL)
		{
		MrBayesPrint ("%s   Failed to allocate partition in SetUpPartitionCounters\n", spacer);
		return ERROR;
		}
	partition[0] = (SafeLong *) SafeCalloc (2*numLocalTaxa * nLongsNeeded, sizeof(SafeLong));
	if (partition[0] == NULL)
		{
		free (partition);
		MrBayesPrint ("%s   Failed to allocate partition[0] in SetUpPartitionCounters\n", spacer);
		return ERROR;
		}
	partFreqTreeRoot = (PFNODE **) SafeCalloc (numTopologies, sizeof (PFNODE *));
	if (partFreqTreeRoot == NULL)
		{
		free (partition);
		free (partition[0]);
		MrBayesPrint ("%s   Failed to allocate partFreqTreeRoot in SetUpPartitionCounters\n", spacer);
		return ERROR;
		}
	memAllocs[ALLOC_PFCOUNTERS] = YES;

	for (i=1; i<2*numLocalTaxa; i++)
		{
		partition[i] = partition[0] + i*nLongsNeeded;
		}
	
	for (i=0; i<numLocalTaxa; i++)
		SetBit (i, partition[i]);

	for (i=0; i<numTopologies; i++)
		partFreqTreeRoot[i] = NULL;

	return NO_ERROR;
}





/*----------------------------------------------------------------------
|
|	SetupTermState: create matrix holding unambiguous states for
|		terminals (used for local compression on terminal branches)
|
-----------------------------------------------------------------------*/
int SetUpTermState (void)

{

	int			i, k, n, c, d, x=0, nReps, *termStatePtr;
	SafeLong	*p;
	ModelInfo	*m;
	ModelParams *mp;
	int			numComprChars = 0; 

	/* allocate space for termState and isPartAmbig */
	if (memAllocs[ALLOC_TERMSTATE] == YES || memAllocs[ALLOC_ISPARTAMBIG] == YES)
		{
		MrBayesPrint ("%s   termState or isPartAmbig is not free in SetupTermState\n", spacer);
		return ERROR;
		}

#if defined SSE_ENABLED
	for (d=0; d<numCurrentDivisions; d++)
		{
		m = &modelSettings[d];
		m->numSSEChars = ((m->numChars - 1) / FLOATS_PER_VEC) + 1;
		if( m->dataType != STANDARD && m->gibbsGamma == NO )
			numComprChars += m->numSSEChars * FLOATS_PER_VEC;
		else
			numComprChars += m->numChars;
		}
#else
	numComprChars = numCompressedChars;
#endif

	termState = (int *) SafeCalloc (numLocalTaxa * numComprChars, sizeof(int));
	if (termState)
		memAllocs[ALLOC_TERMSTATE] = YES;
	else
		{
		MrBayesPrint ("%s   Problem allocating termState\n", spacer);
		return (ERROR);
		}
	isPartAmbig = (int *) SafeCalloc (numLocalTaxa*numCurrentDivisions, sizeof(int));
	if (isPartAmbig)
		memAllocs[ALLOC_ISPARTAMBIG] = YES;
	else
		{
		MrBayesPrint ("%s   Problem allocating isPartAmbig\n", spacer);
		return (ERROR);
		}

	/*initialize isPartAmbig */
	for (i=0; i<numLocalTaxa*numCurrentDivisions; i++)
		isPartAmbig[i] = NO;

	/* loop over divisions */
    termStatePtr = termState;
	for (d=0; d<numCurrentDivisions; d++)
		{
		m = &modelSettings[d];
		mp = &modelParams[d];

		/* don't do anything for continuous data */
		if (mp->dataType == CONTINUOUS)
			continue;
		
		if (m->numModelStates > m->numStates)
			nReps = m->numModelStates / mp->nStates;

        m->termState   = (int **) SafeCalloc (numLocalTaxa, sizeof(int *));
        if (!m->termState)
            {
            MrBayesPrint("%s   Problems allocating termState pointers for division %d\n", spacer, d+1);
            return ERROR;
            }



#if defined SSE_ENABLED
		if( m->dataType != STANDARD && m->gibbsGamma == NO )
			numComprChars = m->numSSEChars * FLOATS_PER_VEC;
		else
			numComprChars = m->numChars;	

#else
			numComprChars = m->numChars;
#endif

		for (i=0; i<numLocalTaxa; i++)
            {
            m->termState[i] = termStatePtr;
            termStatePtr += numComprChars;
            }

        m->isPartAmbig = isPartAmbig + numLocalTaxa * d;

		for (i=0; i<numLocalTaxa; i++)
			{
			p = m->parsSets[i];
			for (c=0; c<m->numChars; c++)
				{
				for (k=n=0; k<m->numStates; k++)
					{
					if (IsBitSet(k, p))
						{
						x = k;
						n++;
						}
					}
				/* find appropriate index */
				if (n == 1)
					m->termState[i][c] = x * m->numModelStates;
				else if (n == m->numStates)
					m->termState[i][c] = m->numStates * m->numModelStates;
				else
					m->isPartAmbig[i] = YES;

				p += m->nParsIntsPerSite;
				}
			for (; c<numComprChars; c++)
				{
					 /*Setting to fully ambyg state all padding chars*/
					m->termState[i][c] = m->numStates * m->numModelStates;
				}
			}
		}


	/* print the termState matrix */
#	if	defined (DEBUG_SETUPTERMSTATE)
	PrintTermState();
	getchar();
#	endif

	return NO_ERROR;
	
}





/*----------------------------------------------------------------------------
|
|	SetUsedMoves: This function will extract an array of pointers to the moves
|      that will actually be used in the MCMC sampling. It also makes sure
|      that the parsimonyBased flag is set in the relevant model partitions
|      if there are moves used that are based on parsimony scores
|
-----------------------------------------------------------------------------*/
int SetUsedMoves (void)

{
	
	int			i, j, moveIndex, numGlobalChains;
	MrBFlt		prob, sum, cumSum;

	/* first count moves */
	numUsedMoves = 0;
	numGlobalChains = chainParams.numChains * chainParams.numRuns;
	for (i=0; i<numApplicableMoves; i++)
		{
		prob = 0.0;
		for (j=0; j<numGlobalChains; j++)
			{
			if (moves[i]->relProposalProb[j] > prob)
				prob = moves[i]->relProposalProb[j];
			}
		if (prob > 0.000001)
			numUsedMoves++;
		}
	
	/* allocate space */
	if (memAllocs[ALLOC_USEDMOVES] == YES)
		{
		MrBayesPrint ("%s   Memory problem: usedMoves not free in SetUsedMoves\n", spacer);
		return (ERROR);
		}
	usedMoves = (MCMCMove **) SafeMalloc (numUsedMoves * sizeof (MCMCMove *));
	if (!usedMoves)
		{
		MrBayesPrint ("%s   Problem allocating usedMoves\n", spacer);
		return (ERROR);
		}
	memAllocs[ALLOC_USEDMOVES] = YES;
		
	/* set move pointers */
	moveIndex = 0;
	for (i=0; i<numApplicableMoves; i++)
		{
		prob = 0.0;
		for (j=0; j<numGlobalChains; j++)
			{
			if (moves[i]->relProposalProb[j] > prob)
				prob = moves[i]->relProposalProb[j];
			}
		if (prob > 0.000001)
			usedMoves[moveIndex++] = moves[i];
		}
	
	if (moveIndex != numUsedMoves)
		{
		MrBayesPrint ("%s   Problem finding the used moves\n", spacer);
		return (ERROR);
		}

	/* set parsimony flag if applicable */
	for (i=0; i<numCurrentDivisions; i++)
		modelSettings[i].parsimonyBasedMove = NO;
	for (i=0; i<numUsedMoves; i++)
		{
		if (usedMoves[i]->moveType->parsimonyBased == YES)
			{
			for (j=0; j<usedMoves[i]->parm->nRelParts; j++)
				modelSettings[usedMoves[i]->parm->relParts[j]].parsimonyBasedMove = YES;
			}		
		}

	/* set cumulative proposal probabilities */
	for (j=0; j<numGlobalChains; j++)
		{
		sum = 0.0;
		for (i=0; i<numUsedMoves; i++)
			{
			sum += usedMoves[i]->relProposalProb[j];
			}
		cumSum = 0.0;
		for (i=0; i<numUsedMoves; i++)
			{
			cumSum += usedMoves[i]->relProposalProb[j];
			usedMoves[i]->cumProposalProb[j] = cumSum / sum;
			}
		}

    /* reset acceptance probability values */
    for (i=0; i<numUsedMoves; i++)
        {
        for (j=0; j<numGlobalChains; j++)
            {
            usedMoves[i]->nAccepted[j] = 0;
            usedMoves[i]->nTried[j] = 0;
            usedMoves[i]->nTotAccepted[j] = 0;
            usedMoves[i]->nTotTried[j] = 0;
            }
        }

	return (NO_ERROR);
	
}





void ShowValuesForChain (int chn)

{

	int				i;
	char			s[100];
		
	MrBayesPrint ("%s   Chain = %d\n", spacer, chn);
	MrBayesPrint ("%s      numParams = %d\n", spacer, numParams);
	MrBayesPrint ("%s      numTrees  = %d\n", spacer, numTrees);
	MrBayesPrint ("%s      current state: %d\n", spacer, state[chn]);
	
	strcat (spacer, "   ");

	/* tRatio */
	for (i=0; i<numCurrentDivisions; i++)
		{
		sprintf (s, "tRatio[%d]", i);
		PrintParamValues (modelSettings[i].tRatio, chn, s);
		}

	/* revMat */
	for (i=0; i<numCurrentDivisions; i++)
		{
		sprintf (s, "revMat[%d]", i);
		PrintParamValues (modelSettings[i].revMat, chn, s);
		}

	/* stateFreq */
	for (i=0; i<numCurrentDivisions; i++)
		{
		sprintf (s, "stateFreq[%d]", i);
		PrintParamValues (modelSettings[i].stateFreq, chn, s);
		}

	/* omega */
	for (i=0; i<numCurrentDivisions; i++)
		{
		sprintf (s, "omega[%d]", i);
		PrintParamValues (modelSettings[i].omega, chn, s);
		}

	/* shape */
	for (i=0; i<numCurrentDivisions; i++)
		{
		sprintf (s, "shape[%d]", i);
		PrintParamValues (modelSettings[i].shape, chn, s);
		}

	/* pInvar */
	for (i=0; i<numCurrentDivisions; i++)
		{
		sprintf (s, "pInvar[%d]", i);
		PrintParamValues (modelSettings[i].pInvar, chn, s);
		}

	/* correlation */
	for (i=0; i<numCurrentDivisions; i++)
		{
		sprintf (s, "correlation[%d]", i);
		PrintParamValues (modelSettings[i].correlation, chn, s);
		}

	/* switchRates */
	for (i=0; i<numCurrentDivisions; i++)
		{
		sprintf (s, "switchRates[%d]", i);
		PrintParamValues (modelSettings[i].switchRates, chn, s);
		}

	/* rateMult */
	for (i=0; i<numCurrentDivisions; i++)
		{
		sprintf (s, "rateMult[%d]", i);
		PrintParamValues (modelSettings[i].rateMult, chn, s);
		}

	/* speciationRates */
	for (i=0; i<numCurrentDivisions; i++)
		{
		sprintf (s, "speciationRates[%d]", i);
		PrintParamValues (modelSettings[i].speciationRates, chn, s);
		}

	/* extinctionRates */
	for (i=0; i<numCurrentDivisions; i++)
		{
		sprintf (s, "extinctionRates[%d]", i);
		PrintParamValues (modelSettings[i].extinctionRates, chn, s);
		}

	/* popSize */
	for (i=0; i<numCurrentDivisions; i++)
		{
		sprintf (s, "popSize[%d]", i);
		PrintParamValues (modelSettings[i].popSize, chn, s);
		}

	/* topology */
	for (i=0; i<numCurrentDivisions; i++)
		{
		MrBayesPrint ("%s   topology[%d] state 0\n", spacer, i);
		ShowTree(GetTree (modelSettings[i].topology, chn, 0));
		MrBayesPrint ("%s   topology[%d] state 1\n", spacer, i);
		ShowTree(GetTree (modelSettings[i].topology, chn, 1));
		}
		
	/* brlens */
	for (i=0; i<numCurrentDivisions; i++)
		{
		MrBayesPrint ("%s   tree[%d] state 0\n", spacer, i);
		ShowTree(GetTree (modelSettings[i].topology, chn, 0));
		MrBayesPrint ("%s   tree[%d] state 1\n", spacer, i);
		ShowTree(GetTree (modelSettings[i].topology, chn, 1));
		}

	spacer[strlen(spacer) - 3] = '\0';

#	if	0
	for (i=0; i<sizeOfParamValues; i++)
		MrBayesPrint ("%4d -- %lf\n", i, paramValues[i]);
#	endif

}





/* SmallestNonemptyPFNode: recursive function to smallest nonempty node in a subtree */
PFNODE *SmallestNonemptyPFNode (PFNODE *p, int *i, int j)
{
	PFNODE *q;

	++j;
	if (p == NULL)
		return NULL;
	
	q = SmallestNonemptyPFNode (p->right, i, j);
	
	if (q != NULL)
		{
		return q;
		}
	else if (IsPFNodeEmpty (p) == NO)
		{
		*i = j;
		return p;
		}
	else
		{
		return SmallestNonemptyPFNode (p->left, i, j);
		}
}





/* Talloc: Allocate space for a new node in the tree keeping track of partition frequencies */
PFNODE *Talloc (void)
{
	PFNODE	*temp;

	temp = (PFNODE *) SafeMalloc (sizeof(PFNODE));
	if (temp == NULL)
		return NULL;

	temp->partition = (SafeLong *) SafeCalloc (nLongsNeeded, sizeof (SafeLong));
	if (temp->partition == NULL)
		{
		free (temp);
		return NULL;
		}

	temp->count = (int *) SafeCalloc (chainParams.numRuns, sizeof (int));
	if (temp->count == NULL)
		{
		free (temp->partition);
		free (temp);
		return NULL;
		}

	return temp; 
}





MrBFlt Temperature (int id)

{

	/* let id be number of chain in run */
	id %= chainParams.numChains;
	
	if (chainParams.userDefinedTemps == YES)
		{
		return (chainParams.userTemps[id]);
		}
	else
		{
		return (1.0 / (1.0 + chainParams.chainTemp * id));
		}

}





/* Tfree: Free space for partition frequency counter tree */
void Tfree (PFNODE *r)
{
	if (r != NULL)
		{
		if (r->left != NULL)
			Tfree (r->left);
		if (r->right != NULL)
			Tfree (r->right);

		free (r->partition);
		free (r->count);
		free (r);
		}
}





int TiProbs_Fels (TreeNode *p, int division, int chain)

{

	int			i, j, k, index;
	MrBFlt		t, u, x, z, beta, bigPi_j[4], pij, bigPij,
				*catRate, baseRate, theRate, *pis, length;
	CLFlt		*tiP;
	ModelInfo	*m;

	m = &modelSettings[division];

	/* find transition probabilities */
    tiP = m->tiProbs[m->tiProbsIndex[chain][p->index]];

	/* get base frequencies */
	pis = GetParamSubVals (m->stateFreq, chain, state[chain]);
	
	/* get rate multipliers (for gamma & partition specific rates) */
	theRate =  1.0;
	baseRate =  GetRate (division, chain);
	/* compensate for invariable sites if appropriate */
	if (m->pInvar != NULL)
		baseRate /= ( 1.0 - ( *GetParamVals(m->pInvar, chain, state[chain])));
	/* get category rates */
	if (m->shape == NULL)
		catRate = &theRate;
	else
		catRate = GetParamSubVals (m->shape, chain, state[chain]);
	
	/* rescale beta */
	beta =  (0.5 / ((pis[0] + pis[2])*(pis[1] + pis[3]) + ((pis[0]*pis[2]) + (pis[1]*pis[3]))));

	bigPi_j[0] =  (pis[0] + pis[2]);
	bigPi_j[1] =  (pis[1] + pis[3]);
	bigPi_j[2] =  (pis[0] + pis[2]);
	bigPi_j[3] =  (pis[1] + pis[3]);

	/* find length */
	if (m->cppEvents != NULL)
		{
		length = GetParamSubVals (m->cppEvents, chain, state[chain])[p->index];
		}
	else if (m->tk02BranchRates != NULL)
		{
        length = GetParamSubVals (m->tk02BranchRates, chain, state[chain])[p->index];
		}
	else if (m->igrBranchRates != NULL)
		{
        length = GetParamSubVals (m->igrBranchRates, chain, state[chain])[p->index];
		}
	else
		length = p->length;

    /* numerical errors will ensue if we allow very large or very small branch lengths, which might
       occur in relaxed clock models; an elegant solution would be to substitute the stationary
       probs and initial probs but for now we truncate lengths at small or large values */
    if (length > BRLENS_MAX)
        length = BRLENS_MAX;
    else if (length < BRLENS_MIN)
        length = BRLENS_MIN;

	/* fill in values */
	for (k=index=0; k<m->numGammaCats; k++)
		{
		t =  length * baseRate * catRate[k];

		/* calculate probabilities */
		for (i=0; i<4; i++)
			{
			for (j=0; j<4; j++)
				{
				bigPij = bigPi_j[j];
				pij =  pis[j];
				u =  1.0/bigPij -  1.0;
				x =  exp(-beta * t);
				z = (bigPij - pij) / bigPij;
				
				if (i == j)
					tiP[index++] = (CLFlt) (pij + pij * u * x + z * x);
				else
					tiP[index++] = (CLFlt) (pij + pij * u * x - (pij/bigPij) * x);
				}
			}
		}

	return NO_ERROR;

}





/*----------------------------------------------------------------
|
|	TiProbs_Gen: Calculates transition probabilities for general
|		models with or without rate variation. This function does
|       not work with:
|      
|       1. codon models with omega variation or
|       2. covarion models with rate variation
|
|   In either of these cases, TiProbs_GenCov is used
|
-----------------------------------------------------------------*/
int TiProbs_Gen (TreeNode *p, int division, int chain)

{
	
	register int	i, j, k, n, s, index;
	MrBFlt			t, *catRate, baseRate, *eigenValues, *cijk, 
					EigValexp[64], sum, *ptr, theRate, correctionFactor,
					length;
	CLFlt			*tiP;
	ModelInfo		*m;
	
	m = &modelSettings[division];
	n = m->numModelStates;
	
	/* find the correction factor to make branch lengths
	   in terms of expected number of substitutions per character */
	correctionFactor = 1.0;
	if (m->dataType == DNA || m->dataType == RNA)
		{
		if (m->nucModelId == NUCMODEL_DOUBLET)
			correctionFactor = 2.0;
		else if (m->nucModelId == NUCMODEL_CODON)
			correctionFactor = 3.0;
		}

	/* find transition probabilities */
	tiP = m->tiProbs[m->tiProbsIndex[chain][p->index]];
	
	/* get rate multipliers (for gamma & partition specific rates) */
	theRate = 1.0;
	baseRate =  GetRate (division, chain);
	
	/* compensate for invariable sites if appropriate */
	if (m->pInvar != NULL)
		baseRate /= ( 1.0 - ( *GetParamVals(m->pInvar, chain, state[chain])));
		
	/* get category rates */
	if (m->shape == NULL)
		catRate = &theRate;
	else
		catRate = GetParamSubVals (m->shape, chain, state[chain]);
		
	/* get eigenvalues and cijk pointers */
	eigenValues = m->cijks[m->cijkIndex[chain]];
    cijk        = eigenValues + (2 * n);

	/* find length */
	if (m->cppEvents != NULL)
		{
		length = GetParamSubVals (m->cppEvents, chain, state[chain])[p->index];
		}
	else if (m->tk02BranchRates != NULL)
		{
        length = GetParamSubVals (m->tk02BranchRates, chain, state[chain])[p->index];
		}
	else if (m->igrBranchRates != NULL)
		{
        length = GetParamSubVals (m->igrBranchRates, chain, state[chain])[p->index];
		}
	else
		length = p->length;

    /* numerical errors will ensue if we allow very large or very small branch lengths, which might
       occur in relaxed clock models; an elegant solution would be to substitute the stationary
       probs and initial probs but for now we truncate lengths at small or large values */
    if (length > BRLENS_MAX)
        length = BRLENS_MAX;
    else if (length < BRLENS_MIN)
        length = BRLENS_MIN;

	/* fill in values */
	for (k=index=0; k<m->numGammaCats; k++)
		{
		t =  length * baseRate * catRate[k] * correctionFactor;
		
		for (s=0; s<n; s++)
			EigValexp[s] =  exp(eigenValues[s] * t);

		ptr = cijk;
		for (i=0; i<n; i++)
			{
			for (j=0; j<n; j++)
				{
				sum = 0.0;
				for(s=0; s<n; s++)
					sum += (*ptr++) * EigValexp[s];
				tiP[index++] = (CLFlt) ((sum < 0.0) ? 0.0 : sum);
				}
			}
		}

#	if 0
	printf ("v = %lf (%d)\n", t, p->index);
	for (i=index=0; i<n; i++)
		{
		for (j=0; j<n; j++)
			printf ("%1.4lf ", tiP[index++]);
		printf ("\n");
		}
	printf ("\n");
#	endif

	return NO_ERROR;

}





/*----------------------------------------------------------------
|
|	TiProbs_GenCov: Calculates transition probabilities for codon
|		models with omega variation or covarion models with
|       rate variation.
|
-----------------------------------------------------------------*/
int TiProbs_GenCov (TreeNode *p, int division, int chain)

{
	
	register int	i, j, k, n, s, index;
	int				sizeOfSingleCijk;
	MrBFlt			t, *eigenValues, *cijk, EigValexp[64], sum, *ptr, correctionFactor,
		            length;
	CLFlt			*tiP;
	ModelInfo		*m;
	
	m = &modelSettings[division];
	n = m->numModelStates;
	
	/* find the correction factor to make branch lengths
	   in terms of expected number of substitutions per character */
	correctionFactor = 1.0;
	if (m->dataType == DNA || m->dataType == RNA)
		{
		if (m->nucModelId == NUCMODEL_DOUBLET)
			correctionFactor = 2.0;
		else if (m->nucModelId == NUCMODEL_CODON)
			correctionFactor = 3.0;
		}

	/* find transition probabilities */
	tiP = m->tiProbs[m->tiProbsIndex[chain][p->index]];
    		
	/* get eigenvalues and cijk pointers */
	eigenValues = m->cijks[m->cijkIndex[chain]];
	cijk        = eigenValues + (2 * n);
	
	/* get offset size (we need to move the pointers to the appropriate
	   cijk information for these models) */
	sizeOfSingleCijk = m->cijkLength / m->nCijkParts;

	/* find length */
    if (m->cppEvents != NULL)
		{
		length = GetParamSubVals (m->cppEvents, chain, state[chain])[p->index];
		}
	else if (m->tk02BranchRates != NULL)
		{
        length = GetParamSubVals (m->tk02BranchRates, chain, state[chain])[p->index];
		}
	else if (m->igrBranchRates != NULL)
		{
        length = GetParamSubVals (m->igrBranchRates, chain, state[chain])[p->index];
		}
	else
		length = p->length;

    /* numerical errors will ensue if we allow very large or very small branch lengths, which might
       occur in relaxed clock models; an elegant solution would be to substitute the stationary
       probs and initial probs but for now we truncate lengths at small or large values */
    if (length > BRLENS_MAX)
        length = BRLENS_MAX;
    else if (length < BRLENS_MIN)
        length = BRLENS_MIN;

	/* fill in values */
	for (k=index=0; k<m->nCijkParts; k++)
		{
		t =  length * correctionFactor;
		for (s=0; s<n; s++)
			EigValexp[s] =  exp(eigenValues[s] * t);

		ptr = cijk;
		for (i=0; i<n; i++)
			{
			for (j=0; j<n; j++)
				{
				sum = 0.0;
				for(s=0; s<n; s++)
					sum += (*ptr++) * EigValexp[s];
				tiP[index++] = (CLFlt) ((sum < 0.0) ? 0.0 : sum);
				}
			}
			
		/* increment pointers by m->cijkLength */
		if (k+1 < m->nCijkParts)
			{
			/* shift pointers */
			eigenValues += sizeOfSingleCijk;
			cijk        += sizeOfSingleCijk;
			}
		}
		
#	if 0
	for (i=index=0; i<n; i++)
		{
		for (j=0; j<n; j++)
			printf ("%1.4lf ", tiP[index++]);
		printf ("\n");
		}
#	endif

	return NO_ERROR;

}





/*-----------------------------------------------------------------
|
|	TiProbs_Hky: update transition probabilities for 4by4
|		nucleotide model with nst == 2 (K80/HKY85)
|		with or without rate variation
|
------------------------------------------------------------------*/
int TiProbs_Hky (TreeNode *p, int division, int chain)

{

	int			i, j, k, index;
	MrBFlt		t, kap, u, w, x, y, z, beta, bigPi_j[4], pij, bigPij, *pis,
				*catRate, baseRate, theRate, length;
	CLFlt		*tiP;
	ModelInfo	*m;
	
	m = &modelSettings[division];

	/* find transition probabilities */
    tiP = m->tiProbs[m->tiProbsIndex[chain][p->index]];

	/* get kappa */
	kap =  *GetParamVals (m->tRatio, chain, state[chain]);
	
	/* get base frequencies */
	pis = GetParamSubVals (m->stateFreq, chain, state[chain]);
	
	/* get rate multipliers (for gamma & partition specific rates) */
	theRate = 1.0;
	baseRate =  GetRate (division, chain);
	/* compensate for invariable sites if appropriate */
	if (m->pInvar != NULL)
		baseRate /= ( 1.0 - ( *GetParamVals(m->pInvar, chain, state[chain])));
	/* get category rates */
	if (m->shape == NULL)
		catRate = &theRate;
	else
		catRate = GetParamSubVals (m->shape, chain, state[chain]);
	
	/* rescale beta */
	beta =  0.5 / ((pis[0] + pis[2])*(pis[1] + pis[3]) + kap*((pis[0]*pis[2]) + (pis[1]*pis[3])));

	bigPi_j[0] = pis[0] + pis[2];
	bigPi_j[1] = pis[1] + pis[3];
	bigPi_j[2] = pis[0] + pis[2];
	bigPi_j[3] = pis[1] + pis[3];

	/* find length */
	if (m->cppEvents != NULL)
		{
		length = GetParamSubVals (m->cppEvents, chain, state[chain])[p->index];
		}
	else if (m->tk02BranchRates != NULL)
		{
        length = GetParamSubVals (m->tk02BranchRates, chain, state[chain])[p->index];
		}
	else if (m->igrBranchRates != NULL)
		{
        length = GetParamSubVals (m->igrBranchRates, chain, state[chain])[p->index];
		}
	else
		length = p->length;

    /* numerical errors will ensue if we allow very large or very small branch lengths, which might
       occur in relaxed clock models; an elegant solution would be to substitute the stationary
       probs and initial probs but for now we truncate lengths at small or large values */
    if (length > BRLENS_MAX)
        length = BRLENS_MAX;
    else if (length < BRLENS_MIN)
        length = BRLENS_MIN;

	/* fill in values */
	for (k=index=0; k<m->numGammaCats; k++)
		{
		t =  length * baseRate * catRate[k];

		/* calculate probabilities */
		for (i=0; i<4; i++)
			{
			for (j=0; j<4; j++)
				{
				bigPij = bigPi_j[j];
				pij = pis[j];
				u =  1.0/bigPij -  1.0;
				w = -beta * ( 1.0 + bigPij * (kap -  1.0));
				x =  exp(-beta * t);
				y =  exp(w * t);
				z = (bigPij - pij) / bigPij;
				
				if (i == j)
					tiP[index++] = (CLFlt) (pij + pij * u * x + z * y);
				else if ((i == 0 && j == 2) || (i == 2 && j == 0) || (i == 1 && j == 3) || (i == 3 && j == 1))
					tiP[index++] = (CLFlt) (pij + pij * u * x - (pij/bigPij) * y);
				else
					tiP[index++] = (CLFlt) (pij * ( 1.0 - x));
				}
			}
		}
		
	return NO_ERROR;

}





/*-----------------------------------------------------------------
|
|	TiProbs_JukesCantor: update transition probabilities for 4by4
|		nucleotide model with nst == 1 (Jukes-Cantor)
|		with or without rate variation
|
------------------------------------------------------------------*/
int TiProbs_JukesCantor (TreeNode *p, int division, int chain)

{
	
	/* calculate Jukes Cantor transition probabilities */
	
	int			i, j, k, index;
	MrBFlt		*catRate, baseRate, length;
	CLFlt		pNoChange, pChange, *tiP;
	ModelInfo	*m;
	
	m = &modelSettings[division];

	/* find transition probabilities */
	tiP = m->tiProbs[m->tiProbsIndex[chain][p->index]];

	baseRate =  1.0;
	if (m->shape == NULL)
		catRate = &baseRate;
	else
		catRate = GetParamSubVals (m->shape, chain, state[chain]);
	
	/* find length */
	if (m->cppEvents != NULL)
		{
		length = GetParamSubVals (m->cppEvents, chain, state[chain])[p->index];
		}
	else if (m->tk02BranchRates != NULL)
		{
        length = GetParamSubVals (m->tk02BranchRates, chain, state[chain])[p->index];
		}
	else if (m->igrBranchRates != NULL)
		{
        length = GetParamSubVals (m->igrBranchRates, chain, state[chain])[p->index];
		}
	else
		length = p->length;

    /* numerical errors will ensue if we allow very large or very small branch lengths, which might
       occur in relaxed clock models; an elegant solution would be to substitute the stationary
       probs and initial probs but for now we truncate lengths at small or large values */
    if (length > BRLENS_MAX)
        length = BRLENS_MAX;
    else if (length < BRLENS_MIN)
        length = BRLENS_MIN;

	/* fill in values */
	for (k=index=0; k<m->numGammaCats; k++)
		{
		/* calculate probabilities */
		pChange   = (CLFlt) (0.25 - 0.25 * exp(-(4.0/3.0)*length*catRate[k]));
		pNoChange = (CLFlt) (0.25 + 0.75 * exp(-(4.0/3.0)*length*catRate[k]));
		for (i=0; i<4; i++)
			{
			for (j=0; j<4; j++)
				{
				if (i == j)
					tiP[index++] = pNoChange;
				else
					tiP[index++] = pChange;
				}
			}
		}

	return NO_ERROR;
}





/*-----------------------------------------------------------------
|
|	TiProbs_Res: update transition probabilities for binary
|		restriction site model with or without rate variation
|
------------------------------------------------------------------*/
int TiProbs_Res (TreeNode *p, int division, int chain)

{
	
	int			k, index;
	MrBFlt		baseRate, eV, mu, theRate, v,
				*bs, *catRate, length;
	CLFlt		*tiP;
	ModelInfo	*m;
	
	/* find model settings for the division */
	m = &modelSettings[division];

	/* find transition probabilities */
	tiP = m->tiProbs[m->tiProbsIndex[chain][p->index]];

	/* find rates */
	baseRate =  GetRate (division, chain);
	theRate =  1.0;
	if (m->shape == NULL)
		catRate = &theRate;
	else
		catRate = GetParamSubVals (m->shape, chain, state[chain]);
	
	/* find base frequencies */
	bs = GetParamSubVals(m->stateFreq, chain, state[chain]);

	/* calculate scaling factor */
	mu =  1.0 / (2.0 * bs[0] * bs[1]);
	
	/* find length */
	if (m->cppEvents != NULL)
		{
		length = GetParamSubVals (m->cppEvents, chain, state[chain])[p->index];
		}
	else if (m->tk02BranchRates != NULL)
		{
        length = GetParamSubVals (m->tk02BranchRates, chain, state[chain])[p->index];
		}
	else if (m->igrBranchRates != NULL)
		{
        length = GetParamSubVals (m->igrBranchRates, chain, state[chain])[p->index];
		}
	else
		length = p->length;

    /* numerical errors will ensue if we allow very large or very small branch lengths, which might
       occur in relaxed clock models; an elegant solution would be to substitute the stationary
       probs and initial probs but for now we truncate lengths at small or large values */
    if (length > BRLENS_MAX)
        length = BRLENS_MAX;
    else if (length < BRLENS_MIN)
        length = BRLENS_MIN;

	/* fill in values */
	for (k=index=0; k<m->numGammaCats; k++)
		{
		/* calculate probabilities */
		v =  length * baseRate * catRate[k];
		eV =  exp(-mu * v);
		tiP[index++] = (CLFlt) (bs[0] + bs[1] * eV);
		tiP[index++] = (CLFlt) (bs[1] - bs[1] * eV);
		tiP[index++] = (CLFlt) (bs[0] - bs[0] * eV);
		tiP[index++] = (CLFlt) (bs[1] + bs[0] * eV);
		}

	return NO_ERROR;

}





/*-----------------------------------------------------------------
|
|	TiProbs_Std: update transition probabilities for
|		variable states model with or without rate variation
|
------------------------------------------------------------------*/
int TiProbs_Std (TreeNode *p, int division, int chain)

{
	
	int			b, c, i, j, k, n, s, nStates, index=0, index2;
	MrBFlt		v, eV1, eV2, eV3, eV4, eV5, *catRate,
				baseRate, theRate, pi, f1, f2, f3, f4, f5, f6, f7, root, EigValexp[10],
				*eigenValues, *cijk, sum, *bs, mu, length;
	CLFlt		pNoChange, pChange, *tiP;
	ModelInfo	*m;
#	if defined (DEBUG_TIPROBS_STD)
	int			index3;
#	endif

	m = &modelSettings[division];

	/* find transition probabilities */
    tiP = m->tiProbs[m->tiProbsIndex[chain][p->index]];
    
	/* get rate multiplier */
	theRate =  1.0;
	baseRate =  GetRate (division, chain);

	/* get category rates */
	if (m->shape == NULL)
		catRate = &theRate;
	else
		catRate = GetParamSubVals (m->shape, chain, state[chain]);
	
#	if defined (DEBUG_TIPROBS_STD)
	/* find base frequencies */
	bs = GetParamStdStateFreqs (m->stateFreq, chain, state[chain]);
#	endif

	/* find length */
	if (m->cppEvents != NULL)
		{
		length = GetParamSubVals (m->cppEvents, chain, state[chain])[p->index];
		}
	else if (m->tk02BranchRates != NULL)
		{
        length = GetParamSubVals (m->tk02BranchRates, chain, state[chain])[p->index];
		}
	else if (m->igrBranchRates != NULL)
		{
        length = GetParamSubVals (m->igrBranchRates, chain, state[chain])[p->index];
		}
	else
		length = p->length;

    /* numerical errors will ensue if we allow very large or very small branch lengths, which might
       occur in relaxed clock models; an elegant solution would be to substitute the stationary
       probs and initial probs but for now we truncate lengths at small or large values */
    if (length > BRLENS_MAX)
        length = BRLENS_MAX;
    else if (length < BRLENS_MIN)
        length = BRLENS_MIN;

	/* fill in values; this has to be done differently if state freqs are not equal */
	if (m->stateFreq->paramId == SYMPI_EQUAL)
		{
		/* equal state frequencies */
		/* fill in values for unordered characters */
		index = 0;
#		if defined (DEBUG_TIPROBS_STD)
		index3 = 0;
#		endif
		for (nStates=2; nStates<=10; nStates++)
			{
			if (m->isTiNeeded[nStates-2] == NO)
				continue;
			for (k=0; k<m->numGammaCats; k++)
				{
				/* calculate probabilities */
				v =  length*catRate[k]*baseRate;
				eV1 =  exp(-(nStates / (nStates -  1.0)) * v);
				pChange   = (CLFlt) ((1.0 / nStates) - ((1.0 / nStates) * eV1));
				pNoChange = (CLFlt) ((1.0 / nStates) + ((nStates - 1.0) / nStates) * eV1);
                if (pChange<0.0)
                    pChange = (CLFlt) 0.0;
				for (i=0; i<nStates; i++)
					{
					for (j=0; j<nStates; j++)
						{
						if (i == j)
							tiP[index++] = pNoChange;
						else
							tiP[index++] = pChange;
						}
					}
#   			if defined (DEBUG_TIPROBS_STD)
			    PrintTiProbs (tiP+index-(nStates*nStates), bs+index3, nStates);
#   			endif
				}
#   		if defined (DEBUG_TIPROBS_STD)
		    index3 += nStates;
#   		endif
			}

		/* fill in values for 3-state ordered character */
		if (m->isTiNeeded[9] == YES)
			{
			nStates = 3;
			for (k=0; k<m->numGammaCats; k++)
				{
				/* calculate probabilities */
				v =  length * catRate[k] * baseRate;
				eV1 =  exp (-(3.0 / 4.0) * v);
				eV2 =  exp (-(9.0 / 4.0) * v);
				
				/* pij(0,0) */
				tiP[index] = (CLFlt) ((1.0 / 3.0) + (eV1 / 2.0) + (eV2 / 6.0));
				/* pij(0,1) = pij(1,0) */
				tiP[index+1] = tiP[index+3] = (CLFlt) ((1.0 / 3.0) - (eV2 / 3.0));
				/* pij(0,2) */
				tiP[index+2] = (CLFlt) ((1.0 / 3.0) - (eV1 / 2.0) + (eV2 / 6.0));
				/* pij(1,1) */
				tiP[index+4] = (CLFlt) ((1.0 / 3.0) + (2.0 * eV2 / 3.0));
				
				/* fill in mirror part of matrix */
				index += 5;
				index2 = index - 2;
				for (i=0; i<4; i++)
					tiP[index++] = tiP[index2--];

                /* make sure no value is negative */
                for (i=index-(nStates*nStates); i<index; i++) {
                    if (tiP[i] < 0.0)
                        tiP[i] = (CLFlt) 0.0;
                }
#   			if defined (DEBUG_TIPROBS_STD)
    			PrintTiProbs (tiP+index-(nStates*nStates), bs+index3, nStates);
#   			endif
				}

#			if defined (DEBUG_TIPROBS_STD)
			index3 += nStates;
#			endif
			}

		/* 4-state ordered character */
		if (m->isTiNeeded[10] == YES)
			{
			nStates = 4;
			pi = 1.0 / 4.0;
			root =  sqrt (2.0);
			f1 = root +  1.0;
			f2 = root -  1.0;

			for (k=0; k<m->numGammaCats; k++)
				{
				/* calculate probabilities */
				v =  length * catRate[k] * baseRate;
				eV1 =  1.0 / ( exp ((4.0 * v) / 3.0));
				eV2 =  exp ((2.0 * (root - 2.0) * v) / 3.0) / root;
				eV3 =  1.0 / (root *  exp ((2.0 * (root + 2.0) * v) / 3.0));
				
				/* pij(0,0) */
				tiP[index] = (CLFlt) (pi * (1.0 + eV1 + (f1*eV2) + (f2*eV3)));
				/* pij(0,1) = pij(1,0) */
				tiP[index+1] = tiP[index+4] = (CLFlt) (pi * (1.0 - eV1 + eV2 - eV3));
				/* pij(0,2) = tiP(1,3) */
				tiP[index+2] = tiP[index+7] = (CLFlt) (pi * (1.0 - eV1 - eV2 + eV3));
				/* pij(0,3) */
				tiP[index+3] = (CLFlt) (pi * (1.0 + eV1 - (f1*eV2) - (f2*eV3)));
				/* pij(1,1) */
				tiP[index+5] = (CLFlt) (pi * (1.0 + eV1 + (f2*eV2) + (f1*eV3)));
				/* pij(1,2) */
				tiP[index+6] = (CLFlt) (pi * (1.0 + eV1 - (f2*eV2) - (f1*eV3)));

				/* fill in mirror part of matrix */
				index += 8;
				index2 = index - 1;
				for (i=0; i<8; i++)
					tiP[index++] = tiP[index2--];
        
                /* make sure no value is negative */
                for (i=index-(nStates*nStates); i<index; i++) {
                    if (tiP[i] < 0.0)
                        tiP[i] = (CLFlt) 0.0;
                }
#   			if defined (DEBUG_TIPROBS_STD)
    			PrintTiProbs (tiP+index-(nStates*nStates), bs+index3, nStates);
#   			endif
				}
#			if defined (DEBUG_TIPROBS_STD)
			index3 += nStates;
#			endif
			}

		/* 5-state ordered character */
		if (m->isTiNeeded[11] == YES)
			{
			nStates = 5;
			pi = 1.0 / 5.0;
			root =  sqrt (5.0);

			f5 = root /  4.0;
			f1 =  0.75 + f5;;
			f2 =  1.25 + f5;
			f3 =  1.25 - f5;
			f4 =  0.75 - f5;
			f5 = f5 *  2.0;
			f6 = f5 +  0.5;
			f7 = f5 -  0.5;

			for (k=0; k<m->numGammaCats; k++)
				{
				/* calculate probabilities */
				v =  length * catRate[k] * baseRate;
				v *=  5.0 /  16.0;

				eV1 =  exp ((root -  3.0) * v);
				eV2 =  exp (-(root +  3.0) * v);
				eV3 =  exp ((root -  5.0) * v);
				eV4 =  exp (-(root +  5.0) * v);

				/* pij(0,0) */
				tiP[index] = (CLFlt) (pi*( 1.0 + (f1*eV3) + (f2*eV1) + (f3*eV2) + (f4*eV4)));
				/* pij(0,1) = pij(1,0) */
				tiP[index+1] = tiP[index+5] =
					(CLFlt) (pi*(1.0 - (eV3/2.0) + (f5*eV1) - (f5*eV2) - (eV4/2.0)));
				/* pij(0,2) = pij(2,0) */
				tiP[index+2] = tiP[index+10] = (CLFlt) (pi*(1.0 - (f6*eV3) + (f7*eV4)));
				/* pij(0,3) = pij(1,4) */
				tiP[index+3] = tiP[index+9] =
					(CLFlt) (pi*(1.0 - (eV3/2.0) - (f5*eV1) + (f5*eV2) - (eV4/2.0)));
				/* pij(0,4) */
				tiP[index+4] = (CLFlt) (pi*(1.0 + (f1*eV3) - (f2*eV1) - (f3*eV2) + (f4*eV4)));
				/* pij(1,1) */
				tiP[index+6] = (CLFlt) (pi*(1.0 + (f4*eV3) + (f3*eV1) + (f2*eV2) + (f1*eV4)));
				/* pij(1,2) = pij(2,1) */
				tiP[index+7] = tiP[index+11] = (CLFlt) (pi*(1.0 + (f7*eV3) - (f6*eV4)));
				/* pij(1,3) */
				tiP[index+8] = (CLFlt) (pi*(1.0 + (f4*eV3) - (f3*eV1) - (f2*eV2) + (f1*eV4)));
				/* pij(2,2) */
				tiP[index+12] = (CLFlt) (pi*(1.0 + (2.0*eV3) + (2.0*eV4)));

				/* fill in mirror part of matrix */
				index += 13;
				index2 = index - 2;
				for (i=0; i<12; i++)
					tiP[index++] = tiP[index2--];

                /* make sure no value is negative */
                for (i=index-(nStates*nStates); i<index; i++) {
                    if (tiP[i] < 0.0)
                        tiP[i] = (CLFlt) 0.0;
                }
#	    		if defined (DEBUG_TIPROBS_STD)
    			PrintTiProbs (tiP+index-(nStates*nStates), bs+index3, nStates);
#   			endif
				}
#			if defined (DEBUG_TIPROBS_STD)
			index3 += nStates;
#			endif
			}

		/* 6-state ordered character */
		if (m->isTiNeeded[12] == YES)
			{
			nStates = 6;
			pi =  1.0 /  6.0;
			root =  sqrt (3.0);

			f4 = (3.0 / (2.0 * root));
			f1 =  1.0 + f4;
			f2 =  1.0 - f4;
			f3 =  0.5 + f4;
			f4 =  0.5 - f4;

			for (k=0; k<m->numGammaCats; k++)
				{
				/* calculate probabilities */
				v =  length * catRate[k] * baseRate;
				v /=  5.0;

				eV1 =  exp ( -9 * v);
				eV2 =  exp ( -6 * v);
				eV3 =  exp ( -3 * v);
				eV4 =  exp ( 3.0 * (root -  2.0) * v);
				eV5 =  exp (-( 3.0 * (root +  2.0) * v));

				/* pij(0,0) */
				tiP[index] = (CLFlt) (pi*( 1.0 + (0.5*eV1) + eV2 + (1.5*eV3) + (f1*eV4) + (f2*eV5)));
				/* pij(0,1) = pij(1,0) */
				tiP[index+1] = tiP[index+6] = (CLFlt) (pi*(1.0 - eV1 - eV2 + (f3*eV4) + (f4*eV5)));
				/* pij(0,2) = pij(2,0) */
				tiP[index+2] = tiP[index+12] = 
					(CLFlt) (pi*(1.0 + (0.5*eV1) - eV2 - (1.5*eV3) + (0.5*eV4) + (0.5*eV5)));
				/* pij(0,3) = pij(2,5) */
				tiP[index+3] = tiP[index+17] = 
					(CLFlt) (pi*(1.0 + (0.5*eV1) + eV2 - (1.5*eV3) - (0.5*eV4) - (0.5*eV5)));
				/* pij(0,4) = pij(1,5) */
				tiP[index+4] = tiP[index+11] = (CLFlt) (pi*(1.0 - eV1 + eV2 - (f3*eV4) - (f4*eV5)));
				/* pij(0,5) */
				tiP[index+5] = (CLFlt) (pi*(1.0 + (0.5*eV1) - eV2 + (1.5*eV3) - (f1*eV4) - (f2*eV5)));
				/* pij(1,1) */
				tiP[index+7] = (CLFlt) (pi*(1.0 + (2.0*eV1) + eV2 + eV4 + eV5));
				/* pij(1,2) = pij(2,1) */
				tiP[index+8] = tiP[index+13] = (CLFlt) (pi*(1.0 - eV1 + eV2 - (f4*eV4) - (f3*eV5)));
				/* pij(1,3) = pij(2,4) */
				tiP[index+9] = tiP[index+16] = (CLFlt) (pi*(1.0 - eV1 - eV2 + (f4*eV4) + (f3*eV5)));
				/* pij(1,4) */
				tiP[index+10] = (CLFlt) (pi*(1.0 + (2.0*eV1) - eV2 - eV4 - eV5));
				/* pij(2,2) */
				tiP[index+14] = (CLFlt) (pi*(1.0 + (0.5*eV1) + eV2 + (1.5*eV3) + (f2*eV4) + (f1*eV5)));
				/* pij(2,3) */
				tiP[index+15] = (CLFlt) (pi*(1.0 + (0.5*eV1) - eV2 + (1.5*eV3) - (f2*eV4) - (f1*eV5)));

				/* fill in mirror part of matrix */
				index += 18;
				index2 = index - 1;
				for (i=0; i<18; i++)
					tiP[index++] = tiP[index2--];

                /* make sure no value is negative */
                for (i=index-(nStates*nStates); i<index; i++) {
                    if (tiP[i] < 0.0)
                        tiP[i] = (CLFlt) 0.0;
                }
#   			if defined (DEBUG_TIPROBS_STD)
    			PrintTiProbs (tiP+index-(nStates*nStates), bs+index3, nStates);
#   			endif
				}
#			if defined (DEBUG_TIPROBS_STD)
			index3 += nStates;
#			endif
			}
		}
	else
		{
		/* unequal state frequencies */
        index = 0;

		/* first fill in for binary characters using beta categories if needed */
		if (m->isTiNeeded[0] == YES)
			{
			/* find base frequencies */
            bs = GetParamStdStateFreqs (m->stateFreq, chain, state[chain]);

			/* cycle through beta and gamma cats */
			for (b=0; b<m->numBetaCats; b++)
				{
				mu =  1.0 / (2.0 * bs[0] * bs[1]);
				for (k=0; k<m->numGammaCats; k++)
					{
					/* calculate probabilities */
					v =  length*catRate[k]*baseRate;
					eV1 =  exp(- mu * v);
					tiP[index++] = (CLFlt) (bs[0] + (bs[1] * eV1));
					tiP[index++] = (CLFlt) (bs[1] - (bs[1] * eV1));
					tiP[index++] = (CLFlt) (bs[0] - (bs[0] * eV1));
					tiP[index++] = (CLFlt) (bs[1] + (bs[0] * eV1));
					}
				/* update stationary state frequency pointer */
				bs += 2;
				}
			}

		/* now use general algorithm for the other cases */
	    if (m->cijkLength > 0)
			{
            
			/* first update cijk if necessary */
			//if (m->cijkLength > 0 && m->upDateCijk == YES)
				//{
                /* TODO: (IMPORTANT) This UpDateCijk is probably a bug */
				//if (UpDateCijk (division, chain) == ERROR)
				//	return (ERROR);
				//}

			/* then get first set of eigenvalues */
			eigenValues = m->cijks[m->cijkIndex[chain]];

			/* and cycle through the relevant characters */
			for (c=0; c<m->stateFreq->nSympi; c++)
				{
				n = m->stateFreq->sympinStates[c];

				/* fill in values */
				for (k=0; k<m->numGammaCats; k++)
					{
					v =  length * baseRate * catRate[k];
					
			        cijk = eigenValues + (2 * n);

					for (s=0; s<n; s++)
						EigValexp[s] =  exp(eigenValues[s] * v);

					for (i=0; i<n; i++)
						{
						for (j=0; j<n; j++)
							{
							sum = 0.0;
							for(s=0; s<n; s++)
								sum += (*cijk++) * EigValexp[s];
							tiP[index++] = (CLFlt) ((sum <  0.0) ?  0.0 : sum);
							}
						}
					}

				/* update eigenValues pointer */
				eigenValues += (n * n * n) + (2 * n);

				}
			}
		}

	return NO_ERROR;

}





void TouchAllCijks (int chain)

{

	int i;

	for (i=0; i<numCurrentDivisions; i++)
		{
		if (modelSettings[i].nCijkParts >= 1)
			modelSettings[i].upDateCijk = YES;
		}

	return;
	
}





void TouchAllPartitions (void)

{

	int i;

	for (i=0; i<numCurrentDivisions; i++)
		{
		modelSettings[i].upDateCl = YES;
		}

	return;
	
}





void TouchAllTreeNodes (ModelInfo *m, int chain)

{

	int			i;
    Tree        *t;
	TreeNode	*p;

    t = GetTree(m->brlens, chain, state[chain]);
	for (i=0; i<t->nNodes; i++)
		{
		p = t->allDownPass[i];
		p->upDateCl = YES;
		p->upDateTi = YES;
		}
    m->upDateAll = YES;
}





void TouchAllTrees (int chain)

{

	int			i, j;
	Tree		*t;
	TreeNode	*p;

	for (i=0; i<numTrees; i++)
		{
		t = GetTreeFromIndex (i, chain, state[chain]);
		for (j=0; j<t->nNodes; j++)
			{
			p = t->allDownPass[j];
			p->upDateCl = YES;
			p->upDateTi = YES;
			}
		}

    for (i=0; i<numCurrentDivisions; i++)
        modelSettings[i].upDateAll = YES;

	return;
	
}





/*------------------------------------------------------------------
|
|	TreeLength: Calculates the tree length as the sum of the lengths
|		of all the branches. The tree length is the expected number 
|       of character state transformations per character over the 
|       entire phylogenetic tree.
|
-------------------------------------------------------------------*/
MrBFlt TreeLength (Param *param, int chain)

{

	int				i, j;
	MrBFlt			tl;
	Tree			*t;
	TreeNode		*p;

	if (param->paramId == BRLENS_PARSIMONY)
		{
		tl = 0.0;
		for (j=0; j<param->nRelParts; j++)
			tl += modelSettings[param->relParts[j]].parsTreeLength[2*chain+state[chain]];
		}
	else
		{
		/* get tree */
		t = GetTree (param, chain, state[chain]);
		
		/* loop over all branches of the tree */
		tl = 0.0;
		for (i=0; i<t->nNodes; i++)
			{
			p = t->allDownPass[i];
			if (p->anc != NULL)
				{
				if (p->anc->anc == NULL)
					{
					if (t->isRooted == NO)
						tl += p->length;
					}
				else
					{
					tl += p->length;
					}
				}
			}
		}
				
	return (tl);
	
}



int UpDateCijk (int whichPart, int whichChain)

{

	int			c, i, j, k, n, n3, isComplex, sizeOfSingleCijk, cType, numQAllocated;
	MrBFlt		**q[100], **eigvecs, **inverseEigvecs;
	MrBFlt		*eigenValues, *eigvalsImag, *cijk;
	MrBFlt		*bs, *bsBase, *rateOmegaValues=NULL, rA=0.0, rS=0.0, posScaler, *omegaCatFreq=NULL;
	complex		**Ceigvecs, **CinverseEigvecs;
	ModelInfo	*m;
	Param		*p;
#if defined (BEAGLE_ENABLED)
	int			u;
	double      *beagleEigvecs=NULL, *beagleInverseEigvecs=NULL;
#endif

	/* get a pointer to the model settings for this partition */
	m = &modelSettings[whichPart];
    assert (m->upDateCijk == YES);
	
	/* we should only go through here if we have cijk information available for the partition */
	if (m->cijkLength > 0) 
		{
		/* flip cijk space */
		FlipCijkSpace(m, whichChain);
		
		/* figure out information on either omega values or rate values, if necessary */
		if (m->dataType == DNA || m->dataType == RNA)
			{
			if (m->nucModelId == NUCMODEL_CODON)                                                    /* we have a NY98 model     */
				{
				rateOmegaValues = GetParamVals(m->omega, whichChain, state[whichChain]);
				if (m->numOmegaCats > 1)
					omegaCatFreq = GetParamSubVals (m->omega, whichChain, state[whichChain]);
				}
			else if (m->nCijkParts > 1 && m->nucModelId == NUCMODEL_4BY4 && m->numModelStates == 8) /* we have a covarion model */
				rateOmegaValues = GetParamSubVals (m->shape, whichChain, state[whichChain]);        /* with rate variation      */
			}
		else if (m->dataType == PROTEIN)
			{
			if (m->nCijkParts > 1)                                                                  /* we have a covarion model */
				rateOmegaValues = GetParamSubVals (m->shape, whichChain, state[whichChain]);        /* with rate variation      */
			}
#if defined (BEAGLE_ENABLED)
		else if (m->dataType == RESTRICTION){}
#endif
		else if (m->dataType != STANDARD)
			{
			MrBayesPrint ("%s   ERROR: Should not be updating cijks!\n", spacer);
			return (ERROR);
			}
		
		if (m->dataType == STANDARD)
			{
			/* set pointers and other stuff needed */
			numQAllocated = 1;
			p = m->stateFreq;
			eigenValues = m->cijks[m->cijkIndex[whichChain]];
			q[0] = AllocateSquareDoubleMatrix (10);
			eigvecs = AllocateSquareDoubleMatrix (10);
			inverseEigvecs = AllocateSquareDoubleMatrix (10);
			Ceigvecs = AllocateSquareComplexMatrix (10);
			CinverseEigvecs = AllocateSquareComplexMatrix (10);
			bsBase = GetParamStdStateFreqs (m->stateFreq, whichChain, state[whichChain]);
			
			/* cycle over characters needing cijks */
			for (c=0; c<p->nSympi; c++)
				{
				n = p->sympinStates[c];
				bs = bsBase + p->sympiBsIndex[c];
				cType = p->sympiCType[c];
				n3 = n * n * n;
				eigvalsImag = eigenValues + n;
				cijk = eigenValues + (2 * n);
				if (SetStdQMatrix (q[0], n, bs, cType) == ERROR)
					return (ERROR);
				isComplex = GetEigens (n, q[0], eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
				if (isComplex == NO)
					{
					CalcCijk (n, cijk, eigvecs, inverseEigvecs);
					}
				else
					{
                    if( isComplex == YES )
					    MrBayesPrint ("%s   ERROR: Complex eigenvalues found!\n", spacer);
                    else
                        MrBayesPrint ("%s   ERROR: Computing eigenvalues problem!\n", spacer);
					goto errorExit;
					}
				eigenValues += (n3 + (2 * n));
				}
			}
		else
			{
			/* all other data types */
			numQAllocated = m->nCijkParts;
			sizeOfSingleCijk = m->cijkLength / m->nCijkParts;
			n = m->numModelStates;
			n3 = n * n * n;
#if defined (BEAGLE_ENABLED)
            if (m->useBeagle == YES)
                eigenValues = m->cijks[m->cijkIndex[whichChain]/m->nCijkParts];
            else
    			eigenValues = m->cijks[m->cijkIndex[whichChain]];
#else
			eigenValues = m->cijks[m->cijkIndex[whichChain]];
#endif
			eigvalsImag = eigenValues + n;
			cijk        = eigenValues + (2 * n);
			for (k=0; k<numQAllocated; k++)
				q[k] = AllocateSquareDoubleMatrix (n);
			eigvecs = AllocateSquareDoubleMatrix (n);
			inverseEigvecs = AllocateSquareDoubleMatrix (n);
			Ceigvecs = AllocateSquareComplexMatrix (n);
			CinverseEigvecs = AllocateSquareComplexMatrix (n);
			bs = GetParamSubVals (m->stateFreq, whichChain, state[whichChain]);
			
			if (m->nCijkParts == 1)
				{
				if (m->dataType == DNA || m->dataType == RNA)
					{
					if (m->nucModelId == NUCMODEL_CODON)
						{
						if (SetNucQMatrix (q[0], n, whichChain, whichPart, rateOmegaValues[0], &rA, &rS) == ERROR)
							goto errorExit;
						}
					else
						{
						if (SetNucQMatrix (q[0], n, whichChain, whichPart, 1.0, &rA, &rS) == ERROR)
							goto errorExit;
						}
					}
#if defined (BEAGLE_ENABLED)
				else if(m->dataType == RESTRICTION)
					{
					SetBinaryQMatrix (q[0], whichChain, whichPart);
					}
#endif
				else
					{
					if (SetProteinQMatrix (q[0], n, whichChain, whichPart, 1.0) == ERROR)
						goto errorExit;
					}
				isComplex = GetEigens (n, q[0], eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
#if defined (BEAGLE_ENABLED)
				if (isComplex == YES)
					{
                    if( isComplex == YES )
					    MrBayesPrint ("%s   ERROR: Complex eigenvalues found!\n", spacer);
                    else
                        MrBayesPrint ("%s   ERROR: Computing eigenvalues problem!\n", spacer);
					goto errorExit;
					}
                if (m->useBeagle == YES)
                    {
                    /* TODO: only allocate this space once at initialization */
                    beagleEigvecs = (double*) SafeCalloc (2*n*n, sizeof(double));
                    beagleInverseEigvecs = beagleEigvecs + n*n;
                    for (i=k=0; i<n; i++)
                        {
							//eigenValues[i] =0.1;
                        for (j=0; j<n; j++)
                            {
                            beagleEigvecs[k] = eigvecs[i][j];
                            beagleInverseEigvecs[k] = inverseEigvecs[i][j];
                            k++;
                            }
                        }
                    beagleSetEigenDecomposition(m->beagleInstance,
                                                m->cijkIndex[whichChain],
                                                beagleEigvecs,
                                                beagleInverseEigvecs,
                                                eigenValues);
                    free(beagleEigvecs);
                    }
				else
					{
					CalcCijk (n, cijk, eigvecs, inverseEigvecs);
					}
#else
				if (isComplex == NO)
					{
					CalcCijk (n, cijk, eigvecs, inverseEigvecs);
					}
				else
					{
					MrBayesPrint ("%s   ERROR: Complex eigenvalues found!\n", spacer);
					goto errorExit;
					}
#endif
				}
			else
				{
				/* Here, we calculate the rate matrices (Q) for various nucleotide and amino acid
				   data models. Usually, when the rate matrix is set in SetNucQMatrix, it is scaled
				   such that the average substitution rate is one. However, there is a complication
				   for positive selection models using codon rate matrices. First, we have more than
				   one matrix; in fact, we have as many rate matrices as there are omega values. Second,
				   the mean substitution rate still has to be one. And third, we want the synonymous
				   rate to be the same across the rate matrices. For positive selection models, the Q
				   matrix comes out of SetNucQMatrix unscaled. Once we have all m->nCijkParts rate 
				   matrices, we then scale again, this time to ensure that the mean substitution rate is one. */

				/* First, calculate rate matrices for each category: */
				posScaler = 0.0;
				for (k=0; k<m->nCijkParts; k++)
					{
					if (m->dataType == DNA || m->dataType == RNA)
						{
						if (SetNucQMatrix (q[k], n, whichChain, whichPart, rateOmegaValues[k], &rA, &rS) == ERROR)
							goto errorExit;
						}
					else
						{
						if (SetProteinQMatrix (q[k], n, whichChain, whichPart, rateOmegaValues[k]) == ERROR)
							goto errorExit;
						}
					if (m->nucModelId == NUCMODEL_CODON && m->numOmegaCats > 1)
						posScaler += omegaCatFreq[k] * (rS + rA);
					}
					
				/* Then rescale the rate matrices, if this is a positive selection model: */
				if (m->nucModelId == NUCMODEL_CODON && m->numOmegaCats > 1)
					{
					posScaler = 1.0 / posScaler;
					for (k=0; k<m->nCijkParts; k++)
						{
						for (i=0; i<n; i++)
							for (j=0; j<n; j++)
								q[k][i][j] *= posScaler;
						}
					}

				/* Finally, calculate eigenvalues, etc.: */
#if defined (BEAGLE_ENABLED)
                if (m->useBeagle == YES)
                    {
                    /* TODO: only allocate this space once at initialization */
                    beagleEigvecs = (double*) SafeCalloc (2*n*n, sizeof(double));
                    beagleInverseEigvecs = beagleEigvecs + n*n;
                    }
#endif
				for (k=0; k<m->nCijkParts; k++)
					{
					isComplex = GetEigens (n, q[k], eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
#if defined (BEAGLE_ENABLED)
					if (isComplex == YES)
						{
                        if( isComplex == YES )
					        MrBayesPrint ("%s   ERROR: Complex eigenvalues found!\n", spacer);
                        else
                            MrBayesPrint ("%s   ERROR: Computing eigenvalues problem!\n", spacer);
						goto errorExit;
						}
                    if (m->useBeagle == YES)
                        {
                        for (i=u=0; i<n; i++)
                            {
                            for (j=0; j<n; j++)
                                {
                                beagleEigvecs[u] = eigvecs[i][j];
                                beagleInverseEigvecs[u] = inverseEigvecs[i][j];
								u++;
                                }
                            }

                        beagleSetEigenDecomposition(m->beagleInstance,
                                                    m->cijkIndex[whichChain] + k,
                                                    beagleEigvecs,
                                                    beagleInverseEigvecs,
                                                    eigenValues);
                        }
                    else
						{
						CalcCijk (n, cijk, eigvecs, inverseEigvecs);
						}
#else
					if (isComplex == NO)
						{
						CalcCijk (n, cijk, eigvecs, inverseEigvecs);
						}
					else
						{
						MrBayesPrint ("%s   ERROR: Complex eigenvalues found!\n", spacer);
						goto errorExit;
						}
#endif
					/* shift pointers */
					eigenValues += sizeOfSingleCijk;
					eigvalsImag += sizeOfSingleCijk;
					cijk        += sizeOfSingleCijk;
					}
#if defined (BEAGLE_ENABLED)
                free(beagleEigvecs);
#endif
				}
			}
			
		for (k=0; k<numQAllocated; k++)
			FreeSquareDoubleMatrix (q[k]);
		FreeSquareDoubleMatrix (eigvecs);
		FreeSquareDoubleMatrix (inverseEigvecs);
		FreeSquareComplexMatrix (Ceigvecs);
		FreeSquareComplexMatrix (CinverseEigvecs);
		}
		
	return (NO_ERROR);

	errorExit:		
		for (k=0; k<numQAllocated; k++)
			FreeSquareDoubleMatrix (q[k]);
		FreeSquareDoubleMatrix (eigvecs);
		FreeSquareDoubleMatrix (inverseEigvecs);
		FreeSquareComplexMatrix (Ceigvecs);
		FreeSquareComplexMatrix (CinverseEigvecs);

		return ERROR;

}

