d974b49f5c01a1e230d64b4088596cf6f71c103b
[jalview.git] / src / jalview / hmmer / HMMSearchThread.java
1 package jalview.hmmer;
2
3 import jalview.datamodel.Alignment;
4 import jalview.datamodel.AlignmentAnnotation;
5 import jalview.datamodel.AlignmentI;
6 import jalview.datamodel.Annotation;
7 import jalview.datamodel.HiddenMarkovModel;
8 import jalview.datamodel.SequenceI;
9 import jalview.gui.AlignFrame;
10 import jalview.gui.JvOptionPane;
11 import jalview.io.DataSourceType;
12 import jalview.io.FileParse;
13 import jalview.io.StockholmFile;
14 import jalview.util.MessageManager;
15 import jalview.ws.params.ArgumentI;
16 import jalview.ws.params.simple.BooleanOption;
17
18 import java.io.BufferedReader;
19 import java.io.File;
20 import java.io.FileReader;
21 import java.io.IOException;
22 import java.io.PrintWriter;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Scanner;
26
27 import javax.swing.JOptionPane;
28
29 public class HMMSearchThread extends HmmerCommand implements Runnable
30 {
31   static final String HMMSEARCH = "hmmsearch";
32
33   boolean realign = false;
34
35   boolean trim = false;
36
37   int seqsToReturn = Integer.MAX_VALUE;
38
39   SequenceI[] seqs;
40
41   /**
42    * Constructor for the HMMSearchThread
43    * 
44    * @param af
45    */
46   public HMMSearchThread(AlignFrame af, List<ArgumentI> args)
47   {
48     super(af, args);
49   }
50
51   /**
52    * Runs the HMMSearchThread: the data on the alignment or group is exported,
53    * then the command is executed in the command line and then the data is
54    * imported and displayed in a new frame
55    */
56   @Override
57   public void run()
58   {
59     HiddenMarkovModel hmm = af.getSelectedHMM();
60     if (hmm == null)
61     {
62       JOptionPane.showMessageDialog(af,
63               MessageManager.getString("warn.no_selected_hmm"));
64       return;
65     }
66
67     SequenceI hmmSeq = af.getSelectedHMMSequence();
68     long msgId = System.currentTimeMillis();
69     af.setProgressBar(MessageManager.getString("status.running_hmmsearch"),
70             msgId);
71
72     try
73     {
74       File hmmFile = createTempFile("hmm", ".hmm");
75       File hitsAlignmentFile = createTempFile("hitAlignment", ".sto");
76       File searchOutputFile = createTempFile("searchOutput", ".sto");
77
78       exportHmm(hmm, hmmFile.getAbsoluteFile());
79
80       boolean ran = runCommand(searchOutputFile, hitsAlignmentFile, hmmFile);
81       if (!ran)
82       {
83         JvOptionPane.showInternalMessageDialog(af,
84                 MessageManager.getString("warn.hmmsearch_failed"));
85         return;
86       }
87
88       importData(hmmSeq, hitsAlignmentFile, hmmFile, searchOutputFile);
89       // TODO make realignment of search results a step at this level
90       // and make it conditional on this.realign
91     } catch (IOException | InterruptedException e)
92     {
93       e.printStackTrace();
94     }
95     finally
96     {
97       af.setProgressBar("", msgId);
98     }
99   }
100
101   /**
102    * Executes an hmmsearch with the given hmm as input. The database to be
103    * searched is a local file as specified by the 'Database' parameter, or the
104    * current alignment (written to file) if none is specified.
105    * 
106    * @param searchOutputFile
107    * @param hitsAlignmentFile
108    * @param hmmFile
109    * 
110    * @return
111    * @throws IOException
112    */
113   private boolean runCommand(File searchOutputFile, File hitsAlignmentFile,
114           File hmmFile) throws IOException
115   {
116     String command = getCommandPath(HMMSEARCH);
117     if (command == null)
118     {
119       return false;
120     }
121
122     List<String> args = new ArrayList<>();
123     args.add(command);
124     args.add("-o");
125     args.add(searchOutputFile.getAbsolutePath());
126     args.add("-A");
127     args.add(hitsAlignmentFile.getAbsolutePath());
128
129     boolean dbFound = false;
130     String dbPath = "";
131     File databaseFile = null;
132
133     if (params != null)
134     {
135       for (ArgumentI arg : params)
136       {
137         String name = arg.getName();
138         if (MessageManager.getString("label.number_of_results")
139                 .equals(name))
140         {
141           seqsToReturn = Integer.parseInt(arg.getValue());
142         }
143         else if (MessageManager.getString("label.auto_align_seqs")
144                 .equals(name))
145         {
146           realign = true; // TODO: not used
147         }
148         else if (MessageManager.getString("label.use_accessions")
149                 .equals(name))
150         {
151           args.add("--acc");
152         }
153         else if (MessageManager.getString("label.seq_e_value").equals(name))
154         {
155           args.add("--incE");
156           args.add(arg.getValue());
157         }
158         else if (MessageManager.getString("label.seq_score").equals(name))
159         {
160           args.add("-incT");
161           args.add(arg.getValue());
162         }
163         else if (MessageManager.getString("label.dom_e_value_desc")
164                 .equals(name))
165         {
166           args.add("--incdomE");
167           args.add(arg.getValue());
168         }
169         else if (MessageManager.getString("label.dom_score").equals(name))
170         {
171           args.add("--incdomT");
172           args.add(arg.getValue());
173         }
174         else if (MessageManager.getString("label.trim_termini")
175                 .equals(name))
176         {
177           trim = true;
178         }
179         else if (MessageManager.getString("label.database").equals(name))
180         {
181           dbFound = true;
182           dbPath = arg.getValue();
183           if (!MessageManager.getString("label.this_alignment")
184                   .equals(dbPath))
185           {
186             databaseFile = new File(dbPath);
187           }
188         }
189       }
190     }
191
192     if (!dbFound || MessageManager.getString("label.this_alignment")
193             .equals(dbPath))
194     {
195       AlignmentI alignment = af.getViewport().getAlignment();
196       AlignmentI copy = new Alignment(alignment);
197       List<SequenceI> hmms = copy.getHMMConsensusSequences();
198       for (SequenceI seq : hmms)
199       {
200         copy.deleteSequence(seq);
201       }
202       StockholmFile stoFile = new StockholmFile(copy);
203       stoFile.setSeqs(copy.getSequencesArray());
204       String alignmentString = stoFile.print();
205       databaseFile = createTempFile("database", ".sto");
206       PrintWriter writer = new PrintWriter(databaseFile);
207       writer.print(alignmentString);
208       writer.close();
209     }
210
211     args.add(hmmFile.getAbsolutePath());
212     args.add(databaseFile.getAbsolutePath());
213
214     return runCommand(args);
215   }
216
217   /**
218    * Imports the data from the temporary file to which the output of hmmsearch
219    * is directed.
220    * 
221    * @param hmmSeq
222    */
223   private void importData(SequenceI hmmSeq, File inputAlignmentTemp,
224           File hmmTemp, File searchOutputFile)
225           throws IOException, InterruptedException
226   {
227     BufferedReader br = new BufferedReader(
228             new FileReader(inputAlignmentTemp));
229     try
230     {
231       if (br.readLine() == null)
232       {
233         JOptionPane.showMessageDialog(af,
234                 MessageManager.getString("label.no_sequences_found"));
235         return;
236       }
237       StockholmFile file = new StockholmFile(new FileParse(
238               inputAlignmentTemp.getAbsolutePath(), DataSourceType.FILE));
239       seqs = file.getSeqsAsArray();
240
241       readTable(searchOutputFile);
242
243       int seqCount = Math.min(seqs.length, seqsToReturn);
244       SequenceI[] hmmAndSeqs = new SequenceI[seqCount + 1];
245       hmmAndSeqs[0] = hmmSeq;
246       System.arraycopy(seqs, 0, hmmAndSeqs, 1, seqCount);
247
248       AlignmentI alignment = new Alignment(hmmAndSeqs);
249       AlignFrame frame = new AlignFrame(alignment, 1, 1);
250       frame.setSelectedHMMSequence(hmmSeq);
251       List<ArgumentI> alignArgs = new ArrayList<>();
252       if (trim)
253       {
254         alignArgs.add(new BooleanOption(
255                 MessageManager.getString("label.trim_termini"),
256                 MessageManager.getString("label.trim_termini_desc"), true,
257                 true, true, null));
258       }
259       HMMAlignThread hmmalign = new HMMAlignThread(frame, alignArgs);
260       hmmalign.hmmalignWaitTillComplete();
261       frame = null;
262       hmmTemp.delete();
263       inputAlignmentTemp.delete();
264       searchOutputFile.delete();
265     } finally
266     {
267       if (br != null)
268       {
269         br.close();
270       }
271     }
272   }
273
274   /**
275    * Runs hmmsearch, and waits for the results to be imported before continuing
276    */
277   public void hmmsearchWaitTillComplete()
278   {
279     Thread loader = new Thread(this);
280     loader.start();
281
282     while (loader.isAlive())
283     {
284       try
285       {
286         Thread.sleep(500);
287       } catch (Exception ex)
288       {
289       }
290     }
291
292   }
293
294   void readTable(File inputTableTemp) throws IOException
295   {
296     BufferedReader br = new BufferedReader(new FileReader(inputTableTemp));
297     String line = "";
298     while (!line.startsWith("Query:"))
299     {
300       line = br.readLine();
301     }
302     for (int i = 0; i < 5; i++)
303     {
304       line = br.readLine();
305     }
306
307     int index = 0;
308     while (!"  ------ inclusion threshold ------".equals(line)
309             && !"".equals(line))
310     {
311       Scanner scanner = new Scanner(line);
312
313       String str = scanner.next(); // full sequence eValue score
314       float eValue = Float.parseFloat(str);
315       int seqLength = seqs[index].getLength();
316       Annotation[] annots = new Annotation[seqLength];
317       for (int j = 0; j < seqLength; j++)
318       {
319         annots[j] = new Annotation(eValue);
320       }
321       AlignmentAnnotation annot = new AlignmentAnnotation("E-value",
322               "Score", annots);
323       annot.setScore(Double.parseDouble(str));
324       annot.setSequenceRef(seqs[index]);
325       seqs[index].addAlignmentAnnotation(annot);
326
327       scanner.close();
328       line = br.readLine();
329       index++;
330     }
331
332     br.close();
333   }
334
335 }