/* This file defines the transition matrix for the General Reversible model
   The file should be used as follows:
   
   1) Read Data File and create datafilter filteredData
   2) #include this file (or use SelectTemplateModel(filteredData);)
   3) Define the tree
   4) Proceed with the likelihood function using 'vectorOfFrequencies' as the vector to pass to the constructor.
   
   This model has the following signature:
    #Short:RNA16
   	#Desc:Model allowing for secondary structure constraints in the RNA evolution.#
   	#Dimension:16#
    #DataType:di-nucleotide#
   	#FileName:RNA16.mdl#
   
   05/19/2005  by Sergei L. Kosakovsky Pond
*/


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

modelType = 0;

#include "modelParameters2.mdl";

/* ADD NEW RATE CLASS MATRICES HERE */

DiNucClasses = {{"RNAEqualInput","A 16x16 matrix with a single substitution rate. Not expected to fit the data well, and should only be used as a 'bad' model to compare other models to."}
				{"RNAF81","A 16x16 matrix with a single substitution rate for single nucleotide substitutions and a zero rate for double substitutions. Not expected to fit the data well, and should only be used as a 'bad' model to compare other models to."}
				{"RNA16A","5 rate parameters. Defined in Savill, Hoyle and Higgs. Genetics 157: 399-411."}
				{"RNAREV_1","A subset of the general reversible model with 47 rate parameters, which disallows double instantaneous substitutions."}
				{"RNAREV","A general reversible model with 119 rate parameters."}
				{"Custom Esimated","Load a custom rate matrix from file. Rates estimated from the data."}
				{"Custom Fixed","Load a custom rate matrix from file. Rates are fixed at the values read from the numeric matrix."}};
					
				    
/* END ADD NEW RATE CLASS MATRICES HERE */			    

ChoiceList	(dinucModelType,"Dinucleotide Rate Class Model",1,SKIP_NONE,DiNucClasses);

if (dinucModelType < 0)
{
	return 0;
}

if (dinucModelType >= Rows(DiNucClasses)-2)
{
	SetDialogPrompt ("Locate an di-nucleotide rate profile matrix file:");
	fscanf (PROMPT_FOR_FILE,"Matrix",diNucRateMatrix);
	W_MATRIX_FILE = LAST_FILE_PATH;
}
else
{
	W_MATRIX_FILE = HYPHY_LIB_DIRECTORY+"TemplateBatchFiles"+DIRECTORY_SEPARATOR+"TemplateModels"+DIRECTORY_SEPARATOR+SELECTION_STRINGS;
	fscanf (W_MATRIX_FILE,"Matrix",diNucRateMatrix);
}

if (Rows (diNucRateMatrix) != 16 || Columns (diNucRateMatrix) != 16)
{
	fprintf (stdout, "ERROR: A 16x16 matrix was expected, but not found in rate definition file\n");
	return 0;
}

if (modelType == 1)
{
	#include "defineGamma.mdl";
}
if (modelType == 2)
{
	#include "defineHM.mdl";
}


ChoiceList  (freqResp,"Equilibrium Frequencies",1,NO_SKIP,
			 "Dinucleotide counts","State frequencies are collected from observed dinucleotide counts.",
			 "Nucleotide counts","State frequencies are estimates from products of respective nucleotide counts.",
			 "Estimated","Frequencies are estimated by ML.");
			 
if (freqResp<0) 
{
	return 1;
}
else
{
	 if (freqResp == 0)
	 {
		HarvestFrequencies (vectorOfFrequencies, filteredData,2,2,0);
		FREQUENCY_SENSITIVE = 1;
	 }
	 else
	 {
		vectorOfFrequencies = {16,1};
	 	if (freqResp == 1)
	 	{
			HarvestFrequencies (obsFreqs,filteredData,2,1,1);
			for (h=0; h<4; h=h+1)
			{
				for (v=0; v<4; v=v+1)
				{
					vectorOfFrequencies[h*4+v] = obsFreqs[h][0]*obsFreqs[v][1];
				}
			}
			FREQUENCY_SENSITIVE = 1;
	 	}
	 	else
	 	{
			HarvestFrequencies (obsFreqs,filteredData,2,2,1);
			v = "";
			global f_weight = 1;

			nucChar = "ACGT";

			for (h=0;h<4;h=h+1)
			{
				for (h2=0;h2<4;h2=h2+1)
				{
					varName = "f_"+nucChar[h]+nucChar[h2];
					idx = h*4+h2;
					
					ExecuteCommands ("global "+varName+"=obsFreqs[idx];"+varName+":<1;vectorOfFrequencies["+idx+"]:="+varName+"/f_weight;");
					v = v + "+" + varName;
				}
			}
			ExecuteCommands ("f_weight:="+v[1][Abs(v)-1]+";");	 		
	 	}
	 }
}

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

function PopulateModelMatrix (ModelMatrixName&, EFV)
{
	ModelMatrixName = {16,16};
	global rate_Normalizer = 1;
	
	if (dinucModelType == Rows(DiNucClasses)-1)
	{
		rate_Norm = 0;
		for (h=0; h<16; h=h+1)
		{
			for (v=h+1; v<16; v=v+1)
			{
				if (v!=h)
				{
					if (Abs("" + diNucRateMatrix[h][v]))
					{
						rateEntry = ""+diNucRateMatrix[h][v];
						rate_Norm = rate_Norm + rateEntry;
						
						if (modelType>=1)
						{
							rateEntry = rateEntry + "*c";
						}
						
						ExecuteCommands ("ModelMatrixName["+h+"]["+v+"]:="+rateEntry  +"*rate_Normalizer*t");
						ExecuteCommands ("ModelMatrixName["+v+"]["+h+"]:="+rateEntry  +"*rate_Normalizer*t");
					}
				}
			}
		}
		ExecuteCommands ("rate_Normalizer:=100./rate_Norm__;");
	}
	else
	{
		rate_Norm = "";
		alreadyDefined = {};
		for (h=0; h<16; h=h+1)
		{
			for (v=h+1; v<16; v=v+1)
			{
				if (v!=h)
				{
					if (Abs("" + diNucRateMatrix[h][v]))
					{
						rateEntry = "R_"+diNucRateMatrix[h][v];
						if (alreadyDefined[rateEntry] == 0)
						{
							ExecuteCommands ("global "+rateEntry + "=1;");
							rate_Norm = rate_Norm + "+" + rateEntry;
							alreadyDefined[rateEntry] = 1;
						}
						
						if (modelType>=1)
						{
							rateEntry = rateEntry + "*c";
						}
						
						ExecuteCommands ("ModelMatrixName["+h+"]["+v+"]:="+rateEntry  +"*rate_Normalizer*t");
						ExecuteCommands ("ModelMatrixName["+v+"]["+h+"]:="+rateEntry  +"*rate_Normalizer*t");
					}
				}
			}
		}
		ExecuteCommands ("rate_Normalizer:=100./("+rate_Norm[1][Abs(rate_Norm)-1]+");");
	}
	
	return 1;
}

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

MULTIPLY_BY_FREQS = PopulateModelMatrix ("RNA16",observedFreq);
Model RNA16Model = (RNA16, vectorOfFrequencies, MULTIPLY_BY_FREQS);
