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 mc_view.PDBChain;
50 import mc_view.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, Object inFile,
63 DataSourceType sourceType) throws IOException
65 // BH 2018 File or String for filename
66 super(immediate, inFile, sourceType);
69 public JmolParser(Object inFile, DataSourceType sourceType)
72 super(inFile, sourceType);
75 public JmolParser(FileParse fp) throws IOException
85 * Calls the Jmol library to parse the PDB/mmCIF file, and then inspects the
86 * resulting object model to generate Jalview-style sequences, with secondary
87 * structure annotation added where available (i.e. where it has been computed
88 * by Jmol using DSSP).
90 * @see jalview.io.AlignFile#parse()
93 public void parse() throws IOException
95 setChains(new Vector<PDBChain>());
96 Viewer jmolModel = getJmolData();
97 jmolModel.openReader(getDataName(), getDataName(), getReader());
98 waitForScript(jmolModel);
101 * Convert one or more Jmol Model objects to Jalview sequences
103 if (jmolModel.ms.mc > 0)
105 // ideally we do this
108 // setStructureFileType(jmolModel.evalString("show _fileType"));
109 // } catch (Exception q)
113 // instead, we distinguish .cif from non-.cif by filename
114 setStructureFileType(getDataName().toLowerCase().endsWith(".cif")
115 ? PDBEntry.Type.MMCIF.toString()
118 transformJmolModelToJalview(jmolModel.ms);
123 * create a headless jmol instance for dataprocessing
127 private Viewer getJmolData()
134 * params -o (output to sysout) -n (nodisplay) -x (exit when finished)
135 * see http://wiki.jmol.org/index.php/Jmol_Application
138 viewer = JalviewJmolBinding.getJmolData(this);
139 // ensure the 'new' (DSSP) not 'old' (Ramachandran) SS method is used
140 viewer.setBooleanProperty("defaultStructureDSSP", true);
141 } catch (ClassCastException x)
143 throw new Error(MessageManager.formatMessage(
144 "error.jmol_version_not_compatible_with_jalview_version",
146 { JmolViewer.getJmolVersion() }), x);
152 public void transformJmolModelToJalview(ModelSet ms) throws IOException
157 List<SequenceI> rna = new ArrayList<SequenceI>();
158 List<SequenceI> prot = new ArrayList<SequenceI>();
160 String pdbId = (String) ms.getInfo(0, "title");
164 setId(safeName(getDataName()));
165 setPDBIdAvailable(false);
170 setPDBIdAvailable(true);
172 List<Atom> significantAtoms = convertSignificantAtoms(ms);
173 for (Atom tmpatom : significantAtoms)
175 if (tmpatom.resNumIns.trim().equals(lastID))
177 // phosphorylated protein - seen both CA and P..
180 tmpchain = findChain(tmpatom.chain);
181 if (tmpchain != null)
183 tmpchain.atoms.addElement(tmpatom);
186 tmpchain = new PDBChain(getId(), tmpatom.chain);
187 getChains().add(tmpchain);
188 tmpchain.atoms.addElement(tmpatom);
190 lastID = tmpatom.resNumIns.trim();
192 if (isParseImmediately())
194 // configure parsing settings from the static singleton
201 for (PDBChain chain : getChains())
203 SequenceI chainseq = postProcessChain(chain);
213 // look at local setting for adding secondary tructure
214 if (predictSecondaryStructure)
216 createAnnotation(chainseq, chain, ms.at);
219 } catch (OutOfMemoryError er)
222 "OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
223 throw new IOException(MessageManager
224 .getString("exception.outofmemory_loading_mmcif_file"));
228 private List<Atom> convertSignificantAtoms(ModelSet ms)
230 List<Atom> significantAtoms = new ArrayList<Atom>();
231 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
232 org.jmol.modelset.Atom prevAtom = null;
233 for (org.jmol.modelset.Atom atom : ms.at)
235 if (atom.getAtomName().equalsIgnoreCase("CA")
236 || atom.getAtomName().equalsIgnoreCase("P"))
238 if (!atomValidated(atom, prevAtom, chainTerMap))
242 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
243 curAtom.atomIndex = atom.getIndex();
244 curAtom.chain = atom.getChainIDStr();
245 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
246 : atom.group.getInsertionCode();
247 curAtom.name = atom.getAtomName();
248 curAtom.number = atom.getAtomNumber();
249 curAtom.resName = atom.getGroup3(true);
250 curAtom.resNumber = atom.getResno();
251 curAtom.occupancy = ms.occupancies != null
252 ? ms.occupancies[atom.getIndex()]
253 : Float.valueOf(atom.getOccupancy100());
254 String fmt = new Format("%4i").form(curAtom.resNumber);
255 curAtom.resNumIns = (fmt + curAtom.insCode);
256 curAtom.tfactor = atom.getBfactor100() / 100f;
258 // significantAtoms.add(curAtom);
259 // ignore atoms from subsequent models
260 if (!significantAtoms.contains(curAtom))
262 significantAtoms.add(curAtom);
267 return significantAtoms;
270 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
271 org.jmol.modelset.Atom prevAtom,
272 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
274 // System.out.println("Atom: " + curAtom.getAtomNumber()
275 // + " Last atom index " + curAtom.group.lastAtomIndex);
276 if (chainTerMap == null || prevAtom == null)
280 String curAtomChId = curAtom.getChainIDStr();
281 String prevAtomChId = prevAtom.getChainIDStr();
282 // new chain encoutered
283 if (!prevAtomChId.equals(curAtomChId))
285 // On chain switch add previous chain termination to xTerMap if not exists
286 if (!chainTerMap.containsKey(prevAtomChId))
288 chainTerMap.put(prevAtomChId, prevAtom);
290 // if current atom belongs to an already terminated chain and the resNum
291 // diff < 5 then mark as valid and update termination Atom
292 if (chainTerMap.containsKey(curAtomChId))
294 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
298 if ((curAtom.getResno()
299 - chainTerMap.get(curAtomChId).getResno()) < 5)
301 chainTerMap.put(curAtomChId, curAtom);
307 // atom with previously terminated chain encountered
308 else if (chainTerMap.containsKey(curAtomChId))
310 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
314 if ((curAtom.getResno()
315 - chainTerMap.get(curAtomChId).getResno()) < 5)
317 chainTerMap.put(curAtomChId, curAtom);
322 // HETATM with resNum jump > 2
323 return !(curAtom.isHetero()
324 && ((curAtom.getResno() - prevAtom.getResno()) > 2));
327 private void createAnnotation(SequenceI sequence, PDBChain chain,
328 org.jmol.modelset.Atom[] jmolAtoms)
330 char[] secstr = new char[sequence.getLength()];
331 char[] secstrcode = new char[sequence.getLength()];
333 // Ensure Residue size equals Seq size
334 if (chain.residues.size() != sequence.getLength())
339 for (Residue residue : chain.residues)
341 Atom repAtom = residue.getAtoms().get(0);
342 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
343 .getProteinStructureSubType();
344 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
348 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
349 secstrcode, chain.id, sequence.getStart());
353 * Helper method that adds an AlignmentAnnotation for secondary structure to
354 * the sequence, provided at least one secondary structure prediction has been
365 protected void addSecondaryStructureAnnotation(String modelTitle,
366 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
369 int length = sq.getLength();
370 boolean ssFound = false;
371 Annotation asecstr[] = new Annotation[length + firstResNum - 1];
372 for (int p = 0; p < length; p++)
374 if (secstr[p] >= 'A' && secstr[p] <= 'z')
378 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
379 secstrcode[p], Float.NaN);
381 } catch (Exception e)
383 // e.printStackTrace();
390 String mt = modelTitle == null ? getDataName() : modelTitle;
392 AlignmentAnnotation ann = new AlignmentAnnotation(
393 "Secondary Structure", "Secondary Structure for " + mt,
395 ann.belowAlignment = true;
397 ann.autoCalculated = false;
398 ann.setCalcId(getClass().getName());
399 ann.adjustForAlignment();
400 ann.validateRangeAndDisplay();
401 annotations.add(ann);
402 sq.addAlignmentAnnotation(ann);
406 private void waitForScript(Viewer jmd)
408 while (jmd.isScriptExecuting())
414 } catch (InterruptedException x)
421 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
422 * secondary structure arrays at the given sequence position
424 * @param proteinStructureSubType
429 protected void setSecondaryStructure(STR proteinStructureSubType, int pos,
430 char[] secstr, char[] secstrcode)
432 switch (proteinStructureSubType)
451 switch (proteinStructureSubType)
457 secstrcode[pos] = 'H';
460 secstrcode[pos] = 'E';
468 * Convert any non-standard peptide codes to their standard code table
469 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
471 * @param threeLetterCode
475 protected void replaceNonCanonicalResidue(String threeLetterCode,
478 String canonical = ResidueProperties
479 .getCanonicalAminoAcid(threeLetterCode);
480 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
482 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
487 * Not implemented - returns null
490 public String print(SequenceI[] seqs, boolean jvSuffix)
499 public void setCallbackFunction(String callbackType,
500 String callbackFunction)
505 public void notifyCallback(CBK cbType, Object[] data)
507 String strInfo = (data == null || data[1] == null ? null
508 : data[1].toString());
512 sendConsoleEcho(strInfo);
515 notifyScriptTermination((String) data[2],
516 ((Integer) data[3]).intValue());
519 String mystatus = (String) data[3];
520 if (mystatus.indexOf("Picked") >= 0
521 || mystatus.indexOf("Sequence") >= 0)
524 sendConsoleMessage(strInfo);
526 else if (mystatus.indexOf("Completed") >= 0)
528 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
529 strInfo.length() - 1));
533 sendConsoleMessage(data == null ? null : strInfo);
536 sendConsoleMessage(strInfo);
543 String lastConsoleEcho = "";
545 private void sendConsoleEcho(String string)
547 lastConsoleEcho += string;
548 lastConsoleEcho += "\n";
551 String lastConsoleMessage = "";
553 private void sendConsoleMessage(String string)
555 lastConsoleMessage += string;
556 lastConsoleMessage += "\n";
559 int lastScriptTermination = -1;
561 String lastScriptMessage = "";
563 private void notifyScriptTermination(String string, int intValue)
565 lastScriptMessage += string;
566 lastScriptMessage += "\n";
567 lastScriptTermination = intValue;
571 public boolean notifyEnabled(CBK callbackPick)
573 switch (callbackPick)
587 * Not implemented - returns null
590 public String eval(String strEval)
596 * Not implemented - returns null
599 public float[][] functionXY(String functionName, int x, int y)
605 * Not implemented - returns null
608 public float[][][] functionXYZ(String functionName, int nx, int ny,
615 * Not implemented - returns null
618 public String createImage(String fileName, String imageType,
619 Object text_or_bytes, int quality)
625 * Not implemented - returns null
628 public Map<String, Object> getRegistryInfo()
637 public void showUrl(String url)
642 * Not implemented - returns null
645 public int[] resizeInnerPanel(String data)
651 public Map<String, Object> getJSpecViewProperty(String arg0)
656 public boolean isPredictSecondaryStructure()
658 return predictSecondaryStructure;
661 public void setPredictSecondaryStructure(
662 boolean predictSecondaryStructure)
664 this.predictSecondaryStructure = predictSecondaryStructure;
667 public boolean isVisibleChainAnnotation()
669 return visibleChainAnnotation;
672 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
674 this.visibleChainAnnotation = visibleChainAnnotation;