/* * StarTreeModel.java * * Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard * * This file is part of BEAST. * See the NOTICE file distributed with this work for additional * information regarding copyright ownership and licensing. * * BEAST is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * BEAST is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with BEAST; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA */ package dr.evomodel.tree; import dr.evolution.tree.NodeRef; import dr.evolution.tree.Tree; import dr.inference.model.Bounds; import dr.inference.model.Model; import dr.inference.model.Parameter; import dr.inference.model.Variable; /** * @author Marc Suchard */ public class StarTreeModel extends TreeModel { public StarTreeModel(String id, Tree tree) { super(id, tree); maxTipHeightKnown = false; rootHeightParameter = null; sharedRoot = null; } @Override public void setupHeightBounds() { if (heightBoundsSetup) { throw new IllegalArgumentException("Node height bounds set up twice"); } for (int i = 0; i < getNodeCount(); i++) { setupHeightBounds((Node) getNode(i)); } heightBoundsSetup = true; } // private void fixInternalNodeHeightToRoot() { // double rootHeight = getNodeHeight(getRoot()); // for (int i = 0; i < getInternalNodeCount(); ++i) { // Node node = (Node) getInternalNode(i); // if (node != getRoot()) { // node.heightParameter.setParameterValueQuietly(0, rootHeight); // } // } // fixedInternalNodes = true; // } // public void setRootHeightParameter(Parameter p) { // addVariable(p); // rootHeightParameter = p; // } private void setupHeightBounds(Node node) { node.heightParameter.addBounds(new StarTreeNodeHeightBounds(node.heightParameter)); } protected void handleModelChangedEvent(Model model, Object object, int index) { if (model == sharedRoot) { if (object instanceof TreeChangedEvent) { TreeChangedEvent event = (TreeChangedEvent) object; if (event.getParameter() == sharedRoot.getRootHeightParameter()) { pushTreeChangedEvent(); } } } } public void handleVariableChangedEvent(Variable variable, int index, Parameter.ChangeType type) { if (variable == rootHeightParameter) { pushTreeChangedEvent(); } else { final Node node = getNodeOfParameter((Parameter) variable); if (node.isRoot()) { pushTreeChangedEvent(); } else if (node.isExternal()) { maxTipHeightKnown = false; pushTreeChangedEvent(); } else { throw new IllegalArgumentException("Can not sample internal nodes in StarTree"); } super.handleVariableChangedEvent(variable, index, type); } } public double getNodeHeight(final NodeRef nr) { Node node = (Node) nr; if (!node.isExternal()) { if (rootHeightParameter != null) { return rootHeightParameter.getParameterValue(0); } else if (sharedRoot != null) { return sharedRoot.getNodeHeight(sharedRoot.getRoot()); } else { return ((Node) getRoot()).getHeight(); } } return node.getHeight(); } public void setSharedRootHeightParameter(TreeModel sharedRoot) { this.sharedRoot = sharedRoot; addModel(sharedRoot); } private class StarTreeNodeHeightBounds implements Bounds<Double> { public StarTreeNodeHeightBounds(Parameter parameter) { nodeHeightParameter = parameter; } public Double getUpperLimit(int i) { Node node = getNodeOfParameter(nodeHeightParameter); if (node.isRoot()) { return Double.POSITIVE_INFINITY; } else { return getNodeHeight(getRoot()); } } public Double getLowerLimit(int i) { Node node = getNodeOfParameter(nodeHeightParameter); if (node.isExternal()) { return 0.0; } else { return getMaxTipHeight(); } } public int getBoundsDimension() { return 1; } private Parameter nodeHeightParameter = null; } public void storeState() { super.storeState(); savedMaxTipHeight = maxTipHeight; savedMaxTipHeightKnown = maxTipHeightKnown; } public void restoreState() { super.restoreState(); maxTipHeight = savedMaxTipHeight; maxTipHeightKnown = savedMaxTipHeightKnown; } private double getMaxTipHeight() { if (!maxTipHeightKnown) { maxTipHeight = getNodeHeight(getExternalNode(0)); for (int i = 1; i < getExternalNodeCount(); ++i) { double height = getNodeHeight(getExternalNode(i)); if (height > maxTipHeight) { maxTipHeight = height; } } maxTipHeightKnown = true; } return maxTipHeight; } private boolean maxTipHeightKnown = false; private boolean savedMaxTipHeightKnown; private double maxTipHeight = 5; private double savedMaxTipHeight; private Parameter rootHeightParameter = null; private TreeModel sharedRoot = null; }