JAL-2629 default HMMBuild to alignment if not specified by args
[jalview.git] / src / jalview / hmmer / HMMBuild.java
index b892e5c..6de7029 100644 (file)
@@ -1,28 +1,25 @@
 package jalview.hmmer;
 
 import jalview.api.AlignViewportI;
+import jalview.bin.Cache;
 import jalview.datamodel.Alignment;
-import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AnnotatedCollectionI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.gui.AlignFrame;
-import jalview.gui.AlignViewport;
-import jalview.gui.AlignmentPanel;
 import jalview.gui.JvOptionPane;
 import jalview.io.DataSourceType;
 import jalview.io.FileParse;
 import jalview.io.HMMFile;
+import jalview.util.FileUtils;
 import jalview.util.MessageManager;
-import jalview.workers.InformationThread;
 import jalview.ws.params.ArgumentI;
 
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Hashtable;
-import java.util.Iterator;
 import java.util.List;
 
 /**
@@ -58,6 +55,12 @@ public class HMMBuild extends HmmerCommand
   @Override
   public void run()
   {
+    if (params == null || params.isEmpty())
+    {
+      Cache.log.error("No parameters to HMMBuild!|");
+      return;
+    }
+
     long msgID = System.currentTimeMillis();
     af.setProgressBar(MessageManager.getString("status.running_hmmbuild"),
             msgID);
@@ -65,66 +68,88 @@ public class HMMBuild extends HmmerCommand
     AlignViewportI viewport = af.getViewport();
     try
     {
-      List<AnnotatedCollectionI> runBuildFor = new ArrayList<>();
-      if (params != null)
-      {
-        for (ArgumentI arg : params)
-        {
-          String name = arg.getName();
-          if (MessageManager.getString("label.hmmbuild_for").equals(name))
-          {
-            String value = arg.getValue();
-            if (MessageManager.getString("label.alignment")
-                    .equals(value))
-            {
-              runBuildFor.add(alignment);
-            }
-            else if (MessageManager.getString("label.groups_and_alignment")
-                    .equals(value))
-            {
-              runBuildFor.add(alignment);
-              runBuildFor.addAll(viewport.getAlignment().getGroups());
-            }
-            else if (MessageManager.getString("label.groups").equals(value))
-            {
-              runBuildFor.addAll(viewport.getAlignment().getGroups());
-            }
-            else if (MessageManager.getString("label.selected_group")
-                    .equals(value))
-            {
-              runBuildFor.add(viewport.getSelectionGroup());
-            }
-          }
-          else if (MessageManager.getString("label.use_reference")
-                  .equals(name))
-          {
-            // todo disable this option if no RF annotation on alignment
-            if (!af.getViewport().hasReferenceAnnotation())
-            {
-              JvOptionPane.showInternalMessageDialog(af, MessageManager
-                      .getString("warn.no_reference_annotation"));
-              // return;
-            }
-          }
-        }
-      }
-
       /*
        * run hmmbuild for alignment and/or groups as selected
        */
+      List<AnnotatedCollectionI> runBuildFor = parseParameters(viewport);
+
       for (AnnotatedCollectionI grp : runBuildFor)
       {
         runHMMBuild(grp);
       }
     } finally
     {
-      viewport.updateInformation(af.alignPanel);
-      af.buildColourMenu(); // to enable HMMER colour schemes
       af.setProgressBar("", msgID);
+      viewport.alignmentChanged(af.alignPanel);
+      af.buildColourMenu(); // to enable HMMER colour schemes
     }
   }
 
   /**
+   * Scans the parameters to determine whether to run hmmmbuild for the whole
+   * alignment or specified subgroup(s) or both
+   * 
+   * @param viewport
+   * @return
+   */
+  protected List<AnnotatedCollectionI> parseParameters(
+          AlignViewportI viewport)
+  {
+    List<AnnotatedCollectionI> runBuildFor = new ArrayList<>();
+    boolean foundArg = false;
+
+    for (ArgumentI arg : params)
+    {
+      String name = arg.getName();
+      if (MessageManager.getString("label.hmmbuild_for").equals(name))
+      {
+        foundArg = true;
+        String value = arg.getValue();
+        if (MessageManager.getString("label.alignment").equals(value))
+        {
+          runBuildFor.add(alignment);
+        }
+        else if (MessageManager.getString("label.groups_and_alignment")
+                .equals(value))
+        {
+          runBuildFor.add(alignment);
+          runBuildFor.addAll(viewport.getAlignment().getGroups());
+        }
+        else if (MessageManager.getString("label.groups").equals(value))
+        {
+          runBuildFor.addAll(viewport.getAlignment().getGroups());
+        }
+        else if (MessageManager.getString("label.selected_group")
+                .equals(value))
+        {
+          runBuildFor.add(viewport.getSelectionGroup());
+        }
+      }
+      else if (MessageManager.getString("label.use_reference")
+              .equals(name))
+      {
+        // todo disable this option if no RF annotation on alignment
+        if (!af.getViewport().hasReferenceAnnotation())
+        {
+          JvOptionPane.showInternalMessageDialog(af, MessageManager
+                  .getString("warn.no_reference_annotation"));
+          // return;
+        }
+      }
+    }
+
+    /*
+     * default is to build for the whole alignment
+     */
+    if (!foundArg)
+    {
+      runBuildFor.add(alignment);
+    }
+
+    return runBuildFor;
+  }
+
+  /**
    * Runs hmmbuild on the given sequences (alignment or group)
    * 
    * @param grp
@@ -135,11 +160,8 @@ public class HMMBuild extends HmmerCommand
     File alignmentFile = null;
     try
     {
-      hmmFile = createTempFile("hmm", ".hmm");
-      alignmentFile = createTempFile("output", ".sto");
-      List<SequenceI> seqs = ac.getSequences();
-      List<SequenceI> copy = new ArrayList<>();
-      copy.addAll(seqs);
+      hmmFile = FileUtils.createTempFile("hmm", ".hmm");
+      alignmentFile = FileUtils.createTempFile("output", ".sto");
 
       if (ac instanceof Alignment)
       {
@@ -151,32 +173,20 @@ public class HMMBuild extends HmmerCommand
         }
       }
 
-      /*
-       * copy over sequences, excluding hmm consensus sequences
-       * hmm sequences and their Information annotation are also deleted
-       * in preparation for re-adding them when recalculated
-       */
-      Iterator<SequenceI> it = copy.iterator();
-      while (it.hasNext())
+      deleteHmmSequences(ac);
+
+      List<SequenceI> copy = new ArrayList<>();
+      if (ac instanceof Alignment)
+      {
+        copy.addAll(ac.getSequences());
+      }
+      else
       {
-        SequenceI seq = it.next();
-        if (seq.isHMMConsensusSequence())
+        SequenceI[] sel = ((SequenceGroup) ac)
+                .getSelectionAsNewSequences((AlignmentI) ac.getContext());
+        for (SequenceI seq : sel)
         {
-          // todo leave it to InformationThread to delete annotations?
-          AlignmentAnnotation[] seqAnnotations = seq
-                  .getAnnotation();
-          if (seqAnnotations != null)
-          {
-            for (AlignmentAnnotation ann : seqAnnotations)
-            {
-              if (InformationThread.HMM_CALC_ID.equals(ann.getCalcId()))
-              {
-                alignment.deleteAnnotation(ann);
-              }
-            }
-          }
-          alignment.deleteSequence(seq);
-          it.remove();
+          copy.add(seq);
         }
       }
 
@@ -185,11 +195,13 @@ public class HMMBuild extends HmmerCommand
 
       exportStockholm(copyArray, alignmentFile, ac);
 
-      recoverSequences(sequencesHash, seqs.toArray(new SequenceI[] {}));
+      recoverSequences(sequencesHash, copy.toArray(new SequenceI[] {}));
 
       boolean ran = runCommand(alignmentFile, hmmFile, ac);
       if (!ran)
       {
+        JvOptionPane.showInternalMessageDialog(af, MessageManager
+                .formatMessage("warn.command_failed", "hmmbuild"));
         return;
       }
       importData(hmmFile, ac);
@@ -210,6 +222,33 @@ public class HMMBuild extends HmmerCommand
   }
 
   /**
+   * A helper method that deletes any HMM consensus sequence from the given
+   * collection, and from the parent alignment if <code>ac</code> is a subgroup
+   * 
+   * @param ac
+   */
+  void deleteHmmSequences(AnnotatedCollectionI ac)
+  {
+    List<SequenceI> hmmSeqs = ac.getHmmSequences();
+    for (SequenceI hmmSeq : hmmSeqs)
+    {
+      if (ac instanceof SequenceGroup)
+      {
+        ((SequenceGroup) ac).deleteSequence(hmmSeq, false);
+        AnnotatedCollectionI context = ac.getContext();
+        if (context != null && context instanceof AlignmentI)
+        {
+          ((AlignmentI) context).deleteSequence(hmmSeq);
+        }
+      }
+      else
+      {
+        ((AlignmentI) ac).deleteSequence(hmmSeq);
+      }
+    }
+  }
+
+  /**
    * Constructs and executes the hmmbuild command as a separate process
    * 
    * @param sequencesFile
@@ -237,7 +276,7 @@ public class HMMBuild extends HmmerCommand
      * HMM name (will be given to consensus sequence) is
      * - as specified by an input parameter if set
      * - else group name with _HMM appended (if for a group)
-     * - else align fame title with _HMM appended (if title is not too long)
+     * - else align frame title with _HMM appended (if title is not too long)
      * - else "Alignment_HMM" 
      */
     String name = "";
@@ -287,8 +326,8 @@ public class HMMBuild extends HmmerCommand
       args.add(ARG_DNA);
     }
 
-    args.add(hmmFile.getAbsolutePath());
-    args.add(sequencesFile.getAbsolutePath());
+    args.add(getFilePath(hmmFile));
+    args.add(getFilePath(sequencesFile));
 
     return runCommand(args);
   }
@@ -306,43 +345,38 @@ public class HMMBuild extends HmmerCommand
   private void importData(File hmmFile, AnnotatedCollectionI ac)
           throws IOException
   {
+    if (hmmFile.length() == 0L)
+    {
+      Cache.log.error("Error: hmmbuild produced empty hmm file");
+      return;
+    }
+
     HMMFile file = new HMMFile(
             new FileParse(hmmFile.getAbsolutePath(), DataSourceType.FILE));
-    SequenceI[] seqs = file.getSeqsAsArray();
-    SequenceI hmmSeq = seqs[0];
-    hmmSeq.createDatasetSequence();
+    SequenceI hmmSeq = file.getHMM().getConsensusSequence();
+
+    if (hmmSeq == null)
+    {
+      // hmmbuild failure not detected earlier
+      return;
+    }
+
     if (ac instanceof SequenceGroup)
     {
       SequenceGroup grp = (SequenceGroup) ac;
-      hmmSeq.insertCharAt(0, ac.getStartRes(), '-');
+      char gapChar = alignment.getGapCharacter();
+      hmmSeq.insertCharAt(0, ac.getStartRes(), gapChar);
       hmmSeq.insertCharAt(ac.getEndRes() + 1,
-              alignment.getWidth() - ac.getEndRes() - 1, '-');
-      hmmSeq.updateHMMMapping();
+              alignment.getWidth() - ac.getEndRes() - 1, gapChar);
       SequenceI topSeq = grp.getSequencesInOrder(alignment)[0];
       int topIndex = alignment.findIndex(topSeq);
       alignment.insertSequenceAt(topIndex, hmmSeq);
       ac.setSeqrep(hmmSeq);
       grp.addSequence(hmmSeq, false);
-      grp.setHmmConsensus(hmmSeq);
     }
     else
     {
       alignment.insertSequenceAt(0, hmmSeq);
-      alignment.setHmmConsensus(hmmSeq);
-    }
-
-    AlignViewport viewport = af.getViewport();
-    if (viewport != null)
-    {
-      AlignmentPanel alignPanel = viewport.getAlignPanel();
-      viewport.alignmentChanged(alignPanel);
-      alignPanel.adjustAnnotationHeight();
-      viewport.updateSequenceIdColours();
-
-      if (alignPanel.alignFrame.getSelectedHMM() == null)
-      {
-        alignPanel.alignFrame.setSelectedHMMSequence(hmmSeq);
-      }
     }
   }
 }