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.Serializable; 024import java.util.ArrayList; 025import java.util.List; 026 027import org.biojava.nbio.structure.Atom; 028import org.biojava.nbio.structure.StructureException; 029import org.biojava.nbio.structure.StructureIdentifier; 030 031/** 032 * A general implementation of a {@link MultipleAlignment}. 033 * 034 * @author Aleix Lafita 035 * @since 4.1.0 036 * 037 */ 038public class MultipleAlignmentImpl extends AbstractScoresCache implements 039 Serializable, MultipleAlignment, Cloneable { 040 041 private static final long serialVersionUID = 3432043794125805139L; 042 043 private MultipleAlignmentEnsemble parent; 044 private List<BlockSet> blockSets; 045 046 // Cache variables (can be updated) 047 private int length; 048 private int coreLength; 049 private List<Integer> alignResCounts; 050 private List<Double> coverages; 051 052 /** 053 * Default Constructor. Empty alignment. No structures assigned. 054 * 055 * @return MultipleAlignment an empty MultipleAlignment instance. 056 */ 057 public MultipleAlignmentImpl() { 058 this(new MultipleAlignmentEnsembleImpl()); // assign an empty ensemble. 059 } 060 061 /** 062 * Constructor linking to an existing ensemble. Automatically adds this 063 * alignment to the parent ensemble. 064 * 065 * @param ensemble 066 * parent MultipleAlignmentEnsemble. 067 * @return MultipleAlignment an alignment instance part of an ensemble. 068 */ 069 public MultipleAlignmentImpl(MultipleAlignmentEnsemble ensemble) { 070 071 super(); 072 parent = ensemble; 073 if (parent != null) 074 parent.getMultipleAlignments().add(this); 075 076 blockSets = null; 077 078 length = -1; // Value -1 reserved to indicate that has to be calculated 079 coreLength = -1; 080 alignResCounts = null; // Value null means not set 081 coverages = null; 082 } 083 084 /** 085 * Copy constructor. Recursively copies member BlockSets. 086 * 087 * @param ma 088 * MultipleAlignmentImpl to copy. 089 * @return MultipleAlignmentImpl identical copy of the alignment. 090 */ 091 public MultipleAlignmentImpl(MultipleAlignmentImpl ma) { 092 093 super(ma); // Copy the scores 094 parent = ma.parent; 095 096 length = ma.length; 097 coreLength = ma.coreLength; 098 099 blockSets = null; 100 if (ma.blockSets != null) { 101 // Make a deep copy of everything 102 this.blockSets = new ArrayList<BlockSet>(); 103 for (BlockSet bs : ma.blockSets) { 104 BlockSet newBS = bs.clone(); 105 newBS.setMultipleAlignment(this); 106 this.blockSets.add(newBS); 107 } 108 } 109 } 110 111 @Override 112 public void clear() { 113 super.clear(); 114 length = -1; 115 coreLength = -1; 116 alignResCounts = null; 117 for (BlockSet a : getBlockSets()) { 118 a.clear(); 119 } 120 } 121 122 @Override 123 public MultipleAlignmentImpl clone() { 124 return new MultipleAlignmentImpl(this); 125 } 126 127 @Override 128 public String toString() { 129 List<String> ids = new ArrayList<String>(parent 130 .getStructureIdentifiers().size()); 131 for (StructureIdentifier i : parent.getStructureIdentifiers()) { 132 ids.add(i.getIdentifier()); 133 } 134 String resume = "Structures:" + ids + " \nAlgorithm:" 135 + parent.getAlgorithmName() + "_" + parent.getVersion() 136 + " \nBlockSets: " + getBlockSets().size() + " \nBlocks: " 137 + getBlocks().size() + " \nLength: " + length() 138 + " \nCore Length: " + getCoreLength(); 139 for (String score : getScores()) { 140 resume += " \n" + score + ": "; 141 resume += String.format("%.2f", getScore(score)); 142 } 143 return resume; 144 } 145 146 @Override 147 public List<BlockSet> getBlockSets() { 148 if (blockSets == null) 149 blockSets = new ArrayList<BlockSet>(); 150 return blockSets; 151 } 152 153 @Override 154 public List<Block> getBlocks() { 155 List<Block> blocks = new ArrayList<Block>(); 156 for (BlockSet bs : getBlockSets()) { 157 blocks.addAll(bs.getBlocks()); 158 } 159 return blocks; 160 } 161 162 @Override 163 public void setBlockSets(List<BlockSet> blockSets) { 164 this.blockSets = blockSets; 165 } 166 167 @Override 168 public BlockSet getBlockSet(int index) { 169 return blockSets.get(index); 170 } 171 172 @Override 173 public Block getBlock(int index) { 174 List<Block> blocks = getBlocks(); 175 return blocks.get(index); 176 } 177 178 @Override 179 public List<Atom[]> getAtomArrays() { 180 return parent.getAtomArrays(); 181 } 182 183 @Override 184 public StructureIdentifier getStructureIdentifier(int index) { 185 return parent.getStructureIdentifiers().get(index); 186 } 187 188 @Override 189 public int size() { 190 return parent.size(); 191 } 192 193 @Override 194 public int length() { 195 if (length < 0) 196 updateLength(); 197 return length; 198 } 199 200 @Override 201 public int getCoreLength() { 202 if (coreLength < 0) 203 updateCoreLength(); 204 return coreLength; 205 } 206 207 /** 208 * Force recalculation of the length (aligned columns) based on the BlockSet 209 * lengths. 210 */ 211 protected void updateLength() { 212 if (getBlockSets().size() == 0) { 213 throw new IndexOutOfBoundsException( 214 "Empty MultipleAlignment: blockSets size == 0."); 215 } // Otherwise try to calculate it from the BlockSet information 216 else { 217 length = 0; 218 for (BlockSet blockSet : blockSets) 219 length += blockSet.length(); 220 } 221 } 222 223 /** 224 * Force recalculation of the core length (ungapped columns) based on the 225 * BlockSet core lengths. 226 */ 227 protected void updateCoreLength() { 228 if (getBlockSets().size() == 0) { 229 throw new IndexOutOfBoundsException( 230 "Empty MultipleAlignment: blockSets size == 0."); 231 } // Otherwise try to calculate it from the BlockSet information 232 else { 233 coreLength = 0; 234 for (BlockSet blockSet : blockSets) 235 coreLength += blockSet.getCoreLength(); 236 } 237 } 238 239 /** 240 * Updates all cached properties 241 * 242 * @throws StructureException 243 */ 244 protected void updateCache() { 245 updateCoreLength(); 246 updateLength(); 247 } 248 249 @Override 250 public MultipleAlignmentEnsemble getEnsemble() { 251 return parent; 252 } 253 254 @Override 255 public void setEnsemble(MultipleAlignmentEnsemble parent) { 256 this.parent = parent; 257 } 258 259 @Override 260 public List<Integer> getAlignResCounts() { 261 262 if (alignResCounts != null) 263 return alignResCounts; 264 265 alignResCounts = new ArrayList<Integer>(size()); 266 for (int s = 0; s < size(); s++) 267 alignResCounts.add(0); 268 269 for (BlockSet bs : blockSets) { 270 List<Integer> bscounts = bs.getAlignResCounts(); 271 for (int s = 0; s < size(); s++) 272 alignResCounts.set(s, alignResCounts.get(s) + bscounts.get(s)); 273 } 274 return alignResCounts; 275 } 276 277 @Override 278 public List<Double> getCoverages() { 279 280 if (coverages != null) 281 return coverages; 282 283 List<Integer> counts = getAlignResCounts(); 284 coverages = new ArrayList<Double>(size()); 285 for (int s = 0; s < size(); s++) 286 coverages.add(counts.get(s) 287 / (double) getAtomArrays().get(s).length); 288 return coverages; 289 } 290 291}