/* * CheckPointUpdater.java * * Copyright (c) 2002-2017 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.app.realtime; import dr.app.beast.BeastParser; import dr.app.checkpoint.BeastCheckpointer; import dr.app.util.Arguments; import dr.evolution.alignment.PatternList; import dr.evolution.distance.DistanceMatrix; import dr.evolution.distance.F84DistanceMatrix; import dr.evolution.distance.JukesCantorDistanceMatrix; import dr.evolution.util.Taxon; import dr.inference.markovchain.MarkovChain; import dr.inference.mcmc.MCMC; import dr.xml.XMLParseException; import dr.xml.XMLParser; import org.xml.sax.SAXException; import javax.xml.parsers.ParserConfigurationException; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Locale; /** * @author Guy Baele */ public class CheckPointUpdaterApp { private final boolean ADD_TAXA = true; private final boolean VERBOSE = true; private final boolean PARSER_WARNINGS = true; private final boolean STRICT_XML = false; public enum UpdateChoice { JC69DISTANCE("JC69Distance", new JukesCantorDistanceMatrix()), F84DISTANCE("F84Distance", new F84DistanceMatrix()), SIMPLE("Simple", new SimpleDistanceMatrix()); private String name; private DistanceMatrix matrix; UpdateChoice(String name, DistanceMatrix matrix) { this.name = name; this.matrix = matrix; } public void setPatterns(PatternList patterns) { this.matrix.setPatterns(patterns); } public Taxon getClosestTaxon(Taxon taxon) { if (matrix == null) { throw new RuntimeException("Patterns need to be set first."); } int taxonIndex = matrix.getTaxonIndex(taxon); int closestIndex = 0; double minimumDistance = Double.MAX_VALUE; for (int i = 0; i < matrix.getColumnCount(); i++) { if (i != taxonIndex) { if (matrix.getElement(taxonIndex, i) < minimumDistance) { minimumDistance = matrix.getElement(taxonIndex, i); closestIndex = i; } } } return matrix.getTaxon(closestIndex); } public Taxon getClosestTaxon(Taxon taxon, ArrayList<Taxon> taxa) { if (matrix == null) { throw new RuntimeException("Patterns need to be set first."); } int taxonIndex = matrix.getTaxonIndex(taxon); int closestIndex = 0; double minimumDistance = Double.MAX_VALUE; for (int i = 0; i < matrix.getColumnCount(); i++) { if (i != taxonIndex) { if ((matrix.getElement(taxonIndex, i) < minimumDistance) && (taxa.contains(matrix.getTaxon(i)))) { minimumDistance = matrix.getElement(taxonIndex, i); closestIndex = i; } } } return matrix.getTaxon(closestIndex); } public double getDistance(Taxon taxonOne, Taxon taxonTwo) { System.out.println("taxon 1: " + taxonOne + " (" + matrix.getTaxonIndex(taxonOne) + ")"); System.out.println("taxon 2: " + taxonTwo + " (" + matrix.getTaxonIndex(taxonTwo) + ")"); return matrix.getElement(matrix.getTaxonIndex(taxonOne), matrix.getTaxonIndex(taxonTwo)); } public String getName() { return this.name; } public DistanceMatrix getMatrix() { return this.matrix; } public String toString() { return this.name; } } /** * The goal is to modify and existing checkpoint file with additional information and generate a novel checkpoint file. * Running the MCMC chain after parsing the file(s) should not happen. * @param beastXMLFileName */ public CheckPointUpdaterApp(String beastXMLFileName, String debugStateFile, UpdateChoice choice) { //no additional parsers, we don't need BEAGLE at the moment just yet XMLParser parser = new BeastParser(new String[]{beastXMLFileName}, null, VERBOSE, PARSER_WARNINGS, STRICT_XML); try { FileReader fileReader = new FileReader(beastXMLFileName); //Don't run the analysis, so set the argument to false //parser.parse(fileReader, false); //get the MCMC object MCMC mcmc = (MCMC) parser.parse(fileReader, MCMC.class); MarkovChain mc = mcmc.getMarkovChain(); // Install the checkpointer. This creates a factory that returns // appropriate savers and loaders according to the user's options. // BeastCheckpointer checkpoint = new BeastCheckpointer(); CheckPointModifier checkpoint = new CheckPointModifier(); //load the stored checkpoint file //this will/should also copy any trait information present in the checkpoint file //TODO Check if this works for multiple trees (e.g. for multiple partitions) long state = checkpoint.loadState(mc, new double[]{Double.NaN}); //probably don't need this but it's good to check double logL = mc.evaluate(); System.out.println("likelihood = " + logL); mc.getLikelihood().makeDirty(); logL = mc.evaluate(); System.out.println("likelihood = " + logL); if (ADD_TAXA) { checkpoint.extendLoadState(choice); logL = mc.evaluate(); System.out.println("likelihood = " + logL); mc.getLikelihood().makeDirty(); logL = mc.evaluate(); System.out.println("likelihood = " + logL); } checkpoint.saveState(mc, state, logL); //TODO .log and .trees files are being created; not necessary here as we're not running an analysis fileReader.close(); } catch (FileNotFoundException fnf) { System.out.println(fnf); } catch (IOException io) { System.out.println(io); io.printStackTrace(); } catch (SAXException sax) { System.out.println(sax); } catch (XMLParseException xml) { System.out.println(xml); } catch (ParserConfigurationException pce) { System.out.println(pce); } } public static void main(String[] args) throws java.io.IOException { // There is a major issue with languages that use the comma as a decimal separator. // To ensure compatibility between programs in the package, enforce the US locale. Locale.setDefault(Locale.US); Arguments arguments = new Arguments( new Arguments.Option[]{ new Arguments.StringOption("BEAST_XML", "FILENAME", "Specify a BEAST XML file"), new Arguments.StringOption("load_dump", "FILENAME", "Specify a filename to load a dumped state from"), new Arguments.StringOption("output_file", "FILENAME", "Specify a filename for the output file"), new Arguments.StringOption("update_choice", "UPDATECHOICE", "Specify a function by which to update the tree"), new Arguments.Option("help", "Print this information and stop") }); try { arguments.parseArguments(args); } catch (Arguments.ArgumentException ae) { System.out.println(); System.out.println(ae.getMessage()); System.out.println(); //printUsage(arguments); System.exit(1); } String inputFile = null; if (arguments.hasOption("BEAST_XML")) { inputFile = arguments.getStringOption("BEAST_XML"); } else { throw new RuntimeException("No BEAST XML file specified."); } String debugStateFile; if (arguments.hasOption("load_dump")) { debugStateFile = arguments.getStringOption("load_dump"); //pass on as argument System.setProperty(BeastCheckpointer.LOAD_STATE_FILE, debugStateFile); } else { throw new RuntimeException("No dump file specified."); } String choice = ""; if (arguments.hasOption("update_choice")) { choice = arguments.getStringOption("update_choice"); } else { throw new RuntimeException("Update mechanism needs to be specified."); } UpdateChoice chosen = null; for (UpdateChoice ch : UpdateChoice.values()) { if (choice.equals(ch.getName())) { chosen = ch; break; } } if (chosen == null) { throw new RuntimeException("Incorrect update mechanism specified."); } if (arguments.hasOption("output_file")) { String outputStateFile = arguments.getStringOption("output_file"); //pass on as argument System.setProperty(BeastCheckpointer.SAVE_STATE_FILE, outputStateFile); } else { throw new RuntimeException("No output file specified."); } new CheckPointUpdaterApp(inputFile, debugStateFile, chosen); System.exit(0); } }