package beast.evolution.sitemodel;
import java.util.ArrayList;
import java.util.List;
import beast.core.CalculationNode;
import beast.core.Description;
import beast.core.Input;
import beast.core.Input.Validate;
import beast.core.StateNode;
import beast.evolution.datatype.DataType;
import beast.evolution.likelihood.TreeLikelihood;
import beast.evolution.substitutionmodel.SubstitutionModel;
import beast.evolution.tree.Node;
/**
* SiteModel - Specifies how rates and substitution models vary across sites.
*
* @author Andrew Rambaut
* @author Alexei Drummond
* @version $Id: SiteModel.java,v 1.77 2005/05/24 20:25:58 rambaut Exp $
*/
public interface SiteModelInterface {
/**
* set DataType so it can validate the Substitution model can handle it *
* @param dataType
*/
void setDataType(DataType dataType);
@Description(value = "Base implementation of a site model with substitution model and rate categories.", isInheritable = false)
public abstract class Base extends CalculationNode implements SiteModelInterface {
final public Input<SubstitutionModel> substModelInput =
new Input<>("substModel", "substitution model along branches in the beast.tree", null, Validate.REQUIRED);
/**
* Specifies whether SiteModel should integrate over the different categories at
* each site. If true, the SiteModel will calculate the likelihood of each site
* for each category. If false it will assume that there is each site can have a
* different category.
*
* @return the boolean
*/
abstract public boolean integrateAcrossCategories();
/**
* @return the number of categories of substitution processes
*/
abstract public int getCategoryCount();
/**
* Get the category of a particular site. If integrateAcrossCategories is true.
* then throws an IllegalArgumentException.
*
* @param site the index of the site
* @param node
* @return the index of the category
*/
abstract public int getCategoryOfSite(int site, Node node);
/**
* Get the rate for a particular category. This will include the 'mu' parameter, an overall
* scaling of the siteModel.
*
* @param category the category number
* @param node
* @return the rate.
*/
abstract public double getRateForCategory(int category, Node node);
/**
* Get an array of the rates for all categories.
*
* @param node
* @return an array of rates.
*/
abstract public double[] getCategoryRates(Node node);
/**
* Get the expected proportion of sites in this category.
*
* @param category the category number
* @param node
* @return the proportion.
*/
abstract public double getProportionForCategory(int category, Node node);
/**
* Get an array of the expected proportion of sites for all categories.
*
* @param node
* @return an array of proportions.
*/
abstract public double[] getCategoryProportions(Node node);
public boolean canSetSubstModel(Object o) {
final SubstitutionModel substModel = (SubstitutionModel) o;
if (m_dataType == null) {
// try to find out the data type from the data in a treelikelihood in an output
for (Object beastObject : getOutputs()) {
if (beastObject instanceof TreeLikelihood) {
TreeLikelihood likelihood = (TreeLikelihood) beastObject;
m_dataType = likelihood.dataInput.get().getDataType();
break;
}
}
}
if (m_dataType != null) {
if (!substModel.canHandleDataType(m_dataType)) {
return false;
//throw new Exception("substitution model cannot handle data type");
}
}
return true;
}
DataType m_dataType;
/**
* Flag indicating proportional invariant is treated as a separate
* category. If set to false, only gamma-categories are returned and
* a TreeLikelihood has to deal with the proportional invariant category
* separately -- and potentially much more efficiently.
*/
public boolean hasPropInvariantCategory = true;
public void setPropInvariantIsCategory(final boolean propInvariantIsCategory) {
hasPropInvariantCategory = propInvariantIsCategory;
refresh();
}
/**
* set up categories, reserve appropriately sized memory *
*/
protected void refresh() {
}
/**
* Get this site model's substitution model
*
* @return the substitution model
*/
public SubstitutionModel getSubstitutionModel() {
return substModelInput.get();
}
/**
* list of IDs onto which SiteModel is conditioned *
*/
protected List<String> conditions = null;
/**
* return the list, useful for ... *
* @return
*/
public List<String> getConditions() {
return conditions;
}
/**
* add item to the list *
* @param stateNode
*/
public void addCondition(final Input<? extends StateNode> stateNode) {
if (stateNode.get() == null) return;
if (conditions == null) conditions = new ArrayList<>();
conditions.add(stateNode.get().getID());
}
@Override
public void setDataType(final DataType dataType) {
m_dataType = dataType;
}
public double getProportionInvariant() {
return 0;
}
} // class SiteModelInterface.Base
} // SiteModelInterface