Merge branch 'features/r2_11_2_alphafold/JAL-629' into features/JAL-3858_PAEsInProjects
[jalview.git] / src / jalview / ws / datamodel / alphafold / PAEContactMatrix.java
1 package jalview.ws.datamodel.alphafold;
2
3 import java.util.Iterator;
4 import java.util.List;
5 import java.util.Map;
6
7 import jalview.datamodel.ContactListI;
8 import jalview.datamodel.ContactListImpl;
9 import jalview.datamodel.ContactListProviderI;
10 import jalview.datamodel.ContactMatrixI;
11 import jalview.datamodel.SequenceI;
12 import jalview.util.MapUtils;
13
14 public class PAEContactMatrix implements ContactMatrixI
15 {
16
17   SequenceI refSeq = null;
18
19   /**
20    * the length that refSeq is expected to be (excluding gaps, of course)
21    */
22   int length;
23
24   int maxrow = 0, maxcol = 0;
25
26   int[] indices1, indices2;
27
28   float[][] elements;
29
30   float maxscore;
31
32   private void setRefSeq(SequenceI _refSeq)
33   {
34     refSeq = _refSeq;
35     while (refSeq.getDatasetSequence() != null)
36     {
37       refSeq = refSeq.getDatasetSequence();
38     }
39     length = _refSeq.getEnd() - _refSeq.getStart() + 1;
40   }
41   @SuppressWarnings("unchecked")
42   public PAEContactMatrix(SequenceI _refSeq, Map<String, Object> pae_obj)
43   {
44     setRefSeq(_refSeq);
45     // convert the lists to primitive arrays and store
46     
47     if (!MapUtils.containsAKey(pae_obj, "predicted_aligned_error", "pae"))
48     {
49       parse_version_1_pAE(pae_obj);
50       return;
51     }
52     else
53     {
54       parse_version_2_pAE(pae_obj);
55     }
56   }
57   /**
58    * construct a sequence associated PAE matrix directly from a float array
59    * @param _refSeq
60    * @param matrix
61    */
62   public PAEContactMatrix(SequenceI _refSeq, float[][] matrix)
63   {
64     setRefSeq(_refSeq);
65     maxcol=0;
66     for (float[] row:matrix)
67     {
68       if (row.length>maxcol)
69       {
70         maxcol=row.length;
71       }
72       maxscore=row[0];
73       for (float f:row)
74       {
75         if (maxscore<f) {
76           maxscore=f;
77         }
78       }
79     }
80     maxrow=matrix.length;
81     elements = matrix;
82     
83   }
84
85   /**
86    * parse a sane JSON representation of the pAE
87    * 
88    * @param pae_obj
89    */
90   @SuppressWarnings("unchecked")
91   private void parse_version_2_pAE(Map<String, Object> pae_obj)
92   {
93     elements = new float[length][length];
94     // this is never going to be reached by the integer rounding.. or is it ?
95     maxscore = ((Double) MapUtils.getFirst(pae_obj,
96             "max_predicted_aligned_error", "max_pae")).floatValue();
97     Iterator<List<Long>> scoreRows = ((List<List<Long>>) MapUtils
98             .getFirst(pae_obj, "predicted_aligned_error", "pae"))
99             .iterator();
100     int row = 0, col = 0;
101     while (scoreRows.hasNext())
102     {
103       Iterator<Long> scores = scoreRows.next().iterator();
104       while (scores.hasNext())
105       {
106         Object d = scores.next();
107         if (d instanceof Double)
108           elements[row][col++] = ((Double) d).longValue();
109         else
110           elements[row][col++] = (float) d;
111       }
112       row++;
113       col = 0;
114     }
115     maxcol = length;
116     maxrow = length;
117   }
118
119   /**
120    * v1 format got ditched 28th July 2022 see
121    * https://alphafold.ebi.ac.uk/faq#:~:text=We%20updated%20the%20PAE%20JSON%20file%20format%20on%2028th%20July%202022
122    * 
123    * @param pae_obj
124    */
125   @SuppressWarnings("unchecked")
126   private void parse_version_1_pAE(Map<String, Object> pae_obj)
127   {
128     // assume indices are with respect to range defined by _refSeq on the
129     // dataset refSeq
130     Iterator<Long> rows = ((List<Long>) pae_obj.get("residue1")).iterator();
131     Iterator<Long> cols = ((List<Long>) pae_obj.get("residue2")).iterator();
132     Iterator<Double> scores = ((List<Double>) pae_obj.get("distance"))
133             .iterator();
134
135     elements = new float[length][length];
136     while (scores.hasNext())
137     {
138       float escore = scores.next().floatValue();
139       int row = rows.next().intValue();
140       int col = cols.next().intValue();
141       if (maxrow < row)
142       {
143         maxrow = row;
144       }
145       if (maxcol < col)
146       {
147         maxcol = col;
148       }
149       elements[row - 1][col - 1] = escore;
150     }
151
152     maxscore = ((Double) MapUtils.getFirst(pae_obj,
153             "max_predicted_aligned_error", "max_pae")).floatValue();
154   }
155
156   @Override
157   public ContactListI getContactList(final int _column)
158   {
159     if (_column < 0 || _column >= elements.length)
160     {
161       return null;
162     }
163
164     return new ContactListImpl(new ContactListProviderI()
165     {
166       @Override
167       public int getPosition()
168       {
169         return _column;
170       }
171
172       @Override
173       public int getContactHeight()
174       {
175         return maxcol-1;
176       }
177
178       @Override
179       public double getContactAt(int column)
180       {
181         if (column < 0 || column >= elements[_column].length)
182         {
183           return -1;
184         }
185         return elements[_column][column];
186       }
187     });
188   }
189
190   @Override
191   public float getMin()
192   {
193     return 0;
194   }
195
196   @Override
197   public float getMax()
198   {
199     return maxscore;
200   }
201
202   @Override
203   public boolean hasReferenceSeq()
204   {
205     return (refSeq != null);
206   }
207
208   @Override
209   public SequenceI getReferenceSeq()
210   {
211     return refSeq;
212   }
213
214   @Override
215   public String getAnnotDescr()
216   {
217     return "Predicted Alignment Error for " + refSeq.getName();
218   }
219
220   @Override
221   public String getAnnotLabel()
222   {
223     return "pAE Matrix";
224   }
225
226   public static final String PAEMATRIX="PAE_MATRIX";
227   @Override
228   public String getType()
229   {
230     return PAEMATRIX;
231   }
232   @Override
233   public int getWidth()
234   {
235     return length;
236   }
237   @Override
238   public int getHeight()
239   {
240     return length;
241   }
242 }