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