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.DataSourceType;
28 import jalview.io.FileParse;
29 import jalview.io.StructureFile;
30 import jalview.schemes.ResidueProperties;
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 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 immediate, String inFile,
63 DataSourceType sourceType) throws IOException
65 super(immediate, inFile, sourceType);
68 public JmolParser(String inFile, DataSourceType sourceType)
71 super(inFile, sourceType);
74 public JmolParser(FileParse fp) throws IOException
84 * Calls the Jmol library to parse the PDB/mmCIF file, and then inspects the
85 * resulting object model to generate Jalview-style sequences, with secondary
86 * structure annotation added where available (i.e. where it has been computed
87 * by Jmol using DSSP).
89 * @see jalview.io.AlignFile#parse()
92 public void parse() throws IOException
94 setChains(new Vector<PDBChain>());
95 Viewer jmolModel = getJmolData();
96 jmolModel.openReader(getDataName(), getDataName(), getReader());
97 waitForScript(jmolModel);
100 * Convert one or more Jmol Model objects to Jalview sequences
102 if (jmolModel.ms.mc > 0)
104 // ideally we do this
107 // setStructureFileType(jmolModel.evalString("show _fileType"));
108 // } catch (Exception q)
112 // instead, we distinguish .cif from non-.cif by filename
113 setStructureFileType(getDataName().toLowerCase().endsWith(".cif")
114 ? PDBEntry.Type.MMCIF.toString()
117 transformJmolModelToJalview(jmolModel.ms);
122 * create a headless jmol instance for dataprocessing
126 private Viewer getJmolData()
133 * params -o (output to sysout) -n (nodisplay) -x (exit when finished)
134 * see http://wiki.jmol.org/index.php/Jmol_Application
136 viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
137 null, "-x -o -n", this);
138 // ensure the 'new' (DSSP) not 'old' (Ramachandran) SS method is used
139 viewer.setBooleanProperty("defaultStructureDSSP", true);
140 } catch (ClassCastException x)
142 throw new Error(MessageManager.formatMessage(
143 "error.jmol_version_not_compatible_with_jalview_version",
145 { JmolViewer.getJmolVersion() }), x);
151 public void transformJmolModelToJalview(ModelSet ms) throws IOException
156 List<SequenceI> rna = new ArrayList<SequenceI>();
157 List<SequenceI> prot = new ArrayList<SequenceI>();
159 String pdbId = (String) ms.getInfo(0, "title");
163 setId(safeName(getDataName()));
164 setPDBIdAvailable(false);
169 setPDBIdAvailable(true);
171 List<Atom> significantAtoms = convertSignificantAtoms(ms);
172 for (Atom tmpatom : significantAtoms)
176 tmpchain = findChain(tmpatom.chain);
177 if (tmpatom.resNumIns.trim().equals(lastID))
179 // phosphorylated protein - seen both CA and P..
182 tmpchain.atoms.addElement(tmpatom);
183 } catch (Exception e)
185 tmpchain = new PDBChain(getId(), tmpatom.chain);
186 getChains().add(tmpchain);
187 tmpchain.atoms.addElement(tmpatom);
189 lastID = tmpatom.resNumIns.trim();
191 if (isParseImmediately())
193 // configure parsing settings from the static singleton
200 for (PDBChain chain : getChains())
202 SequenceI chainseq = postProcessChain(chain);
212 // look at local setting for adding secondary tructure
213 if (predictSecondaryStructure)
215 createAnnotation(chainseq, chain, ms.at);
218 } catch (OutOfMemoryError er)
221 "OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
222 throw new IOException(MessageManager
223 .getString("exception.outofmemory_loading_mmcif_file"));
227 private List<Atom> convertSignificantAtoms(ModelSet ms)
229 List<Atom> significantAtoms = new ArrayList<Atom>();
230 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
231 org.jmol.modelset.Atom prevAtom = null;
232 for (org.jmol.modelset.Atom atom : ms.at)
234 if (atom.getAtomName().equalsIgnoreCase("CA")
235 || atom.getAtomName().equalsIgnoreCase("P"))
237 if (!atomValidated(atom, prevAtom, chainTerMap))
241 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
242 curAtom.atomIndex = atom.getIndex();
243 curAtom.chain = atom.getChainIDStr();
244 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
245 : atom.group.getInsertionCode();
246 curAtom.name = atom.getAtomName();
247 curAtom.number = atom.getAtomNumber();
248 curAtom.resName = atom.getGroup3(true);
249 curAtom.resNumber = atom.getResno();
250 curAtom.occupancy = ms.occupancies != null
251 ? ms.occupancies[atom.getIndex()]
252 : Float.valueOf(atom.getOccupancy100());
253 String fmt = new Format("%4i").form(curAtom.resNumber);
254 curAtom.resNumIns = (fmt + curAtom.insCode);
255 curAtom.tfactor = atom.getBfactor100() / 100f;
257 // significantAtoms.add(curAtom);
258 // ignore atoms from subsequent models
259 if (!significantAtoms.contains(curAtom))
261 significantAtoms.add(curAtom);
266 return significantAtoms;
269 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
270 org.jmol.modelset.Atom prevAtom,
271 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
273 // System.out.println("Atom: " + curAtom.getAtomNumber()
274 // + " Last atom index " + curAtom.group.lastAtomIndex);
275 if (chainTerMap == null || prevAtom == null)
279 String curAtomChId = curAtom.getChainIDStr();
280 String prevAtomChId = prevAtom.getChainIDStr();
281 // new chain encoutered
282 if (!prevAtomChId.equals(curAtomChId))
284 // On chain switch add previous chain termination to xTerMap if not exists
285 if (!chainTerMap.containsKey(prevAtomChId))
287 chainTerMap.put(prevAtomChId, prevAtom);
289 // if current atom belongs to an already terminated chain and the resNum
290 // diff < 5 then mark as valid and update termination Atom
291 if (chainTerMap.containsKey(curAtomChId))
293 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
297 if ((curAtom.getResno()
298 - chainTerMap.get(curAtomChId).getResno()) < 5)
300 chainTerMap.put(curAtomChId, curAtom);
306 // atom with previously terminated chain encountered
307 else if (chainTerMap.containsKey(curAtomChId))
309 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
313 if ((curAtom.getResno()
314 - chainTerMap.get(curAtomChId).getResno()) < 5)
316 chainTerMap.put(curAtomChId, curAtom);
321 // HETATM with resNum jump > 2
322 return !(curAtom.isHetero()
323 && ((curAtom.getResno() - prevAtom.getResno()) > 2));
326 private void createAnnotation(SequenceI sequence, PDBChain chain,
327 org.jmol.modelset.Atom[] jmolAtoms)
329 char[] secstr = new char[sequence.getLength()];
330 char[] secstrcode = new char[sequence.getLength()];
332 // Ensure Residue size equals Seq size
333 if (chain.residues.size() != sequence.getLength())
338 for (Residue residue : chain.residues)
340 Atom repAtom = residue.getAtoms().get(0);
341 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
342 .getProteinStructureSubType();
343 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
347 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
348 secstrcode, chain.id, sequence.getStart());
352 * Helper method that adds an AlignmentAnnotation for secondary structure to
353 * the sequence, provided at least one secondary structure prediction has been
364 protected void addSecondaryStructureAnnotation(String modelTitle,
365 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
368 int length = sq.getLength();
369 boolean ssFound = false;
370 Annotation asecstr[] = new Annotation[length + firstResNum - 1];
371 for (int p = 0; p < length; p++)
373 if (secstr[p] >= 'A' && secstr[p] <= 'z')
377 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
378 secstrcode[p], Float.NaN);
380 } catch (Exception e)
382 // e.printStackTrace();
389 String mt = modelTitle == null ? getDataName() : modelTitle;
391 AlignmentAnnotation ann = new AlignmentAnnotation(
392 "Secondary Structure", "Secondary Structure for " + mt,
394 ann.belowAlignment = true;
396 ann.autoCalculated = false;
397 ann.setCalcId(getClass().getName());
398 ann.adjustForAlignment();
399 ann.validateRangeAndDisplay();
400 annotations.add(ann);
401 sq.addAlignmentAnnotation(ann);
405 private void waitForScript(Viewer jmd)
407 while (jmd.isScriptExecuting())
413 } catch (InterruptedException x)
420 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
421 * secondary structure arrays at the given sequence position
423 * @param proteinStructureSubType
428 protected void setSecondaryStructure(STR proteinStructureSubType, int pos,
429 char[] secstr, char[] secstrcode)
431 switch (proteinStructureSubType)
450 switch (proteinStructureSubType)
456 secstrcode[pos] = 'H';
459 secstrcode[pos] = 'E';
467 * Convert any non-standard peptide codes to their standard code table
468 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
470 * @param threeLetterCode
474 protected void replaceNonCanonicalResidue(String threeLetterCode,
477 String canonical = ResidueProperties
478 .getCanonicalAminoAcid(threeLetterCode);
479 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
481 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
486 * Not implemented - returns null
489 public String print(SequenceI[] seqs, boolean jvSuffix)
498 public void setCallbackFunction(String callbackType,
499 String callbackFunction)
504 public void notifyCallback(CBK cbType, Object[] data)
506 String strInfo = (data == null || data[1] == null ? null
507 : data[1].toString());
511 sendConsoleEcho(strInfo);
514 notifyScriptTermination((String) data[2],
515 ((Integer) data[3]).intValue());
518 String mystatus = (String) data[3];
519 if (mystatus.indexOf("Picked") >= 0
520 || mystatus.indexOf("Sequence") >= 0)
523 sendConsoleMessage(strInfo);
525 else if (mystatus.indexOf("Completed") >= 0)
527 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
528 strInfo.length() - 1));
532 sendConsoleMessage(data == null ? null : strInfo);
535 sendConsoleMessage(strInfo);
542 String lastConsoleEcho = "";
544 private void sendConsoleEcho(String string)
546 lastConsoleEcho += string;
547 lastConsoleEcho += "\n";
550 String lastConsoleMessage = "";
552 private void sendConsoleMessage(String string)
554 lastConsoleMessage += string;
555 lastConsoleMessage += "\n";
558 int lastScriptTermination = -1;
560 String lastScriptMessage = "";
562 private void notifyScriptTermination(String string, int intValue)
564 lastScriptMessage += string;
565 lastScriptMessage += "\n";
566 lastScriptTermination = intValue;
570 public boolean notifyEnabled(CBK callbackPick)
572 switch (callbackPick)
586 * Not implemented - returns null
589 public String eval(String strEval)
595 * Not implemented - returns null
598 public float[][] functionXY(String functionName, int x, int y)
604 * Not implemented - returns null
607 public float[][][] functionXYZ(String functionName, int nx, int ny,
614 * Not implemented - returns null
617 public String createImage(String fileName, String imageType,
618 Object text_or_bytes, int quality)
624 * Not implemented - returns null
627 public Map<String, Object> getRegistryInfo()
636 public void showUrl(String url)
641 * Not implemented - returns null
644 public int[] resizeInnerPanel(String data)
650 public Map<String, Object> getJSpecViewProperty(String arg0)
655 public boolean isPredictSecondaryStructure()
657 return predictSecondaryStructure;
660 public void setPredictSecondaryStructure(
661 boolean predictSecondaryStructure)
663 this.predictSecondaryStructure = predictSecondaryStructure;
666 public boolean isVisibleChainAnnotation()
668 return visibleChainAnnotation;
671 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
673 this.visibleChainAnnotation = visibleChainAnnotation;