Merge branch 'develop' into features/mchmmer
[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> seqs = null;
191         if (forGroup)
192         {
193           seqs = group.getHMMConsensusSequences(true);
194           if (seqs.size() > 0)
195           {
196             return;
197           }
198           array = group.getSelectionAsNewSequences(alignment);
199         }
200         else
201         {
202           seqs = alignment.getHMMConsensusSequences(true);
203           if (!alignment.isAligned())
204           {
205             alignment.padGaps();
206           }
207           array = alignment.getSequencesArray();
208         }
209
210         if (array.length < 1)
211         {
212           if (af != null)
213           {
214             JOptionPane.showMessageDialog(af,
215                     MessageManager.getString("warn.no_sequence_data"));
216           }
217           return;
218         }
219         SequenceI[] newArr = new SequenceI[array.length];
220         int index = 0;
221         for (SequenceI seq : array)
222         {
223           newArr[index] = new Sequence(seq);
224           index++;
225         }
226
227         uniquifySequences(newArr);
228
229         if (forGroup)
230         {
231           exportData(newArr, stoTemp, null, null, group);
232         }
233         else
234         {
235           exportData(newArr, stoTemp, null, null, alignment);
236         }
237
238         SeqsetUtils.deuniquify(hash, array);
239
240       } catch (FileNotFoundException e)
241       {
242         // TODO Auto-generated catch block
243         e.printStackTrace();
244
245       }
246       try
247       {
248         boolean ran = runCommand();
249         if (!ran)
250         {
251           return;
252         }
253       } catch (IOException | InterruptedException e)
254       {
255         // TODO Auto-generated catch block
256         e.printStackTrace();
257       }
258       try
259       {
260
261         importData();
262       } catch (IOException | InterruptedException e)
263       {
264         // TODO Auto-generated catch block
265         e.printStackTrace();
266       }
267     } catch (Exception e)
268     {
269       e.printStackTrace();
270     }
271   }
272
273   /**
274    * Executes the hmmbuild command in the command line.
275    * 
276    * @return
277    * @throws IOException
278    * @throws InterruptedException
279    */
280   private boolean runCommand() throws IOException, InterruptedException
281   {
282     String binaryPath = getCommandRoot(HMMBUILD);
283     if (binaryPath == null)
284     {
285       return false;
286     }
287     String command = binaryPath + SPACE;
288     String name = null;
289
290     if (params != null)
291     {
292       for (ArgumentI arg : params)
293       {
294         String argName = arg.getName();
295         switch (argName)
296         {
297         case "HMM Name":
298           name = arg.getValue();
299           name = name.trim();
300           break;
301         case "Use Reference Annotation":
302           command += "--hand ";
303           break;
304
305         }
306       }
307     }
308
309     if (forGroup && multiJob)
310     {
311       name = group.getName() + "_HMM";
312     }
313
314     if (name == null || "".equals(name))
315     {
316       if (af != null)
317       {
318         if (af.getTitle().length() < 15)
319         {
320           name = af.getTitle();
321         }
322       }
323       if (name == null || "".equals(name))
324       {
325         name = "Alignment";
326       }
327
328     }
329
330     command += "-n " + name.replace(' ', '_') + SPACE;
331     if (!alignment.isNucleotide())
332     {
333       command += FORCEAMINO; // TODO check for rna
334     }
335     else
336     {
337       command += FORCEDNA;
338     }
339
340     command += hmmTemp.getAbsolutePath() + SPACE + stoTemp.getAbsolutePath()
341             + SPACE;
342     return runCommand(command);
343   }
344
345   /**
346    * Imports the .hmm file produced by hmmbuild.
347    * 
348    * @throws IOException
349    * @throws InterruptedException
350    */
351   private void importData() throws IOException, InterruptedException
352   {
353     HMMFile file = new HMMFile(
354             new FileParse(hmmTemp.getAbsolutePath(), DataSourceType.FILE));
355     SequenceI[] seqs = file.getSeqsAsArray();
356     SequenceI seq = seqs[0];
357     seq.createDatasetSequence();
358     if (group != null)
359     {
360       seq.insertCharAt(0, group.getStartRes(), '-');
361       seq.insertCharAt(group.getEndRes() + 1,
362               alignment.getWidth() - group.getEndRes() - 1, '-');
363       seq.updateHMMMapping();
364       SequenceI topSeq = group.getSequencesInOrder(alignment)[0];
365       int topIndex = alignment.findIndex(topSeq);
366       alignment.insertSequenceAt(topIndex, seq);
367       group.setSeqrep(seq);
368       group.addSequence(seq, false);
369     }
370     else
371     {
372       alignment.insertSequenceAt(0, seq);
373     }
374
375     if (viewport != null)
376     {
377       viewport.alignmentChanged(viewport.getAlignPanel());
378       viewport.getAlignPanel().adjustAnnotationHeight();
379       viewport.updateSequenceIdColours();
380
381       if (viewport.getAlignPanel().alignFrame.getSelectedHMM() == null)
382       {
383         viewport.getAlignPanel().alignFrame.setSelectedHMMSequence(seq);
384       }
385     }
386     hmmTemp.delete();
387     stoTemp.delete();
388   }
389
390   /**
391    * Runs hmmbuild, and waits for the results to be imported before continuing
392    */
393   public void hmmbuildWaitTillComplete()
394   {
395     Thread loader = new Thread(this);
396     loader.start();
397
398     while (loader.isAlive())
399     {
400       try
401       {
402         Thread.sleep(500);
403       } catch (Exception ex)
404       {
405       }
406     }
407   }
408 }