org.biojava.nbio.structure.geometry.SuperPositionSVD Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of biojava-structure Show documentation
Show all versions of biojava-structure Show documentation
The protein structure modules of BioJava.
/*
* BioJava development 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.
*
* For more information on the BioJava project and its aims,
* or to join the biojava-l mailing list, visit the home page
* at:
*
* http://www.biojava.org/
*
* Created on Dec 4, 2005
*
*/
package org.biojava.nbio.structure.geometry;
import javax.vecmath.Matrix4d;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import org.biojava.nbio.structure.jama.Matrix;
import org.biojava.nbio.structure.jama.SingularValueDecomposition;
/**
* A class that calculates the superposition between two sets of points using an
* SVD Matrix Decomposition. It was introduced by Wolfgang Kabsch, hence the
* alternative name Kabsh algorithm. Inspired by the biopython SVDSuperimposer
* class.
*
* @author Andreas Prlic
* @author Aleix Lafita
* @since 1.5
* @version %I% %G%
*
*/
public class SuperPositionSVD extends SuperPositionAbstract {
/**
* Constructor for the SVD superposition algorithm.
*
* @param centered
* true if the point arrays are centered at the origin (faster),
* false otherwise
*/
public SuperPositionSVD(boolean centered) {
super(centered);
}
@Override
public Matrix4d superpose(Point3d[] fixed, Point3d[] moved) {
checkInput(fixed, moved);
Point3d cena = CalcPoint.centroid(fixed);
Point3d cenb = CalcPoint.centroid(moved);
double[][] centAcoords = new double[][] { { cena.x, cena.y, cena.z } };
Matrix centroidA = new Matrix(centAcoords);
double[][] centBcoords = new double[][] { { cenb.x, cenb.y, cenb.z } };
Matrix centroidB = new Matrix(centBcoords);
// center at centroid
cena.negate();
cenb.negate();
Point3d[] ats1 = CalcPoint.clonePoint3dArray(fixed);
CalcPoint.translate(new Vector3d(cena), ats1);
Point3d[] ats2 = CalcPoint.clonePoint3dArray(moved);
CalcPoint.translate(new Vector3d(cenb), ats2);
double[][] coordSet1 = new double[ats1.length][3];
double[][] coordSet2 = new double[ats2.length][3];
// copy the atoms into the internal coords;
for (int i = 0; i < ats1.length; i++) {
coordSet1[i] = new double[3];
ats1[i].get(coordSet1[i]);
coordSet2[i] = new double[3];
ats2[i].get(coordSet2[i]);
}
// now this is the bridge to the Jama package:
Matrix a = new Matrix(coordSet1);
Matrix b = new Matrix(coordSet2);
// # correlation matrix
Matrix b_trans = b.transpose();
Matrix corr = b_trans.times(a);
SingularValueDecomposition svd = corr.svd();
Matrix u = svd.getU();
// v is alreaady transposed ! difference to numermic python ...
Matrix vt = svd.getV();
Matrix vt_orig = (Matrix) vt.clone();
Matrix u_transp = u.transpose();
Matrix rot_nottrans = vt.times(u_transp);
Matrix rot = rot_nottrans.transpose();
// check if we have found a reflection
double det = rot.det();
if (det < 0) {
vt = vt_orig.transpose();
vt.set(2, 0, (0 - vt.get(2, 0)));
vt.set(2, 1, (0 - vt.get(2, 1)));
vt.set(2, 2, (0 - vt.get(2, 2)));
Matrix nv_transp = vt.transpose();
rot_nottrans = nv_transp.times(u_transp);
rot = rot_nottrans.transpose();
}
Matrix cb_tmp = centroidB.times(rot);
Matrix tran = centroidA.minus(cb_tmp);
return Matrices.getTransformation(rot, tran);
}
@Override
public double getRmsd(Point3d[] x, Point3d[] y) {
Point3d[] yclone = CalcPoint.clonePoint3dArray(y);
superposeAndTransform(x, yclone);
return CalcPoint.rmsd(x, yclone);
}
}