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 * Created on Aug 2, 2010 021 * Author: Jianjiong Gao 022 * 023 */ 024 025package org.biojava.nbio.protmod.structure; 026 027import org.biojava.nbio.structure.*; 028import org.biojava.nbio.structure.io.mmcif.MetalBondParser; 029import org.biojava.nbio.structure.io.mmcif.chem.MetalBondDistance; 030 031import java.util.ArrayList; 032import java.util.Collections; 033import java.util.List; 034import java.util.Map; 035 036public final class StructureUtil { 037 private StructureUtil() { 038 throw new AssertionError(); 039 } 040 041 /** 042 * 043 * @param group a {@link Group} in structure. 044 * @param isAminoAcid true if it is an amino acid. 045 * @return the {@link StructureGroup} of the group. 046 */ 047 public static StructureGroup getStructureGroup(Group group, boolean isAminoAcid) { 048 ResidueNumber resNum = group.getResidueNumber(); 049 return new StructureGroup(resNum, group.getPDBName(), isAminoAcid); 050 } 051 052 /** 053 * 054 * @param atom a {@link Atom} in structure. 055 * @param isParentAminoAcid true if the containing group is an amino acid. 056 * @return the {@link StructureAtom} of the atom. 057 */ 058 public static StructureAtom getStructureAtom(Atom atom, boolean isParentAminoAcid) { 059 060 Group g = atom.getGroup(); 061 String chainId = g.getChainId(); 062 StructureGroup strucGroup = getStructureGroup(g, isParentAminoAcid); 063 strucGroup.setChainId(chainId); 064 return new StructureAtom(strucGroup, atom.getName()); 065 } 066 067 /** 068 * 069 * @param atom1 the first {@link Atom} in structure. 070 * @param isParentAminoAcid1 true if the first containing group is an amino acid.. 071 * @param atom2 the second {@link Atom} in structure. 072 * @param isParentAminoAcid2 true if the second containing group is an amino acid.. 073 * @return the {@link StructureAtomLinkage} of the two atoms. 074 */ 075 public static StructureAtomLinkage getStructureAtomLinkage(Atom atom1, 076 boolean isParentAminoAcid1, Atom atom2, boolean isParentAminoAcid2) { 077 StructureAtom strucAtom1 = getStructureAtom(atom1, isParentAminoAcid1); 078 StructureAtom strucAtom2 = getStructureAtom(atom2, isParentAminoAcid2); 079 double distance = getAtomDistance(atom1, atom2); 080 return new StructureAtomLinkage(strucAtom1, strucAtom2, distance); 081 } 082 083 /** 084 * 085 * @param atom1 the first {@link Atom} in structure. 086 * @param atom2 the second {@link Atom} in structure. 087 * @return the distance between the two atoms in Angstrom. 088 */ 089 public static double getAtomDistance(Atom atom1, Atom atom2) { 090 double distance; 091 092 distance = Calc.getDistance(atom1, atom2); 093 094 return distance; 095 } 096 097 /** 098 * Find a linkage between two groups within tolerance of bond length, 099 * from potential atoms. 100 * @param group1 the first {@link Group}. 101 * @param group2 the second {@link Group}. 102 * @param potentialNamesOfAtomOnGroup1 potential names of the atom on the first group. 103 * If null, search all atoms on the first group. 104 * @param potentialNamesOfAtomOnGroup2 potential names of the atom on the second group. 105 * If null, search all atoms on the second group. 106 * @param ignoreNCLinkage true to ignore all N-C linkages 107 * @param bondLengthTolerance bond length error tolerance. 108 * @return an array of two Atoms that form bond between each other 109 * if found; null, otherwise. 110 */ 111 public static Atom[] findNearestAtomLinkage(final Group group1, final Group group2, 112 List<String> potentialNamesOfAtomOnGroup1, List<String> potentialNamesOfAtomOnGroup2, 113 final boolean ignoreNCLinkage, double bondLengthTolerance) { 114 115 116 List<Atom[]> linkages = findAtomLinkages(group1, group2, 117 potentialNamesOfAtomOnGroup1, potentialNamesOfAtomOnGroup2, 118 ignoreNCLinkage, bondLengthTolerance); 119 120 Atom[] ret = null; 121 double minDistance = Double.POSITIVE_INFINITY; 122 123 for (Atom[] linkage : linkages) { 124 double distance; 125 126 distance = Calc.getDistance(linkage[0], linkage[1]); 127 128 129 if (distance < minDistance) { 130 minDistance = distance; 131 ret = linkage; 132 } 133 } 134 135 return ret; 136 } 137 138 /** 139 * Find linkages between two groups within tolerance of bond length, 140 * from potential atoms. 141 * @param group1 the first {@link Group}. 142 * @param group2 the second {@link Group}. 143 * @param ignoreNCLinkage true to ignore all N-C linkages 144 * @param bondLengthTolerance bond length error tolerance. 145 * @return a list, each element of which is an array of two Atoms that form bond 146 * between each other. 147 */ 148 public static List<Atom[]> findAtomLinkages(final Group group1, 149 final Group group2, final boolean ignoreNCLinkage, 150 final double bondLengthTolerance) { 151 return findAtomLinkages(group1, group2, 152 null, null, ignoreNCLinkage, bondLengthTolerance); 153 } 154 155 /** 156 * Find linkages between two groups within tolerance of bond length, 157 * from potential atoms. 158 * @param group1 the first {@link Group}. 159 * @param group2 the second {@link Group}. 160 * @param potentialNamesOfAtomOnGroup1 potential names of the atom on the first group. 161 * If null, search all atoms on the first group. 162 * @param potentialNamesOfAtomOnGroup2 potential names of the atom on the second group. 163 * If null, search all atoms on the second group. 164 * @param ignoreNCLinkage true to ignore all N-C linkages 165 * @param bondLengthTolerance bond length error tolerance. 166 * @return a list, each element of which is an array of two Atoms that form bond 167 * between each other. 168 */ 169 public static List<Atom[]> findAtomLinkages(final Group group1, 170 final Group group2, 171 List<String> potentialNamesOfAtomOnGroup1, 172 List<String> potentialNamesOfAtomOnGroup2, 173 final boolean ignoreNCLinkage, 174 final double bondLengthTolerance) { 175 if (group1==null || group2==null) { 176 throw new IllegalArgumentException("Null group(s)."); 177 } 178 179 if (bondLengthTolerance<0) { 180 throw new IllegalArgumentException("bondLengthTolerance cannot be negative."); 181 } 182 183 List<Atom[]> ret = new ArrayList<Atom[]>(); 184 185 if (potentialNamesOfAtomOnGroup1 == null) { 186 // if empty name, search for all atoms 187 potentialNamesOfAtomOnGroup1 = getAtomNames(group1); 188 } 189 190 if (potentialNamesOfAtomOnGroup2 == null) { 191 // if empty name, search for all atoms 192 potentialNamesOfAtomOnGroup2 = getAtomNames(group2); 193 } 194 195 for (String namesOfAtomOnGroup1 : potentialNamesOfAtomOnGroup1) { 196 for (String namesOfAtomOnGroup2 : potentialNamesOfAtomOnGroup2) { 197 Atom[] atoms = findLinkage(group1, group2, namesOfAtomOnGroup1, 198 namesOfAtomOnGroup2, bondLengthTolerance); 199 if (atoms != null) { 200 if (ignoreNCLinkage && 201 ((atoms[0].getName().equals("N") && atoms[1].getName().equals("C")) 202 || (atoms[0].getName().equals("C") && atoms[1].getName().equals("N"))) 203 ) { 204 continue; 205 } 206 207 ret.add(atoms); 208 } 209 } 210 } 211 212 return ret; 213 } 214 215 /** 216 * Find a linkage between two groups within tolerance of bond length. 217 * @param group1 the first {@link Group}. 218 * @param group2 the second {@link Group}. 219 * @param nameOfAtomOnGroup1 atom name of the first group. 220 * @param nameOfAtomOnGroup2 atom name of the second group. 221 * @param bondLengthTolerance bond length error tolerance. 222 * @return an array of two Atoms that form bond between each other 223 * if found; null, otherwise. 224 */ 225 public static Atom[] findLinkage(final Group group1, final Group group2, 226 String nameOfAtomOnGroup1, String nameOfAtomOnGroup2, 227 double bondLengthTolerance) { 228 229 Atom[] ret = new Atom[2]; 230 231 ret[0] = group1.getAtom(nameOfAtomOnGroup1); 232 ret[1] = group2.getAtom(nameOfAtomOnGroup2); 233 234 if (ret[0]==null || ret[1]==null) { 235 return null; 236 } 237 238 239 Atom a1 = ret[0]; 240 Atom a2 = ret[1]; 241 242 boolean hasBond = a1.hasBond(a2); 243 244 if ( hasBond ) { 245 246 return ret; 247 } 248 249 // is it a metal ? 250 251 if ( a1.getElement().isMetal() || a2.getElement().isMetal()){ 252 253 MetalBondDistance defined = getMetalDistanceCutoff(a1.getElement().name(),a2.getElement().name()); 254 255 if ( defined != null) { 256 257 if (hasMetalBond(a1, a2, defined)) 258 return ret; 259 else 260 return null; 261 } 262 263 } 264 265 // not a metal 266 267 double distance = Calc.getDistance(a1, a2); 268 269 float radiusOfAtom1 = ret[0].getElement().getCovalentRadius(); 270 float radiusOfAtom2 = ret[1].getElement().getCovalentRadius(); 271 272 if (Math.abs(distance - radiusOfAtom1 - radiusOfAtom2) 273 > bondLengthTolerance) { 274 return null; 275 } 276 277 278 return ret; 279 } 280 281 private static boolean hasMetalBond(Atom a1, Atom a2, MetalBondDistance definition) { 282 283 double distance = Calc.getDistance(a1,a2); 284 285 Float min = definition.getLowerLimit(); 286 Float max = definition.getUpperLimit(); 287 288 return ( min < distance && max > distance); 289 290 } 291 292 private static MetalBondDistance getMetalDistanceCutoff(String name1, String name2) { 293 Map<String,List<MetalBondDistance>> defs= MetalBondParser.getMetalBondDefinitions(); 294 295 List<MetalBondDistance> distances = defs.get(name1); 296 297 if ( distances == null){ 298 299 distances = defs.get(name2); 300 String tmp = name1; 301 name2 = name1; 302 name1 = tmp; 303 } 304 if ( distances == null){ 305 return null; 306 } 307 308 for ( MetalBondDistance d : distances){ 309 if ( name1.equalsIgnoreCase(d.getAtomType1()) && name2.equalsIgnoreCase(d.getAtomType2()) ) 310 return d; 311 } 312 313 // no matching atom definitions found 314 return null; 315 316 } 317 318 /** 319 * 320 * @param group a {@link Group}. 321 * @return all atom names of the group. 322 */ 323 public static List<String> getAtomNames(Group group) { 324 List<Atom> atoms = group.getAtoms(); 325 if (atoms == null) { 326 return Collections.emptyList(); 327 } 328 329 int n = atoms.size(); 330 List<String> ret = new ArrayList<String>(n); 331 for (int i=0; i<n; i++) { 332 ret.add(atoms.get(i).getName()); 333 } 334 335 return ret; 336 } 337 338 /** 339 * Get all amino acids in a chain. 340 * @param chain 341 * @return 342 */ 343 public static List<Group> getAminoAcids(Chain chain) { 344 345 List<Group> gs = new ArrayList<>(); 346 347 for ( Group g : chain.getAtomGroups()){ 348 349 if ( g.isAminoAcid()) 350 gs.add(g); 351 352 } 353 354 return gs; 355 356 } 357 358}