JAL-2629 fix issue where trim termini setting would not update
[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     boolean trim = true;
167     String bool = Cache.getProperty("TRIM_TERMINI");
168     if ("false".equals(bool))
169     {
170       trim = false;
171     }
172     if (trim)
173     {
174       command += cmds.TRIM;
175     }
176     command += " -o" + inputTemp.getAbsolutePath() + cmds.SPACE
177             + hmmTemp.getAbsolutePath() + cmds.SPACE
178             + outTemp.getAbsolutePath();
179     cmds.runCommand(command);
180   }
181
182   private void importData(int index)
183           throws IOException, InterruptedException
184   {
185     StockholmFile file = new StockholmFile(inputTemp.getAbsolutePath(),
186             DataSourceType.FILE);
187     SequenceI[] result = file.getSeqsAsArray();
188     AlignmentOrder msaorder = new AlignmentOrder(result);
189     // always recover the order - makes parseResult()'s life easier.
190     jalview.analysis.AlignmentSorter.recoverOrder(result);
191     jalview.analysis.SeqsetUtils.deuniquify(cmds.hash, result);
192     allOrders.add(msaorder);
193     allResults[index] = result;
194
195     /*
196     if (newFrame)
197     {
198       FileLoader loader = new FileLoader();
199       AlignFrame aFrame = new AlignFrame(new Alignment(new SequenceI[1]),
200               AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
201       Desktop.addInternalFrame(aFrame, aFrame.getTitle(),
202               AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
203       aFrame.setTitle(
204               af.getName() + "Aligned to " + hmm.getName() + "'s HMM");
205       af.getViewport().setAlignment(null);
206     
207       aFrame.loadJalviewDataFile(inputTemp.getAbsolutePath(),
208               DataSourceType.FILE, FileFormat.Stockholm, null);
209     
210     
211     
212       Map<Integer, SequenceI> copy = new HashMap<>(
213               hmmSeqs);
214       addSeqs(aFrame, copy);
215       SequenceI seq = aFrame.getViewport().getAlignment()
216               .getSequenceAt(0);
217       seq.getHMM().mapToReferenceAnnotation(aFrame, seq);
218       addSeqs(af, hmmSeqs);
219     }
220     else
221     {
222       af.getViewport().getAlignment().getSequences().clear();
223       af.setIsRecurring(true);
224       af.loadJalviewDataFile(inputTemp.getAbsolutePath(),
225               DataSourceType.FILE, FileFormat.Stockholm, null);
226       af.setIsRecurring(false);
227       addSeqs(af, hmmSeqs);
228     }
229     */
230     hmmTemp.delete();
231     outTemp.delete();
232     inputTemp.delete();
233   }
234
235   private void prepareAlignment()
236   {
237     // hmmSeqs = alignment.getHMMConsensusSequences(true);
238     msa = af.gatherSequencesForAlignment();
239   }
240
241   private void displayResults(boolean newFrame)
242   {
243     AlignmentOrder[] arrOrders = allOrders
244             .toArray(new AlignmentOrder[allOrders.size()]);
245     Object[] newview = msa.getUpdatedView(allResults,
246             arrOrders, '-');
247     SequenceI[] alignment = (SequenceI[]) newview[0];
248     HiddenColumns hidden = (HiddenColumns) newview[1];
249     Alignment al = new Alignment(alignment);
250     al.setProperty("Alignment Program", "hmmalign");
251     if (dataset != null)
252     {
253       al.setDataset(dataset);
254     }
255
256     if (newFrame)
257     {
258       displayInNewFrame(al, allOrders, hidden);
259     }
260   }
261
262   private void displayInNewFrame(AlignmentI al,
263           List<AlignmentOrder> alorders, HiddenColumns hidden)
264   {
265     AlignFrame af = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH,
266             AlignFrame.DEFAULT_HEIGHT);
267
268     // initialise with same renderer settings as in parent alignframe.
269     af.getFeatureRenderer().transferSettings(this.featureSettings);
270
271     if (allOrders.size() > 0)
272     {
273       addSortByMenuItems(af, allOrders);
274     }
275
276     // TODO: refactor retrieve and show as new splitFrame as Desktop method
277
278     /*
279      * If alignment was requested from one half of a SplitFrame, show in a
280      * SplitFrame with the other pane similarly aligned.
281      */
282     AlignFrame requestedBy = this.af;
283     if (requestedBy != null && requestedBy.getSplitViewContainer() != null
284             && requestedBy.getSplitViewContainer()
285                     .getComplement(requestedBy) != null)
286     {
287       AlignmentI complement = requestedBy.getSplitViewContainer()
288               .getComplement(requestedBy);
289       String complementTitle = requestedBy.getSplitViewContainer()
290               .getComplementTitle(requestedBy);
291       // becomes null if the alignment window was closed before the alignment
292       // job finished.
293       AlignmentI copyComplement = new Alignment(complement);
294       // todo should this be done by copy constructor?
295       copyComplement.setGapCharacter(complement.getGapCharacter());
296       // share the same dataset (and the mappings it holds)
297       copyComplement.setDataset(complement.getDataset());
298       copyComplement.alignAs(al);
299       if (copyComplement.getHeight() > 0)
300       {
301         af.setTitle(this.af.getTitle());
302         AlignFrame af2 = new AlignFrame(copyComplement,
303                 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
304         af2.setTitle(complementTitle);
305         String linkedTitle = MessageManager
306                 .getString("label.linked_view_title");
307         JInternalFrame splitFrame = new SplitFrame(
308                 al.isNucleotide() ? af : af2, al.isNucleotide() ? af2 : af);
309         Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1);
310         return;
311       }
312     }
313
314     /*
315      * Not from SplitFrame, or failed to created a complementary alignment
316      */
317     Desktop.addInternalFrame(af, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
318             AlignFrame.DEFAULT_HEIGHT);
319   }
320
321   /**
322    * Add sort order options to the AlignFrame menus.
323    * 
324    * @param af
325    * @param alorders
326    */
327   protected void addSortByMenuItems(AlignFrame af,
328           List<AlignmentOrder> alorders)
329   {
330     // update orders
331     if (alorders.size() == 1)
332     {
333       af.addSortByOrderMenuItem("hmmalign" + " Ordering", alorders.get(0));
334     }
335     else
336     {
337       // construct a non-redundant ordering set
338       List<String> names = new ArrayList<>();
339       for (int i = 0, l = alorders.size(); i < l; i++)
340       {
341         String orderName = " Region " + i;
342         int j = i + 1;
343
344         while (j < l)
345         {
346           if (alorders.get(i).equals(alorders.get(j)))
347           {
348             alorders.remove(j);
349             l--;
350             orderName += "," + j;
351           }
352           else
353           {
354             j++;
355           }
356         }
357
358         if (i == 0 && j == 1)
359         {
360           names.add("");
361         }
362         else
363         {
364           names.add(orderName);
365         }
366       }
367       for (int i = 0, l = alorders.size(); i < l; i++)
368       {
369         af.addSortByOrderMenuItem("hmmalign" + (names.get(i)) + " Ordering",
370                 alorders.get(i));
371       }
372     }
373   }
374
375   }
376
377