001package org.biojava.nbio.structure.contact; 002 003import org.biojava.nbio.structure.Atom; 004import org.biojava.nbio.structure.Calc; 005import org.biojava.nbio.structure.Chain; 006import org.biojava.nbio.structure.Group; 007import org.biojava.nbio.structure.Structure; 008import org.biojava.nbio.structure.StructureTools; 009import org.biojava.nbio.structure.xtal.CrystalTransform; 010import org.biojava.nbio.structure.xtal.SpaceGroup; 011 012import javax.vecmath.Point3d; 013import java.util.ArrayList; 014import java.util.Collection; 015import java.util.List; 016 017/** 018 * A class containing methods to find interfaces in a given structure. 019 * @author Jose Duarte 020 * @since 5.4.0 021 */ 022public class InterfaceFinder { 023 024 public static final double DEFAULT_CONTACT_CUTOFF = 6; 025 026 private static final CrystalTransform IDENTITY_TRANSFORM = new CrystalTransform((SpaceGroup) null); 027 private static final boolean INCLUDE_HETATOMS = true; 028 029 private List<Chain> polyChains; 030 private double cutoff; 031 032 private BoundingBox[] boundingBoxes; 033 034 public InterfaceFinder(Structure structure) { 035 this.polyChains = new ArrayList<>(structure.getPolyChains()); 036 trimPolyChains(); 037 this.cutoff = DEFAULT_CONTACT_CUTOFF; 038 } 039 040 /** 041 * Remove polymer chains with 0 atoms. 042 */ 043 private void trimPolyChains() { 044 polyChains.removeIf(chain -> { 045 int count = chain.getAtomGroups().stream().map(Group::getAtoms).mapToInt(Collection::size).sum(); 046 return count == 0; 047 }); 048 } 049 050 /** 051 * Set the contact distance cutoff. 052 * @param cutoff the distance value in Angstroms 053 */ 054 public void setCutoff(double cutoff) { 055 this.cutoff = cutoff; 056 } 057 058 /** 059 * Find all inter polymer-chain interfaces in the structure. 060 * Two chains will be considered in contact if at least a pair of atoms (one from each chain) is within the 061 * contact cutoff. 062 * @return the list of all interfaces 063 */ 064 public StructureInterfaceList getAllInterfaces() { 065 initBoundingBoxes(); 066 067 StructureInterfaceList list = new StructureInterfaceList(); 068 069 for (int i = 0; i<polyChains.size(); i++) { 070 for (int j = i + 1; j<polyChains.size(); j++) { 071 if (! boundingBoxes[i].overlaps(boundingBoxes[j], cutoff)) { 072 continue; 073 } 074 StructureInterface interf = calcInterface(polyChains.get(i), polyChains.get(j)); 075 if (interf!=null) { 076 list.add(interf); 077 } 078 } 079 } 080 return list; 081 } 082 083 private void initBoundingBoxes() { 084 boundingBoxes = new BoundingBox[polyChains.size()]; 085 for (int i = 0; i<polyChains.size(); i++) { 086 Atom[] atoms = StructureTools.getAllNonHAtomArray(polyChains.get(i), INCLUDE_HETATOMS); 087 Point3d[] points = Calc.atomsToPoints(atoms); 088 BoundingBox bb = new BoundingBox(points); 089 boundingBoxes[i] = bb; 090 } 091 } 092 093 private StructureInterface calcInterface(Chain chain1, Chain chain2) { 094 AtomContactSet graph = StructureTools.getAtomsInContact(chain1, chain2, cutoff, INCLUDE_HETATOMS); 095 096 StructureInterface interf = null; 097 if (graph.size()>0) { 098 interf = new StructureInterface( 099 StructureTools.getAllNonHAtomArray(chain1, INCLUDE_HETATOMS), StructureTools.getAllNonHAtomArray(chain2, INCLUDE_HETATOMS), 100 chain1.getName(), chain2.getName(), 101 graph, 102 IDENTITY_TRANSFORM, IDENTITY_TRANSFORM); 103 } 104 105 return interf; 106 } 107}