/*
* TreeTrace.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.evolution.io;
import dr.evolution.tree.Tree;
import dr.util.Identifiable;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
/**
* @author Andrew Rambaut
* @author Alexei Drummond
* @version $Id: TreeTrace.java,v 1.10 2005/05/24 20:25:58 rambaut Exp $
*/
public class TreeTrace implements Identifiable {
public TreeTrace() {
}
public int getTreeCount(int burnin) {
int startIndex = (burnin - minState) / stepSize;
if (startIndex < 0) {
startIndex = 0;
}
return trees.size() - startIndex;
}
public Tree getTree(int index, int burnin) {
int startIndex = (burnin - minState) / stepSize;
if (startIndex < 0) {
startIndex = 0;
}
return trees.get(index + startIndex);
}
public void add(Tree tree) {
trees.add(tree);
}
public void setMinimumState(int minState) {
this.minState = minState;
}
public int getMinimumState() {
return minState;
}
public void setStepSize(int stepSize) {
this.stepSize = stepSize;
}
public int getStepSize() {
return stepSize;
}
public int getMaximumState() {
return (trees.size() - 1) * stepSize + minState;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
private ArrayList<Tree> trees = new ArrayList<Tree>();
private int minState;
private int stepSize;
private String id;
/**
* Loads the trace for with trees from a reader
*
* @param r the reader to load the trees from
* @return the TreeTrace
* @throws dr.evolution.io.Importer.ImportException
* thrown when tree file is not correctly formatted
* @throws java.io.IOException if general I/O error occurs
*/
public static TreeTrace loadTreeTrace(Reader r) throws IOException, Importer.ImportException {
BufferedReader reader = new BufferedReader(r);
TreeTrace trace = new TreeTrace();
dr.evolution.util.TaxonList taxonList = null;
int minState = -1;
int stepSize = 0;
String line = reader.readLine();
if (line.toUpperCase().startsWith("#NEXUS")) {
NexusImporter importer = new NexusImporter(reader);
Tree[] trees = importer.importTrees(null);
if (trees.length < 2) {
throw new Importer.ImportException("Less than two trees in the trace file");
}
String id1 = trees[0].getId();
String id2 = trees[1].getId();
minState = getStateNumber(id1);
stepSize = getStateNumber(id2) - minState;
for (Tree tree : trees) {
trace.add(tree);
}
} else {
NewickImporter importer = new NewickImporter(reader);
while (true) {
int state = 0;
Tree tree;
try {
state = importer.readInteger();
tree = importer.importTree(taxonList);
if (taxonList == null) {
// The first tree becomes the taxon list. This means
// that all subsequent trees will look up their taxa
// in that taxon list rather than creating their own
// duplicitous ones.
taxonList = tree;
}
} catch (Importer.ImportException ie) {
System.out.println("Error reading tree for state " + state);
throw ie;
} catch (EOFException e) {
break;
}
if (minState == -1) {
minState = state;
} else if (stepSize == 0) {
stepSize = state - minState;
}
trace.add(tree);
}
}
trace.setMinimumState(minState);
trace.setStepSize(stepSize);
return trace;
}
private static int getStateNumber(String id) throws Importer.ImportException {
try {
if (id.indexOf('_') != -1) { // probably BEAST tree file
return Integer.parseInt(id.substring(id.indexOf('_') + 1));
} else if (id.indexOf('.') != -1) { // probably MrBayes tree file
int rep = Integer.parseInt(id.substring(id.indexOf('.') + 1));
if (rep == 1) rep = 0;
return rep;
}
throw new NumberFormatException();
} catch (NumberFormatException nfe) {
throw new Importer.ImportException("Bad state number in tree label '" + id + "', the state must be preceded by an underscore(_).");
}
}
}