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) -n (nodisplay) -x (exit when finished)
128 * see http://wiki.jmol.org/index.php/Jmol_Application
130 viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
131 null, "-x -o -n", this);
132 // ensure the 'new' (DSSP) not 'old' (Ramachandran) SS method is used
133 viewer.setBooleanProperty("defaultStructureDSSP", true);
134 } catch (ClassCastException x)
136 throw new Error(MessageManager.formatMessage(
137 "error.jmol_version_not_compatible_with_jalview_version",
138 new String[] { JmolViewer.getJmolVersion() }), x);
144 public void transformJmolModelToJalview(ModelSet ms) throws IOException
149 List<SequenceI> rna = new ArrayList<SequenceI>();
150 List<SequenceI> prot = new ArrayList<SequenceI>();
152 String pdbId = (String) ms.getInfo(0, "title");
154 List<Atom> significantAtoms = convertSignificantAtoms(ms);
155 for (Atom tmpatom : significantAtoms)
159 tmpchain = findChain(tmpatom.chain);
160 if (tmpatom.resNumIns.trim().equals(lastID))
162 // phosphorylated protein - seen both CA and P..
165 tmpchain.atoms.addElement(tmpatom);
166 } catch (Exception e)
168 tmpchain = new PDBChain(pdbId, tmpatom.chain);
169 getChains().add(tmpchain);
170 tmpchain.atoms.addElement(tmpatom);
172 lastID = tmpatom.resNumIns.trim();
181 setId(safeName(getDataName()));
183 for (PDBChain chain : getChains())
185 SequenceI chainseq = postProcessChain(chain);
195 if (StructureImportSettings.isProcessSecondaryStructure())
197 createAnnotation(chainseq, chain, ms.at);
200 } catch (OutOfMemoryError er)
203 .println("OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
204 throw new IOException(
206 .getString("exception.outofmemory_loading_mmcif_file"));
210 private List<Atom> convertSignificantAtoms(ModelSet ms)
212 List<Atom> significantAtoms = new ArrayList<Atom>();
213 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
214 org.jmol.modelset.Atom prevAtom = null;
215 for (org.jmol.modelset.Atom atom : ms.at)
217 if (atom.getAtomName().equalsIgnoreCase("CA")
218 || atom.getAtomName().equalsIgnoreCase("P"))
220 if (!atomValidated(atom, prevAtom, chainTerMap))
224 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
225 curAtom.atomIndex = atom.getIndex();
226 curAtom.chain = atom.getChainIDStr();
227 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
228 : atom.group.getInsertionCode();
229 curAtom.name = atom.getAtomName();
230 curAtom.number = atom.getAtomNumber();
231 curAtom.resName = atom.getGroup3(true);
232 curAtom.resNumber = atom.getResno();
233 curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
234 .getIndex()] : Float.valueOf(atom.getOccupancy100());
235 String fmt = new Format("%4i").form(curAtom.resNumber);
236 curAtom.resNumIns = (fmt + curAtom.insCode);
237 curAtom.tfactor = atom.getBfactor100() / 100f;
239 // significantAtoms.add(curAtom);
240 // ignore atoms from subsequent models
241 if (!significantAtoms.contains(curAtom))
243 significantAtoms.add(curAtom);
248 return significantAtoms;
251 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
252 org.jmol.modelset.Atom prevAtom,
253 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
255 // System.out.println("Atom: " + curAtom.getAtomNumber()
256 // + " Last atom index " + curAtom.group.lastAtomIndex);
257 if (chainTerMap == null || prevAtom == null)
261 String curAtomChId = curAtom.getChainIDStr();
262 String prevAtomChId = prevAtom.getChainIDStr();
263 // new chain encoutered
264 if (!prevAtomChId.equals(curAtomChId))
266 // On chain switch add previous chain termination to xTerMap if not exists
267 if (!chainTerMap.containsKey(prevAtomChId))
269 chainTerMap.put(prevAtomChId, prevAtom);
271 // if current atom belongs to an already terminated chain and the resNum
272 // diff < 5 then mark as valid and update termination Atom
273 if (chainTerMap.containsKey(curAtomChId))
275 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
279 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
281 chainTerMap.put(curAtomChId, curAtom);
287 // atom with previously terminated chain encountered
288 else if (chainTerMap.containsKey(curAtomChId))
290 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
294 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
296 chainTerMap.put(curAtomChId, curAtom);
301 // HETATM with resNum jump > 2
302 return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
306 private void createAnnotation(SequenceI sequence, PDBChain chain,
307 org.jmol.modelset.Atom[] jmolAtoms)
309 char[] secstr = new char[sequence.getLength()];
310 char[] secstrcode = new char[sequence.getLength()];
312 // Ensure Residue size equals Seq size
313 if (chain.residues.size() != sequence.getLength())
318 for (Residue residue : chain.residues)
320 Atom repAtom = residue.getAtoms().get(0);
321 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
322 .getProteinStructureSubType();
323 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
327 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
328 secstrcode, chain.id, sequence.getStart());
332 * Helper method that adds an AlignmentAnnotation for secondary structure to
333 * the sequence, provided at least one secondary structure prediction has been
344 protected void addSecondaryStructureAnnotation(String modelTitle,
345 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
348 char[] seq = sq.getSequence();
349 boolean ssFound = false;
350 Annotation asecstr[] = new Annotation[seq.length + firstResNum - 1];
351 for (int p = 0; p < seq.length; p++)
353 if (secstr[p] >= 'A' && secstr[p] <= 'z')
357 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
358 secstrcode[p], Float.NaN);
360 } catch (Exception e)
362 // e.printStackTrace();
369 String mt = modelTitle == null ? getDataName() : modelTitle;
371 AlignmentAnnotation ann = new AlignmentAnnotation(
372 "Secondary Structure", "Secondary Structure for " + mt,
374 ann.belowAlignment = true;
376 ann.autoCalculated = false;
377 ann.setCalcId(getClass().getName());
378 ann.adjustForAlignment();
379 ann.validateRangeAndDisplay();
380 annotations.add(ann);
381 sq.addAlignmentAnnotation(ann);
385 private void waitForScript(Viewer jmd)
387 while (jmd.isScriptExecuting())
393 } catch (InterruptedException x)
400 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
401 * secondary structure arrays at the given sequence position
403 * @param proteinStructureSubType
408 protected void setSecondaryStructure(STR proteinStructureSubType,
409 int pos, char[] secstr, char[] secstrcode)
411 switch (proteinStructureSubType)
430 switch (proteinStructureSubType)
436 secstrcode[pos] = 'H';
439 secstrcode[pos] = 'E';
447 * Convert any non-standard peptide codes to their standard code table
448 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
450 * @param threeLetterCode
454 protected void replaceNonCanonicalResidue(String threeLetterCode,
457 String canonical = ResidueProperties
458 .getCanonicalAminoAcid(threeLetterCode);
459 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
461 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
466 * Not implemented - returns null
469 public String print()
478 public void setCallbackFunction(String callbackType,
479 String callbackFunction)
484 public void notifyCallback(CBK cbType, Object[] data)
486 String strInfo = (data == null || data[1] == null ? null : data[1]
491 sendConsoleEcho(strInfo);
494 notifyScriptTermination((String) data[2],
495 ((Integer) data[3]).intValue());
498 String mystatus = (String) data[3];
499 if (mystatus.indexOf("Picked") >= 0
500 || mystatus.indexOf("Sequence") >= 0)
503 sendConsoleMessage(strInfo);
505 else if (mystatus.indexOf("Completed") >= 0)
507 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
508 strInfo.length() - 1));
512 sendConsoleMessage(data == null ? null : strInfo);
515 sendConsoleMessage(strInfo);
522 String lastConsoleEcho = "";
524 private void sendConsoleEcho(String string)
526 lastConsoleEcho += string;
527 lastConsoleEcho += "\n";
530 String lastConsoleMessage = "";
532 private void sendConsoleMessage(String string)
534 lastConsoleMessage += string;
535 lastConsoleMessage += "\n";
538 int lastScriptTermination = -1;
540 String lastScriptMessage = "";
542 private void notifyScriptTermination(String string, int intValue)
544 lastScriptMessage += string;
545 lastScriptMessage += "\n";
546 lastScriptTermination = intValue;
550 public boolean notifyEnabled(CBK callbackPick)
552 switch (callbackPick)
566 * Not implemented - returns null
569 public String eval(String strEval)
575 * Not implemented - returns null
578 public float[][] functionXY(String functionName, int x, int y)
584 * Not implemented - returns null
587 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
593 * Not implemented - returns null
596 public String createImage(String fileName, String imageType,
597 Object text_or_bytes, int quality)
603 * Not implemented - returns null
606 public Map<String, Object> getRegistryInfo()
615 public void showUrl(String url)
620 * Not implemented - returns null
623 public Dimension resizeInnerPanel(String data)
629 public Map<String, Object> getJSpecViewProperty(String arg0)
634 public boolean isPredictSecondaryStructure()
636 return predictSecondaryStructure;
639 public void setPredictSecondaryStructure(boolean predictSecondaryStructure)
641 this.predictSecondaryStructure = predictSecondaryStructure;
644 public boolean isVisibleChainAnnotation()
646 return visibleChainAnnotation;
649 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
651 this.visibleChainAnnotation = visibleChainAnnotation;