58a4a838fb0b1797478c09d4a5d1733b0cc21984
[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     
82   }
83
84   /**
85    * parse a sane JSON representation of the pAE
86    * 
87    * @param pae_obj
88    */
89   @SuppressWarnings("unchecked")
90   private void parse_version_2_pAE(Map<String, Object> pae_obj)
91   {
92     elements = new float[length][length];
93     // this is never going to be reached by the integer rounding.. or is it ?
94     maxscore = ((Double) MapUtils.getFirst(pae_obj,
95             "max_predicted_aligned_error", "max_pae")).floatValue();
96     Iterator<List<Long>> scoreRows = ((List<List<Long>>) MapUtils
97             .getFirst(pae_obj, "predicted_aligned_error", "pae"))
98             .iterator();
99     int row = 0, col = 0;
100     while (scoreRows.hasNext())
101     {
102       Iterator<Long> scores = scoreRows.next().iterator();
103       while (scores.hasNext())
104       {
105         elements[row][col++] = scores.next();
106       }
107       row++;
108       col = 0;
109     }
110     maxcol = length;
111     maxrow = length;
112   }
113
114   /**
115    * v1 format got ditched 28th July 2022 see
116    * https://alphafold.ebi.ac.uk/faq#:~:text=We%20updated%20the%20PAE%20JSON%20file%20format%20on%2028th%20July%202022
117    * 
118    * @param pae_obj
119    */
120   @SuppressWarnings("unchecked")
121   private void parse_version_1_pAE(Map<String, Object> pae_obj)
122   {
123     // assume indices are with respect to range defined by _refSeq on the
124     // dataset refSeq
125     Iterator<Long> rows = ((List<Long>) pae_obj.get("residue1")).iterator();
126     Iterator<Long> cols = ((List<Long>) pae_obj.get("residue2")).iterator();
127     Iterator<Double> scores = ((List<Double>) pae_obj.get("distance"))
128             .iterator();
129
130     elements = new float[length][length];
131     while (scores.hasNext())
132     {
133       float escore = scores.next().floatValue();
134       int row = rows.next().intValue();
135       int col = cols.next().intValue();
136       if (maxrow < row)
137       {
138         maxrow = row;
139       }
140       if (maxcol < col)
141       {
142         maxcol = col;
143       }
144       elements[row - 1][col - 1] = escore;
145     }
146
147     maxscore = ((Double) MapUtils.getFirst(pae_obj,
148             "max_predicted_aligned_error", "max_pae")).floatValue();
149   }
150
151   @Override
152   public ContactListI getContactList(final int _column)
153   {
154     if (_column < 0 || _column >= elements.length)
155     {
156       return null;
157     }
158
159     return new ContactListImpl(new ContactListProviderI()
160     {
161       @Override
162       public int getPosition()
163       {
164         return _column;
165       }
166
167       @Override
168       public int getContactHeight()
169       {
170         return maxcol - 1;
171       }
172
173       @Override
174       public double getContactAt(int column)
175       {
176         if (column < 0 || column >= elements[_column].length)
177         {
178           return -1;
179         }
180         return elements[_column][column];
181       }
182     });
183   }
184
185   @Override
186   public float getMin()
187   {
188     return 0;
189   }
190
191   @Override
192   public float getMax()
193   {
194     return maxscore;
195   }
196
197   @Override
198   public boolean hasReferenceSeq()
199   {
200     return (refSeq != null);
201   }
202
203   @Override
204   public SequenceI getReferenceSeq()
205   {
206     return refSeq;
207   }
208
209   @Override
210   public String getAnnotDescr()
211   {
212     return "Predicted Alignment Error for " + refSeq.getName();
213   }
214
215   @Override
216   public String getAnnotLabel()
217   {
218     return "pAE Matrix";
219   }
220
221   public static final String PAEMATRIX="PAE_MATRIX";
222   @Override
223   public String getType()
224   {
225     return PAEMATRIX;
226   }
227 }