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) throws IOException
69 public JmolParser(FileParse fp) throws IOException
79 * Calls the Jmol library to parse the PDB/mmCIF file, and then inspects the
80 * resulting object model to generate Jalview-style sequences, with secondary
81 * structure annotation added where available (i.e. where it has been computed
82 * by Jmol using DSSP).
84 * @see jalview.io.AlignFile#parse()
87 public void parse() throws IOException
89 setChains(new Vector<PDBChain>());
90 Viewer jmolModel = getJmolData();
91 jmolModel.openReader(getDataName(), getDataName(), getReader());
92 waitForScript(jmolModel);
95 * Convert one or more Jmol Model objects to Jalview sequences
97 if (jmolModel.ms.mc > 0)
102 // setStructureFileType(jmolModel.evalString("show _fileType"));
103 // } catch (Exception q)
107 // instead, we distinguish .cif from non-.cif by filename
108 setStructureFileType(getDataName().toLowerCase().endsWith(".cif") ? PDBEntry.Type.MMCIF
109 .toString() : "PDB");
111 transformJmolModelToJalview(jmolModel.ms);
116 * create a headless jmol instance for dataprocessing
120 private Viewer getJmolData()
127 * params -o (output to sysout) -i (no info logging, less verbose)
128 * -n (nodisplay) -x (exit when finished)
129 * see http://wiki.jmol.org/index.php/Jmol_Application
131 viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
132 null, "-x -o -n -i", this);
133 // ensure the 'new' (DSSP) not 'old' (Ramachandran) SS method is used
134 viewer.setBooleanProperty("defaultStructureDSSP", true);
135 } catch (ClassCastException x)
137 throw new Error(MessageManager.formatMessage(
138 "error.jmol_version_not_compatible_with_jalview_version",
139 new String[] { JmolViewer.getJmolVersion() }), x);
145 public void transformJmolModelToJalview(ModelSet ms) throws IOException
150 List<SequenceI> rna = new ArrayList<SequenceI>();
151 List<SequenceI> prot = new ArrayList<SequenceI>();
153 String pdbId = (String) ms.getInfo(0, "title");
155 List<Atom> significantAtoms = convertSignificantAtoms(ms);
156 for (Atom tmpatom : significantAtoms)
160 tmpchain = findChain(tmpatom.chain);
161 if (tmpatom.resNumIns.trim().equals(lastID))
163 // phosphorylated protein - seen both CA and P..
166 tmpchain.atoms.addElement(tmpatom);
167 } catch (Exception e)
169 tmpchain = new PDBChain(pdbId, tmpatom.chain);
170 getChains().add(tmpchain);
171 tmpchain.atoms.addElement(tmpatom);
173 lastID = tmpatom.resNumIns.trim();
182 setId(safeName(getDataName()));
184 for (PDBChain chain : getChains())
186 SequenceI chainseq = postProcessChain(chain);
196 if (StructureImportSettings.isProcessSecondaryStructure())
198 createAnnotation(chainseq, chain, ms.at);
201 } catch (OutOfMemoryError er)
204 .println("OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
205 throw new IOException(
207 .getString("exception.outofmemory_loading_mmcif_file"));
211 private List<Atom> convertSignificantAtoms(ModelSet ms)
213 List<Atom> significantAtoms = new ArrayList<Atom>();
214 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
215 org.jmol.modelset.Atom prevAtom = null;
216 for (org.jmol.modelset.Atom atom : ms.at)
218 if (atom.getAtomName().equalsIgnoreCase("CA")
219 || atom.getAtomName().equalsIgnoreCase("P"))
221 if (!atomValidated(atom, prevAtom, chainTerMap))
225 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
226 curAtom.atomIndex = atom.getIndex();
227 curAtom.chain = atom.getChainIDStr();
228 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
229 : atom.group.getInsertionCode();
230 curAtom.name = atom.getAtomName();
231 curAtom.number = atom.getAtomNumber();
232 curAtom.resName = atom.getGroup3(true);
233 curAtom.resNumber = atom.getResno();
234 curAtom.occupancy = ms.occupancies != null ? ms.occupancies[atom
235 .getIndex()] : Float.valueOf(atom.getOccupancy100());
236 String fmt = new Format("%4i").form(curAtom.resNumber);
237 curAtom.resNumIns = (fmt + curAtom.insCode);
238 curAtom.tfactor = atom.getBfactor100() / 100f;
240 // significantAtoms.add(curAtom);
241 // ignore atoms from subsequent models
242 if (!significantAtoms.contains(curAtom))
244 significantAtoms.add(curAtom);
249 return significantAtoms;
252 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
253 org.jmol.modelset.Atom prevAtom,
254 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
256 // System.out.println("Atom: " + curAtom.getAtomNumber()
257 // + " Last atom index " + curAtom.group.lastAtomIndex);
258 if (chainTerMap == null || prevAtom == null)
262 String curAtomChId = curAtom.getChainIDStr();
263 String prevAtomChId = prevAtom.getChainIDStr();
264 // new chain encoutered
265 if (!prevAtomChId.equals(curAtomChId))
267 // On chain switch add previous chain termination to xTerMap if not exists
268 if (!chainTerMap.containsKey(prevAtomChId))
270 chainTerMap.put(prevAtomChId, prevAtom);
272 // if current atom belongs to an already terminated chain and the resNum
273 // diff < 5 then mark as valid and update termination Atom
274 if (chainTerMap.containsKey(curAtomChId))
276 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
280 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
282 chainTerMap.put(curAtomChId, curAtom);
288 // atom with previously terminated chain encountered
289 else if (chainTerMap.containsKey(curAtomChId))
291 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
295 if ((curAtom.getResno() - chainTerMap.get(curAtomChId).getResno()) < 5)
297 chainTerMap.put(curAtomChId, curAtom);
302 // HETATM with resNum jump > 2
303 return !(curAtom.isHetero() && ((curAtom.getResno() - prevAtom
307 private void createAnnotation(SequenceI sequence, PDBChain chain,
308 org.jmol.modelset.Atom[] jmolAtoms)
310 char[] secstr = new char[sequence.getLength()];
311 char[] secstrcode = new char[sequence.getLength()];
313 // Ensure Residue size equals Seq size
314 if (chain.residues.size() != sequence.getLength())
319 for (Residue residue : chain.residues)
321 Atom repAtom = residue.getAtoms().get(0);
322 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
323 .getProteinStructureSubType();
324 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
328 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
329 secstrcode, chain.id, sequence.getStart());
333 * Helper method that adds an AlignmentAnnotation for secondary structure to
334 * the sequence, provided at least one secondary structure prediction has been
345 protected void addSecondaryStructureAnnotation(String modelTitle,
346 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
349 char[] seq = sq.getSequence();
350 boolean ssFound = false;
351 Annotation asecstr[] = new Annotation[seq.length + firstResNum - 1];
352 for (int p = 0; p < seq.length; p++)
354 if (secstr[p] >= 'A' && secstr[p] <= 'z')
358 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
359 secstrcode[p], Float.NaN);
361 } catch (Exception e)
363 // e.printStackTrace();
370 String mt = modelTitle == null ? getDataName() : modelTitle;
372 AlignmentAnnotation ann = new AlignmentAnnotation(
373 "Secondary Structure", "Secondary Structure for " + mt,
375 ann.belowAlignment = true;
377 ann.autoCalculated = false;
378 ann.setCalcId(getClass().getName());
379 ann.adjustForAlignment();
380 ann.validateRangeAndDisplay();
381 annotations.add(ann);
382 sq.addAlignmentAnnotation(ann);
386 private void waitForScript(Viewer jmd)
388 while (jmd.isScriptExecuting())
394 } catch (InterruptedException x)
401 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
402 * secondary structure arrays at the given sequence position
404 * @param proteinStructureSubType
409 protected void setSecondaryStructure(STR proteinStructureSubType,
410 int pos, char[] secstr, char[] secstrcode)
412 switch (proteinStructureSubType)
431 switch (proteinStructureSubType)
437 secstrcode[pos] = 'H';
440 secstrcode[pos] = 'E';
448 * Convert any non-standard peptide codes to their standard code table
449 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
451 * @param threeLetterCode
455 protected void replaceNonCanonicalResidue(String threeLetterCode,
458 String canonical = ResidueProperties
459 .getCanonicalAminoAcid(threeLetterCode);
460 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
462 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
467 * Not implemented - returns null
470 public String print()
479 public void setCallbackFunction(String callbackType,
480 String callbackFunction)
485 public void notifyCallback(CBK cbType, Object[] data)
487 String strInfo = (data == null || data[1] == null ? null : data[1]
492 sendConsoleEcho(strInfo);
495 notifyScriptTermination((String) data[2],
496 ((Integer) data[3]).intValue());
499 String mystatus = (String) data[3];
500 if (mystatus.indexOf("Picked") >= 0
501 || mystatus.indexOf("Sequence") >= 0)
504 sendConsoleMessage(strInfo);
506 else if (mystatus.indexOf("Completed") >= 0)
508 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
509 strInfo.length() - 1));
513 sendConsoleMessage(data == null ? null : strInfo);
516 sendConsoleMessage(strInfo);
523 String lastConsoleEcho = "";
525 private void sendConsoleEcho(String string)
527 lastConsoleEcho += string;
528 lastConsoleEcho += "\n";
531 String lastConsoleMessage = "";
533 private void sendConsoleMessage(String string)
535 lastConsoleMessage += string;
536 lastConsoleMessage += "\n";
539 int lastScriptTermination = -1;
541 String lastScriptMessage = "";
543 private void notifyScriptTermination(String string, int intValue)
545 lastScriptMessage += string;
546 lastScriptMessage += "\n";
547 lastScriptTermination = intValue;
551 public boolean notifyEnabled(CBK callbackPick)
553 switch (callbackPick)
567 * Not implemented - returns null
570 public String eval(String strEval)
576 * Not implemented - returns null
579 public float[][] functionXY(String functionName, int x, int y)
585 * Not implemented - returns null
588 public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
594 * Not implemented - returns null
597 public String createImage(String fileName, String imageType,
598 Object text_or_bytes, int quality)
604 * Not implemented - returns null
607 public Map<String, Object> getRegistryInfo()
616 public void showUrl(String url)
621 * Not implemented - returns null
624 public Dimension resizeInnerPanel(String data)
630 public Map<String, Object> getJSpecViewProperty(String arg0)
635 public boolean isPredictSecondaryStructure()
637 return predictSecondaryStructure;
640 public void setPredictSecondaryStructure(boolean predictSecondaryStructure)
642 this.predictSecondaryStructure = predictSecondaryStructure;
645 public boolean isVisibleChainAnnotation()
647 return visibleChainAnnotation;
650 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
652 this.visibleChainAnnotation = visibleChainAnnotation;