3 import jalview.api.AlignViewportI;
4 import jalview.bin.Cache;
5 import jalview.datamodel.Alignment;
6 import jalview.datamodel.AlignmentI;
7 import jalview.datamodel.AlignmentView;
8 import jalview.datamodel.AnnotatedCollectionI;
9 import jalview.datamodel.SequenceGroup;
10 import jalview.datamodel.SequenceI;
11 import jalview.gui.AlignFrame;
12 import jalview.gui.JvOptionPane;
13 import jalview.io.DataSourceType;
14 import jalview.io.FileParse;
15 import jalview.io.HMMFile;
16 import jalview.util.FileUtils;
17 import jalview.util.MessageManager;
18 import jalview.ws.params.ArgumentI;
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Hashtable;
24 import java.util.List;
27 * A class that runs the hmmbuild command as a separate process.
32 public class HMMBuild extends HmmerCommand
34 static final String ARG_AMINO = "--amino";
36 static final String ARG_DNA = "--dna";
38 static final String ARG_RNA = "--rna";
46 public HMMBuild(AlignFrame alignFrame, List<ArgumentI> args)
48 super(alignFrame, args);
52 * Builds a HMM from an alignment (and/or groups), then imports and adds it to
53 * the alignment (and/or groups). Call this method directly to execute
54 * synchronously, or via start() in a new Thread for asynchronously.
59 if (params == null || params.isEmpty())
61 Cache.log.error("No parameters to HMMBuild!|");
65 long msgID = System.currentTimeMillis();
66 af.setProgressBar(MessageManager.getString("status.running_hmmbuild"),
69 AlignViewportI viewport = af.getViewport();
73 * run hmmbuild for alignment and/or groups as selected
75 List<AnnotatedCollectionI> runBuildFor = parseParameters(viewport);
77 for (AnnotatedCollectionI grp : runBuildFor)
83 af.setProgressBar("", msgID);
84 viewport.alignmentChanged(af.alignPanel);
85 af.buildColourMenu(); // to enable HMMER colour schemes
90 * Scans the parameters to determine whether to run hmmmbuild for the whole
91 * alignment or specified subgroup(s) or both
96 protected List<AnnotatedCollectionI> parseParameters(
97 AlignViewportI viewport)
99 List<AnnotatedCollectionI> runBuildFor = new ArrayList<>();
100 boolean foundArg = false;
102 for (ArgumentI arg : params)
104 String name = arg.getName();
105 if (MessageManager.getString("label.hmmbuild_for").equals(name))
108 String value = arg.getValue();
110 if (MessageManager.getString("label.alignment").equals(value))
112 runBuildFor.add(viewport.getAlignmentView(false)
113 .getVisibleAlignment('-'));
115 else if (MessageManager.getString("label.groups_and_alignment")
118 AlignmentView av = viewport.getAlignmentView(true);
119 runBuildFor.add(av.getVisibleAlignment('-'));
120 runBuildFor.addAll(av.getVisibleGroups('-'));
122 else if (MessageManager.getString("label.groups").equals(value))
124 AlignmentView av = viewport.getAlignmentView(false);
125 runBuildFor.addAll(av.getVisibleGroups('-'));
127 else if (MessageManager.getString("label.selected_group")
130 AlignmentView av = viewport.getAlignmentView(true);
131 runBuildFor.add(av.getVisibleAlignment('-'));
134 else if (MessageManager.getString("label.use_reference")
137 // todo disable this option if no RF annotation on alignment
138 if (!af.getViewport().hasReferenceAnnotation())
140 JvOptionPane.showInternalMessageDialog(af, MessageManager
141 .getString("warn.no_reference_annotation"));
148 * default is to build for the whole alignment
152 runBuildFor.add(alignment);
159 * Runs hmmbuild on the given sequences (alignment or group)
163 private void runHMMBuild(AnnotatedCollectionI ac)
166 File alignmentFile = null;
169 hmmFile = FileUtils.createTempFile("hmm", ".hmm");
170 alignmentFile = FileUtils.createTempFile("output", ".sto");
172 if (ac instanceof Alignment)
174 AlignmentI al = (Alignment) ac;
175 // todo pad gaps in an unaligned SequenceGroup as well?
182 deleteHmmSequences(ac);
184 List<SequenceI> copy = new ArrayList<>();
185 if (ac instanceof Alignment)
187 copy.addAll(ac.getSequences());
191 SequenceI[] sel = ((SequenceGroup) ac)
192 .getSelectionAsNewSequences((AlignmentI) ac.getContext());
193 for (SequenceI seq : sel)
198 // TODO rather than copy alignment data we should anonymize in situ -
199 // export/File import could use anonymization hash to reinstate references
201 SequenceI[] copyArray = copy.toArray(new SequenceI[copy.size()]);
202 Hashtable sequencesHash = stashSequences(copyArray);
204 exportStockholm(copyArray, alignmentFile, ac);
206 recoverSequences(sequencesHash, copy.toArray(new SequenceI[] {}));
208 boolean ran = runCommand(alignmentFile, hmmFile, ac);
211 JvOptionPane.showInternalMessageDialog(af, MessageManager
212 .formatMessage("warn.command_failed", "hmmbuild"));
215 importData(hmmFile, ac);
216 } catch (Exception e)
225 if (alignmentFile != null)
227 alignmentFile.delete();
233 * A helper method that deletes any HMM consensus sequence from the given
234 * collection, and from the parent alignment if <code>ac</code> is a subgroup
238 void deleteHmmSequences(AnnotatedCollectionI ac)
240 List<SequenceI> hmmSeqs = ac.getHmmSequences();
241 for (SequenceI hmmSeq : hmmSeqs)
243 if (ac instanceof SequenceGroup)
245 ((SequenceGroup) ac).deleteSequence(hmmSeq, false);
246 AnnotatedCollectionI context = ac.getContext();
247 if (context != null && context instanceof AlignmentI)
249 ((AlignmentI) context).deleteSequence(hmmSeq);
254 ((AlignmentI) ac).deleteSequence(hmmSeq);
260 * Constructs and executes the hmmbuild command as a separate process
262 * @param sequencesFile
263 * the alignment from which the HMM is built
265 * the output file to which the HMM is written
267 * alignment or group for which the hmm is generated
270 * @throws IOException
272 private boolean runCommand(File sequencesFile, File hmmFile,
273 AnnotatedCollectionI group) throws IOException
275 String cmd = getCommandPath(HMMBUILD);
278 return false; // executable not found
280 List<String> args = new ArrayList<>();
284 * HMM name (will be given to consensus sequence) is
285 * - as specified by an input parameter if set
286 * - else group name with _HMM appended (if for a group)
287 * - else align frame title with _HMM appended (if title is not too long)
288 * - else "Alignment_HMM"
294 for (ArgumentI arg : params)
296 String argName = arg.getName();
300 name = arg.getValue().trim();
302 case "Use Reference Annotation":
309 if (group instanceof SequenceGroup)
311 name = ((SequenceGroup) group).getName() + "_HMM";
316 if (af != null && af.getTitle().length() < 15)
318 name = af.getTitle();
322 name = "Alignment_HMM";
327 args.add(name.replace(' ', '_'));
328 if (!alignment.isNucleotide())
330 args.add(ARG_AMINO); // TODO check for rna
337 args.add(getFilePath(hmmFile));
338 args.add(getFilePath(sequencesFile));
340 return runCommand(args);
344 * Imports the .hmm file produced by hmmbuild, and inserts the HMM consensus
345 * sequence (with attached HMM profile) as the first sequence in the alignment
346 * or group for which it was generated
350 * (optional) the group for which the hmm was generated
351 * @throws IOException
353 private void importData(File hmmFile, AnnotatedCollectionI ac)
356 if (hmmFile.length() == 0L)
358 Cache.log.error("Error: hmmbuild produced empty hmm file");
362 HMMFile file = new HMMFile(
363 new FileParse(hmmFile.getAbsolutePath(), DataSourceType.FILE));
364 SequenceI hmmSeq = file.getHMM().getConsensusSequence();
368 // hmmbuild failure not detected earlier
372 if (ac instanceof SequenceGroup)
374 SequenceGroup grp = (SequenceGroup) ac;
375 char gapChar = alignment.getGapCharacter();
376 hmmSeq.insertCharAt(0, ac.getStartRes(), gapChar);
377 hmmSeq.insertCharAt(ac.getEndRes() + 1,
378 alignment.getWidth() - ac.getEndRes() - 1, gapChar);
379 SequenceI topSeq = grp.getSequencesInOrder(alignment)[0];
380 int topIndex = alignment.findIndex(topSeq);
381 alignment.insertSequenceAt(topIndex, hmmSeq);
382 ac.setSeqrep(hmmSeq);
383 grp.addSequence(hmmSeq, false);
387 alignment.insertSequenceAt(0, hmmSeq);