d5baedf6947e1db7b071319f85dd90d746dad1bd
[jalview.git] / src / jalview / hmmer / HMMSearchThread.java
1 package jalview.hmmer;
2
3 import jalview.bin.Cache;
4 import jalview.datamodel.Alignment;
5 import jalview.datamodel.AlignmentAnnotation;
6 import jalview.datamodel.AlignmentI;
7 import jalview.datamodel.Annotation;
8 import jalview.datamodel.HiddenMarkovModel;
9 import jalview.datamodel.SequenceI;
10 import jalview.gui.AlignFrame;
11 import jalview.gui.JvOptionPane;
12 import jalview.gui.Preferences;
13 import jalview.io.DataSourceType;
14 import jalview.io.FileParse;
15 import jalview.io.StockholmFile;
16 import jalview.util.MessageManager;
17 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
18 import jalview.ws.params.ArgumentI;
19 import jalview.ws.params.simple.BooleanOption;
20
21 import java.io.BufferedReader;
22 import java.io.File;
23 import java.io.FileReader;
24 import java.io.IOException;
25 import java.io.PrintWriter;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.Scanner;
29
30 import javax.swing.JOptionPane;
31
32 public class HMMSearchThread implements Runnable
33 {
34   /**
35    * feature settings from view that job was associated with
36    */
37   protected FeatureRendererSettings featureSettings = null;
38
39   /**
40    * Object containing frequently used commands.
41    */
42   HMMERCommands cmds = new HMMERCommands();
43
44   AlignFrame af;
45
46   HiddenMarkovModel hmm;
47
48   boolean newFrame, realign = false, trim = false;
49
50   Integer numberOfSequences = null;
51
52   long barID;
53
54   SequenceI hmmSeq;
55
56   List<ArgumentI> params;
57
58   File hmmTemp = null;
59
60   File inputAlignmentTemp = null;
61
62   File inputTableTemp = null;
63
64   File databaseFile = null;
65
66   SequenceI[] seqs;
67
68   /**
69    * Constructor for the HMMSearchThread. If create new frame is set to true, a
70    * new frame will be created.
71    * 
72    * @param af
73    * @param createNewFrame
74    */
75   public HMMSearchThread(AlignFrame af, boolean createNewFrame,
76           List<ArgumentI> args)
77   {
78     this.af = af;
79     newFrame = createNewFrame;
80     featureSettings = af.getFeatureRenderer().getSettings();
81     params = args;
82   }
83
84   /**
85    * Runs the HMMSearchThread: the data on the alignment or group is exported,
86    * then the command is executed in the command line and then the data is
87    * imported and displayed in a new frame (if true).
88    */
89   @Override
90   public void run()
91   {
92     if (af.getSelectedHMM() == null)
93     {
94       JOptionPane.showMessageDialog(af,
95               MessageManager.getString("warn.no_selected_hmm"));
96       return;
97     }
98     else
99     {
100       hmm = af.getSelectedHMM();
101     }
102
103     hmmSeq = af.getSelectedHMMSequence();
104     barID = System.currentTimeMillis();
105     af.setProgressBar(MessageManager.getString("status.running_hmmsearch"),
106             barID);
107     cmds.HMMERFOLDER = Cache.getProperty(Preferences.HMMER_PATH);
108
109     try
110     {
111       createTemporaryFiles();
112     } catch (IOException e2)
113     {
114       e2.printStackTrace();
115     }
116     try
117     {
118       cmds.exportData(null, null, hmm, hmmTemp.getAbsoluteFile(), null);
119     } catch (IOException e1)
120     {
121       e1.printStackTrace();
122     }
123     try
124     {
125       boolean ran = runCommand();
126       if (!ran)
127       {
128         JvOptionPane.showInternalMessageDialog(af,
129                 MessageManager.getString("warn.hmmsearch_failed"));
130         return;
131       }
132     } catch (IOException | InterruptedException e)
133     {
134       e.printStackTrace();
135     }
136     try
137     {
138       importData();
139     } catch (IOException | InterruptedException e)
140     {
141       // TODO Auto-generated catch block
142       e.printStackTrace();
143     }
144
145     af.setProgressBar(MessageManager.getString("status.running_hmmsearch"),
146             barID);
147
148   }
149
150   /**
151    * Creates temporary files for exporting and importing the data.
152    * 
153    * @throws IOException
154    */
155   private void createTemporaryFiles() throws IOException
156   {
157     hmmTemp = File.createTempFile("hmm", ".hmm");
158     hmmTemp.deleteOnExit();
159     inputAlignmentTemp = File.createTempFile("inputAl", ".sto");
160     inputAlignmentTemp.deleteOnExit();
161     inputTableTemp = File.createTempFile("buffer", ".sto");
162     inputTableTemp.deleteOnExit();
163   }
164
165   /**
166    * Executes the hmmsearch command in the command line.
167    * 
168    * @return
169    * @throws IOException
170    * @throws InterruptedException
171    */
172   private boolean runCommand() throws IOException, InterruptedException
173   {
174     Boolean dbFound = false;
175     String dbPath = "";
176     File file = new File(cmds.HMMERFOLDER + "/hmmsearch");
177     if (!file.canExecute())
178     {
179       file = new File(cmds.HMMERFOLDER + "/hmmsearch.exe");
180       {
181         if (!file.canExecute())
182         {
183           return false;
184         }
185       }
186     }
187
188     String command = cmds.HMMERFOLDER + "/hmmsearch -o "
189             + inputTableTemp.getAbsolutePath() + " -A "
190             + inputAlignmentTemp.getAbsolutePath() + cmds.SPACE;
191     if (params != null)
192     {
193       for (ArgumentI arg : params)
194       {
195         String name = arg.getName();
196         switch (name)
197         {
198         case "Number of Results to Return":
199           numberOfSequences = Integer.parseInt(arg.getValue());
200           break;
201         case "Automatically Align Fetched Sequences":
202           if ("Automatically Align Fetched Sequences"
203                   .equals(arg.getValue()))
204           {
205             realign = true;
206           }
207           break;
208         case "Return Accessions":
209           if ("Return Accessions".equals(arg.getValue()))
210           {
211             command += "--acc ";
212           }
213           break;
214         case "Sequence E-value Cutoff":
215           command += "--incE " + arg.getValue() + cmds.SPACE;
216           break;
217         case "Sequence Score Threshold":
218           command += "-incT " + arg.getValue() + cmds.SPACE;
219           break;
220         case "Domain E-value Threshold":
221           command += "--incdomE " + arg.getValue() + cmds.SPACE;
222           break;
223         case "Domain Score Threshold":
224           command += "--incdomT " + arg.getValue() + cmds.SPACE;
225           break;
226         case "Trim Non-Matching Termini":
227           trim = true;
228           break;
229         case "Database":
230           dbFound = true;
231           dbPath = arg.getValue();
232           if (!MessageManager.getString("label.this_alignment")
233                   .equals(dbPath))
234           {
235             databaseFile = new File(dbPath);
236           }
237         }
238
239       }
240     }
241
242     if (dbFound == false || MessageManager.getString("label.this_alignment")
243             .equals(dbPath))
244     {
245       AlignmentI alignment = af.getViewport().getAlignment();
246       AlignmentI copy = new Alignment(alignment);
247       copy.getHMMConsensusSequences(true);
248       StockholmFile stoFile = new StockholmFile(copy);
249       stoFile.setSeqs(copy.getSequencesArray());
250       String alignmentString = stoFile.print();
251       databaseFile = File.createTempFile("database", ".sto");
252       databaseFile.deleteOnExit();
253       PrintWriter writer = new PrintWriter(databaseFile);
254       writer.print(alignmentString);
255       writer.close();
256     }
257
258     command += hmmTemp.getAbsolutePath() + cmds.SPACE
259             + databaseFile.getAbsolutePath();
260     return cmds.runCommand(command);
261   }
262
263   /**
264    * Imports the data from the temporary file to which the output of hmmsearch
265    * is directed.
266    */
267   private void importData() throws IOException, InterruptedException
268   {
269     BufferedReader br = new BufferedReader(
270             new FileReader(inputAlignmentTemp));
271     if (br.readLine() == null)
272     {
273       JOptionPane.showMessageDialog(af,
274               MessageManager.getString("label.no_sequences_found"));
275       return;
276     }
277     StockholmFile file = new StockholmFile(new FileParse(
278             inputAlignmentTemp.getAbsolutePath(), DataSourceType.FILE));
279     seqs = file.getSeqsAsArray();
280
281     readTable();
282
283     SequenceI[] hmmAndSeqs;
284     if (numberOfSequences != null && numberOfSequences < seqs.length)
285     {
286       hmmAndSeqs = new SequenceI[numberOfSequences + 1];
287     }
288     else
289     {
290       hmmAndSeqs = new SequenceI[seqs.length + 1];
291     }
292     hmmAndSeqs[0] = hmmSeq;
293
294     if (numberOfSequences != null && seqs.length > numberOfSequences)
295     {
296       System.arraycopy(seqs, 0, hmmAndSeqs, 1, numberOfSequences);
297     }
298     else
299     {
300       System.arraycopy(seqs, 0, hmmAndSeqs, 1, seqs.length);
301     }
302
303     AlignmentI alignment = new Alignment(hmmAndSeqs);
304     AlignFrame frame = new AlignFrame(alignment, 1, 1);
305     frame.setSelectedHMMSequence(hmmSeq);
306     List<ArgumentI> alignArgs = new ArrayList<>();
307     if (trim)
308     {
309       alignArgs.add(new BooleanOption(
310               MessageManager.getString("label.trim_termini"),
311               MessageManager.getString("label.trim_termini_desc"), true,
312               true, true, null));
313     }
314     HMMAlignThread hmmalign = new HMMAlignThread(frame, true, alignArgs);
315     hmmalign.hmmalignWaitTillComplete();
316     frame = null;
317     hmmTemp.delete();
318     inputAlignmentTemp.delete();
319     inputTableTemp.delete();
320   }
321
322   /**
323    * Runs hmmsearch, and waits for the results to be imported before continuing
324    */
325   public void hmmsearchWaitTillComplete()
326   {
327     Thread loader = new Thread(this);
328     loader.start();
329
330     while (loader.isAlive())
331     {
332       try
333       {
334         Thread.sleep(500);
335       } catch (Exception ex)
336       {
337       }
338     }
339
340   }
341
342   public void readTable() throws IOException
343   {
344     BufferedReader br = new BufferedReader(new FileReader(inputTableTemp));
345     String line = "";
346     while (!line.startsWith("Query:"))
347     {
348       line = br.readLine();
349     }
350     for (int i = 0; i < 5; i++)
351     {
352       line = br.readLine();
353     }
354
355     int index = 0;
356     while (!"  ------ inclusion threshold ------".equals(line)
357             && !"".equals(line))
358     {
359       Scanner scanner = new Scanner(line);
360
361       String str = scanner.next();
362       Annotation[] annots = new Annotation[seqs[index].getLength()];
363       for (Annotation an : annots)
364       {
365         an = new Annotation(Float.parseFloat(str));
366       }
367       AlignmentAnnotation annot = new AlignmentAnnotation("E-value",
368               "Score", annots);
369       annot.setScore(Double.parseDouble(str));
370       annot.setSequenceRef(seqs[index]);
371       seqs[index].addAlignmentAnnotation(annot);
372
373       scanner.close();
374       line = br.readLine();
375       index++;
376     }
377
378     br.close();
379   }
380
381 }