diff --git a/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/StructureTest.java b/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/StructureTest.java index ec2f589929..76edc8dcd4 100644 --- a/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/StructureTest.java +++ b/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/StructureTest.java @@ -21,16 +21,17 @@ package org.biojava.nbio.structure.test; import org.biojava.nbio.structure.*; +import org.biojava.nbio.structure.geometry.SuperPositions; import org.biojava.nbio.structure.io.FileParsingParameters; import org.biojava.nbio.structure.io.PDBFileParser; import org.biojava.nbio.structure.io.SSBondImpl; -import org.biojava.nbio.structure.jama.Matrix; - import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Set; +import javax.vecmath.Matrix4d; + import org.junit.BeforeClass; import org.junit.Test; @@ -41,8 +42,6 @@ * @author Andreas Prlic * @since 1.5 */ - - public class StructureTest { private static Structure structure; @@ -266,18 +265,12 @@ public void testMutation() throws Exception { atoms2[1] = g2.getAtom("CA"); atoms2[2] = g2.getAtom("CB"); + Matrix4d transform = SuperPositions.superpose( + Calc.atomsToPoints(atoms1), Calc.atomsToPoints(atoms2)); - SVDSuperimposer svds = new SVDSuperimposer(atoms1,atoms2); - - - Matrix rotMatrix = svds.getRotation(); - Atom tran = svds.getTranslation(); - - Group newGroup = (Group)g2.clone(); - - Calc.rotate(newGroup,rotMatrix); + Group newGroup = (Group) g2.clone(); - Calc.shift(newGroup,tran); + Calc.transform(newGroup, transform); Atom ca1 = g1.getAtom("CA"); Atom oldca2 = g2.getAtom("CA"); diff --git a/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/align/FlipAFPChainTest.java b/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/align/FlipAFPChainTest.java index 9f62b85778..f08d8c3a5a 100644 --- a/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/align/FlipAFPChainTest.java +++ b/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/align/FlipAFPChainTest.java @@ -25,6 +25,7 @@ package org.biojava.nbio.structure.test.align; import junit.framework.TestCase; + import org.biojava.nbio.structure.*; import org.biojava.nbio.structure.align.StructureAlignment; import org.biojava.nbio.structure.align.StructureAlignmentFactory; @@ -150,7 +151,7 @@ private double getRMSD(AFPChain afpChain, Atom[] ca1, Atom[] ca2) assertTrue(catmp1.length == afpChain.getNrEQR()); - return SVDSuperimposer.getRMS(catmp1,catmp2); + return Calc.rmsd(catmp1,catmp2); } public static void rotateAtoms2(AFPChain afpChain,Atom[] ca2){ diff --git a/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/align/fatcat/FlipAFPChainTest.java b/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/align/fatcat/FlipAFPChainTest.java index 8aa21461c4..a7b0c15777 100644 --- a/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/align/fatcat/FlipAFPChainTest.java +++ b/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/align/fatcat/FlipAFPChainTest.java @@ -25,6 +25,7 @@ package org.biojava.nbio.structure.test.align.fatcat; import junit.framework.TestCase; + import org.biojava.nbio.structure.*; import org.biojava.nbio.structure.align.StructureAlignment; import org.biojava.nbio.structure.align.StructureAlignmentFactory; @@ -171,7 +172,7 @@ private double getRMSD(AFPChain afpChain, Atom[] ca1, Atom[] ca2) assertTrue(catmp1.length == afpChain.getNrEQR()); - return SVDSuperimposer.getRMS(catmp1,catmp2); + return Calc.rmsd(catmp1,catmp2); } public static void rotateAtoms2(AFPChain afpChain,Atom[] ca2){ diff --git a/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/align/fatcat/TestFlexibleRotationMatrices.java b/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/align/fatcat/TestFlexibleRotationMatrices.java index 551a6d5288..b1ff3ddb8b 100644 --- a/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/align/fatcat/TestFlexibleRotationMatrices.java +++ b/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/align/fatcat/TestFlexibleRotationMatrices.java @@ -25,6 +25,7 @@ package org.biojava.nbio.structure.test.align.fatcat; import junit.framework.TestCase; + import org.biojava.nbio.structure.*; import org.biojava.nbio.structure.align.StructureAlignment; import org.biojava.nbio.structure.align.fatcat.FatCatFlexible; @@ -34,19 +35,18 @@ import org.biojava.nbio.structure.align.util.AtomCache; import org.biojava.nbio.structure.align.xml.AFPChainXMLConverter; import org.biojava.nbio.structure.align.xml.AFPChainXMLParser; +import org.biojava.nbio.structure.geometry.Matrices; +import org.biojava.nbio.structure.geometry.SuperPositions; import org.biojava.nbio.structure.jama.Matrix; import java.io.IOException; import java.util.ArrayList; import java.util.List; - +import javax.vecmath.Matrix4d; public class TestFlexibleRotationMatrices extends TestCase{ - - - public void testFlexibleRotationMatrices(){ String name1 = "1a21.A"; @@ -200,7 +200,7 @@ private void compareBlock(int blockNr, AFPChain afpChain, AFPChain newChain, // calc RMSD - double rmsdFile = SVDSuperimposer.getRMS(blockSet1, blockSet2); + double rmsdFile = Calc.rmsd(blockSet1, blockSet2); // this is the value from the file. it never seems to match precisely, probably is calculated from initial block. // we can't reproduce the initial block, since we don;t serialize it. @@ -209,10 +209,12 @@ private void compareBlock(int blockNr, AFPChain afpChain, AFPChain newChain, // THIS IS CALCULATING THE "correct" rotation matrix, that should be in the file - SVDSuperimposer svd = new SVDSuperimposer(blockSet1, blockSet2copy); + Matrix4d transform = SuperPositions.superpose(Calc.atomsToPoints(blockSet1), + Calc.atomsToPoints(blockSet2copy)); + //double rmsdForce = SVDSuperimposer.getRMS(atomSet1, atomSet2); - Matrix m = svd.getRotation(); - Atom s = svd.getTranslation(); + Matrix m = Matrices.getRotationJAMA(transform); + Atom s = Calc.getTranslationVector(transform); Matrix max = maxs2[blockNr]; Atom shift = shifts2[blockNr]; @@ -231,7 +233,7 @@ private void compareBlock(int blockNr, AFPChain afpChain, AFPChain newChain, Calc.rotate(a, m); Calc.shift( a, s); } - double rmsd3 = SVDSuperimposer.getRMS(blockSet1,blockSet2copy); + double rmsd3 = Calc.rmsd(blockSet1,blockSet2copy); assertTrue("The RMSD values don;t match after rotation / shift for block " + blockNr + "! should be: " + rmsd3 + " but found: " +rmsdFile, compareRmsd(rmsd3, rmsdFile)); diff --git a/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/symmetry/TestQuatSymmetryDetectorExamples.java b/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/symmetry/TestQuatSymmetryDetectorExamples.java index 9ec0b15b1a..fc3e5d009b 100644 --- a/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/symmetry/TestQuatSymmetryDetectorExamples.java +++ b/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/symmetry/TestQuatSymmetryDetectorExamples.java @@ -68,9 +68,30 @@ public void testNMR() throws IOException, StructureException { assertFalse(symmetry.isPseudoStoichiometric()); } + + /** + * Test a dihedral symmetry: 2VML + */ + @Test + public void testDihedral() throws IOException, StructureException { + + Structure pdb = StructureIO.getStructure("BIO:2vml:1"); + + SubunitClustererParameters clusterParams = new SubunitClustererParameters(); + clusterParams.setClustererMethod(SubunitClustererMethod.SEQUENCE); + QuatSymmetryParameters symmParams = new QuatSymmetryParameters(); + QuatSymmetryResults symmetry = QuatSymmetryDetector.calcGlobalSymmetry( + pdb, symmParams, clusterParams); + + // D3 symmetry non pseudosymmetric + assertEquals("D3", symmetry.getSymmetry()); + assertEquals("A6B6", symmetry.getStoichiometry()); + + } /** * Hemoglobin has both symmetry and pseudosymmetry: 4HHB + * TODO pseudosymmetry in hemoglobin fails * * @throws StructureException * @throws IOException diff --git a/biojava-structure-gui/src/main/java/demo/DemoQuatSymmetryJmol.java b/biojava-structure-gui/src/main/java/demo/DemoQuatSymmetryJmol.java index 909240eb97..47865e88d8 100644 --- a/biojava-structure-gui/src/main/java/demo/DemoQuatSymmetryJmol.java +++ b/biojava-structure-gui/src/main/java/demo/DemoQuatSymmetryJmol.java @@ -61,7 +61,7 @@ public class DemoQuatSymmetryJmol { public static void main(String[] args) throws IOException, StructureException { - String name = "1VYM"; + String name = "2vml"; // Download the biological assembly AtomCache cache = new AtomCache(); @@ -72,7 +72,6 @@ public static void main(String[] args) throws IOException, SubunitClustererParameters cp = new SubunitClustererParameters(); cp.setClustererMethod(SubunitClustererMethod.SEQUENCE); // normal // cp.setClustererMethod(SubunitClustererMethod.STRUCTURE); // pseudo - // cp.setClustererMethod(SubunitClustererMethod.INTERNAL_SYMMETRY); cp.setCoverageThreshold(0.9); // Calculate and display the global symmetry diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/Calc.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/Calc.java index 92d90088d6..829cb47589 100644 --- a/biojava-structure/src/main/java/org/biojava/nbio/structure/Calc.java +++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/Calc.java @@ -23,6 +23,8 @@ package org.biojava.nbio.structure; import org.biojava.nbio.structure.geometry.CalcPoint; +import org.biojava.nbio.structure.geometry.Matrices; +import org.biojava.nbio.structure.geometry.SuperPositionSVD; import org.biojava.nbio.structure.jama.Matrix; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -992,13 +994,14 @@ public static final Atom createVirtualCBAtom(AminoAcid amino) arr2[1] = amino.getCA(); arr2[2] = amino.getC(); - // ok now we got the two arrays, do a SVD: + // ok now we got the two arrays, do a Superposition: - SVDSuperimposer svd = new SVDSuperimposer(arr2, arr1); - - Matrix rotMatrix = svd.getRotation(); - Atom tranMatrix = svd.getTranslation(); + SuperPositionSVD svd = new SuperPositionSVD(false); + Matrix4d transform = svd.superpose(arr1, arr2); + Matrix rotMatrix = Matrices.getRotationJAMA(transform); + Atom tranMatrix = getTranslationVector(transform); + Calc.rotate(aCB, rotMatrix); Atom virtualCB = Calc.add(aCB, tranMatrix); @@ -1180,23 +1183,6 @@ public static void shift(Atom[] ca, Atom b) { Calc.shift(atom, b); } - /** - * Convert JAMA rotation and translation to a Vecmath transformation matrix. - * Because the JAMA matrix is a pre-multiplication matrix and the Vecmath - * matrix is a post-multiplication one, the rotation matrix is transposed to - * ensure that the transformation they produce is the same. - * - * @param rot - * 3x3 Rotation matrix - * @param trans - * 3x1 Translation matrix - * @return 4x4 transformation matrix - */ - public static Matrix4d getTransformation(Matrix rot, Matrix trans) { - return new Matrix4d(new Matrix3d(rot.getColumnPackedCopy()), - new Vector3d(trans.getColumnPackedCopy()), 1.0); - } - /** * Convert JAMA rotation and translation to a Vecmath transformation matrix. * Because the JAMA matrix is a pre-multiplication matrix and the Vecmath @@ -1213,30 +1199,9 @@ public static Matrix4d getTransformation(Matrix rot, Atom trans) { return new Matrix4d(new Matrix3d(rot.getColumnPackedCopy()), new Vector3d(trans.getCoords()), 1.0); } - - /** - * Convert Vecmath transformation into a JAMA rotation matrix. Because the - * JAMA matrix is a pre-multiplication matrix and the Vecmath matrix is a - * post-multiplication one, the rotation matrix is transposed to ensure that - * the transformation they produce is the same. - * - * @param transform - * Matrix4d with transposed rotation matrix - * @return - */ - public static Matrix getRotationMatrix(Matrix4d transform) { - - Matrix rot = new Matrix(3, 3); - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - rot.set(j, i, transform.getElement(i, j)); // transposed - } - } - return rot; - } - + /** - * Extract the translational vector of a Vecmath transformation. + * Extract the translational vector as an Atom of a transformation matrix. * * @param transform * Matrix4d @@ -1264,4 +1229,127 @@ public static Point3d[] atomsToPoints(Atom[] atoms) { } return points; } + + /** + * Calculate the RMSD of two Atom arrays, already superposed. + * + * @param x + * array of Atoms superposed to y + * @param y + * array of Atoms superposed to x + * @return RMSD + */ + public static double rmsd(Atom[] x, Atom[] y) { + return CalcPoint.rmsd(atomsToPoints(x), atomsToPoints(y)); + } + + /** + * Calculate the TM-Score for the superposition. + * + * Normalizes by the maximum-length structure (that is, {@code max\{len1,len2\}}) rather than the minimum. + * + * Atom sets must be superposed. + * + *
+ * Citation:
+ * Zhang Y and Skolnick J (2004). "Scoring function for automated
+ * assessment of protein structure template quality". Proteins 57: 702 -
+ * 710.
+ *
+ * @param atomSet1
+ * atom array 1
+ * @param atomSet2
+ * atom array 2
+ * @param len1
+ * The full length of the protein supplying atomSet1
+ * @param len2
+ * The full length of the protein supplying atomSet2
+ * @return The TM-Score
+ * @throws StructureException
+ * @see {@link #getTMScore(Atom[], Atom[], int, int)}, which normalizes by
+ * the minimum length
+ */
+ public static double getTMScoreAlternate(Atom[] atomSet1, Atom[] atomSet2,
+ int len1, int len2) throws StructureException {
+ if (atomSet1.length != atomSet2.length) {
+ throw new StructureException(
+ "The two atom sets are not of same length!");
+ }
+ if (atomSet1.length > len1) {
+ throw new StructureException(
+ "len1 must be greater or equal to the alignment length!");
+ }
+ if (atomSet2.length > len2) {
+ throw new StructureException(
+ "len2 must be greater or equal to the alignment length!");
+ }
+
+ int Lmax = Math.max(len1, len2);
+ int Laln = atomSet1.length;
+
+ double d0 = 1.24 * Math.cbrt(Lmax - 15.) - 1.8;
+ double d0sq = d0 * d0;
+
+ double sum = 0;
+ for (int i = 0; i < Laln; i++) {
+ double d = Calc.getDistance(atomSet1[i], atomSet2[i]);
+ sum += 1. / (1 + d * d / d0sq);
+ }
+
+ return sum / Lmax;
+ }
+
+ /**
+ * Calculate the TM-Score for the superposition.
+ *
+ * Normalizes by the minimum-length structure (that is, {@code min\{len1,len2\}}).
+ *
+ * Atom sets must be pre-rotated.
+ *
+ *
+ * Citation:
+ * Zhang Y and Skolnick J (2004). "Scoring function for automated
+ * assessment of protein structure template quality". Proteins 57: 702 -
+ * 710.
+ *
+ * @param atomSet1
+ * atom array 1
+ * @param atomSet2
+ * atom array 2
+ * @param len1
+ * The full length of the protein supplying atomSet1
+ * @param len2
+ * The full length of the protein supplying atomSet2
+ * @return The TM-Score
+ * @throws StructureException
+ */
+ public static double getTMScore(Atom[] atomSet1, Atom[] atomSet2, int len1,
+ int len2) throws StructureException {
+ if (atomSet1.length != atomSet2.length) {
+ throw new StructureException(
+ "The two atom sets are not of same length!");
+ }
+ if (atomSet1.length > len1) {
+ throw new StructureException(
+ "len1 must be greater or equal to the alignment length!");
+ }
+ if (atomSet2.length > len2) {
+ throw new StructureException(
+ "len2 must be greater or equal to the alignment length!");
+ }
+
+ int Lmin = Math.min(len1, len2);
+ int Laln = atomSet1.length;
+
+ double d0 = 1.24 * Math.cbrt(Lmin - 15.) - 1.8;
+ double d0sq = d0 * d0;
+
+ double sum = 0;
+ for (int i = 0; i < Laln; i++) {
+ double d = Calc.getDistance(atomSet1[i], atomSet2[i]);
+ sum += 1. / (1 + d * d / d0sq);
+ }
+
+ return sum / Lmin;
+ }
}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/SVDSuperimposer.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/SVDSuperimposer.java
deleted file mode 100644
index 6bd953dc19..0000000000
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/SVDSuperimposer.java
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * 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;
-
-import javax.vecmath.Matrix4d;
-import javax.vecmath.Point3d;
-
-import org.biojava.nbio.structure.geometry.CalcPoint;
-import org.biojava.nbio.structure.jama.Matrix;
-import org.biojava.nbio.structure.jama.SingularValueDecomposition;
-
-
-/** A class that calculates the superimposition between two sets of atoms
- * inspired by the biopython SVDSuperimposer class...
- *
- *
- * example usage:
- *
- // get some arbitrary amino acids from somewhere
- String filename = "/Users/ap3/WORK/PDB/5pti.pdb" ;
-
- PDBFileReader pdbreader = new PDBFileReader();
- Structure struc = pdbreader.getStructure(filename);
- Group g1 = (Group)struc.getChain(0).getGroup(21).clone();
- Group g2 = (Group)struc.getChain(0).getGroup(53).clone();
-
- if ( g1.getPDBName().equals("GLY")){
- if ( g1 instanceof AminoAcid){
- Atom cb = Calc.createVirtualCBAtom((AminoAcid)g1);
- g1.addAtom(cb);
- }
- }
-
- if ( g2.getPDBName().equals("GLY")){
- if ( g2 instanceof AminoAcid){
- Atom cb = Calc.createVirtualCBAtom((AminoAcid)g2);
- g2.addAtom(cb);
- }
- }
-
- Structure struc2 = new StructureImpl((Group)g2.clone());
-
- System.out.println(g1);
- System.out.println(g2);
-
-
- Atom[] atoms1 = new Atom[3];
- Atom[] atoms2 = new Atom[3];
-
- atoms1[0] = g1.getAtom("N");
- atoms1[1] = g1.getAtom("CA");
- atoms1[2] = g1.getAtom("CB");
-
-
- atoms2[0] = g2.getAtom("N");
- atoms2[1] = g2.getAtom("CA");
- atoms2[2] = g2.getAtom("CB");
-
-
- SVDSuperimposer svds = new SVDSuperimposer(atoms1,atoms2);
-
-
- Matrix rotMatrix = svds.getRotation();
- Atom tranMatrix = svds.getTranslation();
-
-
- // now we have all the info to perform the rotations ...
-
- Calc.rotate(struc2,rotMatrix);
-
- // shift structure 2 onto structure one ...
- Calc.shift(struc2,tranMatrix);
-
- //
- // write the whole thing to a file to view in a viewer
-
- String outputfile = "/Users/ap3/WORK/PDB/rotated.pdb";
-
- FileOutputStream out= new FileOutputStream(outputfile);
- PrintStream p = new PrintStream( out );
-
- Structure newstruc = new StructureImpl();
-
- Chain c1 = new ChainImpl();
- c1.setName("A");
- c1.addGroup(g1);
- newstruc.addChain(c1);
-
- Chain c2 = struc2.getChain(0);
- c2.setName("B");
- newstruc.addChain(c2);
-
- // show where the group was originally ...
- Chain c3 = new ChainImpl();
- c3.setName("C");
- //c3.addGroup(g1);
- c3.addGroup(g2);
-
- newstruc.addChain(c3);
- p.println(newstruc.toPDB());
-
- p.close();
-
- System.out.println("wrote to file " + outputfile);
-
-
-
- * TODO the documentaton should contain a reference and explanation
- * of the algorithm, rather than example code.
- * The example should go to demo (Aleix 08/2016)
- *
- * @author Andreas Prlic
- * @since 1.5
- * @version %I% %G%
-
- */
-public class SVDSuperimposer {
-
- private Matrix rot;
- private Matrix tran;
-
- private Matrix centroidA;
- private Matrix centroidB;
-
- /** Create a SVDSuperimposer object and calculate a SVD
- * superimposition of two sets of atoms.
- *
- * @param atomSet1 Atom array 1, fixed
- * @param atomSet2 Atom array 2, moved/transformed
- * @throws StructureException
- */
- public SVDSuperimposer(Atom[] atomSet1,Atom[]atomSet2)
- throws StructureException{
-
- if ( atomSet1.length != atomSet2.length ){
- throw new StructureException("The two atom sets are not of same length!");
- }
-
- Atom cena = Calc.getCentroid(atomSet1);
- Atom cenb = Calc.getCentroid(atomSet2);
-
- double[][] centAcoords = new double[][]{{cena.getX(),cena.getY(),cena.getZ()}};
- centroidA = new Matrix(centAcoords);
-
- double[][] centBcoords = new double[][]{{cenb.getX(),cenb.getY(),cenb.getZ()}};
- centroidB = new Matrix(centBcoords);
-
- // center at centroid
-
- Atom[] ats1 = Calc.centerAtoms(atomSet1,cena);
- Atom[] ats2 = Calc.centerAtoms(atomSet2,cenb);
-
- 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] = ats1[i].getCoords();
- coordSet2[i] = ats2[i].getCoords();
- }
-
- calculate(coordSet1,coordSet2);
-
- }
-
- /** Create a SVDSuperimposer object and calculate a SVD
- * superimposition of two sets of points.
- *
- * @param pointSet1 Point3d array 1, fixed
- * @param pointSet2 Point3d array 2, moved/ transformed
- * @throws StructureException
- */
- public SVDSuperimposer(Point3d[] pointSet1, Point3d[] pointSet2)
- throws StructureException{
-
- if ( pointSet1.length != pointSet2.length ){
- throw new StructureException("The two point sets are not of same length!");
- }
-
- Point3d cena = CalcPoint.centroid(pointSet1);
- Point3d cenb = CalcPoint.centroid(pointSet2);
-
- double[][] centAcoords = new double[][]{{cena.x,cena.y,cena.z}};
- centroidA = new Matrix(centAcoords);
-
- double[][] centBcoords = new double[][]{{cenb.x,cenb.x,cenb.x}};
- centroidB = new Matrix(centBcoords);
-
- // center at centroid
-
- cena.negate();
- cenb.negate();
-
- Point3d[] ats1 = CalcPoint.clonePoint3dArray(pointSet1);
- CalcPoint.translate(cena, ats1);
-
- Point3d[] ats2 = CalcPoint.clonePoint3dArray(pointSet2);
- CalcPoint.translate(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]);
- }
-
- calculate(coordSet1,coordSet2);
-
- }
-
-
- /** Do the actual calculation.
- *
- * @param coordSet1 coordinates for atom array 1
- * @param coordSet2 coordiantes for atom array 2
- */
- private void calculate(double[][] coordSet1, double[][]coordSet2){
- // 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);
- 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);
- tran = centroidA.minus(cb_tmp);
-
-
- }
-
- /** Calculate the RMS (root mean square) deviation of two sets of atoms.
- *
- * Atom sets must be pre-rotated.
- *
- * @param atomSet1 atom array 1
- * @param atomSet2 atom array 2
- * @return the RMS of two atom sets
- * @throws StructureException
- */
- public static double getRMS(Atom[] atomSet1, Atom[] atomSet2) throws StructureException {
- if ( atomSet1.length != atomSet2.length ){
- throw new StructureException("The two atom sets are not of same length!");
- }
-
- double sum = 0.0;
- for ( int i =0 ; i < atomSet1.length;i++){
- double d = Calc.getDistance(atomSet1[i],atomSet2[i]);
- sum += (d*d);
-
- }
-
- double avd = ( sum/ atomSet1.length);
- //System.out.println("av dist" + avd);
- return Math.sqrt(avd);
-
- }
-
- /**
- * Calculate the TM-Score for the superposition.
- *
- * Normalizes by the minimum-length structure (that is, {@code min\{len1,len2\}}).
- *
- * Atom sets must be pre-rotated.
- *
- * Citation: Citation:
- * The algorithm is a distance matrix based, rigid body protein structure superimposition.
- * It is based on a variation of the PSC++ algorithm provided by Peter Lackner
- * (Peter.Lackner@sbg.ac.at, personal communication) .
+ * The algorithm is a distance matrix based, rigid body protein structure
+ * superimposition. It is based on a variation of the PSC++ algorithm provided
+ * by Peter Lackner (Peter.Lackner@sbg.ac.at, personal communication) .
*
- * This class uses the {@link SVDSuperimposer} algorithm.
+ * This class uses the {@link SuperPositionSVD} algorithm.
*
* @author Aleix Lafita
* @since 4.2.0
@@ -161,9 +162,9 @@ public void superimpose(MultipleAlignment alignment)
array2 = StructureTools.cloneAtomArray(array2);
//From the superimposer we obtain the rotation and translation
- SVDSuperimposer svd = new SVDSuperimposer(array1, array2);
- Calc.transform(array2, svd.getTransformation());
- transforms.add(svd.getTransformation());
+ Matrix4d trans = SuperPositions.superpose(Calc.atomsToPoints(array1),
+ Calc.atomsToPoints(array2));
+ transforms.add(trans);
}
//Set transformation of the BlockSet
bs.setTransformations(transforms);
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/align/multiple/util/MultipleAlignmentScorer.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/align/multiple/util/MultipleAlignmentScorer.java
index ed8315eb66..1422348e6d 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/align/multiple/util/MultipleAlignmentScorer.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/align/multiple/util/MultipleAlignmentScorer.java
@@ -26,7 +26,6 @@
import org.biojava.nbio.structure.Atom;
import org.biojava.nbio.structure.Calc;
-import org.biojava.nbio.structure.SVDSuperimposer;
import org.biojava.nbio.structure.StructureException;
import org.biojava.nbio.structure.align.multiple.MultipleAlignment;
import org.biojava.nbio.structure.jama.Matrix;
@@ -289,7 +288,7 @@ public static double getAvgTMScore(List
- * This class uses the {@link SVDSuperimposer} algorithm.
+ * This class uses the {@link SuperPositionSVD} algorithm.
*
* @author Spencer Bliven
* @author Aleix Lafita
@@ -150,9 +151,9 @@ public void superimpose(MultipleAlignment alignment)
array2 = StructureTools.cloneAtomArray(array2);
//From the superimposer we obtain the rotation and translation
- SVDSuperimposer svd = new SVDSuperimposer(array1, array2);
- Calc.transform(array2, svd.getTransformation());
- transforms.add(svd.getTransformation());
+ Matrix4d trans = SuperPositions.superpose(Calc.atomsToPoints(array1),
+ Calc.atomsToPoints(array2));
+ transforms.add(trans);
}
//Set transformation of the BlockSet
bs.setTransformations(transforms);
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/align/pairwise/AlternativeAlignment.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/align/pairwise/AlternativeAlignment.java
index f049aecd6b..62c5015e8b 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/align/pairwise/AlternativeAlignment.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/align/pairwise/AlternativeAlignment.java
@@ -28,6 +28,8 @@
import org.biojava.nbio.structure.align.helper.AligMatEl;
import org.biojava.nbio.structure.align.helper.IndexPair;
import org.biojava.nbio.structure.align.helper.JointFragments;
+import org.biojava.nbio.structure.geometry.Matrices;
+import org.biojava.nbio.structure.geometry.SuperPositions;
import org.biojava.nbio.structure.jama.Matrix;
import java.io.Serializable;
@@ -35,6 +37,8 @@
import java.util.List;
import java.util.logging.Logger;
+import javax.vecmath.Matrix4d;
+
/**
* Implements a class which handles one possible (alternative) solution.
*
@@ -776,13 +780,14 @@ private void super_pos_alig(Atom[]ca1,Atom[]ca2,int[] idx1, int[] idx2, boolean
ca2subset[i] = (Atom) ca2[pos2].clone();
}
- SVDSuperimposer svd = new SVDSuperimposer(ca1subset,ca2subset);
- this.currentRotMatrix = svd.getRotation();
- this.currentTranMatrix = svd.getTranslation();
+ Matrix4d trans = SuperPositions.superpose(Calc.atomsToPoints(ca1subset),
+ Calc.atomsToPoints(ca2subset));
+ this.currentRotMatrix = Matrices.getRotationJAMA(trans);
+ this.currentTranMatrix = Calc.getTranslationVector(trans);
//currentRotMatrix.print(3,3);
if ( getRMS) {
rotateShiftAtoms(ca2subset);
- this.rms = SVDSuperimposer.getRMS(ca1subset,ca2subset);
+ this.rms = Calc.rmsd(ca1subset,ca2subset);
}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/align/pairwise/FragmentJoiner.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/align/pairwise/FragmentJoiner.java
index 3a6bc141fa..47cac82c94 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/align/pairwise/FragmentJoiner.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/align/pairwise/FragmentJoiner.java
@@ -24,7 +24,6 @@
import org.biojava.nbio.structure.Atom;
import org.biojava.nbio.structure.Calc;
-import org.biojava.nbio.structure.SVDSuperimposer;
import org.biojava.nbio.structure.StructureException;
import org.biojava.nbio.structure.align.StrucAligParameters;
import org.biojava.nbio.structure.align.helper.AlignTools;
@@ -314,7 +313,7 @@ public static double getRMS(Atom[] ca1, Atom[]ca2,JointFragments frag) throws St
Calc.shift(a, atom);
}
- rms = SVDSuperimposer.getRMS(ca1subset,ca2subset);
+ rms = Calc.rmsd(ca1subset,ca2subset);
return rms;
}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/align/quaternary/QsAlign.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/align/quaternary/QsAlign.java
index 928d343c72..83cd550e61 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/align/quaternary/QsAlign.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/align/quaternary/QsAlign.java
@@ -11,7 +11,6 @@
import org.biojava.nbio.structure.Atom;
import org.biojava.nbio.structure.Calc;
-import org.biojava.nbio.structure.SVDSuperimposer;
import org.biojava.nbio.structure.Structure;
import org.biojava.nbio.structure.StructureException;
import org.biojava.nbio.structure.StructureTools;
@@ -30,6 +29,7 @@
import org.biojava.nbio.structure.cluster.SubunitClustererParameters;
import org.biojava.nbio.structure.cluster.SubunitExtractor;
import org.biojava.nbio.structure.contact.Pair;
+import org.biojava.nbio.structure.geometry.SuperPositions;
import org.biojava.nbio.structure.geometry.UnitQuaternions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -180,7 +180,7 @@ public static QsAlignResult align(List
@@ -899,9 +904,13 @@ public static void updateSuperposition(AFPChain afpChain, Atom[] ca1, Atom[] ca2
}
//Superimpose the two structures in correspondance to the new alignment
- SVDSuperimposer svd = new SVDSuperimposer(ca1aligned, ca2aligned);
- Matrix matrix = svd.getRotation();
- Atom shift = svd.getTranslation();
+ Matrix4d trans = SuperPositions.superpose(Calc.atomsToPoints(ca1aligned),
+ Calc.atomsToPoints(ca2aligned));
+
+ Matrix matrix = Matrices.getRotationJAMA(trans);
+ Atom shift = Calc.getTranslationVector(trans);
+
+
Matrix[] blockMxs = new Matrix[afpChain.getBlockNum()];
Arrays.fill(blockMxs, matrix);
afpChain.setBlockRotationMatrix(blockMxs);
@@ -915,8 +924,8 @@ public static void updateSuperposition(AFPChain afpChain, Atom[] ca1, Atom[] ca2
}
//Calculate the RMSD and TM score for the new alignment
- double rmsd = SVDSuperimposer.getRMS(ca1aligned, ca2aligned);
- double tmScore = SVDSuperimposer.getTMScore(ca1aligned, ca2aligned, ca1.length, ca2.length);
+ double rmsd = Calc.rmsd(ca1aligned, ca2aligned);
+ double tmScore = Calc.getTMScore(ca1aligned, ca2aligned, ca1.length, ca2.length);
afpChain.setTotalRmsdOpt(rmsd);
afpChain.setTMScore(tmScore);
@@ -944,16 +953,17 @@ public static void updateSuperposition(AFPChain afpChain, Atom[] ca1, Atom[] ca2
ca2block = (Atom[]) resizeArray(ca2block, position);
}
//Superimpose the two block structures
- SVDSuperimposer svdb = new SVDSuperimposer(ca1block, ca2block);
- Matrix matrixb = svdb.getRotation();
- Atom shiftb = svdb.getTranslation();
- for (Atom a : ca2block) {
- Calc.rotate(a, matrixb);
- Calc.shift(a, shiftb);
- }
+ Matrix4d transb = SuperPositions.superpose(Calc.atomsToPoints(ca1block),
+ Calc.atomsToPoints(ca2block));
+
+ Matrix matrixb = Matrices.getRotationJAMA(trans);
+ Atom shiftb = Calc.getTranslationVector(trans);
+
+ Calc.transform(ca2block, transb);
+
//Calculate the RMSD and TM score for the block
- double rmsdb = SVDSuperimposer.getRMS(ca1block, ca2block);
- double tmScoreb = SVDSuperimposer.getTMScore(ca1block, ca2block, ca1.length, ca2.length);
+ double rmsdb = Calc.rmsd(ca1block, ca2block);
+ double tmScoreb = Calc.getTMScore(ca1block, ca2block, ca1.length, ca2.length);
blockRMSD[k] = rmsdb;
blockScore[k] = tmScoreb;
}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/align/util/AtomCache.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/align/util/AtomCache.java
index 26d717e849..ecb0c8f665 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/align/util/AtomCache.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/align/util/AtomCache.java
@@ -72,7 +72,7 @@ public class AtomCache {
* The default output bioassembly style: if true the bioassemblies are multimodel,
* if false the bioassemblies are flat with renamed chains for symmetry-partners.
*/
- public static final boolean DEFAULT_BIOASSEMBLY_STYLE = true;
+ public static final boolean DEFAULT_BIOASSEMBLY_STYLE = false;
public static final String BIOL_ASSEMBLY_IDENTIFIER = "BIO:";
public static final String CHAIN_NR_SYMBOL = ":";
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/align/util/RotationAxis.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/align/util/RotationAxis.java
index 779e78be6c..91d87512e1 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/align/util/RotationAxis.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/align/util/RotationAxis.java
@@ -26,6 +26,7 @@
import org.biojava.nbio.structure.StructureException;
import org.biojava.nbio.structure.align.model.AFPChain;
import org.biojava.nbio.structure.contact.Pair;
+import org.biojava.nbio.structure.geometry.Matrices;
import org.biojava.nbio.structure.jama.Matrix;
import javax.vecmath.AxisAngle4d;
@@ -175,7 +176,7 @@ public RotationAxis(Matrix rotation, Atom translation) {
*/
public RotationAxis(Matrix4d transform) {
- Matrix rot = Calc.getRotationMatrix(transform);
+ Matrix rot = Matrices.getRotationJAMA(transform);
Atom transl = Calc.getTranslationVector(transform);
init(rot,transl);
}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/cluster/SubunitExtractor.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/cluster/SubunitExtractor.java
index d5e943a6c8..bb628f37aa 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/cluster/SubunitExtractor.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/cluster/SubunitExtractor.java
@@ -68,31 +68,24 @@ public static List
+ * This class complements and extends the functionallity of vecmath and JAMA.
+ *
+ * @author Aleix Lafita
+ * @since 5.0.0
+ *
+ */
+public class Matrices {
+
+ /** Prevent instantiation */
+ private Matrices(){}
+
+ /**
+ * Convert a transformation matrix into a JAMA rotation matrix. Because the
+ * JAMA matrix is a pre-multiplication matrix and the Vecmath matrix is a
+ * post-multiplication one, the rotation matrix is transposed to ensure that
+ * the transformation they produce is the same.
+ *
+ * @param transform
+ * Matrix4d with transposed rotation matrix
+ * @return rotation matrix as JAMA object
+ */
+ public static Matrix getRotationJAMA(Matrix4d transform) {
+
+ Matrix rot = new Matrix(3, 3);
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ rot.set(j, i, transform.getElement(i, j)); // transposed
+ }
+ }
+ return rot;
+ }
+
+ /**
+ * Convert a transformation matrix into a rotation matrix.
+ *
+ * @param transform
+ * Matrix4d
+ * @return rotation matrix
+ */
+ public static Matrix3d getRotationMatrix(Matrix4d transform) {
+
+ Matrix3d rot = new Matrix3d();
+ transform.setRotationScale(rot);
+ return rot;
+ }
+
+ /**
+ * Extract the translational vector of a transformation matrix.
+ *
+ * @param transform
+ * Matrix4d
+ * @return Vector3d translation vector
+ */
+ public static Vector3d getTranslationVector(Matrix4d transform) {
+ Vector3d transl = new Vector3d();
+ transform.get(transl);
+ return transl;
+ }
+
+ /**
+ * Convert JAMA rotation and translation to a Vecmath transformation matrix.
+ * Because the JAMA matrix is a pre-multiplication matrix and the Vecmath
+ * matrix is a post-multiplication one, the rotation matrix is transposed to
+ * ensure that the transformation they produce is the same.
+ *
+ * @param rot
+ * 3x3 Rotation matrix
+ * @param trans
+ * 3x1 Translation matrix
+ * @return 4x4 transformation matrix
+ */
+ public static Matrix4d getTransformation(Matrix rot, Matrix trans) {
+ return new Matrix4d(new Matrix3d(rot.getColumnPackedCopy()),
+ new Vector3d(trans.getColumnPackedCopy()), 1.0);
+ }
+
+}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPosition.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPosition.java
index f7abe7deb0..b5844da94d 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPosition.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPosition.java
@@ -1,305 +1,79 @@
-/*
- * 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/
- *
- */
package org.biojava.nbio.structure.geometry;
-import javax.vecmath.*;
+import javax.vecmath.Matrix4d;
+import javax.vecmath.Point3d;
/**
- * The SuperPosition is a static Class that contains methods to superpose arrays
- * of Points in 3D.
- *
- * @author Peter Rose
+ * The SuperPosition interface defines and documents the required methods for
+ * any superpostion algorithm implementation, so that the input and expected
+ * output are uniform.
*
+ * @author Aleix Lafita
+ * @since 5.0.0
+ *
*/
-public final class SuperPosition {
-
- /** Prevent instantiation */
- private SuperPosition() {
- }
-
- /**
- * This method superposes x onto y, so it transforms the coordinates of x.
- * The translation component of the matrix is wrong.
- *
- * @param x
- * point array, point coordinates will be modified
- * @param y
- * point array, point coordinates will not be modified
- * @return the Matrix4d used for superposition, without translation
- * @deprecated use {@link #superposeWithTranslation(Point3d[], Point3d[])}
- */
- @Deprecated
- public static Matrix4d superpose(Point3d[] x, Point3d[] y) {
- // superpose x onto y
- Point3d[] ref = CalcPoint.clonePoint3dArray(y);
-
- Point3d ytrans = CalcPoint.centroid(ref);
- ytrans.negate();
- CalcPoint.translate(ytrans, ref);
-
- CalcPoint.center(x);
-
- // calculate quaternion from relative orientation
- Quat4d q = UnitQuaternions.relativeOrientation(x, ref);
-
- Matrix4d rotTrans = new Matrix4d();
- rotTrans.set(q);
-
- // set translational component of transformation matrix TODO wrong
- ytrans.negate();
- rotTrans.setTranslation(new Vector3d(ytrans));
-
- // tranform coordinates
- CalcPoint.transform(rotTrans, x);
-
- return rotTrans;
- }
+public interface SuperPosition {
/**
- * This method superposes x onto y, so it transforms the coordinates of x.
+ * Obtain the superposition matrix that minimizes the RMSD between two
+ * arrays of equivalent points.
+ *
+ * The two point arrays have to be of the same length and the order of
+ * points have to be the same, so that a specific position in the one array
+ * is equivalent to the same position in the other array.
*
- * @param x
- * point array, point coordinates will be modified
- * @param y
- * point array, point coordinates will not be modified
- * @return the Matrix4d used for superposition
+ * @param fixed
+ * point array as reference, onto which the other point array is
+ * superposed. Original coordinates will not be modified.
+ * @param moved
+ * point array to which the resulting transformation matrix is
+ * applied. Original coordinates will not be modified.
+ * @return transformation matrix as a Matrix4d to superpose moved onto fixed
+ * point arrays
*/
- public static Matrix4d superposeWithTranslation(Point3d[] x, Point3d[] y) {
-
- // translate to origin
- Point3d[] xref = CalcPoint.clonePoint3dArray(x);
- Point3d xtrans = CalcPoint.centroid(xref);
- xtrans.negate();
- CalcPoint.translate(xtrans, xref);
-
- Point3d[] yref = CalcPoint.clonePoint3dArray(y);
- Point3d ytrans = CalcPoint.centroid(yref);
- ytrans.negate();
- CalcPoint.translate(ytrans, yref);
-
- // calculate rotational component (rotation around origin)
- Quat4d q = UnitQuaternions.relativeOrientation(xref, yref);
- Matrix4d rotTrans = new Matrix4d();
- rotTrans.set(q);
-
- // combine with x -> origin translation
- Matrix4d trans = new Matrix4d();
- trans.setIdentity();
- trans.setTranslation(new Vector3d(xtrans));
- rotTrans.mul(rotTrans, trans);
-
- // combine with origin -> y translation
- ytrans.negate();
- Matrix4d transInverse = new Matrix4d();
- transInverse.setIdentity();
- transInverse.setTranslation(new Vector3d(ytrans));
- rotTrans.mul(transInverse, rotTrans);
-
- // transform x coordinates onto y coordinate frame
- CalcPoint.transform(rotTrans, x);
-
- return rotTrans;
- }
+ public Matrix4d superpose(Point3d[] fixed, Point3d[] moved);
/**
- * This method superposes x onto y, so it transforms the coordinates of x.
- * It requires the points to be centered (use
- * {@link CalcPoint#center(Point3d[])}, because the transformation matrix
- * will not have translation component (faster).
+ * Transform an array of points so that the coordinates of its points
+ * minimize the RMSD to the other array of equivalent points, and return the
+ * transformation matrix applied.
+ *
+ * The two point arrays have to be of the same length and the order of
+ * points have to be the same, so that a specific position in the one array
+ * is equivalent to the same position in the other array.
*
- * @param x
- * point array, point coordinates will be modified
- * @param y
- * point array, point coordinates will not be modified
- * @return the Matrix4d used for superposition, without translation
+ * @param fixed
+ * point array as reference, onto which the other point array is
+ * superposed. Original coordinates will not be modified.
+ * @param moved
+ * point array to which the resulting transformation matrix is
+ * applied. Original coordinates will be transformed.
+ * @return transformation matrix as a Matrix4d to superpose moved onto fixed
+ * point arrays
*/
- public static Matrix4d superposeAtOrigin(Point3d[] x, Point3d[] y) {
- Quat4d q = UnitQuaternions.relativeOrientation(x, y);
-
- Matrix4d rotTrans = new Matrix4d();
- rotTrans.set(q);
-
- CalcPoint.transform(rotTrans, x);
-
- return rotTrans;
- }
+ public Matrix4d superposeAndTransform(Point3d[] fixed, Point3d[] moved);
/**
- * This method superposes x onto y, so it transforms the coordinates of x.
- * It requires the points to be centered (use
- * {@link CalcPoint#center(Point3d[])}, because the transformation matrix
- * will not have translation component (faster).
+ * Calculate the RMSD between two arrays of equivalent points that are not
+ * superposed.
+ *
+ * This is equivalent to first superposing the point arrays with
+ * {@link SuperPosition#superposeAndTransform(Point3d[], Point3d[])} and
+ * then calculating the RMSD of the superposed point arrays with
+ * {@link CalcPoint#rmsd(Point3d[], Point3d[])}, but it will be faster when
+ * the transformation matrix is not needed.
+ *
+ * The two point arrays have to be of the same length and the order of
+ * points have to be the same, so that a specific position in the one array
+ * is equivalent to the same position in the other array.
*
* @param x
- * point array, point coordinates will be modified
- * @param y
- * point array, point coordinates will not be modified
- * @param axisAngle
- * to be filled with rotation axis
- * @return the Matrix4d used for superposition, without translation
- */
- public static Matrix4d superposeAtOrigin(Point3d[] x, Point3d[] y,
- AxisAngle4d axisAngle) {
- Quat4d q = UnitQuaternions.relativeOrientation(x, y);
- Matrix4d rotTrans = new Matrix4d();
- rotTrans.setIdentity();
- rotTrans.set(q);
- axisAngle.set(q);
- Vector3d axis = new Vector3d(axisAngle.x, axisAngle.y, axisAngle.z);
- if (axis.lengthSquared() < 1.0E-6) {
- // System.err.println("Error: SuperPosition.superposeAtOrigin: axis vector undefined!");
- axisAngle.x = 0;
- axisAngle.y = 0;
- axisAngle.z = 1;
- axisAngle.angle = 0;
- } else {
- axis.normalize();
- axisAngle.x = axis.x;
- axisAngle.y = axis.y;
- axisAngle.z = axis.z;
- }
- CalcPoint.transform(rotTrans, x);
-
- return rotTrans;
- }
-
- /**
- * Calculate the RMSD of two point arrays, already superposed.
- *
- * @param x
- * array of points superposed to y
- * @param y
- * array of points superposed to x
- * @return RMSD
- */
- public static double rmsd(Point3d[] x, Point3d[] y) {
- double sum = 0.0;
- for (int i = 0; i < x.length; i++) {
- sum += x[i].distanceSquared(y[i]);
- }
- return Math.sqrt(sum / x.length);
- }
-
- /*
- * Needs documentation!
- *
- * @param x
- *
- * @param y
- *
- * @return
- */
- public static double rmsdMin(Point3d[] x, Point3d[] y) {
- double sum = 0.0;
- for (int i = 0; i < x.length; i++) {
- double minDist = Double.MAX_VALUE;
- for (int j = 0; j < y.length; j++) {
- minDist = Math.min(minDist, x[i].distanceSquared(y[j]));
- }
- sum += minDist;
- }
- return Math.sqrt(sum / x.length);
- }
-
- /**
- * Returns the TM-Score for two superimposed sets of coordinates Yang Zhang
- * and Jeffrey Skolnick, PROTEINS: Structure, Function, and Bioinformatics
- * 57:702–710 (2004)
- *
- * @param x
- * coordinate set 1
- * @param y
- * coordinate set 2
- * @param lengthNative
- * total length of native sequence
- * @return
- */
- public static double TMScore(Point3d[] x, Point3d[] y, int lengthNative) {
- double d0 = 1.24 * Math.cbrt(x.length - 15.0) - 1.8;
- double d0Sq = d0 * d0;
-
- double sum = 0;
- for (int i = 0; i < x.length; i++) {
- sum += 1.0 / (1.0 + x[i].distanceSquared(y[i]) / d0Sq);
- }
-
- return sum / lengthNative;
- }
-
- /*
- * Needs documentation!
- *
- * @param x
- * @param y
- * @return
- */
- public static double GTSlikeScore(Point3d[] x, Point3d[] y) {
- int contacts = 0;
-
- for (Point3d px : x) {
- double minDist = Double.MAX_VALUE;
-
- for (Point3d py : y) {
- minDist = Math.min(minDist, px.distanceSquared(py));
- }
-
- if (minDist > 64)
- continue;
- contacts++;
-
- if (minDist > 16)
- continue;
- contacts++;
-
- if (minDist > 4)
- continue;
- contacts++;
-
- if (minDist > 1)
- continue;
- contacts++;
- }
-
- return contacts * 25.0 / x.length;
- }
-
- /*
- * Needs documentation!
- * @param x
+ * an array of points. Original coordinates will not be modified.
* @param y
- * @param maxDistance
- * @return
+ * an array of points. Original coordinates will not be modified.
+ * @return the minimum RMSD between the equivalent point arrays (after
+ * superposition)
*/
- public static int contacts(Point3d[] x, Point3d[] y, double maxDistance) {
- int contacts = 0;
- for (int i = 0; i < x.length; i++) {
- double minDist = Double.MAX_VALUE;
- for (int j = 0; j < y.length; j++) {
- minDist = Math.min(minDist, x[i].distanceSquared(y[j]));
- }
- if (minDist < maxDistance * maxDistance) {
- contacts++;
- }
- }
- return contacts;
- }
+ public double getRmsd(Point3d[] x, Point3d[] y);
}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositionAbstract.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositionAbstract.java
new file mode 100644
index 0000000000..6107e6c266
--- /dev/null
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositionAbstract.java
@@ -0,0 +1,50 @@
+package org.biojava.nbio.structure.geometry;
+
+import javax.vecmath.Matrix4d;
+import javax.vecmath.Point3d;
+
+/**
+ * The SuperPositionAbstract contains common code shared by all SuperPosition
+ * algorithm implementations.
+ *
+ * @author Aleix Lafita
+ * @since 5.0.0
+ *
+ */
+public abstract class SuperPositionAbstract implements SuperPosition {
+
+ protected boolean centered;
+
+ public SuperPositionAbstract(boolean centered) {
+ this.centered = centered;
+ }
+
+ @Override
+ public Matrix4d superposeAndTransform(Point3d[] fixed, Point3d[] moved) {
+ Matrix4d rotTrans = superpose(fixed, moved);
+ CalcPoint.transform(rotTrans, moved);
+ return rotTrans;
+ }
+
+ /**
+ * Check that the input to the superposition algorithms is valid.
+ *
+ * @param fixed
+ * @param moved
+ */
+ protected void checkInput(Point3d[] fixed, Point3d[] moved) {
+ if (fixed.length != moved.length)
+ throw new IllegalArgumentException(
+ "Point arrays to superpose are of different lengths.");
+ }
+
+ /**
+ * @param centered
+ * true if the point arrays are centered at the origin (faster),
+ * false otherwise
+ */
+ public void setCentered(boolean centered) {
+ this.centered = centered;
+ }
+
+}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositionQCP.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositionQCP.java
index 765762d5e4..a5d9a4aa1c 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositionQCP.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositionQCP.java
@@ -107,20 +107,13 @@
* @author Peter Rose (adopted to Java)
* @author Aleix Lafita (adopted to Java)
*/
-public final class SuperPositionQCP {
+public final class SuperPositionQCP extends SuperPositionAbstract {
private static final Logger logger = LoggerFactory
.getLogger(SuperPositionQCP.class);
- /**
- * The required eigenvector precission
- */
- private static final double EVEC_PREC = 1E-6;
-
- /**
- * The required eigenvalue precission
- */
- private static final double EVAL_PREC = 1E-11;
+ private double evec_prec = 1E-6;
+ private double eval_prec = 1E-11;
private Point3d[] x;
private Point3d[] y;
@@ -145,20 +138,30 @@ public final class SuperPositionQCP {
private boolean transformationCalculated = false;
private boolean centered = false;
- /**
- * Default constructor
- */
- public SuperPositionQCP() {
- this.centered = false;
+ /**
+ * Default constructor for the quaternion based superposition algorithm.
+ *
+ * @param centered
+ * true if the point arrays are centered at the origin (faster),
+ * false otherwise
+ */
+ public SuperPositionQCP(boolean centered) {
+ super(centered);
}
/**
- * Constructor with option to set centered flag. This constructor
- * should be used if both coordinate input set have been centered at the origin.
- * @param centered if set true, the input coordinates are already centered at the origin
+ * Constructor with option to set the precision values.
+ *
+ * @param centered
+ * true if the point arrays are centered at the origin (faster),
+ * false otherwise
+ * @param evec_prec required eigenvector precision
+ * @param eval_prec required eigenvalue precision
*/
- public SuperPositionQCP(boolean centered) {
- this.centered = centered;
+ public SuperPositionQCP(boolean centered, double evec_prec, double eval_prec) {
+ super(centered);
+ this.evec_prec = evec_prec;
+ this.eval_prec = eval_prec;
}
/**
@@ -167,7 +170,7 @@ public SuperPositionQCP(boolean centered) {
* @param x 3d points of reference coordinate set
* @param y 3d points of coordinate set for superposition
*/
- public void set(Point3d[] x, Point3d[] y) {
+ private void set(Point3d[] x, Point3d[] y) {
this.x = x;
this.y = y;
rmsdCalculated = false;
@@ -182,7 +185,7 @@ public void set(Point3d[] x, Point3d[] y) {
* @param y 3d points of coordinate set for superposition
* @param weight a weight in the inclusive range [0,1] for each point
*/
- public void set(Point3d[] x, Point3d[] y, double[] weight) {
+ private void set(Point3d[] x, Point3d[] y, double[] weight) {
this.x = x;
this.y = y;
this.weight = weight;
@@ -190,10 +193,6 @@ public void set(Point3d[] x, Point3d[] y, double[] weight) {
transformationCalculated = false;
}
- public void setCentered(boolean centered) {
- this.centered = centered;
- }
-
/**
* Return the RMSD of the superposition of input coordinate set y onto x.
* Note, this is the fasted way to calculate an RMSD without actually
@@ -201,19 +200,16 @@ public void setCentered(boolean centered) {
* calculations are only performed if necessary.
* @return root mean square deviation for superposition of y onto x
*/
- public double getRmsd() {
+ private double getRmsd() {
if (!rmsdCalculated) {
calcRmsd(x, y);
}
return rmsd;
}
- /**
- * Returns a 4x4 transformation matrix that transforms the y coordinates onto the x coordinates.
- * The calculation is performed "lazy", meaning calculations are only performed if necessary.
- * @return 4x4 transformation matrix to transform y coordinates onto x
- */
- public Matrix4d getTransformationMatrix() {
+ @Override
+ public Matrix4d superpose(Point3d[] fixed, Point3d[] moved) {
+ set(moved, fixed);
getRotationMatrix();
if (!centered) {
calcTransformation();
@@ -222,8 +218,27 @@ public Matrix4d getTransformationMatrix() {
}
return transformation;
}
+
+ /**
+ * Weighted superposition.
+ *
+ * @param fixed
+ * @param moved
+ * @param weight array of weigths for each equivalent point position
+ * @return
+ */
+ public Matrix4d weightedSuperpose(Point3d[] fixed, Point3d[] moved, double[] weight) {
+ set(moved, fixed, weight);
+ getRotationMatrix();
+ if (!centered) {
+ calcTransformation();
+ } else {
+ transformation.set(rotmat);
+ }
+ return transformation;
+ }
- public Matrix3d getRotationMatrix() {
+ private Matrix3d getRotationMatrix() {
getRmsd();
if (!transformationCalculated) {
calcRotationMatrix();
@@ -231,16 +246,6 @@ public Matrix3d getRotationMatrix() {
return rotmat;
}
- /**
- * Returns the transformed (superposed) y coordinates
- * TODO this is actually returning a transformation of the x coordinates, we should review if that's correct and change it if not
- * @return transformed y coordinates
- */
- public Point3d[] getTransformedCoordinates() {
- CalcPoint.transform(transformation, x);
- return x;
- }
-
/**
* Calculates the RMSD value for superposition of y onto x.
* This requires the coordinates to be precentered.
@@ -433,7 +438,7 @@ private int calcRmsd(double len) {
double delta = ((a * mxEigenV + c0) / (2.0 * x2 * mxEigenV + b + a));
mxEigenV -= delta;
- if (Math.abs(mxEigenV - oldg) < Math.abs(EVAL_PREC*mxEigenV))
+ if (Math.abs(mxEigenV - oldg) < Math.abs(eval_prec*mxEigenV))
break;
}
@@ -488,14 +493,14 @@ private int calcRotationMatrix() {
* commented block will never be activated. To be absolutely safe this
* should be uncommented, but it is most likely unnecessary.
*/
- if (qsqr < EVEC_PREC) {
+ if (qsqr < evec_prec) {
q1 = a12 * a3344_4334 - a13 * a3244_4234 + a14 * a3243_4233;
q2 = -a11 * a3344_4334 + a13 * a3144_4134 - a14 * a3143_4133;
q3 = a11 * a3244_4234 - a12 * a3144_4134 + a14 * a3142_4132;
q4 = -a11 * a3243_4233 + a12 * a3143_4133 - a13 * a3142_4132;
qsqr = q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4;
- if (qsqr < EVEC_PREC) {
+ if (qsqr < evec_prec) {
double a1324_1423 = a13 * a24 - a14 * a23, a1224_1422 = a12
* a24 - a14 * a22;
double a1223_1322 = a12 * a23 - a13 * a22, a1124_1421 = a11
@@ -509,7 +514,7 @@ private int calcRotationMatrix() {
q4 = -a41 * a1223_1322 + a42 * a1123_1321 - a43 * a1122_1221;
qsqr = q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4;
- if (qsqr < EVEC_PREC) {
+ if (qsqr < evec_prec) {
q1 = a32 * a1324_1423 - a33 * a1224_1422 + a34 * a1223_1322;
q2 = -a31 * a1324_1423 + a33 * a1124_1421 - a34
* a1123_1321;
@@ -518,7 +523,7 @@ private int calcRotationMatrix() {
* a1122_1221;
qsqr = q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4;
- if (qsqr < EVEC_PREC) {
+ if (qsqr < evec_prec) {
/*
* if qsqr is still too small, return the identity
* matrix.
@@ -566,4 +571,21 @@ private int calcRotationMatrix() {
return 1;
}
+ @Override
+ public double getRmsd(Point3d[] fixed, Point3d[] moved) {
+ set(moved, fixed);
+ return getRmsd();
+ }
+
+ /**
+ * @param fixed
+ * @param moved
+ * @param weight array of weigths for each equivalent point position
+ * @return weighted RMSD.
+ */
+ public double getWeightedRmsd(Point3d[] fixed, Point3d[] moved, double[] weight) {
+ set(moved, fixed, weight);
+ return getRmsd();
+ }
+
}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositionQuat.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositionQuat.java
new file mode 100644
index 0000000000..1888c0d6b9
--- /dev/null
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositionQuat.java
@@ -0,0 +1,98 @@
+/*
+ * 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/
+ *
+ */
+package org.biojava.nbio.structure.geometry;
+
+import javax.vecmath.*;
+
+/**
+ * The SuperPositionQuat implements a quaternion based algorithm to superpose
+ * arrays of Points in 3D.
+ *
+ * @author Peter Rose
+ * @author Aleix Lafita
+ *
+ */
+public final class SuperPositionQuat extends SuperPositionAbstract {
+
+ /**
+ * Constructor for the quaternion based superposition algorithm.
+ *
+ * @param centered
+ * true if the point arrays are centered at the origin (faster),
+ * false otherwise
+ */
+ public SuperPositionQuat(boolean centered) {
+ super(centered);
+ }
+
+ @Override
+ public Matrix4d superpose(Point3d[] fixed, Point3d[] moved) {
+
+ checkInput(fixed, moved);
+
+ if (centered) {
+ Quat4d q = UnitQuaternions.relativeOrientation(fixed, moved);
+ Matrix4d rotTrans = new Matrix4d();
+ rotTrans.set(q);
+ return rotTrans;
+ }
+
+ // translate to origin
+ Point3d[] xref = CalcPoint.clonePoint3dArray(fixed);
+ Point3d xtrans = CalcPoint.centroid(xref);
+ xtrans.negate();
+ CalcPoint.translate(xtrans, xref);
+
+ Point3d[] yref = CalcPoint.clonePoint3dArray(moved);
+ Point3d ytrans = CalcPoint.centroid(yref);
+ ytrans.negate();
+ CalcPoint.translate(ytrans, yref);
+
+ // calculate rotational component (rotation around origin)
+ Quat4d q = UnitQuaternions.relativeOrientation(xref, yref);
+ Matrix4d rotTrans = new Matrix4d();
+ rotTrans.set(q);
+
+ // combine with moved -> origin translation
+ Matrix4d trans = new Matrix4d();
+ trans.setIdentity();
+ trans.setTranslation(new Vector3d(ytrans));
+ rotTrans.mul(rotTrans, trans);
+
+ // combine with origin -> fixed translation
+ xtrans.negate();
+ Matrix4d transInverse = new Matrix4d();
+ transInverse.setIdentity();
+ transInverse.setTranslation(new Vector3d(xtrans));
+ rotTrans.mul(transInverse, rotTrans);
+
+ return rotTrans;
+
+ }
+
+ @Override
+ public double getRmsd(Point3d[] x, Point3d[] y) {
+ Point3d[] yclone = CalcPoint.clonePoint3dArray(y);
+ superposeAndTransform(x, yclone);
+ return CalcPoint.rmsd(x, yclone);
+ }
+
+}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositionSVD.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositionSVD.java
new file mode 100644
index 0000000000..aa91d254bd
--- /dev/null
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositionSVD.java
@@ -0,0 +1,149 @@
+/*
+ * 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 org.biojava.nbio.structure.Atom;
+import org.biojava.nbio.structure.Calc;
+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);
+ }
+
+ public Matrix4d superpose(Atom[] fixed, Atom[] moved) {
+ return superpose(Calc.atomsToPoints(fixed), Calc.atomsToPoints(moved));
+ }
+
+ @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.x, cenb.x } };
+ Matrix centroidB = new Matrix(centBcoords);
+
+ // center at centroid
+
+ cena.negate();
+ cenb.negate();
+
+ Point3d[] ats1 = CalcPoint.clonePoint3dArray(fixed);
+ CalcPoint.translate(cena, ats1);
+
+ Point3d[] ats2 = CalcPoint.clonePoint3dArray(moved);
+ CalcPoint.translate(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);
+ }
+
+}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositions.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositions.java
new file mode 100644
index 0000000000..56a788a669
--- /dev/null
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/SuperPositions.java
@@ -0,0 +1,87 @@
+package org.biojava.nbio.structure.geometry;
+
+import javax.vecmath.Matrix4d;
+import javax.vecmath.Point3d;
+
+/**
+ * SuperPositions is a Class that provides static helper methods and an easy
+ * access to the whole family of {@link SuperPosition} algorithms.
+ *
+ * It defines a static SuperPosition object and uses it for calculation.
+ *
+ * @author Aleix Lafita
+ * @since 5.0.0
+ *
+ */
+public class SuperPositions {
+
+ private static SuperPositionAbstract superposer = new SuperPositionQuat(
+ false);
+
+ /** Prevent instantiation */
+ private SuperPositions(){}
+
+ /**
+ * Use the {@link SuperPosition#superpose(Point3d[], Point3d[])} method of
+ * the default static SuperPosition algorithm contained in this Class.
+ */
+ public static Matrix4d superpose(Point3d[] fixed, Point3d[] moved) {
+ superposer.setCentered(false);
+ return superposer.superpose(fixed, moved);
+ }
+
+ /**
+ * Use the {@link SuperPosition#superpose(Point3d[], Point3d[])} method of
+ * the default static SuperPosition algorithm contained in this Class,
+ * assuming that the point arrays are centered at the origin.
+ */
+ public static Matrix4d superposeAtOrigin(Point3d[] fixed, Point3d[] moved) {
+ superposer.setCentered(true);
+ return superposer.superpose(fixed, moved);
+ }
+
+ /**
+ * Use the {@link SuperPosition#superposeAndTransform(Point3d[], Point3d[])}
+ * method of the default static SuperPosition algorithm contained in this
+ * Class.
+ */
+ public static Matrix4d superposeAndTransform(Point3d[] fixed,
+ Point3d[] moved) {
+ superposer.setCentered(false);
+ return superposer.superposeAndTransform(fixed, moved);
+ }
+
+ /**
+ * Use the {@link SuperPosition#superposeAndTransform(Point3d[], Point3d[])}
+ * method of the default static SuperPosition algorithm contained in this
+ * Class, assuming that the point arrays are centered at the origin.
+ */
+ public static Matrix4d superposeAndTransformAtOrigin(Point3d[] fixed,
+ Point3d[] moved) {
+ superposer.setCentered(true);
+ return superposer.superposeAndTransform(fixed, moved);
+ }
+
+ /**
+ * Use the {@link SuperPosition#getRmsd(Point3d[], Point3d[])} method of the
+ * default static SuperPosition algorithm contained in this Class.
+ */
+ public static double getRmsd(Point3d[] fixed, Point3d[] moved) {
+ superposer.setCentered(false);
+ return superposer.getRmsd(fixed, moved);
+ }
+
+ /**
+ * Use the {@link SuperPosition#getRmsd(Point3d[], Point3d[])} method of the
+ * default static SuperPosition algorithm contained in this Class, assuming
+ * that the point arrays are centered at the origin.
+ */
+ public static double getRmsdAtOrigin(Point3d[] fixed, Point3d[] moved) {
+ superposer.setCentered(true);
+ return superposer.getRmsd(fixed, moved);
+ }
+
+ public static void setDefaultSuperPosition(SuperPositionAbstract defaultAlgorithm) {
+ superposer = defaultAlgorithm;
+ }
+}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/UnitQuaternions.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/UnitQuaternions.java
index bacb845eca..9b780bb942 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/UnitQuaternions.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/geometry/UnitQuaternions.java
@@ -125,14 +125,18 @@ public static double angle(Quat4d q) {
* The arrays of points need to be centered at the origin. To center the
* points use {@link CalcPoint#center(Point3d[])}.
*
- * @param a
- * array of Point3d, centered at origin
- * @param b
- * array of Point3d, centered at origin
- * @return the angle in radians of the relative orientation of the points
+ * @param fixed
+ * array of Point3d, centered at origin. Original coordinates
+ * will not be modified.
+ * @param moved
+ * array of Point3d, centered at origin. Original coordinates
+ * will not be modified.
+ * @return the angle in radians of the relative orientation of the points,
+ * angle to rotate moved to bring it to the same orientation as
+ * fixed.
*/
- public static double orientationAngle(Point3d[] a, Point3d[] b) {
- Quat4d q = relativeOrientation(a, b);
+ public static double orientationAngle(Point3d[] fixed, Point3d[] moved) {
+ Quat4d q = relativeOrientation(fixed, moved);
return angle(q);
}
@@ -141,36 +145,39 @@ public static double orientationAngle(Point3d[] a, Point3d[] b) {
* Equivalent to {@link #angle(Quat4d)} of the unit quaternion obtained by
* {@link #relativeOrientation(Point3d[], Point3d[])}.
*
- * @param a
- * array of Point3d
- * @param b
- * array of Point3d
+ * @param fixed
+ * array of Point3d. Original coordinates will not be modified.
+ * @param moved
+ * array of Point3d. Original coordinates will not be modified.
* @param centered
* true if the points are already centered at the origin
- * @return the angle in radians of the relative orientation of the points
+ * @return the angle in radians of the relative orientation of the points,
+ * angle to rotate moved to bring it to the same orientation as
+ * fixed.
*/
- public static double orientationAngle(Point3d[] a, Point3d[] b,
+ public static double orientationAngle(Point3d[] fixed, Point3d[] moved,
boolean centered) {
if (!centered) {
- a = CalcPoint.clonePoint3dArray(a);
- b = CalcPoint.clonePoint3dArray(b);
- CalcPoint.center(a);
- CalcPoint.center(b);
+ fixed = CalcPoint.clonePoint3dArray(fixed);
+ moved = CalcPoint.clonePoint3dArray(moved);
+ CalcPoint.center(fixed);
+ CalcPoint.center(moved);
}
- return orientationAngle(a, b);
+ return orientationAngle(fixed, moved);
}
/**
* Calculate the relative quaternion orientation of two arrays of points.
*
- * @param a
- * point array
- * @param b
- * point array
- * @return a unit quaternion representing the relative orientation
+ * @param fixed
+ * point array, coordinates will not be modified
+ * @param moved
+ * point array, coordinates will not be modified
+ * @return a unit quaternion representing the relative orientation, to
+ * rotate moved to bring it to the same orientation as fixed.
*/
- public static Quat4d relativeOrientation(Point3d[] a, Point3d[] b) {
- Matrix m = CalcPoint.formMatrix(a, b);
+ public static Quat4d relativeOrientation(Point3d[] fixed, Point3d[] moved) {
+ Matrix m = CalcPoint.formMatrix(moved, fixed); // inverse
EigenvalueDecomposition eig = m.eig();
double[][] v = eig.getV().getArray();
Quat4d q = new Quat4d(v[1][3], v[2][3], v[3][3], v[0][3]);
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/axis/HelixAxisAligner.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/axis/HelixAxisAligner.java
index 037dd8e277..e90e657a22 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/axis/HelixAxisAligner.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/axis/HelixAxisAligner.java
@@ -20,17 +20,25 @@
*/
package org.biojava.nbio.structure.symmetry.axis;
+import org.biojava.nbio.structure.geometry.CalcPoint;
import org.biojava.nbio.structure.geometry.MomentsOfInertia;
-import org.biojava.nbio.structure.geometry.SuperPosition;
import org.biojava.nbio.structure.symmetry.core.Helix;
import org.biojava.nbio.structure.symmetry.core.HelixLayers;
import org.biojava.nbio.structure.symmetry.core.QuatSymmetryResults;
import org.biojava.nbio.structure.symmetry.core.QuatSymmetrySubunits;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import javax.vecmath.*;
import java.util.*;
public class HelixAxisAligner extends AxisAligner {
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(HelixAxisAligner.class);
+
+
private static final Vector3d Y_AXIS = new Vector3d(0,1,0);
private static final Vector3d Z_AXIS = new Vector3d(0,0,1);
@@ -483,8 +491,9 @@ private Matrix4d alignAxes(Vector3d[] axisVectors, Vector3d[] referenceVectors)
Point3d[] ref = new Point3d[2];
ref[0] = new Point3d(referenceVectors[0]);
ref[1] = new Point3d(referenceVectors[1]);
- if (SuperPosition.rmsd(axes, ref) > 0.1) {
- System.out.println("Warning: AxisTransformation: axes alignment is off. RMSD: " + SuperPosition.rmsd(axes, ref));
+ if (CalcPoint.rmsd(axes, ref) > 0.1) {
+ logger.warn("AxisTransformation: axes alignment is off. RMSD: "
+ + CalcPoint.rmsd(axes, ref));
}
return m2;
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/axis/RotationAxisAligner.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/axis/RotationAxisAligner.java
index 8e1e73fa53..9dbb87f3cd 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/axis/RotationAxisAligner.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/axis/RotationAxisAligner.java
@@ -20,18 +20,24 @@
*/
package org.biojava.nbio.structure.symmetry.axis;
+import org.biojava.nbio.structure.geometry.CalcPoint;
import org.biojava.nbio.structure.geometry.MomentsOfInertia;
-import org.biojava.nbio.structure.geometry.SuperPosition;
import org.biojava.nbio.structure.symmetry.core.QuatSymmetryResults;
import org.biojava.nbio.structure.symmetry.core.Rotation;
import org.biojava.nbio.structure.symmetry.core.RotationGroup;
import org.biojava.nbio.structure.symmetry.core.QuatSymmetrySubunits;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.vecmath.*;
import java.util.*;
public class RotationAxisAligner extends AxisAligner{
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(RotationAxisAligner.class);
+
private static final Vector3d X_AXIS = new Vector3d(1,0,0);
private static final Vector3d Y_AXIS = new Vector3d(0,1,0);
private static final Vector3d Z_AXIS = new Vector3d(0,0,1);
@@ -463,8 +469,9 @@ private Matrix4d alignAxes(Vector3d[] axisVectors, Vector3d[] referenceVectors)
Point3d[] ref = new Point3d[2];
ref[0] = new Point3d(referenceVectors[0]);
ref[1] = new Point3d(referenceVectors[1]);
- if (SuperPosition.rmsd(axes, ref) > 0.1) {
- System.out.println("Warning: AxisTransformation: axes alignment is off. RMSD: " + SuperPosition.rmsd(axes, ref));
+ if (CalcPoint.rmsd(axes, ref) > 0.1) {
+ logger.warn("AxisTransformation: axes alignment is off. RMSD: "
+ + CalcPoint.rmsd(axes, ref));
}
return m2;
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/C2RotationSolver.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/C2RotationSolver.java
index b691dda050..a001d6462c 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/C2RotationSolver.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/C2RotationSolver.java
@@ -22,11 +22,12 @@
package org.biojava.nbio.structure.symmetry.core;
import org.biojava.nbio.structure.geometry.CalcPoint;
-import org.biojava.nbio.structure.geometry.SuperPosition;
+import org.biojava.nbio.structure.geometry.UnitQuaternions;
import javax.vecmath.AxisAngle4d;
import javax.vecmath.Matrix4d;
import javax.vecmath.Point3d;
+import javax.vecmath.Quat4d;
import javax.vecmath.Vector3d;
import java.util.ArrayList;
@@ -78,9 +79,29 @@ private void solve() {
Point3d[] y = CalcPoint.clonePoint3dArray(traces.get(1));
CalcPoint.translate(new Point3d(trans), y);
+ // TODO implement this piece of code using at origin superposition
+ Quat4d quat = UnitQuaternions.relativeOrientation(
+ x, y);
AxisAngle4d axisAngle = new AxisAngle4d();
-
- Matrix4d transformation = SuperPosition.superposeAtOrigin(x, y, axisAngle);
+ Matrix4d transformation = new Matrix4d();
+
+ transformation.set(quat);
+ axisAngle.set(quat);
+
+ Vector3d axis = new Vector3d(axisAngle.x, axisAngle.y, axisAngle.z);
+ if (axis.lengthSquared() < 1.0E-6) {
+ axisAngle.x = 0;
+ axisAngle.y = 0;
+ axisAngle.z = 1;
+ axisAngle.angle = 0;
+ } else {
+ axis.normalize();
+ axisAngle.x = axis.x;
+ axisAngle.y = axis.y;
+ axisAngle.z = axis.z;
+ }
+
+ CalcPoint.transform(transformation, y);
// if rmsd or angle deviation is above threshold, stop
double angleThresholdRadians = Math.toRadians(parameters.getAngleThreshold());
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/HelixSolver.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/HelixSolver.java
index 9ff28c64dd..9d60e12485 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/HelixSolver.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/HelixSolver.java
@@ -21,7 +21,7 @@
package org.biojava.nbio.structure.symmetry.core;
import org.biojava.nbio.structure.geometry.CalcPoint;
-import org.biojava.nbio.structure.geometry.SuperPosition;
+import org.biojava.nbio.structure.geometry.SuperPositions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -90,17 +90,14 @@ private void solve() {
logger.debug("HelixSolver: pair: " + Arrays.toString(pair));
int contacts = entry.getValue();
- Point3d[] h1 = null;
- Point3d[] h2 = null;
+ Point3d[] h1 = CalcPoint.clonePoint3dArray(repeatUnits.get(pair[0]));
+ Point3d[] h2 = CalcPoint.clonePoint3dArray(repeatUnits.get(pair[1]));
// trial superposition of repeat unit pairs to get a seed
// permutation
- h1 = CalcPoint.clonePoint3dArray(repeatUnits.get(pair[0]));
- h2 = CalcPoint.clonePoint3dArray(repeatUnits.get(pair[1]));
- Matrix4d transformation = SuperPosition.superposeWithTranslation(
- h1, h2);
+ Matrix4d transformation = SuperPositions.superposeAndTransform(h2, h1);
- double rmsd = SuperPosition.rmsd(h1, h2);
+ double rmsd = CalcPoint.rmsd(h1, h2);
double rise = getRise(transformation,
repeatUnitCenters.get(pair[0]),
repeatUnitCenters.get(pair[1]));
@@ -185,9 +182,9 @@ private void solve() {
// calculate subunit rmsd if at least 3 subunits are available
double subunitRmsd = 0;
if (point1.size() > 2) {
- transformation = SuperPosition.superposeWithTranslation(h1, h2);
+ transformation = SuperPositions.superposeAndTransform(h2, h1);
- subunitRmsd = SuperPosition.rmsd(h1, h2);
+ subunitRmsd = CalcPoint.rmsd(h1, h2);
rise = getRise(transformation, repeatUnitCenters.get(pair[0]),
repeatUnitCenters.get(pair[1]));
angle = getAngle(transformation);
@@ -229,13 +226,13 @@ private void solve() {
point1.toArray(h1);
point2.toArray(h2);
Point3d[] h3 = CalcPoint.clonePoint3dArray(h1);
- transformation = SuperPosition.superposeWithTranslation(h1, h2);
+ transformation = SuperPositions.superposeAndTransform(h2, h1);
Point3d xtrans = CalcPoint.centroid(h3);
xtrans.negate();
- double traceRmsd = SuperPosition.rmsd(h1, h2);
+ double traceRmsd = CalcPoint.rmsd(h1, h2);
rise = getRise(transformation, repeatUnitCenters.get(pair[0]),
repeatUnitCenters.get(pair[1]));
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/QuatSuperpositionScorer.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/QuatSuperpositionScorer.java
index e1e87d0c05..5df1278563 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/QuatSuperpositionScorer.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/QuatSuperpositionScorer.java
@@ -21,7 +21,7 @@
package org.biojava.nbio.structure.symmetry.core;
-import org.biojava.nbio.structure.geometry.SuperPosition;
+import org.biojava.nbio.structure.geometry.SuperPositions;
import javax.vecmath.Matrix4d;
import javax.vecmath.Point3d;
@@ -150,7 +150,7 @@ private static void calcIntrasubunitScores(QuatSymmetrySubunits subunits, Matrix
}
// superpose individual subunits
- SuperPosition.superposeWithTranslation(trans, orig);
+ SuperPositions.superposeAndTransform(orig, trans);
for (int j = 0; j < orig.length; j++) {
double dSq = orig[j].distanceSquared(trans[j]);
sumTm += 1.0/(1.0 + dSq/d0Sq);
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/RotationSolver.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/RotationSolver.java
index e2645c2201..2a879df3d1 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/RotationSolver.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/RotationSolver.java
@@ -21,14 +21,16 @@
package org.biojava.nbio.structure.symmetry.core;
+import org.biojava.nbio.structure.geometry.CalcPoint;
import org.biojava.nbio.structure.geometry.MomentsOfInertia;
-import org.biojava.nbio.structure.geometry.SuperPosition;
+import org.biojava.nbio.structure.geometry.UnitQuaternions;
import org.biojava.nbio.structure.symmetry.geometry.DistanceBox;
import org.biojava.nbio.structure.symmetry.geometry.SphereSampler;
import javax.vecmath.AxisAngle4d;
import javax.vecmath.Matrix4d;
import javax.vecmath.Point3d;
+import javax.vecmath.Quat4d;
import javax.vecmath.Vector3d;
import java.util.ArrayList;
@@ -166,10 +168,31 @@ private boolean evaluatePermutation(List
+ * Test the correctness of various Text outputs for {@link MultipleAlignment}s.
+ *
* Currently tested:
- *
- * Zhang Y and Skolnick J (2004). "Scoring function for automated assessment
- * of protein structure template quality". Proteins 57: 702 - 710.
- *
- * @param atomSet1 atom array 1
- * @param atomSet2 atom array 2
- * @param len1 The full length of the protein supplying atomSet1
- * @param len2 The full length of the protein supplying atomSet2
- * @return The TM-Score
- * @throws StructureException
- */
- public static double getTMScore(Atom[] atomSet1, Atom[] atomSet2, int len1, int len2) throws StructureException {
- if ( atomSet1.length != atomSet2.length ){
- throw new StructureException("The two atom sets are not of same length!");
- }
- if ( atomSet1.length > len1 ){
- throw new StructureException("len1 must be greater or equal to the alignment length!");
- }
- if ( atomSet2.length > len2 ){
- throw new StructureException("len2 must be greater or equal to the alignment length!");
- }
-
- int Lmin = Math.min(len1,len2);
- int Laln = atomSet1.length;
-
- double d0 = 1.24 * Math.cbrt(Lmin - 15.) - 1.8;
- double d0sq = d0*d0;
-
- double sum = 0;
- for(int i=0;i
- * Zhang Y and Skolnick J (2004). "Scoring function for automated assessment
- * of protein structure template quality". Proteins 57: 702 - 710.
- *
- * @param atomSet1 atom array 1
- * @param atomSet2 atom array 2
- * @param len1 The full length of the protein supplying atomSet1
- * @param len2 The full length of the protein supplying atomSet2
- * @return The TM-Score
- * @throws StructureException
- * @see {@link #getTMScore(Atom[], Atom[], int, int)}, which normalizes by the minimum length
- */
- public static double getTMScoreAlternate(Atom[] atomSet1, Atom[] atomSet2, int len1, int len2) throws StructureException {
- if ( atomSet1.length != atomSet2.length ){
- throw new StructureException("The two atom sets are not of same length!");
- }
- if ( atomSet1.length > len1 ){
- throw new StructureException("len1 must be greater or equal to the alignment length!");
- }
- if ( atomSet2.length > len2 ){
- throw new StructureException("len2 must be greater or equal to the alignment length!");
- }
-
- int Lmax = Math.max(len1,len2);
- int Laln = atomSet1.length;
-
- double d0 = 1.24 * Math.cbrt(Lmax - 15.) - 1.8;
- double d0sq = d0*d0;
-
- double sum = 0;
- for(int i=0;iExample
- *
+ *
+ *
*
*
*
@@ -131,12 +135,13 @@
*/
public class StructurePairAligner {
- private final static Logger logger = LoggerFactory.getLogger(StructurePairAligner.class);
+ private final static Logger logger = LoggerFactory
+ .getLogger(StructurePairAligner.class);
AlternativeAlignment[] alts;
Matrix distanceMatrix;
StrucAligParameters params;
- FragmentPair[] fragPairs;
+ FragmentPair[] fragPairs;
List
* public void run(){
-
- // first load two example structures
- {@link InputStream} inStream1 = this.getClass().getResourceAsStream("/files/5pti.pdb");
- {@link InputStream} inStream2 = this.getClass().getResourceAsStream("/files/1tap.pdb");
-
- {@link Structure} structure1 = null;
- {@link Structure} structure2 = null;
-
- {@link PDBFileParser} pdbpars = new {@link PDBFileParser}();
- structure1 = pdbpars.parsePDBFile(inStream1) ;
- structure2 = pdbpars.parsePDBFile(inStream2);
-
-
- // calculate structure superimposition for two complete structures
- {@link StructurePairAligner} aligner = new {@link StructurePairAligner}();
-
-
- // align the full 2 structures with default parameters.
- // see StructurePairAligner for more options and how to align
- // any set of Atoms
- aligner.align(structure1,structure2);
-
- {@link AlternativeAlignment}[] aligs = aligner.getAlignments();
- {@link AlternativeAlignment} a = aligs[0];
- System.out.println(a);
-
- //display the alignment in Jmol
-
- // first get an artificial structure for the alignment
- {@link Structure} artificial = a.getAlignedStructure(structure1, structure2);
-
-
- // and then send it to Jmol (only will work if Jmol is in the Classpath)
-
- BiojavaJmol jmol = new BiojavaJmol();
- jmol.setTitle(artificial.getName());
- jmol.setStructure(artificial);
-
- // color the two structures
-
-
- jmol.evalString("select *; backbone 0.4; wireframe off; spacefill off; " +
- "select not protein and not solvent; spacefill on;");
- jmol.evalString("select *"+"/1 ; color red; model 1; ");
-
-
- // now color the equivalent residues ...
-
- String[] pdb1 = a.getPDBresnum1();
- for (String res : pdb1 ){
- jmol.evalString("select " + res + "/1 ; backbone 0.6; color white;");
- }
-
- jmol.evalString("select *"+"/2; color blue; model 2;");
- String[] pdb2 = a.getPDBresnum2();
- for (String res :pdb2 ){
- jmol.evalString("select " + res + "/2 ; backbone 0.6; color yellow;");
- }
-
-
- // now show both models again.
- jmol.evalString("model 0;");
-
- }
- *
+ *
+ * // first load two example structures
+ * {@link InputStream} inStream1 = this.getClass().getResourceAsStream("/files/5pti.pdb");
+ * {@link InputStream} inStream2 = this.getClass().getResourceAsStream("/files/1tap.pdb");
+ *
+ * {@link Structure} structure1 = null;
+ * {@link Structure} structure2 = null;
+ *
+ * {@link PDBFileParser} pdbpars = new {@link PDBFileParser}();
+ * structure1 = pdbpars.parsePDBFile(inStream1) ;
+ * structure2 = pdbpars.parsePDBFile(inStream2);
+ *
+ *
+ * // calculate structure superimposition for two complete structures
+ * {@link StructurePairAligner} aligner = new {@link StructurePairAligner}();
+ *
+ *
+ * // align the full 2 structures with default parameters.
+ * // see StructurePairAligner for more options and how to align
+ * // any set of Atoms
+ * aligner.align(structure1,structure2);
+ *
+ * {@link AlternativeAlignment}[] aligs = aligner.getAlignments();
+ * {@link AlternativeAlignment} a = aligs[0];
+ * System.out.println(a);
+ *
+ * //display the alignment in Jmol
+ *
+ * // first get an artificial structure for the alignment
+ * {@link Structure} artificial = a.getAlignedStructure(structure1, structure2);
+ *
+ *
+ * // and then send it to Jmol (only will work if Jmol is in the Classpath)
+ *
+ * BiojavaJmol jmol = new BiojavaJmol();
+ * jmol.setTitle(artificial.getName());
+ * jmol.setStructure(artificial);
+ *
+ * // color the two structures
+ *
+ *
+ * jmol.evalString("select *; backbone 0.4; wireframe off; spacefill off; " +
+ * "select not protein and not solvent; spacefill on;");
+ * jmol.evalString("select *"+"/1 ; color red; model 1; ");
+ *
+ *
+ * // now color the equivalent residues ...
+ *
+ * String[] pdb1 = a.getPDBresnum1();
+ * for (String res : pdb1 ){
+ * jmol.evalString("select " + res + "/1 ; backbone 0.6; color white;");
+ * }
+ *
+ * jmol.evalString("select *"+"/2; color blue; model 2;");
+ * String[] pdb2 = a.getPDBresnum2();
+ * for (String res :pdb2 ){
+ * jmol.evalString("select " + res + "/2 ; backbone 0.6; color yellow;");
+ * }
+ *
+ *
+ * // now show both models again.
+ * jmol.evalString("model 0;");
+ *
+ * }
+ *
+ *
*
* @author Aleix Lafita
@@ -53,27 +51,24 @@ public class TestMultipleAlignmentWriter {
private MultipleAlignment alignment2;
/**
- * Build the alignments in common for every writer output,
- * so that they do not have to be created each time.
+ * Build the alignments in common for every writer output, so that they do
+ * not have to be created each time.
+ *
* @throws IOException
* @throws StructureException
*/
- public TestMultipleAlignmentWriter()
- throws StructureException, IOException{
-
+ public TestMultipleAlignmentWriter() throws StructureException, IOException {
+
alignment1 = TestSampleGenerator.testAlignment1();
alignment2 = TestSampleGenerator.testAlignment2();
}
-
-
@Test
- public void testFASTA1() throws IOException{
+ public void testFASTA1() throws IOException {
String result = MultipleAlignmentWriter.toFASTA(alignment1);
- FileReader file = new FileReader(
- "src/test/resources/testMSTA1.fasta");
+ FileReader file = new FileReader("src/test/resources/testMSTA1.fasta");
BufferedReader reader = new BufferedReader(file);
String line = null;
StringBuilder stringBuilder = new StringBuilder();
@@ -85,7 +80,7 @@ public void testFASTA1() throws IOException{
reader.close();
String expected = stringBuilder.toString();
- assertEquals(expected,result);
+ assertEquals(expected, result);
}
@Test
@@ -93,8 +88,7 @@ public void testFASTA2() throws IOException {
String result = MultipleAlignmentWriter.toFASTA(alignment2);
- FileReader file = new FileReader(
- "src/test/resources/testMSTA2.fasta");
+ FileReader file = new FileReader("src/test/resources/testMSTA2.fasta");
BufferedReader reader = new BufferedReader(file);
String line = null;
StringBuilder stringBuilder = new StringBuilder();
@@ -106,16 +100,15 @@ public void testFASTA2() throws IOException {
reader.close();
String expected = stringBuilder.toString();
- assertEquals(expected,result);
+ assertEquals(expected, result);
}
@Test
- public void testFatCat1() throws IOException{
+ public void testFatCat1() throws IOException {
String result = MultipleAlignmentWriter.toFatCat(alignment1);
- FileReader file = new FileReader(
- "src/test/resources/testMSTA1.fatcat");
+ FileReader file = new FileReader("src/test/resources/testMSTA1.fatcat");
BufferedReader reader = new BufferedReader(file);
String line = null;
StringBuilder stringBuilder = new StringBuilder();
@@ -127,16 +120,15 @@ public void testFatCat1() throws IOException{
reader.close();
String expected = stringBuilder.toString();
- assertEquals(expected,result);
+ assertEquals(expected, result);
}
@Test
- public void testFatCat2() throws IOException{
+ public void testFatCat2() throws IOException {
String result = MultipleAlignmentWriter.toFatCat(alignment2);
- FileReader file = new FileReader(
- "src/test/resources/testMSTA2.fatcat");
+ FileReader file = new FileReader("src/test/resources/testMSTA2.fatcat");
BufferedReader reader = new BufferedReader(file);
String line = null;
StringBuilder stringBuilder = new StringBuilder();
@@ -148,11 +140,11 @@ public void testFatCat2() throws IOException{
reader.close();
String expected = stringBuilder.toString();
- assertEquals(expected,result);
+ assertEquals(expected, result);
}
@Test
- public void testAlignedResidues1() throws IOException{
+ public void testAlignedResidues1() throws IOException {
String result = MultipleAlignmentWriter.toAlignedResidues(alignment1);
@@ -169,11 +161,11 @@ public void testAlignedResidues1() throws IOException{
reader.close();
String expected = stringBuilder.toString();
- assertEquals(expected,result);
+ assertEquals(expected, result);
}
@Test
- public void testAlignedResidues2() throws IOException{
+ public void testAlignedResidues2() throws IOException {
String result = MultipleAlignmentWriter.toAlignedResidues(alignment2);
@@ -190,98 +182,7 @@ public void testAlignedResidues2() throws IOException{
reader.close();
String expected = stringBuilder.toString();
- assertEquals(expected,result);
- }
-
- @Test
- public void testTransformMatrices1() throws IOException{
-
- String result = MultipleAlignmentWriter.
- toTransformMatrices(alignment1);
-
- FileReader file = new FileReader(
- "src/test/resources/testMSTA1.transforms");
- BufferedReader reader = new BufferedReader(file);
- String line = null;
- StringBuilder stringBuilder = new StringBuilder();
-
- while ((line = reader.readLine()) != null) {
- stringBuilder.append(line);
- stringBuilder.append("\n");
- }
- reader.close();
-
- String expected = stringBuilder.toString();
- assertEquals(expected,result);
- }
-
- @Test
- public void testTransformMatrices2() throws IOException{
-
- String result = MultipleAlignmentWriter.
- toTransformMatrices(alignment2);
-
-
- FileReader file = new FileReader(
- "src/test/resources/testMSTA2.transforms");
- BufferedReader reader = new BufferedReader(file);
- String line = null;
- StringBuilder stringBuilder = new StringBuilder();
-
- while ((line = reader.readLine()) != null) {
- stringBuilder.append(line);
- stringBuilder.append("\n");
- }
- reader.close();
-
- String expected = stringBuilder.toString();
- // TODO THIS SHOULD BE REWRITTEN TO USE FLOATS
- //assertEquals(expected,result);
-
+ assertEquals(expected, result);
}
- @Test
- public void testXMLformat1() throws IOException{
-
- MultipleAlignmentEnsemble ensemble = alignment1.getEnsemble();
- String result = MultipleAlignmentWriter.toXML(ensemble);
-
- FileReader file = new FileReader(
- "src/test/resources/testMSTA1.xml");
- BufferedReader reader = new BufferedReader(file);
- String line = null;
- StringBuilder stringBuilder = new StringBuilder();
-
- while ((line = reader.readLine()) != null) {
- stringBuilder.append(line);
- stringBuilder.append("\n");
- }
- reader.close();
-
- String expected = stringBuilder.toString();
- assertEquals(expected,result);
- }
-
- @Test
- public void testXMLformat2() throws IOException{
-
- MultipleAlignmentEnsemble ensemble = alignment2.getEnsemble();
- String result = MultipleAlignmentWriter.toXML(ensemble);
-
- FileReader file = new FileReader(
- "src/test/resources/testMSTA2.xml");
- BufferedReader reader = new BufferedReader(file);
- String line = null;
- StringBuilder stringBuilder = new StringBuilder();
-
- while ((line = reader.readLine()) != null) {
- stringBuilder.append(line);
- stringBuilder.append("\n");
- }
- reader.close();
-
- String expected = stringBuilder.toString();
- // TODO THIS SHOULD BE REWRITTEN TO DO FLOAT AND NOT TEXT COMPARISON
-// assertEquals(expected,result);
- }
}
diff --git a/biojava-structure/src/test/java/org/biojava/nbio/structure/geometry/TestSuperPosition.java b/biojava-structure/src/test/java/org/biojava/nbio/structure/geometry/TestSuperPosition.java
new file mode 100644
index 0000000000..b7f693e311
--- /dev/null
+++ b/biojava-structure/src/test/java/org/biojava/nbio/structure/geometry/TestSuperPosition.java
@@ -0,0 +1,167 @@
+package org.biojava.nbio.structure.geometry;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+import javax.vecmath.AxisAngle4d;
+import javax.vecmath.Matrix4d;
+import javax.vecmath.Point3d;
+import javax.vecmath.Vector3d;
+
+import org.biojava.nbio.structure.StructureException;
+import org.biojava.nbio.structure.geometry.SuperPositionQuat;
+import org.biojava.nbio.structure.geometry.SuperPositionQCP;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test the Quaternion-Based Characteristic Polynomial {@link SuperPositionQCP}
+ * algorithm for RMSD and Superposition calculations.
+ *
+ * @author Aleix Lafita
+ * @since 5.0.0
+ *
+ */
+public class TestSuperPosition {
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(TestSuperPosition.class);
+
+ private List