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.AlignTools; 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.getName2() != null) { 165 structureIdentifiers = Arrays.<StructureIdentifier> asList( 166 new StructureName(afp.getName1()), 167 new StructureName(afp.getName2())); 168 } 169 algorithmName = afp.getAlgorithmName(); 170 version = afp.getVersion(); 171 calculationTime = afp.getCalculationTime(); 172 173 MultipleAlignment msa = new MultipleAlignmentImpl(this); 174 setMultipleAlignments(Arrays.asList(msa)); 175 176 // Convert the rotation and translation to a Matrix4D and set it 177 Matrix4d ident = new Matrix4d(); 178 ident.setIdentity(); 179 Matrix[] rot = afp.getBlockRotationMatrix(); 180 Atom[] shift = afp.getBlockShiftVector(); 181 182 // Create a BlockSet for every block in AFPChain if flexible 183 if (flexible) { 184 for (int bs = 0; bs < afp.getBlockNum(); bs++) { 185 BlockSet blockSet = new BlockSetImpl(msa); 186 Matrix4d blockTr = null; 187 try { 188 blockTr = Calc.getTransformation(rot[bs], shift[bs]); 189 } catch (IndexOutOfBoundsException e) { 190 blockTr = ident; 191 } catch (NullPointerException e) { 192 blockTr = ident; 193 } 194 blockSet.setTransformations(Arrays.asList(ident, blockTr)); 195 Block block = new BlockImpl(blockSet); 196 block.setAlignRes(new ArrayList<List<Integer>>()); 197 block.getAlignRes().add(new ArrayList<Integer>()); 198 block.getAlignRes().add(new ArrayList<Integer>()); 199 200 // Set the transformation of the BlockSet 201 Matrix rotB = afp.getBlockRotationMatrix()[bs]; 202 Atom shiftB = afp.getBlockShiftVector()[bs]; 203 Matrix4d transformB = Calc.getTransformation(rotB, shiftB); 204 blockSet.setTransformations(Arrays.asList(ident, transformB)); 205 206 // Convert the optimal alignment to a Block 207 for (int i = 0; i < afp.getOptAln()[bs][0].length; i++) { 208 block.getAlignRes().get(0).add(afp.getOptAln()[bs][0][i]); 209 block.getAlignRes().get(1).add(afp.getOptAln()[bs][1][i]); 210 } 211 } 212 } // Create a Block for every block in AFPChain if not flexible 213 else { 214 BlockSet blockSet = new BlockSetImpl(msa); 215 Matrix4d blockTr = null; 216 try { 217 blockTr = Calc.getTransformation(rot[0], shift[0]); 218 } catch (IndexOutOfBoundsException e) { 219 blockTr = ident; 220 } catch (NullPointerException e) { 221 blockTr = ident; 222 } 223 blockSet.setTransformations(Arrays.asList(ident, blockTr)); 224 for (int bs = 0; bs < afp.getBlockNum(); bs++) { 225 Block block = new BlockImpl(blockSet); 226 block.setAlignRes(new ArrayList<List<Integer>>()); 227 block.getAlignRes().add(new ArrayList<Integer>()); 228 block.getAlignRes().add(new ArrayList<Integer>()); 229 230 // Convert the optimal alignment to a Block 231 for (int i = 0; i < afp.getOptAln()[bs][0].length; i++) { 232 block.getAlignRes().get(0).add(afp.getOptAln()[bs][0][i]); 233 block.getAlignRes().get(1).add(afp.getOptAln()[bs][1][i]); 234 } 235 } 236 } 237 238 // Copy the scores stored in the AFPChain 239 msa.putScore(MultipleAlignmentScorer.PROBABILITY, afp.getProbability()); 240 msa.putScore(MultipleAlignmentScorer.AVGTM_SCORE, afp.getTMScore()); 241 msa.putScore(MultipleAlignmentScorer.CE_SCORE, afp.getAlignScore()); 242 msa.putScore(MultipleAlignmentScorer.RMSD, afp.getTotalRmsdOpt()); 243 } 244 245 @Override 246 public MultipleAlignmentEnsembleImpl clone() { 247 return new MultipleAlignmentEnsembleImpl(this); 248 } 249 250 @Override 251 public String getAlgorithmName() { 252 return algorithmName; 253 } 254 255 @Override 256 public void setAlgorithmName(String algorithmName) { 257 this.algorithmName = algorithmName; 258 } 259 260 @Override 261 public String getVersion() { 262 return version; 263 } 264 265 @Override 266 public void setVersion(String version) { 267 this.version = version; 268 } 269 270 @Override 271 public Long getIoTime() { 272 return ioTime; 273 } 274 275 @Override 276 public void setIoTime(Long millis) { 277 this.ioTime = millis; 278 } 279 280 @Override 281 public Long getCalculationTime() { 282 return calculationTime; 283 } 284 285 @Override 286 public void setCalculationTime(Long millis) { 287 this.calculationTime = millis; 288 } 289 290 @Override 291 public List<StructureIdentifier> getStructureIdentifiers() { 292 return structureIdentifiers; 293 } 294 295 @Override 296 public void setStructureIdentifiers(List<StructureIdentifier> structureNames) { 297 this.structureIdentifiers = structureNames; 298 } 299 300 @Override 301 public List<Atom[]> getAtomArrays() { 302 if (atomArrays == null) { 303 try { 304 updateAtomArrays(); 305 } catch (IOException e) { 306 throw new NullPointerException(e.getMessage()); 307 } catch (StructureException e) { 308 throw new NullPointerException(e.getMessage()); 309 } 310 } 311 return atomArrays; 312 } 313 314 @Override 315 public void setAtomArrays(List<Atom[]> atomArrays) { 316 this.atomArrays = atomArrays; 317 } 318 319 /** 320 * Force the atom arrays to regenerate based on 321 * {@link #getStructureIdentifiers()}. 322 * 323 * @throws IOException 324 * @throws StructureException 325 */ 326 public void updateAtomArrays() throws IOException, StructureException { 327 AtomCache cache = new AtomCache(); 328 atomArrays = new ArrayList<Atom[]>(); 329 for (StructureIdentifier name : getStructureIdentifiers()) { 330 Atom[] array = cache.getRepresentativeAtoms(name); 331 atomArrays.add(array); 332 } 333 } 334 335 @Override 336 public List<Matrix> getDistanceMatrix() { 337 if (distanceMatrix == null) 338 updateDistanceMatrix(); 339 return distanceMatrix; 340 } 341 342 /** 343 * Force recalculation of the distance matrices. 344 */ 345 public void updateDistanceMatrix() { 346 347 // Reset the distance Matrix variable 348 distanceMatrix = new ArrayList<Matrix>(); 349 350 for (int s = 0; s < size(); s++) { 351 Atom[] ca = atomArrays.get(s); 352 Matrix distMat = AlignTools.getDistanceMatrix(ca, ca); 353 distanceMatrix.add(distMat); 354 } 355 } 356 357 @Override 358 public List<MultipleAlignment> getMultipleAlignments() { 359 360 if (multipleAlignments == null) { 361 multipleAlignments = new ArrayList<MultipleAlignment>(); 362 } 363 return multipleAlignments; 364 } 365 366 @Override 367 public MultipleAlignment getMultipleAlignment(int index) { 368 return multipleAlignments.get(index); 369 } 370 371 @Override 372 public void setMultipleAlignments(List<MultipleAlignment> alignments) { 373 this.multipleAlignments = alignments; 374 } 375 376 @Override 377 public void addMultipleAlignment(MultipleAlignment alignment) { 378 if (multipleAlignments == null) { 379 multipleAlignments = new ArrayList<MultipleAlignment>(); 380 } 381 multipleAlignments.add(alignment); 382 alignment.setEnsemble(this); 383 } 384 385 @Override 386 public int size() { 387 if (structureIdentifiers != null) 388 return structureIdentifiers.size(); 389 else if (atomArrays != null) 390 return atomArrays.size(); 391 else { 392 throw new IndexOutOfBoundsException( 393 "Empty ensemble: names == null && atoms == null"); 394 } 395 } 396 397 @Override 398 public void clear() { 399 super.clear(); 400 distanceMatrix = null; 401 for (MultipleAlignment a : getMultipleAlignments()) 402 a.clear(); 403 } 404}