/*
* CoalescentLikelihoodParser.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.evomodelxml.coalescent;
import dr.evolution.tree.TreeUtils;
import dr.evolution.util.Taxa;
import dr.evolution.util.TaxonList;
import dr.evomodel.coalescent.CoalescentLikelihood;
import dr.evomodel.coalescent.DemographicModel;
import dr.evomodel.coalescent.MultiLociTreeSet;
import dr.evomodel.coalescent.OldAbstractCoalescentLikelihood;
import dr.evomodel.tree.TreeModel;
import dr.xml.*;
import java.util.ArrayList;
import java.util.List;
/**
*/
public class CoalescentLikelihoodParser extends AbstractXMLObjectParser {
public static final String COALESCENT_LIKELIHOOD = "coalescentLikelihood";
public static final String MODEL = "model";
public static final String POPULATION_TREE = "populationTree";
public static final String POPULATION_FACTOR = "factor";
public static final String INCLUDE = "include";
public static final String EXCLUDE = "exclude";
public String getParserName() {
return COALESCENT_LIKELIHOOD;
}
public Object parseXMLObject(XMLObject xo) throws XMLParseException {
XMLObject cxo = xo.getChild(MODEL);
DemographicModel demoModel = (DemographicModel) cxo.getChild(DemographicModel.class);
List<TreeModel> trees = new ArrayList<TreeModel>();
List<Double> popFactors = new ArrayList<Double>();
MultiLociTreeSet treesSet = demoModel instanceof MultiLociTreeSet ? (MultiLociTreeSet) demoModel : null;
for (int k = 0; k < xo.getChildCount(); ++k) {
final Object child = xo.getChild(k);
if (child instanceof XMLObject) {
cxo = (XMLObject) child;
if (cxo.getName().equals(POPULATION_TREE)) {
final TreeModel t = (TreeModel) cxo.getChild(TreeModel.class);
assert t != null;
trees.add(t);
popFactors.add(cxo.getAttribute(POPULATION_FACTOR, 1.0));
}
}
// in the future we may have arbitrary multi-loci element
// else if( child instanceof MultiLociTreeSet ) {
// treesSet = (MultiLociTreeSet)child;
// }
}
TreeModel treeModel = null;
if (trees.size() == 1 && popFactors.get(0) == 1.0) {
treeModel = trees.get(0);
} else if (trees.size() > 1) {
treesSet = new MultiLociTreeSet.Default(trees, popFactors);
} else if (!(trees.size() == 0 && treesSet != null)) {
throw new XMLParseException("Incorrectly constructed likelihood element");
}
TaxonList includeSubtree = null;
if (xo.hasChildNamed(INCLUDE)) {
includeSubtree = (TaxonList) xo.getElementFirstChild(INCLUDE);
}
List<TaxonList> excludeSubtrees = new ArrayList<TaxonList>();
if (xo.hasChildNamed(EXCLUDE)) {
cxo = xo.getChild(EXCLUDE);
for (int i = 0; i < cxo.getChildCount(); i++) {
excludeSubtrees.add((TaxonList) cxo.getChild(i));
}
}
if (treeModel != null) {
try {
return new CoalescentLikelihood(treeModel, includeSubtree, excludeSubtrees, demoModel);
} catch (TreeUtils.MissingTaxonException mte) {
throw new XMLParseException("treeModel missing a taxon from taxon list in " + getParserName() + " element");
}
} else {
if (includeSubtree != null || excludeSubtrees.size() > 0) {
throw new XMLParseException("Include/Exclude taxa not supported for multi locus sets");
}
// Use old code for multi locus sets.
// This is a little unfortunate but the current code is using AbstractCoalescentLikelihood as
// a base - and modifing it will probsbly result in a bigger mess.
return new OldAbstractCoalescentLikelihood(treesSet, demoModel);
}
}
//************************************************************************
// AbstractXMLObjectParser implementation
//************************************************************************
public String getParserDescription() {
return "This element represents the likelihood of the tree given the demographic function.";
}
public Class getReturnType() {
return CoalescentLikelihood.class;
}
public XMLSyntaxRule[] getSyntaxRules() {
return rules;
}
private final XMLSyntaxRule[] rules = {
new ElementRule(MODEL, new XMLSyntaxRule[]{
new ElementRule(DemographicModel.class)
}, "The demographic model which describes the effective population size over time"),
new ElementRule(POPULATION_TREE, new XMLSyntaxRule[]{
AttributeRule.newDoubleRule(POPULATION_FACTOR, true),
new ElementRule(TreeModel.class)
}, "Tree(s) to compute likelihood for", 0, Integer.MAX_VALUE),
new ElementRule(INCLUDE, new XMLSyntaxRule[]{
new ElementRule(Taxa.class)
}, "An optional subset of taxa on which to calculate the likelihood (should be monophyletic)", true),
new ElementRule(EXCLUDE, new XMLSyntaxRule[]{
new ElementRule(Taxa.class, 1, Integer.MAX_VALUE)
}, "One or more subsets of taxa which should be excluded from calculate the likelihood (should be monophyletic)", true)
};
}