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();
196 for (PDBChain chain : getChains())
198 SequenceI chainseq = postProcessChain(chain);
208 if (StructureImportSettings.isProcessSecondaryStructure())
210 createAnnotation(chainseq, chain, ms.at);
213 } catch (OutOfMemoryError er)
216 "OUT OF MEMORY LOADING TRANSFORMING JMOL MODEL TO JALVIEW MODEL");
217 throw new IOException(MessageManager
218 .getString("exception.outofmemory_loading_mmcif_file"));
222 private List<Atom> convertSignificantAtoms(ModelSet ms)
224 List<Atom> significantAtoms = new ArrayList<Atom>();
225 HashMap<String, org.jmol.modelset.Atom> chainTerMap = new HashMap<String, org.jmol.modelset.Atom>();
226 org.jmol.modelset.Atom prevAtom = null;
227 for (org.jmol.modelset.Atom atom : ms.at)
229 if (atom.getAtomName().equalsIgnoreCase("CA")
230 || atom.getAtomName().equalsIgnoreCase("P"))
232 if (!atomValidated(atom, prevAtom, chainTerMap))
236 Atom curAtom = new Atom(atom.x, atom.y, atom.z);
237 curAtom.atomIndex = atom.getIndex();
238 curAtom.chain = atom.getChainIDStr();
239 curAtom.insCode = atom.group.getInsertionCode() == '\000' ? ' '
240 : atom.group.getInsertionCode();
241 curAtom.name = atom.getAtomName();
242 curAtom.number = atom.getAtomNumber();
243 curAtom.resName = atom.getGroup3(true);
244 curAtom.resNumber = atom.getResno();
245 curAtom.occupancy = ms.occupancies != null
246 ? ms.occupancies[atom.getIndex()]
247 : Float.valueOf(atom.getOccupancy100());
248 String fmt = new Format("%4i").form(curAtom.resNumber);
249 curAtom.resNumIns = (fmt + curAtom.insCode);
250 curAtom.tfactor = atom.getBfactor100() / 100f;
252 // significantAtoms.add(curAtom);
253 // ignore atoms from subsequent models
254 if (!significantAtoms.contains(curAtom))
256 significantAtoms.add(curAtom);
261 return significantAtoms;
264 private boolean atomValidated(org.jmol.modelset.Atom curAtom,
265 org.jmol.modelset.Atom prevAtom,
266 HashMap<String, org.jmol.modelset.Atom> chainTerMap)
268 // System.out.println("Atom: " + curAtom.getAtomNumber()
269 // + " Last atom index " + curAtom.group.lastAtomIndex);
270 if (chainTerMap == null || prevAtom == null)
274 String curAtomChId = curAtom.getChainIDStr();
275 String prevAtomChId = prevAtom.getChainIDStr();
276 // new chain encoutered
277 if (!prevAtomChId.equals(curAtomChId))
279 // On chain switch add previous chain termination to xTerMap if not exists
280 if (!chainTerMap.containsKey(prevAtomChId))
282 chainTerMap.put(prevAtomChId, prevAtom);
284 // if current atom belongs to an already terminated chain and the resNum
285 // diff < 5 then mark as valid and update termination Atom
286 if (chainTerMap.containsKey(curAtomChId))
288 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
292 if ((curAtom.getResno()
293 - chainTerMap.get(curAtomChId).getResno()) < 5)
295 chainTerMap.put(curAtomChId, curAtom);
301 // atom with previously terminated chain encountered
302 else if (chainTerMap.containsKey(curAtomChId))
304 if (curAtom.getResno() < chainTerMap.get(curAtomChId).getResno())
308 if ((curAtom.getResno()
309 - chainTerMap.get(curAtomChId).getResno()) < 5)
311 chainTerMap.put(curAtomChId, curAtom);
316 // HETATM with resNum jump > 2
317 return !(curAtom.isHetero()
318 && ((curAtom.getResno() - prevAtom.getResno()) > 2));
321 private void createAnnotation(SequenceI sequence, PDBChain chain,
322 org.jmol.modelset.Atom[] jmolAtoms)
324 char[] secstr = new char[sequence.getLength()];
325 char[] secstrcode = new char[sequence.getLength()];
327 // Ensure Residue size equals Seq size
328 if (chain.residues.size() != sequence.getLength())
333 for (Residue residue : chain.residues)
335 Atom repAtom = residue.getAtoms().get(0);
336 STR proteinStructureSubType = jmolAtoms[repAtom.atomIndex].group
337 .getProteinStructureSubType();
338 setSecondaryStructure(proteinStructureSubType, annotIndex, secstr,
342 addSecondaryStructureAnnotation(chain.pdbid, sequence, secstr,
343 secstrcode, chain.id, sequence.getStart());
347 * Helper method that adds an AlignmentAnnotation for secondary structure to
348 * the sequence, provided at least one secondary structure prediction has been
359 protected void addSecondaryStructureAnnotation(String modelTitle,
360 SequenceI sq, char[] secstr, char[] secstrcode, String chainId,
363 int length = sq.getLength();
364 boolean ssFound = false;
365 Annotation asecstr[] = new Annotation[length + firstResNum - 1];
366 for (int p = 0; p < length; p++)
368 if (secstr[p] >= 'A' && secstr[p] <= 'z')
372 asecstr[p] = new Annotation(String.valueOf(secstr[p]), null,
373 secstrcode[p], Float.NaN);
375 } catch (Exception e)
377 // e.printStackTrace();
384 String mt = modelTitle == null ? getDataName() : modelTitle;
386 AlignmentAnnotation ann = new AlignmentAnnotation(
387 "Secondary Structure", "Secondary Structure for " + mt,
389 ann.belowAlignment = true;
391 ann.autoCalculated = false;
392 ann.setCalcId(getClass().getName());
393 ann.adjustForAlignment();
394 ann.validateRangeAndDisplay();
395 annotations.add(ann);
396 sq.addAlignmentAnnotation(ann);
400 private void waitForScript(Viewer jmd)
402 while (jmd.isScriptExecuting())
408 } catch (InterruptedException x)
415 * Convert Jmol's secondary structure code to Jalview's, and stored it in the
416 * secondary structure arrays at the given sequence position
418 * @param proteinStructureSubType
423 protected void setSecondaryStructure(STR proteinStructureSubType, int pos,
424 char[] secstr, char[] secstrcode)
426 switch (proteinStructureSubType)
445 switch (proteinStructureSubType)
451 secstrcode[pos] = 'H';
454 secstrcode[pos] = 'E';
462 * Convert any non-standard peptide codes to their standard code table
463 * equivalent. (Initial version only does Selenomethionine MSE->MET.)
465 * @param threeLetterCode
469 protected void replaceNonCanonicalResidue(String threeLetterCode,
472 String canonical = ResidueProperties
473 .getCanonicalAminoAcid(threeLetterCode);
474 if (canonical != null && !canonical.equalsIgnoreCase(threeLetterCode))
476 seq[pos] = ResidueProperties.getSingleCharacterCode(canonical);
481 * Not implemented - returns null
484 public String print(SequenceI[] seqs, boolean jvSuffix)
493 public void setCallbackFunction(String callbackType,
494 String callbackFunction)
499 public void notifyCallback(CBK cbType, Object[] data)
501 String strInfo = (data == null || data[1] == null ? null
502 : data[1].toString());
506 sendConsoleEcho(strInfo);
509 notifyScriptTermination((String) data[2],
510 ((Integer) data[3]).intValue());
513 String mystatus = (String) data[3];
514 if (mystatus.indexOf("Picked") >= 0
515 || mystatus.indexOf("Sequence") >= 0)
518 sendConsoleMessage(strInfo);
520 else if (mystatus.indexOf("Completed") >= 0)
522 sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
523 strInfo.length() - 1));
527 sendConsoleMessage(data == null ? null : strInfo);
530 sendConsoleMessage(strInfo);
537 String lastConsoleEcho = "";
539 private void sendConsoleEcho(String string)
541 lastConsoleEcho += string;
542 lastConsoleEcho += "\n";
545 String lastConsoleMessage = "";
547 private void sendConsoleMessage(String string)
549 lastConsoleMessage += string;
550 lastConsoleMessage += "\n";
553 int lastScriptTermination = -1;
555 String lastScriptMessage = "";
557 private void notifyScriptTermination(String string, int intValue)
559 lastScriptMessage += string;
560 lastScriptMessage += "\n";
561 lastScriptTermination = intValue;
565 public boolean notifyEnabled(CBK callbackPick)
567 switch (callbackPick)
581 * Not implemented - returns null
584 public String eval(String strEval)
590 * Not implemented - returns null
593 public float[][] functionXY(String functionName, int x, int y)
599 * Not implemented - returns null
602 public float[][][] functionXYZ(String functionName, int nx, int ny,
609 * Not implemented - returns null
612 public String createImage(String fileName, String imageType,
613 Object text_or_bytes, int quality)
619 * Not implemented - returns null
622 public Map<String, Object> getRegistryInfo()
631 public void showUrl(String url)
636 * Not implemented - returns null
639 public int[] resizeInnerPanel(String data)
645 public Map<String, Object> getJSpecViewProperty(String arg0)
650 public boolean isPredictSecondaryStructure()
652 return predictSecondaryStructure;
655 public void setPredictSecondaryStructure(
656 boolean predictSecondaryStructure)
658 this.predictSecondaryStructure = predictSecondaryStructure;
661 public boolean isVisibleChainAnnotation()
663 return visibleChainAnnotation;
666 public void setVisibleChainAnnotation(boolean visibleChainAnnotation)
668 this.visibleChainAnnotation = visibleChainAnnotation;