e7bc58c31d0ebae85e29caf31f8d14e5537e2a7a
[jalview.git] / src / jalview / hmmer / HMMBuildThread.java
1 package jalview.hmmer;
2
3 import jalview.api.AlignViewportI;
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.IOException;
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import javax.swing.JOptionPane;
23
24 public class HMMBuildThread extends HmmerCommand implements Runnable
25 {
26   static final String ARG_AMINO = "--amino";
27
28   static final String ARG_DNA = "--dna";
29
30   static final String ARG_RNA = "--rna";
31
32   AlignmentI alignment;
33
34   /**
35    * Constructor
36    * 
37    * @param alignFrame
38    * @param args
39    */
40   public HMMBuildThread(AlignFrame alignFrame, List<ArgumentI> args)
41   {
42     super(alignFrame, args);
43   }
44
45   /**
46    * Builds a HMM from an alignment (and/or groups), then imports and adds it to
47    * the alignment (and/or groups)
48    */
49   @Override
50   public void run()
51   {
52     long msgID = System.currentTimeMillis();
53     if (af != null)
54     {
55       af.setProgressBar(MessageManager.getString("status.running_hmmbuild"),
56               msgID);
57     }
58
59     AlignViewportI viewport = af.getViewport();
60     try
61     {
62       List<SequenceGroup> groups = new ArrayList<>();
63       if (params != null)
64       {
65         for (ArgumentI arg : params)
66         {
67           String name = arg.getName();
68           if (MessageManager.getString("label.hmmbuild_for").equals(name))
69           {
70             String value = arg.getValue();
71             if (MessageManager.getString("label.alignment").equals(value))
72             {
73               alignment = viewport.getAlignment();
74             }
75             else if (MessageManager.getString("label.groups_and_alignment")
76                     .equals(value))
77             {
78               alignment = viewport.getAlignment();
79               groups.addAll(viewport.getAlignment().getGroups());
80             }
81             else if (MessageManager.getString("label.groups").equals(value))
82             {
83               alignment = null;
84               groups = viewport.getAlignment().getGroups();
85             }
86             else if ("label.selected_group".equals(value))
87             {
88               alignment = null;
89               groups.add(viewport.getSelectionGroup());
90             }
91           }
92           else if (MessageManager.getString("label.use_reference")
93                   .equals(name))
94           {
95             // todo disable this option if no RF annotation on alignment
96             if (!af.getViewport().hasReferenceAnnotation())
97             {
98               JvOptionPane.showInternalMessageDialog(af, MessageManager
99                       .getString("warn.no_reference_annotation"));
100               // return;
101             }
102           }
103         }
104       }
105       else if (viewport != null)
106       {
107         alignment = viewport.getAlignment();
108       }
109
110       if (alignment != null)
111       {
112         runHMMBuild(null);
113       }
114
115       if (alignment == null)
116       {
117         alignment = viewport.getAlignment();
118       }
119
120       for (SequenceGroup grp : groups)
121       {
122         runHMMBuild(grp);
123       }
124     } finally
125     {
126       if (af != null)
127       {
128         af.setProgressBar("", msgID);
129       }
130     }
131   }
132
133   /**
134    * Runs hmmbuild on the alignment, or on the group if one is specified
135    * 
136    * @param grp
137    */
138   private void runHMMBuild(SequenceGroup group)
139   {
140     if (alignment == null && group == null)
141     {
142       JOptionPane.showMessageDialog(af,
143               MessageManager.getString("warn.no_sequence_data"));
144     }
145     File hmmFile = null;
146     File alignmentFile = null;
147     try
148     {
149       hmmFile = createTempFile("hmm", ".hmm");
150       alignmentFile = createTempFile("output", ".sto");
151       SequenceI[] array;
152       List<SequenceI> hmmSeqs = null;
153       if (group != null)
154       {
155         hmmSeqs = group.getHMMConsensusSequences();
156         array = group.getSelectionAsNewSequences(alignment);
157       }
158       else
159       {
160         hmmSeqs = alignment.getHMMConsensusSequences();
161         // todo pad gaps in an unaligned SequenceGroup as well?
162         if (!alignment.isAligned())
163         {
164           alignment.padGaps();
165         }
166         array = alignment.getSequencesArray();
167       }
168
169       if (array.length < 1)
170       {
171         if (af != null)
172         {
173           JOptionPane.showMessageDialog(af,
174                   MessageManager.getString("warn.no_sequence_data"));
175         }
176         return;
177       }
178
179       /*
180        * copy over sequences excluding hmm consensus sequences
181        */
182       SequenceI[] newArr = new SequenceI[array.length - hmmSeqs.size()];
183       int index = 0;
184       for (SequenceI seq : array)
185       {
186         if (seq.isHMMConsensusSequence())
187         {
188           alignment.deleteSequence(seq);
189         }
190         else
191         {
192           newArr[index] = new Sequence(seq);
193           index++;
194         }
195       }
196
197       stashSequences(newArr);
198
199       exportStockholm(newArr, alignmentFile,
200               group != null ? group : alignment);
201
202       recoverSequences(array);
203
204       boolean ran = runCommand(alignmentFile, hmmFile, group);
205       if (!ran)
206       {
207         return;
208       }
209       importData(hmmFile, group);
210     } catch (Exception e)
211     {
212       e.printStackTrace();
213     } finally
214     {
215       if (hmmFile != null)
216       {
217         hmmFile.delete();
218       }
219       if (alignmentFile != null)
220       {
221         alignmentFile.delete();
222       }
223     }
224   }
225
226   /**
227    * Constructs and executes the hmmbuild command as a separate process
228    * 
229    * @param sequences
230    *          the alignment from which the HMM is built
231    * @param hmm
232    *          the output file to which the HMM is written
233    * @param group
234    *          (optional) group for which the hmm is generated
235    * 
236    * @return
237    * @throws IOException
238    * @throws InterruptedException
239    */
240   private boolean runCommand(File sequences, File hmm, SequenceGroup group)
241           throws IOException, InterruptedException
242   {
243
244     String cmd = getCommandPath(HMMBUILD);
245     if (cmd == null)
246     {
247       return false;
248     }
249     List<String> args = new ArrayList<>();
250     args.add(cmd);
251     String name = null;
252
253     if (params != null)
254     {
255       for (ArgumentI arg : params)
256       {
257         String argName = arg.getName();
258         switch (argName)
259         {
260         case "HMM Name":
261           name = arg.getValue();
262           name = name.trim();
263           break;
264         case "Use Reference Annotation":
265           args.add("--hand");
266           break;
267         }
268       }
269     }
270
271     if (group != null)
272     {
273       name = group.getName() + "_HMM";
274     }
275
276     if (name == null || "".equals(name))
277     {
278       if (af != null)
279       {
280         if (af.getTitle().length() < 15)
281         {
282           name = af.getTitle();
283         }
284       }
285       if (name == null || "".equals(name))
286       {
287         name = "Alignment";
288       }
289
290     }
291
292     args.add("-n");
293     args.add(name.replace(' ', '_'));
294     if (!alignment.isNucleotide())
295     {
296       args.add(ARG_AMINO); // TODO check for rna
297     }
298     else
299     {
300       args.add(ARG_DNA);
301     }
302
303     args.add(hmm.getAbsolutePath());
304     args.add(sequences.getAbsolutePath());
305
306     return runCommand(args);
307   }
308
309   /**
310    * Imports the .hmm file produced by hmmbuild, and inserts the HMM consensus
311    * sequence (with attached HMM profile) as the first sequence in the alignment
312    * or group for which it was generated
313    * 
314    * @param hmmFile
315    * @oparam group (optional) the group for which the hmm was generated
316    * @throws IOException
317    * @throws InterruptedException
318    */
319   private void importData(File hmmFile, SequenceGroup group)
320           throws IOException, InterruptedException
321   {
322     HMMFile file = new HMMFile(
323             new FileParse(hmmFile.getAbsolutePath(), DataSourceType.FILE));
324     SequenceI[] seqs = file.getSeqsAsArray();
325     SequenceI seq = seqs[0];
326     seq.createDatasetSequence();
327     if (group != null)
328     {
329       seq.insertCharAt(0, group.getStartRes(), '-');
330       seq.insertCharAt(group.getEndRes() + 1,
331               alignment.getWidth() - group.getEndRes() - 1, '-');
332       seq.updateHMMMapping();
333       SequenceI topSeq = group.getSequencesInOrder(alignment)[0];
334       int topIndex = alignment.findIndex(topSeq);
335       alignment.insertSequenceAt(topIndex, seq);
336       group.setSeqrep(seq);
337       group.addSequence(seq, false);
338     }
339     else
340     {
341       alignment.insertSequenceAt(0, seq);
342     }
343
344     AlignViewport viewport = af.getViewport();
345     if (viewport != null)
346     {
347       viewport.alignmentChanged(viewport.getAlignPanel());
348       viewport.getAlignPanel().adjustAnnotationHeight();
349       viewport.updateSequenceIdColours();
350
351       if (viewport.getAlignPanel().alignFrame.getSelectedHMM() == null)
352       {
353         viewport.getAlignPanel().alignFrame.setSelectedHMMSequence(seq);
354       }
355     }
356   }
357
358   /**
359    * Runs hmmbuild, and waits for the results to be imported before continuing
360    */
361   public void hmmbuildWaitTillComplete()
362   {
363     Thread loader = new Thread(this);
364     loader.start();
365
366     while (loader.isAlive())
367     {
368       try
369       {
370         Thread.sleep(500);
371       } catch (Exception ex)
372       {
373       }
374     }
375   }
376 }