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; 024import org.biojava.nbio.structure.Calc; 025import org.biojava.nbio.structure.Chain; 026import org.biojava.nbio.structure.cluster.SubunitCluster; 027import org.biojava.nbio.structure.geometry.CalcPoint; 028import org.biojava.nbio.structure.geometry.MomentsOfInertia; 029import org.biojava.nbio.structure.symmetry.utils.SymmetryTools; 030 031import javax.vecmath.Point3d; 032import javax.vecmath.Vector3d; 033 034import java.util.*; 035import java.util.stream.Collectors; 036 037/** 038 * A bean to represent information about the set of {@link org.biojava.nbio.structure.cluster.Subunit}s being 039 * considered for symmetry detection. This class is a helper for the 040 * {@link QuatSymmetryDetector} algorithm, since it calculates and caches the 041 * {@link MomentsOfInertia} and the centroids of each Subunit. 042 * 043 * @author Peter Rose 044 * @author Aleix Lafita 045 * 046 */ 047public class QuatSymmetrySubunits { 048 049 private List<Point3d[]> caCoords = new ArrayList<>(); 050 private List<Point3d> originalCenters = new ArrayList<>(); 051 private List<Point3d> centers = new ArrayList<>(); 052 private List<Vector3d> unitVectors = new ArrayList<>(); 053 054 private List<Integer> folds = new ArrayList<>(); 055 private List<Integer> clusterIds = new ArrayList<>(); 056 private List<SubunitCluster> clusters; 057 058 private Point3d centroid; 059 private MomentsOfInertia momentsOfInertia = new MomentsOfInertia(); 060 061 /** 062 * Converts the List of {@link SubunitCluster} to a Subunit object. 063 * 064 * @param clusters 065 * List of SubunitCluster 066 */ 067 public QuatSymmetrySubunits(List<SubunitCluster> clusters) { 068 069 this.clusters = clusters; 070 071 // Loop through all subunits in the clusters and fill Lists 072 for (int c = 0; c < clusters.size(); c++) { 073 074 for (int s = 0; s < clusters.get(c).size(); s++) { 075 076 clusterIds.add(c); 077 Atom[] atoms = clusters.get(c).getAlignedAtomsSubunit(s); 078 079 Point3d[] points = Calc.atomsToPoints(atoms); 080 081 caCoords.add(points); 082 } 083 } 084 085 // List number of members in each cluster 086 List<Integer> stoichiometries = clusters.stream().map(c -> c.size()) 087 .collect(Collectors.toList()); 088 folds = SymmetryTools.getValidFolds(stoichiometries); 089 } 090 091 public List<Point3d[]> getTraces() { 092 return caCoords; 093 } 094 095 public List<Integer> getClusterIds() { 096 return clusterIds; 097 } 098 099 /** 100 * This method is provisional and should only be used for coloring Subunits. 101 * A new coloring schema has to be implemented to allow the coloring of 102 * Subunits, without implying one Subunit = one Chain. 103 * 104 * @return A List of the Chain Ids of each Subunit 105 */ 106 public List<String> getChainIds() { 107 108 List<String> chains = new ArrayList<String>(getSubunitCount()); 109 110 // Loop through all subunits in the clusters and fill Lists 111 for (int c = 0; c < clusters.size(); c++) { 112 for (int s = 0; s < clusters.get(c).size(); s++) 113 chains.add(clusters.get(c).getSubunits().get(s).getName()); 114 } 115 116 return chains; 117 } 118 119 /** 120 * This method is provisional and should only be used for coloring Subunits. 121 * A new coloring schema has to be implemented to allow the coloring of 122 * Subunits, without implying one Subunit = one Chain. 123 * 124 * @return A List of the Model number of each Subunit 125 */ 126 public List<Integer> getModelNumbers() { 127 128 List<Integer> models = new ArrayList<Integer>(getSubunitCount()); 129 130 // Loop through all subunits in the clusters and fill Lists 131 for (int c = 0; c < clusters.size(); c++) { 132 for (int s = 0; s < clusters.get(c).size(); s++) { 133 134 Atom[] atoms = clusters.get(c).getAlignedAtomsSubunit(s); 135 136 // TODO guess them chain and model (very ugly) 137 Chain chain = atoms[0].getGroup().getChain(); 138 139 int model = 0; 140 for (int m = 0; m < chain.getStructure().nrModels(); m++) { 141 if (chain.getStructure().getModel(m).contains(chain)) { 142 model = m; 143 break; 144 } 145 } 146 models.add(model); 147 } 148 } 149 return models; 150 } 151 152 public int getSubunitCount() { 153 run(); 154 if (centers == null) { 155 return 0; 156 } 157 return centers.size(); 158 } 159 160 public List<Integer> getFolds() { 161 return folds; 162 } 163 164 public int getCalphaCount() { 165 int count = 0; 166 for (Point3d[] trace : caCoords) { 167 count += trace.length; 168 } 169 return count; 170 } 171 172 public int getLargestSubunit() { 173 int index = -1; 174 int maxLength = 0; 175 for (int i = 0; i < caCoords.size(); i++) { 176 int length = caCoords.get(i).length; 177 if (length > maxLength) { 178 index = i; 179 } 180 } 181 return index; 182 } 183 184 public List<Point3d> getCenters() { 185 run(); 186 return centers; 187 } 188 189 public List<Vector3d> getUnitVectors() { 190 run(); 191 return unitVectors; 192 } 193 194 public List<Point3d> getOriginalCenters() { 195 run(); 196 return originalCenters; 197 } 198 199 public Point3d getCentroid() { 200 run(); 201 return centroid; 202 } 203 204 public MomentsOfInertia getMomentsOfInertia() { 205 run(); 206 return momentsOfInertia; 207 } 208 209 private void run() { 210 if (centers.size() > 0) { 211 return; 212 } 213 calcOriginalCenters(); 214 calcCentroid(); 215 calcCenters(); 216 calcMomentsOfIntertia(); 217 } 218 219 private void calcOriginalCenters() { 220 for (Point3d[] trace : caCoords) { 221 Point3d com = CalcPoint.centroid(trace); 222 originalCenters.add(com); 223 } 224 } 225 226 private void calcCentroid() { 227 Point3d[] orig = originalCenters.toArray(new Point3d[originalCenters 228 .size()]); 229 centroid = CalcPoint.centroid(orig); 230 } 231 232 private void calcCenters() { 233 for (Point3d p : originalCenters) { 234 Point3d c = new Point3d(p); 235 c.sub(centroid); 236 centers.add(c); 237 Vector3d v = new Vector3d(c); 238 v.normalize(); 239 unitVectors.add(v); 240 } 241 } 242 243 public Point3d getLowerBound() { 244 Point3d lower = new Point3d(); 245 for (Point3d p : centers) { 246 if (p.x < lower.x) { 247 lower.x = p.x; 248 } 249 if (p.y < lower.y) { 250 lower.y = p.y; 251 } 252 if (p.z < lower.z) { 253 lower.z = p.z; 254 } 255 } 256 return lower; 257 } 258 259 public Point3d getUpperBound() { 260 Point3d upper = new Point3d(); 261 for (Point3d p : centers) { 262 if (p.x > upper.x) { 263 upper.x = p.x; 264 } 265 if (p.y > upper.y) { 266 upper.y = p.y; 267 } 268 if (p.z > upper.z) { 269 upper.z = p.z; 270 } 271 } 272 return upper; 273 } 274 275 private void calcMomentsOfIntertia() { 276 for (Point3d[] trace : caCoords) { 277 for (Point3d p : trace) { 278 momentsOfInertia.addPoint(p, 1.0f); 279 } 280 } 281 } 282 283}