3 import jalview.analysis.SeqsetUtils;
4 import jalview.bin.Cache;
5 import jalview.datamodel.Alignment;
6 import jalview.datamodel.AlignmentAnnotation;
7 import jalview.datamodel.AlignmentI;
8 import jalview.datamodel.AnnotatedCollectionI;
9 import jalview.datamodel.Annotation;
10 import jalview.datamodel.HiddenMarkovModel;
11 import jalview.datamodel.SequenceGroup;
12 import jalview.datamodel.SequenceI;
13 import jalview.gui.AlignFrame;
14 import jalview.gui.JvOptionPane;
15 import jalview.gui.Preferences;
16 import jalview.io.FastaFile;
17 import jalview.io.HMMFile;
18 import jalview.io.StockholmFile;
19 import jalview.util.FileUtils;
20 import jalview.util.MessageManager;
21 import jalview.util.Platform;
22 import jalview.ws.params.ArgumentI;
24 import java.io.BufferedReader;
26 import java.io.FileNotFoundException;
27 import java.io.IOException;
28 import java.io.InputStreamReader;
29 import java.io.PrintWriter;
30 import java.nio.file.Paths;
31 import java.util.ArrayList;
32 import java.util.Hashtable;
33 import java.util.List;
36 * Base class for hmmbuild, hmmalign and hmmsearch
41 public abstract class HmmerCommand implements Runnable
43 public static final String HMMBUILD = "hmmbuild";
45 protected final AlignFrame af;
47 protected final AlignmentI alignment;
49 protected final List<ArgumentI> params;
52 * constants for i18n lookup of passed parameter names
54 static final String DATABASE_KEY = "label.database";
56 static final String THIS_ALIGNMENT_KEY = "label.this_alignment";
58 static final String USE_ACCESSIONS_KEY = "label.use_accessions";
60 static final String AUTO_ALIGN_SEQS_KEY = "label.auto_align_seqs";
62 static final String NUMBER_OF_RESULTS_KEY = "label.number_of_results";
64 static final String TRIM_TERMINI_KEY = "label.trim_termini";
66 static final String REPORTING_CUTOFF_KEY = "label.reporting_cutoff";
68 static final String CUTOFF_NONE = "None";
70 static final String CUTOFF_SCORE = "Score";
72 static final String CUTOFF_EVALUE = "E-Value";
74 static final String SEQ_EVALUE_KEY = "label.seq_evalue";
76 static final String DOM_EVALUE_KEY = "label.dom_evalue";
78 static final String SEQ_SCORE_KEY = "label.seq_score";
80 static final String DOM_SCORE_KEY = "label.dom_score";
82 static final String ARG_TRIM = "--trim";
90 public HmmerCommand(AlignFrame alignFrame, List<ArgumentI> args)
93 alignment = af.getViewport().getAlignment();
98 * Answers true if preference HMMER_PATH is set, and its value is the path to
99 * a directory that contains an executable <code>hmmbuild</code> or
100 * <code>hmmbuild.exe</code>, else false
104 public static boolean isHmmerAvailable()
106 File exec = FileUtils.getExecutable(HMMBUILD,
107 Cache.getProperty(Preferences.HMMER_PATH));
112 * Uniquifies the sequences when exporting and stores their details in a
117 protected Hashtable stashSequences(SequenceI[] seqs)
119 return SeqsetUtils.uniquify(seqs, true);
123 * Restores the sequence data lost by uniquifying
128 protected void recoverSequences(Hashtable hashtable, SequenceI[] seqs)
130 SeqsetUtils.deuniquify(hashtable, seqs);
134 * Runs a command as a separate process and waits for it to complete. Answers
135 * true if the process return status is zero, else false.
138 * the executable command and any arguments to it
139 * @throws IOException
141 public boolean runCommand(List<String> commands)
144 List<String> args = Platform.isWindows() ? wrapWithCygwin(commands)
149 ProcessBuilder pb = new ProcessBuilder(args);
150 pb.redirectErrorStream(true); // merge syserr to sysout
151 if (Platform.isWindows())
153 String path = pb.environment().get("Path");
154 path = jalview.bin.Cache.getProperty("CYGWIN_PATH") + ";" + path;
155 pb.environment().put("Path", path);
157 final Process p = pb.start();
158 new Thread(new Runnable()
163 BufferedReader input = new BufferedReader(
164 new InputStreamReader(p.getInputStream()));
167 String line = input.readLine();
170 System.out.println(line);
171 line = input.readLine();
173 } catch (IOException e)
181 int exitValue = p.exitValue();
184 Cache.log.error("Command failed, return code = " + exitValue);
185 Cache.log.error("Command/args were: " + args.toString());
187 return exitValue == 0; // 0 is success, by convention
188 } catch (Exception e)
196 * Converts the given command to a Cygwin "bash" command wrapper. The hmmer
197 * command and any arguments to it are converted into a single parameter to the
202 protected List<String> wrapWithCygwin(List<String> commands)
204 File bash = FileUtils.getExecutable("bash",
205 Cache.getProperty(Preferences.CYGWIN_PATH));
208 Cache.log.error("Cygwin shell not found");
212 List<String> wrapped = new ArrayList<>();
213 // wrapped.add("C:\Users\tva\run");
214 wrapped.add(bash.getAbsolutePath());
218 * combine hmmbuild/search/align and arguments to a single string
220 StringBuilder sb = new StringBuilder();
221 for (String cmd : commands)
223 sb.append(" ").append(cmd);
225 wrapped.add(sb.toString());
231 * Exports an alignment, and reference (RF) annotation if present, to the
232 * specified file, in Stockholm format, removing all HMM sequences
237 * @throws IOException
239 public void exportStockholm(SequenceI[] seqs, File toFile,
240 AnnotatedCollectionI annotated) throws IOException
246 AlignmentI newAl = new Alignment(seqs);
247 if (!newAl.isAligned())
252 if (toFile != null && annotated != null)
254 AlignmentAnnotation[] annots = annotated.getAlignmentAnnotation();
257 for (AlignmentAnnotation annot : annots)
259 if (annot.label.contains("Reference") || "RF".equals(annot.label))
261 AlignmentAnnotation newRF;
262 if (annot.annotations.length > newAl.getWidth())
264 Annotation[] rfAnnots = new Annotation[newAl.getWidth()];
265 System.arraycopy(annot.annotations, 0, rfAnnots, 0,
267 newRF = new AlignmentAnnotation("RF", "Reference Positions",
272 newRF = new AlignmentAnnotation(annot);
274 newAl.addAnnotation(newRF);
280 StockholmFile file = new StockholmFile(newAl);
281 String output = file.print(seqs, false);
282 PrintWriter writer = new PrintWriter(toFile);
283 writer.println(output);
288 * Exports the given alignment withotu any anotations to a fasta file
293 public void exportFasta(AlignmentI al, File toFile)
295 FastaFile file = new FastaFile();
297 String output = file.print(al.getSequencesArray(), false);
301 writer = new PrintWriter(toFile);
302 writer.println(output);
304 } catch (FileNotFoundException e)
312 * Answers the full path to the given hmmer executable, or null if file cannot
313 * be found or is not executable
316 * command short name e.g. hmmalign
318 * @throws IOException
320 protected String getCommandPath(String cmd)
323 String binariesFolder = Cache.getProperty(Preferences.HMMER_PATH);
324 // ensure any symlink to the directory is resolved:
325 binariesFolder = Paths.get(binariesFolder).toRealPath().toString();
326 File file = FileUtils.getExecutable(cmd, binariesFolder);
327 if (file == null && af != null)
329 JvOptionPane.showInternalMessageDialog(af, MessageManager
330 .formatMessage("label.executable_not_found", cmd));
333 return file == null ? null : getFilePath(file, true);
337 * Exports an HMM to the specified file
341 * @throws IOException
343 public void exportHmm(HiddenMarkovModel hmm, File hmmFile)
348 HMMFile file = new HMMFile(hmm);
349 PrintWriter writer = new PrintWriter(hmmFile);
350 writer.print(file.print());
357 * Exports a sequence to the specified file
361 * @throws IOException
363 public void exportSequence(SequenceI seq, File seqFile) throws IOException
367 FastaFile file = new FastaFile();
368 PrintWriter writer = new PrintWriter(seqFile);
369 writer.print(file.print(new SequenceI[] { seq }, false));
375 * Answers the HMM profile for the profile sequence the user selected (default
376 * is just the first HMM sequence in the alignment)
380 protected HiddenMarkovModel getHmmProfile()
382 String alignToParamName = MessageManager.getString("label.use_hmm");
383 for (ArgumentI arg : params)
385 String name = arg.getName();
386 if (name.equals(alignToParamName))
388 String seqName = arg.getValue();
389 SequenceI hmmSeq = alignment.findName(seqName);
390 if (hmmSeq.hasHMMProfile())
392 return hmmSeq.getHMM();
400 * Answers the HMM profile for the profile sequence the user selected (default
401 * is just the first HMM sequence in the alignment)
405 protected SequenceI getSequence()
407 String alignToParamName = MessageManager
408 .getString("label.use_sequence");
409 for (ArgumentI arg : params)
411 String name = arg.getName();
412 if (name.equals(alignToParamName))
414 String seqName = arg.getValue();
415 SequenceI seq = alignment.findName(seqName);
423 * Answers an absolute path to the given file, in a format suitable for
424 * processing by a hmmer command. On a Windows platform, the native Windows file
425 * path is converted to Cygwin format, by replacing '\'with '/' and drive letter
426 * X with /cygdrive/x.
430 * True if file is to be read/written from within the Cygwin
431 * shell. Should be false for any imports.
434 protected String getFilePath(File resultFile, boolean isInCygwin)
436 String path = resultFile.getAbsolutePath();
437 if (Platform.isWindows() && isInCygwin)
439 // the first backslash escapes '\' for the regular expression argument
440 path = path.replaceAll("\\" + File.separator, "/");
441 int colon = path.indexOf(':');
444 String drive = path.substring(0, colon);
445 path = path.replaceAll(drive + ":", "/cygdrive/" + drive);
453 * A helper method that deletes any HMM consensus sequence from the given
454 * collection, and from the parent alignment if <code>ac</code> is a subgroup
458 void deleteHmmSequences(AnnotatedCollectionI ac)
460 List<SequenceI> hmmSeqs = ac.getHmmSequences();
461 for (SequenceI hmmSeq : hmmSeqs)
463 if (ac instanceof SequenceGroup)
465 ((SequenceGroup) ac).deleteSequence(hmmSeq, false);
466 AnnotatedCollectionI context = ac.getContext();
467 if (context != null && context instanceof AlignmentI)
469 ((AlignmentI) context).deleteSequence(hmmSeq);
474 ((AlignmentI) ac).deleteSequence(hmmSeq);