2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
21 package jalview.ext.jmol;
23 import jalview.datamodel.AlignmentAnnotation;
24 import jalview.datamodel.Annotation;
25 import jalview.datamodel.PDBEntry;
26 import jalview.datamodel.SequenceI;
27 import jalview.io.FileParse;
28 import jalview.io.StructureFile;
29 import jalview.schemes.ResidueProperties;
30 import jalview.structure.StructureImportSettings;
31 import jalview.util.Format;
32 import jalview.util.MessageManager;
34 import java.io.IOException;
35 import java.util.ArrayList;
36 import java.util.HashMap;
37 import java.util.List;
39 import java.util.Vector;
41 import javajs.awt.Dimension;
43 import org.jmol.api.JmolStatusListener;
44 import org.jmol.api.JmolViewer;
45 import org.jmol.c.CBK;
46 import org.jmol.c.STR;
47 import org.jmol.modelset.ModelSet;
48 import org.jmol.viewer.Viewer;
51 import MCview.PDBChain;
52 import MCview.Residue;
55 * Import and process files with Jmol for file like PDB, mmCIF
60 public class JmolParser extends StructureFile implements JmolStatusListener
64 public JmolParser(String inFile, String type) throws IOException
69 public JmolParser(FileParse fp) throws IOException
79 * Calls the Jmol library to parse the PDB/mmCIF file, and then inspects the
80 * resulting object model to generate Jalview-style sequences, with secondary
81 * structure annotation added where available (i.e. where it has been computed
82 * by Jmol using DSSP).
84 * @see jalview.io.AlignFile#parse()
87 public void parse() throws IOException
89 setChains(new Vector<PDBChain>());
90 Viewer jmolModel = getJmolData();
91 jmolModel.openReader(getDataName(), getDataName(), getReader());
92 waitForScript(jmolModel);
95 * Convert one or more Jmol Model objects to Jalview sequences
97 if (jmolModel.ms.mc > 0)
102 // setStructureFileType(jmolModel.evalString("show _fileType"));
103 // } catch (Exception q)
107 // instead, we distinguish .cif from non-.cif by filename
108 setStructureFileType(getDataName().toLowerCase().endsWith(".cif") ? PDBEntry.Type.MMCIF
109 .toString() : "PDB");
111 transformJmolModelToJalview(jmolModel.ms);
116 * create a headless jmol instance for dataprocessing
120 private Viewer getJmolData()
127 * params -o (output to sysout) -i (no info logging, less verbose)
128 * -n (nodisplay) -x (exit when finished)
129 * see http://wiki.jmol.org/index.php/Jmol_Application
131 viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
132 null, "-x -o -n -i", this);
133 // ensure the 'new' (DSSP) not 'old' (Ramachandran) SS method is used
134 viewer.setBooleanProperty("defaultStructureDSSP", true);
135 } catch (ClassCastException x)
137 throw new Error(MessageManager.formatMessage(
138 "error.jmol_version_not_compatible_with_jalview_version",
139 new String[] { JmolViewer.getJmolVersion() }), x);
145 public void transformJmolModelToJalview(ModelSet ms) throws IOException
150 List<SequenceI> rna = new ArrayList<SequenceI>();
151 List<SequenceI> prot = new ArrayList<SequenceI>();
153 String pdbId = (String) ms.getInfo(0, "title");
157 setId(safeName(getDataName()));
163 List<Atom> significantAtoms = convertSignificantAtoms(ms);
164 for (Atom tmpatom : significantAtoms)
168 tmpchain = findChain(tmpatom.chain);
169 if (tmpatom.resNumIns.trim().equals(lastID))
171 // phosphorylated protein - seen both CA and P..
174 tmpchain.atoms.addElement(tmpatom);
175 } catch (Exception e)
177 tmpchain = new PDBChain(getId(), tmpatom.chain);
178 getChains().add(tmpchain);
179 tmpchain.atoms.addElement(tmpatom);
181 lastID = tmpatom.resNumIns.trim();
188 for (PDBChain chain : getChains())
190 SequenceI chainseq = postProcessChain(chain);
200 if (StructureImportSettings.isProcessSecondaryStructure())
202 createAnnotation(chainseq, chain, ms.at);
205 } catch (OutOfMemoryError er)
208 .println("OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
209 throw new IOException(
211 .getString("exception.outofmemory_loading_mmcif_file"));
215 private List<Atom> convertSignificantAtoms(ModelSet ms)
217 List<Atom> significantAtoms = new ArrayList<Atom>();
218 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
219 org.jmol.modelset.Atom prevAtom = null;
220 for (org.jmol.modelset.Atom atom : ms.at)
222 if (atom.getAtomName().equalsIgnoreCase("CA")
223 || atom.getAtomName().equalsIgnoreCase("P"))
225 if (!atomValidated(atom, prevAtom, chainTerMap))
229 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
230 curAtom.atomIndex = atom.getIndex();
231 curAtom.chain = atom.getChainIDStr();
232 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
233 : atom.group.getInsertionCode();
234 curAtom.name = atom.getAtomName();
235 curAtom.number = atom.getAtomNumber();
236 curAtom.resName = atom.getGroup3(true);
237 curAtom.resNumber = atom.getResno();
238 curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
239 .getIndex()] : Float.valueOf(atom.getOccupancy100());
240 String fmt = new Format("%4i").form(curAtom.resNumber);
241 curAtom.resNumIns = (fmt + curAtom.insCode);
242 curAtom.tfactor = atom.getBfactor100() / 100f;
244 // significantAtoms.add(curAtom);
245 // ignore atoms from subsequent models
246 if (!significantAtoms.contains(curAtom))
248 significantAtoms.add(curAtom);
253 return significantAtoms;
256 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
257 org.jmol.modelset.Atom prevAtom,
258 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
260 // System.out.println("Atom: " + curAtom.getAtomNumber()
261 // + " Last atom index " + curAtom.group.lastAtomIndex);
262 if (chainTerMap == null || prevAtom == null)
266 String curAtomChId = curAtom.getChainIDStr();
267 String prevAtomChId = prevAtom.getChainIDStr();
268 // new chain encoutered
269 if (!prevAtomChId.equals(curAtomChId))
271 // On chain switch add previous chain termination to xTerMap if not exists
272 if (!chainTerMap.containsKey(prevAtomChId))
274 chainTerMap.put(prevAtomChId, prevAtom);
276 // if current atom belongs to an already terminated chain and the resNum
277 // diff < 5 then mark as valid and update termination Atom
278 if (chainTerMap.containsKey(curAtomChId))
280 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
284 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
286 chainTerMap.put(curAtomChId, curAtom);
292 // atom with previously terminated chain encountered
293 else if (chainTerMap.containsKey(curAtomChId))
295 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
299 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
301 chainTerMap.put(curAtomChId, curAtom);
306 // HETATM with resNum jump > 2
307 return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
311 private void createAnnotation(SequenceI sequence, PDBChain chain,
312 org.jmol.modelset.Atom[] jmolAtoms)
314 char[] secstr = new char[sequence.getLength()];
315 char[] secstrcode = new char[sequence.getLength()];
317 // Ensure Residue size equals Seq size
318 if (chain.residues.size() != sequence.getLength())
323 for (Residue residue : chain.residues)
325 Atom repAtom = residue.getAtoms().get(0);
326 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
327 .getProteinStructureSubType();
328 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
332 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
333 secstrcode, chain.id, sequence.getStart());
337 * Helper method that adds an AlignmentAnnotation for secondary structure to
338 * the sequence, provided at least one secondary structure prediction has been
349 protected void addSecondaryStructureAnnotation(String modelTitle,
350 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
353 char[] seq = sq.getSequence();
354 boolean ssFound = false;
355 Annotation asecstr[] = new Annotation[seq.length + firstResNum - 1];
356 for (int p = 0; p < seq.length; p++)
358 if (secstr[p] >= 'A' && secstr[p] <= 'z')
362 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
363 secstrcode[p], Float.NaN);
365 } catch (Exception e)
367 // e.printStackTrace();
374 String mt = modelTitle == null ? getDataName() : modelTitle;
376 AlignmentAnnotation ann = new AlignmentAnnotation(
377 "Secondary Structure", "Secondary Structure for " + mt,
379 ann.belowAlignment = true;
381 ann.autoCalculated = false;
382 ann.setCalcId(getClass().getName());
383 ann.adjustForAlignment();
384 ann.validateRangeAndDisplay();
385 annotations.add(ann);
386 sq.addAlignmentAnnotation(ann);
390 private void waitForScript(Viewer jmd)
392 while (jmd.isScriptExecuting())
398 } catch (InterruptedException x)
405 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
406 * secondary structure arrays at the given sequence position
408 * @param proteinStructureSubType
413 protected void setSecondaryStructure(STR proteinStructureSubType,
414 int pos, char[] secstr, char[] secstrcode)
416 switch (proteinStructureSubType)
435 switch (proteinStructureSubType)
441 secstrcode[pos] = 'H';
444 secstrcode[pos] = 'E';
452 * Convert any non-standard peptide codes to their standard code table
453 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
455 * @param threeLetterCode
459 protected void replaceNonCanonicalResidue(String threeLetterCode,
462 String canonical = ResidueProperties
463 .getCanonicalAminoAcid(threeLetterCode);
464 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
466 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
471 * Not implemented - returns null
474 public String print()
483 public void setCallbackFunction(String callbackType,
484 String callbackFunction)
489 public void notifyCallback(CBK cbType, Object[] data)
491 String strInfo = (data == null || data[1] == null ? null : data[1]
496 sendConsoleEcho(strInfo);
499 notifyScriptTermination((String) data[2],
500 ((Integer) data[3]).intValue());
503 String mystatus = (String) data[3];
504 if (mystatus.indexOf("Picked") >= 0
505 || mystatus.indexOf("Sequence") >= 0)
508 sendConsoleMessage(strInfo);
510 else if (mystatus.indexOf("Completed") >= 0)
512 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
513 strInfo.length() - 1));
517 sendConsoleMessage(data == null ? null : strInfo);
520 sendConsoleMessage(strInfo);
527 String lastConsoleEcho = "";
529 private void sendConsoleEcho(String string)
531 lastConsoleEcho += string;
532 lastConsoleEcho += "\n";
535 String lastConsoleMessage = "";
537 private void sendConsoleMessage(String string)
539 lastConsoleMessage += string;
540 lastConsoleMessage += "\n";
543 int lastScriptTermination = -1;
545 String lastScriptMessage = "";
547 private void notifyScriptTermination(String string, int intValue)
549 lastScriptMessage += string;
550 lastScriptMessage += "\n";
551 lastScriptTermination = intValue;
555 public boolean notifyEnabled(CBK callbackPick)
557 switch (callbackPick)
571 * Not implemented - returns null
574 public String eval(String strEval)
580 * Not implemented - returns null
583 public float[][] functionXY(String functionName, int x, int y)
589 * Not implemented - returns null
592 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
598 * Not implemented - returns null
601 public String createImage(String fileName, String imageType,
602 Object text_or_bytes, int quality)
608 * Not implemented - returns null
611 public Map<String, Object> getRegistryInfo()
620 public void showUrl(String url)
625 * Not implemented - returns null
628 public Dimension resizeInnerPanel(String data)
634 public Map<String, Object> getJSpecViewProperty(String arg0)
639 public boolean isPredictSecondaryStructure()
641 return predictSecondaryStructure;
644 public void setPredictSecondaryStructure(boolean predictSecondaryStructure)
646 this.predictSecondaryStructure = predictSecondaryStructure;
649 public boolean isVisibleChainAnnotation()
651 return visibleChainAnnotation;
654 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
656 this.visibleChainAnnotation = visibleChainAnnotation;