es.uvigo.ei.sing.adops.operations.running.ExecuteExperimentBySteps.java Source code

Java tutorial

Introduction

Here is the source code for es.uvigo.ei.sing.adops.operations.running.ExecuteExperimentBySteps.java

Source

/*-
 * #%L
 * ADOPS
 * %%
 * Copyright (C) 2012 - 2017 David Reboiro-Jato, Miguel Reboiro-Jato, Jorge Vieira, Florentino Fdez-Riverola, Cristina P. Vieira, Nuno A. Fonseca
 * %%
 * 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 3 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, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */
package es.uvigo.ei.sing.adops.operations.running;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;

import es.uvigo.ei.aibench.core.operation.annotation.Cancel;
import es.uvigo.ei.aibench.core.operation.annotation.Direction;
import es.uvigo.ei.aibench.core.operation.annotation.Operation;
import es.uvigo.ei.aibench.core.operation.annotation.Port;
import es.uvigo.ei.aibench.core.operation.annotation.Progress;
import es.uvigo.ei.sing.adops.datatypes.CodeMLOutput;
import es.uvigo.ei.sing.adops.datatypes.Experiment;
import es.uvigo.ei.sing.adops.datatypes.ExperimentOutput;
import es.uvigo.ei.sing.adops.datatypes.MrBayesOutput;
import es.uvigo.ei.sing.adops.datatypes.OperationOutput;
import es.uvigo.ei.sing.adops.datatypes.TCoffeeOutput;
import es.uvigo.ei.sing.adops.operations.running.codeml.CodeMLOperation;
import es.uvigo.ei.sing.adops.operations.running.mrbayes.MrBayesOperation;
import es.uvigo.ei.sing.adops.operations.running.tcoffee.TCoffeeOperation;
import es.uvigo.ei.sing.adops.util.Utils;
import es.uvigo.ei.sing.adops.util.Utils.LinesFilter;

@Operation(name = "Run Experiment")
public class ExecuteExperimentBySteps extends CallableOperation<ExperimentOutput> {
    private final static Logger LOG = Logger.getLogger(ExecuteExperimentBySteps.class);

    private Experiment experiment;
    private ExperimentOutput experimentOutput;

    private TCoffeeOperation tCoffeeOperation;
    private MrBayesOperation mrBayesOperation;
    private CodeMLOperation codeMLOperation;

    private PrintStream logPS;
    private File logFile;

    private StatusProgress progress = new StatusProgress();

    @Progress
    public StatusProgress getProgress() {
        return progress;
    }

    public static class StatusProgress {
        private String status = "";

        public String getStatus() {
            return status;
        }

        public void setStatus(String status) {
            this.status = status;
        }
    }

    @Port(name = "Experiment", direction = Direction.INPUT, order = 1)
    public void setExperiment(Experiment experiment) {
        this.experiment = experiment;

        this.setOutputFolder(experiment.getFolder());
    }

    @Port(name = "Use Std. Output", order = 2, direction = Direction.INPUT, defaultValue = "true")
    public void setUseStdOutput(boolean useStdOutput) {
        if (useStdOutput)
            this.addPrintStream(System.out);
        else
            this.removePrintStream(System.out);
    }

    @Port(name = "Print Stream", direction = Direction.INPUT, order = 3, allowNull = true)
    public void setOutputStream(PrintStream out) {
        this.addPrintStream(out);
    }

    @Port(direction = Direction.OUTPUT, order = 1000)
    public ExperimentOutput createExperimentOutput() throws OperationException {
        try {
            this.progress.setStatus("Starting");

            this.experiment.setRunning(true);

            this.checkInterrupted();

            this.progress.setStatus("Creating output.log file");
            this.logFile = this.newOutputFile("output.log");
            this.addPrintStream(new PrintStream(logFile));

            this.checkInterrupted();

            this.progress.setStatus("Generating input files");
            this.experiment.generateInputFiles();

            this.checkInterrupted();

            return this.experimentOutput = new ExperimentOutput(this.experiment);
        } catch (IOException ioe) {
            this.clearWhenException();
            throw new OperationException("Error initializing execution", ioe);
        } catch (InterruptedException ie) {
            return null;
        } catch (Exception e) {
            this.clearWhenException();
            throw new OperationException("Unexpected error initializing execution", e);
        }
    }

    @Port(direction = Direction.OUTPUT, order = 2000)
    public TCoffeeOutput runTCoffee() throws OperationException {
        try {
            this.progress.setStatus("Running T-Coffee");

            this.checkInterrupted();

            this.tCoffeeOperation = new TCoffeeOperation();
            this.tCoffeeOperation.configure(this.experiment);
            this.configureOutputStreams(this.tCoffeeOperation);

            this.checkInterrupted();

            final TCoffeeOutput output = this.tCoffeeOperation.call();

            this.checkInterrupted();

            this.replaceSequenceNames(output.getAlignmentFile(),
                    this.experimentOutput.getRenamedAlignedFastaFile());
            this.replaceSequenceNames(output.getProteinAlignmentFile(),
                    this.experimentOutput.getRenamedAlignedProteinFastaFile());
            this.replaceSequenceNames(output.getFinalScoreFile(), this.experimentOutput.getRenamedScoreAsciiFile());
            this.replaceSequenceNamesAln(output.getFinalUsedAlnFile(),
                    this.experimentOutput.getRenamedAlignedProteinAlnFile());
            this.replaceOGaps(this.experimentOutput.getRenamedAlignedFastaFile());
            this.replaceOGaps(this.experimentOutput.getRenamedAlignedProteinFastaFile());
            this.replaceOGaps(this.experimentOutput.getRenamedScoreAsciiFile(), new Utils.LinesFilter() {
                @Override
                public boolean accept(int index, String line) {
                    return line.matches("^C[0-9]+.*");
                }
            });

            this.checkInterrupted();

            this.experimentOutput.setTCoffeeOutput(output);

            return output;
        } catch (OperationException oe) {
            this.clearWhenException();
            throw oe;
        } catch (IOException ioe) {
            this.clearWhenException();
            throw new OperationException("I/O error while running T-Coffee", ioe);
        } catch (InterruptedException ie) {
            return null;
        } catch (Exception e) {
            this.clearWhenException();
            throw new OperationException("Unexpected error running T-Coffee", e);
        }
    }

    @Port(direction = Direction.OUTPUT, order = 3000)
    public OperationOutput runMrBayes() throws OperationException {
        try {
            this.progress.setStatus("Running MrBayes");

            this.checkInterrupted();

            // MrBayes Configuration
            this.mrBayesOperation = new MrBayesOperation();
            this.mrBayesOperation.configure(this.experiment);
            this.configureOutputStreams(this.mrBayesOperation);

            this.checkInterrupted();

            final MrBayesOutput output = this.mrBayesOperation.call();

            this.checkInterrupted();

            this.replaceSequenceNames(output.getConFile(), this.experimentOutput.getRenamedTreeFile(), true);
            this.replaceSequenceNames(output.getPsrfFile(), this.experimentOutput.getPsrfFile());

            this.checkInterrupted();

            this.experimentOutput.setMrBayesOutput(output);

            return output;
        } catch (OperationException oe) {
            this.clearWhenException();
            throw oe;
        } catch (IOException ioe) {
            this.clearWhenException();
            throw new OperationException("I/O error while running MrBayes", ioe);
        } catch (InterruptedException ie) {
            return null;
        } catch (Exception e) {
            this.clearWhenException();
            throw new OperationException("Unexpected error running MrBayes", e);
        }
    }

    @Port(direction = Direction.OUTPUT, order = 4000)
    public CodeMLOutput runCodeML() throws OperationException {
        try {
            this.progress.setStatus("Running CodeML");

            this.checkInterrupted();

            this.codeMLOperation = new CodeMLOperation();
            this.codeMLOperation.configure(this.experiment);

            this.codeMLOperation.setConsFile(this.experimentOutput.getMrBayesOutput().getConFile());
            this.configureOutputStreams(this.codeMLOperation);

            this.checkInterrupted();

            final CodeMLOutput output = this.codeMLOperation.call();

            this.checkInterrupted();

            this.replaceSequenceNames(output.getOutputFile(), this.experimentOutput.getCodeMLOutputFile());
            this.replaceSequenceNames(output.getSummaryFile(), this.experimentOutput.getCodeMLSummaryFile());

            this.checkInterrupted();

            this.experimentOutput.setCodeMLOutput(output);

            return output;
        } catch (OperationException oe) {
            this.clearWhenException();
            throw oe;
        } catch (IOException ioe) {
            this.clearWhenException();
            throw new OperationException("I/O error while running CodeML", ioe);
        } catch (InterruptedException ie) {
            return null;
        } catch (Exception e) {
            this.clearWhenException();
            throw new OperationException("Unexpected error running CodeML", e);
        }
    }

    @Port(direction = Direction.OUTPUT, order = 5000)
    public ExperimentOutput getResult() throws OperationException {
        try {
            this.progress.setStatus("Generating summary file");

            this.checkInterrupted();

            FileUtils.writeLines(this.experimentOutput.getSummaryFile(),
                    Arrays.asList("--- EXPERIMENT NOTES",
                            FileUtils.readFileToString(this.experiment.getNotesFile()), "\n--- WARNINGS",
                            this.experiment.getWarnings(), "\n--- EXPERIMENT PROPERTIES",
                            this.experiment.getConfiguration().toString(), "\n--- PSRF SUMMARY",
                            FileUtils.readFileToString(this.experimentOutput.getPsrfFile()), "\n--- CODEML SUMMARY",
                            FileUtils.readFileToString(this.experimentOutput.getCodeMLSummaryFile())));

            if (this.logPS != null)
                this.logPS.close();

            this.experimentOutput.setFinished(true);
            this.experiment.setRunning(false);

            return this.experimentOutput;
        } catch (IOException ioe) {
            this.clearWhenException();
            throw new OperationException("Error generating result", ioe);
        } catch (InterruptedException ie) {
            this.clearWhenInterrupted();

            return null;
        } catch (Exception e) {
            this.clearWhenException();
            throw new OperationException("Unexpected error summarizing results", e);
        }
    }

    @Override
    protected ExperimentOutput internalCall() throws OperationException {
        this.createExperimentOutput();
        this.runTCoffee();
        this.runMrBayes();
        this.runCodeML();

        return this.getResult();
    }

    private void replaceOGaps(File inputFile) throws IOException {
        this.replaceOGaps(inputFile, new Utils.LinesFilter() {
            @Override
            public boolean accept(int index, String line) {
                return !line.startsWith(">");
            }
        });
    }

    private void replaceOGaps(File inputFile, LinesFilter filter) throws IOException {
        FileUtils.writeLines(inputFile,
                Utils.replaceNames(Collections.singletonMap("o", "-"), FileUtils.readLines(inputFile), filter));
    }

    private void replaceSequenceNames(File inputFile, File outputFile) throws IOException {
        this.replaceSequenceNames(inputFile, outputFile, false);
    }

    private void replaceSequenceNames(File inputFile, File outputFile, boolean isTree) throws IOException {
        final Map<String, String> names = this.experiment.getNames();

        if (isTree) {
            for (Map.Entry<String, String> name : names.entrySet()) {
                name.setValue(name.getValue().replaceAll("[():,]", "_"));
            }
        }

        final List<String> lines = FileUtils.readLines(inputFile);

        FileUtils.writeLines(outputFile, Utils.replaceNames(names, lines));
    }

    private void replaceSequenceNamesAln(File inputFile, File outputFile) throws IOException {
        final Map<String, String> names = this.experiment.getNames();
        final List<String> lines = FileUtils.readLines(inputFile);

        int maxLength = Integer.MIN_VALUE;
        for (Map.Entry<String, String> name : names.entrySet()) {
            maxLength = Math.max(maxLength, name.getValue().length());
        }

        for (Map.Entry<String, String> name : names.entrySet()) {
            String newName = name.getValue();

            while (newName.length() < maxLength) {
                newName += ' ';
            }

            name.setValue(newName);
        }

        final ListIterator<String> itLines = lines.listIterator();
        if (itLines.hasNext())
            itLines.next();

        // TODO Review parsing
        while (itLines.hasNext()) {
            itLines.next(); // White line

            String line = null;
            // Sequences
            while (itLines.hasNext()) {
                line = itLines.next();
                if (line.isEmpty())
                    break;
                final String[] lineSplit = line.split("\\s+");
                final String name = lineSplit.length == 0 ? "" : lineSplit[0];

                if (names.get(name) == null)
                    break;

                itLines.set(names.get(name) + "   " + lineSplit[1]);
            }

            // Marks line
            if (line != null && !line.isEmpty() && line.startsWith(" ")) {
                String newLine = line;

                if (maxLength < 13)
                    newLine = newLine.substring(13 - maxLength);
                else
                    for (int i = 16; i < maxLength + 3; i++) {
                        newLine = ' ' + newLine;
                    }

                itLines.set(newLine);
            }
        }

        FileUtils.writeLines(outputFile, lines);
    }

    @Override
    @Cancel
    public void cancel() {
        super.cancel();

        if (this.tCoffeeOperation != null)
            this.tCoffeeOperation.cancel();
        if (this.mrBayesOperation != null)
            this.mrBayesOperation.cancel();
        if (this.codeMLOperation != null)
            this.codeMLOperation.cancel();
    }

    @Override
    public void clear() {
        this.experiment.setRunning(false);
        if (this.logPS != null) {
            this.removePrintStream(this.logPS);
            this.logPS.close();
        }

        if (this.tCoffeeOperation != null)
            this.tCoffeeOperation.clear();
        if (this.mrBayesOperation != null)
            this.mrBayesOperation.clear();
        if (this.codeMLOperation != null)
            this.codeMLOperation.clear();

        super.clear();
    }

    @Override
    protected void clearWhenException() {
        if (this.logPS != null) {
            this.removePrintStream(this.logPS);
            this.logPS.close();
        }

        this.experiment.setRunning(false);
    }

    @Override
    protected void clearWhenInterrupted() {
        super.clearWhenInterrupted();

        if (this.logPS != null) {
            this.removePrintStream(this.logPS);
            this.logPS.close();
        }

        this.experiment.setRunning(false);
    }

    private void configureOutputStreams(ProcessOperation<?, ?, ?> operation) {
        operation.clearPrintStreams();

        for (PrintStream ps : this.getPrintStreams()) {
            operation.addPrintStream(ps);
        }
    }

    public final File generateTreeFile(File conFile, File namesFile, File treeFile) {
        // Read names file
        final Map<String, String> names = this.experiment.getNames();

        // Create new tree file
        try (BufferedReader br = new BufferedReader(new FileReader(conFile));
                FileWriter treeFW = new FileWriter(treeFile);) {

            String line = null;
            while ((line = br.readLine()) != null) {
                if (line.indexOf("con_50_majrule") != -1)
                    for (String s : names.keySet())
                        line = line.replaceAll(s, names.get(s));

                treeFW.append(line + "\n");
            }
        } catch (IOException e) {
            LOG.error("Error generating tree file", e);

            throw new RuntimeException("Error generating tree file", e);
        }

        return treeFile;
    }
}