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();
191 // always use resource name, not the hardwired file
192 // Does the value of ID get used ? Behaviour needs to be
193 // documented and tested
194 setId(getDataName());
197 for (PDBChain chain : getChains())
199 SequenceI chainseq = postProcessChain(chain);
209 if (StructureImportSettings.isProcessSecondaryStructure())
211 createAnnotation(chainseq, chain, ms.at);
214 } catch (OutOfMemoryError er)
217 .println("OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
218 throw new IOException(
220 .getString("exception.outofmemory_loading_mmcif_file"));
224 private List<Atom> convertSignificantAtoms(ModelSet ms)
226 List<Atom> significantAtoms = new ArrayList<Atom>();
227 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
228 org.jmol.modelset.Atom prevAtom = null;
229 for (org.jmol.modelset.Atom atom : ms.at)
231 if (atom.getAtomName().equalsIgnoreCase("CA")
232 || atom.getAtomName().equalsIgnoreCase("P"))
234 if (!atomValidated(atom, prevAtom, chainTerMap))
238 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
239 curAtom.atomIndex = atom.getIndex();
240 curAtom.chain = atom.getChainIDStr();
241 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
242 : atom.group.getInsertionCode();
243 curAtom.name = atom.getAtomName();
244 curAtom.number = atom.getAtomNumber();
245 curAtom.resName = atom.getGroup3(true);
246 curAtom.resNumber = atom.getResno();
247 curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
248 .getIndex()] : Float.valueOf(atom.getOccupancy100());
249 String fmt = new Format("%4i").form(curAtom.resNumber);
250 curAtom.resNumIns = (fmt + curAtom.insCode);
251 curAtom.tfactor = atom.getBfactor100() / 100f;
253 // significantAtoms.add(curAtom);
254 // ignore atoms from subsequent models
255 if (!significantAtoms.contains(curAtom))
257 significantAtoms.add(curAtom);
262 return significantAtoms;
265 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
266 org.jmol.modelset.Atom prevAtom,
267 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
269 // System.out.println("Atom: " + curAtom.getAtomNumber()
270 // + " Last atom index " + curAtom.group.lastAtomIndex);
271 if (chainTerMap == null || prevAtom == null)
275 String curAtomChId = curAtom.getChainIDStr();
276 String prevAtomChId = prevAtom.getChainIDStr();
277 // new chain encoutered
278 if (!prevAtomChId.equals(curAtomChId))
280 // On chain switch add previous chain termination to xTerMap if not exists
281 if (!chainTerMap.containsKey(prevAtomChId))
283 chainTerMap.put(prevAtomChId, prevAtom);
285 // if current atom belongs to an already terminated chain and the resNum
286 // diff < 5 then mark as valid and update termination Atom
287 if (chainTerMap.containsKey(curAtomChId))
289 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
293 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
295 chainTerMap.put(curAtomChId, curAtom);
301 // atom with previously terminated chain encountered
302 else if (chainTerMap.containsKey(curAtomChId))
304 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
308 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
310 chainTerMap.put(curAtomChId, curAtom);
315 // HETATM with resNum jump > 2
316 return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
320 private void createAnnotation(SequenceI sequence, PDBChain chain,
321 org.jmol.modelset.Atom[] jmolAtoms)
323 char[] secstr = new char[sequence.getLength()];
324 char[] secstrcode = new char[sequence.getLength()];
326 // Ensure Residue size equals Seq size
327 if (chain.residues.size() != sequence.getLength())
332 for (Residue residue : chain.residues)
334 Atom repAtom = residue.getAtoms().get(0);
335 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
336 .getProteinStructureSubType();
337 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
341 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
342 secstrcode, chain.id, sequence.getStart());
346 * Helper method that adds an AlignmentAnnotation for secondary structure to
347 * the sequence, provided at least one secondary structure prediction has been
358 protected void addSecondaryStructureAnnotation(String modelTitle,
359 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
362 char[] seq = sq.getSequence();
363 boolean ssFound = false;
364 Annotation asecstr[] = new Annotation[seq.length + firstResNum - 1];
365 for (int p = 0; p < seq.length; p++)
367 if (secstr[p] >= 'A' && secstr[p] <= 'z')
371 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
372 secstrcode[p], Float.NaN);
374 } catch (Exception e)
376 // e.printStackTrace();
383 String mt = modelTitle == null ? getDataName() : modelTitle;
385 AlignmentAnnotation ann = new AlignmentAnnotation(
386 "Secondary Structure", "Secondary Structure for " + mt,
388 ann.belowAlignment = true;
390 ann.autoCalculated = false;
391 ann.setCalcId(getClass().getName());
392 ann.adjustForAlignment();
393 ann.validateRangeAndDisplay();
394 annotations.add(ann);
395 sq.addAlignmentAnnotation(ann);
399 private void waitForScript(Viewer jmd)
401 while (jmd.isScriptExecuting())
407 } catch (InterruptedException x)
414 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
415 * secondary structure arrays at the given sequence position
417 * @param proteinStructureSubType
422 protected void setSecondaryStructure(STR proteinStructureSubType,
423 int pos, char[] secstr, char[] secstrcode)
425 switch (proteinStructureSubType)
444 switch (proteinStructureSubType)
450 secstrcode[pos] = 'H';
453 secstrcode[pos] = 'E';
461 * Convert any non-standard peptide codes to their standard code table
462 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
464 * @param threeLetterCode
468 protected void replaceNonCanonicalResidue(String threeLetterCode,
471 String canonical = ResidueProperties
472 .getCanonicalAminoAcid(threeLetterCode);
473 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
475 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
480 * Not implemented - returns null
483 public String print()
492 public void setCallbackFunction(String callbackType,
493 String callbackFunction)
498 public void notifyCallback(CBK cbType, Object[] data)
500 String strInfo = (data == null || data[1] == null ? null : data[1]
505 sendConsoleEcho(strInfo);
508 notifyScriptTermination((String) data[2],
509 ((Integer) data[3]).intValue());
512 String mystatus = (String) data[3];
513 if (mystatus.indexOf("Picked") >= 0
514 || mystatus.indexOf("Sequence") >= 0)
517 sendConsoleMessage(strInfo);
519 else if (mystatus.indexOf("Completed") >= 0)
521 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
522 strInfo.length() - 1));
526 sendConsoleMessage(data == null ? null : strInfo);
529 sendConsoleMessage(strInfo);
536 String lastConsoleEcho = "";
538 private void sendConsoleEcho(String string)
540 lastConsoleEcho += string;
541 lastConsoleEcho += "\n";
544 String lastConsoleMessage = "";
546 private void sendConsoleMessage(String string)
548 lastConsoleMessage += string;
549 lastConsoleMessage += "\n";
552 int lastScriptTermination = -1;
554 String lastScriptMessage = "";
556 private void notifyScriptTermination(String string, int intValue)
558 lastScriptMessage += string;
559 lastScriptMessage += "\n";
560 lastScriptTermination = intValue;
564 public boolean notifyEnabled(CBK callbackPick)
566 switch (callbackPick)
580 * Not implemented - returns null
583 public String eval(String strEval)
589 * Not implemented - returns null
592 public float[][] functionXY(String functionName, int x, int y)
598 * Not implemented - returns null
601 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
607 * Not implemented - returns null
610 public String createImage(String fileName, String imageType,
611 Object text_or_bytes, int quality)
617 * Not implemented - returns null
620 public Map<String, Object> getRegistryInfo()
629 public void showUrl(String url)
634 * Not implemented - returns null
637 public Dimension resizeInnerPanel(String data)
643 public Map<String, Object> getJSpecViewProperty(String arg0)
648 public boolean isPredictSecondaryStructure()
650 return predictSecondaryStructure;
653 public void setPredictSecondaryStructure(boolean predictSecondaryStructure)
655 this.predictSecondaryStructure = predictSecondaryStructure;
658 public boolean isVisibleChainAnnotation()
660 return visibleChainAnnotation;
663 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
665 this.visibleChainAnnotation = visibleChainAnnotation;