JAL-3829 select single best TDB structure and select structures from particular provi...
[jalview.git] / src / jalview / gui / structurechooser / TDBResultAnalyser.java
1 package jalview.gui.structurechooser;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.BitSet;
6 import java.util.Collection;
7 import java.util.Collections;
8 import java.util.Comparator;
9 import java.util.List;
10
11 import jalview.datamodel.SequenceI;
12 import jalview.fts.api.FTSData;
13 import jalview.fts.core.FTSRestRequest;
14
15 public class TDBResultAnalyser
16 {
17
18   /**
19    * model categories - update as needed. warnings output if unknown types
20    * encountered.
21    * 
22    * Order denotes 'trust'
23    */
24   private static List<String> EXP_CATEGORIES = Arrays
25           .asList(new String[]
26           { "EXPERIMENTALLY DETERMINED", "DEEP-LEARNING",
27               "TEMPLATE-BASED" });
28
29   private SequenceI seq;
30
31   private Collection<FTSData> collectedResults;
32
33   private FTSRestRequest lastTdbRequest;
34
35   private int idx_ups;
36
37   private int idx_upe;
38
39   private int idx_mcat;
40
41   private int idx_mqual;
42
43   private int idx_resol;
44
45   /**
46    * selection model
47    */
48   private String filter=null;
49   /**
50    * limit to particular source
51    */
52   private String sourceFilter=null;
53
54   private int idx_mprov;
55
56   public TDBResultAnalyser(SequenceI seq,
57           Collection<FTSData> collectedResults,
58           FTSRestRequest lastTdbRequest, String fieldToFilterBy, String string)
59   {
60     this.seq = seq;
61     this.collectedResults = collectedResults;
62     this.lastTdbRequest = lastTdbRequest;
63     this.filter = fieldToFilterBy;
64     this.sourceFilter = string;
65     idx_ups = lastTdbRequest.getFieldIndex("Uniprot Start");
66     idx_upe = lastTdbRequest.getFieldIndex("Uniprot End");
67     idx_mcat = lastTdbRequest.getFieldIndex("Model Category");
68     idx_mprov = lastTdbRequest.getFieldIndex("Provider");
69     idx_mqual = lastTdbRequest.getFieldIndex("Confidence");
70     idx_resol = lastTdbRequest.getFieldIndex("Resolution");
71   }
72   private final int scoreCategory(String cat)
73   {
74     // TODO: make quicker
75     int idx = EXP_CATEGORIES.indexOf(cat.toUpperCase());
76     if (idx == -1)
77     {
78       System.out.println("Unknown category: '" + cat + "'");
79     }
80     return -EXP_CATEGORIES.size() - idx;
81   }
82
83   /**
84    * sorts records discovered by 3D beacons and excludes any that don't
85    * intersect with the sequence's start/end rage
86    * 
87    * @return
88    */
89   public List<FTSData> getFilteredResponse()
90   {
91     List<FTSData> filteredResponse = new ArrayList<FTSData>();
92
93     // ignore anything outside the sequence region
94     for (FTSData row : collectedResults)
95     {
96       int up_s = (Integer) row.getSummaryData()[idx_ups];
97       int up_e = (Integer) row.getSummaryData()[idx_upe];
98       String provider = (String) row.getSummaryData()[idx_mprov];
99       if (sourceFilter == null ||  sourceFilter.equals(provider))
100       {
101         if (seq == row.getSummaryData()[0] && up_e > seq.getStart()
102                 && up_s < seq.getEnd())
103         {
104           filteredResponse.add(row);
105         }
106       }
107     }
108     // sort according to decreasing length,
109     // increasing start
110     Collections.sort(filteredResponse, new Comparator<FTSData>()
111     {
112       @Override
113       public int compare(FTSData o1, FTSData o2)
114       {
115         Object[] o1data = o1.getSummaryData();
116         Object[] o2data = o2.getSummaryData();
117         int o1_s = (Integer) o1data[idx_ups];
118         int o1_e = (Integer) o1data[idx_upe];
119         int o1_cat = scoreCategory((String) o1data[idx_mcat]);
120         int o2_s = (Integer) o2data[idx_ups];
121         int o2_e = (Integer) o2data[idx_upe];
122         int o2_cat = scoreCategory((String) o2data[idx_mcat]);
123
124         if (o1_cat == o2_cat)
125         {
126           if (o1_s == o2_s)
127           {
128             int o1_xtent = o1_e - o1_s;
129             int o2_xtent = o2_e - o2_s;
130             if (o1_xtent == o2_xtent)
131             {
132               if (o1_cat == scoreCategory(EXP_CATEGORIES.get(0)))
133               {
134                 // experimental structures, so rank on quality
135                 double o1_res = (Double) o1data[idx_resol];
136                 double o2_res = (Double) o2data[idx_resol];
137                 return (o2_res < o1_res) ? 1 : (o2_res == o1_res) ? 0 : -1;
138               }
139               else
140               {
141                 // models, so rank on qmean
142                 float o1_mq = (Float) o1data[idx_mqual];
143                 float o2_mq = (Float) o2data[idx_mqual];
144                 return (o2_mq < o1_mq) ? 1 : (o2_mq == o1_mq) ? 0 : -1;
145               }
146             }
147             else
148             {
149               return o1_xtent - o2_xtent;
150             }
151           }
152           else
153           {
154             return o1_s - o2_s;
155           }
156         }
157         else
158         {
159           return o2_cat - o1_cat;
160         }
161       }
162
163       @Override
164       public boolean equals(Object obj)
165       {
166         return super.equals(obj);
167       }
168     });
169     return filteredResponse;
170   }
171
172   /**
173    * return list of structures to be marked as selected for this sequence according to given criteria
174    * @param filteredStructures - sorted, filtered structures from getFilteredResponse
175    * 
176    */
177   public List<FTSData> selectStructures(List<FTSData> filteredStructures)
178   {
179     List<FTSData> selected = new ArrayList<FTSData>();
180     BitSet cover = new BitSet();
181     cover.set(seq.getStart(),seq.getEnd());
182     // walk down the list of structures, selecting some to add to selected
183     for (FTSData structure:filteredStructures)
184     {
185       Object[] odata=structure.getSummaryData();
186       int o1_s = (Integer) odata[idx_ups];
187       int o1_e = (Integer) odata[idx_upe];
188       int o1_cat = scoreCategory((String) odata[idx_mcat]);
189       BitSet scover = new BitSet();
190       // measure intersection
191       scover.set(o1_s,o1_e);
192       scover.and(cover);
193       if (scover.cardinality()>4)
194       {
195         selected.add(structure);
196         // clear the range covered by this structure
197         cover.andNot(scover); 
198       }
199     }
200     // final step is to sort on length - this might help the superposition process
201     Collections.sort(selected,new Comparator<FTSData>()
202     {
203       @Override
204       public int compare(FTSData o1, FTSData o2)
205       {
206         Object[] o1data = o1.getSummaryData();
207         Object[] o2data = o2.getSummaryData();
208         int o1_xt = ((Integer) o1data[idx_upe]) - ((Integer) o1data[idx_ups]);
209         int o1_cat = scoreCategory((String) o1data[idx_mcat]);
210         int o2_xt = ((Integer) o2data[idx_upe]-(Integer) o2data[idx_ups]);
211         int o2_cat = scoreCategory((String) o2data[idx_mcat]);
212         return o2_xt-o1_xt;
213       }
214     });
215     if (filter.equals(ThreeDBStructureChooserQuerySource.FILTER_FIRST_BEST_COVERAGE))
216     {
217       return selected.subList(0, 1);
218     }
219     return selected;
220   }
221
222 }