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(boolean addAlignmentAnnotations, boolean predictSecStr,
65 boolean externalSecStr, String inFile, String type)
71 public JmolParser(boolean addAlignmentAnnotations, boolean predictSecStr,
72 boolean externalSecStr, FileParse fp) throws IOException
82 * Calls the Jmol library to parse the PDB/mmCIF file, and then inspects the
83 * resulting object model to generate Jalview-style sequences, with secondary
84 * structure annotation added where available (i.e. where it has been computed
85 * by Jmol using DSSP).
87 * @see jalview.io.AlignFile#parse()
90 public void parse() throws IOException
92 setChains(new Vector<PDBChain>());
93 Viewer jmolModel = getJmolData();
94 jmolModel.openReader(getDataName(), getDataName(), getReader());
95 waitForScript(jmolModel);
98 * Convert one or more Jmol Model objects to Jalview sequences
100 if (jmolModel.ms.mc > 0)
102 // ideally we do this
105 // setStructureFileType(jmolModel.evalString("show _fileType"));
106 // } catch (Exception q)
110 // instead, we distinguish .cif from non-.cif by filename
111 setStructureFileType(getDataName().toLowerCase().endsWith(".cif") ? PDBEntry.Type.MMCIF
112 .toString() : "PDB");
114 transformJmolModelToJalview(jmolModel.ms);
119 * create a headless jmol instance for dataprocessing
123 private Viewer getJmolData()
129 viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
130 null, "-x -o -n", this);
131 // ensure the 'new' (DSSP) not 'old' (Ramachandran) SS method is used
132 viewer.setBooleanProperty("defaultStructureDSSP", true);
133 } catch (ClassCastException x)
135 throw new Error(MessageManager.formatMessage(
136 "error.jmol_version_not_compatible_with_jalview_version",
137 new String[] { JmolViewer.getJmolVersion() }), x);
143 public void transformJmolModelToJalview(ModelSet ms) throws IOException
148 List<SequenceI> rna = new ArrayList<SequenceI>();
149 List<SequenceI> prot = new ArrayList<SequenceI>();
151 String pdbId = (String) ms.getInfo(0, "title");
153 List<Atom> significantAtoms = convertSignificantAtoms(ms);
154 for (Atom tmpatom : significantAtoms)
158 tmpchain = findChain(tmpatom.chain);
159 if (tmpatom.resNumIns.trim().equals(lastID))
161 // phosphorylated protein - seen both CA and P..
164 tmpchain.atoms.addElement(tmpatom);
165 } catch (Exception e)
167 tmpchain = new PDBChain(pdbId, tmpatom.chain);
168 getChains().add(tmpchain);
169 tmpchain.atoms.addElement(tmpatom);
171 lastID = tmpatom.resNumIns.trim();
180 setId(safeName(getDataName()));
182 for (PDBChain chain : getChains())
184 SequenceI chainseq = postProcessChain(chain);
194 if (StructureImportSettings.isProcessSecondaryStructure())
196 createAnnotation(chainseq, chain, ms.at);
199 } catch (OutOfMemoryError er)
202 .println("OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
203 throw new IOException(
205 .getString("exception.outofmemory_loading_mmcif_file"));
209 private List<Atom> convertSignificantAtoms(ModelSet ms)
211 List<Atom> significantAtoms = new ArrayList<Atom>();
212 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
213 org.jmol.modelset.Atom prevAtom = null;
214 for (org.jmol.modelset.Atom atom : ms.at)
216 if (atom.getAtomName().equalsIgnoreCase("CA")
217 || atom.getAtomName().equalsIgnoreCase("P"))
219 if (!atomValidated(atom, prevAtom, chainTerMap))
223 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
224 curAtom.atomIndex = atom.getIndex();
225 curAtom.chain = atom.getChainIDStr();
226 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
227 : atom.group.getInsertionCode();
228 curAtom.name = atom.getAtomName();
229 curAtom.number = atom.getAtomNumber();
230 curAtom.resName = atom.getGroup3(true);
231 curAtom.resNumber = atom.getResno();
232 curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
233 .getIndex()] : Float.valueOf(atom.getOccupancy100());
234 String fmt = new Format("%4i").form(curAtom.resNumber);
235 curAtom.resNumIns = (fmt + curAtom.insCode);
236 curAtom.tfactor = atom.getBfactor100() / 100f;
238 // significantAtoms.add(curAtom);
239 // ignore atoms from subsequent models
240 if (!significantAtoms.contains(curAtom))
242 significantAtoms.add(curAtom);
247 return significantAtoms;
250 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
251 org.jmol.modelset.Atom prevAtom,
252 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
254 // System.out.println("Atom: " + curAtom.getAtomNumber()
255 // + " Last atom index " + curAtom.group.lastAtomIndex);
256 if (chainTerMap == null || prevAtom == null)
260 String curAtomChId = curAtom.getChainIDStr();
261 String prevAtomChId = prevAtom.getChainIDStr();
262 // new chain encoutered
263 if (!prevAtomChId.equals(curAtomChId))
265 // On chain switch add previous chain termination to xTerMap if not exists
266 if (!chainTerMap.containsKey(prevAtomChId))
268 chainTerMap.put(prevAtomChId, prevAtom);
270 // if current atom belongs to an already terminated chain and the resNum
271 // diff < 5 then mark as valid and update termination Atom
272 if (chainTerMap.containsKey(curAtomChId))
274 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
278 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
280 chainTerMap.put(curAtomChId, curAtom);
286 // atom with previously terminated chain encountered
287 else 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);
300 // HETATM with resNum jump > 2
301 return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
305 private void createAnnotation(SequenceI sequence, PDBChain chain,
306 org.jmol.modelset.Atom[] jmolAtoms)
308 char[] secstr = new char[sequence.getLength()];
309 char[] secstrcode = new char[sequence.getLength()];
311 // Ensure Residue size equals Seq size
312 if (chain.residues.size() != sequence.getLength())
317 for (Residue residue : chain.residues)
319 Atom repAtom = residue.getAtoms().get(0);
320 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
321 .getProteinStructureSubType();
322 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
326 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
327 secstrcode, chain.id, sequence.getStart());
331 * Helper method that adds an AlignmentAnnotation for secondary structure to
332 * the sequence, provided at least one secondary structure prediction has been
343 protected void addSecondaryStructureAnnotation(String modelTitle,
344 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
347 char[] seq = sq.getSequence();
348 boolean ssFound = false;
349 Annotation asecstr[] = new Annotation[seq.length + firstResNum - 1];
350 for (int p = 0; p < seq.length; p++)
352 if (secstr[p] >= 'A' && secstr[p] <= 'z')
356 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
357 secstrcode[p], Float.NaN);
359 } catch (Exception e)
361 // e.printStackTrace();
368 String mt = modelTitle == null ? getDataName() : modelTitle;
370 AlignmentAnnotation ann = new AlignmentAnnotation(
371 "Secondary Structure", "Secondary Structure for " + mt,
373 ann.belowAlignment = true;
375 ann.autoCalculated = false;
376 ann.setCalcId(getClass().getName());
377 ann.adjustForAlignment();
378 ann.validateRangeAndDisplay();
379 annotations.add(ann);
380 sq.addAlignmentAnnotation(ann);
384 private void waitForScript(Viewer jmd)
386 while (jmd.isScriptExecuting())
392 } catch (InterruptedException x)
399 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
400 * secondary structure arrays at the given sequence position
402 * @param proteinStructureSubType
407 protected void setSecondaryStructure(STR proteinStructureSubType,
408 int pos, char[] secstr, char[] secstrcode)
410 switch (proteinStructureSubType)
429 switch (proteinStructureSubType)
435 secstrcode[pos] = 'H';
438 secstrcode[pos] = 'E';
446 * Convert any non-standard peptide codes to their standard code table
447 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
449 * @param threeLetterCode
453 protected void replaceNonCanonicalResidue(String threeLetterCode,
456 String canonical = ResidueProperties
457 .getCanonicalAminoAcid(threeLetterCode);
458 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
460 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
465 * Not implemented - returns null
468 public String print()
477 public void setCallbackFunction(String callbackType,
478 String callbackFunction)
483 public void notifyCallback(CBK cbType, Object[] data)
485 String strInfo = (data == null || data[1] == null ? null : data[1]
490 sendConsoleEcho(strInfo);
493 notifyScriptTermination((String) data[2],
494 ((Integer) data[3]).intValue());
497 String mystatus = (String) data[3];
498 if (mystatus.indexOf("Picked") >= 0
499 || mystatus.indexOf("Sequence") >= 0)
502 sendConsoleMessage(strInfo);
504 else if (mystatus.indexOf("Completed") >= 0)
506 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
507 strInfo.length() - 1));
511 sendConsoleMessage(data == null ? null : strInfo);
514 sendConsoleMessage(strInfo);
521 String lastConsoleEcho = "";
523 private void sendConsoleEcho(String string)
525 lastConsoleEcho += string;
526 lastConsoleEcho += "\n";
529 String lastConsoleMessage = "";
531 private void sendConsoleMessage(String string)
533 lastConsoleMessage += string;
534 lastConsoleMessage += "\n";
537 int lastScriptTermination = -1;
539 String lastScriptMessage = "";
541 private void notifyScriptTermination(String string, int intValue)
543 lastScriptMessage += string;
544 lastScriptMessage += "\n";
545 lastScriptTermination = intValue;
549 public boolean notifyEnabled(CBK callbackPick)
551 switch (callbackPick)
565 * Not implemented - returns null
568 public String eval(String strEval)
574 * Not implemented - returns null
577 public float[][] functionXY(String functionName, int x, int y)
583 * Not implemented - returns null
586 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
592 * Not implemented - returns null
595 public String createImage(String fileName, String imageType,
596 Object text_or_bytes, int quality)
602 * Not implemented - returns null
605 public Map<String, Object> getRegistryInfo()
614 public void showUrl(String url)
619 * Not implemented - returns null
622 public Dimension resizeInnerPanel(String data)
628 public Map<String, Object> getJSpecViewProperty(String arg0)
633 public boolean isPredictSecondaryStructure()
635 return predictSecondaryStructure;
638 public void setPredictSecondaryStructure(boolean predictSecondaryStructure)
640 this.predictSecondaryStructure = predictSecondaryStructure;
643 public boolean isVisibleChainAnnotation()
645 return visibleChainAnnotation;
648 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
650 this.visibleChainAnnotation = visibleChainAnnotation;