JAL-2629 tidy tests, refactor hmmer node mapping slightly
[jalview.git] / src / jalview / hmmer / HMMAlignThread.java
index 532271b..fdc1c1c 100644 (file)
@@ -1,6 +1,6 @@
 package jalview.hmmer;
 
-import jalview.bin.Cache;
+import jalview.analysis.AlignmentSorter;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
@@ -11,7 +11,6 @@ import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
 import jalview.gui.Desktop;
 import jalview.gui.JvOptionPane;
-import jalview.gui.Preferences;
 import jalview.gui.SplitFrame;
 import jalview.io.DataSourceType;
 import jalview.io.StockholmFile;
@@ -23,25 +22,20 @@ 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";
 
-  /**
+  static final String ARG_TRIM = "--trim";
+
+  /*
    * feature settings from view that job was associated with
    */
   protected FeatureRendererSettings featureSettings = null;
 
-  /**
-   * Object containing frequently used commands.
-   */
-  HMMERCommands cmds = new HMMERCommands();
-
-  AlignFrame af;
-
   AlignmentI alignment;
 
   AlignmentI dataset;
@@ -52,43 +46,23 @@ public class HMMAlignThread implements Runnable
 
   HiddenMarkovModel hmm;
 
-  List<ArgumentI> args;
-
-  boolean newFrame;
-
-  long barID;
-
-  Map<Integer, SequenceI> hmmSeqs;
-
-  File hmmTemp = null;
-
-  File outTemp = null;
-
-  File inputTemp = null;
-
-  List<AlignmentOrder> allOrders;
-
   SequenceI[][] allResults;
 
   /**
-   * Constructor for the HMMAlignThread. If create new frame is set to true, a
-   * new frame will be created.
+   * Constructor for the HMMAlignThread
    * 
    * @param af
-   * @param createNewFrame
+   * @param args
    */
-  public HMMAlignThread(AlignFrame af, boolean createNewFrame,
-          List<ArgumentI> args)
+  public HMMAlignThread(AlignFrame af, List<ArgumentI> args)
   {
-    this.af = af;
+    super(af, args);
     alignment = af.getViewport().getAlignment();
     if (alignment.getDataset() != null)
     {
       dataset = alignment.getDataset();
     }
-    newFrame = createNewFrame;
     featureSettings = af.getFeatureRenderer().getSettings();
-    this.args = args;
   }
 
   /**
@@ -100,156 +74,125 @@ public class HMMAlignThread implements Runnable
   @Override
   public void run()
   {
-
     hmm = af.getSelectedHMM();
+    if (hmm == null)
+    {
+      System.err.println("Can't run hmmalign as no HMM profile selected");
+      return;
+    }
 
-    barID = System.currentTimeMillis();
+    long msgId = System.currentTimeMillis();
     af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
-            barID);
-    cmds.HMMERFOLDER = Cache.getProperty(Preferences.HMMER_PATH);
-      prepareAlignment();
-      SequenceI[][] subAlignments = msa.getVisibleContigs('-');
-      allOrders = new ArrayList<>();
-      allResults = new SequenceI[subAlignments.length][];
-      int job = 0;
-      for (SequenceI[] seqs : subAlignments)
+            msgId);
+    prepareAlignment();
+    SequenceI[][] subAlignments = msa.getVisibleContigs('-');
+
+    List<AlignmentOrder> allOrders = new ArrayList<>();
+    allResults = new SequenceI[subAlignments.length][];
+    int job = 0;
+    for (SequenceI[] seqs : subAlignments)
+    {
+      stashSequences(seqs);
+      try
       {
-        cmds.uniquifySequences(seqs);
-        try
-        {
-          createTemporaryFiles();
-        } catch (IOException e2)
-        {
-          e2.printStackTrace();
-        }
-        try
-        {
-          cmds.exportData(seqs, outTemp.getAbsoluteFile(), hmm,
-                  hmmTemp.getAbsoluteFile());
-        } catch (IOException e1)
-        {
-          e1.printStackTrace();
-        }
-        try
-        {
-          boolean ran = runCommand();
-          if (!ran)
-          {
-            JvOptionPane.showInternalMessageDialog(af,
-                    MessageManager.getString("warn.hmmalign_failed"));
-            return;
-          }
-        } catch (IOException | InterruptedException e)
-        {
-          e.printStackTrace();
-        }
-        try
-        {
-          importData(job);
-        } catch (IOException | InterruptedException e)
-        {
-          // TODO Auto-generated catch block
-          e.printStackTrace();
-        }
-        job++;
-      }
+        File modelFile = createTempFile("hmm", ".hmm");
+        File alignmentFile = createTempFile("output", ".sto");
+        File resultFile = createTempFile("input", ".sto");
 
+        exportStockholm(seqs, alignmentFile.getAbsoluteFile(), null);
+        exportHmm(hmm, modelFile.getAbsoluteFile());
 
-    displayResults(newFrame);
+        boolean ran = runCommand(modelFile, alignmentFile, resultFile);
+        if (!ran)
+        {
+          JvOptionPane.showInternalMessageDialog(af,
+                  MessageManager.getString("warn.hmmalign_failed"));
+          return;
+        }
 
-    af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
-            barID);
+        SequenceI[] result = importData(resultFile, allOrders);
+        allResults[job] = result;
+        modelFile.delete();
+        alignmentFile.delete();
+        resultFile.delete();
+      } catch (IOException e)
+      {
+        e.printStackTrace();
+      }
+      job++;
+    }
 
-  }
+    displayResults(allOrders);
 
-  /**
-   * Creates temporary files for exporting and importing the data.
-   * 
-   * @throws IOException
-   */
-  private void createTemporaryFiles() throws IOException
-  {
-    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();
+    af.setProgressBar("", msgId);
   }
 
   /**
-   * Executes the hmmalign command in the command line.
+   * Executes the hmmalign command and returns true if successful, false if an
+   * error is detected
    * 
+   * @param modelFile
+   *          the HMM to align to
+   * @param alignmentFile
+   *          the sequences to align
+   * @param resultFile
+   *          the file to hold the results of alignment
    * @return
    * @throws IOException
-   * @throws InterruptedException
    */
-  private boolean runCommand() throws IOException, InterruptedException
+  private boolean runCommand(File modelFile, File alignmentFile,
+          File resultFile)
+          throws IOException
   {
-    File file = new File(cmds.HMMERFOLDER + "/hmmalign");
-    if (!file.canExecute())
-    {
-      file = new File(cmds.HMMERFOLDER + "/hmmalign.exe");
-      {
-        if (!file.canExecute())
-        {
-          return false;
-        }
-      }
-    }
-    String command = cmds.HMMERFOLDER + cmds.HMMALIGN;
-    String version = Cache.getProperty("HMMER_VERSION");
-    if (!"3.1b2".equals(version))
+    String command = getCommandPath(HMMALIGN);
+    if (command == null)
     {
-      command += cmds.ALLCOL;
+      return false;
     }
-    if (args != null)
+    List<String> args = new ArrayList<>();
+    args.add(command);
+
+    if (params != null)
     {
-      for (ArgumentI arg : args)
+      for (ArgumentI arg : params)
       {
         String name = arg.getName();
-        switch (name)
+        if (MessageManager.getString("label.trim_termini").equals(name))
         {
-        case "Trim Non-Matching Termini":
-          command += "--trim";
+          args.add(ARG_TRIM);
         }
       }
     }
-    command += " -o " + inputTemp.getAbsolutePath() + cmds.SPACE
-            + hmmTemp.getAbsolutePath() + cmds.SPACE
-            + outTemp.getAbsolutePath();
-    return cmds.runCommand(command);
+    args.add("-o");
+    args.add(resultFile.getAbsolutePath());
+    args.add(modelFile.getAbsolutePath());
+    args.add(alignmentFile.getAbsolutePath());
+    
+    return runCommand(args);
   }
 
   /**
-   * Imports the data from the temporary file to which the output of hmmalign is
-   * directed. this is used for an internal job.
+   * Imports the data from the file holding the output of hmmalign
+   * 
+   * @param resultFile
+   * @param allOrders
+   *          a list of alignment orders to add to
    * 
-   * @param index
-   *          The index of the 'job' (or region of an alignment).
+   * @return
    * @throws IOException
-   * @throws InterruptedException
    */
-  private void importData(int index)
-          throws IOException, InterruptedException
+  private SequenceI[] importData(File resultFile,
+          List<AlignmentOrder> allOrders) throws IOException
   {
-    StockholmFile file = new StockholmFile(inputTemp.getAbsolutePath(),
+    StockholmFile file = new StockholmFile(resultFile.getAbsolutePath(),
             DataSourceType.FILE);
     SequenceI[] result = file.getSeqsAsArray();
     AlignmentOrder msaorder = new AlignmentOrder(result);
-    jalview.analysis.AlignmentSorter.recoverOrder(result);
-    jalview.analysis.SeqsetUtils.deuniquify(cmds.hash, result);
+    AlignmentSorter.recoverOrder(result);
+    recoverSequences(result);
     allOrders.add(msaorder);
-    allResults[index] = result;
-    hmmTemp.delete();
-    outTemp.delete();
-    inputTemp.delete();
+
+    return result;
   }
 
   /**
@@ -257,60 +200,52 @@ public class HMMAlignThread implements Runnable
    */
   private void prepareAlignment()
   {
-    // hmmSeqs = alignment.getHMMConsensusSequences(true);
     msa = af.gatherSequencesForAlignment();
   }
 
   /**
-   * Displays the results of all 'jobs'.
+   * Displays the results of all 'jobs' in a new frame
    * 
-   * @param newFrame
+   * @param allOrders
    */
-  private void displayResults(boolean newFrame)
+  private void displayResults(List<AlignmentOrder> allOrders)
   {
     AlignmentOrder[] arrOrders = allOrders
             .toArray(new AlignmentOrder[allOrders.size()]);
-    Object[] newview = msa.getUpdatedView(allResults,
-            arrOrders, '-');
-    SequenceI[] alignment = (SequenceI[]) newview[0];
+    Object[] newview = msa.getUpdatedView(allResults, arrOrders, '-');
+    SequenceI[] seqs = (SequenceI[]) newview[0];
     HiddenColumns hidden = (HiddenColumns) newview[1];
-    Alignment al = new Alignment(alignment);
+    Alignment al = new Alignment(seqs);
     al.setProperty("Alignment Program", "hmmalign");
     if (dataset != null)
     {
       al.setDataset(dataset);
     }
 
-    if (newFrame)
-    {
-      displayInNewFrame(al, allOrders, hidden);
-    }
+    displayInNewFrame(al, allOrders, hidden);
   }
 
   /**
-   * Displays the results in a new frame.
+   * Displays the results in a new frame
    * 
    * @param al
-   *          The alignment containing the results.
+   *          The alignment containing the results
    * @param alorders
    *          The order of the sequences in the alignment on which the jobs were
-   *          run.
+   *          run
    * @param hidden
-   *          Hidden columns in the previous alignment.
+   *          Hidden columns in the previous alignment
    */
   private void displayInNewFrame(AlignmentI al,
           List<AlignmentOrder> alorders, HiddenColumns hidden)
   {
-    AlignFrame af = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH,
+    AlignFrame alignFrame = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH,
             AlignFrame.DEFAULT_HEIGHT);
 
     // initialise with same renderer settings as in parent alignframe.
-    af.getFeatureRenderer().transferSettings(this.featureSettings);
+    alignFrame.getFeatureRenderer().transferSettings(this.featureSettings);
 
-    if (allOrders.size() > 0)
-    {
-      addSortByMenuItems(af, allOrders);
-    }
+    addSortByMenuItems(alignFrame, alorders);
 
     // TODO: refactor retrieve and show as new splitFrame as Desktop method
 
@@ -337,14 +272,14 @@ public class HMMAlignThread implements Runnable
       copyComplement.alignAs(al);
       if (copyComplement.getHeight() > 0)
       {
-        af.setTitle(this.af.getTitle());
+        alignFrame.setTitle(this.af.getTitle());
         AlignFrame af2 = new AlignFrame(copyComplement,
                 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
         af2.setTitle(complementTitle);
         String linkedTitle = MessageManager
                 .getString("label.linked_view_title");
         JInternalFrame splitFrame = new SplitFrame(
-                al.isNucleotide() ? af : af2, al.isNucleotide() ? af2 : af);
+                al.isNucleotide() ? alignFrame : af2, al.isNucleotide() ? af2 : alignFrame);
         Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1);
         return;
       }
@@ -353,23 +288,23 @@ public class HMMAlignThread implements Runnable
     /*
      * Not from SplitFrame, or failed to created a complementary alignment
      */
-    Desktop.addInternalFrame(af, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
+    Desktop.addInternalFrame(alignFrame, alignFrame.getTitle(), AlignFrame.DEFAULT_WIDTH,
             AlignFrame.DEFAULT_HEIGHT);
   }
 
   /**
-   * Add sort order options to the AlignFrame menus.
+   * Adds sort order options to the AlignFrame menus
    * 
-   * @param af
+   * @param alignFrame
    * @param alorders
    */
-  protected void addSortByMenuItems(AlignFrame af,
+  protected void addSortByMenuItems(AlignFrame alignFrame,
           List<AlignmentOrder> alorders)
   {
     // update orders
     if (alorders.size() == 1)
     {
-      af.addSortByOrderMenuItem("hmmalign" + " Ordering", alorders.get(0));
+      alignFrame.addSortByOrderMenuItem("hmmalign" + " Ordering", alorders.get(0));
     }
     else
     {
@@ -405,7 +340,7 @@ public class HMMAlignThread implements Runnable
       }
       for (int i = 0, l = alorders.size(); i < l; i++)
       {
-        af.addSortByOrderMenuItem("hmmalign" + (names.get(i)) + " Ordering",
+        alignFrame.addSortByOrderMenuItem("hmmalign" + (names.get(i)) + " Ordering",
                 alorders.get(i));
       }
     }
@@ -430,6 +365,4 @@ public class HMMAlignThread implements Runnable
     }
 
   }
-  }
-
-
+}