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