/* Copyright (C) 2009 Diego Darriba This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package es.uvigo.darwin.prottest; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.logging.Handler; import java.util.logging.Level; import static es.uvigo.darwin.prottest.global.ApplicationGlobals.APPLICATION_PROPERTIES; import mpi.MPI; import pal.misc.Identifier; import pal.tree.Tree; import es.uvigo.darwin.prottest.consensus.Consensus; import es.uvigo.darwin.prottest.exe.PhyMLv3AminoAcidRunEstimator; import es.uvigo.darwin.prottest.facade.ProtTestFacade; import es.uvigo.darwin.prottest.facade.ProtTestFacadeMPJ; import es.uvigo.darwin.prottest.facade.ProtTestFacadeSequential; import es.uvigo.darwin.prottest.facade.ProtTestFacadeThread; import es.uvigo.darwin.prottest.facade.TreeFacade; import es.uvigo.darwin.prottest.facade.TreeFacadeImpl; import es.uvigo.darwin.prottest.global.options.ApplicationOptions; import es.uvigo.darwin.prottest.model.Model; import es.uvigo.darwin.prottest.observer.ModelUpdaterObserver; import es.uvigo.darwin.prottest.observer.ObservableModelUpdater; import es.uvigo.darwin.prottest.selection.AIC; import es.uvigo.darwin.prottest.selection.AICc; import es.uvigo.darwin.prottest.selection.BIC; import es.uvigo.darwin.prottest.selection.DT; import es.uvigo.darwin.prottest.selection.InformationCriterion; import es.uvigo.darwin.prottest.selection.LNL; import es.uvigo.darwin.prottest.selection.printer.PrintFramework; import es.uvigo.darwin.prottest.util.FixedBitSet; import es.uvigo.darwin.prottest.util.argumentparser.ProtTestArgumentParser; import es.uvigo.darwin.prottest.util.collection.ModelCollection; import es.uvigo.darwin.prottest.util.collection.SingleModelCollection; import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException; import es.uvigo.darwin.prottest.util.factory.ProtTestFactory; import es.uvigo.darwin.prottest.util.logging.ProtTestLogger; import es.uvigo.darwin.prottest.util.printer.ProtTestPrinter; import es.uvigo.darwin.xprottest.XProtTestApp; /** * This is the main class of ProtTest. It calls the methods in the * concrete facade to interact with the model layer of the application. * * @author Diego Darriba */ public class ProtTest { /** The Constant versionNumber. */ public static final String versionNumber = "3.4.2"; /** The Constant versionDate. */ public static final String versionDate = "8th May 2016"; /** The MPJ rank of the process. It is only useful if MPJ is running.*/ public static int MPJ_ME; /** The MPJ size of the communicator. It is only useful if MPJ is running.*/ public static int MPJ_SIZE; /** The MPJ running state. */ public static boolean MPJ_RUN; /** The ProtTest factory. */ private static ProtTestFactory factory; public static final String URL_MANUAL = "http://darwin.uvigo.es/download/prottest_manual.pdf"; public static final String URL_HOMEPAGE = "http://github.com/ddarriba/prottest3"; public static final String URL_DISCUSSION_GROUP = "https://groups.google.com/group/prottest"; /** * The main method. It initializes the MPJ runtime environment, parses * the application arguments, initializes the application options and * starts the analysis of the substitution models. * * @param args the arguments */ public static void main(String[] args) { if (args.length < 1) { XProtTestApp.launch(XProtTestApp.class, args); return; } // initializing MPJ environment (if available) try { String[] argsApp = MPI.Init(args); MPJ_ME = MPI.COMM_WORLD.Rank(); MPJ_SIZE = MPI.COMM_WORLD.Size(); MPJ_RUN = true; args = argsApp; } catch (Exception e) { MPJ_ME = 0; MPJ_SIZE = 1; MPJ_RUN = false; } // force static initialization if (APPLICATION_PROPERTIES == null) { System.err.println("Error initialization ProtTest properties"); finalize(1); } try { args = ProtTestFactory.initialize(args); } catch (IllegalArgumentException e) { System.out.println("Illegal argument: " + e.getMessage()); finalize(1); } factory = ProtTestFactory.getInstance(); // Checking PhyML binary if (!PhyMLv3AminoAcidRunEstimator.checkBinary()) { finalize(1); } ProtTestLogger logger = ProtTestLogger.getDefaultLogger(); logger.setStdHandlerLevel(Level.INFO); // parse arguments ApplicationOptions opts = new ApplicationOptions(); int numThreads = 1; try { // check arguments and get application options numThreads = Integer.parseInt( factory.createProtTestArgumentParser(args, opts). getValue(ProtTestArgumentParser.PARAM_NUM_THREADS)); } catch (IllegalArgumentException e) { if (MPJ_ME == 0) { System.err.println("\n" + e.getMessage()); System.err.println("Run with -h for help.\n"); } finalize(1); } catch (ProtTestInternalException e) { if (MPJ_ME == 0) { System.err.println(e.getMessage()); } finalize(1); } catch (ExceptionInInitializerError e) { if (MPJ_ME == 0) { System.err.println("An error has occurred while initializing. Check your prottest.properties file."); } finalize(1); } if (MPJ_ME == 0) { try { if (opts.isLogEnabled()) { Handler logHandler = factory.createLogHandler(); if (logHandler != null) { logger.addHandler(logHandler); } } } catch (IOException ex) { logger.severeln(ex.getMessage()); } } // get the facade instance TreeFacade treeFacade = new TreeFacadeImpl(); ProtTestFacade facade; if (MPJ_RUN) { facade = new ProtTestFacadeMPJ(MPJ_RUN, MPJ_ME, MPJ_SIZE); } else if (numThreads > 1) { facade = new ProtTestFacadeThread(numThreads); } else { facade = new ProtTestFacadeSequential(); } /* if multiple models are optimized together, the execution will be monitorized */ if (MPJ_RUN || numThreads > 1) { facade.addObserver(new ModelUpdaterObserver() { @Override public void update(ObservableModelUpdater o, Model model, ApplicationOptions options) { if (model.isComputed() && options != null) { System.out.println("Computed: " + model.getModelName() + " (" + model.getLk() + ")"); } else { System.out.println("Computing " + model.getModelName() + "..."); } } }); } if (opts.isDebug()) { logger.setStdHandlerLevel(Level.ALL); } if (MPJ_ME == 0) { ProtTestPrinter.printHeader(); opts.reportComplete(); } Model[] models; try { // model optimization models = facade.startAnalysis(opts); // analyze results if (MPJ_ME == 0) { ModelCollection allModelsList = new SingleModelCollection(models, opts.getAlignment()); InformationCriterion aic, aicc, bic, dt, lnc; if (opts.isAIC()) { printCriterion( "AIC", new AIC(allModelsList, 1.0, opts.getSampleSize()), logger, opts, facade, treeFacade); } if (opts.isBIC()) { printCriterion( "BIC", new BIC(allModelsList, 1.0, opts.getSampleSize()), logger, opts, facade, treeFacade); } if (opts.isAICc()) { printCriterion( "AICc", new AICc(allModelsList, 1.0, opts.getSampleSize()), logger, opts, facade, treeFacade); } if (opts.isDT()) { printCriterion( "DT", new DT(allModelsList, 1.0, opts.getSampleSize()), logger, opts, facade, treeFacade); } if (!(opts.isAIC() | opts.isDT() | opts.isAICc() | opts.isDT())) { printCriterion( "lnL", new LNL(allModelsList, 1.0, opts.getSampleSize()), logger, opts, facade, treeFacade); } // display 7-framework comparison if (opts.isAll()) { PrintFramework.printFrameworksComparison(allModelsList); } } } catch (ProtTestInternalException e) { logger.severeln(e.getMessage()); finalize(-1); } catch (UnsupportedOperationException e) { logger.severeln(e.getMessage()); finalize(-1); } // finalize execution finalize(0); if (MPJ_RUN) { MPI.Finalize(); } } private static void printCriterion(String name, InformationCriterion ic, ProtTestLogger logger, ApplicationOptions opts, ProtTestFacade facade, TreeFacade treeFacade) { // let's print results: facade.printModelsSorted(ic); // display best model tree in ASCII if (opts.isDisplayASCIITree()) { ProtTestPrinter.printTreeHeader(ic.getBestModel().getModelName()); logger.infoln(treeFacade.toASCII(ic.getBestModel().getTree())); } // display best model tree in Newick if (opts.isDisplayNewickTree()) { if (!opts.isDisplayASCIITree()) { ProtTestPrinter.printTreeHeader(ic.getBestModel().getModelName()); } logger.infoln(treeFacade.toNewick(ic.getBestModel().getTree(), true, true, false)); } // display consensus tree data if (opts.isDisplayConsensusTree()) { ProtTestPrinter.printTreeHeader("MODEL AVERAGED PHYLOGENY"); Consensus consensus = treeFacade.createConsensus(ic, opts.getConsensusThreshold()); logger.infoln("----------------------------------------"); logger.infoln("Selection criterion: . . . . " + name); logger.infoln("Confidence interval: . . . . " + ic.getConfidenceInterval()); logger.infoln("Sample size: . . . . . . . . " + opts.getSampleSize()); logger.infoln("Consensus support threshold: " + opts.getConsensusThreshold()); logger.infoln("----------------------------------------"); logger.infoln(""); Set<FixedBitSet> keySet = consensus.getCladeSupport().keySet(); List<FixedBitSet> splitsInConsensus = new ArrayList<FixedBitSet>(); List<FixedBitSet> splitsOutFromConsensus = new ArrayList<FixedBitSet>(); for (FixedBitSet fbs : keySet) { if (fbs.cardinality() > 1) { double psupport = (1.0 * consensus.getCladeSupport().get(fbs)) / 1.0; if (psupport < opts.getConsensusThreshold()) { splitsOutFromConsensus.add(fbs); } else { splitsInConsensus.add(fbs); } } } logger.infoln("# # # # # # # # # # # # # # # #"); logger.infoln(" "); logger.infoln("Species in order:"); logger.infoln(" "); for (int i = 0; i < consensus.getIdGroup().getIdCount(); i++) { Identifier id = consensus.getIdGroup().getIdentifier(i); logger.infoln(" " + (i + 1) + ". " + id.getName()); } logger.infoln(" "); logger.infoln("# # # # # # # # # # # # # # # #"); logger.infoln(" "); logger.infoln("Sets included in the consensus tree"); logger.infoln(" "); int numTaxa = consensus.getIdGroup().getIdCount(); logger.infoln(consensus.getSetsIncluded()); logger.infoln(" "); logger.infoln("Sets NOT included in consensus tree"); logger.infoln(" "); logger.infoln(consensus.getSetsNotIncluded()); logger.infoln(" "); logger.infoln("# # # # # # # # # # # # # # # #"); logger.infoln(" "); Tree consensusTree = consensus.getConsensusTree(); String newickTree = treeFacade.toNewick(consensusTree, true, true, true); logger.infoln(newickTree); logger.infoln(" "); logger.infoln("# # # # # # # # # # # # # # # #"); logger.infoln(" "); logger.infoln(treeFacade.toASCII(consensusTree)); logger.infoln(""); logger.infoln(treeFacade.branchInfo(consensusTree)); logger.infoln(""); logger.infoln(treeFacade.heightInfo(consensusTree)); } } /** * Finalizes the MPJ runtime environment. When an error occurs, it * aborts the execution of every other processes. * * @param status the finalization status */ public static void finalize(int status) { if (status != 0) { if (MPJ_RUN) { MPI.COMM_WORLD.Abort(status); } } if (MPJ_RUN) { MPI.Finalize(); } System.exit(status); } }