function BuildCodonFrequencies (obsF)
{
	if (!ModelMatrixDimension)
	{
		ModelMatrixDimension = 64;
		for (h = 0 ;h<64; h=h+1)
		{
			if (_Genetic_Code[h]==10)
			{
				ModelMatrixDimension = ModelMatrixDimension-1;
			}
		}
	}

	PIStop = 1.0;
	result = {ModelMatrixDimension,1};
	hshift = 0;

	for (h=0; h<64; h=h+1)
	{
		first = h$16;
		second = h%16$4;
		third = h%4;
		if (_Genetic_Code[h]==10) 
		{
			hshift = hshift+1;
			PIStop = PIStop-obsF[first][0]*obsF[second][1]*obsF[third][2];
			continue; 
		}
		result[h-hshift][0]=obsF[first][0]*obsF[second][1]*obsF[third][2];
	}
	return result*(1.0/PIStop);
}

/*------------------------------------------------------------------------*/

function ReportSite2 (siteI, siteM)
{
	fullSites[siteI][0] = doneSites[siteM][0];
	fullSites[siteI][1] = doneSites[siteM][1];
	fullSites[siteI][2] = doneSites[siteM][6];
	fullSites[siteI][3] = doneSites[siteM][2];
	fullSites[siteI][4] = doneSites[siteM][3];
	fullSites[siteI][5] = doneSites[siteM][4];
	fullSites[siteI][6] = doneSites[siteM][5];
	if (Columns (fullSites) > 7)
	{
		fullSites[siteI][7] = doneSites[siteM][7];	
	}


	fprintf (stdout, "Site ", Format(siteI+1,4,0)," dN/dS = ", Format(fullSites[siteI][2],7,4),
					 " dN = ", Format(fullSites[siteI][0],7,4),
					 " dS = ", Format(fullSites[siteI][1],7,4),
					 " dS(=dN) ",Format(fullSites[siteI][3],7,4),
					 " Full Log(L) = ",Format(fullSites[siteI][6],7,4),
					 " LRT= ",Format(fullSites[siteI][4],7,4),
					 " p-value = ",Format(fullSites[siteI][5],8,5));		
					 
	if (fullSites[siteI][5]<pValue)
	{
		if (fullSites[siteI][0]>fullSites[siteI][1])
		{
			fprintf (stdout, " *P");
		}
		else
		{
			fprintf (stdout, " *N");
		}
	}
	fprintf (stdout, "\n");
	return 0;
}

/*------------------------------------------------------------------------*/

function ReceiveJobs2 (sendOrNot, nullAlt,_siteCount,_siteMap)
{
	MPIReceive (-1, fromNode, result_String);
	
	siteIndex 		= MPINodeState[fromNode-1][1];
	siteNA	  		= MPINodeState[fromNode-1][2];
	siteIndexMap	= MPINodeState[fromNode-1][3];
	
	if (sendOrNot)
	{
		MPISend (fromNode,siteLikelihood);
		MPINodeState[fromNode-1][1] = _siteCount;			
		MPINodeState[fromNode-1][2] = nullAlt;			
		MPINodeState[fromNode-1][3] = _siteMap;			
		MPINodeState[fromNode-1][4] = MPINodeState[fromNode-1][4]+1;			
	}
	else
	{
		MPINodeState[fromNode-1][0] = 0;
		MPINodeState[fromNode-1][1] = -1;		
	}
	
	ExecuteCommands (result_String);
	
	nFValue = siteLikelihood_MLE_VALUES ["nFactor"];
	sFValue = siteLikelihood_MLE_VALUES ["sFactor"];
	if (Columns (doneSites) > 7)
	{
		noFValue = siteLikelihood_MLE_VALUES ["nFactorOther"];
	}
	
	if (siteNA)
	{
		doneSites[siteIndexMap][0] = nFValue;
		doneSites[siteIndexMap][1] = sFValue;
		if (Columns (doneSites) > 7)
		{
			doneSites[siteIndexMap][7] = noFValue;
		}
			
		doneSites[siteIndexMap][6] = nFValue/sFValue;
		doneSites[siteIndexMap][3] = doneSites[siteIndexMap][3]+2*siteLikelihood_MLES[1][0];
		doneSites[siteIndexMap][5] = siteLikelihood_MLES[1][0];
	}
	else
	{
		doneSites[siteIndexMap][3] = doneSites[siteIndexMap][3]-2*siteLikelihood_MLES[1][0];	
		doneSites[siteIndexMap][2] = sFValue;
	}

	if (doneSites[siteIndexMap][4] == 0)
	{
		doneSites[siteIndexMap][4] = -1;
	}
	else
	{
		if (doneSites[siteIndexMap][4] == (-1))
		{
			doneSites[siteIndexMap][4] = 1-CChi2(doneSites[siteIndexMap][3],1);						
			dummy = ReportSite2 (siteIndex, siteIndexMap);
		}
	}
	
	return fromNode-1;
}

/*------------------------------------------------------------------------*/

_DO_TREE_REBALANCE_ = 1;


#include   "TemplateModels/chooseGeneticCode.def";
ChoiceList (nrChoice, "New/Restore",1,SKIP_NONE,
			"New Analysis","Perform a new analysis.",
			"Restore", "Restore an earlier nucleotide fit");
			
if (nrChoice < 0)
{
	return;
}

if (nrChoice == 0)
{
	global AC 	= 1;
	global AT 	= 1;
	global CG 	= 1;
	global CT 	= 1;
	global GT 	= 1;
	global dNdS = 1;		

	NucleotideMatrix	 = {{*,AC*t,t,AT*t}{AC*t,*,CG*t,CT*t}{t,CG*t,*,GT*t}{AT*t,CT*t,GT*t,*}};

	ChoiceList (modelChoice, "Model Options",1,SKIP_NONE,
				"Default","Use HKY85 and MG94xHKY85.",
				"Custom", "Use any reversible nucleotide model crossed with MG94.");
				
	if (modelChoice < 0)
	{
		return;
	}

	modelDesc = "";

	if (modelChoice)
	{
		done = 0;
		while (!done)
		{
			fprintf (stdout,"\nPlease enter a 6 character model designation (e.g:010010 defines HKY85):");
			fscanf  (stdin,"String", modelDesc);
			if (Abs(modelDesc)==6)
			{	
				done = 1;
			}
		}			
	}
	else
	{
		modelDesc = "010010";
	}


	ModelTitle = ""+modelDesc[0];
				
	rateBiasTerms = {{"AC","1","AT","CG","CT","GT"}};
	paramCount	  = 0;

	modelConstraintString = "";

	for (customLoopCounter2=1; customLoopCounter2<6; customLoopCounter2=customLoopCounter2+1)
	{
		for (customLoopCounter=0; customLoopCounter<customLoopCounter2; customLoopCounter=customLoopCounter+1)
		{
			if (modelDesc[customLoopCounter2]==modelDesc[customLoopCounter])
			{
				ModelTitle  = ModelTitle+modelDesc[customLoopCounter2];	
				if (rateBiasTerms[customLoopCounter2] == "1")
				{
					modelConstraintString = modelConstraintString + rateBiasTerms[customLoopCounter]+":="+rateBiasTerms[customLoopCounter2]+";";
				}
				else
				{
					modelConstraintString = modelConstraintString + rateBiasTerms[customLoopCounter2]+":="+rateBiasTerms[customLoopCounter]+";";			
				}
				break;
			}
		}
		if (customLoopCounter==customLoopCounter2)
		{
			ModelTitle = ModelTitle+modelDesc[customLoopCounter2];	
		}
	}	

	if (Abs(modelConstraintString))
	{
		ExecuteCommands (modelConstraintString);
	}
	#include "_MFReader_.ibf";

	codonFrequencies 	= BuildCodonFrequencies(positionFrequencies);
	Model NucModel 		= (NucleotideMatrix, overallFrequencies, 1);

	SetDialogPrompt ("Save nucleotide model fit to:");
	fprintf (PROMPT_FOR_FILE, CLEAR_FILE);
	NUC_FILE_PATH = LAST_FILE_PATH;
}
else
{
	SetDialogPrompt ("Restore nucleotide fit from:");
	ExecuteAFile	(PROMPT_FOR_FILE);

	GetString 		(nucLFInfo, nucLF, -1);
	fileCount = 	Columns(nucLFInfo["Trees"]);
	fprintf (stdout, "\nLoaded a fit on ", fileCount, " data sets\n");

	totalCodonCount = 0;
	totalUniqueSites = 0;
	treeStrings		= {};
	for (fileID = 1; fileID <= fileCount; fileID = fileID + 1)
	{
		ExecuteCommands 	  ("DataSetFilter filteredData_" + fileID + " = CreateFilter (ds_"+fileID +",3,\"\",\"\",GeneticCodeExclusions);");
		ExecuteCommands 	  ("totalCodonCount=totalCodonCount+filteredData_" + fileID + ".sites;treeStrings[fileID] = Format(nucTree_" +fileID+ ",1,1);totalUniqueSites=totalUniqueSites+filteredData_"+fileID+".unique_sites;" );
	}

	positionFrequencies       = {4,3};
	overallFrequencies 		  = {4,1};
	for (fileID = 1; fileID <= fileCount; fileID = fileID + 1)
	{
		ExecuteCommands 	  ("HarvestFrequencies (tp, filteredData_"+fileID+",3,1,1);HarvestFrequencies (ts, filteredData_"+fileID+",1,1,1);cfs = filteredData_"+fileID+".sites;");
		positionFrequencies 		= positionFrequencies 		 + tp*(cfs/totalCodonCount);
		overallFrequencies  		= overallFrequencies + ts*(cfs/totalCodonCount);
	}

	codonFrequencies = BuildCodonFrequencies(positionFrequencies); 
	
	pMatch = {6,1};
	pCheck = {{AC__,AT__,CG__,CT__,GT__}};
	if (pCheck[0] == 1)
	{
		ModelTitle = "00";
		pCount = 1;
		pMatch[0] = 1;
	}
	else
	{
		pCount = 2;
		ModelTitle = "01";
		pMatch[0] = pCheck[0];
		pMatch[1] = 1;	
	}
	
	for (l=1; l<5; l=l+1)
	{	
		for (k=0; k<pCount; k=k+1)
		{
			if (pCheck[l] == pMatch[k])
			{
				break;
			}
		}
		
		if (k<pCount)
		{
			ModelTitle = ModelTitle + k;
		}
		else
		{
			pMatch[pCount] = pCheck[l];
			ModelTitle = ModelTitle + pCount;
			pCount = pCount+1;			
		}
	}
}

