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(String inFile, String type)
70 public JmolParser(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 // ideally we do this
103 // setStructureFileType(jmolModel.evalString("show _fileType"));
104 // } catch (Exception q)
108 // instead, we distinguish .cif from non-.cif by filename
109 setStructureFileType(getDataName().toLowerCase().endsWith(".cif") ? PDBEntry.Type.MMCIF
110 .toString() : "PDB");
112 transformJmolModelToJalview(jmolModel.ms);
117 * create a headless jmol instance for dataprocessing
121 private Viewer getJmolData()
127 viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
128 null, "-x -o -n", this);
129 // ensure the 'new' (DSSP) not 'old' (Ramachandran) SS method is used
130 viewer.setBooleanProperty("defaultStructureDSSP", true);
131 } catch (ClassCastException x)
133 throw new Error(MessageManager.formatMessage(
134 "error.jmol_version_not_compatible_with_jalview_version",
135 new String[] { JmolViewer.getJmolVersion() }), x);
141 public void transformJmolModelToJalview(ModelSet ms) throws IOException
146 List<SequenceI> rna = new ArrayList<SequenceI>();
147 List<SequenceI> prot = new ArrayList<SequenceI>();
149 String pdbId = (String) ms.getInfo(0, "title");
151 List<Atom> significantAtoms = convertSignificantAtoms(ms);
152 for (Atom tmpatom : significantAtoms)
156 tmpchain = findChain(tmpatom.chain);
157 if (tmpatom.resNumIns.trim().equals(lastID))
159 // phosphorylated protein - seen both CA and P..
162 tmpchain.atoms.addElement(tmpatom);
163 } catch (Exception e)
165 tmpchain = new PDBChain(pdbId, tmpatom.chain);
166 getChains().add(tmpchain);
167 tmpchain.atoms.addElement(tmpatom);
169 lastID = tmpatom.resNumIns.trim();
178 setId(safeName(getDataName()));
180 for (PDBChain chain : getChains())
182 SequenceI chainseq = postProcessChain(chain);
192 if (StructureImportSettings.isProcessSecondaryStructure())
194 createAnnotation(chainseq, chain, ms.at);
197 } catch (OutOfMemoryError er)
200 .println("OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
201 throw new IOException(
203 .getString("exception.outofmemory_loading_mmcif_file"));
207 private List<Atom> convertSignificantAtoms(ModelSet ms)
209 List<Atom> significantAtoms = new ArrayList<Atom>();
210 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
211 org.jmol.modelset.Atom prevAtom = null;
212 for (org.jmol.modelset.Atom atom : ms.at)
214 if (atom.getAtomName().equalsIgnoreCase("CA")
215 || atom.getAtomName().equalsIgnoreCase("P"))
217 if (!atomValidated(atom, prevAtom, chainTerMap))
221 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
222 curAtom.atomIndex = atom.getIndex();
223 curAtom.chain = atom.getChainIDStr();
224 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
225 : atom.group.getInsertionCode();
226 curAtom.name = atom.getAtomName();
227 curAtom.number = atom.getAtomNumber();
228 curAtom.resName = atom.getGroup3(true);
229 curAtom.resNumber = atom.getResno();
230 curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
231 .getIndex()] : Float.valueOf(atom.getOccupancy100());
232 String fmt = new Format("%4i").form(curAtom.resNumber);
233 curAtom.resNumIns = (fmt + curAtom.insCode);
234 curAtom.tfactor = atom.getBfactor100() / 100f;
236 // significantAtoms.add(curAtom);
237 // ignore atoms from subsequent models
238 if (!significantAtoms.contains(curAtom))
240 significantAtoms.add(curAtom);
245 return significantAtoms;
248 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
249 org.jmol.modelset.Atom prevAtom,
250 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
252 // System.out.println("Atom: " + curAtom.getAtomNumber()
253 // + " Last atom index " + curAtom.group.lastAtomIndex);
254 if (chainTerMap == null || prevAtom == null)
258 String curAtomChId = curAtom.getChainIDStr();
259 String prevAtomChId = prevAtom.getChainIDStr();
260 // new chain encoutered
261 if (!prevAtomChId.equals(curAtomChId))
263 // On chain switch add previous chain termination to xTerMap if not exists
264 if (!chainTerMap.containsKey(prevAtomChId))
266 chainTerMap.put(prevAtomChId, prevAtom);
268 // if current atom belongs to an already terminated chain and the resNum
269 // diff < 5 then mark as valid and update termination Atom
270 if (chainTerMap.containsKey(curAtomChId))
272 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
276 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
278 chainTerMap.put(curAtomChId, curAtom);
284 // atom with previously terminated chain encountered
285 else if (chainTerMap.containsKey(curAtomChId))
287 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
291 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
293 chainTerMap.put(curAtomChId, curAtom);
298 // HETATM with resNum jump > 2
299 return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
303 private void createAnnotation(SequenceI sequence, PDBChain chain,
304 org.jmol.modelset.Atom[] jmolAtoms)
306 char[] secstr = new char[sequence.getLength()];
307 char[] secstrcode = new char[sequence.getLength()];
309 // Ensure Residue size equals Seq size
310 if (chain.residues.size() != sequence.getLength())
315 for (Residue residue : chain.residues)
317 Atom repAtom = residue.getAtoms().get(0);
318 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
319 .getProteinStructureSubType();
320 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
324 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
325 secstrcode, chain.id, sequence.getStart());
329 * Helper method that adds an AlignmentAnnotation for secondary structure to
330 * the sequence, provided at least one secondary structure prediction has been
341 protected void addSecondaryStructureAnnotation(String modelTitle,
342 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
345 char[] seq = sq.getSequence();
346 boolean ssFound = false;
347 Annotation asecstr[] = new Annotation[seq.length + firstResNum - 1];
348 for (int p = 0; p < seq.length; p++)
350 if (secstr[p] >= 'A' && secstr[p] <= 'z')
354 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
355 secstrcode[p], Float.NaN);
357 } catch (Exception e)
359 // e.printStackTrace();
366 String mt = modelTitle == null ? getDataName() : modelTitle;
368 AlignmentAnnotation ann = new AlignmentAnnotation(
369 "Secondary Structure", "Secondary Structure for " + mt,
371 ann.belowAlignment = true;
373 ann.autoCalculated = false;
374 ann.setCalcId(getClass().getName());
375 ann.adjustForAlignment();
376 ann.validateRangeAndDisplay();
377 annotations.add(ann);
378 sq.addAlignmentAnnotation(ann);
382 private void waitForScript(Viewer jmd)
384 while (jmd.isScriptExecuting())
390 } catch (InterruptedException x)
397 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
398 * secondary structure arrays at the given sequence position
400 * @param proteinStructureSubType
405 protected void setSecondaryStructure(STR proteinStructureSubType,
406 int pos, char[] secstr, char[] secstrcode)
408 switch (proteinStructureSubType)
427 switch (proteinStructureSubType)
433 secstrcode[pos] = 'H';
436 secstrcode[pos] = 'E';
444 * Convert any non-standard peptide codes to their standard code table
445 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
447 * @param threeLetterCode
451 protected void replaceNonCanonicalResidue(String threeLetterCode,
454 String canonical = ResidueProperties
455 .getCanonicalAminoAcid(threeLetterCode);
456 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
458 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
463 * Not implemented - returns null
466 public String print()
475 public void setCallbackFunction(String callbackType,
476 String callbackFunction)
481 public void notifyCallback(CBK cbType, Object[] data)
483 String strInfo = (data == null || data[1] == null ? null : data[1]
488 sendConsoleEcho(strInfo);
491 notifyScriptTermination((String) data[2],
492 ((Integer) data[3]).intValue());
495 String mystatus = (String) data[3];
496 if (mystatus.indexOf("Picked") >= 0
497 || mystatus.indexOf("Sequence") >= 0)
500 sendConsoleMessage(strInfo);
502 else if (mystatus.indexOf("Completed") >= 0)
504 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
505 strInfo.length() - 1));
509 sendConsoleMessage(data == null ? null : strInfo);
512 sendConsoleMessage(strInfo);
519 String lastConsoleEcho = "";
521 private void sendConsoleEcho(String string)
523 lastConsoleEcho += string;
524 lastConsoleEcho += "\n";
527 String lastConsoleMessage = "";
529 private void sendConsoleMessage(String string)
531 lastConsoleMessage += string;
532 lastConsoleMessage += "\n";
535 int lastScriptTermination = -1;
537 String lastScriptMessage = "";
539 private void notifyScriptTermination(String string, int intValue)
541 lastScriptMessage += string;
542 lastScriptMessage += "\n";
543 lastScriptTermination = intValue;
547 public boolean notifyEnabled(CBK callbackPick)
549 switch (callbackPick)
563 * Not implemented - returns null
566 public String eval(String strEval)
572 * Not implemented - returns null
575 public float[][] functionXY(String functionName, int x, int y)
581 * Not implemented - returns null
584 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
590 * Not implemented - returns null
593 public String createImage(String fileName, String imageType,
594 Object text_or_bytes, int quality)
600 * Not implemented - returns null
603 public Map<String, Object> getRegistryInfo()
612 public void showUrl(String url)
617 * Not implemented - returns null
620 public Dimension resizeInnerPanel(String data)
626 public Map<String, Object> getJSpecViewProperty(String arg0)
631 public boolean isPredictSecondaryStructure()
633 return predictSecondaryStructure;
636 public void setPredictSecondaryStructure(boolean predictSecondaryStructure)
638 this.predictSecondaryStructure = predictSecondaryStructure;
641 public boolean isVisibleChainAnnotation()
643 return visibleChainAnnotation;
646 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
648 this.visibleChainAnnotation = visibleChainAnnotation;