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.SequenceI;
26 import jalview.io.FileParse;
27 import jalview.io.StructureFile;
28 import jalview.schemes.ResidueProperties;
29 import jalview.structure.StructureImportSettings;
30 import jalview.util.MessageManager;
32 import java.io.IOException;
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.List;
37 import java.util.Vector;
39 import javajs.awt.Dimension;
41 import org.jmol.api.JmolStatusListener;
42 import org.jmol.api.JmolViewer;
43 import org.jmol.c.CBK;
44 import org.jmol.c.STR;
45 import org.jmol.modelset.ModelSet;
46 import org.jmol.viewer.Viewer;
49 import MCview.PDBChain;
50 import MCview.Residue;
53 * Import and process files with Jmol for file like PDB, mmCIF
58 public class JmolParser extends StructureFile implements JmolStatusListener
62 public JmolParser(boolean addAlignmentAnnotations, boolean predictSecStr,
63 boolean externalSecStr, String inFile, String type)
69 public JmolParser(boolean addAlignmentAnnotations, boolean predictSecStr,
70 boolean externalSecStr, 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 transformJmolModelToJalview(jmolModel.ms);
105 * create a headless jmol instance for dataprocessing
109 private Viewer getJmolData()
115 viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
116 null, "-x -o -n", this);
117 // ensure the 'new' (DSSP) not 'old' (Ramachandran) SS method is used
118 viewer.setBooleanProperty("defaultStructureDSSP", true);
119 } catch (ClassCastException x)
121 throw new Error(MessageManager.formatMessage(
122 "error.jmol_version_not_compatible_with_jalview_version",
123 new String[] { JmolViewer.getJmolVersion() }), x);
129 public void transformJmolModelToJalview(ModelSet ms) throws IOException
134 List<SequenceI> rna = new ArrayList<SequenceI>();
135 List<SequenceI> prot = new ArrayList<SequenceI>();
137 String pdbId = (String) ms.getInfo(0, "title");
139 List<Atom> significantAtoms = convertSignificantAtoms(ms);
140 for (Atom tmpatom : significantAtoms)
144 tmpchain = findChain(tmpatom.chain);
145 if (tmpatom.resNumIns.trim().equals(lastID))
147 // phosphorylated protein - seen both CA and P..
150 tmpchain.atoms.addElement(tmpatom);
151 } catch (Exception e)
153 tmpchain = new PDBChain(pdbId, tmpatom.chain);
154 getChains().add(tmpchain);
155 tmpchain.atoms.addElement(tmpatom);
157 lastID = tmpatom.resNumIns.trim();
166 setId(safeName(getDataName()));
168 for (PDBChain chain : getChains())
170 SequenceI chainseq = postProcessChain(chain);
180 if (StructureImportSettings.isProcessSecondaryStructure())
182 createAnnotation(chainseq, chain, ms.at);
185 } catch (OutOfMemoryError er)
188 .println("OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
189 throw new IOException(
191 .getString("exception.outofmemory_loading_mmcif_file"));
195 private List<Atom> convertSignificantAtoms(ModelSet ms)
197 List<Atom> significantAtoms = new ArrayList<Atom>();
198 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
199 org.jmol.modelset.Atom prevAtom = null;
200 for (org.jmol.modelset.Atom atom : ms.at)
202 if (atom.getAtomName().equalsIgnoreCase("CA")
203 || atom.getAtomName().equalsIgnoreCase("P"))
205 if (!atomValidated(atom, prevAtom, chainTerMap))
209 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
210 curAtom.atomIndex = atom.getIndex();
211 curAtom.chain = atom.getChainIDStr();
212 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
213 : atom.group.getInsertionCode();
214 curAtom.name = atom.getAtomName();
215 curAtom.number = atom.getAtomNumber();
216 curAtom.resName = atom.getGroup3(true);
217 curAtom.resNumber = atom.getResno();
218 curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
219 .getIndex()] : Float.valueOf(atom.getOccupancy100());
220 curAtom.resNumIns = ("" + curAtom.resNumber + curAtom.insCode)
222 curAtom.tfactor = atom.getBfactor100() / 100f;
224 // significantAtoms.add(curAtom);
225 // ignore atoms from subsequent models
226 if (!significantAtoms.contains(curAtom))
228 significantAtoms.add(curAtom);
233 return significantAtoms;
236 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
237 org.jmol.modelset.Atom prevAtom,
238 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
240 // System.out.println("Atom: " + curAtom.getAtomNumber()
241 // + " Last atom index " + curAtom.group.lastAtomIndex);
242 if (chainTerMap == null || prevAtom == null)
246 String curAtomChId = curAtom.getChainIDStr();
247 String prevAtomChId = prevAtom.getChainIDStr();
248 // new chain encoutered
249 if (!prevAtomChId.equals(curAtomChId))
251 // On chain switch add previous chain termination to xTerMap if not exists
252 if (!chainTerMap.containsKey(prevAtomChId))
254 chainTerMap.put(prevAtomChId, prevAtom);
256 // if current atom belongs to an already terminated chain and the resNum
257 // diff < 5 then mark as valid and update termination Atom
258 if (chainTerMap.containsKey(curAtomChId))
260 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
264 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
266 chainTerMap.put(curAtomChId, curAtom);
272 // atom with previously terminated chain encountered
273 else if (chainTerMap.containsKey(curAtomChId))
275 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
279 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
281 chainTerMap.put(curAtomChId, curAtom);
286 // HETATM with resNum jump > 2
287 return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
291 private void createAnnotation(SequenceI sequence, PDBChain chain,
292 org.jmol.modelset.Atom[] jmolAtoms)
294 char[] secstr = new char[sequence.getLength()];
295 char[] secstrcode = new char[sequence.getLength()];
297 // Ensure Residue size equals Seq size
298 if (chain.residues.size() != sequence.getLength())
303 for (Residue residue : chain.residues)
305 Atom repAtom = residue.getAtoms().get(0);
306 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
307 .getProteinStructureSubType();
308 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
312 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
313 secstrcode, chain.id, sequence.getStart());
317 * Helper method that adds an AlignmentAnnotation for secondary structure to
318 * the sequence, provided at least one secondary structure prediction has been
329 protected void addSecondaryStructureAnnotation(String modelTitle,
330 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
333 char[] seq = sq.getSequence();
334 boolean ssFound = false;
335 Annotation asecstr[] = new Annotation[seq.length + firstResNum - 1];
336 for (int p = 0; p < seq.length; p++)
338 if (secstr[p] >= 'A' && secstr[p] <= 'z')
342 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
343 secstrcode[p], Float.NaN);
345 } catch (Exception e)
347 // e.printStackTrace();
354 String mt = modelTitle == null ? getDataName() : modelTitle;
356 AlignmentAnnotation ann = new AlignmentAnnotation(
357 "Secondary Structure", "Secondary Structure for " + mt,
359 ann.belowAlignment = true;
361 ann.autoCalculated = false;
362 ann.setCalcId(getClass().getName());
363 ann.adjustForAlignment();
364 ann.validateRangeAndDisplay();
365 annotations.add(ann);
366 sq.addAlignmentAnnotation(ann);
370 private void waitForScript(Viewer jmd)
372 while (jmd.isScriptExecuting())
378 } catch (InterruptedException x)
385 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
386 * secondary structure arrays at the given sequence position
388 * @param proteinStructureSubType
393 protected void setSecondaryStructure(STR proteinStructureSubType,
394 int pos, char[] secstr, char[] secstrcode)
396 switch (proteinStructureSubType)
415 switch (proteinStructureSubType)
421 secstrcode[pos] = 'H';
424 secstrcode[pos] = 'E';
432 * Convert any non-standard peptide codes to their standard code table
433 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
435 * @param threeLetterCode
439 protected void replaceNonCanonicalResidue(String threeLetterCode,
442 String canonical = ResidueProperties
443 .getCanonicalAminoAcid(threeLetterCode);
444 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
446 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
451 * Not implemented - returns null
454 public String print()
463 public void setCallbackFunction(String callbackType,
464 String callbackFunction)
469 public void notifyCallback(CBK cbType, Object[] data)
471 String strInfo = (data == null || data[1] == null ? null : data[1]
476 sendConsoleEcho(strInfo);
479 notifyScriptTermination((String) data[2],
480 ((Integer) data[3]).intValue());
483 String mystatus = (String) data[3];
484 if (mystatus.indexOf("Picked") >= 0
485 || mystatus.indexOf("Sequence") >= 0)
488 sendConsoleMessage(strInfo);
490 else if (mystatus.indexOf("Completed") >= 0)
492 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
493 strInfo.length() - 1));
497 sendConsoleMessage(data == null ? null : strInfo);
500 sendConsoleMessage(strInfo);
507 String lastConsoleEcho = "";
509 private void sendConsoleEcho(String string)
511 lastConsoleEcho += string;
512 lastConsoleEcho += "\n";
515 String lastConsoleMessage = "";
517 private void sendConsoleMessage(String string)
519 lastConsoleMessage += string;
520 lastConsoleMessage += "\n";
523 int lastScriptTermination = -1;
525 String lastScriptMessage = "";
527 private void notifyScriptTermination(String string, int intValue)
529 lastScriptMessage += string;
530 lastScriptMessage += "\n";
531 lastScriptTermination = intValue;
535 public boolean notifyEnabled(CBK callbackPick)
537 switch (callbackPick)
551 * Not implemented - returns null
554 public String eval(String strEval)
560 * Not implemented - returns null
563 public float[][] functionXY(String functionName, int x, int y)
569 * Not implemented - returns null
572 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
578 * Not implemented - returns null
581 public String createImage(String fileName, String imageType,
582 Object text_or_bytes, int quality)
588 * Not implemented - returns null
591 public Map<String, Object> getRegistryInfo()
600 public void showUrl(String url)
605 * Not implemented - returns null
608 public Dimension resizeInnerPanel(String data)
614 public Map<String, Object> getJSpecViewProperty(String arg0)
619 public boolean isPredictSecondaryStructure()
621 return predictSecondaryStructure;
624 public void setPredictSecondaryStructure(boolean predictSecondaryStructure)
626 this.predictSecondaryStructure = predictSecondaryStructure;
629 public boolean isVisibleChainAnnotation()
631 return visibleChainAnnotation;
634 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
636 this.visibleChainAnnotation = visibleChainAnnotation;