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.FileFormat;
-import jalview.io.FileLoader;
+import jalview.io.StockholmFile;
import jalview.util.MessageManager;
+import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
+import jalview.ws.params.ArgumentI;
-import java.io.FileNotFoundException;
+import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
+import javax.swing.JInternalFrame;
+
public class HMMAlignThread implements Runnable
{
+ /**
+ * feature settings from view that job was associated with
+ */
+ protected FeatureRendererSettings featureSettings = null;
+
+ /**
+ * Object containing frequently used commands.
+ */
+ HMMERCommands cmds = new HMMERCommands();
+
AlignFrame af;
AlignmentI alignment;
+ AlignmentI dataset;
+
+ List<AlignmentOrder> orders;
+
+ AlignmentView msa;
+
HiddenMarkovModel hmm;
+ List<ArgumentI> args;
+
boolean newFrame;
long barID;
Map<Integer, SequenceI> hmmSeqs;
- public HMMAlignThread(AlignFrame af, boolean createNewFrame)
+ File hmmTemp = null;
+
+ File outTemp = null;
+
+ File inputTemp = null;
+
+ List<AlignmentOrder> allOrders;
+
+ SequenceI[][] allResults;
+
+ /**
+ * Constructor for the HMMAlignThread. If create new frame is set to true, a
+ * new frame will be created.
+ *
+ * @param af
+ * @param createNewFrame
+ */
+ public HMMAlignThread(AlignFrame af, boolean createNewFrame,
+ List<ArgumentI> args)
{
this.af = af;
alignment = af.getViewport().getAlignment();
- hmm = alignment.getSequenceAt(0).getHMM();
+ if (alignment.getDataset() != null)
+ {
+ dataset = alignment.getDataset();
+ }
newFrame = createNewFrame;
+ featureSettings = af.getFeatureRenderer().getSettings();
+ this.args = args;
}
+ /**
+ * Runs the HMMAlignThread: the data on the alignment or group is exported,
+ * then the command is executed in the command line and then the data is
+ * imported and displayed in a new frame (if true). The command is executed
+ * for each segemtn of the alignment.
+ */
@Override
public void run()
{
+
+ hmm = af.getSelectedHMM();
+
barID = System.currentTimeMillis();
- af.setProgressBar(MessageManager.getString("status.running_hmmbuild"),
+ af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
barID);
+ cmds.HMMERFOLDER = Cache.getProperty(Preferences.HMMER_PATH);
+ 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);
- try
+ af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
+ barID);
+
+ }
+
+ /**
+ * Creates temporary files for exporting and importing the data.
+ *
+ * @throws IOException
+ */
+ private void createTemporaryFiles() throws IOException
+ {
+ if (hmmTemp == null)
{
- try
- {
- hmmSeqs = alignment.getHMMConsensusSequences(true);
- HMMERCommands.exportData(alignment, true, true, hmm);
- } catch (FileNotFoundException e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ hmmTemp = File.createTempFile("hmm", ".hmm");
+ hmmTemp.deleteOnExit();
+ }
+ if (outTemp == null)
+ {
+ outTemp = File.createTempFile("output", ".sto");
+ outTemp.deleteOnExit();
+ }
+ inputTemp = File.createTempFile("input", ".sto");
+ inputTemp.deleteOnExit();
+ }
- }
- try
- {
- runCommand();
- } catch (IOException | InterruptedException e)
+ /**
+ * Executes the hmmalign command in the command line.
+ *
+ * @return
+ * @throws IOException
+ * @throws InterruptedException
+ */
+ private boolean runCommand() throws IOException, InterruptedException
+ {
+ File file = new File(cmds.HMMERFOLDER + "/hmmalign");
+ if (!file.canExecute())
+ {
+ file = new File(cmds.HMMERFOLDER + "/hmmalign.exe");
{
- // TODO Auto-generated catch block
- e.printStackTrace();
+ if (!file.canExecute())
+ {
+ return false;
+ }
}
- try
- {
- importData();
- } catch (IOException | InterruptedException e)
+ }
+ String command = cmds.HMMERFOLDER + cmds.HMMALIGN;
+ String version = Cache.getProperty("HMMER_VERSION");
+ if (!"3.1b2".equals(version))
+ {
+ command += cmds.ALLCOL;
+ }
+ if (args != null)
+ {
+ for (ArgumentI arg : args)
{
- // TODO Auto-generated catch block
- e.printStackTrace();
+ String name = arg.getName();
+ switch (name)
+ {
+ case "Trim Non-Matching Termini":
+ command += "--trim";
+ }
}
- } catch (Exception e)
+ }
+ command += " -o " + inputTemp.getAbsolutePath() + cmds.SPACE
+ + hmmTemp.getAbsolutePath() + cmds.SPACE
+ + outTemp.getAbsolutePath();
+ return cmds.runCommand(command);
+ }
+
+ /**
+ * Imports the data from the temporary file to which the output of hmmalign is
+ * directed. this is used for an internal job.
+ *
+ * @param index
+ * The index of the 'job' (or region of an alignment).
+ * @throws IOException
+ * @throws InterruptedException
+ */
+ 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();
+ }
+
+ /**
+ * Gathers the sequences in preparation for the alignment.
+ */
+ private void prepareAlignment()
+ {
+ // hmmSeqs = alignment.getHMMConsensusSequences(true);
+ msa = af.gatherSequencesForAlignment();
+ }
+
+ /**
+ * Displays the results of all 'jobs'.
+ *
+ * @param newFrame
+ */
+ 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);
+ }
- } finally
+ if (newFrame)
{
- af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
- barID);
+ displayInNewFrame(al, allOrders, hidden);
}
}
- private void runCommand() throws IOException, InterruptedException
+ /**
+ * Displays the results in a new frame.
+ *
+ * @param al
+ * The alignment containing the results.
+ * @param alorders
+ * The order of the sequences in the alignment on which the jobs were
+ * run.
+ * @param hidden
+ * Hidden columns in the previous alignment.
+ */
+ private void displayInNewFrame(AlignmentI al,
+ List<AlignmentOrder> alorders, HiddenColumns hidden)
{
- String command = HMMERCommands.HMMALIGN;
- if (!hmm.getFileHeader().contains("HMMER3/f"))
+ 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)
{
- command += HMMERCommands.ALLCOL;
+ addSortByMenuItems(af, allOrders);
}
- command += HMMERCommands.TRIM + HMMERCommands.OUTPUTALIGNMENT
- + HMMERCommands.JALVIEWDIRECTORY + HMMERCommands.HMMBUFFER
- + HMMERCommands.JALVIEWDIRECTORY
- + HMMERCommands.ALIGNMENTBUFFER;
- HMMERCommands.runCommand(command);
+
+ // 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);
}
- private void importData() throws IOException, InterruptedException
+ /**
+ * Add sort order options to the AlignFrame menus.
+ *
+ * @param af
+ * @param alorders
+ */
+ protected void addSortByMenuItems(AlignFrame af,
+ List<AlignmentOrder> alorders)
{
- if (newFrame)
+ // update orders
+ if (alorders.size() == 1)
{
- FileLoader loader = new FileLoader();
- AlignFrame newAFrame = loader.LoadFileWaitTillLoaded(
- HMMERCommands.ALIGNMENTINPUT, DataSourceType.FILE);
- addSeqs(newAFrame);
+ af.addSortByOrderMenuItem("hmmalign" + " Ordering", alorders.get(0));
}
else
{
- af.getViewport().getAlignment().getSequences().clear();
- af.loadJalviewDataFile(HMMERCommands.ALIGNMENTBUFFER,
- DataSourceType.FILE, FileFormat.Stockholm, null);
- addSeqs(af);
+ // construct a non-redundant ordering set
+ List<String> 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));
+ }
}
}
- private void addSeqs(AlignFrame alignFrame)
+ /**
+ * Runs hmmalign, and waits for the results to be imported before continuing
+ */
+ public void hmmalignWaitTillComplete()
{
- for (Map.Entry<Integer, SequenceI> entry : hmmSeqs.entrySet())
+ Thread loader = new Thread(this);
+ loader.start();
+
+ while (loader.isAlive())
{
- SequenceI seq = entry.getValue();
- Integer pos = entry.getKey();
- HMMERCommands.addHMMConsensusSequence(alignFrame, seq, pos);
+ try
+ {
+ Thread.sleep(500);
+ } catch (Exception ex)
+ {
+ }
}
- }
}
+ }