diff --git a/biojava-aa-prop/pom.xml b/biojava-aa-prop/pom.xml
index 5c35a618b8..89ef2154ef 100644
--- a/biojava-aa-prop/pom.xml
+++ b/biojava-aa-prop/pom.xml
@@ -2,7 +2,7 @@
biojava
org.biojava
- 4.2.5
+ 4.2.6
4.0.0
biojava-aa-prop
@@ -70,12 +70,12 @@
org.biojava
biojava-core
- 4.2.5
+ 4.2.6
org.biojava
biojava-structure
- 4.2.5
+ 4.2.6
diff --git a/biojava-alignment/pom.xml b/biojava-alignment/pom.xml
index d42f48f857..41389cdd4e 100644
--- a/biojava-alignment/pom.xml
+++ b/biojava-alignment/pom.xml
@@ -4,7 +4,7 @@
biojava
org.biojava
- 4.2.5
+ 4.2.6
biojava-alignment
biojava-alignment
@@ -46,7 +46,7 @@
org.biojava
biojava-core
- 4.2.5
+ 4.2.6
compile
@@ -74,7 +74,7 @@
org.biojava
biojava-phylo
- 4.2.5
+ 4.2.6
diff --git a/biojava-core/pom.xml b/biojava-core/pom.xml
index 80cab2a58a..e3b0e9a7a1 100644
--- a/biojava-core/pom.xml
+++ b/biojava-core/pom.xml
@@ -3,7 +3,7 @@
biojava
org.biojava
- 4.2.5
+ 4.2.6
4.0.0
biojava-core
diff --git a/biojava-genome/pom.xml b/biojava-genome/pom.xml
index 93ca9d0423..b382489846 100644
--- a/biojava-genome/pom.xml
+++ b/biojava-genome/pom.xml
@@ -3,7 +3,7 @@
biojava
org.biojava
- 4.2.5
+ 4.2.6
4.0.0
biojava-genome
@@ -85,13 +85,13 @@
org.biojava
biojava-core
- 4.2.5
+ 4.2.6
compile
org.biojava
biojava-alignment
- 4.2.5
+ 4.2.6
compile
diff --git a/biojava-integrationtest/pom.xml b/biojava-integrationtest/pom.xml
index 82703c0da0..dca85357b3 100644
--- a/biojava-integrationtest/pom.xml
+++ b/biojava-integrationtest/pom.xml
@@ -4,7 +4,7 @@
biojava
org.biojava
- 4.2.5
+ 4.2.6
biojava-integrationtest
jar
@@ -32,7 +32,7 @@
org.biojava
biojava-structure
- 4.2.5
+ 4.2.6
diff --git a/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/StructureToolsTest.java b/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/StructureToolsTest.java
index de234a7159..7faf37e823 100644
--- a/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/StructureToolsTest.java
+++ b/biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/StructureToolsTest.java
@@ -22,8 +22,6 @@
*/
package org.biojava.nbio.structure.test;
-import junit.framework.TestCase;
-
import org.biojava.nbio.structure.*;
import org.biojava.nbio.structure.align.util.AtomCache;
import org.biojava.nbio.structure.io.FileParsingParameters;
@@ -31,18 +29,21 @@
import org.biojava.nbio.structure.io.mmcif.ChemCompGroupFactory;
import org.biojava.nbio.structure.io.mmcif.ChemCompProvider;
import org.biojava.nbio.structure.io.mmcif.DownloadChemCompProvider;
+import org.junit.Before;
+import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import static org.junit.Assume.assumeNoException;
+import static org.junit.Assert.*;
-public class StructureToolsTest extends TestCase {
+public class StructureToolsTest {
Structure structure, structure2, structure3, structure4;
- @Override
- protected void setUp() throws IOException
+ @Before
+ public void setUp() throws IOException
{
InputStream inStream = this.getClass().getResourceAsStream("/5pti.pdb");
assertNotNull(inStream);
@@ -85,12 +86,13 @@ protected void setUp() throws IOException
inStream.close();
}
-
+ @Test
public void testGetCAAtoms(){
Atom[] cas = StructureTools.getRepresentativeAtomArray(structure);
assertEquals("did not find the expected number of Atoms (58), but got " + cas.length,58,cas.length);
}
+ @Test
public void testGetAtomsConsistency() throws IOException, StructureException{
//Save the existing ChemCompProvider
@@ -120,11 +122,13 @@ public void testGetAtomsConsistency() throws IOException, StructureException{
ChemCompGroupFactory.setChemCompProvider(provider);
}
+ @Test
public void testGetNrAtoms(){
int length = StructureTools.getNrAtoms(structure);
assertEquals("did not find the expected number of Atoms (1087), but got " + length,1087,length);
}
+ @Test
@SuppressWarnings("deprecation")
public void testGetSubRanges() throws StructureException {
String range;
@@ -239,6 +243,7 @@ public void testGetSubRanges() throws StructureException {
} catch(IllegalArgumentException ex) {} //expected
}
+ @Test
public void testRevisedConvention() throws IOException, StructureException{
AtomCache cache = new AtomCache();
@@ -319,6 +324,7 @@ public void testRevisedConvention() throws IOException, StructureException{
* Test some subranges that we used to have problems with
* @throws StructureException
*/
+ @Test
@SuppressWarnings("deprecation")
public void testGetSubRangesExtended() throws StructureException {
String range;
@@ -380,6 +386,7 @@ public void testGetSubRangesExtended() throws StructureException {
* Test insertion codes
* @throws StructureException
*/
+ @Test
@SuppressWarnings("deprecation")
public void testGetSubRangesInsertionCodes() throws StructureException {
String range;
@@ -437,6 +444,7 @@ public void testGroupsWithinShell() {
//TODO
}
+ @Test
public void testCAmmCIF() throws StructureException {
//Save the existing ChemCompProvider
@@ -473,5 +481,36 @@ public void testCAmmCIF() throws StructureException {
ChemCompGroupFactory.setChemCompProvider(provider);
}
+
+ @Test
+ public void testGetRepresentativeAtomsProtein() throws StructureException, IOException {
+ Structure s = StructureIO.getStructure("1smt");
+ Chain c = s.getChain(0);
+ Atom[] atoms = StructureTools.getRepresentativeAtomArray(c);
+ assertEquals(98,atoms.length);
+
+ Chain clonedChain = (Chain)c.clone();
+ atoms = StructureTools.getRepresentativeAtomArray(clonedChain);
+ assertEquals(98,atoms.length);
+ }
+ /**
+ * See https://github.com/biojava/biojava/issues/631
+ * @throws StructureException
+ * @throws IOException
+ */
+ @Test
+ public void testGetRepresentativeAtomsDna() throws StructureException, IOException {
+
+ Structure s = StructureIO.getStructure("2pvi");
+ Chain c = s.getChainByPDB("C");
+ Atom[] atoms = StructureTools.getRepresentativeAtomArray(c); // chain C (1st nucleotide chain)
+ // actually it should be 13, but at the moment one of the nucleotides is not caught correctly because it's non-standard
+ assertEquals(12,atoms.length);
+
+ Chain clonedChain = (Chain)c.clone();
+ atoms = StructureTools.getRepresentativeAtomArray(clonedChain); // chain C (1st nucleotide chain)
+ assertEquals(12,atoms.length);
+
+ }
}
diff --git a/biojava-modfinder/pom.xml b/biojava-modfinder/pom.xml
index a1f7b57970..e969b11f09 100644
--- a/biojava-modfinder/pom.xml
+++ b/biojava-modfinder/pom.xml
@@ -4,7 +4,7 @@
biojava
org.biojava
- 4.2.5
+ 4.2.6
biojava-modfinder
biojava-modfinder
@@ -31,7 +31,7 @@
org.biojava
biojava-structure
- 4.2.5
+ 4.2.6
jar
compile
diff --git a/biojava-ontology/pom.xml b/biojava-ontology/pom.xml
index 441b3bded0..305039b548 100644
--- a/biojava-ontology/pom.xml
+++ b/biojava-ontology/pom.xml
@@ -4,7 +4,7 @@
org.biojava
biojava
- 4.2.5
+ 4.2.6
biojava-ontology
diff --git a/biojava-phylo/pom.xml b/biojava-phylo/pom.xml
index affe865373..bc55ac6307 100644
--- a/biojava-phylo/pom.xml
+++ b/biojava-phylo/pom.xml
@@ -3,7 +3,7 @@
biojava
org.biojava
- 4.2.5
+ 4.2.6
4.0.0
biojava-phylo
@@ -44,7 +44,7 @@
org.biojava
biojava-core
- 4.2.5
+ 4.2.6
compile
diff --git a/biojava-protein-disorder/pom.xml b/biojava-protein-disorder/pom.xml
index 9e12925676..b95632bc2c 100644
--- a/biojava-protein-disorder/pom.xml
+++ b/biojava-protein-disorder/pom.xml
@@ -3,7 +3,7 @@
biojava
org.biojava
- 4.2.5
+ 4.2.6
biojava-protein-disorder
jar
@@ -63,7 +63,7 @@
org.biojava
biojava-core
- 4.2.5
+ 4.2.6
diff --git a/biojava-sequencing/pom.xml b/biojava-sequencing/pom.xml
index eb65c46b23..0990a8e9b2 100644
--- a/biojava-sequencing/pom.xml
+++ b/biojava-sequencing/pom.xml
@@ -3,7 +3,7 @@
biojava
org.biojava
- 4.2.5
+ 4.2.6
4.0.0
biojava-sequencing
@@ -47,7 +47,7 @@
org.biojava
biojava-core
- 4.2.5
+ 4.2.6
compile
diff --git a/biojava-structure-gui/pom.xml b/biojava-structure-gui/pom.xml
index d5b18c9e14..f96aad2a97 100644
--- a/biojava-structure-gui/pom.xml
+++ b/biojava-structure-gui/pom.xml
@@ -3,7 +3,7 @@
biojava
org.biojava
- 4.2.5
+ 4.2.6
4.0.0
biojava-structure-gui
@@ -25,13 +25,13 @@
org.biojava
biojava-structure
- 4.2.5
+ 4.2.6
compile
org.biojava
biojava-core
- 4.2.5
+ 4.2.6
compile
diff --git a/biojava-structure/pom.xml b/biojava-structure/pom.xml
index 0be0265a08..ac6de4757a 100644
--- a/biojava-structure/pom.xml
+++ b/biojava-structure/pom.xml
@@ -4,7 +4,7 @@
biojava
org.biojava
- 4.2.5
+ 4.2.6
biojava-structure
biojava-structure
@@ -22,13 +22,13 @@
org.biojava
biojava-alignment
- 4.2.5
+ 4.2.6
compile
org.biojava
biojava-core
- 4.2.5
+ 4.2.6
compile
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 dee571a3cb..d09252f16c 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
@@ -699,12 +699,17 @@ public static final void shift(Group group , Atom a ){
- /** Returns the center of mass of the set of atoms.
+ /**
+ * Returns the center of mass of the set of atoms.
* @param atomSet a set of Atoms
* @return an Atom representing the Centroid of the set of atoms
*/
public static final Atom getCentroid(Atom[] atomSet){
+ // if we don't catch this case, the centroid returned is (NaN,NaN,NaN), which can cause lots of problems down the line
+ if (atomSet.length==0)
+ throw new IllegalArgumentException("Atom array has length 0, can't calculate centroid!");
+
double[] coords = new double[3];
coords[0] = 0;
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/NucleotideImpl.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/NucleotideImpl.java
index 7cc5a9400b..75fa3b8da6 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/NucleotideImpl.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/NucleotideImpl.java
@@ -93,5 +93,36 @@ public Atom getP() {
}
- // no need to implement clone here, it's already in super class
+ // note we need to implement a clone here, despite there's one in super class already,
+ // that's due to issue https://github.com/biojava/biojava/issues/631 - JD 2017-01-21
+ @Override
+ public Object clone() {
+
+ NucleotideImpl n = new NucleotideImpl();
+ n.setPDBFlag(has3D());
+ n.setResidueNumber(getResidueNumber());
+
+ n.setPDBName(getPDBName());
+
+ // copy the atoms
+ for (Atom atom1 : atoms) {
+ Atom atom = (Atom) atom1.clone();
+ n.addAtom(atom);
+ atom.setGroup(n);
+ }
+
+ // copying the alt loc groups if present, otherwise they stay null
+ if (getAltLocs()!=null && !getAltLocs().isEmpty()) {
+ for (Group altLocGroup:this.getAltLocs()) {
+ Group nAltLocGroup = (Group)altLocGroup.clone();
+ n.addAltLoc(nAltLocGroup);
+ }
+ }
+
+ if (chemComp!=null)
+ n.setChemComp(chemComp);
+
+
+ return n;
+ }
}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/asa/AsaCalculator.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/asa/AsaCalculator.java
index c5d39662cd..b5c66e6c59 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/asa/AsaCalculator.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/asa/AsaCalculator.java
@@ -411,7 +411,7 @@ else if (atomCode.equals("CA") || atomCode.equals("CB") ||
else if (atomCode.equals("CG")) return TETRAHEDRAL_CARBON_VDW;
default:
- logger.warn("Unexpected carbon atom "+atomCode+" for aminoacid "+aa+", assigning its standard vdw radius");
+ logger.info("Unexpected carbon atom "+atomCode+" for aminoacid "+aa+", assigning its standard vdw radius");
return Element.C.getVDWRadius();
}
}
@@ -419,12 +419,8 @@ else if (atomCode.equals("CA") || atomCode.equals("CB") ||
// not any of the expected atoms
} else {
// non standard aas, (e.g. MSE, LLP) will always have this problem,
- // thus we log at info level for them, at warn for others
- if (amino.getChemComp()!=null && amino.getChemComp().isStandard()) {
- logger.warn("Unexpected atom "+atomCode+" for aminoacid "+aa+ " ("+amino.getPDBName()+"), assigning its standard vdw radius");
- } else {
- logger.info("Unexpected atom "+atomCode+" for aminoacid "+aa+ " ("+amino.getPDBName()+"), assigning its standard vdw radius");
- }
+ logger.info("Unexpected atom "+atomCode+" for aminoacid "+aa+ " ("+amino.getPDBName()+"), assigning its standard vdw radius");
+
return atom.getElement().getVDWRadius();
}
@@ -449,7 +445,7 @@ private static double getRadiusForNucl(NucleotideImpl nuc, Atom atom) {
if (atom.getElement()==Element.O) return OXIGEN_VDW;
- logger.warn("Unexpected atom "+atom.getName()+" for nucleotide "+nuc.getPDBName()+", assigning its standard vdw radius");
+ logger.info("Unexpected atom "+atom.getName()+" for nucleotide "+nuc.getPDBName()+", assigning its standard vdw radius");
return atom.getElement().getVDWRadius();
}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/HelixAxisAligner.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/HelixAxisAligner.java
index 6685e6a3ce..8e69ea83b8 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/HelixAxisAligner.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/HelixAxisAligner.java
@@ -22,11 +22,16 @@
import org.biojava.nbio.structure.symmetry.geometry.MomentsOfInertia;
import org.biojava.nbio.structure.symmetry.geometry.SuperPosition;
+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);
@@ -480,7 +485,7 @@ private Matrix4d alignAxes(Vector3d[] axisVectors, Vector3d[] referenceVectors)
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));
+ LOGGER.info("AxisTransformation: axes alignment is off. RMSD: " + SuperPosition.rmsd(axes, ref));
}
return m2;
@@ -600,7 +605,7 @@ private void calcReferenceVector() {
referenceVector = getReferenceAxisCylic();
if (referenceVector == null) {
- System.err.println("Warning: no reference vector found. Using y-axis.");
+ LOGGER.warn("no reference vector found. Using y-axis.");
referenceVector = new Vector3d(Y_AXIS);
}
// make sure reference vector is perpendicular principal roation vector
@@ -616,7 +621,7 @@ private Vector3d orthogonalize(Vector3d vector1, Vector3d vector2) {
vector2.negate();
}
if (Math.abs(dot) < 0.00001) {
- System.out.println("HelixAxisAligner: Warning: reference axis parallel");
+ LOGGER.info("HelixAxisAligner: reference axis parallel");
}
vector2.cross(vector1, vector2);
// System.out.println("Intermed. refVector: " + vector2);
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/PermutationGroup.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/PermutationGroup.java
index 675e4facb0..19f10ba72e 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/PermutationGroup.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/PermutationGroup.java
@@ -23,6 +23,7 @@
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -30,7 +31,7 @@
*
* @author Peter
*/
-public class PermutationGroup {
+public class PermutationGroup implements Iterable> {
List> permutations = new ArrayList>();
public void addPermutation(List permutation) {
@@ -139,4 +140,9 @@ public String getGroupTable() {
public int hashCode() {
return getGroupTable().hashCode();
}
+
+ @Override
+ public Iterator> iterator() {
+ return permutations.iterator();
+ }
}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/RotationAxisAligner.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/RotationAxisAligner.java
index 12d5db93b6..1a5bf33f32 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/RotationAxisAligner.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/RotationAxisAligner.java
@@ -22,11 +22,16 @@
import org.biojava.nbio.structure.symmetry.geometry.MomentsOfInertia;
import org.biojava.nbio.structure.symmetry.geometry.SuperPosition;
+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);
@@ -320,7 +325,7 @@ private List alignWithReferenceAxis(List orbit) {
}
Collections.reverse(orbit.subList(1, orbit.size()));
if (orbit.get(1) != index2) {
- System.err.println("Warning: alignWithReferenceAxis failed");
+ LOGGER.warn("alignWithReferenceAxis failed");
}
// System.out.println("Orbit2: " + orbit);
return orbit;
@@ -459,7 +464,7 @@ private Matrix4d alignAxes(Vector3d[] axisVectors, Vector3d[] referenceVectors)
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));
+ LOGGER.info("AxisTransformation: axes alignment is off. RMSD: " + SuperPosition.rmsd(axes, ref));
}
return m2;
@@ -632,7 +637,7 @@ private List deconvolute(List orbit) {
int index = p0.indexOf(current);
int next = p1.get(index);
if (!orbit.contains(next)) {
- System.err.println("deconvolute: inconsistency in permuation. Returning original order");
+ LOGGER.warn("deconvolute: inconsistency in permuation. Returning original order");
return orbit;
}
inRotationOrder.add(next);
@@ -675,7 +680,7 @@ private void calcReferenceVector() {
}
if (referenceVector == null) {
- System.err.println("Warning: no reference vector found. Using y-axis.");
+ LOGGER.warn("no reference vector found. Using y-axis.");
referenceVector = new Vector3d(Y_AXIS);
}
// make sure reference vector is perpendicular principal roation vector
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/RotationGroup.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/RotationGroup.java
index ead65b5b20..c605aa29e7 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/RotationGroup.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/RotationGroup.java
@@ -27,13 +27,14 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Iterator;
import java.util.List;
/**
*
* @author Peter
*/
-public class RotationGroup {
+public class RotationGroup implements Iterable {
private List rotations = new ArrayList();
private int principalAxisIndex = 0;
private int higherOrderRotationAxis = 0;
@@ -369,4 +370,9 @@ public int compare(Rotation o1, Rotation o2) {
}
});
}
+
+ @Override
+ public Iterator iterator() {
+ return rotations.iterator();
+ }
}
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 8802ef3bbc..bbc0d4cf9e 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,19 +21,22 @@
package org.biojava.nbio.structure.symmetry.core;
-import org.biojava.nbio.structure.symmetry.geometry.DistanceBox;
-import org.biojava.nbio.structure.symmetry.geometry.MomentsOfInertia;
-import org.biojava.nbio.structure.symmetry.geometry.SphereSampler;
-import org.biojava.nbio.structure.symmetry.geometry.SuperPosition;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import javax.vecmath.AxisAngle4d;
import javax.vecmath.Matrix4d;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+
+import org.biojava.nbio.structure.symmetry.geometry.DistanceBox;
+import org.biojava.nbio.structure.symmetry.geometry.MomentsOfInertia;
+import org.biojava.nbio.structure.symmetry.geometry.SphereSampler;
+import org.biojava.nbio.structure.symmetry.geometry.SuperPosition;
/**
@@ -50,7 +53,8 @@ public class RotationSolver implements QuatSymmetrySolver {
private Matrix4d centroidInverse = new Matrix4d();
private Point3d[] originalCoords = null;
private Point3d[] transformedCoords = null;
- private Set> hashCodes = new HashSet>();
+ // Cache whether a permutation is invalid (null) vs has been added to rotations
+ private Map,Rotation> evaluatedPermutations = new HashMap<>();
private RotationGroup rotations = new RotationGroup();
@@ -95,9 +99,14 @@ private void solve() {
List angles = getAngles();
- for (int i = 0; i < sphereCount; i++) {
+ for (int i = 0; i < sphereCount; i++) {
+ // Sampled orientation
+ //TODO The SphereSampler samples 4D orientation space. We really
+ // only need to sample 3D unit vectors, since we use limited
+ // angles. -SB
SphereSampler.getAxisAngle(i, sphereAngle);
+ // Each valid rotation angle
for (double angle : angles) {
// apply rotation
sphereAngle.angle = angle;
@@ -113,14 +122,14 @@ private void solve() {
List permutation = getPermutation();
// System.out.println("Rotation Solver: permutation: " + i + ": " + permutation);
- boolean isValidPermuation = isValidPermutation(permutation);
- if (! isValidPermuation) {
- continue;
+ // check if novel
+ if ( evaluatedPermutations.containsKey(permutation)) {
+ continue; //either invalid or already added
}
- boolean newPermutation = evaluatePermutation(permutation);
- if (newPermutation) {
- completeRotationGroup();
+ Rotation newPermutation = isValidPermutation(permutation);
+ if (newPermutation != null) {
+ completeRotationGroup(newPermutation);
}
// check if all symmetry operations have been found.
@@ -131,33 +140,84 @@ private void solve() {
}
}
- private void completeRotationGroup() {
+ /**
+ * Combine current rotations to make all possible permutations.
+ * If these are all valid, add them to the rotations
+ * @param additionalRots Additional rotations we are considering adding to this.rotations
+ * @return whether the rotations were valid and added
+ */
+ private boolean completeRotationGroup(Rotation... additionalRots) {
PermutationGroup g = new PermutationGroup();
- for (int i = 0; i < rotations.getOrder(); i++) {
- Rotation s = rotations.getRotation(i);
+ for (Rotation s : rotations) {
g.addPermutation(s.getPermutation());
}
+ for( Rotation s : additionalRots) {
+ g.addPermutation(s.getPermutation());
+ // inputs should not have been added already
+ assert evaluatedPermutations.get(s.getPermutation()) == null;
+ }
g.completeGroup();
// the group is complete, nothing to do
- if (g.getOrder() == rotations.getOrder()) {
- return;
+ if (g.getOrder() == rotations.getOrder()+additionalRots.length) {
+ for( Rotation s : additionalRots) {
+ addRotation(s);
+ }
+ return true;
}
// try to complete the group
- for (int i = 0; i < g.getOrder(); i++) {
- List permutation = g.getPermutation(i);
-
- boolean isValidPermutation = isValidPermutation(permutation);
- if (isValidPermutation) {
+ List newRots = new ArrayList<>(g.getOrder());
+ // First, quick check for whether they're allowed
+ for (List permutation : g) {
+ if( evaluatedPermutations.containsKey(permutation)) {
+ Rotation rot = evaluatedPermutations.get(permutation);
+ if( rot == null ) {
+ return false;
+ }
+ } else {
+ if( ! isAllowedPermutation(permutation)) {
+ return false;
+ }
+ }
+ }
+ // Slower check including the superpositions
+ for (List permutation : g) {
+ Rotation rot;
+ if( evaluatedPermutations.containsKey(permutation)) {
+ rot = evaluatedPermutations.get(permutation);
+ } else {
+ rot = isValidPermutation(permutation);
+ }
- // perform permutation of subunits
- evaluatePermutation(permutation);
+ if( rot == null ) {
+ // if any induced rotation is invalid, abort
+ return false;
+ }
+ if(!evaluatedPermutations.containsKey(permutation)){ //novel
+ newRots.add(rot);
}
}
+ // Add rotations
+ for( Rotation rot : newRots) {
+ addRotation(rot);
+ }
+ return true;
}
- private boolean evaluatePermutation(List permutation) {
+ private void addRotation(Rotation rot) {
+ evaluatedPermutations.put(rot.getPermutation(),rot);
+ rotations.addRotation(rot);
+ }
+
+ /**
+ * Superimpose subunits based on the given permutation. Then check whether
+ * the superposition passes RMSD thresholds and create a Rotation to
+ * represent it if so.
+ * @param permutation A list specifying which subunits should be aligned by the current transformation
+ * @return A Rotation representing the permutation, or null if the superposition did not meet thresholds.
+ */
+ private Rotation superimposePermutation(List permutation) {
// permutate subunits
for (int j = 0, n = subunits.getSubunitCount(); j < n; j++) {
transformedCoords[j].set(originalCoords[permutation.get(j)]);
@@ -176,17 +236,20 @@ private boolean evaluatePermutation(List permutation) {
// evaluate superposition of CA traces
QuatSymmetryScores scores = QuatSuperpositionScorer.calcScores(subunits, transformation, permutation);
if (scores.getRmsd() < 0.0 || scores.getRmsd() > parameters.getRmsdThreshold()) {
- return false;
+ return null;
}
scores.setRmsdCenters(subunitRmsd);
Rotation symmetryOperation = createSymmetryOperation(permutation, transformation, axisAngle, fold, scores);
- rotations.addRotation(symmetryOperation);
- return true;
+ return symmetryOperation;
}
- return false;
+ return null;
}
+ /**
+ * Get valid rotation angles given the number of subunits
+ * @return The rotation angle corresponding to each fold of {@link Subunits#getFolds()}
+ */
private List getAngles() {
int n = subunits.getSubunitCount();
// for spherical symmetric cases, n cannot be higher than 60
@@ -210,44 +273,53 @@ private boolean isSpherical() {
return m.getSymmetryClass(0.05) == MomentsOfInertia.SymmetryClass.SYMMETRIC;
}
- private boolean isValidPermutation(List permutation) {
- if (permutation.size() == 0) {
- return false;
- }
+ /**
+ * Checks if a particular permutation is allowed and superimposes well.
+ * Caches results.
+ * @param permutation
+ * @return null if invalid, or a rotation if valid
+ */
+ private Rotation isValidPermutation(List permutation) {
+ if (permutation.size() == 0) {
+ return null;
+ }
- // if this permutation is a duplicate, return false
- if (hashCodes.contains(permutation)) {
- return false;
+ // cached value
+ if (evaluatedPermutations.containsKey(permutation)) {
+ return evaluatedPermutations.get(permutation);
}
// check if permutation is allowed
if (! isAllowedPermutation(permutation)) {
- return false;
- }
-
- // get fold and make sure there is only one E (fold=1) permutation
- int fold = PermutationGroup.getOrder(permutation);
- if (rotations.getOrder() > 1 && fold == 1) {
- return false;
- }
-
- if (fold == 0 || subunits.getSubunitCount() % fold != 0) {
- return false;
+ evaluatedPermutations.put(permutation, null);
+ return null;
}
- // if this permutation is a duplicate, returns false
- return hashCodes.add(permutation);
+ // check if superimposes
+ Rotation rot = superimposePermutation(permutation);
+ return rot;
}
+ /**
+ * The permutation must map all subunits onto an equivalent subunit
+ * and no subunit onto itself
+ * @param permutation
+ * @return
+ */
private boolean isAllowedPermutation(List permutation) {
List seqClusterId = subunits.getSequenceClusterIds();
+ int selfaligned = 0;
for (int i = 0; i < permutation.size(); i++) {
int j = permutation.get(i);
- if (seqClusterId.get(i) != seqClusterId.get(j)) {
+ if ( seqClusterId.get(i) != seqClusterId.get(j)) {
return false;
}
+ if(i == j ) {
+ selfaligned++;
+ }
}
- return true;
+ // either identity (all self aligned) or all unique
+ return selfaligned == 0 || selfaligned == permutation.size();
}
/**
* Adds translational component to rotation matrix
@@ -260,7 +332,7 @@ private void combineWithTranslation(Matrix4d rotation) {
rotation.mul(rotation, centroidInverse);
}
- private Rotation createSymmetryOperation(List permutation, Matrix4d transformation, AxisAngle4d axisAngle, int fold, QuatSymmetryScores scores) {
+ private static Rotation createSymmetryOperation(List permutation, Matrix4d transformation, AxisAngle4d axisAngle, int fold, QuatSymmetryScores scores) {
Rotation s = new Rotation();
s.setPermutation(new ArrayList(permutation));
s.setTransformation(new Matrix4d(transformation));
@@ -299,6 +371,11 @@ private double calcDistanceThreshold() {
return distanceThreshold;
}
+ /**
+ * Compare this.transformedCoords with the original coords. For each
+ * subunit, return the transformed subunit with the closest position.
+ * @return A list mapping each subunit to the closest transformed subunit
+ */
private List getPermutation() {
List permutation = new ArrayList(transformedCoords.length);
double sum = 0.0f;
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/Subunits.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/Subunits.java
index 6e980be703..c639cae3bc 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/Subunits.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/core/Subunits.java
@@ -65,6 +65,12 @@ public class Subunits {
* @param modelNumbers Model number for the subunit
*/
public Subunits(List caCoords, List sequenceClusterIds, List pseudoStoichiometry, List minSequenceIdentity, List maxSequenceIdentity, List folds, List chainIds, List modelNumbers) {
+
+ for (int i=0; i triples = new ArrayList();
@@ -38,6 +42,7 @@ class Permute {
triples.add(tmp);
int n = 1;
+ // Unpermuted ±x,±y,±z
if (t.x != 0) {
for (int i = 0; i < n; ++i) {
Tuple3i m = triples.get(i);
@@ -66,6 +71,7 @@ class Permute {
return;
}
+ // At least one differing value
for (int i = 0; i < n; ++i) {
Point3i m = triples.get(i);
triples.add(new Point3i(m.y, m.z, m.x));
@@ -77,6 +83,7 @@ class Permute {
return;
}
+ // At least two differing values
for (int i = 0; i < n; ++i) {
Point3i m = triples.get(i);
triples.add(new Point3i(m.y, m.x, m.z));
@@ -94,7 +101,10 @@ public Point3i get(int i) {
};
/**
- *
+ * Sample possible orientations. An orientation can be represented as a
+ * quaternion or as a rotation axis and angle. The orientations are somewhat
+ * evenly distributed over orientation space, but the current implementation
+ * is not suited for statistically uniform sampling.
* @author Peter
*/
public final class SphereSampler {
@@ -125,16 +135,20 @@ public final class SphereSampler {
+ // Approximate spacing between grid points
private static final double delta = 0.15846;
+ // Amount of distortion towards grid corners to account for the projection back to a 4-sphere
private static final double sigma = 0.00;
- private static final int ntot = 7416;
- private static final int ncell = 309;
- private static final int nent = 18;
+ private static final int ntot = 7416; // total number of grid points over the 24 cells
+ private static final int ncell = 309; // number of grid points per cell
+ private static final int nent = 18; // number of distinct grid points (with k>=l>=m)
+ // Why not (5,5,3) and (5,5,5)? Would they overlap with other cells? -SB
private static final int[] k = { 0, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5};
private static final int[] l = { 0, 1, 0, 2, 2, 1, 3, 3, 0, 2, 2, 4, 4, 4, 1, 3, 3, 5};
private static final int[] m = { 0, 1, 0, 0, 2, 1, 1, 3, 0, 0, 2, 0, 2, 4, 1, 1, 3, 1};
+ // number of permutations to expect for each (k,l,m) tuple
private static final int[] mult = { 1, 8, 6, 12, 8, 24, 24, 8, 6, 24, 24, 12, 24, 8, 24, 48, 24, 24};
static
@@ -142,15 +156,29 @@ public final class SphereSampler {
List myorientations = new ArrayList();
+ // 60 equally spaced grid points covering all quaternions
+ // This could be removed, since the 48-cell bcc lattice has lower angle error -SB
for (int i = 0; i < IcosahedralSampler.getSphereCount(); i++) {
myorientations.add(IcosahedralSampler.getQuat4d(i));
}
+
+ // SB's interpretation of this code:
+ // Directly form a 4D grid over the 4-sphere of orientations. Start by
+ // making a 3D body-centered lattice with w=1. Then use the hypercube symmetries
+ // to extend this grid over the whole surface.
+ // The permuted (k,l,m) values together make a diagonal grid out to ±(5,5,5).
+ // The point spacing is distorted by the pind() function so that the
+ // projection of the points back to the 4-sphere will be more even.
+
+ // This is the c48u309 lattice from Karney 2006, with a max error of 10.07
+ // degrees.
+
List grid = new ArrayList();
int ncell1 = 0;
- for (int n = 0; n < nent; ++n) {
+ for (int n = 0; n < nent; ++n) { // for each tuple (k,l,m) above
Permute p = new Permute(new Point3i(k[n], l[n], m[n]));
assert (mult[n] == p.size());
- for (int i = 0; i < mult[n]; ++i) {
+ for (int i = 0; i < mult[n]; ++i) { // for each permutation
Point3i t = p.get(i);
grid.add(new Quat4d(1.0, pind(0.5 * t.x, delta, sigma), pind(
0.5 * t.y, delta, sigma), pind(0.5 * t.z, delta, sigma)));
@@ -158,6 +186,7 @@ public final class SphereSampler {
ncell1 += mult[n];
}
assert (ncell1 == ncell);
+ // Apply symmetry operations to distribute grid over all values of w
int nc = grid.size();
assert (nc == ncell);
for (int n = 1; n < 24; ++n) {
@@ -168,6 +197,7 @@ public final class SphereSampler {
qs.mul(q, grid.get(i));
grid.add(qs);
// s.add(times(q, s.getOrientation(i)), s.getWeight(i)); // this data set has no weights
+ // Actually, it does have weights but we don't care since we don't need uniform sampling. -SB
}
}
assert (grid.size() == ntot);
@@ -196,6 +226,10 @@ public static void getAxisAngle(int index, AxisAngle4f axisAngle) {
axisAngle.set(orientations.get(index));
}
+ /**
+ * @param index Index between 0 and {@link #getSphereCount()}-1
+ * @param axisAngle (Output) modified to contain the index-th sampled orientation
+ */
public static void getAxisAngle(int index, AxisAngle4d axisAngle) {
axisAngle.set(orientations.get(index));
diff --git a/biojava-survival/pom.xml b/biojava-survival/pom.xml
index d7c072c558..1f03bad9be 100644
--- a/biojava-survival/pom.xml
+++ b/biojava-survival/pom.xml
@@ -4,7 +4,7 @@
org.biojava
biojava
- 4.2.5
+ 4.2.6
biojava-survival
diff --git a/biojava-ws/pom.xml b/biojava-ws/pom.xml
index 490d79c32d..646bd14a0b 100644
--- a/biojava-ws/pom.xml
+++ b/biojava-ws/pom.xml
@@ -3,7 +3,7 @@
biojava
org.biojava
- 4.2.5
+ 4.2.6
biojava-ws
biojava-ws
@@ -19,7 +19,7 @@
org.biojava
biojava-core
- 4.2.5
+ 4.2.6
compile
diff --git a/pom.xml b/pom.xml
index e1daf1fcea..3993929e35 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
org.biojava
biojava
pom
- 4.2.5
+ 4.2.6
biojava
BioJava is an open-source project dedicated to providing a Java framework for processing biological
data. It provides analytical and statistical routines, parsers for common file formats and allows the
@@ -44,7 +44,7 @@
scm:git:git@github.com:biojava/biojava.git
https://github.com/biojava/biojava
- biojava-4.2.5
+ biojava-4.2.6