Updated with latest from mchmmer branch
[jalview.git] / src / jalview / hmmer / HMMSearch.java
diff --git a/src/jalview/hmmer/HMMSearch.java b/src/jalview/hmmer/HMMSearch.java
new file mode 100644 (file)
index 0000000..30299e9
--- /dev/null
@@ -0,0 +1,320 @@
+package jalview.hmmer;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.JvOptionPane;
+import jalview.io.DataSourceType;
+import jalview.io.FileParse;
+import jalview.io.StockholmFile;
+import jalview.util.MessageManager;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.simple.BooleanOption;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+import javax.swing.JOptionPane;
+
+public class HMMSearch extends HmmerCommand
+{
+  static final String HMMSEARCH = "hmmsearch";
+
+  boolean realign = false;
+
+  boolean trim = false;
+
+  int seqsToReturn = Integer.MAX_VALUE;
+
+  SequenceI[] seqs;
+
+  /**
+   * Constructor for the HMMSearchThread
+   * 
+   * @param af
+   */
+  public HMMSearch(AlignFrame af, List<ArgumentI> args)
+  {
+    super(af, args);
+  }
+
+  /**
+   * Runs the HMMSearchThread: 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. Call this method directly to execute
+   * synchronously, or via start() in a new Thread for asynchronously.
+   */
+  @Override
+  public void run()
+  {
+    HiddenMarkovModel hmm = af.getSelectedHMM();
+    if (hmm == null)
+    {
+      JOptionPane.showMessageDialog(af,
+              MessageManager.getString("warn.no_selected_hmm"));
+      return;
+    }
+
+    SequenceI hmmSeq = af.getSelectedHMMSequence();
+    long msgId = System.currentTimeMillis();
+    af.setProgressBar(MessageManager.getString("status.running_hmmsearch"),
+            msgId);
+
+    try
+    {
+      File hmmFile = createTempFile("hmm", ".hmm");
+      File hitsAlignmentFile = createTempFile("hitAlignment", ".sto");
+      File searchOutputFile = createTempFile("searchOutput", ".sto");
+
+      exportHmm(hmm, hmmFile.getAbsoluteFile());
+
+      boolean ran = runCommand(searchOutputFile, hitsAlignmentFile, hmmFile);
+      if (!ran)
+      {
+        JvOptionPane.showInternalMessageDialog(af,
+                MessageManager.getString("warn.hmmsearch_failed"));
+        return;
+      }
+
+      importData(hmmSeq, hitsAlignmentFile, hmmFile, searchOutputFile);
+      // TODO make realignment of search results a step at this level
+      // and make it conditional on this.realign
+    } catch (IOException | InterruptedException e)
+    {
+      e.printStackTrace();
+    }
+    finally
+    {
+      af.setProgressBar("", msgId);
+    }
+  }
+
+  /**
+   * Executes an hmmsearch with the given hmm as input. The database to be
+   * searched is a local file as specified by the 'Database' parameter, or the
+   * current alignment (written to file) if none is specified.
+   * 
+   * @param searchOutputFile
+   * @param hitsAlignmentFile
+   * @param hmmFile
+   * 
+   * @return
+   * @throws IOException
+   */
+  private boolean runCommand(File searchOutputFile, File hitsAlignmentFile,
+          File hmmFile) throws IOException
+  {
+    String command = getCommandPath(HMMSEARCH);
+    if (command == null)
+    {
+      return false;
+    }
+
+    List<String> args = new ArrayList<>();
+    args.add(command);
+    args.add("-o");
+    args.add(searchOutputFile.getAbsolutePath());
+    args.add("-A");
+    args.add(hitsAlignmentFile.getAbsolutePath());
+
+    boolean dbFound = false;
+    String dbPath = "";
+    File databaseFile = null;
+
+    if (params != null)
+    {
+      for (ArgumentI arg : params)
+      {
+        String name = arg.getName();
+        if (MessageManager.getString("label.number_of_results")
+                .equals(name))
+        {
+          seqsToReturn = Integer.parseInt(arg.getValue());
+        }
+        else if (MessageManager.getString("label.auto_align_seqs")
+                .equals(name))
+        {
+          realign = true; // TODO: not used
+        }
+        else if (MessageManager.getString("label.use_accessions")
+                .equals(name))
+        {
+          args.add("--acc");
+        }
+        else if (MessageManager.getString("label.seq_e_value").equals(name))
+        {
+          args.add("--incE");
+          args.add(arg.getValue());
+        }
+        else if (MessageManager.getString("label.seq_score").equals(name))
+        {
+          args.add("-incT");
+          args.add(arg.getValue());
+        }
+        else if (MessageManager.getString("label.dom_e_value_desc")
+                .equals(name))
+        {
+          args.add("--incdomE");
+          args.add(arg.getValue());
+        }
+        else if (MessageManager.getString("label.dom_score").equals(name))
+        {
+          args.add("--incdomT");
+          args.add(arg.getValue());
+        }
+        else if (MessageManager.getString("label.trim_termini")
+                .equals(name))
+        {
+          trim = true;
+        }
+        else if (MessageManager.getString("label.database").equals(name))
+        {
+          dbFound = true;
+          dbPath = arg.getValue();
+          if (!MessageManager.getString("label.this_alignment")
+                  .equals(dbPath))
+          {
+            databaseFile = new File(dbPath);
+          }
+        }
+      }
+    }
+
+    if (!dbFound || MessageManager.getString("label.this_alignment")
+            .equals(dbPath))
+    {
+      /*
+       * no external database specified for search, so
+       * export current alignment as 'database' to search
+       */
+      databaseFile = createTempFile("database", ".sto");
+      AlignmentI al = af.getViewport().getAlignment();
+      AlignmentI copy = new Alignment(al);
+      SequenceI hmms = copy.getHmmConsensus();
+      if (hmms != null)
+      {
+        copy.deleteSequence(hmms);
+      }
+      exportStockholm(copy.getSequencesArray(), databaseFile, null);
+      // StockholmFile stoFile = new StockholmFile(copy);
+      // stoFile.setSeqs(copy.getSequencesArray());
+      // String alignmentString = stoFile.print();
+      // PrintWriter writer = new PrintWriter(databaseFile);
+      // writer.print(alignmentString);
+      // writer.close();
+    }
+
+    args.add(hmmFile.getAbsolutePath());
+    args.add(databaseFile.getAbsolutePath());
+
+    return runCommand(args);
+  }
+
+  /**
+   * Imports the data from the temporary file to which the output of hmmsearch
+   * is directed.
+   * 
+   * @param hmmSeq
+   */
+  private void importData(SequenceI hmmSeq, File inputAlignmentTemp,
+          File hmmTemp, File searchOutputFile)
+          throws IOException, InterruptedException
+  {
+    BufferedReader br = new BufferedReader(
+            new FileReader(inputAlignmentTemp));
+    try
+    {
+      if (br.readLine() == null)
+      {
+        JOptionPane.showMessageDialog(af,
+                MessageManager.getString("label.no_sequences_found"));
+        return;
+      }
+      StockholmFile file = new StockholmFile(new FileParse(
+              inputAlignmentTemp.getAbsolutePath(), DataSourceType.FILE));
+      seqs = file.getSeqsAsArray();
+
+      readTable(searchOutputFile);
+
+      int seqCount = Math.min(seqs.length, seqsToReturn);
+      SequenceI[] hmmAndSeqs = new SequenceI[seqCount + 1];
+      hmmAndSeqs[0] = hmmSeq;
+      System.arraycopy(seqs, 0, hmmAndSeqs, 1, seqCount);
+
+      AlignmentI alignment = new Alignment(hmmAndSeqs);
+      AlignFrame frame = new AlignFrame(alignment, 1, 1);
+      frame.setSelectedHMMSequence(hmmSeq);
+      List<ArgumentI> alignArgs = new ArrayList<>();
+      if (trim)
+      {
+        alignArgs.add(new BooleanOption(
+                MessageManager.getString("label.trim_termini"),
+                MessageManager.getString("label.trim_termini_desc"), true,
+                true, true, null));
+      }
+      HMMAlign hmmalign = new HMMAlign(frame, alignArgs);
+      hmmalign.run();
+      frame = null;
+      hmmTemp.delete();
+      inputAlignmentTemp.delete();
+      searchOutputFile.delete();
+    } finally
+    {
+      if (br != null)
+      {
+        br.close();
+      }
+    }
+  }
+
+  void readTable(File inputTableTemp) throws IOException
+  {
+    BufferedReader br = new BufferedReader(new FileReader(inputTableTemp));
+    String line = "";
+    while (!line.startsWith("Query:"))
+    {
+      line = br.readLine();
+    }
+    for (int i = 0; i < 5; i++)
+    {
+      line = br.readLine();
+    }
+
+    int index = 0;
+    while (!"  ------ inclusion threshold ------".equals(line)
+            && !"".equals(line))
+    {
+      Scanner scanner = new Scanner(line);
+
+      String str = scanner.next(); // full sequence eValue score
+      float eValue = Float.parseFloat(str);
+      int seqLength = seqs[index].getLength();
+      Annotation[] annots = new Annotation[seqLength];
+      for (int j = 0; j < seqLength; j++)
+      {
+        annots[j] = new Annotation(eValue);
+      }
+      AlignmentAnnotation annot = new AlignmentAnnotation("E-value",
+              "Score", annots);
+      annot.setScore(Double.parseDouble(str));
+      annot.setSequenceRef(seqs[index]);
+      seqs[index].addAlignmentAnnotation(annot);
+
+      scanner.close();
+      line = br.readLine();
+      index++;
+    }
+
+    br.close();
+  }
+
+}