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.symmetry.geometry.SuperPosition; 024 025import javax.vecmath.Point3d; 026import java.util.*; 027import java.util.Map.Entry; 028 029public class HelicalRepeatUnit { 030 private Subunits subunits = null; 031 private List<Point3d> repeatUnitCenters = new ArrayList<Point3d>(); 032 private List<Point3d[]> repeatUnits = new ArrayList<Point3d[]>(); 033 private List<List<Integer>> repeatUnitIndices = new ArrayList<List<Integer>>(); 034 private Map<Integer[], Integer> interactingNeighbors = Collections.emptyMap(); 035 036public HelicalRepeatUnit(Subunits subunits) { 037 this.subunits = subunits; 038} 039 040public List<Point3d> getRepeatUnitCenters() { 041 if (repeatUnitCenters.isEmpty()) { 042 run(); 043 } 044 return repeatUnitCenters; 045} 046 047public List<Point3d[]> getRepeatUnits() { 048 if (repeatUnits.isEmpty()) { 049 run(); 050 } 051 return repeatUnits; 052} 053 054public List<List<Integer>> getRepeatUnitIndices() { 055 return repeatUnitIndices; 056} 057 058public Map<Integer[], Integer> getInteractingRepeatUnits() { 059 if (interactingNeighbors.isEmpty()) { 060 run(); 061 } 062 return interactingNeighbors; 063} 064 065private void run() { 066 this.repeatUnitCenters = calcRepeatUnitCenters(); 067 if (this.repeatUnitCenters.size() == 0) { 068 return; 069 } 070 this.repeatUnits = calcRepeatUnits(); 071 this.interactingNeighbors = findInteractingNeigbors(); 072} 073 074private List<Point3d> calcRepeatUnitCenters() { 075 Set<Integer> uniqueModels = new HashSet<Integer>(subunits.getModelNumbers()); 076 int modelCount = uniqueModels.size(); 077 List<Integer> folds = this.subunits.getFolds(); 078 int maxFold = folds.get(folds.size()-1); 079 080 List<Point3d> repeatCenters = new ArrayList<Point3d>(); 081 List<Point3d> centers = subunits.getCenters(); 082 List<Integer> models = subunits.getModelNumbers(); 083 084// if (modelCount == maxFold && subunits.getSubunitCount() > 3) { 085 if (maxFold%modelCount == 0 && modelCount > 1 && subunits.getSubunitCount() > 3) { 086// System.out.println("calcRepeatUnitCenters case 1"); 087 for (int i = 0; i < modelCount; i++) { 088 List<Integer> subunitIndices = new ArrayList<Integer>(); 089 Point3d p = new Point3d(); 090 int count = 0; 091// System.out.println("Models: " + models.size()); 092 for (int j = 0; j < models.size(); j++) { 093 if (models.get(j) == i) { 094 p.add(centers.get(j)); 095 subunitIndices.add(j); 096 count++; 097 } 098 } 099// System.out.println("count: " + count); 100 p.scale(1.0/count); 101// System.out.println("Orig Repeat unit: " + p); 102 repeatCenters.add(p); 103 repeatUnitIndices.add(subunitIndices); 104 } 105 } else { 106// System.out.println("calcRepeatUnitCenters case21"); 107 // TODO need to group subunits into repeating groups 108 // Case of 3B5U: A14, but seems to form (A2)*7 and symmetry related subunits don't have direct contact 109 List<Integer> sequenceClusterIds = subunits.getSequenceClusterIds(); 110 for (int i = 0; i < subunits.getSubunitCount(); i++) { 111 List<Integer> subunitIndices = new ArrayList<Integer>(1); 112 if (sequenceClusterIds.get(i) == 0) { 113 repeatCenters.add(new Point3d(centers.get(i))); 114// System.out.println("Orig Repeat unit: " + centers.get(i)); 115 subunitIndices.add(i); 116 repeatUnitIndices.add(subunitIndices); 117 } 118 } 119 } 120 121 // helixes should have at least 3 repeat centers 122// System.out.println("Number of repeat centers: " + repeatCenters.size()); 123 if (repeatCenters.size() < 3) { 124 repeatCenters.clear(); 125 } 126 127 return repeatCenters; 128} 129 130private List<Point3d[]> calcRepeatUnits() { 131 Set<Integer> uniqueModels = new HashSet<Integer>(subunits.getModelNumbers()); 132 int modelCount = uniqueModels.size(); 133 List<Integer> folds = this.subunits.getFolds(); 134 int maxFold = folds.get(folds.size()-1); 135 136 List<Point3d[]> repeatTraces = new ArrayList<Point3d[]>(); 137 List<Integer> models = subunits.getModelNumbers(); 138 List<Point3d[]> traces = subunits.getTraces(); 139 140// if (modelCount == maxFold && subunitCount > 3) { 141 if (maxFold%modelCount == 0 && modelCount > 1 && subunits.getSubunitCount() > 3) { 142 for (int i = 0; i < modelCount; i++) { 143 List<Point3d> coords = new ArrayList<Point3d>(); 144 for (int j = 0; j < models.size(); j++) { 145 if (models.get(j) == i) { 146 coords.addAll(Arrays.asList(traces.get(j))); 147 } 148 } 149 Point3d[] x = new Point3d[coords.size()]; 150 coords.toArray(x); 151// repeatTraces.add(x); // make sure we don't accidently change the original coordinates 152 repeatTraces.add(SuperPosition.clonePoint3dArray(x)); 153 } 154 } else { 155 List<Integer> sequenceClusterIds = subunits.getSequenceClusterIds(); 156 for (int i = 0; i < subunits.getSubunitCount(); i++) { 157 if (sequenceClusterIds.get(i) == 0) { 158 Point3d[] x = subunits.getTraces().get(i); 159 repeatTraces.add(SuperPosition.clonePoint3dArray(x)); 160 } 161 } 162 } 163 164// for (int i = 0; i < repeatTraces.size(); i++) { 165// System.out.println("Repeat " + i); 166// System.out.println(Arrays.toString(repeatTraces.get(i))); 167// } 168 return repeatTraces; 169} 170 171private Map<Integer[], Integer> findInteractingNeigbors() { 172 Map<Integer[], Integer> contactMap = new HashMap<Integer[], Integer>(); 173 174 Map<Integer, List<Integer[]>> distanceMap = findClosestPairs(8); 175 for (List<Integer[]> pairs: distanceMap.values()) 176 for (Integer[] pair: pairs) { 177 Integer contacts = calcContactNumber(repeatUnits.get(pair[0]), repeatUnits.get(pair[1])); 178// System.out.println("contacts: " + pair[0] + "-" + pair[1] + ": " + contacts); 179 if (contacts > 0) { 180 contactMap.put(pair, contacts); 181 } 182 } 183 184 return contactMap; 185} 186 187private Map<Integer, List<Integer[]>> findClosestPairs(int maxNeighbors) { 188 Map<Integer, List<Integer[]>> reducedMap = new TreeMap<Integer, List<Integer[]>>(); 189 190 Map<Integer, List<Integer[]>> distanceMap = new TreeMap<Integer, List<Integer[]>>(); 191 int nCenters = repeatUnitCenters.size(); 192// System.out.println("repeatUnitCenters: " + repeatUnitCenters); 193 194 for (int i = 0; i < nCenters-1; i++) { 195 for (int j = i+1; j < nCenters; j++) { 196 float dist = (float)repeatUnitCenters.get(i).distance(repeatUnitCenters.get(j)); 197 // round to 2 digits precision 198// System.out.println("dist pair: " + i + "-" + j + ": " + dist); 199 dist *= 100; 200 int intDist = Math.round(dist); 201 List<Integer[]> pairs = distanceMap.get(intDist); 202 // save only one representative pair for each distance 203 if (pairs == null) { 204 pairs = new ArrayList<Integer[]>(); 205 } 206 Integer[] pair = new Integer[2]; 207 pair[0] = i; 208 pair[1] = j; 209 pairs.add(pair); 210 distanceMap.put(intDist, pairs); 211 } 212 } 213 214 int count = 0; 215 for (Entry<Integer, List<Integer[]>> entry: distanceMap.entrySet()) { 216 if (! (reducedMap.containsKey(entry.getKey())) ) { 217 reducedMap.put(entry.getKey(), entry.getValue()); 218// System.out.println("dist pair: " + entry.getValue() + ": " + entry.getKey()); 219 count++; 220 if (count == maxNeighbors) { 221 break; 222 } 223 } 224 } 225 distanceMap.clear(); 226 227 return reducedMap; 228} 229 230private static int calcContactNumber(Point3d[] a, Point3d[] b) { 231 int contacts = 0; 232 for (Point3d pa : a) { 233 for (Point3d pb : b) { 234 if (pa.distance(pb) < 10) { 235 contacts++; 236 } 237 } 238 } 239 return contacts; 240} 241}