Clover icon

Coverage Report

  1. Project Clover database Thu Mar 26 2026 08:01:43 GMT
  2. Package jalview.ws.dbsources

File EBIAlfaFold.java

 

Coverage histogram

../../../img/srcFileCovDistChart4.png
49% of files have more coverage

Code metrics

86
212
27
1
784
545
95
0.45
7.85
27
3.52

Classes

Class Line # Actions
EBIAlfaFold 70 212 95
0.3415384634.2%
 

Contributing tests

This file is covered by 68 tests. .

Source view

1   
2    /*
3    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
4    * Copyright (C) $$Year-Rel$$ The Jalview Authors
5    *
6    * This file is part of Jalview.
7    *
8    * Jalview is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License
10    * as published by the Free Software Foundation, either version 3
11    * of the License, or (at your option) any later version.
12    *
13    * Jalview is distributed in the hope that it will be useful, but
14    * WITHOUT ANY WARRANTY; without even the implied warranty
15    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16    * PURPOSE. See the GNU General Public License for more details.
17    *
18    * You should have received a copy of the GNU General Public License
19    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
20    * The Jalview Authors are detailed in the 'AUTHORS' file.
21    */
22    package jalview.ws.dbsources;
23   
24    import java.io.File;
25    import java.io.FileInputStream;
26    import java.io.FileNotFoundException;
27    import java.io.IOException;
28    import java.io.InputStream;
29    import java.net.URL;
30    import java.util.ArrayList;
31    import java.util.Date;
32    import java.util.HashMap;
33    import java.util.List;
34    import java.util.Map;
35   
36    import org.json.simple.JSONArray;
37    import org.json.simple.JSONObject;
38    import org.json.simple.parser.ParseException;
39   
40    import com.stevesoft.pat.Regex;
41   
42    import jalview.api.FeatureSettingsModelI;
43    import jalview.bin.Console;
44    import jalview.datamodel.AlignmentAnnotation;
45    import jalview.datamodel.AlignmentI;
46    import jalview.datamodel.ContactMatrixI;
47    import jalview.datamodel.DBRefEntry;
48    import jalview.datamodel.PDBEntry;
49    import jalview.datamodel.SequenceFeature;
50    import jalview.datamodel.SequenceI;
51    import jalview.gui.Desktop;
52    import jalview.io.DataSourceType;
53    import jalview.io.FileFormat;
54    import jalview.io.FileFormatI;
55    import jalview.io.FormatAdapter;
56    import jalview.io.PDBFeatureSettings;
57    import jalview.structure.StructureImportSettings.TFType;
58    import jalview.structure.StructureMapping;
59    import jalview.structure.StructureSelectionManager;
60    import jalview.util.MessageManager;
61    import jalview.util.Platform;
62    import jalview.ws.datamodel.alphafold.AlphaFoldDBEntry;
63    import jalview.ws.datamodel.alphafold.PAEContactMatrix;
64    import jalview.ws.utils.UrlDownloadClient;
65   
66    /**
67    * @author JimP
68    *
69    */
 
70    public class EBIAlfaFold extends EbiFileRetrievedProxy
71    {
72    private static final String SEPARATOR = "|";
73   
74    private static final String COLON = ":";
75   
76    private static String AF_VERSION = null;
77   
 
78  244 toggle public EBIAlfaFold()
79    {
80  244 super();
81    }
82   
83    /*
84    * (non-Javadoc)
85    *
86    * @see jalview.ws.DbSourceProxy#getAccessionSeparator()
87    */
 
88  0 toggle @Override
89    public String getAccessionSeparator()
90    {
91  0 return null;
92    }
93   
94    /*
95    * (non-Javadoc)
96    *
97    * @see jalview.ws.DbSourceProxy#getAccessionValidator()
98    */
 
99  244 toggle @Override
100    public Regex getAccessionValidator()
101    {
102    // Since AF Multimer, accessions can be like AF00012344 rather than AF-Q0130e-F1
103    // also need to be able to map _model_v1 in cif files
104  244 Regex validator = new Regex("(AF-[A-Z]*[0-9]+[A-Z0-9]+([-0-9A-Za-z_]*[0-9]+)?)");
105  244 validator.setIgnoreCase(true);
106  244 return validator;
107    }
108   
109    /*
110    * (non-Javadoc)
111    *
112    * @see jalview.ws.DbSourceProxy#getDbSource()
113    */
 
114  0 toggle @Override
115    public String getDbSource()
116    {
117  0 return "ALPHAFOLD";
118    }
119   
120    /*
121    * (non-Javadoc)
122    *
123    * @see jalview.ws.DbSourceProxy#getDbVersion()
124    */
 
125  0 toggle @Override
126    public String getDbVersion()
127    {
128  0 return "1";
129    }
130   
 
131  0 toggle public static String pingAPIVersion()
132    {
133  0 if (AF_VERSION != null)
134    {
135  0 return AF_VERSION;
136    }
137  0 synchronized (EBIAlfaFold.class)
138    {
139  0 if (AF_VERSION != null)
140    {
141  0 return AF_VERSION;
142    }
143   
144  0 String Version = null;
145  0 try
146    {
147  0 URL ping = new URL(
148    "https://alphafold.ebi.ac.uk/api/prediction/Q5VSL9");
149  0 Object resp = Platform.parseJSON(ping.openStream());
150  0 if (resp != null && resp instanceof JSONArray)
151    {
152  0 Version = (((JSONObject) ((JSONArray) resp).get(0))
153    .get("latestVersion")).toString();
154  0 AF_VERSION = Version;
155    }
156    } catch (Throwable x)
157    {
158  0 jalview.bin.Console.errPrintln(
159    "Couldn't get EBI AlphaFold DB latest version!");
160  0 jalview.bin.Console.errPrintln(x);
161    }
162  0 return Version;
163    }
164    }
165   
166    /**
167    * grab one or more accessions via the AlphaFoldDB api
168    * Errors are logged but not thrown.
169    *
170    * @param accession - list of accession IDs
171    * @return List<AlphaFoldDBEntry> entries for each ID that were actually found
172    */
 
173  32 toggle public static List<AlphaFoldDBEntry> lookUpEntries(String... accession) {
174  32 List<AlphaFoldDBEntry> entries=new ArrayList();
175  32 for (String id:accession) {
176   
177  32 try
178    {
179  32 URL ping = new URL(
180    "https://alphafold.ebi.ac.uk/api/prediction/"+id);
181  32 Object resp = Platform.parseJSON(ping.openStream());
182  32 if (resp != null && resp instanceof JSONArray)
183    {
184  32 AlphaFoldDBEntry entry = new AlphaFoldDBEntry();
185  32 entry.Json=(JSONObject) ((JSONArray) resp).get(0);
186  32 entry.accessionId=id;
187  32 entry.paeFile = new URL(entry.Json.get("paeDocUrl").toString());
188  32 entry.mmCif = new URL(entry.Json.get("cifUrl").toString());
189  32 entries.add(entry);
190    }
191    } catch (Throwable x)
192    {
193  0 jalview.bin.Console.errPrintln(
194    "Couldn't get EBI AlphaFold DB Entry for "+id);
195  0 jalview.bin.Console.errPrintln(x);
196    }
197    }
198  32 return entries;
199    }
200   
 
201  0 toggle public static String getAlphaFoldCifDownloadUrl(String id, String vnum)
202    {
203  0 if (vnum == null || vnum.length() == 0)
204    {
205  0 pingAPIVersion();
206  0 vnum = AF_VERSION;
207    }
208  0 return "https://alphafold.ebi.ac.uk/files/" + id + "-model_v" + vnum
209    + ".cif";
210    }
211   
 
212  0 toggle public static String getAlphaFoldPaeDownloadUrl(String id, String vnum)
213    {
214  0 if (vnum == null || vnum.length() == 0)
215    {
216  0 pingAPIVersion();
217  0 vnum = AF_VERSION;
218    }
219  0 return "https://alphafold.ebi.ac.uk/files/" + id
220    + "-predicted_aligned_error_v" + vnum + ".json";
221    }
222   
223    /*
224    * (non-Javadoc)
225    *
226    * @see jalview.ws.DbSourceProxy#getSequenceRecords(java.lang.String[])
227    */
 
228  0 toggle @Override
229    public AlignmentI getSequenceRecords(String queries) throws Exception
230    {
231  0 return getSequenceRecords(queries, null);
232    }
233   
 
234  0 toggle public AlignmentI getSequenceRecords(String queries, String retrievalUrl)
235    throws Exception
236    {
237  0 AlignmentI pdbAlignment = null;
238  0 String chain = null;
239  0 String id = null;
240  0 if (queries.indexOf(COLON) > -1)
241    {
242  0 chain = queries.substring(queries.indexOf(COLON) + 1);
243  0 id = queries.substring(0, queries.indexOf(COLON));
244    }
245    else
246    {
247  0 id = queries;
248    }
249   
250  0 if (!isValidReference(id))
251    {
252  0 jalview.bin.Console.errPrintln(
253    "(AFClient) Ignoring invalid alphafold query: '" + id + "'");
254  0 stopQuery();
255  0 return null;
256    }
257  0 String alphaFoldCif = getAlphaFoldCifDownloadUrl(id, AF_VERSION);
258  0 if (retrievalUrl != null)
259    {
260  0 alphaFoldCif = retrievalUrl;
261    }
262   
263  0 try
264    {
265  0 File tmpFile = File.createTempFile(id, ".cif");
266  0 Console.debug("Retrieving structure file for " + id + " from "
267    + alphaFoldCif);
268  0 UrlDownloadClient.download(alphaFoldCif, tmpFile);
269   
270    // may not need this check ?
271  0 file = tmpFile.getAbsolutePath();
272  0 if (file == null)
273    {
274  0 return null;
275    }
276    // TODO Get the PAE file somewhere around here and remove from JmolParser
277   
278  0 pdbAlignment = importDownloadedStructureFromUrl(alphaFoldCif, tmpFile,
279    id, chain, getDbSource(), getDbVersion());
280   
281  0 if (pdbAlignment == null || pdbAlignment.getHeight() < 1)
282    {
283  0 throw new Exception(MessageManager.formatMessage(
284    "exception.no_pdb_records_for_chain", new String[]
285  0 { id, ((chain == null) ? "' '" : chain) }));
286    }
287    // done during structure retrieval
288    // retrieve_AlphaFold_pAE(id, pdbAlignment, retrievalUrl);
289   
290    } catch (Exception ex) // Problem parsing PDB file
291    {
292  0 stopQuery();
293  0 throw (ex);
294    }
295  0 return pdbAlignment;
296    }
297   
298    /**
299    * get an alphafold pAE for the given id and return the File object of the
300    * downloaded (temp) file
301    *
302    * @param id
303    * @param retrievalUrl
304    * - URL of .mmcif from EBI-AlphaFold - will be used to generate the
305    * pAE URL automatically
306    * @throws IOException
307    * @throws Exception
308    */
 
309  32 toggle public static File fetchAlphaFoldPAE(String id, String retrievalUrl)
310    throws IOException
311    {
312  32 Console.debug(
313  32 "Fetching PAE for "+id+" from "+((retrievalUrl==null) ? "AlphaFoldDB" : retrievalUrl));
314   
315  32 String paeURL=null;
316   
317  32 if (retrievalUrl != null)
318    {
319    // manufacture the PAE url from a url like ...-model-vN.cif
320  0 paeURL = retrievalUrl.replace("model", "predicted_aligned_error")
321    .replace(".cif", ".json");
322    } else {
323    // import PAE as contact matrix - assume this will work if there was a
324    // model
325  32 Console.trace("Resolving PAE URL...");
326  32 String pId=id;
327  32 if (pId.indexOf('-',4)>12) // allows AF-QBLAH-F1 monomer style
328    {
329  0 pId = pId.substring(0,pId.indexOf('-',4));
330    }
331  32 List<AlphaFoldDBEntry> entries = lookUpEntries(pId);
332  32 paeURL = entries.get(0).paeFile.toExternalForm();
333  32 Console.trace("Resolved : "+paeURL);
334    }
335  32 return fetchAPAE_from(id, paeURL);
336    }
337   
338    /**
339    * get a PAE file or reuse existing file
340    *
341    * @param id
342    * - null or an alphafold ID if this is an alphafold model - used
343    * only to construct tempfile name
344    * @param retrievalUrl
345    * - URL of .mmcif from EBI-AlphaFold - will be used to generate the
346    * pAE URL automatically
347    * @throws IOException
348    * @throws Exception
349    */
 
350  35 toggle public static File fetchAPAE_from(String id, String paeURL)
351    throws IOException
352    {
353  35 Console.debug(
354    "fetchAPAE called for "+id+" from '" + paeURL + "'");
355   
356    // check the cache
357  35 File pae = paeDownloadCache.get(paeURL);
358  35 if (pae != null && pae.exists() && (new Date().getTime()
359    - pae.lastModified()) < PAE_CACHE_STALE_TIME)
360    {
361  32 Console.debug(
362    "Using existing file in PAE cache for '" + paeURL + "'");
363  32 return pae;
364    }
365   
366  3 try
367    {
368  3 pae = File.createTempFile(id == null ? "af_pae" : id, "pae_json");
369    } catch (IOException e)
370    {
371  0 e.printStackTrace();
372    }
373  3 Console.debug("Downloading pae from " + paeURL + " to " + pae.toString()
374    + "");
375  3 try
376    {
377  3 UrlDownloadClient.download(paeURL, pae);
378    } catch (IOException e)
379    {
380  0 throw e;
381    }
382    // cache and it if successful
383  3 paeDownloadCache.put(paeURL, pae);
384  3 return pae;
385    }
386   
387    /**
388    * get an alphafold pAE for the given id, and add it to sequence 0 in
389    * pdbAlignment (assuming it came from structurefile parser).
390    *
391    * @param id
392    * @param pdbAlignment
393    * @param retrievalUrl
394    * - URL of .mmcif from EBI-AlphaFold - will be used to generate the
395    * pAE URL automatically
396    * @throws IOException
397    * @throws Exception
398    */
 
399  0 toggle public static void retrieve_AlphaFold_pAE(String id,
400    AlignmentI pdbAlignment, String retrievalUrl) throws IOException
401    {
402  0 File pae = fetchAlphaFoldPAE(id, retrievalUrl);
403  0 addAlphaFoldPAE(pdbAlignment, pae, 0, null, false, false, null);
404    }
405   
 
406  95 toggle public static void addAlphaFoldPAE(AlignmentI pdbAlignment, File pae,
407    int index, String id, boolean isStruct, boolean isStructId,
408    String label)
409    {
410  95 FileInputStream paeInput = null;
411  95 try
412    {
413  95 paeInput = new FileInputStream(pae);
414    } catch (FileNotFoundException e)
415    {
416  0 Console.error(
417    "Could not find pAE file '" + pae.getAbsolutePath() + "'", e);
418  0 return;
419    }
420   
421  95 if (isStruct)
422    {
423    // ###### WRITE A TEST for this bit of the logic addAlphaFoldPAE with
424    // different params.
425  0 StructureSelectionManager ssm = StructureSelectionManager
426    .getStructureSelectionManager(Desktop.instance);
427  0 if (ssm != null)
428    {
429  0 String structFilename = isStructId ? ssm.findFileForPDBId(id) : id;
430  0 addPAEToStructure(ssm, structFilename, pae, label);
431    }
432   
433    }
434    else
435    {
436    // attach to sequence?!
437  95 try
438    {
439  95 if (!importPaeJSONAsContactMatrixToSequence(pdbAlignment, paeInput,
440    index, id, label))
441    {
442  0 Console.warn("Could not import contact matrix from '"
443    + pae.getAbsolutePath() + "' to sequence.");
444    }
445    } catch (IOException e1)
446    {
447  0 Console.error("Error when importing pAE file '"
448    + pae.getAbsolutePath() + "'", e1);
449    } catch (ParseException e2)
450    {
451  0 Console.error("Error when parsing pAE file '"
452    + pae.getAbsolutePath() + "'", e2);
453    }
454    }
455   
456    }
457   
 
458  0 toggle public static void addPAEToStructure(StructureSelectionManager ssm,
459    String structFilename, File pae, String label)
460    {
461  0 FileInputStream paeInput = null;
462  0 try
463    {
464  0 paeInput = new FileInputStream(pae);
465    } catch (FileNotFoundException e)
466    {
467  0 Console.error(
468    "Could not find pAE file '" + pae.getAbsolutePath() + "'", e);
469  0 return;
470    }
471  0 if (ssm == null)
472    {
473  0 ssm = StructureSelectionManager
474    .getStructureSelectionManager(Desktop.instance);
475    }
476  0 if (ssm != null)
477    {
478  0 StructureMapping[] smArray = ssm.getMapping(structFilename);
479   
480  0 try
481    {
482  0 if (!importPaeJSONAsContactMatrixToStructure(smArray, paeInput,
483    label))
484    {
485  0 Console.warn("Could not import contact matrix from '"
486    + pae.getAbsolutePath() + "' to structure.");
487    }
488    } catch (IOException e1)
489    {
490  0 Console.error("Error when importing pAE file '"
491    + pae.getAbsolutePath() + "'", e1);
492    } catch (ParseException e2)
493    {
494  0 Console.error("Error when parsing pAE file '"
495    + pae.getAbsolutePath() + "'", e2);
496    }
497    }
498    }
499   
500    /**
501    * parses the given pAE matrix and adds it to sequence 0 in the given
502    * alignment
503    *
504    * @param pdbAlignment
505    * @param pae_input
506    * @return true if there was a pAE matrix added
507    * @throws ParseException
508    * @throws IOException
509    * @throws Exception
510    */
 
511  95 toggle public static boolean importPaeJSONAsContactMatrixToSequence(
512    AlignmentI pdbAlignment, InputStream pae_input, int index,
513    String seqId, String label) throws IOException, ParseException
514    {
515  95 SequenceI sequence = null;
516  95 if (seqId == null)
517    {
518  95 int seqToGet = index > 0 ? index : 0;
519  95 sequence = pdbAlignment.getSequenceAt(seqToGet);
520    }
521  95 if (sequence == null)
522    {
523  0 SequenceI[] sequences = pdbAlignment.findSequenceMatch(seqId);
524  0 if (sequences == null || sequences.length < 1)
525    {
526  0 Console.warn("Could not find sequence with id '" + seqId
527    + "' to attach pAE matrix to. Ignoring matrix.");
528  0 return false;
529    }
530    else
531    {
532  0 sequence = sequences[0]; // just use the first sequence with this seqId
533    }
534    }
535  95 if (sequence == null)
536    {
537  0 return false;
538    }
539  95 return importPaeJSONAsContactMatrixToSequence(pdbAlignment, pae_input,
540    sequence, label);
541    }
542   
 
543  95 toggle public static boolean importPaeJSONAsContactMatrixToSequence(
544    AlignmentI pdbAlignment, InputStream pae_input,
545    SequenceI sequence, String label)
546    throws IOException, ParseException
547    {
548  95 JSONObject paeDict = parseJSONtoPAEContactMatrix(pae_input);
549  95 if (paeDict == null)
550    {
551  0 Console.debug("JSON file did not parse properly.");
552  0 return false;
553    }
554    // look up chains key, and resolve sequences in chains to the pdbAlignment sequences.
555    // loop over each one..
556   
557  95 ContactMatrixI matrix = new PAEContactMatrix(sequence, paeDict);
558   
559  95 AlignmentAnnotation cmannot = sequence.addContactList(matrix);
560  95 if (label != null)
561  0 cmannot.label = label;
562  95 pdbAlignment.addAnnotation(cmannot);
563   
564  95 return true;
565    }
566   
 
567  101 toggle public static JSONObject parseJSONtoPAEContactMatrix(
568    InputStream pae_input) throws IOException, ParseException
569    {
570  101 Object paeJson = Platform.parseJSON(pae_input);
571  101 JSONObject paeDict = null;
572  101 if (paeJson instanceof JSONObject)
573    {
574  20 paeDict = (JSONObject) paeJson;
575    }
576  81 else if (paeJson instanceof JSONArray)
577    {
578  81 JSONArray jsonArray = (JSONArray) paeJson;
579  81 if (jsonArray.size() > 0)
580  81 paeDict = (JSONObject) jsonArray.get(0);
581    }
582   
583  101 return paeDict;
584    }
585   
586    // ###### TEST THIS
 
587  3 toggle public static boolean importPaeJSONAsContactMatrixToStructure(
588    StructureMapping[] smArray, InputStream paeInput, String label)
589    throws IOException, ParseException
590    {
591  3 boolean someDone = false;
592  3 for (StructureMapping sm : smArray)
593    {
594  3 boolean thisDone = importPaeJSONAsContactMatrixToStructure(sm,
595    paeInput, label);
596  3 someDone |= thisDone;
597    }
598  3 return someDone;
599    }
600   
 
601  3 toggle public static boolean importPaeJSONAsContactMatrixToStructure(
602    StructureMapping sm, InputStream paeInput, String label)
603    throws IOException, ParseException
604    {
605  3 JSONObject pae_obj = parseJSONtoPAEContactMatrix(paeInput);
606  3 if (pae_obj == null)
607    {
608  0 Console.debug("JSON file did not parse properly.");
609  0 return false;
610    }
611   
612  3 SequenceI seq = sm.getSequence();
613  3 ContactMatrixI matrix = new PAEContactMatrix(seq, pae_obj);
614  3 AlignmentAnnotation cmannot = sm.getSequence().addContactList(matrix);
615    /* this already happens in Sequence.addContactList()
616    seq.addAlignmentAnnotation(cmannot);
617    */
618  3 return true;
619    }
620   
621    /**
622    * general purpose structure importer - designed to yield alignment useful for
623    * transfer of annotation to associated sequences
624    *
625    * @param alphaFoldCif
626    * @param tmpFile
627    * @param id
628    * @param chain
629    * @param dbSource
630    * @param dbVersion
631    * @return
632    * @throws Exception
633    */
 
634  0 toggle public static AlignmentI importDownloadedStructureFromUrl(
635    String alphaFoldCif, File tmpFile, String id, String chain,
636    String dbSource, String dbVersion) throws Exception
637    {
638  0 String file = tmpFile.getAbsolutePath();
639    // todo get rid of Type and use FileFormatI instead?
640  0 FileFormatI fileFormat = FileFormat.MMCif;
641  0 TFType tempfacType = TFType.PLDDT;
642  0 AlignmentI pdbAlignment = new FormatAdapter().readFile(tmpFile, file,
643    DataSourceType.FILE, fileFormat, tempfacType);
644   
645  0 if (pdbAlignment != null)
646    {
647  0 List<SequenceI> toremove = new ArrayList<SequenceI>();
648  0 for (SequenceI pdbcs : pdbAlignment.getSequences())
649    {
650  0 String chid = null;
651    // Mapping map=null;
652  0 for (PDBEntry pid : pdbcs.getAllPDBEntries())
653    {
654  0 if (pid.getFile() == file)
655    {
656  0 chid = pid.getChainCode();
657    }
658    }
659  0 if (chain == null || (chid != null && (chid.equals(chain)
660    || chid.trim().equals(chain.trim())
661    || (chain.trim().length() == 0 && chid.equals("_")))))
662    {
663    // FIXME seems to result in 'PDB|1QIP|1qip|A' - 1QIP is redundant.
664    // TODO: suggest simplify naming to 1qip|A as default name defined
665  0 pdbcs.setName(id + SEPARATOR + pdbcs.getName());
666    // Might need to add more metadata to the PDBEntry object
667    // like below
668    /*
669    * PDBEntry entry = new PDBEntry(); // Construct the PDBEntry
670    * entry.setId(id); if (entry.getProperty() == null)
671    * entry.setProperty(new Hashtable());
672    * entry.getProperty().put("chains", pdbchain.id + "=" +
673    * sq.getStart() + "-" + sq.getEnd());
674    * sq.getDatasetSequence().addPDBId(entry);
675    */
676    // Add PDB DB Refs
677    // We make a DBRefEtntry because we have obtained the PDB file from
678    // a
679    // verifiable source
680    // JBPNote - PDB DBRefEntry should also carry the chain and mapping
681    // information
682  0 if (dbSource != null)
683    {
684  0 DBRefEntry dbentry = new DBRefEntry(dbSource,
685   
686  0 dbVersion, (chid == null ? id : id + chid));
687    // dbentry.setMap()
688  0 pdbcs.addDBRef(dbentry);
689    // update any feature groups
690  0 List<SequenceFeature> allsf = pdbcs.getFeatures()
691    .getAllFeatures();
692  0 List<SequenceFeature> newsf = new ArrayList<SequenceFeature>();
693  0 if (allsf != null && allsf.size() > 0)
694    {
695  0 for (SequenceFeature f : allsf)
696    {
697  0 if (file.equals(f.getFeatureGroup()))
698    {
699  0 f = new SequenceFeature(f, f.type, f.begin, f.end, id,
700    f.score);
701    }
702  0 newsf.add(f);
703    }
704  0 pdbcs.setSequenceFeatures(newsf);
705    }
706    }
707    }
708    else
709    {
710    // mark this sequence to be removed from the alignment
711    // - since it's not from the right chain
712  0 toremove.add(pdbcs);
713    }
714    }
715    // now remove marked sequences
716  0 for (SequenceI pdbcs : toremove)
717    {
718  0 pdbAlignment.deleteSequence(pdbcs);
719  0 if (pdbcs.getAnnotation() != null)
720    {
721  0 for (AlignmentAnnotation aa : pdbcs.getAnnotation())
722    {
723  0 pdbAlignment.deleteAnnotation(aa);
724    }
725    }
726    }
727    }
728  0 return pdbAlignment;
729    }
730   
731    /*
732    * (non-Javadoc)
733    *
734    * @see jalview.ws.DbSourceProxy#isValidReference(java.lang.String)
735    */
 
736  0 toggle @Override
737    public boolean isValidReference(String accession)
738    {
739  0 Regex r = getAccessionValidator();
740  0 return r.search(accession.trim());
741    }
742   
743    /**
744    * human glyoxalase
745    */
 
746  0 toggle @Override
747    public String getTestQuery()
748    {
749  0 return "AF-O15552-F1";
750    }
751   
 
752  0 toggle @Override
753    public String getDbName()
754    {
755  0 return "ALPHAFOLD"; // getDbSource();
756    }
757   
 
758  0 toggle @Override
759    public int getTier()
760    {
761  0 return 0;
762    }
763   
764    /**
765    * Returns a descriptor for suitable feature display settings with
766    * <ul>
767    * <li>ResNums or insertions features visible</li>
768    * <li>insertions features coloured red</li>
769    * <li>ResNum features coloured by label</li>
770    * <li>Insertions displayed above (on top of) ResNums</li>
771    * </ul>
772    */
 
773  0 toggle @Override
774    public FeatureSettingsModelI getFeatureColourScheme()
775    {
776  0 return new PDBFeatureSettings();
777    }
778   
779    // days * 86400000
780    private static final long PAE_CACHE_STALE_TIME = 1 * 86400000;
781   
782    private static Map<String, File> paeDownloadCache = new HashMap<>();
783   
784    }