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();
213 curAtom.name = atom.getAtomName();
214 curAtom.number = atom.getAtomNumber();
215 curAtom.resName = atom.getGroup3(true);
216 curAtom.resNumber = atom.getResno();
217 curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
218 .getIndex()] : Float.valueOf(atom.getOccupancy100());
219 curAtom.resNumIns = "" + curAtom.resNumber + curAtom.insCode;
220 curAtom.tfactor = atom.getBfactor100() / 100f;
222 significantAtoms.add(curAtom);
226 return significantAtoms;
229 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
230 org.jmol.modelset.Atom prevAtom,
231 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
233 if (chainTerMap == null || prevAtom == null)
237 String curAtomChId = curAtom.getChainIDStr();
238 String prevAtomChId = prevAtom.getChainIDStr();
239 // new chain encoutered
240 if (!prevAtomChId.equals(curAtomChId))
242 // On chain switch add previous chain termination to xTerMap if not exists
243 if (!chainTerMap.containsKey(prevAtomChId))
245 chainTerMap.put(prevAtomChId, prevAtom);
247 // if current atom belongs to an already terminated chain and the resNum
248 // diff < 5 then mark as valid and update termination Atom
249 if (chainTerMap.containsKey(curAtomChId))
251 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
253 chainTerMap.put(curAtomChId, curAtom);
259 // atom with previously terminated chain encountered
260 else if (chainTerMap.containsKey(curAtomChId))
262 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
264 chainTerMap.put(curAtomChId, curAtom);
269 // HETATM with resNum jump > 2
270 return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
274 private void createAnnotation(SequenceI sequence, PDBChain chain,
275 org.jmol.modelset.Atom[] jmolAtoms)
277 char[] secstr = new char[sequence.getLength()];
278 char[] secstrcode = new char[sequence.getLength()];
280 // Ensure Residue size equals Seq size
281 if (chain.residues.size() != sequence.getLength())
286 for (Residue residue : chain.residues)
288 Atom repAtom = residue.getAtoms().get(0);
289 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
290 .getProteinStructureSubType();
291 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
295 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
296 secstrcode, chain.id, sequence.getStart());
300 * Helper method that adds an AlignmentAnnotation for secondary structure to
301 * the sequence, provided at least one secondary structure prediction has been
312 protected void addSecondaryStructureAnnotation(String modelTitle,
313 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
316 char[] seq = sq.getSequence();
317 boolean ssFound = false;
318 Annotation asecstr[] = new Annotation[seq.length + firstResNum - 1];
319 for (int p = 0; p < seq.length; p++)
321 if (secstr[p] >= 'A' && secstr[p] <= 'z')
325 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
326 secstrcode[p], Float.NaN);
328 } catch (Exception e)
330 // e.printStackTrace();
337 String mt = modelTitle == null ? getDataName() : modelTitle;
339 AlignmentAnnotation ann = new AlignmentAnnotation(
340 "Secondary Structure", "Secondary Structure for " + mt,
342 ann.belowAlignment = true;
344 ann.autoCalculated = false;
345 ann.setCalcId(getClass().getName());
346 ann.adjustForAlignment();
347 ann.validateRangeAndDisplay();
348 annotations.add(ann);
349 sq.addAlignmentAnnotation(ann);
353 private void waitForScript(Viewer jmd)
355 while (jmd.isScriptExecuting())
361 } catch (InterruptedException x)
368 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
369 * secondary structure arrays at the given sequence position
371 * @param proteinStructureSubType
376 protected void setSecondaryStructure(STR proteinStructureSubType,
377 int pos, char[] secstr, char[] secstrcode)
379 switch (proteinStructureSubType)
398 switch (proteinStructureSubType)
404 secstrcode[pos] = 'H';
407 secstrcode[pos] = 'E';
415 * Convert any non-standard peptide codes to their standard code table
416 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
418 * @param threeLetterCode
422 protected void replaceNonCanonicalResidue(String threeLetterCode,
425 String canonical = ResidueProperties
426 .getCanonicalAminoAcid(threeLetterCode);
427 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
429 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
434 * Not implemented - returns null
437 public String print()
446 public void setCallbackFunction(String callbackType,
447 String callbackFunction)
452 public void notifyCallback(CBK cbType, Object[] data)
454 String strInfo = (data == null || data[1] == null ? null : data[1]
459 sendConsoleEcho(strInfo);
462 notifyScriptTermination((String) data[2],
463 ((Integer) data[3]).intValue());
466 String mystatus = (String) data[3];
467 if (mystatus.indexOf("Picked") >= 0
468 || mystatus.indexOf("Sequence") >= 0)
471 sendConsoleMessage(strInfo);
473 else if (mystatus.indexOf("Completed") >= 0)
475 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
476 strInfo.length() - 1));
480 sendConsoleMessage(data == null ? null : strInfo);
483 sendConsoleMessage(strInfo);
490 String lastConsoleEcho = "";
492 private void sendConsoleEcho(String string)
494 lastConsoleEcho += string;
495 lastConsoleEcho += "\n";
498 String lastConsoleMessage = "";
500 private void sendConsoleMessage(String string)
502 lastConsoleMessage += string;
503 lastConsoleMessage += "\n";
506 int lastScriptTermination = -1;
508 String lastScriptMessage = "";
510 private void notifyScriptTermination(String string, int intValue)
512 lastScriptMessage += string;
513 lastScriptMessage += "\n";
514 lastScriptTermination = intValue;
518 public boolean notifyEnabled(CBK callbackPick)
520 switch (callbackPick)
534 * Not implemented - returns null
537 public String eval(String strEval)
543 * Not implemented - returns null
546 public float[][] functionXY(String functionName, int x, int y)
552 * Not implemented - returns null
555 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
561 * Not implemented - returns null
564 public String createImage(String fileName, String imageType,
565 Object text_or_bytes, int quality)
571 * Not implemented - returns null
574 public Map<String, Object> getRegistryInfo()
583 public void showUrl(String url)
588 * Not implemented - returns null
591 public Dimension resizeInnerPanel(String data)
597 public Map<String, Object> getJSpecViewProperty(String arg0)
602 public boolean isPredictSecondaryStructure()
604 return predictSecondaryStructure;
607 public void setPredictSecondaryStructure(boolean predictSecondaryStructure)
609 this.predictSecondaryStructure = predictSecondaryStructure;
612 public boolean isVisibleChainAnnotation()
614 return visibleChainAnnotation;
617 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
619 this.visibleChainAnnotation = visibleChainAnnotation;