/* * VariableDemographicModel.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.coalescent; import dr.evolution.coalescent.TreeIntervals; import dr.evolution.tree.Tree; import dr.evomodel.tree.TreeModel; import dr.evomodelxml.coalescent.VariableDemographicModelParser; import dr.inference.model.Model; import dr.inference.model.Parameter; import dr.inference.model.Variable; import dr.util.Author; import dr.util.Citable; import dr.util.Citation; import java.util.Arrays; import java.util.List; /** * @author Joseph Heled * @version $Id$ */ public class VariableDemographicModel extends DemographicModel implements MultiLociTreeSet, Citable { private final Parameter popSizeParameter; private final Parameter indicatorParameter; public Type getType() { return type; } private final Type type; private final boolean logSpace; private final boolean mid; private final TreeModel[] trees; private VDdemographicFunction demoFunction = null; private VDdemographicFunction savedDemoFunction = null; private final double[] populationFactors; public Parameter getPopulationValues() { return popSizeParameter; } public enum Type { LINEAR("linear"), EXPONENTIAL("exponential"), STEPWISE("stepwise"); Type(String name) { this.name = name; } public String toString() { return name; } String name; } public VariableDemographicModel(TreeModel[] trees, double[] popFactors, Parameter popSizeParameter, Parameter indicatorParameter, Type type, boolean logSpace, boolean mid) { super(VariableDemographicModelParser.MODEL_NAME); this.popSizeParameter = popSizeParameter; this.indicatorParameter = indicatorParameter; this.populationFactors = popFactors; int events = 0; for (Tree t : trees) { // number of coalescent events events += t.getExternalNodeCount() - 1; // we will have to handle this I guess assert t.getUnits() == trees[0].getUnits(); } // all trees share time 0, need fixing for serial data events += type == Type.STEPWISE ? 0 : 1; final int popSizes = popSizeParameter.getDimension(); final int nIndicators = indicatorParameter.getDimension(); this.type = type; this.logSpace = logSpace; this.mid = mid; if (popSizes != events) { System.err.println("INFO: resetting length of parameter " + popSizeParameter.getParameterName() + "(size " + popSizeParameter.getSize() + ") in variable demographic model to " + events); popSizeParameter.setDimension(events); popSizeParameter.addBounds(new Parameter.DefaultBounds(Double.MAX_VALUE, -Double.MAX_VALUE, popSizeParameter.getDimension())); } if (nIndicators != events - 1) { System.err.println("INFO: resetting length of parameter " + indicatorParameter.getParameterName() + " in variable demographic model to " + (events - 1)); indicatorParameter.setDimension(events - 1); indicatorParameter.addBounds(new Parameter.DefaultBounds(1, 0, indicatorParameter.getDimension())); } this.trees = trees; for (TreeModel t : trees) { addModel(t); } addVariable(indicatorParameter); addVariable(popSizeParameter); } public int nLoci() { return trees.length; } public Tree getTree(int k) { return trees[k]; } public TreeIntervals getTreeIntervals(int nt) { return getDemographicFunction().getTreeIntervals(nt); } public double getPopulationFactor(int nt) { return populationFactors[nt]; } public void storeTheState() { // as a demographic model store/restore is already taken care of } public void restoreTheState() { // as a demographic model store/restore is already taken care of } public VDdemographicFunction getDemographicFunction() { if (demoFunction == null) { demoFunction = new VDdemographicFunction(trees, type, indicatorParameter.getParameterValues(), popSizeParameter.getParameterValues(), logSpace, mid); } else { demoFunction.setup(trees, indicatorParameter.getParameterValues(), popSizeParameter.getParameterValues(), logSpace, mid); } return demoFunction; } protected void handleModelChangedEvent(Model model, Object object, int index) { // tree has changed //System.out.println("model changed: " + model); if (demoFunction != null) { if (demoFunction == savedDemoFunction) { demoFunction = new VDdemographicFunction(demoFunction); } for (int k = 0; k < trees.length; ++k) { if (model == trees[k]) { demoFunction.treeChanged(k); //System.out.println("tree changed: " + k + " " + Arrays.toString(demoFunction.dirtyTrees) // + " " + demoFunction.dirtyTrees); break; } assert k + 1 < trees.length; } } super.handleModelChangedEvent(model, object, index); fireModelChanged(this); } protected final void handleVariableChangedEvent(Variable variable, int index, Parameter.ChangeType type) { //System.out.println("parm changed: " + parameter); super.handleVariableChangedEvent(variable, index, type); if (demoFunction != null) { if (demoFunction == savedDemoFunction) { demoFunction = new VDdemographicFunction(demoFunction); } demoFunction.setDirty(); } fireModelChanged(this); } protected void storeState() { savedDemoFunction = demoFunction; } protected void restoreState() { //System.out.println("restore"); demoFunction = savedDemoFunction; savedDemoFunction = null; } @Override public Citation.Category getCategory() { return Citation.Category.TREE_PRIORS; } @Override public String getDescription() { return "Extended Bayesian Skyline multi-locus coalescent model"; } @Override public List<Citation> getCitations() { return Arrays.asList(new Citation( new Author[]{ new Author("J", "Heled"), new Author("AJ", "Drummond"), }, "Bayesian inference of population size history from multiple loci", 2008, "BMC Evolutionary Biology", 8, "289", "10.1186/1471-2148-8-289" )); } }