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.multiple; 022 023import java.io.IOException; 024import java.io.Serializable; 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.List; 028 029import javax.vecmath.Matrix4d; 030 031import org.biojava.nbio.structure.Atom; 032import org.biojava.nbio.structure.Calc; 033import org.biojava.nbio.structure.StructureException; 034import org.biojava.nbio.structure.StructureIdentifier; 035import org.biojava.nbio.structure.align.client.StructureName; 036import org.biojava.nbio.structure.align.helper.AlignUtils; 037import org.biojava.nbio.structure.align.model.AFPChain; 038import org.biojava.nbio.structure.align.multiple.util.MultipleAlignmentScorer; 039import org.biojava.nbio.structure.align.util.AtomCache; 040import org.biojava.nbio.structure.jama.Matrix; 041 042/** 043 * A general implementation of a {@link MultipleAlignmentEnsemble}. 044 * 045 * @author Aleix Lafita 046 * @since 4.1.0 047 * 048 */ 049public class MultipleAlignmentEnsembleImpl extends AbstractScoresCache 050 implements MultipleAlignmentEnsemble, Serializable, Cloneable { 051 052 private static final long serialVersionUID = -5732485866623431898L; 053 054 // Creation Properties 055 private String algorithmName; 056 private String version; 057 private Long ioTime; 058 private Long calculationTime; 059 060 // Structure Identifiers 061 private List<StructureIdentifier> structureIdentifiers; 062 private List<Atom[]> atomArrays; 063 private List<Matrix> distanceMatrix; 064 065 private List<MultipleAlignment> multipleAlignments; 066 067 /** 068 * Default Constructor. Empty ensemble, no structures assigned. 069 * 070 * @return MultipleAlignmentEnsemble an empty ensemble instance. 071 */ 072 public MultipleAlignmentEnsembleImpl() { 073 074 algorithmName = null; 075 version = null; 076 ioTime = null; 077 calculationTime = null; 078 079 structureIdentifiers = null; 080 atomArrays = null; 081 distanceMatrix = null; 082 multipleAlignments = null; 083 } 084 085 /** 086 * Constructor using structure identifiers. 087 * 088 * @param structureIdentifiers 089 * List of Structure names, that can be parsed by 090 * {@link AtomCache}. 091 * @return MultipleAlignmentEnsemble an ensemble with the structures. 092 */ 093 public MultipleAlignmentEnsembleImpl( 094 List<StructureIdentifier> structureIdentifiers) { 095 this(); 096 setStructureIdentifiers(structureIdentifiers); 097 } 098 099 /** 100 * Copy constructor. This copies recursively all member variables, including 101 * MultipleAlignments, Atom arrays and cached variables. 102 * 103 * @param e 104 * MultipleAlignmentEnsemble to copy. 105 * @return MultipleAlignmentEnsemble identical copy of the input ensemble. 106 */ 107 public MultipleAlignmentEnsembleImpl(MultipleAlignmentEnsembleImpl e) { 108 109 super(e); // Copy the scores 110 algorithmName = e.algorithmName; 111 version = e.version; 112 ioTime = e.ioTime; 113 calculationTime = e.calculationTime; 114 115 distanceMatrix = null; 116 if (e.distanceMatrix != null) { 117 // Make a deep copy of everything 118 distanceMatrix = new ArrayList<Matrix>(); 119 for (Matrix mat : e.distanceMatrix) { 120 distanceMatrix.add((Matrix) mat.clone()); 121 } 122 } 123 124 multipleAlignments = null; 125 if (e.multipleAlignments != null) { 126 // Make a deep copy of everything 127 multipleAlignments = new ArrayList<MultipleAlignment>(); 128 for (MultipleAlignment msa : e.multipleAlignments) { 129 MultipleAlignment newMSA = msa.clone(); 130 newMSA.setEnsemble(this); 131 multipleAlignments.add(newMSA); 132 } 133 } 134 135 if (e.atomArrays != null) { 136 atomArrays = new ArrayList<Atom[]>(e.atomArrays); 137 } 138 if (e.structureIdentifiers != null) { 139 structureIdentifiers = new ArrayList<StructureIdentifier>( 140 e.structureIdentifiers); 141 } 142 } 143 144 /** 145 * Constructor from an AFPChain instance. Creates an equivalent pairwise 146 * alignment, but in the MultipleAlignment format. 147 * 148 * @param afp 149 * pairwise alignment 150 * @param ca1 151 * Atoms of the first strcuture 152 * @param ca2 153 * Atoms of the second structure 154 * @param flexible 155 * true if the alignment is flexible (use BlockSets) 156 * @return MultipleAlignmentEnsemble an ensemble 157 */ 158 public MultipleAlignmentEnsembleImpl(AFPChain afp, Atom[] ca1, Atom[] ca2, 159 boolean flexible) { 160 161 this(); 162 // Copy all the creation and algorithm information 163 atomArrays = Arrays.asList(ca1, ca2); 164 if (afp.getName1() != null && !afp.getName1().isEmpty() && 165 afp.getName2() != null && !afp.getName2().isEmpty()) { 166 structureIdentifiers = Arrays.<StructureIdentifier> asList( 167 new StructureName(afp.getName1()), 168 new StructureName(afp.getName2())); 169 } 170 algorithmName = afp.getAlgorithmName(); 171 version = afp.getVersion(); 172 calculationTime = afp.getCalculationTime(); 173 174 MultipleAlignment msa = new MultipleAlignmentImpl(this); 175 setMultipleAlignments(Arrays.asList(msa)); 176 177 // Convert the rotation and translation to a Matrix4D and set it 178 Matrix4d ident = new Matrix4d(); 179 ident.setIdentity(); 180 Matrix[] rot = afp.getBlockRotationMatrix(); 181 Atom[] shift = afp.getBlockShiftVector(); 182 183 // Create a BlockSet for every block in AFPChain if flexible 184 if (flexible) { 185 for (int bs = 0; bs < afp.getBlockNum(); bs++) { 186 BlockSet blockSet = new BlockSetImpl(msa); 187 Matrix4d blockTr = null; 188 try { 189 blockTr = Calc.getTransformation(rot[bs], shift[bs]); 190 } catch (IndexOutOfBoundsException e) { 191 blockTr = ident; 192 } catch (NullPointerException e) { 193 blockTr = ident; 194 } 195 blockSet.setTransformations(Arrays.asList(ident, blockTr)); 196 Block block = new BlockImpl(blockSet); 197 block.setAlignRes(new ArrayList<List<Integer>>()); 198 block.getAlignRes().add(new ArrayList<Integer>()); 199 block.getAlignRes().add(new ArrayList<Integer>()); 200 201 // Set the transformation of the BlockSet 202 Matrix rotB = afp.getBlockRotationMatrix()[bs]; 203 Atom shiftB = afp.getBlockShiftVector()[bs]; 204 Matrix4d transformB = Calc.getTransformation(rotB, shiftB); 205 blockSet.setTransformations(Arrays.asList(ident, transformB)); 206 207 // Convert the optimal alignment to a Block 208 for (int i = 0; i < afp.getOptAln()[bs][0].length; i++) { 209 block.getAlignRes().get(0).add(afp.getOptAln()[bs][0][i]); 210 block.getAlignRes().get(1).add(afp.getOptAln()[bs][1][i]); 211 } 212 } 213 } // Create a Block for every block in AFPChain if not flexible 214 else { 215 BlockSet blockSet = new BlockSetImpl(msa); 216 Matrix4d blockTr = null; 217 try { 218 blockTr = Calc.getTransformation(rot[0], shift[0]); 219 } catch (IndexOutOfBoundsException e) { 220 blockTr = ident; 221 } catch (NullPointerException e) { 222 blockTr = ident; 223 } 224 blockSet.setTransformations(Arrays.asList(ident, blockTr)); 225 for (int bs = 0; bs < afp.getBlockNum(); bs++) { 226 Block block = new BlockImpl(blockSet); 227 block.setAlignRes(new ArrayList<List<Integer>>()); 228 block.getAlignRes().add(new ArrayList<Integer>()); 229 block.getAlignRes().add(new ArrayList<Integer>()); 230 231 // Convert the optimal alignment to a Block 232 for (int i = 0; i < afp.getOptAln()[bs][0].length; i++) { 233 block.getAlignRes().get(0).add(afp.getOptAln()[bs][0][i]); 234 block.getAlignRes().get(1).add(afp.getOptAln()[bs][1][i]); 235 } 236 } 237 } 238 239 // Copy the scores stored in the AFPChain 240 msa.putScore(MultipleAlignmentScorer.PROBABILITY, afp.getProbability()); 241 msa.putScore(MultipleAlignmentScorer.AVGTM_SCORE, afp.getTMScore()); 242 msa.putScore(MultipleAlignmentScorer.CE_SCORE, afp.getAlignScore()); 243 msa.putScore(MultipleAlignmentScorer.RMSD, afp.getTotalRmsdOpt()); 244 } 245 246 @Override 247 public MultipleAlignmentEnsembleImpl clone() { 248 return new MultipleAlignmentEnsembleImpl(this); 249 } 250 251 @Override 252 public String getAlgorithmName() { 253 return algorithmName; 254 } 255 256 @Override 257 public void setAlgorithmName(String algorithmName) { 258 this.algorithmName = algorithmName; 259 } 260 261 @Override 262 public String getVersion() { 263 return version; 264 } 265 266 @Override 267 public void setVersion(String version) { 268 this.version = version; 269 } 270 271 @Override 272 public Long getIoTime() { 273 return ioTime; 274 } 275 276 @Override 277 public void setIoTime(Long millis) { 278 this.ioTime = millis; 279 } 280 281 @Override 282 public Long getCalculationTime() { 283 return calculationTime; 284 } 285 286 @Override 287 public void setCalculationTime(Long millis) { 288 this.calculationTime = millis; 289 } 290 291 @Override 292 public List<StructureIdentifier> getStructureIdentifiers() { 293 return structureIdentifiers; 294 } 295 296 @Override 297 public void setStructureIdentifiers(List<StructureIdentifier> structureNames) { 298 this.structureIdentifiers = structureNames; 299 } 300 301 @Override 302 public List<Atom[]> getAtomArrays() { 303 if (atomArrays == null) { 304 try { 305 updateAtomArrays(); 306 } catch (IOException e) { 307 throw new NullPointerException(e.getMessage()); 308 } catch (StructureException e) { 309 throw new NullPointerException(e.getMessage()); 310 } 311 } 312 return atomArrays; 313 } 314 315 @Override 316 public void setAtomArrays(List<Atom[]> atomArrays) { 317 this.atomArrays = atomArrays; 318 } 319 320 /** 321 * Force the atom arrays to regenerate based on 322 * {@link #getStructureIdentifiers()}. 323 * 324 * @throws IOException 325 * @throws StructureException 326 */ 327 public void updateAtomArrays() throws IOException, StructureException { 328 AtomCache cache = new AtomCache(); 329 atomArrays = new ArrayList<Atom[]>(); 330 for (StructureIdentifier name : getStructureIdentifiers()) { 331 Atom[] array = cache.getRepresentativeAtoms(name); 332 atomArrays.add(array); 333 } 334 } 335 336 @Override 337 public List<Matrix> getDistanceMatrix() { 338 if (distanceMatrix == null) 339 updateDistanceMatrix(); 340 return distanceMatrix; 341 } 342 343 /** 344 * Force recalculation of the distance matrices. 345 */ 346 public void updateDistanceMatrix() { 347 348 // Reset the distance Matrix variable 349 distanceMatrix = new ArrayList<Matrix>(); 350 351 for (int s = 0; s < size(); s++) { 352 Atom[] ca = atomArrays.get(s); 353 Matrix distMat = AlignUtils.getDistanceMatrix(ca, ca); 354 distanceMatrix.add(distMat); 355 } 356 } 357 358 @Override 359 public List<MultipleAlignment> getMultipleAlignments() { 360 361 if (multipleAlignments == null) { 362 multipleAlignments = new ArrayList<MultipleAlignment>(); 363 } 364 return multipleAlignments; 365 } 366 367 @Override 368 public MultipleAlignment getMultipleAlignment(int index) { 369 return multipleAlignments.get(index); 370 } 371 372 @Override 373 public void setMultipleAlignments(List<MultipleAlignment> alignments) { 374 this.multipleAlignments = alignments; 375 } 376 377 @Override 378 public void addMultipleAlignment(MultipleAlignment alignment) { 379 if (multipleAlignments == null) { 380 multipleAlignments = new ArrayList<MultipleAlignment>(); 381 } 382 multipleAlignments.add(alignment); 383 alignment.setEnsemble(this); 384 } 385 386 @Override 387 public int size() { 388 if (structureIdentifiers != null) 389 return structureIdentifiers.size(); 390 else if (atomArrays != null) 391 return atomArrays.size(); 392 else { 393 throw new IndexOutOfBoundsException( 394 "Empty ensemble: names == null && atoms == null"); 395 } 396 } 397 398 @Override 399 public void clear() { 400 super.clear(); 401 distanceMatrix = null; 402 for (MultipleAlignment a : getMultipleAlignments()) 403 a.clear(); 404 } 405}