From 023163e0fe8837c1ddb75eb30abc058f7747b5c2 Mon Sep 17 00:00:00 2001 From: Jim Procter Date: Mon, 30 Aug 2021 10:09:33 +0100 Subject: [PATCH] JAL-3829 generalised Alphafold retrieval mechanism to be reused for PDBEntrys with retrieval URIs discovered via 3d beacons --- src/jalview/datamodel/PDBEntry.java | 10 +- src/jalview/gui/AppJmol.java | 21 +++- src/jalview/ws/dbsources/EBIAlfaFold.java | 172 +++++++++++++++++------------ 3 files changed, 128 insertions(+), 75 deletions(-) diff --git a/src/jalview/datamodel/PDBEntry.java b/src/jalview/datamodel/PDBEntry.java index 1edc94b..672a59e 100755 --- a/src/jalview/datamodel/PDBEntry.java +++ b/src/jalview/datamodel/PDBEntry.java @@ -462,19 +462,25 @@ public class PDBEntry } + private static final String RETRIEVE_FROM="RETRIEVE_FROM"; /** * Permanent URI for retrieving the original structure data * @param urlStr */ public void setRetrievalUrl(String urlStr) { - setProperty("RETRIEVE_FROM", urlStr); + setProperty(RETRIEVE_FROM, urlStr); } /** * get the Permanent URI for retrieving the original structure data */ public String getRetrievalUrl() { - return (String) getProperty("RETRIEVE_FROM"); + return (String) getProperty(RETRIEVE_FROM); + } + + public boolean hasRetrievalUrl() + { + return (properties!=null && properties.containsKey(RETRIEVE_FROM)); } } diff --git a/src/jalview/gui/AppJmol.java b/src/jalview/gui/AppJmol.java index d085117..9280caa 100644 --- a/src/jalview/gui/AppJmol.java +++ b/src/jalview/gui/AppJmol.java @@ -43,6 +43,7 @@ import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.datamodel.StructureViewerModel; import jalview.datamodel.StructureViewerModel.StructureData; +import jalview.fts.service.alphafold.AlphafoldRestClient; import jalview.gui.ImageExporter.ImageWriterI; import jalview.gui.StructureViewer.ViewerType; import jalview.structure.StructureCommand; @@ -53,6 +54,7 @@ import jalview.util.MessageManager; import jalview.util.Platform; import jalview.ws.dbsources.EBIAlfaFold; import jalview.ws.dbsources.Pdb; +import jalview.ws.utils.UrlDownloadClient; public class AppJmol extends StructureViewerBase { @@ -448,7 +450,8 @@ public class AppJmol extends StructureViewerBase // todo: extract block as method and pull up (also ChimeraViewFrame) // retrieve the pdb and store it locally AlignmentI pdbseq = null; - pdbid = jmb.getPdbEntry(pi).getId(); + PDBEntry strucEntry = jmb.getPdbEntry(pi); + pdbid = strucEntry.getId(); long hdl = pdbid.hashCode() - System.currentTimeMillis(); setProgressMessage(MessageManager .formatMessage("status.fetching_pdb", new String[] @@ -459,7 +462,21 @@ public class AppJmol extends StructureViewerBase { pdbseq = afclient.getSequenceRecords(pdbid); } else { - pdbseq = pdbclient.getSequenceRecords(pdbid); + if (strucEntry.hasRetrievalUrl()) + { + File tmpFile = File.createTempFile(pdbid, "cif"); + String fromUrl = strucEntry.getRetrievalUrl(); + UrlDownloadClient.download(fromUrl, tmpFile); + + // may not need this check ? + file = tmpFile.getAbsolutePath(); + if (file != null) + { + pdbseq = EBIAlfaFold.importDownloadedStructureFromUrl(fromUrl,tmpFile,pdbid,null,null,null); + } + } else { + pdbseq = pdbclient.getSequenceRecords(pdbid); + } } } catch (OutOfMemoryError oomerror) { diff --git a/src/jalview/ws/dbsources/EBIAlfaFold.java b/src/jalview/ws/dbsources/EBIAlfaFold.java index 5edcafa..b4cb614 100644 --- a/src/jalview/ws/dbsources/EBIAlfaFold.java +++ b/src/jalview/ws/dbsources/EBIAlfaFold.java @@ -106,10 +106,12 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy { return "1"; } + public static String getAlphaFoldCifDownloadUrl(String id) { - return "https://alphafold.ebi.ac.uk/files/"+id+"-model_v1.cif"; + return "https://alphafold.ebi.ac.uk/files/" + id + "-model_v1.cif"; } + /* * (non-Javadoc) * @@ -133,100 +135,128 @@ public class EBIAlfaFold extends EbiFileRetrievedProxy if (!isValidReference(id)) { - System.err.println("(AFClient) Ignoring invalid pdb query: '" + id + "'"); + System.err.println( + "(AFClient) Ignoring invalid pdb query: '" + id + "'"); stopQuery(); return null; } String alphaFoldCif = getAlphaFoldCifDownloadUrl(id); - - try { - File tmpFile = File.createTempFile(id,"cif"); + + try + { + File tmpFile = File.createTempFile(id, "cif"); UrlDownloadClient.download(alphaFoldCif, tmpFile); + + // may not need this check ? file = tmpFile.getAbsolutePath(); if (file == null) { - return null; + return null; + } + + pdbAlignment = importDownloadedStructureFromUrl(alphaFoldCif, tmpFile, id, chain, getDbSource(),getDbVersion()); + + + if (pdbAlignment == null || pdbAlignment.getHeight() < 1) + { + throw new Exception(MessageManager.formatMessage( + "exception.no_pdb_records_for_chain", new String[] + { id, ((chain == null) ? "' '" : chain) })); + } + + } catch (Exception ex) // Problem parsing PDB file + { + stopQuery(); + throw (ex); } - // todo get rid of Type and use FileFormatI instead? - FileFormatI fileFormat = FileFormat.MMCif; - pdbAlignment = new FormatAdapter().readFile(tmpFile, DataSourceType.FILE, - fileFormat); - if (pdbAlignment != null) + return pdbAlignment; + } + + /** + * general purpose structure importer - designed to yield alignment useful for transfer of annotation to associated sequences + * @param alphaFoldCif + * @param tmpFile + * @param id + * @param chain + * @param dbSource + * @param dbVersion + * @return + * @throws Exception + */ + public static AlignmentI importDownloadedStructureFromUrl(String alphaFoldCif, + File tmpFile, String id, String chain, String dbSource, String dbVersion) throws Exception + { + String file = tmpFile.getAbsolutePath(); + // todo get rid of Type and use FileFormatI instead? + FileFormatI fileFormat = FileFormat.MMCif; + AlignmentI pdbAlignment = new FormatAdapter().readFile(tmpFile, + DataSourceType.FILE, fileFormat); + if (pdbAlignment != null) + { + List toremove = new ArrayList(); + for (SequenceI pdbcs : pdbAlignment.getSequences()) { - List toremove = new ArrayList(); - for (SequenceI pdbcs : pdbAlignment.getSequences()) + String chid = null; + // Mapping map=null; + for (PDBEntry pid : pdbcs.getAllPDBEntries()) { - String chid = null; - // Mapping map=null; - for (PDBEntry pid : pdbcs.getAllPDBEntries()) + if (pid.getFile() == file) { - if (pid.getFile() == file) - { - chid = pid.getChainCode(); + chid = pid.getChainCode(); - } } - if (chain == null || (chid != null && (chid.equals(chain) - || chid.trim().equals(chain.trim()) - || (chain.trim().length() == 0 && chid.equals("_"))))) + } + if (chain == null || (chid != null && (chid.equals(chain) + || chid.trim().equals(chain.trim()) + || (chain.trim().length() == 0 && chid.equals("_"))))) + { + // FIXME seems to result in 'PDB|1QIP|1qip|A' - 1QIP is redundant. + // TODO: suggest simplify naming to 1qip|A as default name defined + pdbcs.setName(id + SEPARATOR + pdbcs.getName()); + // Might need to add more metadata to the PDBEntry object + // like below + /* + * PDBEntry entry = new PDBEntry(); // Construct the PDBEntry + * entry.setId(id); if (entry.getProperty() == null) + * entry.setProperty(new Hashtable()); + * entry.getProperty().put("chains", pdbchain.id + "=" + + * sq.getStart() + "-" + sq.getEnd()); + * sq.getDatasetSequence().addPDBId(entry); + */ + // Add PDB DB Refs + // We make a DBRefEtntry because we have obtained the PDB file from + // a + // verifiable source + // JBPNote - PDB DBRefEntry should also carry the chain and mapping + // information + if (dbSource != null) { - // FIXME seems to result in 'PDB|1QIP|1qip|A' - 1QIP is redundant. - // TODO: suggest simplify naming to 1qip|A as default name defined - pdbcs.setName(id - + SEPARATOR + pdbcs.getName()); - // Might need to add more metadata to the PDBEntry object - // like below - /* - * PDBEntry entry = new PDBEntry(); // Construct the PDBEntry - * entry.setId(id); if (entry.getProperty() == null) - * entry.setProperty(new Hashtable()); - * entry.getProperty().put("chains", pdbchain.id + "=" + - * sq.getStart() + "-" + sq.getEnd()); - * sq.getDatasetSequence().addPDBId(entry); - */ - // Add PDB DB Refs - // We make a DBRefEtntry because we have obtained the PDB file from - // a - // verifiable source - // JBPNote - PDB DBRefEntry should also carry the chain and mapping - // information - DBRefEntry dbentry = new DBRefEntry(getDbSource(), - getDbVersion(), (chid == null ? id : id + chid)); + DBRefEntry dbentry = new DBRefEntry(dbSource, + + dbVersion, (chid == null ? id : id + chid)); // dbentry.setMap() pdbcs.addDBRef(dbentry); } - else - { - // mark this sequence to be removed from the alignment - // - since it's not from the right chain - toremove.add(pdbcs); - } } - // now remove marked sequences - for (SequenceI pdbcs : toremove) + else { - pdbAlignment.deleteSequence(pdbcs); - if (pdbcs.getAnnotation() != null) - { - for (AlignmentAnnotation aa : pdbcs.getAnnotation()) - { - pdbAlignment.deleteAnnotation(aa); - } - } + // mark this sequence to be removed from the alignment + // - since it's not from the right chain + toremove.add(pdbcs); } } - - if (pdbAlignment == null || pdbAlignment.getHeight() < 1) + // now remove marked sequences + for (SequenceI pdbcs : toremove) { - throw new Exception(MessageManager.formatMessage( - "exception.no_pdb_records_for_chain", new String[] - { id, ((chain == null) ? "' '" : chain) })); + pdbAlignment.deleteSequence(pdbcs); + if (pdbcs.getAnnotation() != null) + { + for (AlignmentAnnotation aa : pdbcs.getAnnotation()) + { + pdbAlignment.deleteAnnotation(aa); + } + } } - - } catch (Exception ex) // Problem parsing PDB file - { - stopQuery(); - throw (ex); } return pdbAlignment; } -- 1.7.10.2