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");
156 setId(safeName(getDataName()));
162 List<Atom> significantAtoms = convertSignificantAtoms(ms);
163 for (Atom tmpatom : significantAtoms)
167 tmpchain = findChain(tmpatom.chain);
168 if (tmpatom.resNumIns.trim().equals(lastID))
170 // phosphorylated protein - seen both CA and P..
173 tmpchain.atoms.addElement(tmpatom);
174 } catch (Exception e)
176 tmpchain = new PDBChain(getId(), tmpatom.chain);
177 getChains().add(tmpchain);
178 tmpchain.atoms.addElement(tmpatom);
180 lastID = tmpatom.resNumIns.trim();
187 for (PDBChain chain : getChains())
189 SequenceI chainseq = postProcessChain(chain);
199 if (StructureImportSettings.isProcessSecondaryStructure())
201 createAnnotation(chainseq, chain, ms.at);
204 } catch (OutOfMemoryError er)
207 .println("OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
208 throw new IOException(
210 .getString("exception.outofmemory_loading_mmcif_file"));
214 private List<Atom> convertSignificantAtoms(ModelSet ms)
216 List<Atom> significantAtoms = new ArrayList<Atom>();
217 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
218 org.jmol.modelset.Atom prevAtom = null;
219 for (org.jmol.modelset.Atom atom : ms.at)
221 if (atom.getAtomName().equalsIgnoreCase("CA")
222 || atom.getAtomName().equalsIgnoreCase("P"))
224 if (!atomValidated(atom, prevAtom, chainTerMap))
228 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
229 curAtom.atomIndex = atom.getIndex();
230 curAtom.chain = atom.getChainIDStr();
231 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
232 : atom.group.getInsertionCode();
233 curAtom.name = atom.getAtomName();
234 curAtom.number = atom.getAtomNumber();
235 curAtom.resName = atom.getGroup3(true);
236 curAtom.resNumber = atom.getResno();
237 curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
238 .getIndex()] : Float.valueOf(atom.getOccupancy100());
239 String fmt = new Format("%4i").form(curAtom.resNumber);
240 curAtom.resNumIns = (fmt + curAtom.insCode);
241 curAtom.tfactor = atom.getBfactor100() / 100f;
243 // significantAtoms.add(curAtom);
244 // ignore atoms from subsequent models
245 if (!significantAtoms.contains(curAtom))
247 significantAtoms.add(curAtom);
252 return significantAtoms;
255 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
256 org.jmol.modelset.Atom prevAtom,
257 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
259 // System.out.println("Atom: " + curAtom.getAtomNumber()
260 // + " Last atom index " + curAtom.group.lastAtomIndex);
261 if (chainTerMap == null || prevAtom == null)
265 String curAtomChId = curAtom.getChainIDStr();
266 String prevAtomChId = prevAtom.getChainIDStr();
267 // new chain encoutered
268 if (!prevAtomChId.equals(curAtomChId))
270 // On chain switch add previous chain termination to xTerMap if not exists
271 if (!chainTerMap.containsKey(prevAtomChId))
273 chainTerMap.put(prevAtomChId, prevAtom);
275 // if current atom belongs to an already terminated chain and the resNum
276 // diff < 5 then mark as valid and update termination Atom
277 if (chainTerMap.containsKey(curAtomChId))
279 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
283 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
285 chainTerMap.put(curAtomChId, curAtom);
291 // atom with previously terminated chain encountered
292 else if (chainTerMap.containsKey(curAtomChId))
294 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
298 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
300 chainTerMap.put(curAtomChId, curAtom);
305 // HETATM with resNum jump > 2
306 return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
310 private void createAnnotation(SequenceI sequence, PDBChain chain,
311 org.jmol.modelset.Atom[] jmolAtoms)
313 char[] secstr = new char[sequence.getLength()];
314 char[] secstrcode = new char[sequence.getLength()];
316 // Ensure Residue size equals Seq size
317 if (chain.residues.size() != sequence.getLength())
322 for (Residue residue : chain.residues)
324 Atom repAtom = residue.getAtoms().get(0);
325 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
326 .getProteinStructureSubType();
327 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
331 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
332 secstrcode, chain.id, sequence.getStart());
336 * Helper method that adds an AlignmentAnnotation for secondary structure to
337 * the sequence, provided at least one secondary structure prediction has been
348 protected void addSecondaryStructureAnnotation(String modelTitle,
349 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
352 char[] seq = sq.getSequence();
353 boolean ssFound = false;
354 Annotation asecstr[] = new Annotation[seq.length + firstResNum - 1];
355 for (int p = 0; p < seq.length; p++)
357 if (secstr[p] >= 'A' && secstr[p] <= 'z')
361 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
362 secstrcode[p], Float.NaN);
364 } catch (Exception e)
366 // e.printStackTrace();
373 String mt = modelTitle == null ? getDataName() : modelTitle;
375 AlignmentAnnotation ann = new AlignmentAnnotation(
376 "Secondary Structure", "Secondary Structure for " + mt,
378 ann.belowAlignment = true;
380 ann.autoCalculated = false;
381 ann.setCalcId(getClass().getName());
382 ann.adjustForAlignment();
383 ann.validateRangeAndDisplay();
384 annotations.add(ann);
385 sq.addAlignmentAnnotation(ann);
389 private void waitForScript(Viewer jmd)
391 while (jmd.isScriptExecuting())
397 } catch (InterruptedException x)
404 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
405 * secondary structure arrays at the given sequence position
407 * @param proteinStructureSubType
412 protected void setSecondaryStructure(STR proteinStructureSubType,
413 int pos, char[] secstr, char[] secstrcode)
415 switch (proteinStructureSubType)
434 switch (proteinStructureSubType)
440 secstrcode[pos] = 'H';
443 secstrcode[pos] = 'E';
451 * Convert any non-standard peptide codes to their standard code table
452 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
454 * @param threeLetterCode
458 protected void replaceNonCanonicalResidue(String threeLetterCode,
461 String canonical = ResidueProperties
462 .getCanonicalAminoAcid(threeLetterCode);
463 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
465 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
470 * Not implemented - returns null
473 public String print()
482 public void setCallbackFunction(String callbackType,
483 String callbackFunction)
488 public void notifyCallback(CBK cbType, Object[] data)
490 String strInfo = (data == null || data[1] == null ? null : data[1]
495 sendConsoleEcho(strInfo);
498 notifyScriptTermination((String) data[2],
499 ((Integer) data[3]).intValue());
502 String mystatus = (String) data[3];
503 if (mystatus.indexOf("Picked") >= 0
504 || mystatus.indexOf("Sequence") >= 0)
507 sendConsoleMessage(strInfo);
509 else if (mystatus.indexOf("Completed") >= 0)
511 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
512 strInfo.length() - 1));
516 sendConsoleMessage(data == null ? null : strInfo);
519 sendConsoleMessage(strInfo);
526 String lastConsoleEcho = "";
528 private void sendConsoleEcho(String string)
530 lastConsoleEcho += string;
531 lastConsoleEcho += "\n";
534 String lastConsoleMessage = "";
536 private void sendConsoleMessage(String string)
538 lastConsoleMessage += string;
539 lastConsoleMessage += "\n";
542 int lastScriptTermination = -1;
544 String lastScriptMessage = "";
546 private void notifyScriptTermination(String string, int intValue)
548 lastScriptMessage += string;
549 lastScriptMessage += "\n";
550 lastScriptTermination = intValue;
554 public boolean notifyEnabled(CBK callbackPick)
556 switch (callbackPick)
570 * Not implemented - returns null
573 public String eval(String strEval)
579 * Not implemented - returns null
582 public float[][] functionXY(String functionName, int x, int y)
588 * Not implemented - returns null
591 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
597 * Not implemented - returns null
600 public String createImage(String fileName, String imageType,
601 Object text_or_bytes, int quality)
607 * Not implemented - returns null
610 public Map<String, Object> getRegistryInfo()
619 public void showUrl(String url)
624 * Not implemented - returns null
627 public Dimension resizeInnerPanel(String data)
633 public Map<String, Object> getJSpecViewProperty(String arg0)
638 public boolean isPredictSecondaryStructure()
640 return predictSecondaryStructure;
643 public void setPredictSecondaryStructure(boolean predictSecondaryStructure)
645 this.predictSecondaryStructure = predictSecondaryStructure;
648 public boolean isVisibleChainAnnotation()
650 return visibleChainAnnotation;
653 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
655 this.visibleChainAnnotation = visibleChainAnnotation;