2262baed476ddc4d463b62951915e9103e25af5b
[jalview.git] / src / jalview / hmmer / HMMBuildThread.java
1 package jalview.hmmer;
2
3 import jalview.bin.Cache;
4 import jalview.datamodel.AlignmentI;
5 import jalview.datamodel.HiddenMarkovModel;
6 import jalview.datamodel.Sequence;
7 import jalview.datamodel.SequenceGroup;
8 import jalview.datamodel.SequenceI;
9 import jalview.gui.AlignFrame;
10 import jalview.gui.AlignViewport;
11 import jalview.gui.JvOptionPane;
12 import jalview.gui.Preferences;
13 import jalview.io.DataSourceType;
14 import jalview.io.FileParse;
15 import jalview.io.HMMFile;
16 import jalview.util.MessageManager;
17 import jalview.ws.params.ArgumentI;
18
19 import java.io.File;
20 import java.io.FileNotFoundException;
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import javax.swing.JOptionPane;
26
27 public class HMMBuildThread implements Runnable
28 {
29   HMMERCommands cmds = new HMMERCommands();
30
31   AlignFrame af;
32
33   AlignViewport viewport;
34
35   boolean multiJob = false;
36
37   AlignmentI alignment;
38
39   SequenceGroup group;
40
41   List<ArgumentI> params;
42
43   boolean forGroup = false;
44
45   File hmmTemp = null;
46
47   File stoTemp = null;
48
49   long barID;
50
51   /**
52    * This is used for validation purposes. Do not use!
53    * 
54    * @param viewport
55    */
56   public HMMBuildThread(AlignmentI alignment)
57   {
58     this.alignment = alignment;
59     forGroup = false;
60   }
61
62   public HMMBuildThread(AlignFrame af, List<ArgumentI> args)
63   {
64     this.af = af;
65     viewport = af.getViewport();
66     params = args;
67   }
68
69   /**
70    * Builds a HMM from an alignment, then imports and adds it to the alignment.
71    */
72   @Override
73   public void run()
74   {
75     barID = System.currentTimeMillis();
76     if (af != null)
77     {
78       af.setProgressBar(MessageManager.getString("status.running_hmmbuild"),
79               barID);
80     }
81     cmds.HMMERFOLDER = Cache.getProperty(Preferences.HMMER_PATH);
82
83     List<SequenceGroup> groups = new ArrayList<>();
84     if (params != null)
85     {
86       for (ArgumentI arg : params)
87       {
88         String name = arg.getName();
89         if (MessageManager.getString("label.hmmbuild_for").equals(name))
90         {
91           String value = arg.getValue();
92           if ("Alignment".equals(value))
93           {
94             alignment = viewport.getAlignment();
95             break;
96           }
97           else if ("All groups and alignment".equals(value))
98           {
99             alignment = viewport.getAlignment();
100             groups.addAll(viewport.getAlignment().getGroups());
101             if (groups.size() > 0)
102             {
103               multiJob = true;
104             }
105             break;
106           }
107           else if ("All groups".equals(value))
108           {
109             alignment = null;
110             groups = viewport.getAlignment().getGroups();
111             if (groups.size() > 0)
112             {
113               multiJob = true;
114             }
115             break;
116           }
117           else if ("Selected group".equals(value))
118           {
119             alignment = null;
120             groups.add(viewport.getSelectionGroup());
121             break;
122           }
123         }
124         else if (MessageManager.getString("label.use_reference")
125                 .equals(name))
126         {
127           if (!af.getViewport().hasReferenceAnnotation())
128           {
129             if (af != null)
130             {
131               af.setProgressBar(
132                       MessageManager.getString("status.running_hmmbuild"),
133                       barID);
134             }
135             JvOptionPane.showInternalMessageDialog(af, MessageManager
136                     .getString("warn.no_reference_annotation"));
137             return;
138           }
139         }
140       }
141     }
142     else if (viewport != null)
143     {
144       alignment = viewport.getAlignment();
145     }
146
147     if (alignment != null)
148     {
149       forGroup = false;
150       runHMMBuild();
151     }
152
153     if (alignment == null)
154     {
155       alignment = viewport.getAlignment();
156     }
157
158     if (groups != null && groups.size() > 0)
159     {
160       for (SequenceGroup grp : groups)
161       {
162         group = grp;
163         forGroup = true;
164         runHMMBuild();
165       }
166     }
167
168     if (af != null)
169     {
170       af.setProgressBar(MessageManager.getString("status.running_hmmbuild"),
171               barID);
172     }
173   }
174
175   private void runHMMBuild()
176   {
177     if (alignment == null && group == null)
178     {
179       JOptionPane.showMessageDialog(af,
180               MessageManager.getString("warn.no_sequence_data"));
181     }
182     try
183     {
184       hmmTemp = File.createTempFile("hmm", ".hmm");
185       hmmTemp.deleteOnExit();
186       stoTemp = File.createTempFile("output", ".sto");
187       stoTemp.deleteOnExit();
188     } catch (IOException e1)
189     {
190       e1.printStackTrace();
191     }
192
193     try
194     {
195       try
196       {
197         SequenceI[] array;
198         List<SequenceI> seqs = null;
199         if (forGroup)
200         {
201           seqs = group.getHMMConsensusSequences(true);
202           if (seqs.size() > 0)
203           {
204             return;
205           }
206           array = group.getSelectionAsNewSequences(alignment);
207         }
208         else
209         {
210           seqs = alignment.getHMMConsensusSequences(true);
211           if (!alignment.isAligned())
212           {
213             alignment.padGaps();
214           }
215           array = alignment.getSequencesArray();
216         }
217
218         cmds.setHmmSeqs(seqs);
219
220         if (array.length < 1)
221         {
222           if (af != null)
223           {
224             JOptionPane.showMessageDialog(af,
225                     MessageManager.getString("warn.no_sequence_data"));
226           }
227           return;
228         }
229         SequenceI[] newArr = new SequenceI[array.length];
230         int index = 0;
231         for (SequenceI seq : array)
232         {
233           newArr[index] = new Sequence(seq);
234           index++;
235         }
236
237         cmds.uniquifySequences(newArr);
238
239         if (forGroup)
240         {
241           cmds.exportData(newArr, stoTemp, null, null, group);
242         }
243         else
244         {
245           cmds.exportData(newArr, stoTemp, null, null, alignment);
246         }
247
248         jalview.analysis.SeqsetUtils.deuniquify(cmds.hash, array);
249
250       } catch (FileNotFoundException e)
251       {
252         // TODO Auto-generated catch block
253         e.printStackTrace();
254
255       }
256       try
257       {
258         boolean ran = runCommand();
259         if (!ran)
260         {
261           return;
262         }
263       } catch (IOException | InterruptedException e)
264       {
265         // TODO Auto-generated catch block
266         e.printStackTrace();
267       }
268       try
269       {
270
271         importData();
272       } catch (IOException | InterruptedException e)
273       {
274         // TODO Auto-generated catch block
275         e.printStackTrace();
276       }
277     } catch (Exception e)
278     {
279       e.printStackTrace();
280     }
281   }
282
283   /**
284    * Executes the hmmbuild command in the command line.
285    * 
286    * @return
287    * @throws IOException
288    * @throws InterruptedException
289    */
290   private boolean runCommand() throws IOException, InterruptedException
291   {
292     File file = new File(cmds.HMMERFOLDER + "/hmmbuild");
293     if (!file.canExecute())
294     {
295       file = new File(cmds.HMMERFOLDER + "/hmmbuild.exe");
296       {
297         if (!file.canExecute())
298         {
299           if (af != null)
300           {
301             JvOptionPane.showInternalMessageDialog(af,
302                     MessageManager.getString("warn.hmmbuild_failed"));
303           }
304           return false;
305         }
306       }
307     }
308     String command = cmds.HMMERFOLDER + cmds.HMMBUILD + cmds.SPACE;
309     String name = null;
310
311     if (params != null)
312     {
313       for (ArgumentI arg : params)
314       {
315         String argName = arg.getName();
316         switch (argName)
317         {
318         case "HMM Name":
319           name = arg.getValue();
320           name = name.trim();
321           break;
322         case "Use Reference Annotation":
323           command += "--hand ";
324           break;
325
326         }
327       }
328     }
329
330     if (forGroup && multiJob)
331     {
332       name = group.getName() + "_HMM";
333     }
334
335     if (name == null || "".equals(name))
336     {
337       if (af != null)
338       {
339         if (af.getTitle().length() < 15)
340         {
341           name = af.getTitle();
342         }
343       }
344       if (name == null || "".equals(name))
345       {
346         name = "Alignment";
347       }
348
349     }
350
351     command += "-n " + name.replace(' ', '_') + cmds.SPACE;
352     if (!alignment.isNucleotide())
353     {
354       command += cmds.FORCEAMINO; // TODO check for rna
355     }
356     else
357     {
358       command += cmds.FORCEDNA;
359     }
360
361     command += hmmTemp.getAbsolutePath() + cmds.SPACE
362             + stoTemp.getAbsolutePath() + cmds.SPACE;
363     return cmds.runCommand(command);
364   }
365
366   /**
367    * Imports the .hmm file produced by hmmbuild.
368    * 
369    * @throws IOException
370    * @throws InterruptedException
371    */
372   private void importData() throws IOException, InterruptedException
373   {
374     HMMFile file = new HMMFile(
375             new FileParse(hmmTemp.getAbsolutePath(), DataSourceType.FILE));
376     SequenceI[] seqs = file.getSeqsAsArray();
377     SequenceI seq = seqs[0];
378     seq.createDatasetSequence();
379     HiddenMarkovModel hmm = file.getHMM();
380     if (group != null)
381     {
382       seq.insertCharAt(0, group.getStartRes(), '-');
383       seq.insertCharAt(group.getEndRes() + 1,
384               alignment.getWidth() - group.getEndRes() - 1, '-');
385       seq.updateHMMMapping();
386       SequenceI topSeq = group.getSequencesInOrder(alignment)[0];
387       int topIndex = alignment.findIndex(topSeq);
388       alignment.insertSequenceAt(topIndex, seq);
389       group.setSeqrep(seq);
390       group.addSequence(seq, false);
391     }
392     else
393     {
394       alignment.insertSequenceAt(0, seq);
395     }
396
397     if (viewport != null)
398     {
399       viewport.alignmentChanged(viewport.getAlignPanel());
400       viewport.getAlignPanel().adjustAnnotationHeight();
401       viewport.updateSequenceIdColours();
402
403       if (viewport.getAlignPanel().alignFrame.getSelectedHMM() == null)
404       {
405         viewport.getAlignPanel().alignFrame.setSelectedHMMSequence(seq);
406       }
407     }
408     hmmTemp.delete();
409     stoTemp.delete();
410   }
411
412   /**
413    * Runs hmmbuild, and waits for the results to be imported before continuing
414    */
415   public void hmmbuildWaitTillComplete()
416   {
417     Thread loader = new Thread(this);
418     loader.start();
419
420     while (loader.isAlive())
421     {
422       try
423       {
424         Thread.sleep(500);
425       } catch (Exception ex)
426       {
427       }
428     }
429   }
430 }