JAL-629 fix a PAEMatrix casting error
[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   @SuppressWarnings("unchecked")
33   public PAEContactMatrix(SequenceI _refSeq, Map<String, Object> pae_obj)
34   {
35     refSeq = _refSeq;
36     while (refSeq.getDatasetSequence() != null)
37     {
38       refSeq = refSeq.getDatasetSequence();
39     }
40     // convert the lists to primitive arrays and store
41     length = _refSeq.getEnd() - _refSeq.getStart() + 1;
42
43     if (!MapUtils.containsAKey(pae_obj, "predicted_aligned_error", "pae"))
44     {
45       parse_version_1_pAE(pae_obj);
46       return;
47     }
48     else
49     {
50       parse_version_2_pAE(pae_obj);
51     }
52   }
53
54   /**
55    * parse a sane JSON representation of the pAE
56    * 
57    * @param pae_obj
58    */
59   private void parse_version_2_pAE(Map<String, Object> pae_obj)
60   {
61     elements = new float[length][length];
62     // this is never going to be reached by the integer rounding.. or is it ?
63     maxscore = ((Double) MapUtils.getFirst(pae_obj,
64             "max_predicted_aligned_error", "max_pae")).floatValue();
65     Iterator<List<Long>> scoreRows = ((List<List<Long>>) MapUtils
66             .getFirst(pae_obj, "predicted_aligned_error", "pae"))
67             .iterator();
68     int row = 0, col = 0;
69     while (scoreRows.hasNext())
70     {
71       Iterator<Long> scores = scoreRows.next().iterator();
72       while (scores.hasNext())
73       {
74         Object d = scores.next();
75         if (d instanceof Double)
76           elements[row][col++] = ((Double) d).longValue();
77         else
78           elements[row][col++] = (float) d;
79       }
80       row++;
81       col = 0;
82     }
83     maxcol = length;
84     maxrow = length;
85   }
86
87   /**
88    * v1 format got ditched 28th July 2022 see
89    * https://alphafold.ebi.ac.uk/faq#:~:text=We%20updated%20the%20PAE%20JSON%20file%20format%20on%2028th%20July%202022
90    * 
91    * @param pae_obj
92    */
93   private void parse_version_1_pAE(Map<String, Object> pae_obj)
94   {
95     // assume indices are with respect to range defined by _refSeq on the
96     // dataset refSeq
97     Iterator<Long> rows = ((List<Long>) pae_obj.get("residue1")).iterator();
98     Iterator<Long> cols = ((List<Long>) pae_obj.get("residue2")).iterator();
99     Iterator<Double> scores = ((List<Double>) pae_obj.get("distance"))
100             .iterator();
101
102     elements = new float[length][length];
103     while (scores.hasNext())
104     {
105       float escore = scores.next().floatValue();
106       int row = rows.next().intValue();
107       int col = cols.next().intValue();
108       if (maxrow < row)
109       {
110         maxrow = row;
111       }
112       if (maxcol < col)
113       {
114         maxcol = col;
115       }
116       elements[row - 1][col - 1] = escore;
117     }
118
119     maxscore = ((Double) MapUtils.getFirst(pae_obj,
120             "max_predicted_aligned_error", "max_pae")).floatValue();
121   }
122
123   @Override
124   public ContactListI getContactList(final int _column)
125   {
126     if (_column < 0 || _column >= elements.length)
127     {
128       return null;
129     }
130
131     return new ContactListImpl(new ContactListProviderI()
132     {
133       @Override
134       public int getPosition()
135       {
136         return _column;
137       }
138
139       @Override
140       public int getContactHeight()
141       {
142         return maxcol - 1;
143       }
144
145       @Override
146       public double getContactAt(int column)
147       {
148         if (column < 0 || column >= elements[_column].length)
149         {
150           return -1;
151         }
152         // TODO Auto-generated method stub
153         return elements[_column][column];
154       }
155     });
156   }
157
158   @Override
159   public float getMin()
160   {
161     return 0;
162   }
163
164   @Override
165   public float getMax()
166   {
167     return maxscore;
168   }
169
170   @Override
171   public boolean hasReferenceSeq()
172   {
173     return (refSeq != null);
174   }
175
176   @Override
177   public SequenceI getReferenceSeq()
178   {
179     return refSeq;
180   }
181
182   @Override
183   public String getAnnotDescr()
184   {
185     return "Predicted Alignment Error for " + refSeq.getName();
186   }
187
188   @Override
189   public String getAnnotLabel()
190   {
191     return "pAE Matrix";
192   }
193 }