All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.biojava.nbio.structure.align.AFPTwister Maven / Gradle / Ivy

The newest version!
/* This class is based on the original FATCAT implementation by
 * 
 * Yuzhen Ye & Adam Godzik (2003)
 * Flexible structure alignment by chaining aligned fragment pairs allowing twists.
 * Bioinformatics vol.19 suppl. 2. ii246-ii255.
 * https://www.ncbi.nlm.nih.gov/pubmed/14534198
 * 
* * Thanks to Yuzhen Ye and A. Godzik for granting permission to freely use and redistribute this code. * * This code may be freely distributed and modified under the * terms of the GNU Lesser General Public Licence. This should * be distributed with the code. If you do not have a copy, * see: * * http://www.gnu.org/copyleft/lesser.html * * Copyright for this code is held jointly by the individual * authors. These should be listed in @author doc comments. * * * Created on Jun 17, 2009 * Created by Andreas Prlic - RCSB PDB * */ package org.biojava.nbio.structure.align; import org.biojava.nbio.structure.*; import org.biojava.nbio.structure.align.model.AFP; import org.biojava.nbio.structure.align.model.AFPChain; import org.biojava.nbio.structure.geometry.Matrices; import org.biojava.nbio.structure.geometry.SuperPositions; import org.biojava.nbio.structure.jama.Matrix; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; import javax.vecmath.Matrix4d; public class AFPTwister { private final static Logger logger = LoggerFactory .getLogger(AFPTwister.class); // private static final boolean showAlignmentSteps = false; /** * calculate the total rmsd of the blocks output a merged pdb file for both * proteins protein 1, in chain A protein 2 is twisted according to the * twists detected, in chain B * * @return twisted Groups */ public static Group[] twistPDB(AFPChain afpChain, Atom[] ca1, Atom[] ca2) throws StructureException { // -------------------------------------------------------- if (afpChain.isShortAlign()) return new Group[0]; List afpSet = afpChain.getAfpSet(); int blockNum = afpChain.getBlockNum(); int i, b2, e2; // superimposing according to the initial AFP-chaining Atom[] origCA = StructureTools.cloneAtomArray(ca2); Atom[] iniTwistPdb = StructureTools.cloneAtomArray(ca2); int[] blockResSize = afpChain.getBlockResSize(); int[][][] blockResList = afpChain.getBlockResList(); int[] afpChainList = afpChain.getAfpChainList(); int[] block2Afp = afpChain.getBlock2Afp(); int[] blockSize = afpChain.getBlockSize(); int[] focusAfpList = afpChain.getFocusAfpList(); if (focusAfpList == null) { focusAfpList = new int[afpChain.getMinLen()]; afpChain.setFocusAfpList(focusAfpList); } int focusAfpn = 0; e2 = 0; b2 = 0; logger.debug("blockNUm at twister: {}", blockNum); for (int bk = 0; bk < blockNum; bk++) { // THIS IS TRANSFORMING THE ORIGINAL ca2 COORDINATES, NO CLONING... // copies the atoms over to iniTwistPdb later on in modifyCod transformOrigPDB(blockResSize[bk], blockResList[bk][0], blockResList[bk][1], ca1, ca2, null, -1); // transform pro2 according to comparison of pro1 and pro2 at give // residues if (bk > 0) { b2 = e2; } logger.debug("b2 is {} before modifyCon", b2); if (bk < (blockNum - 1)) { // bend at the middle of two consecutive AFPs int afpPos = afpChainList[block2Afp[bk] + blockSize[bk] - 1]; AFP a1 = afpSet.get(afpPos); e2 = a1.getP2(); int afpPos2 = afpChainList[block2Afp[bk + 1]]; AFP a2 = afpSet.get(afpPos2); e2 = (a2.getP2() - e2) / 2 + e2; logger.debug("e2 : {}", e2); } else { // last one is until the end... e2 = ca2.length; } // this copies the coordinates over into iniTwistPdb cloneAtomRange(iniTwistPdb, ca2, b2, e2); // bound[bk] = e2; for (i = 0; i < blockSize[bk]; i++) { focusAfpList[focusAfpn] = afpChainList[block2Afp[bk] + i]; focusAfpn++; } } int focusResn = afp2Res(afpChain, focusAfpn, focusAfpList, 0); afpChain.setTotalLenIni(focusResn); logger.debug(String.format("calrmsdini for %d residues", focusResn)); double totalRmsdIni = calCaRmsd(ca1, iniTwistPdb, focusResn, afpChain.getFocusRes1(), afpChain.getFocusRes2()); afpChain.setTotalRmsdIni(totalRmsdIni); logger.debug("got iniRMSD: {}", totalRmsdIni); if (totalRmsdIni == 5.76611141613097) { logger.debug("{}", afpChain.getAlnseq1()); logger.debug("{}", afpChain.getAlnsymb()); logger.debug("{}", afpChain.getAlnseq2()); } afpChain.setFocusAfpList(focusAfpList); afpChain.setBlock2Afp(block2Afp); afpChain.setAfpChainList(afpChainList); return twistOptimized(afpChain, ca1, origCA); } /** * superimposing according to the optimized alignment * * @param afpChain * @param ca1 * @param ca2 * @return Group array twisted. * @throws StructureException */ public static Group[] twistOptimized(AFPChain afpChain, Atom[] ca1, Atom[] ca2) throws StructureException { Atom[] optTwistPdb = new Atom[ca2.length]; int gPos = -1; for (Atom a : ca2) { gPos++; optTwistPdb[gPos] = a; } int blockNum = afpChain.getBlockNum(); int b2 = 0; int e2 = 0; int focusResn = 0; int[] focusRes1 = afpChain.getFocusRes1(); int[] focusRes2 = afpChain.getFocusRes2(); if (focusRes1 == null) { focusRes1 = new int[afpChain.getCa1Length()]; afpChain.setFocusRes1(focusRes1); } if (focusRes2 == null) { focusRes2 = new int[afpChain.getCa2Length()]; afpChain.setFocusRes2(focusRes2); } int[] optLen = afpChain.getOptLen(); int[][][] optAln = afpChain.getOptAln(); for (int bk = 0; bk < blockNum; bk++) { // THIS IS TRANSFORMING THE ORIGINAL ca2 COORDINATES, NO CLONING... // copies the atoms over to iniTwistPdb later on in modifyCod transformOrigPDB(optLen[bk], optAln[bk][0], optAln[bk][1], ca1, ca2, afpChain, bk); // transform pro2 according to comparison of pro1 and pro2 at give // residues if (bk > 0) { b2 = e2; } if (bk < blockNum - 1) { // bend at the middle of two consecutive // blocks e2 = optAln[bk][1][optLen[bk] - 1]; e2 = (optAln[bk + 1][1][0] - e2) / 2 + e2; } else { e2 = ca2.length; } cloneAtomRange(optTwistPdb, ca2, b2, e2); for (int i = 0; i < optLen[bk]; i++) { focusRes1[focusResn] = optAln[bk][0][i]; focusRes2[focusResn] = optAln[bk][1][i]; focusResn++; } } int totalLenOpt = focusResn; logger.debug("calrmsdopt for {} residues", focusResn); double totalRmsdOpt = calCaRmsd(ca1, optTwistPdb, focusResn, focusRes1, focusRes2); logger.debug("got opt RMSD: {}", totalRmsdOpt); int optLength = afpChain.getOptLength(); if (totalLenOpt != optLength) { logger.warn("Final alignment length is different {} {}", totalLenOpt, optLength); } logger.debug("final alignment length {}, rmsd {}", focusResn, totalRmsdOpt); afpChain.setTotalLenOpt(totalLenOpt); afpChain.setTotalRmsdOpt(totalRmsdOpt); return StructureTools.cloneGroups(optTwistPdb); } /** * transform the coordinates in the ca2 according to the superimposing of * the given position pairs. No Cloning, transforms input atoms. */ // orig name: transPdb private static void transformOrigPDB(int n, int[] res1, int[] res2, Atom[] ca1, Atom[] ca2, AFPChain afpChain, int blockNr) throws StructureException { logger.debug( "transforming original coordinates {} len1: {} res1: {} len2: {} res2: {}", n, ca1.length, res1.length, ca2.length, res2.length); Atom[] cod1 = getAtoms(ca1, res1, n, false); Atom[] cod2 = getAtoms(ca2, res2, n, false); // double *cod1 = pro1->Cod4Res(n, res1); // double *cod2 = pro2->Cod4Res(n, res2); Matrix4d transform = SuperPositions.superpose(Calc.atomsToPoints(cod1), Calc.atomsToPoints(cod2)); Matrix r = Matrices.getRotationJAMA(transform); Atom t = Calc.getTranslationVector(transform); logger.debug("transPdb: transforming orig coordinates with matrix: {}", r); if (afpChain != null) { Matrix[] ms = afpChain.getBlockRotationMatrix(); if (ms == null) ms = new Matrix[afpChain.getBlockNum()]; ms[blockNr] = r; Atom[] shifts = afpChain.getBlockShiftVector(); if (shifts == null) shifts = new Atom[afpChain.getBlockNum()]; shifts[blockNr] = t; afpChain.setBlockRotationMatrix(ms); afpChain.setBlockShiftVector(shifts); } for (Atom a : ca2) Calc.transform(a.getGroup(), transform); } // like Cod4Res // most likely the clone flag is not needed private static Atom[] getAtoms(Atom[] ca, int[] positions, int length, boolean clone) { List atoms = new ArrayList<>(); for (int i = 0; i < length; i++) { int p = positions[i]; Atom a; if (clone) { a = (Atom) ca[p].clone(); a.setGroup((Group) ca[p].getGroup().clone()); } else { a = ca[p]; } atoms.add(a); } return atoms.toArray(new Atom[0]); } /** * Clones and copies the Atoms from p2 into p1 range is between r1 and r2 * * @param p1 * @param p2 * @param r1 * @param r2 */ // orig name: modifyCod private static void cloneAtomRange(Atom[] p1, Atom[] p2, int r1, int r2) throws StructureException { logger.debug("modifyCod from: {} to: {}", r1, r2); // special clone method, can;t use StructureTools.cloneCAArray, since we // access the data // slightly differently here. List model = new ArrayList<>(); for (int i = r1; i < r2; i++) { Group g = p2[i].getGroup(); Group newG = (Group) g.clone(); p1[i] = newG.getAtom(p2[i].getName()); Chain parentC = g.getChain(); Chain newChain = null; for (Chain c : model) { if (c.getName().equals(parentC.getName())) { newChain = c; break; } } if (newChain == null) { newChain = new ChainImpl(); newChain.setName(parentC.getName()); model.add(newChain); } newChain.addGroup(newG); } // modify caCod } /** * Return the rmsd of the CAs between the input pro and this protein, at * given positions. quite similar to transPdb but while that one transforms * the whole ca2, this one only works on the res1 and res2 positions. * * Modifies the coordinates in the second set of Atoms (pro). * * @return rmsd of CAs */ private static double calCaRmsd(Atom[] ca1, Atom[] pro, int resn, int[] res1, int[] res2) throws StructureException { Atom[] cod1 = getAtoms(ca1, res1, resn, false); Atom[] cod2 = getAtoms(pro, res2, resn, false); if (cod1.length == 0 || cod2.length == 0) { logger.info("length of atoms == 0!"); return 99; } Matrix4d transform = SuperPositions.superpose(Calc.atomsToPoints(cod1), Calc.atomsToPoints(cod2)); for (Atom a : cod2) Calc.transform(a.getGroup(), transform); return Calc.rmsd(cod1, cod2); } /** * Set the list of equivalent residues in the two proteins given a list of * AFPs * * WARNING: changes the values for FocusRes1, focusRes2 and FocusResn in * afpChain! * * @param afpChain * the AFPChain to store resuts * @param afpn * nr of afp * @param afpPositions * @param listStart * @return nr of eq residues */ public static int afp2Res(AFPChain afpChain, int afpn, int[] afpPositions, int listStart) { int[] res1 = afpChain.getFocusRes1(); int[] res2 = afpChain.getFocusRes2(); int minLen = afpChain.getMinLen(); int n = 0; List afpSet = afpChain.getAfpSet(); for (int i = listStart; i < listStart + afpn; i++) { int a = afpPositions[i]; for (int j = 0; j < afpSet.get(a).getFragLen(); j++) { if (n >= minLen) { throw new RuntimeException( "Error: too many residues in AFPChainer.afp2Res!"); } res1[n] = afpSet.get(a).getP1() + j; res2[n] = afpSet.get(a).getP2() + j; n++; } } afpChain.setFocusRes1(res1); afpChain.setFocusRes2(res2); afpChain.setFocusResn(n); if (n == 0) { logger.warn("n=0!!! + " + afpn + " " + listStart + " " + afpPositions.length); } return n; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy