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