Merge branch 'develop' into features/mchmmer
[jalview.git] / src / jalview / hmmer / HMMAlignThread.java
index 2674c8c..fadbdb1 100644 (file)
@@ -1,5 +1,7 @@
 package jalview.hmmer;
 
+import jalview.analysis.AlignmentSorter;
+import jalview.analysis.SeqsetUtils;
 import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
@@ -10,33 +12,30 @@ import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
-import jalview.gui.Preferences;
+import jalview.gui.JvOptionPane;
 import jalview.gui.SplitFrame;
 import jalview.io.DataSourceType;
 import jalview.io.StockholmFile;
 import jalview.util.MessageManager;
 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
+import jalview.ws.params.ArgumentI;
 
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 import javax.swing.JInternalFrame;
 
-public class HMMAlignThread implements Runnable
+public class HMMAlignThread extends HmmerCommand implements Runnable
 {
+  static final String HMMALIGN = "hmmalign";
 
-  /**
+  /*
    * feature settings from view that job was associated with
    */
   protected FeatureRendererSettings featureSettings = null;
 
-  HMMERCommands cmds = new HMMERCommands();
-
-  AlignFrame af;
-
   AlignmentI alignment;
 
   AlignmentI dataset;
@@ -47,12 +46,12 @@ public class HMMAlignThread implements Runnable
 
   HiddenMarkovModel hmm;
 
+  List<ArgumentI> args;
+
   boolean newFrame;
 
   long barID;
 
-  Map<Integer, SequenceI> hmmSeqs;
-
   File hmmTemp = null;
 
   File outTemp = null;
@@ -63,7 +62,15 @@ public class HMMAlignThread implements Runnable
 
   SequenceI[][] allResults;
 
-  public HMMAlignThread(AlignFrame af, boolean createNewFrame)
+  /**
+   * Constructor for the HMMAlignThread. If create new frame is set to true, a
+   * new frame will be created.
+   * 
+   * @param af
+   * @param createNewFrame
+   */
+  public HMMAlignThread(AlignFrame af, boolean createNewFrame,
+          List<ArgumentI> args)
   {
     this.af = af;
     alignment = af.getViewport().getAlignment();
@@ -71,23 +78,26 @@ public class HMMAlignThread implements Runnable
     {
       dataset = alignment.getDataset();
     }
-    hmm = alignment.getSequenceAt(0).getHMM();
     newFrame = createNewFrame;
     featureSettings = af.getFeatureRenderer().getSettings();
+    this.args = args;
   }
 
+  /**
+   * Runs the HMMAlignThread: the data on the alignment or group is exported,
+   * then the command is executed in the command line and then the data is
+   * imported and displayed in a new frame (if true). The command is executed
+   * for each segemtn of the alignment.
+   */
   @Override
   public void run()
   {
+
+    hmm = af.getSelectedHMM();
+
     barID = System.currentTimeMillis();
-    af.setProgressBar(MessageManager.getString("status.running_hmmbuild"),
+    af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
             barID);
-    cmds.HMMERFOLDER = Cache.getProperty(Preferences.HMMER_PATH);
-
-    // if (!alignment.isAligned())
-    // {
-    // alignment.padGaps();
-    // }
     prepareAlignment();
     SequenceI[][] subAlignments = msa.getVisibleContigs('-');
     allOrders = new ArrayList<>();
@@ -95,7 +105,7 @@ public class HMMAlignThread implements Runnable
     int job = 0;
     for (SequenceI[] seqs : subAlignments)
     {
-      cmds.uniquifySequences(seqs);
+      uniquifySequences(seqs);
       try
       {
         createTemporaryFiles();
@@ -105,15 +115,21 @@ public class HMMAlignThread implements Runnable
       }
       try
       {
-        cmds.exportData(seqs, outTemp.getAbsoluteFile(), hmm,
-                hmmTemp.getAbsoluteFile());
+        exportData(seqs, outTemp.getAbsoluteFile(), hmm,
+                hmmTemp.getAbsoluteFile(), null);
       } catch (IOException e1)
       {
         e1.printStackTrace();
       }
       try
       {
-        runCommand();
+        boolean ran = runCommand();
+        if (!ran)
+        {
+          JvOptionPane.showInternalMessageDialog(af,
+                  MessageManager.getString("warn.hmmalign_failed"));
+          return;
+        }
       } catch (IOException | InterruptedException e)
       {
         e.printStackTrace();
@@ -131,34 +147,78 @@ public class HMMAlignThread implements Runnable
 
     displayResults(newFrame);
 
-    af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
-            barID);
+    af.setProgressBar("", barID);
 
   }
 
+  /**
+   * Creates temporary files for exporting and importing the data.
+   * 
+   * @throws IOException
+   */
   private void createTemporaryFiles() throws IOException
   {
-    hmmTemp = File.createTempFile("hmm", ".hmm");
-    hmmTemp.deleteOnExit();
-    outTemp = File.createTempFile("output", ".sto");
-    outTemp.deleteOnExit();
+    if (hmmTemp == null)
+    {
+      hmmTemp = File.createTempFile("hmm", ".hmm");
+      hmmTemp.deleteOnExit();
+    }
+    if (outTemp == null)
+    {
+      outTemp = File.createTempFile("output", ".sto");
+      outTemp.deleteOnExit();
+    }
     inputTemp = File.createTempFile("input", ".sto");
     inputTemp.deleteOnExit();
   }
 
-  private void runCommand() throws IOException, InterruptedException
+  /**
+   * Executes the hmmalign command in the command line
+   * 
+   * @return
+   * @throws IOException
+   * @throws InterruptedException
+   */
+  private boolean runCommand() throws IOException, InterruptedException
   {
-    String command = cmds.HMMERFOLDER + cmds.HMMALIGN;
-    if (!hmm.getFileHeader().contains("HMMER3/f"))
+    String binaryPath = getCommandRoot(HMMALIGN);
+    if (binaryPath == null) {
+      return false;
+    }
+    String command = binaryPath + SPACE;
+    // todo parse version from ./hmmerbuild -h
+    String version = Cache.getProperty("HMMER_VERSION");
+    if (!"3.1b2".equals(version))
+    {
+      // command += ALLCOL; // todo obsolete option?
+    }
+    if (args != null)
     {
-      command += cmds.ALLCOL;
+      for (ArgumentI arg : args)
+      {
+        String name = arg.getName();
+        switch (name)
+        {
+        case "Trim Non-Matching Termini":
+          command += "--trim";
+        }
+      }
     }
-    command += cmds.TRIM + " -o" + inputTemp.getAbsolutePath() + cmds.SPACE
-            + hmmTemp.getAbsolutePath() + cmds.SPACE
+    command += " -o " + inputTemp.getAbsolutePath() + SPACE
+            + hmmTemp.getAbsolutePath() + SPACE
             + outTemp.getAbsolutePath();
-    cmds.runCommand(command);
+    return runCommand(command);
   }
 
+  /**
+   * Imports the data from the temporary file to which the output of hmmalign is
+   * directed. this is used for an internal job.
+   * 
+   * @param index
+   *          The index of the 'job' (or region of an alignment).
+   * @throws IOException
+   * @throws InterruptedException
+   */
   private void importData(int index)
           throws IOException, InterruptedException
   {
@@ -166,74 +226,34 @@ public class HMMAlignThread implements Runnable
             DataSourceType.FILE);
     SequenceI[] result = file.getSeqsAsArray();
     AlignmentOrder msaorder = new AlignmentOrder(result);
-    // always recover the order - makes parseResult()'s life easier.
-    jalview.analysis.AlignmentSorter.recoverOrder(result);
-    jalview.analysis.SeqsetUtils.deuniquify(cmds.hash, result);
+    AlignmentSorter.recoverOrder(result);
+    SeqsetUtils.deuniquify(hash, result);
     allOrders.add(msaorder);
     allResults[index] = result;
-
-    /*
-    if (newFrame)
-    {
-      FileLoader loader = new FileLoader();
-      AlignFrame aFrame = new AlignFrame(new Alignment(new SequenceI[1]),
-              AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
-      Desktop.addInternalFrame(aFrame, aFrame.getTitle(),
-              AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
-      aFrame.setTitle(
-              af.getName() + "Aligned to " + hmm.getName() + "'s HMM");
-      af.getViewport().setAlignment(null);
-    
-      aFrame.loadJalviewDataFile(inputTemp.getAbsolutePath(),
-              DataSourceType.FILE, FileFormat.Stockholm, null);
-    
-    
-    
-      Map<Integer, SequenceI> copy = new HashMap<>(
-              hmmSeqs);
-      addSeqs(aFrame, copy);
-      SequenceI seq = aFrame.getViewport().getAlignment()
-              .getSequenceAt(0);
-      seq.getHMM().mapToReferenceAnnotation(aFrame, seq);
-      addSeqs(af, hmmSeqs);
-    }
-    else
-    {
-      af.getViewport().getAlignment().getSequences().clear();
-      af.setIsRecurring(true);
-      af.loadJalviewDataFile(inputTemp.getAbsolutePath(),
-              DataSourceType.FILE, FileFormat.Stockholm, null);
-      af.setIsRecurring(false);
-      addSeqs(af, hmmSeqs);
-    }
-    */
     hmmTemp.delete();
     outTemp.delete();
     inputTemp.delete();
   }
 
-  private void addSeqs(AlignFrame alignFrame, Map<Integer, SequenceI> map)
-  {
-    for (Map.Entry<Integer, SequenceI> entry : map.entrySet())
-    {
-      SequenceI seq = entry.getValue();
-      Integer pos = entry.getKey();
-      cmds.addHMMConsensusSequence(alignFrame, seq, pos);
-    }
-  }
-
+  /**
+   * Gathers the sequences in preparation for the alignment.
+   */
   private void prepareAlignment()
   {
     // hmmSeqs = alignment.getHMMConsensusSequences(true);
     msa = af.gatherSequencesForAlignment();
   }
 
+  /**
+   * Displays the results of all 'jobs'.
+   * 
+   * @param newFrame
+   */
   private void displayResults(boolean newFrame)
   {
     AlignmentOrder[] arrOrders = allOrders
             .toArray(new AlignmentOrder[allOrders.size()]);
-    Object[] newview = msa.getUpdatedView(allResults,
-            arrOrders, '-');
+    Object[] newview = msa.getUpdatedView(allResults, arrOrders, '-');
     SequenceI[] alignment = (SequenceI[]) newview[0];
     HiddenColumns hidden = (HiddenColumns) newview[1];
     Alignment al = new Alignment(alignment);
@@ -249,6 +269,17 @@ public class HMMAlignThread implements Runnable
     }
   }
 
+  /**
+   * Displays the results in a new frame.
+   * 
+   * @param al
+   *          The alignment containing the results.
+   * @param alorders
+   *          The order of the sequences in the alignment on which the jobs were
+   *          run.
+   * @param hidden
+   *          Hidden columns in the previous alignment.
+   */
   private void displayInNewFrame(AlignmentI al,
           List<AlignmentOrder> alorders, HiddenColumns hidden)
   {
@@ -362,6 +393,23 @@ public class HMMAlignThread implements Runnable
     }
   }
 
-  }
+  /**
+   * Runs hmmalign, and waits for the results to be imported before continuing
+   */
+  public void hmmalignWaitTillComplete()
+  {
+    Thread loader = new Thread(this);
+    loader.start();
 
+    while (loader.isAlive())
+    {
+      try
+      {
+        Thread.sleep(500);
+      } catch (Exception ex)
+      {
+      }
+    }
 
+  }
+}