49fc49dcbd09ec420cb3be452859012ecd830c36
[jalview.git] / src / jalview / hmmer / HMMAlignThread.java
1 package jalview.hmmer;
2
3 import jalview.bin.Cache;
4 import jalview.datamodel.Alignment;
5 import jalview.datamodel.AlignmentI;
6 import jalview.datamodel.AlignmentOrder;
7 import jalview.datamodel.AlignmentView;
8 import jalview.datamodel.HiddenColumns;
9 import jalview.datamodel.HiddenMarkovModel;
10 import jalview.datamodel.SequenceI;
11 import jalview.gui.AlignFrame;
12 import jalview.gui.Desktop;
13 import jalview.gui.Preferences;
14 import jalview.gui.SplitFrame;
15 import jalview.io.DataSourceType;
16 import jalview.io.StockholmFile;
17 import jalview.util.MessageManager;
18 import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
19
20 import java.io.File;
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.Map;
25
26 import javax.swing.JInternalFrame;
27 import javax.swing.JOptionPane;
28
29 public class HMMAlignThread implements Runnable
30 {
31
32   /**
33    * feature settings from view that job was associated with
34    */
35   protected FeatureRendererSettings featureSettings = null;
36
37   HMMERCommands cmds = new HMMERCommands();
38
39   AlignFrame af;
40
41   AlignmentI alignment;
42
43   AlignmentI dataset;
44
45   List<AlignmentOrder> orders;
46
47   AlignmentView msa;
48
49   HiddenMarkovModel hmm;
50
51   boolean newFrame;
52
53   long barID;
54
55   Map<Integer, SequenceI> hmmSeqs;
56
57   File hmmTemp = null;
58
59   File outTemp = null;
60
61   File inputTemp = null;
62
63   List<AlignmentOrder> allOrders;
64
65   SequenceI[][] allResults;
66
67   public HMMAlignThread(AlignFrame af, boolean createNewFrame)
68   {
69     this.af = af;
70     alignment = af.getViewport().getAlignment();
71     if (alignment.getDataset() != null)
72     {
73       dataset = alignment.getDataset();
74     }
75     newFrame = createNewFrame;
76     featureSettings = af.getFeatureRenderer().getSettings();
77   }
78
79   @Override
80   public void run()
81   {
82     if (af.getViewport().getSelectedHMM() == null)
83     {
84       JOptionPane.showMessageDialog(af,
85               MessageManager.getString("warn.no_selected_hmm"));
86       return;
87     }
88     else
89     {
90       hmm = af.getViewport().getSelectedHMM();
91     }
92     barID = System.currentTimeMillis();
93     af.setProgressBar(MessageManager.getString("status.running_hmmbuild"),
94             barID);
95     cmds.HMMERFOLDER = Cache.getProperty(Preferences.HMMER_PATH);
96
97     // if (!alignment.isAligned())
98     // {
99     // alignment.padGaps();
100     // }
101     prepareAlignment();
102     SequenceI[][] subAlignments = msa.getVisibleContigs('-');
103     allOrders = new ArrayList<>();
104     allResults = new SequenceI[subAlignments.length][];
105     int job = 0;
106     for (SequenceI[] seqs : subAlignments)
107     {
108       cmds.uniquifySequences(seqs);
109       try
110       {
111         createTemporaryFiles();
112       } catch (IOException e2)
113       {
114         e2.printStackTrace();
115       }
116       try
117       {
118         cmds.exportData(seqs, outTemp.getAbsoluteFile(), hmm,
119                 hmmTemp.getAbsoluteFile());
120       } catch (IOException e1)
121       {
122         e1.printStackTrace();
123       }
124       try
125       {
126         runCommand();
127       } catch (IOException | InterruptedException e)
128       {
129         e.printStackTrace();
130       }
131       try
132       {
133         importData(job);
134       } catch (IOException | InterruptedException e)
135       {
136         // TODO Auto-generated catch block
137         e.printStackTrace();
138       }
139       job++;
140     }
141
142     displayResults(newFrame);
143
144     af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
145             barID);
146
147   }
148
149   private void createTemporaryFiles() throws IOException
150   {
151     hmmTemp = File.createTempFile("hmm", ".hmm");
152     hmmTemp.deleteOnExit();
153     outTemp = File.createTempFile("output", ".sto");
154     outTemp.deleteOnExit();
155     inputTemp = File.createTempFile("input", ".sto");
156     inputTemp.deleteOnExit();
157   }
158
159   private void runCommand() throws IOException, InterruptedException
160   {
161     String command = cmds.HMMERFOLDER + cmds.HMMALIGN;
162     if (!hmm.getFileHeader().contains("HMMER3/f"))
163     {
164       command += cmds.ALLCOL;
165     }
166     command += cmds.TRIM + " -o" + inputTemp.getAbsolutePath() + cmds.SPACE
167             + hmmTemp.getAbsolutePath() + cmds.SPACE
168             + outTemp.getAbsolutePath();
169     cmds.runCommand(command);
170   }
171
172   private void importData(int index)
173           throws IOException, InterruptedException
174   {
175     StockholmFile file = new StockholmFile(inputTemp.getAbsolutePath(),
176             DataSourceType.FILE);
177     SequenceI[] result = file.getSeqsAsArray();
178     AlignmentOrder msaorder = new AlignmentOrder(result);
179     // always recover the order - makes parseResult()'s life easier.
180     jalview.analysis.AlignmentSorter.recoverOrder(result);
181     jalview.analysis.SeqsetUtils.deuniquify(cmds.hash, result);
182     allOrders.add(msaorder);
183     allResults[index] = result;
184
185     /*
186     if (newFrame)
187     {
188       FileLoader loader = new FileLoader();
189       AlignFrame aFrame = new AlignFrame(new Alignment(new SequenceI[1]),
190               AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
191       Desktop.addInternalFrame(aFrame, aFrame.getTitle(),
192               AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
193       aFrame.setTitle(
194               af.getName() + "Aligned to " + hmm.getName() + "'s HMM");
195       af.getViewport().setAlignment(null);
196     
197       aFrame.loadJalviewDataFile(inputTemp.getAbsolutePath(),
198               DataSourceType.FILE, FileFormat.Stockholm, null);
199     
200     
201     
202       Map<Integer, SequenceI> copy = new HashMap<>(
203               hmmSeqs);
204       addSeqs(aFrame, copy);
205       SequenceI seq = aFrame.getViewport().getAlignment()
206               .getSequenceAt(0);
207       seq.getHMM().mapToReferenceAnnotation(aFrame, seq);
208       addSeqs(af, hmmSeqs);
209     }
210     else
211     {
212       af.getViewport().getAlignment().getSequences().clear();
213       af.setIsRecurring(true);
214       af.loadJalviewDataFile(inputTemp.getAbsolutePath(),
215               DataSourceType.FILE, FileFormat.Stockholm, null);
216       af.setIsRecurring(false);
217       addSeqs(af, hmmSeqs);
218     }
219     */
220     hmmTemp.delete();
221     outTemp.delete();
222     inputTemp.delete();
223   }
224
225   private void prepareAlignment()
226   {
227     // hmmSeqs = alignment.getHMMConsensusSequences(true);
228     msa = af.gatherSequencesForAlignment();
229   }
230
231   private void displayResults(boolean newFrame)
232   {
233     AlignmentOrder[] arrOrders = allOrders
234             .toArray(new AlignmentOrder[allOrders.size()]);
235     Object[] newview = msa.getUpdatedView(allResults,
236             arrOrders, '-');
237     SequenceI[] alignment = (SequenceI[]) newview[0];
238     HiddenColumns hidden = (HiddenColumns) newview[1];
239     Alignment al = new Alignment(alignment);
240     al.setProperty("Alignment Program", "hmmalign");
241     if (dataset != null)
242     {
243       al.setDataset(dataset);
244     }
245
246     if (newFrame)
247     {
248       displayInNewFrame(al, allOrders, hidden);
249     }
250   }
251
252   private void displayInNewFrame(AlignmentI al,
253           List<AlignmentOrder> alorders, HiddenColumns hidden)
254   {
255     AlignFrame af = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH,
256             AlignFrame.DEFAULT_HEIGHT);
257
258     // initialise with same renderer settings as in parent alignframe.
259     af.getFeatureRenderer().transferSettings(this.featureSettings);
260
261     if (allOrders.size() > 0)
262     {
263       addSortByMenuItems(af, allOrders);
264     }
265
266     // TODO: refactor retrieve and show as new splitFrame as Desktop method
267
268     /*
269      * If alignment was requested from one half of a SplitFrame, show in a
270      * SplitFrame with the other pane similarly aligned.
271      */
272     AlignFrame requestedBy = this.af;
273     if (requestedBy != null && requestedBy.getSplitViewContainer() != null
274             && requestedBy.getSplitViewContainer()
275                     .getComplement(requestedBy) != null)
276     {
277       AlignmentI complement = requestedBy.getSplitViewContainer()
278               .getComplement(requestedBy);
279       String complementTitle = requestedBy.getSplitViewContainer()
280               .getComplementTitle(requestedBy);
281       // becomes null if the alignment window was closed before the alignment
282       // job finished.
283       AlignmentI copyComplement = new Alignment(complement);
284       // todo should this be done by copy constructor?
285       copyComplement.setGapCharacter(complement.getGapCharacter());
286       // share the same dataset (and the mappings it holds)
287       copyComplement.setDataset(complement.getDataset());
288       copyComplement.alignAs(al);
289       if (copyComplement.getHeight() > 0)
290       {
291         af.setTitle(this.af.getTitle());
292         AlignFrame af2 = new AlignFrame(copyComplement,
293                 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
294         af2.setTitle(complementTitle);
295         String linkedTitle = MessageManager
296                 .getString("label.linked_view_title");
297         JInternalFrame splitFrame = new SplitFrame(
298                 al.isNucleotide() ? af : af2, al.isNucleotide() ? af2 : af);
299         Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1);
300         return;
301       }
302     }
303
304     /*
305      * Not from SplitFrame, or failed to created a complementary alignment
306      */
307     Desktop.addInternalFrame(af, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
308             AlignFrame.DEFAULT_HEIGHT);
309   }
310
311   /**
312    * Add sort order options to the AlignFrame menus.
313    * 
314    * @param af
315    * @param alorders
316    */
317   protected void addSortByMenuItems(AlignFrame af,
318           List<AlignmentOrder> alorders)
319   {
320     // update orders
321     if (alorders.size() == 1)
322     {
323       af.addSortByOrderMenuItem("hmmalign" + " Ordering", alorders.get(0));
324     }
325     else
326     {
327       // construct a non-redundant ordering set
328       List<String> names = new ArrayList<>();
329       for (int i = 0, l = alorders.size(); i < l; i++)
330       {
331         String orderName = " Region " + i;
332         int j = i + 1;
333
334         while (j < l)
335         {
336           if (alorders.get(i).equals(alorders.get(j)))
337           {
338             alorders.remove(j);
339             l--;
340             orderName += "," + j;
341           }
342           else
343           {
344             j++;
345           }
346         }
347
348         if (i == 0 && j == 1)
349         {
350           names.add("");
351         }
352         else
353         {
354           names.add(orderName);
355         }
356       }
357       for (int i = 0, l = alorders.size(); i < l; i++)
358       {
359         af.addSortByOrderMenuItem("hmmalign" + (names.get(i)) + " Ordering",
360                 alorders.get(i));
361       }
362     }
363   }
364
365   }
366
367