package dr.evomodel.continuous; import dr.evolution.tree.Tree; import dr.evolution.tree.NodeRef; import dr.xml.*; import dr.evomodel.tree.TreeModel; import dr.evomodel.tree.TreeStatistic; import dr.inference.model.Statistic; import dr.geo.math.SphericalPolarCoordinates; import java.util.ArrayList; import java.util.List; /** * @author Marc Suchard * @author Philippe Lemey * @author Andrew Rambaut */ public class DiffusionRateStatistic extends Statistic.Abstract { public static final String DIFFUSION_RATE_STATISTIC = "diffusionRateStatistic"; public static final String TREE_DISPERSION_STATISTIC = "treeDispersionStatistic"; public static final String BOOLEAN_OPTION = "greatCircleDistance"; public DiffusionRateStatistic(String name, TreeModel tree, List<AbstractMultivariateTraitLikelihood> traitLikelihoods, boolean genericOption) { super(name); this.traitLikelihoods = traitLikelihoods; this.genericOption = genericOption; } public int getDimension() { return 1; } /** * @return whatever Philippe wants */ public double getStatisticValue(int dim) { String traitName = traitLikelihoods.get(0).getTraitName(); double treelength = 0; double treeDistance = 0; for (AbstractMultivariateTraitLikelihood traitLikelihood : traitLikelihoods) { TreeModel tree = traitLikelihood.getTreeModel(); for (int i = 0; i < tree.getNodeCount(); i++) { NodeRef node = tree.getNode(i); double[] trait = traitLikelihood.getTraitForNode(tree, node, traitName); if (node != tree.getRoot()) { double[] parentTrait = traitLikelihood.getTraitForNode(tree, tree.getParent(node), traitName); treelength += tree.getBranchLength(node); if (genericOption) { // Great Circle distance SphericalPolarCoordinates coord1 = new SphericalPolarCoordinates(trait[0], trait[1]); SphericalPolarCoordinates coord2 = new SphericalPolarCoordinates(parentTrait[0], parentTrait[1]); treeDistance += coord1.distance(coord2); } else { treeDistance += getNativeDistance(trait, parentTrait); } } } } return treeDistance / treelength; } private double getNativeDistance(double[] location1, double[] location2) { return Math.sqrt(Math.pow((location2[0] - location1[0]), 2.0) + Math.pow((location2[1] - location1[1]), 2.0)); } public static XMLObjectParser PARSER = new AbstractXMLObjectParser() { public String getParserName() { return DIFFUSION_RATE_STATISTIC; } @Override public String[] getParserNames() { return new String[] { getParserName(), TREE_DISPERSION_STATISTIC }; } public Object parseXMLObject(XMLObject xo) throws XMLParseException { String name = xo.getAttribute(NAME, xo.getId()); TreeModel tree = (TreeModel) xo.getChild(Tree.class); boolean option = xo.getAttribute(BOOLEAN_OPTION, false); // Default value is false List<AbstractMultivariateTraitLikelihood> traitLikelihoods = new ArrayList<AbstractMultivariateTraitLikelihood>(); for (int i = 0; i < xo.getChildCount(); i++) { if (xo.getChild(i) instanceof AbstractMultivariateTraitLikelihood) { traitLikelihoods.add((AbstractMultivariateTraitLikelihood) xo.getChild(i)); } } return new DiffusionRateStatistic(name, tree, traitLikelihoods, option); } //************************************************************************ // AbstractXMLObjectParser implementation //************************************************************************ public String getParserDescription() { return "A statistic that returns the average of the branch rates"; } public Class getReturnType() { return TreeStatistic.class; } public XMLSyntaxRule[] getSyntaxRules() { return rules; } private XMLSyntaxRule[] rules = new XMLSyntaxRule[]{ AttributeRule.newStringRule(NAME, true), AttributeRule.newBooleanRule(BOOLEAN_OPTION, true), new ElementRule(AbstractMultivariateTraitLikelihood.class, 1, Integer.MAX_VALUE), }; }; private boolean genericOption; private List<AbstractMultivariateTraitLikelihood> traitLikelihoods; }