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)
70 public JmolParser(FileParse fp) throws IOException
80 * Calls the Jmol library to parse the PDB/mmCIF file, and then inspects the
81 * resulting object model to generate Jalview-style sequences, with secondary
82 * structure annotation added where available (i.e. where it has been computed
83 * by Jmol using DSSP).
85 * @see jalview.io.AlignFile#parse()
88 public void parse() throws IOException
90 setChains(new Vector<PDBChain>());
91 Viewer jmolModel = getJmolData();
92 jmolModel.openReader(getDataName(), getDataName(), getReader());
93 waitForScript(jmolModel);
96 * Convert one or more Jmol Model objects to Jalview sequences
98 if (jmolModel.ms.mc > 0)
100 // ideally we do this
103 // setStructureFileType(jmolModel.evalString("show _fileType"));
104 // } catch (Exception q)
108 // instead, we distinguish .cif from non-.cif by filename
109 setStructureFileType(getDataName().toLowerCase().endsWith(".cif") ? PDBEntry.Type.MMCIF
110 .toString() : "PDB");
112 transformJmolModelToJalview(jmolModel.ms);
117 * create a headless jmol instance for dataprocessing
121 private Viewer getJmolData()
128 * params -o (output to sysout) -i (no info logging, less verbose)
129 * -n (nodisplay) -x (exit when finished)
130 * see http://wiki.jmol.org/index.php/Jmol_Application
132 viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
133 null, "-x -o -n -i", this);
134 // ensure the 'new' (DSSP) not 'old' (Ramachandran) SS method is used
135 viewer.setBooleanProperty("defaultStructureDSSP", true);
136 } catch (ClassCastException x)
138 throw new Error(MessageManager.formatMessage(
139 "error.jmol_version_not_compatible_with_jalview_version",
140 new String[] { JmolViewer.getJmolVersion() }), x);
146 public void transformJmolModelToJalview(ModelSet ms) throws IOException
151 List<SequenceI> rna = new ArrayList<SequenceI>();
152 List<SequenceI> prot = new ArrayList<SequenceI>();
154 String pdbId = (String) ms.getInfo(0, "title");
156 List<Atom> significantAtoms = convertSignificantAtoms(ms);
157 for (Atom tmpatom : significantAtoms)
161 tmpchain = findChain(tmpatom.chain);
162 if (tmpatom.resNumIns.trim().equals(lastID))
164 // phosphorylated protein - seen both CA and P..
167 tmpchain.atoms.addElement(tmpatom);
168 } catch (Exception e)
170 tmpchain = new PDBChain(pdbId, tmpatom.chain);
171 getChains().add(tmpchain);
172 tmpchain.atoms.addElement(tmpatom);
174 lastID = tmpatom.resNumIns.trim();
183 setId(safeName(getDataName()));
185 for (PDBChain chain : getChains())
187 SequenceI chainseq = postProcessChain(chain);
197 if (StructureImportSettings.isProcessSecondaryStructure())
199 createAnnotation(chainseq, chain, ms.at);
202 } catch (OutOfMemoryError er)
205 .println("OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
206 throw new IOException(
208 .getString("exception.outofmemory_loading_mmcif_file"));
212 private List<Atom> convertSignificantAtoms(ModelSet ms)
214 List<Atom> significantAtoms = new ArrayList<Atom>();
215 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
216 org.jmol.modelset.Atom prevAtom = null;
217 for (org.jmol.modelset.Atom atom : ms.at)
219 if (atom.getAtomName().equalsIgnoreCase("CA")
220 || atom.getAtomName().equalsIgnoreCase("P"))
222 if (!atomValidated(atom, prevAtom, chainTerMap))
226 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
227 curAtom.atomIndex = atom.getIndex();
228 curAtom.chain = atom.getChainIDStr();
229 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
230 : atom.group.getInsertionCode();
231 curAtom.name = atom.getAtomName();
232 curAtom.number = atom.getAtomNumber();
233 curAtom.resName = atom.getGroup3(true);
234 curAtom.resNumber = atom.getResno();
235 curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
236 .getIndex()] : Float.valueOf(atom.getOccupancy100());
237 String fmt = new Format("%4i").form(curAtom.resNumber);
238 curAtom.resNumIns = (fmt + curAtom.insCode);
239 curAtom.tfactor = atom.getBfactor100() / 100f;
241 // significantAtoms.add(curAtom);
242 // ignore atoms from subsequent models
243 if (!significantAtoms.contains(curAtom))
245 significantAtoms.add(curAtom);
250 return significantAtoms;
253 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
254 org.jmol.modelset.Atom prevAtom,
255 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
257 // System.out.println("Atom: " + curAtom.getAtomNumber()
258 // + " Last atom index " + curAtom.group.lastAtomIndex);
259 if (chainTerMap == null || prevAtom == null)
263 String curAtomChId = curAtom.getChainIDStr();
264 String prevAtomChId = prevAtom.getChainIDStr();
265 // new chain encoutered
266 if (!prevAtomChId.equals(curAtomChId))
268 // On chain switch add previous chain termination to xTerMap if not exists
269 if (!chainTerMap.containsKey(prevAtomChId))
271 chainTerMap.put(prevAtomChId, prevAtom);
273 // if current atom belongs to an already terminated chain and the resNum
274 // diff < 5 then mark as valid and update termination Atom
275 if (chainTerMap.containsKey(curAtomChId))
277 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
281 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
283 chainTerMap.put(curAtomChId, curAtom);
289 // atom with previously terminated chain encountered
290 else if (chainTerMap.containsKey(curAtomChId))
292 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
296 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
298 chainTerMap.put(curAtomChId, curAtom);
303 // HETATM with resNum jump > 2
304 return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
308 private void createAnnotation(SequenceI sequence, PDBChain chain,
309 org.jmol.modelset.Atom[] jmolAtoms)
311 char[] secstr = new char[sequence.getLength()];
312 char[] secstrcode = new char[sequence.getLength()];
314 // Ensure Residue size equals Seq size
315 if (chain.residues.size() != sequence.getLength())
320 for (Residue residue : chain.residues)
322 Atom repAtom = residue.getAtoms().get(0);
323 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
324 .getProteinStructureSubType();
325 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
329 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
330 secstrcode, chain.id, sequence.getStart());
334 * Helper method that adds an AlignmentAnnotation for secondary structure to
335 * the sequence, provided at least one secondary structure prediction has been
346 protected void addSecondaryStructureAnnotation(String modelTitle,
347 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
350 char[] seq = sq.getSequence();
351 boolean ssFound = false;
352 Annotation asecstr[] = new Annotation[seq.length + firstResNum - 1];
353 for (int p = 0; p < seq.length; p++)
355 if (secstr[p] >= 'A' && secstr[p] <= 'z')
359 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
360 secstrcode[p], Float.NaN);
362 } catch (Exception e)
364 // e.printStackTrace();
371 String mt = modelTitle == null ? getDataName() : modelTitle;
373 AlignmentAnnotation ann = new AlignmentAnnotation(
374 "Secondary Structure", "Secondary Structure for " + mt,
376 ann.belowAlignment = true;
378 ann.autoCalculated = false;
379 ann.setCalcId(getClass().getName());
380 ann.adjustForAlignment();
381 ann.validateRangeAndDisplay();
382 annotations.add(ann);
383 sq.addAlignmentAnnotation(ann);
387 private void waitForScript(Viewer jmd)
389 while (jmd.isScriptExecuting())
395 } catch (InterruptedException x)
402 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
403 * secondary structure arrays at the given sequence position
405 * @param proteinStructureSubType
410 protected void setSecondaryStructure(STR proteinStructureSubType,
411 int pos, char[] secstr, char[] secstrcode)
413 switch (proteinStructureSubType)
432 switch (proteinStructureSubType)
438 secstrcode[pos] = 'H';
441 secstrcode[pos] = 'E';
449 * Convert any non-standard peptide codes to their standard code table
450 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
452 * @param threeLetterCode
456 protected void replaceNonCanonicalResidue(String threeLetterCode,
459 String canonical = ResidueProperties
460 .getCanonicalAminoAcid(threeLetterCode);
461 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
463 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
468 * Not implemented - returns null
471 public String print()
480 public void setCallbackFunction(String callbackType,
481 String callbackFunction)
486 public void notifyCallback(CBK cbType, Object[] data)
488 String strInfo = (data == null || data[1] == null ? null : data[1]
493 sendConsoleEcho(strInfo);
496 notifyScriptTermination((String) data[2],
497 ((Integer) data[3]).intValue());
500 String mystatus = (String) data[3];
501 if (mystatus.indexOf("Picked") >= 0
502 || mystatus.indexOf("Sequence") >= 0)
505 sendConsoleMessage(strInfo);
507 else if (mystatus.indexOf("Completed") >= 0)
509 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
510 strInfo.length() - 1));
514 sendConsoleMessage(data == null ? null : strInfo);
517 sendConsoleMessage(strInfo);
524 String lastConsoleEcho = "";
526 private void sendConsoleEcho(String string)
528 lastConsoleEcho += string;
529 lastConsoleEcho += "\n";
532 String lastConsoleMessage = "";
534 private void sendConsoleMessage(String string)
536 lastConsoleMessage += string;
537 lastConsoleMessage += "\n";
540 int lastScriptTermination = -1;
542 String lastScriptMessage = "";
544 private void notifyScriptTermination(String string, int intValue)
546 lastScriptMessage += string;
547 lastScriptMessage += "\n";
548 lastScriptTermination = intValue;
552 public boolean notifyEnabled(CBK callbackPick)
554 switch (callbackPick)
568 * Not implemented - returns null
571 public String eval(String strEval)
577 * Not implemented - returns null
580 public float[][] functionXY(String functionName, int x, int y)
586 * Not implemented - returns null
589 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
595 * Not implemented - returns null
598 public String createImage(String fileName, String imageType,
599 Object text_or_bytes, int quality)
605 * Not implemented - returns null
608 public Map<String, Object> getRegistryInfo()
617 public void showUrl(String url)
622 * Not implemented - returns null
625 public Dimension resizeInnerPanel(String data)
631 public Map<String, Object> getJSpecViewProperty(String arg0)
636 public boolean isPredictSecondaryStructure()
638 return predictSecondaryStructure;
641 public void setPredictSecondaryStructure(boolean predictSecondaryStructure)
643 this.predictSecondaryStructure = predictSecondaryStructure;
646 public boolean isVisibleChainAnnotation()
648 return visibleChainAnnotation;
651 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
653 this.visibleChainAnnotation = visibleChainAnnotation;