From: tcofoegbu Date: Thu, 22 Oct 2015 17:08:14 +0000 (+0100) Subject: JAL-1479 added basic support for SIFTs mapping - more work to follow X-Git-Tag: Release_2_10_0~341^2~10 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=08cc3b53619f49a365d7346c3cc8d7a5ddd1b455;p=jalview.git JAL-1479 added basic support for SIFTs mapping - more work to follow --- diff --git a/src/jalview/analysis/AlignSeq.java b/src/jalview/analysis/AlignSeq.java index 527b1ff..3e4a82b 100755 --- a/src/jalview/analysis/AlignSeq.java +++ b/src/jalview/analysis/AlignSeq.java @@ -580,17 +580,15 @@ public class AlignSeq int nochunks = ((aseq1.length - count) / len) + 1; pid = 0; - output.append("Score = ").append(score[maxi][maxj]).append(NEWLINE); - output.append("Length of alignment = ") - .append(String.valueOf(aseq1.length - count)).append(NEWLINE); - output.append("Sequence "); + output.append("Sequence \u27f7 Structure mapping details: ") + .append(NEWLINE); output.append(new Format("%" + maxid + "s").form(s1.getName())); output.append(" : ").append(String.valueOf(s1.getStart())) .append(" - ").append(String.valueOf(s1.getEnd())); output.append(" (Sequence length = ") .append(String.valueOf(s1str.length())).append(")") .append(NEWLINE); - output.append("Sequence "); + // output.append("Sequence "); output.append(new Format("%" + maxid + "s").form(s2.getName())); output.append(" : ").append(String.valueOf(s2.getStart())) .append(" - ").append(String.valueOf(s2.getEnd())); @@ -598,6 +596,7 @@ public class AlignSeq .append(String.valueOf(s2str.length())).append(")") .append(NEWLINE).append(NEWLINE); + // output mappings for (int j = 0; j < nochunks; j++) { // Print the first aligned sequence @@ -661,10 +660,16 @@ public class AlignSeq output.append(NEWLINE).append(NEWLINE); } + output.append("Length of alignment = ") + .append(String.valueOf(aseq1.length - count)).append(NEWLINE); + output.append("Score = ").append(score[maxi][maxj]).append(NEWLINE); + pid = pid / (aseq1.length - count) * 100; output = output.append(new Format("Percentage ID = %2.2f\n\n") .form(pid)); + output.append(NEWLINE).append( + "Mapping method: Needleman & Wunsch Alignment"); try { os.print(output.toString()); diff --git a/src/jalview/api/SiftsClientI.java b/src/jalview/api/SiftsClientI.java new file mode 100644 index 0000000..13223af --- /dev/null +++ b/src/jalview/api/SiftsClientI.java @@ -0,0 +1,153 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.api; + +import jalview.datamodel.SequenceI; +import jalview.structure.StructureMapping; +import jalview.xml.binding.sifts.Entry.Entity; + +import java.util.HashSet; + +public interface SiftsClientI +{ + /** + * Get the DB Accession Id for the SIFTs Entry + * + * @return + */ + public String getDbAccessionId(); + + /** + * Get DB Coordinate system for the SIFTs Entry + * + * @return + */ + public String getDbCoordSys(); + + /** + * Get DB Evidence for the SIFTs Entry + * + * @return + */ + public String getDbEvidence(); + + /** + * Get DB Source for the SIFTs Entry + * + * @return + */ + public String getDbSource(); + + /** + * Get DB version for the SIFTs Entry + * + * @return + */ + public String getDbVersion(); + + /** + * Get Number of Entities available in the SIFTs Entry + * + * @return + */ + public int getEntityCount(); + + /** + * Get a unique Entity by its Id + * + * @param id + * ID of the entity to fetch + * @return Entity + * @throws Exception + */ + public Entity getEntityById(String id) throws Exception; + + /** + * Get all accession Ids available in the current SIFTs entry + * + * @return a unique set of discovered accession strings + */ + public HashSet getAllMappingAccession(); + + /** + * Check if the accessionId is available in current SIFTs Entry + * + * @param accessionId + * @return + */ + public boolean isFoundInSiftsEntry(String accessionId); + + /** + * Get the standard DB referenced by the SIFTs Entry + * + * @return + */ + public String[] getEntryDBs(); + + /** + * Get the SIFTs Entry details + */ + public void getEntryDetails(); + + /** + * + * @param seq1 + * Sequence to map + * @param seq2 + * Structure Sequence + * @param seqID1 + * sequence id + * @param seqID2 + * structure sequence id + * @param seqType + * type of sequence for the mapping (pep or protein) + * @param nochunks + * @return sequence->structure mapping as int [][] + */ + public StringBuffer getMappingOutput(String seq1, String seq2, + String seqID1, String seqID2, String seqType, int nochunks); + + /** + * + * @param seq + * sequence to generate mapping against the structure + * @param pdbFile + * PDB file for the mapping + * @param chain + * the chain of the entry to use for mapping + * @return StructureMapping + */ + public StructureMapping getSiftsStructureMapping(SequenceI seq, String pdbFile, + String chain); + + /** + * Get residue by residue mapping for a given Sequence and SIFTs entity + * + * @param entityId + * Id of the target entity in the SIFTs entry + * @param seq + * SequenceI + * @return generated mapping + * @throws Exception + */ + public int[][] getGreedyMapping(String entityId, SequenceI seq, + java.io.PrintStream os) throws Exception; +} \ No newline at end of file diff --git a/src/jalview/io/SiftsClient.java b/src/jalview/io/SiftsClient.java new file mode 100644 index 0000000..bde215d --- /dev/null +++ b/src/jalview/io/SiftsClient.java @@ -0,0 +1,624 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.io; + +import jalview.analysis.AlignSeq; +import jalview.api.DBRefEntryI; +import jalview.api.SiftsClientI; +import jalview.datamodel.DBRefEntry; +import jalview.datamodel.SequenceI; +import jalview.schemes.ResidueProperties; +import jalview.structure.StructureMapping; +import jalview.util.Format; +import jalview.xml.binding.sifts.Entry; +import jalview.xml.binding.sifts.Entry.Entity; +import jalview.xml.binding.sifts.Entry.Entity.Segment; +import jalview.xml.binding.sifts.Entry.Entity.Segment.ListMapRegion.MapRegion; +import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue; +import jalview.xml.binding.sifts.Entry.Entity.Segment.ListResidue.Residue.CrossRefDb; +import jalview.xml.binding.sifts.Entry.EntryDetail; +import jalview.xml.binding.sifts.Entry.ListDB.Db; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.URL; +import java.net.URLConnection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.zip.GZIPInputStream; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.stream.FactoryConfigurationError; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +public class SiftsClient implements SiftsClientI +{ + private Entry siftsEntry; + + private String pdbId; + + private static final int BUFFER_SIZE = 4096; + + private static final String SIFTS_FTP_BASE_URL = "ftp://ftp.ebi.ac.uk/pub/databases/msd/sifts/xml/"; + + public static final String DEFAULT_SIFTS_DOWNLOAD_DIR = System + .getProperty("user.home") + + File.separatorChar + + ".sifts_downloads" + File.separatorChar; + + public static final String SIFTS_DOWNLOAD_DIR = jalview.bin.Cache + .getDefault("sifts_download_dir", DEFAULT_SIFTS_DOWNLOAD_DIR); + + private final static String NEWLINE = System.lineSeparator(); + + /** + * Fetch SIFTs file for the given PDB Id and construct an instance of + * SiftsClient + * + * @param pdbId + */ + public SiftsClient(String pdbId) + { + this.pdbId = pdbId; + try + { + File siftsFile = getSiftsFile(pdbId); + siftsEntry = parseSIFTs(siftsFile); + } catch (Exception e) + { + e.printStackTrace(); + } + } + + /** + * Construct an instance of SiftsClient using the supplied SIFTs file - + * the SIFTs file should correspond to the given PDB Id + * + * @param pdbId + * @param siftsFile + */ + public SiftsClient(String pdbId, File siftsFile) + { + this.pdbId = pdbId; + try + { + siftsEntry = parseSIFTs(siftsFile); + } catch (Exception e) + { + e.printStackTrace(); + } + + } + + /** + * Parse the given SIFTs File and return a JAXB POJO of parsed data + * + * @param siftFile + * - the GZipped SIFTs XML file to parse + * @return + * @throws Exception + * if a problem occurs while parsing the SIFTs XML + */ + private Entry parseSIFTs(File siftFile) throws Exception + { + try + { + System.out.println("File : " + siftFile.getAbsolutePath()); + JAXBContext jc = JAXBContext.newInstance("jalview.xml.binding.sifts"); + InputStream in = new FileInputStream(siftFile); + GZIPInputStream gzis = new GZIPInputStream(in); + XMLStreamReader streamReader = XMLInputFactory.newInstance() + .createXMLStreamReader(gzis); + Unmarshaller um = jc.createUnmarshaller(); + return (Entry) um.unmarshal(streamReader); + } catch (JAXBException e) + { + e.printStackTrace(); + } catch (FileNotFoundException e) + { + e.printStackTrace(); + } catch (XMLStreamException e) + { + e.printStackTrace(); + } catch (FactoryConfigurationError e) + { + e.printStackTrace(); + } catch (IOException e) + { + e.printStackTrace(); + } + throw new Exception("Error parsing siftFile"); + } + + /** + * Get a SIFTs XML file for a given PDB Id + * + * @param pdbId + * @return SIFTs XML file + */ + public static File getSiftsFile(String pdbId) + { + File siftsFile = new File(SIFTS_DOWNLOAD_DIR + pdbId.toLowerCase() + + ".xml.gz"); + if (siftsFile.exists()) + { + // TODO it may be worth performing a timestamp age check to determine if a + // new SIFTs file should be re-downloaded as SIFTs entries are usually + // updated weekly + System.out.println(">>> SIFTS File already downloaded for " + pdbId); + return siftsFile; + } + siftsFile = downloadSiftsFile(pdbId.toLowerCase()); + return siftsFile; + } + + /** + * Download a SIFTs XML file for a given PDB Id + * + * @param pdbId + * @return downloaded SIFTs XML file + */ + public static File downloadSiftsFile(String pdbId) + { + String siftFile = pdbId + ".xml.gz"; + String siftsFileFTPURL = SIFTS_FTP_BASE_URL + siftFile; + String downloadedSiftsFile = SIFTS_DOWNLOAD_DIR + siftFile; + File siftsDownloadDir = new File(SIFTS_DOWNLOAD_DIR); + if (!siftsDownloadDir.exists()) + { + siftsDownloadDir.mkdirs(); + } + try + { + System.out.println(">> Download ftp url : " + siftsFileFTPURL); + URL url = new URL(siftsFileFTPURL); + URLConnection conn = url.openConnection(); + InputStream inputStream = conn.getInputStream(); + FileOutputStream outputStream = new FileOutputStream( + downloadedSiftsFile); + byte[] buffer = new byte[BUFFER_SIZE]; + int bytesRead = -1; + while ((bytesRead = inputStream.read(buffer)) != -1) + { + outputStream.write(buffer, 0, bytesRead); + } + outputStream.close(); + inputStream.close(); + System.out.println(">>> File downloaded : " + downloadedSiftsFile); + } catch (IOException ex) + { + ex.printStackTrace(); + } + return new File(downloadedSiftsFile); + } + + /** + * Delete the SIFTs file for the given PDB Id in the local SIFTs download + * directory + * + * @param pdbId + * @return true if the file was deleted or doesn't exist + */ + public static boolean deleteSiftsFileByPDBId(String pdbId) + { + File siftsFile = new File(SIFTS_DOWNLOAD_DIR + pdbId.toLowerCase() + + ".xml.gz"); + if (siftsFile.exists()) + { + return siftsFile.delete(); + } + return true; + } + + + /** + * Get a valid SIFTs DBRef for the given sequence current SIFTs entry + * + * @param seq + * - the target sequence for the operation + * @return a valid DBRefEntry that is SIFTs compatible + * @throws Exception + * if no valid source DBRefEntry was found for the given sequences + */ + public DBRefEntryI getValidSourceDBRef(SequenceI seq) throws Exception + { + DBRefEntryI sourceDBRef = null; + sourceDBRef = seq.getSourceDBRef(); + if (sourceDBRef != null && isValidDBRefEntry(sourceDBRef)) + { + return sourceDBRef; + } + else + { + DBRefEntry[] dbRefs = seq.getDBRefs(); + if (dbRefs == null || dbRefs.length < 1) + { + final SequenceI[] seqs = new SequenceI[] { seq }; + new jalview.ws.DBRefFetcher(seqs, null, null, null, false) + .fetchDBRefs(true); + dbRefs = seq.getDBRefs(); + } + + if (dbRefs == null || dbRefs.length < 1) + { + throw new Exception("Could not get source DB Ref"); + } + + for (DBRefEntryI dbRef : dbRefs) + { + if (dbRef == null || dbRef.getAccessionId() == null + || dbRef.getSource() == null) + { + continue; + } + if (isFoundInSiftsEntry(dbRef.getAccessionId()) + && (dbRef.getSource().equalsIgnoreCase("uniprot") || dbRef + .getSource().equalsIgnoreCase("pdb"))) + { + return dbRef; + } + } + } + if (sourceDBRef != null && isValidDBRefEntry(sourceDBRef)) + { + return sourceDBRef; + } + throw new Exception("Could not get source DB Ref"); + } + + + /** + * Check that the DBRef Entry is properly populated and is available in the + * instantiated SIFTs Entry + * + * @param entry + * - DBRefEntry to validate + * @return true validation is successful otherwise false is returned. + */ + private boolean isValidDBRefEntry(DBRefEntryI entry) + { + return entry != null && entry.getAccessionId() != null + && isFoundInSiftsEntry(entry.getAccessionId()); + // & entry.getStartRes() > 0; + } + + @Override + public HashSet getAllMappingAccession() + { + HashSet accessions = new HashSet(); + List entities = siftsEntry.getEntity(); + for (Entity entity : entities) + { + List segments = entity.getSegment(); + for (Segment segment : segments) + { + List mapRegions = segment.getListMapRegion() + .getMapRegion(); + for (MapRegion mapRegion : mapRegions) + { + accessions.add(mapRegion.getDb().getDbAccessionId()); + } + } + } + return accessions; + } + + + @Override + public int[][] getGreedyMapping(String entityId, SequenceI seq, + java.io.PrintStream os) + throws Exception + { + System.out.println("Generating mappings for : " + entityId); + Entity entity = null; + entity = getEntityById(entityId); + String seqStr = AlignSeq.extractGaps(jalview.util.Comparison.GapChars, + seq.getSequenceAsString()); + // StringBuilder mappedStrucSeq = new StringBuilder(seqStr.length()); + String[] mappedStrucSeq = new String[seqStr.length()]; + int mapping[][] = new int[seqStr.length()][2]; + DBRefEntryI sourceDBRef = seq.getSourceDBRef(); + if (sourceDBRef == null) + { + sourceDBRef = getValidSourceDBRef(seq); + // TODO if sourceDBRef is null at this point then throw an Exception + + // TODO update sequence start/end with sourceDBRef start/end + // seq.setStart(sourceDBRef.getStartRes()); + // seq.setEnd(sourceDBRef.getEndRes()); + } + + String crossRefAccessionId = sourceDBRef.getAccessionId(); + int start = seq.getStart() - 1; + for (int residue[] : mapping) + { + residue[1] = start++; + } + + HashMap resNumMap = new HashMap(); + List segments = entity.getSegment(); + for (Segment segment : segments) + { + System.out.println("Mappging segments : " + segment.getSegId() + "\\" + + segment.getStart() + "-" + segment.getEnd()); + List residues = segment.getListResidue().getResidue(); + for (Residue residue : residues) + { + int refDbResNum = -1; + List cRefDbs = residue.getCrossRefDb(); + for (CrossRefDb cRefDb : cRefDbs) + { + if (cRefDb.getDbAccessionId().equalsIgnoreCase( + crossRefAccessionId)) + { + refDbResNum = Integer.valueOf(cRefDb.getDbResNum()); + } + } + if (refDbResNum == -1) + { + continue; + } + for (int[] x : mapping) + { + if (x[1] == refDbResNum) + { + int resNum = Integer.valueOf(residue.getDbResNum()); + x[0] = resNum; + String value = "x"; + resNumMap.put(resNum, value); + } + } + } + } + + //Generate visual mapping output + // StringBuilder strucSeq = new StringBuilder(); + // for(int[] x : mapping){ + // if(mapping[0] == 0){ + // strucSeq.append(b) + // } + // } + mappedStrucSeq[1] = "x"; + try + { + System.out.println(">>>> seq: " + seqStr + "\nlength " + + seqStr.length()); + System.out.println(">>>> pdb: " + mappedStrucSeq.toString() + + "\nlength " + mappedStrucSeq.toString().length()); + + String printedMapping = getMappingOutput(mappedStrucSeq.toString(), + seqStr, "seqAccession", "strucAccession", "pep", 3) + .toString(); + if (os != null) + { + os.print(printedMapping); + } + System.out.println(); + } catch (Exception ex) + { + ex.printStackTrace(); + } + return mapping; + } + + @Override + public boolean isFoundInSiftsEntry(String accessionId) + { + return accessionId != null + && getAllMappingAccession().contains(accessionId); + } + + @Override + public StructureMapping getSiftsStructureMapping(SequenceI seq, + String pdbFile, String chain) + { + System.out.println("Getting mapping for: " + pdbId + "|" + chain + + " : seq- " + seq.getName()); + + final StringBuilder mappingDetails = new StringBuilder(128); + PrintStream ps = new PrintStream(System.out) + { + @Override + public void print(String x) + { + mappingDetails.append(x); + } + + @Override + public void println() + { + mappingDetails.append(NEWLINE); + } + }; + int[][] mapping = null; + try + { + mapping = getGreedyMapping(chain, seq, ps); + } catch (Exception e) + { + e.printStackTrace(); + } + // String mappingOutput = mappingDetails.toString(); + String mappingOutput = null; + return new StructureMapping(seq, pdbFile, pdbId, chain, mapping, + mappingOutput); + } + + @Override + public Entity getEntityById(String id) throws Exception + { + List entities = siftsEntry.getEntity(); + for (Entity entity : entities) + { + if (!entity.getEntityId().equalsIgnoreCase(id)) + { + continue; + } + return entity; + } + throw new Exception("Entity " + id + " not found"); + } + + @Override + public String[] getEntryDBs() + { + System.out.println("\nListing DB entries..."); + List dbs = siftsEntry.getListDB().getDb(); + for (Db db : dbs) + { + System.out.println(db.getDbSource() + " | " + db.getDbCoordSys()); + } + return null; + } + + @Override + public void getEntryDetails() + { + List eds = siftsEntry.getEntryDetail(); + for (EntryDetail ed : eds) + { + System.out.println("Entry Details: " + ed.getContent() + " " + + ed.getDbSource() + " " + ed.getProperty() + " " + + ed.toString()); + } + } + + @Override + public StringBuffer getMappingOutput(String astr1, String astr2, String s1id, + String s2id, String type, int nochunks) + { + int maxid = s1id.length(); + int len = 72 - maxid - 1; + StringBuffer output = new StringBuffer(); + // output mappings + float pid = 0; + for (int j = 0; j < nochunks; j++) + { + // Print the first aligned sequence + output.append(new Format("%" + (maxid) + "s").form(s1id)).append(" "); + + for (int i = 0; i < len; i++) + { + if ((i + (j * len)) < astr1.length()) + { + output.append(astr1.charAt(i + (j * len))); + } + } + + output.append(NEWLINE); + output.append(new Format("%" + (maxid) + "s").form(" ")).append(" "); + + // Print out the matching chars + for (int i = 0; i < len; i++) + { + if ((i + (j * len)) < astr1.length()) + { + if (astr1.charAt(i + (j * len)) == astr2.charAt(i + (j * len)) + && !jalview.util.Comparison.isGap(astr1.charAt(i + + (j * len)))) + { + pid++; + output.append("|"); + } + else if (type.equals("pep")) + { + if (ResidueProperties.getPAM250(astr1.charAt(i + (j * len)), + astr2.charAt(i + (j * len))) > 0) + { + output.append("."); + } + else + { + output.append(" "); + } + } + else + { + output.append(" "); + } + } + } + // Now print the second aligned sequence + output = output.append(NEWLINE); + output = output.append(new Format("%" + (maxid) + "s").form(s2id)) + .append(" "); + for (int i = 0; i < len; i++) + { + if ((i + (j * len)) < astr2.length()) + { + output.append(astr2.charAt(i + (j * len))); + } + } + output.append(NEWLINE).append(NEWLINE); + } + pid = pid / (astr1.length()) * 100; + System.out.println(output); + System.out.println(pid); + // TODO return output & pid + return output; + } + + @Override + public int getEntityCount() + { + return siftsEntry.getEntity().size(); + } + + @Override + public String getDbAccessionId() + { + return siftsEntry.getDbAccessionId(); + } + + @Override + public String getDbCoordSys() + { + return siftsEntry.getDbCoordSys(); + } + + @Override + public String getDbEvidence() + { + return siftsEntry.getDbEvidence(); + } + + @Override + public String getDbSource() + { + return siftsEntry.getDbSource(); + } + + @Override + public String getDbVersion() + { + return siftsEntry.getDbVersion(); + } +} diff --git a/src/jalview/structure/StructureSelectionManager.java b/src/jalview/structure/StructureSelectionManager.java index e9d736f..0b3696c 100644 --- a/src/jalview/structure/StructureSelectionManager.java +++ b/src/jalview/structure/StructureSelectionManager.java @@ -458,117 +458,61 @@ public class StructureSelectionManager { continue; } - final StringBuilder mappingDetails = new StringBuilder(128); - mappingDetails.append(NEWLINE).append("PDB Sequence is :") - .append(NEWLINE).append("Sequence = ") - .append(maxChain.sequence.getSequenceAsString()); - mappingDetails.append(NEWLINE).append("No of residues = ") - .append(maxChain.residues.size()).append(NEWLINE) - .append(NEWLINE); - PrintStream ps = new PrintStream(System.out) - { - @Override - public void print(String x) - { - mappingDetails.append(x); - } - - @Override - public void println() - { - mappingDetails.append(NEWLINE); - } - }; - - // mapWithNWAlignment(); - // mapWithSIFTS(); - maxAlignseq.printAlignment(ps); - - mappingDetails.append(NEWLINE).append("PDB start/end "); - mappingDetails.append(String.valueOf(maxAlignseq.seq2start)).append( - " "); - mappingDetails.append(String.valueOf(maxAlignseq.seq2end)); - mappingDetails.append(NEWLINE).append("SEQ start/end "); - // TODO JAL-1887 should be fixed from here - mappingDetails.append( - String.valueOf(maxAlignseq.seq1start + seq.getStart() - 1)) - .append(" "); - mappingDetails.append(String.valueOf(maxAlignseq.seq1end - + seq.getEnd() - 1)); - - maxChain.makeExactMapping(maxAlignseq, seq); - jalview.datamodel.Mapping sqmpping = maxAlignseq - .getMappingFromS1(false); - jalview.datamodel.Mapping omap = new jalview.datamodel.Mapping( - sqmpping.getMap().getInverse()); - maxChain.transferRESNUMFeatures(seq, null); - - // allocate enough slots to store the mapping from positions in - // sequence[s] to the associated chain - int[][] mapping = new int[seq.findPosition(seq.getLength()) + 2][2]; - int resNum = -10000; - int index = 0; - - do - { - Atom tmp = maxChain.atoms.elementAt(index); - if (resNum != tmp.resNumber && tmp.alignmentMapping != -1) - { - resNum = tmp.resNumber; - if (tmp.alignmentMapping >= -1) - { - // TODO (JAL-1836) address root cause: negative residue no in PDB - // file - mapping[tmp.alignmentMapping + 1][0] = tmp.resNumber; - mapping[tmp.alignmentMapping + 1][1] = tmp.atomIndex; - } - } - - index++; - } while (index < maxChain.atoms.size()); if (protocol.equals(jalview.io.AppletFormatAdapter.PASTE)) { pdbFile = "INLINE" + pdb.id; } - // StructureMapping newMapping = new StructureMapping(seq, pdbFile, - // pdb.id, maxChainId, mapping, mappingDetails.toString()); - StructureMapping newMapping = new SiftsClient(pdb.id) - .getSiftsMappingsFor(seq, pdbFile, maxChainId); + + StructureMapping seqToStrucMapping = null; + boolean isMapViaSIFTs = Boolean.valueOf(jalview.bin.Cache.getDefault( + "MAP_WITH_SIFTS", "false")); + if (isMapViaSIFTs) + { + SiftsClient siftsClient = new SiftsClient(pdb.id); + seqToStrucMapping = siftsClient.getSiftsStructureMapping(seq, + pdbFile, maxChainId); + // TODO if SIFTs mapping fails.. then fallback to NW alignment + } + else + { + seqToStrucMapping = getNWMappings(seq, pdbFile, + maxChainId, maxChain, pdb, + maxAlignseq); + } + if (forStructureView) { - mappings.add(newMapping); + mappings.add(seqToStrucMapping); } - maxChain.transferResidueAnnotation(newMapping, sqmpping); } - // /////// - return pdb; } - private StructureMapping mapWithNWAlignment(StringBuilder mappingDetails, - PDBChain maxChain, AlignSeq maxAlignseq, SequenceI seq, - PrintStream ps) + private StructureMapping getNWMappings(SequenceI seq, String pdbFile, + String maxChainId, PDBChain maxChain, PDBfile pdb, + AlignSeq maxAlignseq) { - maxAlignseq.printAlignment(ps); + final StringBuilder mappingDetails = new StringBuilder(128); + PrintStream ps = new PrintStream(System.out) + { + @Override + public void print(String x) + { + mappingDetails.append(x); + } - mappingDetails.append(NEWLINE).append("PDB start/end "); - mappingDetails.append(String.valueOf(maxAlignseq.seq2start)) - .append(" "); - mappingDetails.append(String.valueOf(maxAlignseq.seq2end)); - mappingDetails.append(NEWLINE).append("SEQ start/end "); - // TODO JAL-1887 should be fixed from here - mappingDetails.append( - String.valueOf(maxAlignseq.seq1start + seq.getStart() - 1)) - .append(" "); - mappingDetails.append(String.valueOf(maxAlignseq.seq1end + seq.getEnd() - - 1)); + @Override + public void println() + { + mappingDetails.append(NEWLINE); + } + }; + maxAlignseq.printAlignment(ps); maxChain.makeExactMapping(maxAlignseq, seq); jalview.datamodel.Mapping sqmpping = maxAlignseq .getMappingFromS1(false); - jalview.datamodel.Mapping omap = new jalview.datamodel.Mapping(sqmpping - .getMap().getInverse()); maxChain.transferRESNUMFeatures(seq, null); // allocate enough slots to store the mapping from positions in @@ -595,7 +539,10 @@ public class StructureSelectionManager index++; } while (index < maxChain.atoms.size()); - return null; + StructureMapping nwMapping = new StructureMapping(seq, pdbFile, + pdb.id, maxChainId, mapping, mappingDetails.toString()); + maxChain.transferResidueAnnotation(nwMapping, sqmpping); + return nwMapping; } public void removeStructureViewerListener(Object svl, String[] pdbfiles) diff --git a/src/jalview/ws/DBRefFetcher.java b/src/jalview/ws/DBRefFetcher.java index 2e0197c..473d54f 100644 --- a/src/jalview/ws/DBRefFetcher.java +++ b/src/jalview/ws/DBRefFetcher.java @@ -57,7 +57,7 @@ public class DBRefFetcher implements Runnable { SequenceI[] dataset; - IProgressIndicator af; + IProgressIndicator progressWindow; CutAndPasteTransfer output = new CutAndPasteTransfer(); @@ -109,7 +109,7 @@ public class DBRefFetcher implements Runnable IProgressIndicator progressIndicatorFrame, DbSourceProxy[] sources, FeatureSettings featureSettings, boolean isNucleotide) { - this.af = progressIndicatorFrame; + this.progressWindow = progressIndicatorFrame; alseqs = new SequenceI[seqs.length]; SequenceI[] ds = new SequenceI[seqs.length]; for (int i = 0; i < seqs.length; i++) @@ -286,8 +286,12 @@ public class DBRefFetcher implements Runnable } running = true; long startTime = System.currentTimeMillis(); - af.setProgressBar(MessageManager.getString("status.fetching_db_refs"), + if (progressWindow != null) + { + progressWindow.setProgressBar( + MessageManager.getString("status.fetching_db_refs"), startTime); + } try { if (Cache.getDefault("DBREFFETCH_USEPICR", false)) @@ -472,11 +476,14 @@ public class DBRefFetcher implements Runnable // of the viewed sequence } + if (progressWindow != null) + { + progressWindow.setProgressBar( + MessageManager.getString("label.dbref_search_completed"), + startTime); + // promptBeforeBlast(); - af.setProgressBar( - MessageManager.getString("label.dbref_search_completed"), - startTime); - // promptBeforeBlast(); + } running = false; diff --git a/test/jalview/io/1a70.xml.gz b/test/jalview/io/1a70.xml.gz new file mode 100644 index 0000000..3f0b68a Binary files /dev/null and b/test/jalview/io/1a70.xml.gz differ diff --git a/test/jalview/io/SiftsClientTest.java b/test/jalview/io/SiftsClientTest.java new file mode 100644 index 0000000..6ff3705 --- /dev/null +++ b/test/jalview/io/SiftsClientTest.java @@ -0,0 +1,180 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.io; + +import jalview.datamodel.DBRefEntry; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceI; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.PrintStream; + +import org.testng.Assert; +import org.testng.FileAssert; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +public class SiftsClientTest +{ + private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + + private String testPDBId = "1a70"; + + private SiftsClient siftsClient = null; + + SequenceI testSeq = new Sequence( + "P00221", + "MAAT..TTTMMG..MATTFVPKPQAPPMMAALPSNTGR..SLFGLKT.GSR..GGRMTMA" + + "AYKVTLVTPTGNVEFQCPDDVYILDAAEEEGIDLPYSCRAGSCSSCAGKLKTGSLNQDD" + + "QSFLDDDQIDEGWVLTCAAYPVSDVTIETHKEEELTA.", 1, 147); + + int[][] expectedMapping = { { 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 }, + { 0, 4 }, { 0, 5 }, { 0, 6 }, { 0, 7 }, { 0, 8 }, { 0, 9 }, + { 0, 10 }, { 0, 11 }, { 0, 12 }, { 0, 13 }, { 0, 14 }, { 0, 15 }, + { 0, 16 }, { 0, 17 }, { 0, 18 }, { 0, 19 }, { 0, 20 }, { 0, 21 }, + { 0, 22 }, { 0, 23 }, { 0, 24 }, { 0, 25 }, { 0, 26 }, { 0, 27 }, + { 0, 28 }, { 0, 29 }, { 0, 30 }, { 0, 31 }, { 0, 32 }, { 0, 33 }, + { 0, 34 }, { 0, 35 }, { 0, 36 }, { 0, 37 }, { 0, 38 }, { 0, 39 }, + { 0, 40 }, { 0, 41 }, { 0, 42 }, { 0, 43 }, { 0, 44 }, { 0, 45 }, + { 0, 46 }, { 0, 47 }, { 0, 48 }, { 0, 49 }, { 0, 50 }, { 1, 51 }, + { 2, 52 }, { 3, 53 }, { 4, 54 }, { 5, 55 }, { 6, 56 }, { 7, 57 }, + { 8, 58 }, { 9, 59 }, { 10, 60 }, { 11, 61 }, { 12, 62 }, { 13, 63 }, + { 14, 64 }, { 15, 65 }, { 16, 66 }, { 17, 67 }, { 18, 68 }, + { 19, 69 }, { 20, 70 }, { 21, 71 }, { 22, 72 }, { 23, 73 }, + { 24, 74 }, { 25, 75 }, { 26, 76 }, { 27, 77 }, { 28, 78 }, + { 29, 79 }, { 30, 80 }, { 31, 81 }, { 32, 82 }, { 33, 83 }, + { 34, 84 }, { 35, 85 }, { 36, 86 }, { 37, 87 }, { 38, 88 }, + { 39, 89 }, { 40, 90 }, { 41, 91 }, { 42, 92 }, { 43, 93 }, + { 44, 94 }, { 45, 95 }, { 46, 96 }, { 47, 97 }, { 48, 98 }, + { 49, 99 }, { 50, 100 }, { 51, 101 }, { 52, 102 }, { 53, 103 }, + { 54, 104 }, { 55, 105 }, { 56, 106 }, { 57, 107 }, { 58, 108 }, + { 59, 109 }, { 60, 110 }, { 61, 111 }, { 62, 112 }, { 63, 113 }, + { 64, 114 }, { 65, 115 }, { 66, 116 }, { 67, 117 }, { 68, 118 }, + { 69, 119 }, { 70, 120 }, { 71, 121 }, { 72, 122 }, { 73, 123 }, + { 74, 124 }, { 75, 125 }, { 76, 126 }, { 77, 127 }, { 78, 128 }, + { 79, 129 }, { 80, 130 }, { 81, 131 }, { 82, 132 }, { 83, 133 }, + { 84, 134 }, { 85, 135 }, { 86, 136 }, { 87, 137 }, { 88, 138 }, + { 89, 139 }, { 90, 140 }, { 91, 141 }, { 92, 142 }, { 93, 143 }, + { 94, 144 }, { 95, 145 }, { 96, 146 } }; + + @BeforeTest(alwaysRun = true) + public void setUpSiftsClient() + { + // SIFTs entries are updated weekly - so use saved SIFTs file to enforce + // test reproducibility + File testSiftsFile = new File("test/jalview/io/" + testPDBId + + ".xml.gz"); + siftsClient = new SiftsClient(testPDBId, testSiftsFile); + } + + @AfterTest(alwaysRun = true) + public void cleanUpSiftsClient() + { + siftsClient = null; + } + + @BeforeTest(alwaysRun = true) + public void setUpStreams() + { + System.setOut(new PrintStream(outContent)); + } + + @AfterTest(alwaysRun = true) + public void cleanUpStreams() + { + System.setOut(null); + } + + @Test(groups = { "Functional" }) + public void getSIFTsFileTest() + { + Assert.assertTrue(SiftsClient.deleteSiftsFileByPDBId(testPDBId)); + SiftsClient.getSiftsFile(testPDBId); + Assert.assertFalse(outContent.toString().contains( + ">>> SIFTS File already downloaded for " + testPDBId)); + + // test for SIFTs file caching + SiftsClient.getSiftsFile(testPDBId); + Assert.assertTrue(outContent.toString().contains( + ">>> SIFTS File already downloaded for " + testPDBId)); + } + + @Test(groups = { "Functional" }) + public void downloadSiftsFileTest() + { + // Assert that file isn't yet downloaded - if already downloaded, assert it + // is deleted + Assert.assertTrue(SiftsClient.deleteSiftsFileByPDBId(testPDBId)); + File siftsFile = SiftsClient.downloadSiftsFile(testPDBId); + FileAssert.assertFile(siftsFile); + SiftsClient.downloadSiftsFile(testPDBId); + } + + @Test(groups = { "Functional" }) + public void getAllMappingAccessionTest() + { + Assert.assertNotNull(siftsClient); + Assert.assertNotNull(siftsClient.getAllMappingAccession()); + Assert.assertTrue(siftsClient.getAllMappingAccession().size() > 1); + } + + @Test(groups = { "Functional" }) + public void getGreedyMappingTest() + { + Assert.assertNotNull(siftsClient); + Assert.assertNotNull(testSeq); + Assert.assertNotNull(expectedMapping); + + // TODO delete when auto-fetching of DBRefEntry is implemented + DBRefEntry dbRef = new DBRefEntry("uniprot", "", "P00221"); + dbRef.setStartRes(1); + dbRef.setEndRes(147); + testSeq.addDBRef(dbRef); + // testSeq.setSourceDBRef(dbRef); + + try + { + int[][] actualMapping = siftsClient.getGreedyMapping("A", testSeq, + null); + Assert.assertEquals(actualMapping, expectedMapping); + Assert.assertEquals(testSeq.getStart(), 1); + Assert.assertEquals(testSeq.getEnd(), 147); + } catch (Exception e) + { + e.printStackTrace(); + Assert.fail("Exception thrown while generating mapping..."); + } + } + + @Test(groups = { "Functional" }) + public void getValidSourceDBRefTest() + { + + } + + @Test(groups = { "Functional" }) + public void isValidDBRefEntryTest() + { + + } +}