package beast.evolution.substitutionmodel;
import java.lang.reflect.InvocationTargetException;
import beast.core.Description;
import beast.core.Input;
import beast.core.Input.Validate;
import beast.core.parameter.RealParameter;
import beast.evolution.datatype.DataType;
import beast.evolution.datatype.Nucleotide;
@Description("Symmetrical model of nucleotide evolution with equal base frequencies." +
"Rates that are not specified are assumed to be 1.")
public class SYM extends GeneralSubstitutionModel {
final public Input<RealParameter> rateACInput = new Input<>("rateAC", "substitution rate for A to C (default 1)");
final public Input<RealParameter> rateAGInput = new Input<>("rateAG", "substitution rate for A to G (default 1)");
final public Input<RealParameter> rateATInput = new Input<>("rateAT", "substitution rate for A to T (default 1)");
final public Input<RealParameter> rateCGInput = new Input<>("rateCG", "substitution rate for C to G (default 1)");
final public Input<RealParameter> rateCTInput = new Input<>("rateCT", "substitution rate for C to T (default 1)");
final public Input<RealParameter> rateGTInput = new Input<>("rateGT", "substitution rate for G to T (default 1)");
RealParameter rateAC;
RealParameter rateAG;
RealParameter rateAT;
RealParameter rateCG;
RealParameter rateCT;
RealParameter rateGT;
// For hardcoding equal base frequencies
//double[] frequencies;
public SYM() {
ratesInput.setRule(Validate.OPTIONAL);
try {
ratesInput.setValue(null, this);
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}
// Override the superclass SubstitutionModel.Base requirement for input frequencies, since they are equal in SYM
//frequenciesInput.setRule(Validate.OPTIONAL);
//try {
// initAndValidate();
//} catch (Exception e) {
// e.printStackTrace();
// throw new RuntimeException("initAndValidate() call failed when constructing SYM()");
//}
}
@Override
public void initAndValidate() {
if (ratesInput.get() != null) {
throw new IllegalArgumentException("the rates attribute should not be used. Use the individual rates rateAC, rateCG, etc, instead.");
}
//if (frequenciesInput.get() != null) {
// throw new RuntimeException("Frequencies must not be specified in the SYM model. They are assumed equal.");
// }
// Set equal base frequencies
//frequencies = new double[]{0.25, 0.25, 0.25, 0.25};
frequencies = frequenciesInput.get();
updateMatrix = true;
nrOfStates = frequencies.getFreqs().length;
try {
eigenSystem = createEigenSystem();
} catch (SecurityException | ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
throw new IllegalArgumentException(e.getMessage());
}
rateMatrix = new double[nrOfStates][nrOfStates];
relativeRates = new double[nrOfStates * (nrOfStates - 1)];
storedRelativeRates = new double[nrOfStates * (nrOfStates - 1)];
rateAC = getParameter(rateACInput);
rateAG = getParameter(rateAGInput);
rateAT = getParameter(rateATInput);
rateCG = getParameter(rateCGInput);
rateCT = getParameter(rateCTInput);
rateGT = getParameter(rateGTInput);
}
private RealParameter getParameter(Input<RealParameter> parameterInput) {
if (parameterInput.get() != null) {
return parameterInput.get();
}
return new RealParameter("1.0");
}
@Override
protected void setupRelativeRates() {
relativeRates[0] = rateAC.getValue(); // A->C
relativeRates[1] = rateAG.getValue(); // A->G
relativeRates[2] = rateAT.getValue(); // A->T
relativeRates[3] = rateAC.getValue(); // C->A
relativeRates[4] = rateCG.getValue(); // C->G
relativeRates[5] = rateCT.getValue(); // C->T
relativeRates[6] = rateAG.getValue(); // G->A
relativeRates[7] = rateCG.getValue(); // G->C
relativeRates[8] = rateGT.getValue(); // G->T
relativeRates[9] = rateAT.getValue(); // T->A
relativeRates[10] = rateCT.getValue(); //T->C
relativeRates[11] = rateGT.getValue(); //T->G
}
@Override
public boolean canHandleDataType(DataType dataType) {
return dataType instanceof Nucleotide;
}
}