jal-2629 fix for hmmbuild failing due to whitespace in the name
[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   AlignmentI alignment;
36   SequenceGroup group;
37   List<ArgumentI> params;
38
39   boolean multiJob;
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             multiJob = true;
100             break;
101           }
102           else if ("All groups".equals(value))
103           {
104             alignment = null;
105             groups = viewport.getAlignment().getGroups();
106             multiJob = true;
107             break;
108           }
109           else if ("Selected group".equals(value))
110           {
111             alignment = null;
112             groups.add(viewport.getSelectionGroup());
113             break;
114           }
115         }
116         else if (MessageManager.getString("label.use_reference")
117                 .equals(name))
118         {
119           if (!af.getViewport().hasReferenceAnnotation())
120           {
121             if (af != null)
122             {
123               af.setProgressBar(
124                       MessageManager.getString("status.running_hmmbuild"),
125                       barID);
126             }
127             JvOptionPane.showInternalMessageDialog(af, MessageManager
128                     .getString("warn.no_reference_annotation"));
129             return;
130           }
131         }
132       }
133     }
134
135     if (alignment != null)
136     {
137       forGroup = false;
138       runHMMBuild();
139     }
140
141     if (alignment == null)
142     {
143       alignment = viewport.getAlignment();
144     }
145
146     if (groups != null && groups.size() > 0)
147     {
148       for (SequenceGroup grp : groups)
149       {
150         group = grp;
151         forGroup = true;
152         runHMMBuild();
153       }
154     }
155
156
157     if (af != null)
158     {
159       af.setProgressBar(MessageManager.getString("status.running_hmmbuild"),
160               barID);
161     }
162   }
163
164   private void runHMMBuild()
165   {
166     if (alignment == null && group == null)
167       {
168         JOptionPane.showMessageDialog(af,
169               MessageManager.getString("warn.no_sequence_data"));
170       }
171       try
172       {
173         hmmTemp = File.createTempFile("hmm", ".hmm");
174         hmmTemp.deleteOnExit();
175         stoTemp = File.createTempFile("output", ".sto");
176         stoTemp.deleteOnExit();
177       } catch (IOException e1)
178       {
179         e1.printStackTrace();
180       }
181
182     try
183     {
184       try
185       {
186         SequenceI[] array;
187         List<SequenceI> seqs = null;
188         if (forGroup)
189         {
190           seqs = group.getHMMConsensusSequences(true);
191           if (seqs.size() > 0)
192           {
193             return;
194           }
195           array = group.getSelectionAsNewSequences(alignment);
196         }
197         else
198         {
199           seqs = alignment.getHMMConsensusSequences(true);
200           if (!alignment.isAligned())
201           {
202             alignment.padGaps();
203           }
204           array = alignment.getSequencesArray();
205         }
206
207           cmds.setHmmSeqs(seqs);
208
209         if (array.length < 1)
210           {
211           if (af != null)
212           {
213             JOptionPane.showMessageDialog(af,
214                     MessageManager.getString("warn.no_sequence_data"));
215           }
216           return;
217           }
218           SequenceI[] newArr = new SequenceI[array.length];
219           int index = 0;
220           for (SequenceI seq : array)
221           {
222             newArr[index] = new Sequence(seq);
223             index++;
224           }
225
226           cmds.uniquifySequences(newArr);
227           cmds.exportData(newArr, stoTemp, null, null);
228           jalview.analysis.SeqsetUtils.deuniquify(cmds.hash, array);
229
230       } catch (FileNotFoundException e)
231       {
232         // TODO Auto-generated catch block
233         e.printStackTrace();
234
235       }
236       try
237       {
238           boolean ran = runCommand();
239           if (!ran)
240           {
241             return;
242           }
243       } catch (IOException | InterruptedException e)
244       {
245         // TODO Auto-generated catch block
246         e.printStackTrace();
247       }
248       try
249       {
250
251         importData();
252       } catch (IOException | InterruptedException e)
253       {
254         // TODO Auto-generated catch block
255         e.printStackTrace();
256       }
257       } catch (Exception e)
258       {
259         e.printStackTrace();
260     }
261   }
262
263   
264
265   /**
266    * Executes the hmmbuild command in the command line.
267    * 
268    * @return
269    * @throws IOException
270    * @throws InterruptedException
271    */
272   private boolean runCommand() throws IOException, InterruptedException
273   {
274     File file = new File(cmds.HMMERFOLDER + "/hmmbuild");
275     if (!file.canExecute())
276     {
277       file = new File(cmds.HMMERFOLDER + "/hmmbuild.exe");
278       {
279         if (!file.canExecute())
280         {
281           if (af != null)
282           {
283             JvOptionPane.showInternalMessageDialog(af,
284                     MessageManager.getString("warn.hmmbuild_failed"));
285           }
286           return false;
287         }
288       }
289     }
290     String command = cmds.HMMERFOLDER + cmds.HMMBUILD + cmds.SPACE;
291     String name = null;
292
293     if (params != null)
294     {
295       for (ArgumentI arg : params)
296       {
297         String argName = arg.getName();
298         switch (argName)
299         {
300         case "HMM Name":
301           if (!multiJob)
302           {
303             name = arg.getValue();
304             name = name.trim();
305           }
306           break;
307         case "Use Reference Annotation":
308           command += "--hand ";
309           break;
310
311         }
312
313       }
314     }
315
316     if (name == null || "".equals(name))
317     {
318       if (forGroup)
319       {
320         name = group.getName();
321       }
322       else
323       {
324         if (af != null)
325         {
326           name = af.getTitle();
327         }
328         if (name == null || "".equals(name))
329         {
330           name = "Alignment";
331         }
332       }
333     }
334
335
336     command += "-n " + name.replace(' ', '_') + cmds.SPACE;
337     if (!alignment.isNucleotide())
338     {
339       command += cmds.FORCEAMINO; // TODO check for rna
340     }
341     else
342     {
343       command += cmds.FORCEDNA;
344     }
345
346     command += hmmTemp.getAbsolutePath()
347             + cmds.SPACE + stoTemp.getAbsolutePath() + cmds.SPACE;
348     return cmds.runCommand(command);
349   }
350   
351   /**
352    * Imports the .hmm file produced by hmmbuild.
353    * 
354    * @throws IOException
355    * @throws InterruptedException
356    */
357   private void importData() throws IOException, InterruptedException
358   {
359       HMMFile file = new HMMFile(new FileParse(hmmTemp.getAbsolutePath(),
360               DataSourceType.FILE));
361     SequenceI[] seqs = file.getSeqsAsArray();
362     SequenceI seq = seqs[0];
363     seq.createDatasetSequence();
364     HiddenMarkovModel hmm = file.getHMM();
365     if (group != null)
366     {
367       seq.insertCharAt(0, group.getStartRes(), '-');
368       seq.insertCharAt(group.getEndRes() + 1,
369               alignment.getWidth() - group.getEndRes(), '-');
370       seq.updateHMMMapping();
371       SequenceI topSeq = group.getSequencesInOrder(alignment)[0];
372       int topIndex = alignment.findIndex(topSeq);
373       alignment.insertSequenceAt(topIndex, seq);
374       group.setSeqrep(seq);
375       group.addSequence(seq, false);
376     }
377     else
378     {
379       alignment.insertSequenceAt(0, seq);
380     }
381
382     viewport.alignmentChanged(viewport.getAlignPanel());
383     viewport.getAlignPanel().adjustAnnotationHeight();
384     viewport.updateSequenceIdColours();
385
386     if (viewport.getAlignPanel().alignFrame.getSelectedHMM() == null)
387     {
388       viewport.getAlignPanel().alignFrame.setSelectedHMMSequence(seq);
389     }
390     hmmTemp.delete();
391     stoTemp.delete();
392   }
393   
394   /**
395    * Runs hmmbuild, and waits for the results to be imported before continuing
396    */
397   public void hmmbuildWaitTillComplete()
398   {
399     Thread loader = new Thread(this);
400     loader.start();
401
402     while (loader.isAlive())
403     {
404       try
405       {
406         Thread.sleep(500);
407       } catch (Exception ex)
408       {
409       }
410     }
411   }
412 }