package jalview.hmmer; import jalview.bin.Cache; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; import jalview.datamodel.AlignmentView; import jalview.datamodel.HiddenColumns; import jalview.datamodel.HiddenMarkovModel; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; import jalview.gui.Desktop; import jalview.gui.JvOptionPane; import jalview.gui.Preferences; import jalview.gui.SplitFrame; import jalview.io.DataSourceType; import jalview.io.StockholmFile; import jalview.util.MessageManager; import jalview.viewmodel.seqfeatures.FeatureRendererSettings; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.swing.JInternalFrame; import javax.swing.JOptionPane; public class HMMAlignThread implements Runnable { /** * feature settings from view that job was associated with */ protected FeatureRendererSettings featureSettings = null; HMMERCommands cmds = new HMMERCommands(); AlignFrame af; AlignmentI alignment; AlignmentI dataset; List orders; AlignmentView msa; HiddenMarkovModel hmm; boolean newFrame; long barID; Map hmmSeqs; File hmmTemp = null; File outTemp = null; File inputTemp = null; List allOrders; SequenceI[][] allResults; public HMMAlignThread(AlignFrame af, boolean createNewFrame) { this.af = af; alignment = af.getViewport().getAlignment(); if (alignment.getDataset() != null) { dataset = alignment.getDataset(); } newFrame = createNewFrame; featureSettings = af.getFeatureRenderer().getSettings(); } @Override public void run() { if (af.getViewport().getSelectedHMM() == null) { JOptionPane.showMessageDialog(af, MessageManager.getString("warn.no_selected_hmm")); return; } else { hmm = af.getViewport().getSelectedHMM(); } barID = System.currentTimeMillis(); af.setProgressBar(MessageManager.getString("status.running_hmmalign"), barID); cmds.HMMERFOLDER = Cache.getProperty(Preferences.HMMER_PATH); // if (!alignment.isAligned()) // { // alignment.padGaps(); // } prepareAlignment(); SequenceI[][] subAlignments = msa.getVisibleContigs('-'); allOrders = new ArrayList<>(); allResults = new SequenceI[subAlignments.length][]; int job = 0; for (SequenceI[] seqs : subAlignments) { cmds.uniquifySequences(seqs); try { createTemporaryFiles(); } catch (IOException e2) { e2.printStackTrace(); } try { cmds.exportData(seqs, outTemp.getAbsoluteFile(), hmm, hmmTemp.getAbsoluteFile()); } catch (IOException e1) { e1.printStackTrace(); } try { boolean ran = runCommand(); if (!ran) { JvOptionPane.showInternalMessageDialog(af, MessageManager.getString("warn.hmmalign_failed")); return; } } catch (IOException | InterruptedException e) { e.printStackTrace(); } try { importData(job); } catch (IOException | InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } job++; } displayResults(newFrame); af.setProgressBar(MessageManager.getString("status.running_hmmalign"), barID); } private void createTemporaryFiles() throws IOException { hmmTemp = File.createTempFile("hmm", ".hmm"); hmmTemp.deleteOnExit(); outTemp = File.createTempFile("output", ".sto"); outTemp.deleteOnExit(); inputTemp = File.createTempFile("input", ".sto"); inputTemp.deleteOnExit(); } private boolean runCommand() throws IOException, InterruptedException { File file = new File(cmds.HMMERFOLDER + "/binaries/hmmalign.exe"); if (!file.canExecute()) { return false; } String command = cmds.HMMERFOLDER + cmds.HMMALIGN; if (!hmm.getFileHeader().contains("HMMER3/f")) { command += cmds.ALLCOL; } boolean trim = true; String bool = Cache.getProperty("TRIM_TERMINI"); if ("false".equals(bool)) { trim = false; } if (trim) { command += cmds.TRIM; } command += " -o" + inputTemp.getAbsolutePath() + cmds.SPACE + hmmTemp.getAbsolutePath() + cmds.SPACE + outTemp.getAbsolutePath(); return cmds.runCommand(command); } private void importData(int index) throws IOException, InterruptedException { StockholmFile file = new StockholmFile(inputTemp.getAbsolutePath(), DataSourceType.FILE); SequenceI[] result = file.getSeqsAsArray(); AlignmentOrder msaorder = new AlignmentOrder(result); jalview.analysis.AlignmentSorter.recoverOrder(result); jalview.analysis.SeqsetUtils.deuniquify(cmds.hash, result); allOrders.add(msaorder); allResults[index] = result; hmmTemp.delete(); outTemp.delete(); inputTemp.delete(); } private void prepareAlignment() { // hmmSeqs = alignment.getHMMConsensusSequences(true); msa = af.gatherSequencesForAlignment(); } private void displayResults(boolean newFrame) { AlignmentOrder[] arrOrders = allOrders .toArray(new AlignmentOrder[allOrders.size()]); Object[] newview = msa.getUpdatedView(allResults, arrOrders, '-'); SequenceI[] alignment = (SequenceI[]) newview[0]; HiddenColumns hidden = (HiddenColumns) newview[1]; Alignment al = new Alignment(alignment); al.setProperty("Alignment Program", "hmmalign"); if (dataset != null) { al.setDataset(dataset); } if (newFrame) { displayInNewFrame(al, allOrders, hidden); } } private void displayInNewFrame(AlignmentI al, List alorders, HiddenColumns hidden) { AlignFrame af = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); // initialise with same renderer settings as in parent alignframe. af.getFeatureRenderer().transferSettings(this.featureSettings); if (allOrders.size() > 0) { addSortByMenuItems(af, allOrders); } // TODO: refactor retrieve and show as new splitFrame as Desktop method /* * If alignment was requested from one half of a SplitFrame, show in a * SplitFrame with the other pane similarly aligned. */ AlignFrame requestedBy = this.af; if (requestedBy != null && requestedBy.getSplitViewContainer() != null && requestedBy.getSplitViewContainer() .getComplement(requestedBy) != null) { AlignmentI complement = requestedBy.getSplitViewContainer() .getComplement(requestedBy); String complementTitle = requestedBy.getSplitViewContainer() .getComplementTitle(requestedBy); // becomes null if the alignment window was closed before the alignment // job finished. AlignmentI copyComplement = new Alignment(complement); // todo should this be done by copy constructor? copyComplement.setGapCharacter(complement.getGapCharacter()); // share the same dataset (and the mappings it holds) copyComplement.setDataset(complement.getDataset()); copyComplement.alignAs(al); if (copyComplement.getHeight() > 0) { af.setTitle(this.af.getTitle()); AlignFrame af2 = new AlignFrame(copyComplement, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); af2.setTitle(complementTitle); String linkedTitle = MessageManager .getString("label.linked_view_title"); JInternalFrame splitFrame = new SplitFrame( al.isNucleotide() ? af : af2, al.isNucleotide() ? af2 : af); Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1); return; } } /* * Not from SplitFrame, or failed to created a complementary alignment */ Desktop.addInternalFrame(af, af.getTitle(), AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); } /** * Add sort order options to the AlignFrame menus. * * @param af * @param alorders */ protected void addSortByMenuItems(AlignFrame af, List alorders) { // update orders if (alorders.size() == 1) { af.addSortByOrderMenuItem("hmmalign" + " Ordering", alorders.get(0)); } else { // construct a non-redundant ordering set List names = new ArrayList<>(); for (int i = 0, l = alorders.size(); i < l; i++) { String orderName = " Region " + i; int j = i + 1; while (j < l) { if (alorders.get(i).equals(alorders.get(j))) { alorders.remove(j); l--; orderName += "," + j; } else { j++; } } if (i == 0 && j == 1) { names.add(""); } else { names.add(orderName); } } for (int i = 0, l = alorders.size(); i < l; i++) { af.addSortByOrderMenuItem("hmmalign" + (names.get(i)) + " Ordering", alorders.get(i)); } } } }