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.symmetry.core; 022 023import org.biojava.nbio.structure.Atom; 024 025import javax.vecmath.Point3d; 026import java.util.*; 027 028/** 029 * Wraps a sequence clustering with structural information 030 */ 031public class ChainClusterer { 032 private List<SequenceAlignmentCluster> seqClusters = new ArrayList<SequenceAlignmentCluster>(); 033 private boolean modified = true; 034 035 private List<Atom[]> caAligned = new ArrayList<Atom[]>(); 036 private List<Point3d[]> caCoords = new ArrayList<Point3d[]>(); 037 038 public ChainClusterer(List<SequenceAlignmentCluster> seqClusters) { 039 this.seqClusters = seqClusters; 040 this.modified = true; 041 } 042 043 public List<Point3d[]> getCalphaCoordinates() { 044 run(); 045 return caCoords; 046 } 047 048 public List<Atom[]> getCalphaTraces() { 049 run(); 050 return caAligned; 051 } 052 053 public List<String> getChainIds() { 054 run(); 055 List<String> chainIdList = new ArrayList<String>(); 056 057 for (int i = 0; i < seqClusters.size(); i++) { 058 SequenceAlignmentCluster cluster = seqClusters.get(i); 059 for (String chainId: cluster.getChainIds()) { 060 chainIdList.add(chainId); 061 } 062 } 063 return chainIdList; 064 } 065 066 067 public List<Integer> getModelNumbers() { 068 run(); 069 List<Integer> modNumbers = new ArrayList<Integer>(); 070 071 for (int i = 0; i < seqClusters.size(); i++) { 072 SequenceAlignmentCluster cluster = seqClusters.get(i); 073 for (Integer number: cluster.getModelNumbers()) { 074 modNumbers.add(number); 075 } 076 } 077 return modNumbers; 078 } 079 080 public String getStoichiometry() { 081 run(); 082 StringBuilder formula = new StringBuilder(); 083 String alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 084 085 for (int i = 0; i < seqClusters.size(); i++) { 086 String c = "?"; 087 if (i < alpha.length()) { 088 c = alpha.substring(i, i+1); 089 } 090 formula.append(c); 091 int multiplier = seqClusters.get(i).getSequenceCount(); 092 if (multiplier > 1) { 093 formula.append(multiplier); 094 } 095 } 096 return formula.toString(); 097 } 098 099 /** 100 * Get valid symmetry order for this stoichiometry. 101 * @return 102 */ 103 public List<Integer> getFolds() { 104 run(); 105 List<Integer> stoichiometry = new ArrayList<Integer>(seqClusters.size()); 106 for (int id = 0; id < seqClusters.size(); id++) { 107 int seqCount = seqClusters.get(id).getSequenceCount(); 108 stoichiometry.add(seqCount); 109 } 110 return getValidFolds(stoichiometry); 111 } 112 /** 113 * Find valid symmetry orders for a given stoichiometry. For instance, 114 * an A6B4 protein would give [1,2] because (A6B4)1 and (A3B2)2 are valid 115 * decompositions. 116 * @param stoichiometry List giving the number of copies in each chain cluster 117 * @return The common factors of the stoichiometry 118 */ 119 public static List<Integer> getValidFolds(List<Integer> stoichiometry){ 120 List<Integer> denominators = new ArrayList<Integer>(); 121 122 int nChains = Collections.max(stoichiometry); 123 124 // Remove duplicate stoichiometries 125 Set<Integer> nominators = new TreeSet<Integer>(stoichiometry); 126 127 // find common denominators 128 for (int d = 1; d <= nChains; d++) { 129 boolean isDivisable=true; 130 for (Integer n : nominators) { 131 if (n % d != 0) { 132 isDivisable = false; 133 break; 134 } 135 } 136 if(isDivisable) { 137 denominators.add(d); 138 } 139 } 140 return denominators; 141 } 142 143 public List<Integer> getSequenceClusterIds() { 144 run(); 145 List<Integer> list = new ArrayList<Integer>(); 146 147 for (int id = 0; id < seqClusters.size(); id++) { 148 int seqCount = seqClusters.get(id).getSequenceCount(); 149 for (int i = 0; i < seqCount; i++) { 150 list.add(id); 151 } 152 } 153 return list; 154 } 155 156 157 public int getSequenceClusterCount() { 158 run(); 159 return seqClusters.size(); 160 } 161 162 public List<SequenceAlignmentCluster> getSequenceAlignmentClusters() { 163 return seqClusters; 164 } 165 166 public List<Boolean> getPseudoStoichiometry() { 167 run(); 168 List<Boolean> list = new ArrayList<Boolean>(); 169 170 for (int id = 0; id < seqClusters.size(); id++) { 171 int seqCount = seqClusters.get(id).getSequenceCount(); 172 Boolean pseudo = seqClusters.get(id).isPseudoStoichiometric(); 173 for (int i = 0; i < seqCount; i++) { 174 list.add(pseudo); 175 } 176 } 177 return list; 178 } 179 180 public List<Double> getMinSequenceIdentity() { 181 run(); 182 List<Double> list = new ArrayList<Double>(); 183 184 for (int id = 0; id < seqClusters.size(); id++) { 185 int seqCount = seqClusters.get(id).getSequenceCount(); 186 double minSequenceIdentity = seqClusters.get(id).getMinSequenceIdentity(); 187 for (int i = 0; i < seqCount; i++) { 188 list.add(minSequenceIdentity); 189 } 190 } 191 return list; 192 } 193 194 public List<Double> getMaxSequenceIdentity() { 195 run(); 196 List<Double> list = new ArrayList<Double>(); 197 198 for (int id = 0; id < seqClusters.size(); id++) { 199 int seqCount = seqClusters.get(id).getSequenceCount(); 200 double maxSequenceIdentity = seqClusters.get(id).getMaxSequenceIdentity(); 201 for (int i = 0; i < seqCount; i++) { 202 list.add(maxSequenceIdentity); 203 } 204 } 205 return list; 206 } 207 208 @Override 209 public String toString() { 210 run(); 211 StringBuilder builder = new StringBuilder(); 212 builder.append("Sequence alignment clusters: " + seqClusters.size()); 213 builder.append("\n"); 214 for (SequenceAlignmentCluster s: seqClusters) { 215 builder.append("# seq: "); 216 builder.append(s.getSequenceCount()); 217 builder.append(" alignment length: "); 218 builder.append(s.getSequenceAlignmentLength()); 219 builder.append("\n"); 220 } 221 return builder.toString(); 222 } 223 224 private void run() { 225 if (modified) { 226 modified = false; 227 calcAlignedSequences(); 228 createCalphaTraces(); 229 } 230 } 231 232 233 private void calcAlignedSequences() { 234 caAligned = new ArrayList<Atom[]>(); 235 for (SequenceAlignmentCluster cluster: seqClusters) { 236 caAligned.addAll(cluster.getAlignedCalphaAtoms()); 237 } 238 } 239 240 private void createCalphaTraces() { 241 for (Atom[] atoms: caAligned) { 242 Point3d[] trace = new Point3d[atoms.length]; 243 for (int j = 0; j < atoms.length; j++) { 244 trace[j] = new Point3d(atoms[j].getCoords()); 245 } 246 caCoords.add(trace); 247 } 248 } 249}