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.DataSourceType;
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, DataSourceType sourceType)
67 super(inFile, sourceType);
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 transformJmolModelToJalview(jmolModel.ms);
106 * create a headless jmol instance for dataprocessing
110 private Viewer getJmolData()
116 viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
117 null, "-x -o -n", this);
118 // ensure the 'new' (DSSP) not 'old' (Ramachandran) SS method is used
119 viewer.setBooleanProperty("defaultStructureDSSP", true);
120 } catch (ClassCastException x)
122 throw new Error(MessageManager.formatMessage(
123 "error.jmol_version_not_compatible_with_jalview_version",
124 new String[] { JmolViewer.getJmolVersion() }), x);
130 public void transformJmolModelToJalview(ModelSet ms) throws IOException
135 List<SequenceI> rna = new ArrayList<SequenceI>();
136 List<SequenceI> prot = new ArrayList<SequenceI>();
138 String pdbId = (String) ms.getInfo(0, "title");
140 List<Atom> significantAtoms = convertSignificantAtoms(ms);
141 for (Atom tmpatom : significantAtoms)
145 tmpchain = findChain(tmpatom.chain);
146 if (tmpatom.resNumIns.trim().equals(lastID))
148 // phosphorylated protein - seen both CA and P..
151 tmpchain.atoms.addElement(tmpatom);
152 } catch (Exception e)
154 tmpchain = new PDBChain(pdbId, tmpatom.chain);
155 getChains().add(tmpchain);
156 tmpchain.atoms.addElement(tmpatom);
158 lastID = tmpatom.resNumIns.trim();
167 setId(safeName(getDataName()));
169 for (PDBChain chain : getChains())
171 SequenceI chainseq = postProcessChain(chain);
181 if (StructureImportSettings.isProcessSecondaryStructure())
183 createAnnotation(chainseq, chain, ms.at);
186 } catch (OutOfMemoryError er)
189 .println("OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
190 throw new IOException(
192 .getString("exception.outofmemory_loading_mmcif_file"));
196 private List<Atom> convertSignificantAtoms(ModelSet ms)
198 List<Atom> significantAtoms = new ArrayList<Atom>();
199 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
200 org.jmol.modelset.Atom prevAtom = null;
201 for (org.jmol.modelset.Atom atom : ms.at)
203 if (atom.getAtomName().equalsIgnoreCase("CA")
204 || atom.getAtomName().equalsIgnoreCase("P"))
206 if (!atomValidated(atom, prevAtom, chainTerMap))
210 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
211 curAtom.atomIndex = atom.getIndex();
212 curAtom.chain = atom.getChainIDStr();
213 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
214 : atom.group.getInsertionCode();
215 curAtom.name = atom.getAtomName();
216 curAtom.number = atom.getAtomNumber();
217 curAtom.resName = atom.getGroup3(true);
218 curAtom.resNumber = atom.getResno();
219 curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
220 .getIndex()] : Float.valueOf(atom.getOccupancy100());
221 curAtom.resNumIns = ("" + curAtom.resNumber + curAtom.insCode)
223 curAtom.tfactor = atom.getBfactor100() / 100f;
225 // significantAtoms.add(curAtom);
226 // ignore atoms from subsequent models
227 if (!significantAtoms.contains(curAtom))
229 significantAtoms.add(curAtom);
234 return significantAtoms;
237 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
238 org.jmol.modelset.Atom prevAtom,
239 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
241 // System.out.println("Atom: " + curAtom.getAtomNumber()
242 // + " Last atom index " + curAtom.group.lastAtomIndex);
243 if (chainTerMap == null || prevAtom == null)
247 String curAtomChId = curAtom.getChainIDStr();
248 String prevAtomChId = prevAtom.getChainIDStr();
249 // new chain encoutered
250 if (!prevAtomChId.equals(curAtomChId))
252 // On chain switch add previous chain termination to xTerMap if not exists
253 if (!chainTerMap.containsKey(prevAtomChId))
255 chainTerMap.put(prevAtomChId, prevAtom);
257 // if current atom belongs to an already terminated chain and the resNum
258 // diff < 5 then mark as valid and update termination Atom
259 if (chainTerMap.containsKey(curAtomChId))
261 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
263 chainTerMap.put(curAtomChId, curAtom);
269 // atom with previously terminated chain encountered
270 else if (chainTerMap.containsKey(curAtomChId))
272 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
274 chainTerMap.put(curAtomChId, curAtom);
279 // HETATM with resNum jump > 2
280 return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
284 private void createAnnotation(SequenceI sequence, PDBChain chain,
285 org.jmol.modelset.Atom[] jmolAtoms)
287 char[] secstr = new char[sequence.getLength()];
288 char[] secstrcode = new char[sequence.getLength()];
290 // Ensure Residue size equals Seq size
291 if (chain.residues.size() != sequence.getLength())
296 for (Residue residue : chain.residues)
298 Atom repAtom = residue.getAtoms().get(0);
299 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
300 .getProteinStructureSubType();
301 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
305 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
306 secstrcode, chain.id, sequence.getStart());
310 * Helper method that adds an AlignmentAnnotation for secondary structure to
311 * the sequence, provided at least one secondary structure prediction has been
322 protected void addSecondaryStructureAnnotation(String modelTitle,
323 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
326 char[] seq = sq.getSequence();
327 boolean ssFound = false;
328 Annotation asecstr[] = new Annotation[seq.length + firstResNum - 1];
329 for (int p = 0; p < seq.length; p++)
331 if (secstr[p] >= 'A' && secstr[p] <= 'z')
335 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
336 secstrcode[p], Float.NaN);
338 } catch (Exception e)
340 // e.printStackTrace();
347 String mt = modelTitle == null ? getDataName() : modelTitle;
349 AlignmentAnnotation ann = new AlignmentAnnotation(
350 "Secondary Structure", "Secondary Structure for " + mt,
352 ann.belowAlignment = true;
354 ann.autoCalculated = false;
355 ann.setCalcId(getClass().getName());
356 ann.adjustForAlignment();
357 ann.validateRangeAndDisplay();
358 annotations.add(ann);
359 sq.addAlignmentAnnotation(ann);
363 private void waitForScript(Viewer jmd)
365 while (jmd.isScriptExecuting())
371 } catch (InterruptedException x)
378 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
379 * secondary structure arrays at the given sequence position
381 * @param proteinStructureSubType
386 protected void setSecondaryStructure(STR proteinStructureSubType,
387 int pos, char[] secstr, char[] secstrcode)
389 switch (proteinStructureSubType)
408 switch (proteinStructureSubType)
414 secstrcode[pos] = 'H';
417 secstrcode[pos] = 'E';
425 * Convert any non-standard peptide codes to their standard code table
426 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
428 * @param threeLetterCode
432 protected void replaceNonCanonicalResidue(String threeLetterCode,
435 String canonical = ResidueProperties
436 .getCanonicalAminoAcid(threeLetterCode);
437 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
439 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
444 * Not implemented - returns null
447 public String print(SequenceI[] seqs, boolean jvSuffix)
456 public void setCallbackFunction(String callbackType,
457 String callbackFunction)
462 public void notifyCallback(CBK cbType, Object[] data)
464 String strInfo = (data == null || data[1] == null ? null : data[1]
469 sendConsoleEcho(strInfo);
472 notifyScriptTermination((String) data[2],
473 ((Integer) data[3]).intValue());
476 String mystatus = (String) data[3];
477 if (mystatus.indexOf("Picked") >= 0
478 || mystatus.indexOf("Sequence") >= 0)
481 sendConsoleMessage(strInfo);
483 else if (mystatus.indexOf("Completed") >= 0)
485 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
486 strInfo.length() - 1));
490 sendConsoleMessage(data == null ? null : strInfo);
493 sendConsoleMessage(strInfo);
500 String lastConsoleEcho = "";
502 private void sendConsoleEcho(String string)
504 lastConsoleEcho += string;
505 lastConsoleEcho += "\n";
508 String lastConsoleMessage = "";
510 private void sendConsoleMessage(String string)
512 lastConsoleMessage += string;
513 lastConsoleMessage += "\n";
516 int lastScriptTermination = -1;
518 String lastScriptMessage = "";
520 private void notifyScriptTermination(String string, int intValue)
522 lastScriptMessage += string;
523 lastScriptMessage += "\n";
524 lastScriptTermination = intValue;
528 public boolean notifyEnabled(CBK callbackPick)
530 switch (callbackPick)
544 * Not implemented - returns null
547 public String eval(String strEval)
553 * Not implemented - returns null
556 public float[][] functionXY(String functionName, int x, int y)
562 * Not implemented - returns null
565 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
571 * Not implemented - returns null
574 public String createImage(String fileName, String imageType,
575 Object text_or_bytes, int quality)
581 * Not implemented - returns null
584 public Map<String, Object> getRegistryInfo()
593 public void showUrl(String url)
598 * Not implemented - returns null
601 public Dimension resizeInnerPanel(String data)
607 public Map<String, Object> getJSpecViewProperty(String arg0)
612 public boolean isPredictSecondaryStructure()
614 return predictSecondaryStructure;
617 public void setPredictSecondaryStructure(boolean predictSecondaryStructure)
619 this.predictSecondaryStructure = predictSecondaryStructure;
622 public boolean isVisibleChainAnnotation()
624 return visibleChainAnnotation;
627 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
629 this.visibleChainAnnotation = visibleChainAnnotation;