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.MessageManager;
33 import java.io.IOException;
34 import java.util.ArrayList;
35 import java.util.HashMap;
36 import java.util.List;
38 import java.util.Vector;
40 import javajs.awt.Dimension;
42 import org.jmol.api.JmolStatusListener;
43 import org.jmol.api.JmolViewer;
44 import org.jmol.c.CBK;
45 import org.jmol.c.STR;
46 import org.jmol.modelset.ModelSet;
47 import org.jmol.viewer.Viewer;
50 import MCview.PDBChain;
51 import MCview.Residue;
54 * Import and process files with Jmol for file like PDB, mmCIF
59 public class JmolParser extends StructureFile implements JmolStatusListener
63 public JmolParser(boolean addAlignmentAnnotations, boolean predictSecStr,
64 boolean externalSecStr, String inFile, String type)
70 public JmolParser(boolean addAlignmentAnnotations, boolean predictSecStr,
71 boolean externalSecStr, FileParse fp) throws IOException
81 * Calls the Jmol library to parse the PDB/mmCIF file, and then inspects the
82 * resulting object model to generate Jalview-style sequences, with secondary
83 * structure annotation added where available (i.e. where it has been computed
84 * by Jmol using DSSP).
86 * @see jalview.io.AlignFile#parse()
89 public void parse() throws IOException
91 setChains(new Vector<PDBChain>());
92 Viewer jmolModel = getJmolData();
93 jmolModel.openReader(getDataName(), getDataName(), getReader());
94 waitForScript(jmolModel);
97 * Convert one or more Jmol Model objects to Jalview sequences
99 if (jmolModel.ms.mc > 0)
101 // ideally we do this
104 // setStructureFileType(jmolModel.evalString("show _fileType"));
105 // } catch (Exception q)
109 // instead, we distinguish .cif from non-.cif by filename
110 setStructureFileType(getDataName().toLowerCase().endsWith(".cif") ? PDBEntry.Type.MMCIF
111 .toString() : "PDB");
113 transformJmolModelToJalview(jmolModel.ms);
118 * create a headless jmol instance for dataprocessing
122 private Viewer getJmolData()
128 viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
129 null, "-x -o -n", this);
130 // ensure the 'new' (DSSP) not 'old' (Ramachandran) SS method is used
131 viewer.setBooleanProperty("defaultStructureDSSP", true);
132 } catch (ClassCastException x)
134 throw new Error(MessageManager.formatMessage(
135 "error.jmol_version_not_compatible_with_jalview_version",
136 new String[] { JmolViewer.getJmolVersion() }), x);
142 public void transformJmolModelToJalview(ModelSet ms) throws IOException
147 List<SequenceI> rna = new ArrayList<SequenceI>();
148 List<SequenceI> prot = new ArrayList<SequenceI>();
150 String pdbId = (String) ms.getInfo(0, "title");
152 List<Atom> significantAtoms = convertSignificantAtoms(ms);
153 for (Atom tmpatom : significantAtoms)
157 tmpchain = findChain(tmpatom.chain);
158 if (tmpatom.resNumIns.trim().equals(lastID))
160 // phosphorylated protein - seen both CA and P..
163 tmpchain.atoms.addElement(tmpatom);
164 } catch (Exception e)
166 tmpchain = new PDBChain(pdbId, tmpatom.chain);
167 getChains().add(tmpchain);
168 tmpchain.atoms.addElement(tmpatom);
170 lastID = tmpatom.resNumIns.trim();
179 setId(safeName(getDataName()));
181 for (PDBChain chain : getChains())
183 SequenceI chainseq = postProcessChain(chain);
193 if (StructureImportSettings.isProcessSecondaryStructure())
195 createAnnotation(chainseq, chain, ms.at);
198 } catch (OutOfMemoryError er)
201 .println("OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
202 throw new IOException(
204 .getString("exception.outofmemory_loading_mmcif_file"));
208 private List<Atom> convertSignificantAtoms(ModelSet ms)
210 List<Atom> significantAtoms = new ArrayList<Atom>();
211 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
212 org.jmol.modelset.Atom prevAtom = null;
213 for (org.jmol.modelset.Atom atom : ms.at)
215 if (atom.getAtomName().equalsIgnoreCase("CA")
216 || atom.getAtomName().equalsIgnoreCase("P"))
218 if (!atomValidated(atom, prevAtom, chainTerMap))
222 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
223 curAtom.atomIndex = atom.getIndex();
224 curAtom.chain = atom.getChainIDStr();
225 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
226 : atom.group.getInsertionCode();
227 curAtom.name = atom.getAtomName();
228 curAtom.number = atom.getAtomNumber();
229 curAtom.resName = atom.getGroup3(true);
230 curAtom.resNumber = atom.getResno();
231 curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
232 .getIndex()] : Float.valueOf(atom.getOccupancy100());
233 curAtom.resNumIns = ("" + curAtom.resNumber + curAtom.insCode)
235 curAtom.tfactor = atom.getBfactor100() / 100f;
237 // significantAtoms.add(curAtom);
238 // ignore atoms from subsequent models
239 if (!significantAtoms.contains(curAtom))
241 significantAtoms.add(curAtom);
246 return significantAtoms;
249 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
250 org.jmol.modelset.Atom prevAtom,
251 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
253 // System.out.println("Atom: " + curAtom.getAtomNumber()
254 // + " Last atom index " + curAtom.group.lastAtomIndex);
255 if (chainTerMap == null || prevAtom == null)
259 String curAtomChId = curAtom.getChainIDStr();
260 String prevAtomChId = prevAtom.getChainIDStr();
261 // new chain encoutered
262 if (!prevAtomChId.equals(curAtomChId))
264 // On chain switch add previous chain termination to xTerMap if not exists
265 if (!chainTerMap.containsKey(prevAtomChId))
267 chainTerMap.put(prevAtomChId, prevAtom);
269 // if current atom belongs to an already terminated chain and the resNum
270 // diff < 5 then mark as valid and update termination Atom
271 if (chainTerMap.containsKey(curAtomChId))
273 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
277 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
279 chainTerMap.put(curAtomChId, curAtom);
285 // atom with previously terminated chain encountered
286 else if (chainTerMap.containsKey(curAtomChId))
288 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
292 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
294 chainTerMap.put(curAtomChId, curAtom);
299 // HETATM with resNum jump > 2
300 return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
304 private void createAnnotation(SequenceI sequence, PDBChain chain,
305 org.jmol.modelset.Atom[] jmolAtoms)
307 char[] secstr = new char[sequence.getLength()];
308 char[] secstrcode = new char[sequence.getLength()];
310 // Ensure Residue size equals Seq size
311 if (chain.residues.size() != sequence.getLength())
316 for (Residue residue : chain.residues)
318 Atom repAtom = residue.getAtoms().get(0);
319 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
320 .getProteinStructureSubType();
321 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
325 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
326 secstrcode, chain.id, sequence.getStart());
330 * Helper method that adds an AlignmentAnnotation for secondary structure to
331 * the sequence, provided at least one secondary structure prediction has been
342 protected void addSecondaryStructureAnnotation(String modelTitle,
343 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
346 char[] seq = sq.getSequence();
347 boolean ssFound = false;
348 Annotation asecstr[] = new Annotation[seq.length + firstResNum - 1];
349 for (int p = 0; p < seq.length; p++)
351 if (secstr[p] >= 'A' && secstr[p] <= 'z')
355 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
356 secstrcode[p], Float.NaN);
358 } catch (Exception e)
360 // e.printStackTrace();
367 String mt = modelTitle == null ? getDataName() : modelTitle;
369 AlignmentAnnotation ann = new AlignmentAnnotation(
370 "Secondary Structure", "Secondary Structure for " + mt,
372 ann.belowAlignment = true;
374 ann.autoCalculated = false;
375 ann.setCalcId(getClass().getName());
376 ann.adjustForAlignment();
377 ann.validateRangeAndDisplay();
378 annotations.add(ann);
379 sq.addAlignmentAnnotation(ann);
383 private void waitForScript(Viewer jmd)
385 while (jmd.isScriptExecuting())
391 } catch (InterruptedException x)
398 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
399 * secondary structure arrays at the given sequence position
401 * @param proteinStructureSubType
406 protected void setSecondaryStructure(STR proteinStructureSubType,
407 int pos, char[] secstr, char[] secstrcode)
409 switch (proteinStructureSubType)
428 switch (proteinStructureSubType)
434 secstrcode[pos] = 'H';
437 secstrcode[pos] = 'E';
445 * Convert any non-standard peptide codes to their standard code table
446 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
448 * @param threeLetterCode
452 protected void replaceNonCanonicalResidue(String threeLetterCode,
455 String canonical = ResidueProperties
456 .getCanonicalAminoAcid(threeLetterCode);
457 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
459 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
464 * Not implemented - returns null
467 public String print()
476 public void setCallbackFunction(String callbackType,
477 String callbackFunction)
482 public void notifyCallback(CBK cbType, Object[] data)
484 String strInfo = (data == null || data[1] == null ? null : data[1]
489 sendConsoleEcho(strInfo);
492 notifyScriptTermination((String) data[2],
493 ((Integer) data[3]).intValue());
496 String mystatus = (String) data[3];
497 if (mystatus.indexOf("Picked") >= 0
498 || mystatus.indexOf("Sequence") >= 0)
501 sendConsoleMessage(strInfo);
503 else if (mystatus.indexOf("Completed") >= 0)
505 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
506 strInfo.length() - 1));
510 sendConsoleMessage(data == null ? null : strInfo);
513 sendConsoleMessage(strInfo);
520 String lastConsoleEcho = "";
522 private void sendConsoleEcho(String string)
524 lastConsoleEcho += string;
525 lastConsoleEcho += "\n";
528 String lastConsoleMessage = "";
530 private void sendConsoleMessage(String string)
532 lastConsoleMessage += string;
533 lastConsoleMessage += "\n";
536 int lastScriptTermination = -1;
538 String lastScriptMessage = "";
540 private void notifyScriptTermination(String string, int intValue)
542 lastScriptMessage += string;
543 lastScriptMessage += "\n";
544 lastScriptTermination = intValue;
548 public boolean notifyEnabled(CBK callbackPick)
550 switch (callbackPick)
564 * Not implemented - returns null
567 public String eval(String strEval)
573 * Not implemented - returns null
576 public float[][] functionXY(String functionName, int x, int y)
582 * Not implemented - returns null
585 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
591 * Not implemented - returns null
594 public String createImage(String fileName, String imageType,
595 Object text_or_bytes, int quality)
601 * Not implemented - returns null
604 public Map<String, Object> getRegistryInfo()
613 public void showUrl(String url)
618 * Not implemented - returns null
621 public Dimension resizeInnerPanel(String data)
627 public Map<String, Object> getJSpecViewProperty(String arg0)
632 public boolean isPredictSecondaryStructure()
634 return predictSecondaryStructure;
637 public void setPredictSecondaryStructure(boolean predictSecondaryStructure)
639 this.predictSecondaryStructure = predictSecondaryStructure;
642 public boolean isVisibleChainAnnotation()
644 return visibleChainAnnotation;
647 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
649 this.visibleChainAnnotation = visibleChainAnnotation;