001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021package org.biojava.nbio.structure.align.quaternary; 022 023import java.util.ArrayList; 024import java.util.Collections; 025import java.util.List; 026import java.util.Map; 027import java.util.stream.Collectors; 028 029import javax.vecmath.Matrix4d; 030 031import org.biojava.nbio.structure.Atom; 032import org.biojava.nbio.structure.align.multiple.MultipleAlignment; 033import org.biojava.nbio.structure.align.multiple.util.MultipleAlignmentScorer; 034import org.biojava.nbio.structure.cluster.Subunit; 035import org.biojava.nbio.structure.cluster.SubunitCluster; 036 037/** 038 * Result of a Quaternary Structure Alignment {@link QsAlign}. The QsAlignResult 039 * holds the original inputs of the algorithm and the results and scores of the 040 * alignment. 041 * 042 * @author Aleix Lafita 043 * @since 5.0.0 044 * 045 */ 046public class QsAlignResult { 047 048 private List<SubunitCluster> clusters; 049 050 private List<Subunit> subunits1; 051 private List<Subunit> subunits2; 052 053 private Map<Integer, Integer> subunitMap; 054 private MultipleAlignment alignment; 055 056 private QsRelation relation; 057 058 /** 059 * The Constructor of the result takes the same inputs as the 060 * {@link QsAlign} algorithm. 061 * 062 * @param subunits1 063 * @param subunits2 064 */ 065 public QsAlignResult(List<Subunit> subunits1, List<Subunit> subunits2) { 066 067 this.subunits1 = subunits1; 068 this.subunits2 = subunits2; 069 070 subunitMap = Collections.emptyMap(); 071 relation = QsRelation.DIFFERENT; 072 073 } 074 075 /** 076 * Original Subunits of the first group. 077 * 078 * @return an unmodifiable view of the original List 079 */ 080 public List<Subunit> getSubunits1() { 081 return Collections.unmodifiableList(subunits1); 082 } 083 084 /** 085 * Original Subunits of the second group. 086 * 087 * @return an unmodifiable view of the original List 088 */ 089 public List<Subunit> getSubunits2() { 090 return Collections.unmodifiableList(subunits2); 091 } 092 093 /** 094 * Map of Subunit equivalencies from the first to the second group. 095 * 096 * @return an unmodifiable view of the original Map 097 */ 098 public Map<Integer, Integer> getSubunitMap() { 099 100 if (subunitMap == null) 101 return Collections.emptyMap(); 102 103 return Collections.unmodifiableMap(subunitMap); 104 } 105 106 /** 107 * Map of Subunit equivalencies from the first to the second group. 108 * 109 * @param subunitMap 110 */ 111 public void setSubunitMap(Map<Integer, Integer> subunitMap) { 112 113 // Check consistency of the map 114 if (Collections.max(subunitMap.keySet()) > subunits1.size() 115 | Collections.max(subunitMap.values()) > subunits2.size()) 116 throw new IndexOutOfBoundsException( 117 "Subunit Map index higher than Subunit List size."); 118 119 // Update the relation enum 120 if (subunitMap.size() == 0) { 121 relation = QsRelation.DIFFERENT; 122 } else if (subunitMap.keySet().size() == subunits1.size()) { 123 if (subunitMap.values().size() == subunits2.size()) { 124 relation = QsRelation.EQUIVALENT; 125 } else { 126 relation = QsRelation.PARTIAL_COMPLETE; 127 } 128 } else { 129 if (subunitMap.values().size() == subunits2.size()) { 130 relation = QsRelation.PARTIAL_COMPLETE; 131 } else { 132 relation = QsRelation.PARTIAL_INCOMPLETE; 133 } 134 } 135 136 this.subunitMap = subunitMap; 137 } 138 139 /** 140 * The length of the alignment is the number of Subunit equivalencies it 141 * contains. This is equivalent to the size of the Subunit Map. 142 * 143 * @return length of the alignment 144 */ 145 public int length() { 146 if (subunitMap == null) 147 return 0; 148 149 return subunitMap.size(); 150 } 151 152 /** 153 * The transformation 4D matrix that needs to be applied to the second group 154 * of Subunits to superimpose them onto the first group of Subunits, given 155 * the equivalent residues in the SubunitCluster and the Subunit 156 * equivalencies. 157 * <p> 158 * This is equivalent to 159 * multipleAlignment.getBlockSet(0).getTransformations().get(1). 160 * 161 * @return Matrix4d 162 */ 163 public Matrix4d getTransform() { 164 165 if (alignment == null) 166 return null; 167 168 return alignment.getBlockSet(0).getTransformations().get(1); 169 } 170 171 /** 172 * The RMSD between the equivalent residues of the equivalent Subunits after 173 * superposition of the Subunit groups. This is equivalent to 174 * multipleAlignment.getScore(MultipleAlignmentScorer.RMSD). 175 * 176 * @return rmsd 177 */ 178 public double getRmsd() { 179 180 if (alignment == null) 181 return -1.0; 182 if (alignment.getScore(MultipleAlignmentScorer.RMSD) == null) 183 return MultipleAlignmentScorer.getRMSD(alignment); 184 185 return alignment.getScore(MultipleAlignmentScorer.RMSD); 186 } 187 188 /** 189 * The quaternary structure relation {@link QsRelation} between the two 190 * groups of Subunits. 191 * 192 * @return relation 193 */ 194 public QsRelation getRelation() { 195 return relation; 196 } 197 198 /** 199 * The quaternary structure relation {@link QsRelation} between the two 200 * groups of Subunits. 201 * 202 * @param relation 203 */ 204 public void setRelation(QsRelation relation) { 205 this.relation = relation; 206 } 207 208 /** 209 * The alignment that specifies the residue equivalencies of the equivalent 210 * Subunits. 211 * 212 * @return alignment as a MultipleAlignment object 213 */ 214 public MultipleAlignment getAlignment() { 215 return alignment; 216 } 217 218 /** 219 * The alignment that specifies the residue equivalencies of the equivalent 220 * Subunits. 221 * 222 * @param alignment 223 * a MultipleAlignment object 224 */ 225 public void setAlignment(MultipleAlignment alignment) { 226 this.alignment = alignment; 227 } 228 229 /** 230 * Return the aligned subunits of the first Subunit group, in the alignment 231 * order. 232 * 233 * @return a List of Subunits in the alignment order 234 */ 235 public List<Subunit> getAlignedSubunits1() { 236 237 List<Subunit> aligned = new ArrayList<Subunit>(subunitMap.size()); 238 239 for (Integer key : subunitMap.keySet()) 240 aligned.add(subunits1.get(key)); 241 242 return aligned; 243 } 244 245 /** 246 * Return the aligned subunits of the second Subunit group, in the alignment 247 * order. 248 * 249 * @return a List of Subunits in the alignment order 250 */ 251 public List<Subunit> getAlignedSubunits2() { 252 253 List<Subunit> aligned = new ArrayList<Subunit>(subunitMap.size()); 254 255 for (Integer key : subunitMap.keySet()) 256 aligned.add(subunits2.get(subunitMap.get(key))); 257 258 return aligned; 259 } 260 261 public void setClusters(List<SubunitCluster> clusters) { 262 this.clusters = clusters; 263 } 264 265 public Atom[] getAlignedAtomsForSubunits1(int index) { 266 267 // Obtain the indices of the clustered subunits 268 for (SubunitCluster cluster : clusters) { 269 if (cluster.getSubunits().contains(subunits1.get(index))) { 270 return cluster.getAlignedAtomsSubunit(cluster.getSubunits() 271 .indexOf(subunits1.get(index))); 272 } 273 } 274 return null; 275 } 276 277 public Atom[] getAlignedAtomsForSubunits2(int index) { 278 279 // Obtain the indices of the clustered subunits 280 for (SubunitCluster cluster : clusters) { 281 if (cluster.getSubunits().contains(subunits2.get(index))) { 282 return cluster.getAlignedAtomsSubunit(cluster.getSubunits() 283 .indexOf(subunits2.get(index))); 284 } 285 } 286 return null; 287 } 288 289 @Override 290 public String toString() { 291 return "QsAlignResult [relation=" 292 + relation 293 + ", rmsd=" 294 + getRmsd() 295 + ", length=" 296 + length() 297 + ", Aligned 1: " 298 + getAlignedSubunits1().stream().map(s -> s.getName()) 299 .collect(Collectors.toList()) 300 + ", Aligned 2: " 301 + getAlignedSubunits2().stream().map(s -> s.getName()) 302 .collect(Collectors.toList()) + "]"; 303 } 304 305}