Clover icon

Coverage Report

  1. Project Clover database Fri Jul 3 2026 14:09:54 BST
  2. Package jalview.ws.datamodel.alphafold

File PAEContactMatrix.java

 

Coverage histogram

../../../../img/srcFileCovDistChart9.png
13% of files have more coverage

Code metrics

28
80
15
1
318
220
32
0.4
5.33
15
2.13

Classes

Class Line # Actions
PAEContactMatrix 60 80 32
0.813008181.3%
 

Contributing tests

This file is covered by 59 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
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.
11    *
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.
16    *
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.
20    */
21    package jalview.ws.datamodel.alphafold;
22   
23    import java.io.File;
24    import java.io.FileInputStream;
25    import java.io.IOException;
26    import java.util.Iterator;
27    import java.util.List;
28    import java.util.Map;
29   
30    import org.json.simple.JSONObject;
31   
32    import jalview.datamodel.ContactListI;
33    import jalview.datamodel.ContactListImpl;
34    import jalview.datamodel.ContactListProviderI;
35    import jalview.datamodel.ContactMatrixI;
36    import jalview.datamodel.FloatContactMatrix;
37    import jalview.datamodel.GroupSet;
38    import jalview.datamodel.SequenceDummy;
39    import jalview.datamodel.SequenceI;
40    import jalview.io.FileFormatException;
41    import jalview.util.MapList;
42    import jalview.util.MapUtils;
43    import jalview.ws.dbsources.EBIAlfaFold;
44   
45    /**
46    * routines and class for holding predicted alignment error matrices as produced
47    * by alphafold et al.
48    *
49    * getContactList(column) returns the vector of predicted alignment errors for
50    * reference position given by column getElementAt(column, i) returns the
51    * predicted superposition error for the ith position when column is used as
52    * reference
53    *
54    * Many thanks to Ora Schueler Furman for noticing that earlier development
55    * versions did not show the PAE oriented correctly
56    *
57    * @author jprocter
58    *
59    */
 
60    public class PAEContactMatrix extends
61    MappableContactMatrix<PAEContactMatrix> implements ContactMatrixI
62    {
63   
 
64  110 toggle @SuppressWarnings("unchecked")
65    public PAEContactMatrix(SequenceI _refSeq, Map<String, Object> pae_obj)
66    throws FileFormatException
67    {
68  110 this(_refSeq, null, pae_obj);
69    }
70   
 
71  116 toggle @SuppressWarnings("unchecked")
72    public PAEContactMatrix(SequenceI _refSeq, MapList _toSeq, Map<String, Object> pae_obj)
73    throws FileFormatException {
74  116 setRefSeq(_refSeq);
75  116 if (_toSeq!=null) {
76  6 toSeq = _toSeq;
77    }
78    // convert the lists to primitive arrays and store
79   
80  116 if (!MapUtils.containsAKey(pae_obj, "predicted_aligned_error", "pae"))
81    {
82  2 parse_version_1_pAE(pae_obj);
83  2 return;
84    }
85    else
86    {
87  114 parse_version_2_pAE(pae_obj);
88    }
89    }
90   
91    /**
92    * construct a sequence associated PAE matrix directly from a float array
93    *
94    * @param _refSeq
95    * @param matrix
96    */
 
97  6 toggle public PAEContactMatrix(SequenceI _refSeq, float[][] matrix)
98    {
99  6 mappedMatrix = new FloatContactMatrix(matrix);
100  6 setRefSeq(_refSeq);
101    }
102   
103    /**
104    * new matrix with specific mapping to a reference sequence
105    *
106    * @param newRefSeq
107    * @param newFromMapList
108    * @param elements2
109    * @param grps2
110    */
 
111  1 toggle public PAEContactMatrix(SequenceI newRefSeq, MapList newFromMapList,
112    float[][] elements2, GroupSet grps2)
113    {
114  1 this(newRefSeq, new FloatContactMatrix(elements2, grps2));
115  1 toSeq = newFromMapList;
116    }
117   
 
118  1 toggle public PAEContactMatrix(SequenceI _refSeq,
119    ContactMatrixI floatContactMatrix)
120    {
121  1 mappedMatrix = floatContactMatrix;
122  1 setRefSeq(_refSeq);
123    }
124   
 
125  95 toggle public PAEContactMatrix(SequenceI _refSeq, MapList newFromMapList,
126    ContactMatrixI floatContactMatrix)
127    {
128  95 mappedMatrix = floatContactMatrix;
129  95 setRefSeq(_refSeq);
130  95 toSeq = newFromMapList;
131    }
132   
 
133  56 toggle @Override
134    protected PAEContactMatrix newMappableContactMatrix(SequenceI newRefSeq,
135    MapList newFromMapList)
136    {
137  56 return new PAEContactMatrix(newRefSeq, newFromMapList, mappedMatrix);
138    }
139   
140    /**
141    * parse a sane JSON representation of the pAE and update the mappedMatrix
142    *
143    * @param pae_obj
144    */
 
145  114 toggle @SuppressWarnings("unchecked")
146    private void parse_version_2_pAE(Map<String, Object> pae_obj)
147    {
148  114 float maxscore = -1;
149    // look for a maxscore element - if there is one...
150  114 try
151    {
152    // this is never going to be reached by the integer rounding.. or is it ?
153  114 maxscore = ((Double) MapUtils.getFirst(pae_obj,
154    "max_predicted_aligned_error", "max_pae")).floatValue();
155    } catch (Throwable t)
156    {
157    // ignore if a key is not found.
158    }
159  114 List<List<Long>> scoreRows = ((List<List<Long>>) MapUtils
160    .getFirst(pae_obj, "predicted_aligned_error", "pae"));
161  114 float[][] elements = new float[scoreRows.size()][scoreRows.size()];
162  114 int row = 0, col = 0;
163  114 for (List<Long> scoreRow : scoreRows)
164    {
165  21076 Iterator<Long> scores = scoreRow.iterator();
166  8857070 while (scores.hasNext())
167    {
168  8835994 Object d = scores.next();
169  8835994 if (d instanceof Double)
170    {
171  511149 elements[col][row] = ((Double) d).longValue();
172    }
173    else
174    {
175  8324845 elements[col][row] = (float) ((Long) d).longValue();
176    }
177   
178  8835994 if (maxscore < elements[col][row])
179    {
180  0 maxscore = elements[col][row];
181    }
182  8835994 col++;
183    }
184  21076 row++;
185  21076 col = 0;
186    }
187  114 mappedMatrix = new FloatContactMatrix(elements);
188    }
189   
190    /**
191    * v1 format got ditched 28th July 2022 see
192    * https://alphafold.ebi.ac.uk/faq#:~:text=We%20updated%20the%20PAE%20JSON%20file%20format%20on%2028th%20July%202022
193    *
194    * @param pae_obj
195    */
 
196  2 toggle @SuppressWarnings("unchecked")
197    private void parse_version_1_pAE(Map<String, Object> pae_obj)
198    {
199  2 if (pae_obj.containsKey("chains"))
200    {
201  0 Object chains = pae_obj.get("chains");
202    {
203   
204    }
205    }
206    // assume indices are with respect to range defined by _refSeq on the
207    // dataset refSeq
208  2 Iterator<Long> rows = ((List<Long>) pae_obj.get("residue1")).iterator();
209  2 Iterator<Long> cols = ((List<Long>) pae_obj.get("residue2")).iterator();
210    // two pass - to allocate the elements array
211   
212  2 int maxrow = -1, maxcol = -1;
213  6964 while (rows.hasNext())
214    {
215  6962 int row = rows.next().intValue();
216  6962 int col = cols.next().intValue();
217  6962 if (maxrow < row)
218    {
219  118 maxrow = row;
220    }
221  6962 if (maxcol < col)
222    {
223  118 maxcol = col;
224    }
225   
226    }
227  2 rows = ((List<Long>) pae_obj.get("residue1")).iterator();
228  2 cols = ((List<Long>) pae_obj.get("residue2")).iterator();
229  2 Iterator<Double> scores = ((List<Double>) pae_obj.get("distance"))
230    .iterator();
231  2 float[][] elements = new float[maxcol][maxrow];
232  6964 while (scores.hasNext())
233    {
234  6962 float escore = scores.next().floatValue();
235  6962 int row = rows.next().intValue();
236  6962 int col = cols.next().intValue();
237  6962 if (maxrow < row)
238    {
239  0 maxrow = row;
240    }
241  6962 if (maxcol < col)
242    {
243  0 maxcol = col;
244    }
245  6962 elements[col - 1][row - 1] = escore;
246    }
247   
248  2 mappedMatrix = new FloatContactMatrix(elements);
249    }
250   
 
251  120 toggle @Override
252    public String getAnnotDescr()
253    {
254  120 return "Predicted Alignment Error"
255  120 + ((refSeq == null) ? "" : (" for " + refSeq.getName()));
256    }
257   
 
258  120 toggle @Override
259    public String getAnnotLabel()
260    {
261  120 StringBuilder label = new StringBuilder("PAE Matrix");
262    // if (this.getReferenceSeq() != null)
263    // {
264    // label.append(":").append(this.getReferenceSeq().getDisplayId(false));
265    // }
266  120 return label.toString();
267    }
268   
269    public static final String PAEMATRIX = "PAE_MATRIX";
270   
 
271  265 toggle @Override
272    public String getType()
273    {
274  265 return PAEMATRIX;
275    }
276   
 
277  0 toggle public static void validateContactMatrixFile(String fileName)
278    throws FileFormatException, IOException
279    {
280  0 FileInputStream infile = null;
281  0 try
282    {
283  0 infile = new FileInputStream(new File(fileName));
284    } catch (Throwable t)
285    {
286  0 new IOException("Couldn't open " + fileName, t);
287    }
288  0 JSONObject paeDict = null;
289  0 try
290    {
291  0 paeDict = EBIAlfaFold.parseJSONtoPAEContactMatrix(infile);
292    } catch (Throwable t)
293    {
294  0 new FileFormatException("Couldn't parse " + fileName
295    + " as a JSON dict or array containing a dict");
296    }
297   
298  0 PAEContactMatrix matrix = new PAEContactMatrix(
299    new SequenceDummy("Predicted"), (Map<String, Object>) paeDict);
300  0 if (matrix.getWidth() <= 0)
301    {
302  0 throw new FileFormatException(
303    "No data in PAE matrix read from '" + fileName + "'");
304    }
305    }
306   
 
307  28 toggle @Override
308    public boolean equals(Object obj)
309    {
310  28 return super.equals(obj);
311    }
312   
 
313  120 toggle @Override
314    public int hashCode()
315    {
316  120 return super.hashCode();
317    }
318    }