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()));
157 setPDBIdAvailable(false);
162 setPDBIdAvailable(true);
164 List<Atom> significantAtoms = convertSignificantAtoms(ms);
165 for (Atom tmpatom : significantAtoms)
169 tmpchain = findChain(tmpatom.chain);
170 if (tmpatom.resNumIns.trim().equals(lastID))
172 // phosphorylated protein - seen both CA and P..
175 tmpchain.atoms.addElement(tmpatom);
176 } catch (Exception e)
178 tmpchain = new PDBChain(getId(), tmpatom.chain);
179 getChains().add(tmpchain);
180 tmpchain.atoms.addElement(tmpatom);
182 lastID = tmpatom.resNumIns.trim();
189 for (PDBChain chain : getChains())
191 SequenceI chainseq = postProcessChain(chain);
201 if (StructureImportSettings.isProcessSecondaryStructure())
203 createAnnotation(chainseq, chain, ms.at);
206 } catch (OutOfMemoryError er)
209 .println("OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
210 throw new IOException(
212 .getString("exception.outofmemory_loading_mmcif_file"));
216 private List<Atom> convertSignificantAtoms(ModelSet ms)
218 List<Atom> significantAtoms = new ArrayList<Atom>();
219 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
220 org.jmol.modelset.Atom prevAtom = null;
221 for (org.jmol.modelset.Atom atom : ms.at)
223 if (atom.getAtomName().equalsIgnoreCase("CA")
224 || atom.getAtomName().equalsIgnoreCase("P"))
226 if (!atomValidated(atom, prevAtom, chainTerMap))
230 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
231 curAtom.atomIndex = atom.getIndex();
232 curAtom.chain = atom.getChainIDStr();
233 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
234 : atom.group.getInsertionCode();
235 curAtom.name = atom.getAtomName();
236 curAtom.number = atom.getAtomNumber();
237 curAtom.resName = atom.getGroup3(true);
238 curAtom.resNumber = atom.getResno();
239 curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
240 .getIndex()] : Float.valueOf(atom.getOccupancy100());
241 String fmt = new Format("%4i").form(curAtom.resNumber);
242 curAtom.resNumIns = (fmt + curAtom.insCode);
243 curAtom.tfactor = atom.getBfactor100() / 100f;
245 // significantAtoms.add(curAtom);
246 // ignore atoms from subsequent models
247 if (!significantAtoms.contains(curAtom))
249 significantAtoms.add(curAtom);
254 return significantAtoms;
257 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
258 org.jmol.modelset.Atom prevAtom,
259 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
261 // System.out.println("Atom: " + curAtom.getAtomNumber()
262 // + " Last atom index " + curAtom.group.lastAtomIndex);
263 if (chainTerMap == null || prevAtom == null)
267 String curAtomChId = curAtom.getChainIDStr();
268 String prevAtomChId = prevAtom.getChainIDStr();
269 // new chain encoutered
270 if (!prevAtomChId.equals(curAtomChId))
272 // On chain switch add previous chain termination to xTerMap if not exists
273 if (!chainTerMap.containsKey(prevAtomChId))
275 chainTerMap.put(prevAtomChId, prevAtom);
277 // if current atom belongs to an already terminated chain and the resNum
278 // diff < 5 then mark as valid and update termination Atom
279 if (chainTerMap.containsKey(curAtomChId))
281 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
285 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
287 chainTerMap.put(curAtomChId, curAtom);
293 // atom with previously terminated chain encountered
294 else if (chainTerMap.containsKey(curAtomChId))
296 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
300 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
302 chainTerMap.put(curAtomChId, curAtom);
307 // HETATM with resNum jump > 2
308 return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
312 private void createAnnotation(SequenceI sequence, PDBChain chain,
313 org.jmol.modelset.Atom[] jmolAtoms)
315 char[] secstr = new char[sequence.getLength()];
316 char[] secstrcode = new char[sequence.getLength()];
318 // Ensure Residue size equals Seq size
319 if (chain.residues.size() != sequence.getLength())
324 for (Residue residue : chain.residues)
326 Atom repAtom = residue.getAtoms().get(0);
327 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
328 .getProteinStructureSubType();
329 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
333 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
334 secstrcode, chain.id, sequence.getStart());
338 * Helper method that adds an AlignmentAnnotation for secondary structure to
339 * the sequence, provided at least one secondary structure prediction has been
350 protected void addSecondaryStructureAnnotation(String modelTitle,
351 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
354 char[] seq = sq.getSequence();
355 boolean ssFound = false;
356 Annotation asecstr[] = new Annotation[seq.length + firstResNum - 1];
357 for (int p = 0; p < seq.length; p++)
359 if (secstr[p] >= 'A' && secstr[p] <= 'z')
363 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
364 secstrcode[p], Float.NaN);
366 } catch (Exception e)
368 // e.printStackTrace();
375 String mt = modelTitle == null ? getDataName() : modelTitle;
377 AlignmentAnnotation ann = new AlignmentAnnotation(
378 "Secondary Structure", "Secondary Structure for " + mt,
380 ann.belowAlignment = true;
382 ann.autoCalculated = false;
383 ann.setCalcId(getClass().getName());
384 ann.adjustForAlignment();
385 ann.validateRangeAndDisplay();
386 annotations.add(ann);
387 sq.addAlignmentAnnotation(ann);
391 private void waitForScript(Viewer jmd)
393 while (jmd.isScriptExecuting())
399 } catch (InterruptedException x)
406 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
407 * secondary structure arrays at the given sequence position
409 * @param proteinStructureSubType
414 protected void setSecondaryStructure(STR proteinStructureSubType,
415 int pos, char[] secstr, char[] secstrcode)
417 switch (proteinStructureSubType)
436 switch (proteinStructureSubType)
442 secstrcode[pos] = 'H';
445 secstrcode[pos] = 'E';
453 * Convert any non-standard peptide codes to their standard code table
454 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
456 * @param threeLetterCode
460 protected void replaceNonCanonicalResidue(String threeLetterCode,
463 String canonical = ResidueProperties
464 .getCanonicalAminoAcid(threeLetterCode);
465 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
467 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
472 * Not implemented - returns null
475 public String print()
484 public void setCallbackFunction(String callbackType,
485 String callbackFunction)
490 public void notifyCallback(CBK cbType, Object[] data)
492 String strInfo = (data == null || data[1] == null ? null : data[1]
497 sendConsoleEcho(strInfo);
500 notifyScriptTermination((String) data[2],
501 ((Integer) data[3]).intValue());
504 String mystatus = (String) data[3];
505 if (mystatus.indexOf("Picked") >= 0
506 || mystatus.indexOf("Sequence") >= 0)
509 sendConsoleMessage(strInfo);
511 else if (mystatus.indexOf("Completed") >= 0)
513 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
514 strInfo.length() - 1));
518 sendConsoleMessage(data == null ? null : strInfo);
521 sendConsoleMessage(strInfo);
528 String lastConsoleEcho = "";
530 private void sendConsoleEcho(String string)
532 lastConsoleEcho += string;
533 lastConsoleEcho += "\n";
536 String lastConsoleMessage = "";
538 private void sendConsoleMessage(String string)
540 lastConsoleMessage += string;
541 lastConsoleMessage += "\n";
544 int lastScriptTermination = -1;
546 String lastScriptMessage = "";
548 private void notifyScriptTermination(String string, int intValue)
550 lastScriptMessage += string;
551 lastScriptMessage += "\n";
552 lastScriptTermination = intValue;
556 public boolean notifyEnabled(CBK callbackPick)
558 switch (callbackPick)
572 * Not implemented - returns null
575 public String eval(String strEval)
581 * Not implemented - returns null
584 public float[][] functionXY(String functionName, int x, int y)
590 * Not implemented - returns null
593 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
599 * Not implemented - returns null
602 public String createImage(String fileName, String imageType,
603 Object text_or_bytes, int quality)
609 * Not implemented - returns null
612 public Map<String, Object> getRegistryInfo()
621 public void showUrl(String url)
626 * Not implemented - returns null
629 public Dimension resizeInnerPanel(String data)
635 public Map<String, Object> getJSpecViewProperty(String arg0)
640 public boolean isPredictSecondaryStructure()
642 return predictSecondaryStructure;
645 public void setPredictSecondaryStructure(boolean predictSecondaryStructure)
647 this.predictSecondaryStructure = predictSecondaryStructure;
650 public boolean isVisibleChainAnnotation()
652 return visibleChainAnnotation;
655 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
657 this.visibleChainAnnotation = visibleChainAnnotation;