272d21d1f8d766fca9a3d50fb9da324bc05e8f62
[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         elements[row][col++] = scores.next();
75       }
76       row++;
77       col = 0;
78     }
79     maxcol = length;
80     maxrow = length;
81   }
82
83   /**
84    * v1 format got ditched 28th July 2022 see
85    * https://alphafold.ebi.ac.uk/faq#:~:text=We%20updated%20the%20PAE%20JSON%20file%20format%20on%2028th%20July%202022
86    * 
87    * @param pae_obj
88    */
89   private void parse_version_1_pAE(Map<String, Object> pae_obj)
90   {
91     // assume indices are with respect to range defined by _refSeq on the
92     // dataset refSeq
93     Iterator<Long> rows = ((List<Long>) pae_obj.get("residue1")).iterator();
94     Iterator<Long> cols = ((List<Long>) pae_obj.get("residue2")).iterator();
95     Iterator<Double> scores = ((List<Double>) pae_obj.get("distance"))
96             .iterator();
97
98     elements = new float[length][length];
99     while (scores.hasNext())
100     {
101       float escore = scores.next().floatValue();
102       int row = rows.next().intValue();
103       int col = cols.next().intValue();
104       if (maxrow < row)
105       {
106         maxrow = row;
107       }
108       if (maxcol < col)
109       {
110         maxcol = col;
111       }
112       elements[row - 1][col - 1] = escore;
113     }
114
115     maxscore = ((Double) MapUtils.getFirst(pae_obj,
116             "max_predicted_aligned_error", "max_pae")).floatValue();
117   }
118
119   @Override
120   public ContactListI getContactList(final int _column)
121   {
122     if (_column < 0 || _column >= elements.length)
123     {
124       return null;
125     }
126
127     return new ContactListImpl(new ContactListProviderI()
128     {
129       @Override
130       public int getPosition()
131       {
132         return _column;
133       }
134
135       @Override
136       public int getContactHeight()
137       {
138         return maxcol - 1;
139       }
140
141       @Override
142       public double getContactAt(int column)
143       {
144         if (column < 0 || column >= elements[_column].length)
145         {
146           return -1;
147         }
148         // TODO Auto-generated method stub
149         return elements[_column][column];
150       }
151     });
152   }
153
154   @Override
155   public float getMin()
156   {
157     return 0;
158   }
159
160   @Override
161   public float getMax()
162   {
163     return maxscore;
164   }
165
166   @Override
167   public boolean hasReferenceSeq()
168   {
169     return (refSeq != null);
170   }
171
172   @Override
173   public SequenceI getReferenceSeq()
174   {
175     return refSeq;
176   }
177
178   @Override
179   public String getAnnotDescr()
180   {
181     return "Predicted Alignment Error for " + refSeq.getName();
182   }
183
184   @Override
185   public String getAnnotLabel()
186   {
187     return "pAE Matrix";
188   }
189 }