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