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, 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 = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
139 null, "-x -o -n", this);
140 // ensure the 'new' (DSSP) not 'old' (Ramachandran) SS method is used
141 viewer.setBooleanProperty("defaultStructureDSSP", true);
142 } catch (ClassCastException x)
144 throw new Error(MessageManager.formatMessage(
145 "error.jmol_version_not_compatible_with_jalview_version",
147 { JmolViewer.getJmolVersion() }), x);
153 public void transformJmolModelToJalview(ModelSet ms) throws IOException
158 List<SequenceI> rna = new ArrayList<SequenceI>();
159 List<SequenceI> prot = new ArrayList<SequenceI>();
161 String pdbId = (String) ms.getInfo(0, "title");
165 setId(safeName(getDataName()));
166 setPDBIdAvailable(false);
171 setPDBIdAvailable(true);
173 List<Atom> significantAtoms = convertSignificantAtoms(ms);
174 for (Atom tmpatom : significantAtoms)
178 tmpchain = findChain(tmpatom.chain);
179 if (tmpatom.resNumIns.trim().equals(lastID))
181 // phosphorylated protein - seen both CA and P..
184 tmpchain.atoms.addElement(tmpatom);
185 } catch (Exception e)
187 tmpchain = new PDBChain(getId(), tmpatom.chain);
188 getChains().add(tmpchain);
189 tmpchain.atoms.addElement(tmpatom);
191 lastID = tmpatom.resNumIns.trim();
193 if (isParseImmediately())
195 // configure parsing settings from the static singleton
202 for (PDBChain chain : getChains())
204 SequenceI chainseq = postProcessChain(chain);
214 // look at local setting for adding secondary tructure
215 if (predictSecondaryStructure)
217 createAnnotation(chainseq, chain, ms.at);
220 } catch (OutOfMemoryError er)
223 "OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
224 throw new IOException(MessageManager
225 .getString("exception.outofmemory_loading_mmcif_file"));
229 private List<Atom> convertSignificantAtoms(ModelSet ms)
231 List<Atom> significantAtoms = new ArrayList<Atom>();
232 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
233 org.jmol.modelset.Atom prevAtom = null;
234 for (org.jmol.modelset.Atom atom : ms.at)
236 if (atom.getAtomName().equalsIgnoreCase("CA")
237 || atom.getAtomName().equalsIgnoreCase("P"))
239 if (!atomValidated(atom, prevAtom, chainTerMap))
243 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
244 curAtom.atomIndex = atom.getIndex();
245 curAtom.chain = atom.getChainIDStr();
246 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
247 : atom.group.getInsertionCode();
248 curAtom.name = atom.getAtomName();
249 curAtom.number = atom.getAtomNumber();
250 curAtom.resName = atom.getGroup3(true);
251 curAtom.resNumber = atom.getResno();
252 curAtom.occupancy = ms.occupancies != null
253 ? ms.occupancies[atom.getIndex()]
254 : Float.valueOf(atom.getOccupancy100());
255 String fmt = new Format("%4i").form(curAtom.resNumber);
256 curAtom.resNumIns = (fmt + curAtom.insCode);
257 curAtom.tfactor = atom.getBfactor100() / 100f;
259 // significantAtoms.add(curAtom);
260 // ignore atoms from subsequent models
261 if (!significantAtoms.contains(curAtom))
263 significantAtoms.add(curAtom);
268 return significantAtoms;
271 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
272 org.jmol.modelset.Atom prevAtom,
273 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
275 // System.out.println("Atom: " + curAtom.getAtomNumber()
276 // + " Last atom index " + curAtom.group.lastAtomIndex);
277 if (chainTerMap == null || prevAtom == null)
281 String curAtomChId = curAtom.getChainIDStr();
282 String prevAtomChId = prevAtom.getChainIDStr();
283 // new chain encoutered
284 if (!prevAtomChId.equals(curAtomChId))
286 // On chain switch add previous chain termination to xTerMap if not exists
287 if (!chainTerMap.containsKey(prevAtomChId))
289 chainTerMap.put(prevAtomChId, prevAtom);
291 // if current atom belongs to an already terminated chain and the resNum
292 // diff < 5 then mark as valid and update termination Atom
293 if (chainTerMap.containsKey(curAtomChId))
295 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
299 if ((curAtom.getResno()
300 - chainTerMap.get(curAtomChId).getResno()) < 5)
302 chainTerMap.put(curAtomChId, curAtom);
308 // atom with previously terminated chain encountered
309 else if (chainTerMap.containsKey(curAtomChId))
311 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
315 if ((curAtom.getResno()
316 - chainTerMap.get(curAtomChId).getResno()) < 5)
318 chainTerMap.put(curAtomChId, curAtom);
323 // HETATM with resNum jump > 2
324 return !(curAtom.isHetero()
325 && ((curAtom.getResno() - prevAtom.getResno()) > 2));
328 private void createAnnotation(SequenceI sequence, PDBChain chain,
329 org.jmol.modelset.Atom[] jmolAtoms)
331 char[] secstr = new char[sequence.getLength()];
332 char[] secstrcode = new char[sequence.getLength()];
334 // Ensure Residue size equals Seq size
335 if (chain.residues.size() != sequence.getLength())
340 for (Residue residue : chain.residues)
342 Atom repAtom = residue.getAtoms().get(0);
343 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
344 .getProteinStructureSubType();
345 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
349 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
350 secstrcode, chain.id, sequence.getStart());
354 * Helper method that adds an AlignmentAnnotation for secondary structure to
355 * the sequence, provided at least one secondary structure prediction has been
366 protected void addSecondaryStructureAnnotation(String modelTitle,
367 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
370 int length = sq.getLength();
371 boolean ssFound = false;
372 Annotation asecstr[] = new Annotation[length + firstResNum - 1];
373 for (int p = 0; p < length; p++)
375 if (secstr[p] >= 'A' && secstr[p] <= 'z')
379 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
380 secstrcode[p], Float.NaN);
382 } catch (Exception e)
384 // e.printStackTrace();
391 String mt = modelTitle == null ? getDataName() : modelTitle;
393 AlignmentAnnotation ann = new AlignmentAnnotation(
394 "Secondary Structure", "Secondary Structure for " + mt,
396 ann.belowAlignment = true;
398 ann.autoCalculated = false;
399 ann.setCalcId(getClass().getName());
400 ann.adjustForAlignment();
401 ann.validateRangeAndDisplay();
402 annotations.add(ann);
403 sq.addAlignmentAnnotation(ann);
407 private void waitForScript(Viewer jmd)
409 while (jmd.isScriptExecuting())
415 } catch (InterruptedException x)
422 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
423 * secondary structure arrays at the given sequence position
425 * @param proteinStructureSubType
430 protected void setSecondaryStructure(STR proteinStructureSubType, int pos,
431 char[] secstr, char[] secstrcode)
433 switch (proteinStructureSubType)
452 switch (proteinStructureSubType)
458 secstrcode[pos] = 'H';
461 secstrcode[pos] = 'E';
469 * Convert any non-standard peptide codes to their standard code table
470 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
472 * @param threeLetterCode
476 protected void replaceNonCanonicalResidue(String threeLetterCode,
479 String canonical = ResidueProperties
480 .getCanonicalAminoAcid(threeLetterCode);
481 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
483 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
488 * Not implemented - returns null
491 public String print(SequenceI[] seqs, boolean jvSuffix)
500 public void setCallbackFunction(String callbackType,
501 String callbackFunction)
506 public void notifyCallback(CBK cbType, Object[] data)
508 String strInfo = (data == null || data[1] == null ? null
509 : data[1].toString());
513 sendConsoleEcho(strInfo);
516 notifyScriptTermination((String) data[2],
517 ((Integer) data[3]).intValue());
520 String mystatus = (String) data[3];
521 if (mystatus.indexOf("Picked") >= 0
522 || mystatus.indexOf("Sequence") >= 0)
525 sendConsoleMessage(strInfo);
527 else if (mystatus.indexOf("Completed") >= 0)
529 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
530 strInfo.length() - 1));
534 sendConsoleMessage(data == null ? null : strInfo);
537 sendConsoleMessage(strInfo);
544 String lastConsoleEcho = "";
546 private void sendConsoleEcho(String string)
548 lastConsoleEcho += string;
549 lastConsoleEcho += "\n";
552 String lastConsoleMessage = "";
554 private void sendConsoleMessage(String string)
556 lastConsoleMessage += string;
557 lastConsoleMessage += "\n";
560 int lastScriptTermination = -1;
562 String lastScriptMessage = "";
564 private void notifyScriptTermination(String string, int intValue)
566 lastScriptMessage += string;
567 lastScriptMessage += "\n";
568 lastScriptTermination = intValue;
572 public boolean notifyEnabled(CBK callbackPick)
574 switch (callbackPick)
588 * Not implemented - returns null
591 public String eval(String strEval)
597 * Not implemented - returns null
600 public float[][] functionXY(String functionName, int x, int y)
606 * Not implemented - returns null
609 public float[][][] functionXYZ(String functionName, int nx, int ny,
616 * Not implemented - returns null
619 public String createImage(String fileName, String imageType,
620 Object text_or_bytes, int quality)
626 * Not implemented - returns null
629 public Map<String, Object> getRegistryInfo()
638 public void showUrl(String url)
643 * Not implemented - returns null
646 public int[] resizeInnerPanel(String data)
652 public Map<String, Object> getJSpecViewProperty(String arg0)
657 public boolean isPredictSecondaryStructure()
659 return predictSecondaryStructure;
662 public void setPredictSecondaryStructure(
663 boolean predictSecondaryStructure)
665 this.predictSecondaryStructure = predictSecondaryStructure;
668 public boolean isVisibleChainAnnotation()
670 return visibleChainAnnotation;
673 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
675 this.visibleChainAnnotation = visibleChainAnnotation;