JAL-2629 tidy tests, refactor hmmer node mapping slightly
[jalview.git] / src / jalview / hmmer / HMMBuildThread.java
index 4e3dc2e..c52fb86 100644 (file)
@@ -1,6 +1,6 @@
 package jalview.hmmer;
 
-import jalview.analysis.SeqsetUtils;
+import jalview.api.AlignViewportI;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
@@ -15,7 +15,6 @@ import jalview.util.MessageManager;
 import jalview.ws.params.ArgumentI;
 
 import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
@@ -24,267 +23,231 @@ import javax.swing.JOptionPane;
 
 public class HMMBuildThread extends HmmerCommand implements Runnable
 {
-  AlignViewport viewport;
+  static final String ARG_AMINO = "--amino";
 
-  boolean multiJob = false;
+  static final String ARG_DNA = "--dna";
 
-  AlignmentI alignment;
-
-  SequenceGroup group;
-
-  List<ArgumentI> params;
-
-  boolean forGroup = false;
-
-  File hmmTemp = null;
-
-  File stoTemp = null;
+  static final String ARG_RNA = "--rna";
 
-  long barID;
+  AlignmentI alignment;
 
   /**
-   * This is used for validation purposes. Do not use!
+   * Constructor
    * 
-   * @param viewport
+   * @param alignFrame
+   * @param args
    */
-  public HMMBuildThread(AlignmentI alignment)
-  {
-    this.alignment = alignment;
-    forGroup = false;
-  }
-
-  public HMMBuildThread(AlignFrame af, List<ArgumentI> args)
+  public HMMBuildThread(AlignFrame alignFrame, List<ArgumentI> args)
   {
-    this.af = af;
-    viewport = af.getViewport();
-    params = args;
+    super(alignFrame, args);
   }
 
   /**
-   * Builds a HMM from an alignment, then imports and adds it to the alignment.
+   * Builds a HMM from an alignment (and/or groups), then imports and adds it to
+   * the alignment (and/or groups)
    */
   @Override
   public void run()
   {
-    barID = System.currentTimeMillis();
+    long msgID = System.currentTimeMillis();
     if (af != null)
     {
       af.setProgressBar(MessageManager.getString("status.running_hmmbuild"),
-              barID);
+              msgID);
     }
 
-    List<SequenceGroup> groups = new ArrayList<>();
-    if (params != null)
+    AlignViewportI viewport = af.getViewport();
+    try
     {
-      for (ArgumentI arg : params)
+      if (viewport != null)
+      {
+        alignment = viewport.getAlignment();
+      }
+      List<SequenceGroup> groups = new ArrayList<>();
+      if (params != null)
       {
-        String name = arg.getName();
-        if (MessageManager.getString("label.hmmbuild_for").equals(name))
+        for (ArgumentI arg : params)
         {
-          String value = arg.getValue();
-          if ("Alignment".equals(value))
+          String name = arg.getName();
+          if (MessageManager.getString("label.hmmbuild_for").equals(name))
           {
-            alignment = viewport.getAlignment();
-            break;
-          }
-          else if ("All groups and alignment".equals(value))
-          {
-            alignment = viewport.getAlignment();
-            groups.addAll(viewport.getAlignment().getGroups());
-            if (groups.size() > 0)
+            String value = arg.getValue();
+            if (MessageManager.getString("label.alignment").equals(value))
             {
-              multiJob = true;
+              alignment = viewport.getAlignment();
             }
-            break;
-          }
-          else if ("All groups".equals(value))
-          {
-            alignment = null;
-            groups = viewport.getAlignment().getGroups();
-            if (groups.size() > 0)
+            else if (MessageManager.getString("label.groups_and_alignment")
+                    .equals(value))
             {
-              multiJob = true;
+              alignment = viewport.getAlignment();
+              groups.addAll(viewport.getAlignment().getGroups());
+            }
+            else if (MessageManager.getString("label.groups").equals(value))
+            {
+              alignment = null;
+              groups = viewport.getAlignment().getGroups();
+            }
+            else if ("label.selected_group".equals(value))
+            {
+              alignment = null;
+              groups.add(viewport.getSelectionGroup());
             }
-            break;
-          }
-          else if ("Selected group".equals(value))
-          {
-            alignment = null;
-            groups.add(viewport.getSelectionGroup());
-            break;
           }
-        }
-        else if (MessageManager.getString("label.use_reference")
-                .equals(name))
-        {
-          if (!af.getViewport().hasReferenceAnnotation())
+          else if (MessageManager.getString("label.use_reference")
+                  .equals(name))
           {
-            if (af != null)
+            // todo disable this option if no RF annotation on alignment
+            if (!af.getViewport().hasReferenceAnnotation())
             {
-              af.setProgressBar(
-                      MessageManager.getString("status.running_hmmbuild"),
-                      barID);
+              JvOptionPane.showInternalMessageDialog(af, MessageManager
+                      .getString("warn.no_reference_annotation"));
+              // return;
             }
-            JvOptionPane.showInternalMessageDialog(af, MessageManager
-                    .getString("warn.no_reference_annotation"));
-            return;
           }
         }
       }
-    }
-    else if (viewport != null)
-    {
-      alignment = viewport.getAlignment();
-    }
 
-    if (alignment != null)
-    {
-      forGroup = false;
-      runHMMBuild();
-    }
+      if (alignment != null)
+      {
+        runHMMBuild(null);
+      }
 
-    if (alignment == null)
-    {
-      alignment = viewport.getAlignment();
-    }
+      if (alignment == null)
+      {
+        alignment = viewport.getAlignment();
+      }
 
-    if (groups != null && groups.size() > 0)
-    {
       for (SequenceGroup grp : groups)
       {
-        group = grp;
-        forGroup = true;
-        runHMMBuild();
+        runHMMBuild(grp);
       }
-    }
-
-    if (af != null)
+    } finally
     {
-      af.setProgressBar("", barID);
+      if (af != null)
+      {
+        af.setProgressBar("", msgID);
+      }
     }
   }
 
-  private void runHMMBuild()
+  /**
+   * Runs hmmbuild on the alignment, or on the group if one is specified
+   * 
+   * @param grp
+   */
+  private void runHMMBuild(SequenceGroup group)
   {
     if (alignment == null && group == null)
     {
       JOptionPane.showMessageDialog(af,
               MessageManager.getString("warn.no_sequence_data"));
     }
+    File hmmFile = null;
+    File alignmentFile = null;
     try
     {
-      hmmTemp = File.createTempFile("hmm", ".hmm");
-      hmmTemp.deleteOnExit();
-      stoTemp = File.createTempFile("output", ".sto");
-      stoTemp.deleteOnExit();
-    } catch (IOException e1)
-    {
-      e1.printStackTrace();
-    }
-
-    try
-    {
-      try
+      hmmFile = createTempFile("hmm", ".hmm");
+      alignmentFile = createTempFile("output", ".sto");
+      SequenceI[] array;
+      List<SequenceI> hmmSeqs = null;
+      if (group != null)
       {
-        SequenceI[] array;
-        List<SequenceI> seqs = null;
-        if (forGroup)
+        hmmSeqs = group.getHMMConsensusSequences();
+        array = group.getSelectionAsNewSequences(alignment);
+      }
+      else
+      {
+        hmmSeqs = alignment.getHMMConsensusSequences();
+        // todo pad gaps in an unaligned SequenceGroup as well?
+        if (!alignment.isAligned())
         {
-          seqs = group.getHMMConsensusSequences(true);
-          if (seqs.size() > 0)
-          {
-            return;
-          }
-          array = group.getSelectionAsNewSequences(alignment);
+          alignment.padGaps();
         }
-        else
+        array = alignment.getSequencesArray();
+      }
+
+      if (array.length < 1)
+      {
+        if (af != null)
         {
-          seqs = alignment.getHMMConsensusSequences(true);
-          if (!alignment.isAligned())
-          {
-            alignment.padGaps();
-          }
-          array = alignment.getSequencesArray();
+          JOptionPane.showMessageDialog(af,
+                  MessageManager.getString("warn.no_sequence_data"));
         }
+        return;
+      }
 
-        if (array.length < 1)
+      /*
+       * copy over sequences excluding hmm consensus sequences
+       */
+      SequenceI[] newArr = new SequenceI[array.length - hmmSeqs.size()];
+      int index = 0;
+      for (SequenceI seq : array)
+      {
+        if (seq.isHMMConsensusSequence())
         {
-          if (af != null)
-          {
-            JOptionPane.showMessageDialog(af,
-                    MessageManager.getString("warn.no_sequence_data"));
-          }
-          return;
+          alignment.deleteSequence(seq);
         }
-        SequenceI[] newArr = new SequenceI[array.length];
-        int index = 0;
-        for (SequenceI seq : array)
+        else
         {
           newArr[index] = new Sequence(seq);
           index++;
         }
+      }
 
-        uniquifySequences(newArr);
+      stashSequences(newArr);
 
-        if (forGroup)
-        {
-          exportData(newArr, stoTemp, null, null, group);
-        }
-        else
-        {
-          exportData(newArr, stoTemp, null, null, alignment);
-        }
+      exportStockholm(newArr, alignmentFile,
+              group != null ? group : alignment);
 
-        SeqsetUtils.deuniquify(hash, array);
+      recoverSequences(array);
 
-      } catch (FileNotFoundException e)
+      boolean ran = runCommand(alignmentFile, hmmFile, group);
+      if (!ran)
       {
-        // TODO Auto-generated catch block
-        e.printStackTrace();
-
+        return;
       }
-      try
-      {
-        boolean ran = runCommand();
-        if (!ran)
-        {
-          return;
-        }
-      } catch (IOException | InterruptedException e)
+      importData(hmmFile, group);
+    } catch (Exception e)
+    {
+      e.printStackTrace();
+    } finally
+    {
+      if (hmmFile != null)
       {
-        // TODO Auto-generated catch block
-        e.printStackTrace();
+        hmmFile.delete();
       }
-      try
-      {
-
-        importData();
-      } catch (IOException | InterruptedException e)
+      if (alignmentFile != null)
       {
-        // TODO Auto-generated catch block
-        e.printStackTrace();
+        alignmentFile.delete();
       }
-    } catch (Exception e)
-    {
-      e.printStackTrace();
     }
   }
 
   /**
-   * Executes the hmmbuild command in the command line.
+   * Constructs and executes the hmmbuild command as a separate process
+   * 
+   * @param sequences
+   *          the alignment from which the HMM is built
+   * @param hmm
+   *          the output file to which the HMM is written
+   * @param group
+   *          (optional) group for which the hmm is generated
    * 
    * @return
    * @throws IOException
    * @throws InterruptedException
    */
-  private boolean runCommand() throws IOException, InterruptedException
+  private boolean runCommand(File sequences, File hmm, SequenceGroup group)
+          throws IOException, InterruptedException
   {
-    String binaryPath = getCommandRoot(HMMBUILD);
-    if (binaryPath == null)
+
+    String cmd = getCommandPath(HMMBUILD);
+    if (cmd == null)
     {
       return false;
     }
-    String command = binaryPath + SPACE;
+    List<String> args = new ArrayList<>();
+    args.add(cmd);
     String name = null;
 
     if (params != null)
@@ -299,14 +262,13 @@ public class HMMBuildThread extends HmmerCommand implements Runnable
           name = name.trim();
           break;
         case "Use Reference Annotation":
-          command += "--hand ";
+          args.add("--hand");
           break;
-
         }
       }
     }
 
-    if (forGroup && multiJob)
+    if (group != null)
     {
       name = group.getName() + "_HMM";
     }
@@ -327,31 +289,38 @@ public class HMMBuildThread extends HmmerCommand implements Runnable
 
     }
 
-    command += "-n " + name.replace(' ', '_') + SPACE;
+    args.add("-n");
+    args.add(name.replace(' ', '_'));
     if (!alignment.isNucleotide())
     {
-      command += FORCEAMINO; // TODO check for rna
+      args.add(ARG_AMINO); // TODO check for rna
     }
     else
     {
-      command += FORCEDNA;
+      args.add(ARG_DNA);
     }
 
-    command += hmmTemp.getAbsolutePath() + SPACE + stoTemp.getAbsolutePath()
-            + SPACE;
-    return runCommand(command);
+    args.add(hmm.getAbsolutePath());
+    args.add(sequences.getAbsolutePath());
+
+    return runCommand(args);
   }
 
   /**
-   * Imports the .hmm file produced by hmmbuild.
+   * Imports the .hmm file produced by hmmbuild, and inserts the HMM consensus
+   * sequence (with attached HMM profile) as the first sequence in the alignment
+   * or group for which it was generated
    * 
+   * @param hmmFile
+   * @oparam group (optional) the group for which the hmm was generated
    * @throws IOException
    * @throws InterruptedException
    */
-  private void importData() throws IOException, InterruptedException
+  private void importData(File hmmFile, SequenceGroup group)
+          throws IOException, InterruptedException
   {
     HMMFile file = new HMMFile(
-            new FileParse(hmmTemp.getAbsolutePath(), DataSourceType.FILE));
+            new FileParse(hmmFile.getAbsolutePath(), DataSourceType.FILE));
     SequenceI[] seqs = file.getSeqsAsArray();
     SequenceI seq = seqs[0];
     seq.createDatasetSequence();
@@ -372,6 +341,7 @@ public class HMMBuildThread extends HmmerCommand implements Runnable
       alignment.insertSequenceAt(0, seq);
     }
 
+    AlignViewport viewport = af.getViewport();
     if (viewport != null)
     {
       viewport.alignmentChanged(viewport.getAlignPanel());
@@ -383,8 +353,6 @@ public class HMMBuildThread extends HmmerCommand implements Runnable
         viewport.getAlignPanel().alignFrame.setSelectedHMMSequence(seq);
       }
     }
-    hmmTemp.delete();
-    stoTemp.delete();
   }
 
   /**