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.MessageManager;
33 import java.io.IOException;
34 import java.util.ArrayList;
35 import java.util.HashMap;
36 import java.util.List;
38 import java.util.Vector;
40 import javajs.awt.Dimension;
42 import org.jmol.api.JmolStatusListener;
43 import org.jmol.api.JmolViewer;
44 import org.jmol.c.CBK;
45 import org.jmol.c.STR;
46 import org.jmol.modelset.ModelSet;
47 import org.jmol.viewer.Viewer;
50 import MCview.PDBChain;
51 import MCview.Residue;
54 * Import and process files with Jmol for file like PDB, mmCIF
59 public class JmolParser extends StructureFile implements JmolStatusListener
63 public JmolParser(boolean addAlignmentAnnotations, boolean predictSecStr,
64 boolean externalSecStr, String inFile, String type)
70 public JmolParser(boolean addAlignmentAnnotations, boolean predictSecStr,
71 boolean externalSecStr, FileParse fp) throws IOException
81 * Calls the Jmol library to parse the PDB/mmCIF file, and then inspects the
82 * resulting object model to generate Jalview-style sequences, with secondary
83 * structure annotation added where available (i.e. where it has been computed
84 * by Jmol using DSSP).
86 * @see jalview.io.AlignFile#parse()
89 public void parse() throws IOException
91 setChains(new Vector<PDBChain>());
92 Viewer jmolModel = getJmolData();
93 jmolModel.openReader(getDataName(), getDataName(), getReader());
94 waitForScript(jmolModel);
97 * Convert one or more Jmol Model objects to Jalview sequences
99 if (jmolModel.ms.mc > 0)
101 // ideally we do this
104 // setStructureFileType(jmolModel.evalString("show _fileType"));
105 // } catch (Exception q)
109 // instead, we distinguish .cif from non-.cif by filename
110 setStructureFileType(getDataName().toLowerCase().endsWith(".cif") ? PDBEntry.Type.MMCIF
111 .toString() : "PDB");
113 transformJmolModelToJalview(jmolModel.ms);
118 * create a headless jmol instance for dataprocessing
122 private Viewer getJmolData()
128 viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
129 null, "-x -o -n", this);
130 // ensure the 'new' (DSSP) not 'old' (Ramachandran) SS method is used
131 viewer.setBooleanProperty("defaultStructureDSSP", true);
132 } catch (ClassCastException x)
134 throw new Error(MessageManager.formatMessage(
135 "error.jmol_version_not_compatible_with_jalview_version",
136 new String[] { JmolViewer.getJmolVersion() }), x);
142 public void transformJmolModelToJalview(ModelSet ms) throws IOException
147 List<SequenceI> rna = new ArrayList<SequenceI>();
148 List<SequenceI> prot = new ArrayList<SequenceI>();
150 String pdbId = (String) ms.getInfo(0, "title");
152 List<Atom> significantAtoms = convertSignificantAtoms(ms);
153 for (Atom tmpatom : significantAtoms)
157 tmpchain = findChain(tmpatom.chain);
158 if (tmpatom.resNumIns.trim().equals(lastID))
160 // phosphorylated protein - seen both CA and P..
163 tmpchain.atoms.addElement(tmpatom);
164 } catch (Exception e)
166 tmpchain = new PDBChain(pdbId, tmpatom.chain);
167 getChains().add(tmpchain);
168 tmpchain.atoms.addElement(tmpatom);
170 lastID = tmpatom.resNumIns.trim();
179 setId(safeName(getDataName()));
181 for (PDBChain chain : getChains())
183 SequenceI chainseq = postProcessChain(chain);
193 if (StructureImportSettings.isProcessSecondaryStructure())
195 createAnnotation(chainseq, chain, ms.at);
198 } catch (OutOfMemoryError er)
201 .println("OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
202 throw new IOException(
204 .getString("exception.outofmemory_loading_mmcif_file"));
208 private List<Atom> convertSignificantAtoms(ModelSet ms)
210 List<Atom> significantAtoms = new ArrayList<Atom>();
211 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
212 org.jmol.modelset.Atom prevAtom = null;
213 for (org.jmol.modelset.Atom atom : ms.at)
215 if (atom.getAtomName().equalsIgnoreCase("CA")
216 || atom.getAtomName().equalsIgnoreCase("P"))
218 if (!atomValidated(atom, prevAtom, chainTerMap))
222 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
223 curAtom.atomIndex = atom.getIndex();
224 curAtom.chain = atom.getChainIDStr();
225 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
226 : atom.group.getInsertionCode();
227 curAtom.name = atom.getAtomName();
228 curAtom.number = atom.getAtomNumber();
229 curAtom.resName = atom.getGroup3(true);
230 curAtom.resNumber = atom.getResno();
231 curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
232 .getIndex()] : Float.valueOf(atom.getOccupancy100());
233 curAtom.resNumIns = ("" + curAtom.resNumber + curAtom.insCode)
235 curAtom.tfactor = atom.getBfactor100() / 100f;
237 // significantAtoms.add(curAtom);
238 // ignore atoms from subsequent models
239 if (!significantAtoms.contains(curAtom))
241 significantAtoms.add(curAtom);
246 return significantAtoms;
249 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
250 org.jmol.modelset.Atom prevAtom,
251 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
253 // System.out.println("Atom: " + curAtom.getAtomNumber()
254 // + " Last atom index " + curAtom.group.lastAtomIndex);
255 if (chainTerMap == null || prevAtom == null)
259 String curAtomChId = curAtom.getChainIDStr();
260 String prevAtomChId = prevAtom.getChainIDStr();
261 // new chain encoutered
262 if (!prevAtomChId.equals(curAtomChId))
264 // On chain switch add previous chain termination to xTerMap if not exists
265 if (!chainTerMap.containsKey(prevAtomChId))
267 chainTerMap.put(prevAtomChId, prevAtom);
269 // if current atom belongs to an already terminated chain and the resNum
270 // diff < 5 then mark as valid and update termination Atom
271 if (chainTerMap.containsKey(curAtomChId))
273 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
275 chainTerMap.put(curAtomChId, curAtom);
281 // atom with previously terminated chain encountered
282 else if (chainTerMap.containsKey(curAtomChId))
284 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
286 chainTerMap.put(curAtomChId, curAtom);
291 // HETATM with resNum jump > 2
292 return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
296 private void createAnnotation(SequenceI sequence, PDBChain chain,
297 org.jmol.modelset.Atom[] jmolAtoms)
299 char[] secstr = new char[sequence.getLength()];
300 char[] secstrcode = new char[sequence.getLength()];
302 // Ensure Residue size equals Seq size
303 if (chain.residues.size() != sequence.getLength())
308 for (Residue residue : chain.residues)
310 Atom repAtom = residue.getAtoms().get(0);
311 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
312 .getProteinStructureSubType();
313 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
317 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
318 secstrcode, chain.id, sequence.getStart());
322 * Helper method that adds an AlignmentAnnotation for secondary structure to
323 * the sequence, provided at least one secondary structure prediction has been
334 protected void addSecondaryStructureAnnotation(String modelTitle,
335 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
338 char[] seq = sq.getSequence();
339 boolean ssFound = false;
340 Annotation asecstr[] = new Annotation[seq.length + firstResNum - 1];
341 for (int p = 0; p < seq.length; p++)
343 if (secstr[p] >= 'A' && secstr[p] <= 'z')
347 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
348 secstrcode[p], Float.NaN);
350 } catch (Exception e)
352 // e.printStackTrace();
359 String mt = modelTitle == null ? getDataName() : modelTitle;
361 AlignmentAnnotation ann = new AlignmentAnnotation(
362 "Secondary Structure", "Secondary Structure for " + mt,
364 ann.belowAlignment = true;
366 ann.autoCalculated = false;
367 ann.setCalcId(getClass().getName());
368 ann.adjustForAlignment();
369 ann.validateRangeAndDisplay();
370 annotations.add(ann);
371 sq.addAlignmentAnnotation(ann);
375 private void waitForScript(Viewer jmd)
377 while (jmd.isScriptExecuting())
383 } catch (InterruptedException x)
390 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
391 * secondary structure arrays at the given sequence position
393 * @param proteinStructureSubType
398 protected void setSecondaryStructure(STR proteinStructureSubType,
399 int pos, char[] secstr, char[] secstrcode)
401 switch (proteinStructureSubType)
420 switch (proteinStructureSubType)
426 secstrcode[pos] = 'H';
429 secstrcode[pos] = 'E';
437 * Convert any non-standard peptide codes to their standard code table
438 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
440 * @param threeLetterCode
444 protected void replaceNonCanonicalResidue(String threeLetterCode,
447 String canonical = ResidueProperties
448 .getCanonicalAminoAcid(threeLetterCode);
449 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
451 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
456 * Not implemented - returns null
459 public String print()
468 public void setCallbackFunction(String callbackType,
469 String callbackFunction)
474 public void notifyCallback(CBK cbType, Object[] data)
476 String strInfo = (data == null || data[1] == null ? null : data[1]
481 sendConsoleEcho(strInfo);
484 notifyScriptTermination((String) data[2],
485 ((Integer) data[3]).intValue());
488 String mystatus = (String) data[3];
489 if (mystatus.indexOf("Picked") >= 0
490 || mystatus.indexOf("Sequence") >= 0)
493 sendConsoleMessage(strInfo);
495 else if (mystatus.indexOf("Completed") >= 0)
497 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
498 strInfo.length() - 1));
502 sendConsoleMessage(data == null ? null : strInfo);
505 sendConsoleMessage(strInfo);
512 String lastConsoleEcho = "";
514 private void sendConsoleEcho(String string)
516 lastConsoleEcho += string;
517 lastConsoleEcho += "\n";
520 String lastConsoleMessage = "";
522 private void sendConsoleMessage(String string)
524 lastConsoleMessage += string;
525 lastConsoleMessage += "\n";
528 int lastScriptTermination = -1;
530 String lastScriptMessage = "";
532 private void notifyScriptTermination(String string, int intValue)
534 lastScriptMessage += string;
535 lastScriptMessage += "\n";
536 lastScriptTermination = intValue;
540 public boolean notifyEnabled(CBK callbackPick)
542 switch (callbackPick)
556 * Not implemented - returns null
559 public String eval(String strEval)
565 * Not implemented - returns null
568 public float[][] functionXY(String functionName, int x, int y)
574 * Not implemented - returns null
577 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
583 * Not implemented - returns null
586 public String createImage(String fileName, String imageType,
587 Object text_or_bytes, int quality)
593 * Not implemented - returns null
596 public Map<String, Object> getRegistryInfo()
605 public void showUrl(String url)
610 * Not implemented - returns null
613 public Dimension resizeInnerPanel(String data)
619 public Map<String, Object> getJSpecViewProperty(String arg0)
624 public boolean isPredictSecondaryStructure()
626 return predictSecondaryStructure;
629 public void setPredictSecondaryStructure(boolean predictSecondaryStructure)
631 this.predictSecondaryStructure = predictSecondaryStructure;
634 public boolean isVisibleChainAnnotation()
636 return visibleChainAnnotation;
639 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
641 this.visibleChainAnnotation = visibleChainAnnotation;