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