hetatms = StructureTools.getUnalignedGroups(rotCA);
+ int index = rotCA.length;
+ rotCA = Arrays.copyOf(rotCA, rotCA.length + hetatms.size());
for (Group g : hetatms) {
- rotCA = Arrays.copyOf(rotCA, rotCA.length + 1);
- rotCA[rotCA.length - 1] = g.getAtom(0);
+ rotCA[index] = g.getAtom(0);
+ index++;
}
// Transform the structure to ensure a full rotation in the display
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 02889a49cf..779e78be6c 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
@@ -25,6 +25,7 @@
import org.biojava.nbio.structure.Calc;
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.jama.Matrix;
import javax.vecmath.AxisAngle4d;
@@ -112,6 +113,10 @@ public Atom getScrewTranslation() {
public Vector3d getVector3dScrewTranslation() {
return new Vector3d(screwTranslation.getX(),screwTranslation.getY(),screwTranslation.getZ());
}
+
+ public double getTranslation() {
+ return Calc.amount(screwTranslation);
+ }
/**
* Get the component of translation perpendicular to the axis of rotation.
@@ -385,27 +390,17 @@ public String getJmolScript(Atom[] atoms){
}
/**
- * Returns a Jmol script which will display the axis of rotation. This
- * consists of a cyan arrow along the axis, plus an arc showing the angle
- * of rotation.
+ * Find a segment of the axis that covers the specified set of atoms.
*
- * As the rotation angle gets smaller, the axis of rotation becomes poorly
- * defined and would need to get farther and farther away from the protein.
- * This is not particularly useful, so we arbitrarily draw it parallel to
- * the translation and omit the arc.
- * @param atoms Some atoms from the protein, used for determining the bounds
- * of the axis.
- * @param axisID in case of representing more than one axis in the same jmol
- * panel, indicate the ID number.
- *
- * @return The Jmol script, suitable for calls to
- * {@link org.biojava.nbio.structure.align.gui.jmol.StructureAlignmentJmol#evalString() jmol.evalString()}
+ * Projects the input atoms onto the rotation axis and returns the bounding
+ * points.
+ *
+ * In the case of a pure translational axis, the axis location is undefined
+ * so the center of mass will be used instead.
+ * @param atoms
+ * @return two points defining the axis segment
*/
- public String getJmolScript(Atom[] atoms, int axisID){
- final double width=.5;// width of JMol object
- final String axisColor = "yellow"; //axis color
- final String screwColor = "orange"; //screw translation color
-
+ public Pair getAxisEnds(Atom[] atoms) {
// Project each Atom onto the rotation axis to determine limits
double min, max;
min = max = Calc.scalarProduct(rotationAxis,atoms[0]);
@@ -417,7 +412,7 @@ public String getJmolScript(Atom[] atoms, int axisID){
double uLen = Calc.scalarProduct(rotationAxis,rotationAxis);// Should be 1, but double check
min/=uLen;
max/=uLen;
-
+
// Project the origin onto the axis. If the axis is undefined, use the center of mass
Atom axialPt;
if(rotationPos == null) {
@@ -439,6 +434,34 @@ public String getJmolScript(Atom[] atoms, int axisID){
Atom axisMax = (Atom) axialPt.clone();
Calc.scaleAdd(max, rotationAxis, axisMax);
+ return new Pair<>(axisMin, axisMax);
+ }
+ /**
+ * Returns a Jmol script which will display the axis of rotation. This
+ * consists of a cyan arrow along the axis, plus an arc showing the angle
+ * of rotation.
+ *
+ * As the rotation angle gets smaller, the axis of rotation becomes poorly
+ * defined and would need to get farther and farther away from the protein.
+ * This is not particularly useful, so we arbitrarily draw it parallel to
+ * the translation and omit the arc.
+ * @param atoms Some atoms from the protein, used for determining the bounds
+ * of the axis.
+ * @param axisID in case of representing more than one axis in the same jmol
+ * panel, indicate the ID number.
+ *
+ * @return The Jmol script, suitable for calls to
+ * {@link org.biojava.nbio.structure.align.gui.jmol.StructureAlignmentJmol#evalString() jmol.evalString()}
+ */
+ public String getJmolScript(Atom[] atoms, int axisID){
+ final double width=.5;// width of JMol object
+ final String axisColor = "yellow"; //axis color
+ final String screwColor = "orange"; //screw translation color
+
+ Pair endPoints = getAxisEnds(atoms);
+ Atom axisMin = endPoints.getFirst();
+ Atom axisMax = endPoints.getSecond();
+
StringWriter result = new StringWriter();
// set arrow heads to a reasonable length
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/io/mmcif/MetalBondConsumer.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/io/mmcif/MetalBondConsumer.java
new file mode 100644
index 0000000000..34f85b6614
--- /dev/null
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/io/mmcif/MetalBondConsumer.java
@@ -0,0 +1,253 @@
+package org.biojava.nbio.structure.io.mmcif;
+
+import org.biojava.nbio.structure.io.FileParsingParameters;
+import org.biojava.nbio.structure.io.mmcif.chem.MetalBondDistance;
+import org.biojava.nbio.structure.io.mmcif.model.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by andreas on 6/9/16.
+ */
+public class MetalBondConsumer implements MMcifConsumer{
+
+
+ Map> definitions = new HashMap();
+
+ @Override
+ public void documentStart() {
+ definitions.clear();
+ }
+
+ @Override
+ public void documentEnd() {
+
+ // minimize memory consumption
+
+ for (List d : definitions.values()){
+ ArrayList a = (ArrayList)d;
+
+ a.trimToSize();
+ }
+
+ }
+
+ @Override
+ public void newAtomSite(AtomSite atom) {
+
+ }
+
+ @Override
+ public void newEntity(Entity entity) {
+
+ }
+
+
+ @Override
+ public void newEntityPolySeq(EntityPolySeq epolseq) {
+
+ }
+
+ @Override
+ public void newStructAsym(StructAsym sasym) {
+
+ }
+
+ @Override
+ public void setStruct(Struct struct) {
+
+ }
+
+ @Override
+ public void newDatabasePDBrev(DatabasePDBrev dbrev) {
+
+ }
+
+ @Override
+ public void newDatabasePDBrevRecord(DatabasePdbrevRecord dbrev) {
+
+ }
+
+ @Override
+ public void newDatabasePDBremark(DatabasePDBremark remark) {
+
+ }
+
+ @Override
+ public void newExptl(Exptl exptl) {
+
+ }
+
+ @Override
+ public void newCell(Cell cell) {
+
+ }
+
+ @Override
+ public void newSymmetry(Symmetry symmetry) {
+
+ }
+
+ @Override
+ public void newStructNcsOper(StructNcsOper sNcsOper) {
+
+ }
+
+ @Override
+ public void newStructRef(StructRef sref) {
+
+ }
+
+ @Override
+ public void newStructRefSeq(StructRefSeq sref) {
+
+ }
+
+ @Override
+ public void newStructRefSeqDif(StructRefSeqDif sref) {
+
+ }
+
+ @Override
+ public void newStructSite(StructSite sref) {
+
+ }
+
+ @Override
+ public void newStructSiteGen(StructSiteGen sref) {
+
+ }
+
+ @Override
+ public void newPdbxPolySeqScheme(PdbxPolySeqScheme ppss) {
+
+ }
+
+ @Override
+ public void newPdbxNonPolyScheme(PdbxNonPolyScheme ppss) {
+
+ }
+
+ @Override
+ public void newPdbxEntityNonPoly(PdbxEntityNonPoly pen) {
+
+ }
+
+ @Override
+ public void newStructKeywords(StructKeywords kw) {
+
+ }
+
+ @Override
+ public void newRefine(Refine r) {
+
+ }
+
+ @Override
+ public void newChemComp(ChemComp c) {
+
+ }
+
+ @Override
+ public void newChemCompDescriptor(ChemCompDescriptor ccd) {
+
+ }
+
+ @Override
+ public void newPdbxStructOperList(PdbxStructOperList structOper) {
+
+ }
+
+ @Override
+ public void newPdbxStrucAssembly(PdbxStructAssembly strucAssembly) {
+
+ }
+
+ @Override
+ public void newPdbxStrucAssemblyGen(PdbxStructAssemblyGen strucAssembly) {
+
+ }
+
+ @Override
+ public void newChemCompAtom(ChemCompAtom atom) {
+
+ }
+
+ @Override
+ public void newPdbxChemCompIndentifier(PdbxChemCompIdentifier id) {
+
+ }
+
+ @Override
+ public void newChemCompBond(ChemCompBond bond) {
+
+ }
+
+ @Override
+ public void newPdbxChemCompDescriptor(PdbxChemCompDescriptor desc) {
+
+ }
+
+ @Override
+ public void newEntitySrcGen(EntitySrcGen entitySrcGen) {
+
+ }
+
+ @Override
+ public void newEntitySrcNat(EntitySrcNat entitySrcNat) {
+
+ }
+
+ @Override
+ public void newEntitySrcSyn(EntitySrcSyn entitySrcSyn) {
+
+ }
+
+ @Override
+ public void newStructConn(StructConn structConn) {
+
+ }
+
+ @Override
+ public void newAuditAuthor(AuditAuthor aa) {
+
+ }
+
+ @Override
+ public void newGenericData(String category, List loopFields, List lineData) {
+
+ MetalBondDistance d = new MetalBondDistance();
+
+ d.setAtomType1(lineData.get(0));
+ d.setAtomType2(lineData.get(1));
+ d.setLowerLimit(Float.parseFloat(lineData.get(2)));
+ d.setUpperLimit(Float.parseFloat(lineData.get(3)));
+
+ List defs = definitions.get(d.getAtomType1());
+
+ if ( defs == null){
+ defs = new ArrayList<>();
+ definitions.put(d.getAtomType1(),defs);
+ }
+
+ defs.add(d);
+
+ }
+
+ @Override
+ public void setFileParsingParameters(FileParsingParameters params) {
+
+ }
+
+ @Override
+ public FileParsingParameters getFileParsingParameters() {
+ return null;
+ }
+
+ public Map> getDefinitions(){
+ return definitions;
+ }
+}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/io/mmcif/MetalBondParser.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/io/mmcif/MetalBondParser.java
new file mode 100644
index 0000000000..2a4853d935
--- /dev/null
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/io/mmcif/MetalBondParser.java
@@ -0,0 +1,66 @@
+package org.biojava.nbio.structure.io.mmcif;
+
+import org.biojava.nbio.structure.io.mmcif.chem.MetalBondDistance;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.InputStream;
+import java.util.*;
+
+import java.util.zip.GZIPInputStream;
+
+/**
+ * Created by andreas on 6/6/16.
+ */
+public class MetalBondParser {
+
+ private static final Logger logger = LoggerFactory.getLogger(MetalBondParser.class);
+
+ private static final String BONDS_FILE = "org/biojava/nbio/structure/bond_distance_limits.cif.gz";
+
+
+ static Map> definitions;
+
+ static {
+ definitions = init();
+ }
+
+
+ public static Map> getMetalBondDefinitions(){
+ return definitions;
+
+ }
+
+
+ private static Map> init(){
+
+ InputStream inputStream = MetalBondParser.class.getClassLoader().getResourceAsStream(BONDS_FILE);
+
+ if (inputStream == null) {
+ throw new RuntimeException("Could not find resource "+BONDS_FILE+". This probably means that your biojava.jar file is corrupt or incorrectly built.");
+ }
+
+ try {
+ GZIPInputStream gzIS = new GZIPInputStream(inputStream);
+
+ SimpleMMcifParser parser = new SimpleMMcifParser();
+
+ MetalBondConsumer consumer = new MetalBondConsumer();
+ parser.addMMcifConsumer(consumer);
+
+ parser.parse(gzIS);
+
+ Map> defs = consumer.getDefinitions();
+
+ return defs;
+
+ } catch ( Exception e){
+ logger.error(e.getMessage(),e);
+
+ }
+ return null;
+ }
+
+
+
+}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/io/mmcif/chem/MetalBondDistance.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/io/mmcif/chem/MetalBondDistance.java
new file mode 100644
index 0000000000..4d96521f6b
--- /dev/null
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/io/mmcif/chem/MetalBondDistance.java
@@ -0,0 +1,56 @@
+package org.biojava.nbio.structure.io.mmcif.chem;
+
+/** A bean that contains cutoffs for correctly detecting metal bonds.
+ * Definitions are in file bond_distance_limits.cif.gz
+ *
+ * Created by andreas on 6/9/16.
+ */
+public class MetalBondDistance {
+
+ private String atomType1;
+ private String atomType2;
+ private float lowerLimit;
+ private float upperLimit;
+
+ public String getAtomType1() {
+ return atomType1;
+ }
+
+ public void setAtomType1(String atomType1) {
+ this.atomType1 = atomType1;
+ }
+
+ public String getAtomType2() {
+ return atomType2;
+ }
+
+ public void setAtomType2(String atomType2) {
+ this.atomType2 = atomType2;
+ }
+
+ public float getLowerLimit() {
+ return lowerLimit;
+ }
+
+ public void setLowerLimit(float lowerLimit) {
+ this.lowerLimit = lowerLimit;
+ }
+
+ public float getUpperLimit() {
+ return upperLimit;
+ }
+
+ public void setUpperLimit(float upperLimit) {
+ this.upperLimit = upperLimit;
+ }
+
+ @Override
+ public String toString() {
+ return "MetalBindDistance{" +
+ "atomType1='" + atomType1 + '\'' +
+ ", atomType2='" + atomType2 + '\'' +
+ ", lowerLimit=" + lowerLimit +
+ ", upperLimit=" + upperLimit +
+ '}';
+ }
+}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/CeSymm.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/CeSymm.java
index 908d20d5f1..4e3841235b 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/CeSymm.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/CeSymm.java
@@ -250,20 +250,20 @@ protected static CeSymmResult align(Atom[] atoms, CESymmParameters params)
result.setStructureId(id);
// Determine the symmetry Type or get the one in params
- if (params.getSymmType() == SymmetryType.AUTO) {
+ SymmetryType type = params.getSymmType();
+ if (type == SymmetryType.AUTO) {
if (result.getSelfAlignment().getBlockNum() == 1) {
- result.setType(SymmetryType.OPEN);
+ type = SymmetryType.OPEN;
logger.info("Open Symmetry detected");
} else {
- result.setType(SymmetryType.CLOSED);
+ type = SymmetryType.CLOSED;
logger.info("Close Symmetry detected");
}
- } else
- result.setType(params.getSymmType());
+ }
// Do not try the refinement if the self-alignment is not significant
if (optimalAFP.getTMScore() < params.getUnrefinedScoreThreshold()){
- result.setSymmOrder(1);
+ result.setNumRepeats(1);
return result;
}
@@ -278,7 +278,7 @@ protected static CeSymmResult align(Atom[] atoms, CESymmParameters params)
break;
case SEQUENCE_FUNCTION:
// Does not work for OPEN alignments
- if (result.getType() == SymmetryType.CLOSED) {
+ if (type == SymmetryType.CLOSED) {
orderDetector = new SequenceFunctionOrderDetector(
params.getMaxSymmOrder(), 0.4f);
order = orderDetector.calculateOrder(
@@ -287,7 +287,7 @@ protected static CeSymmResult align(Atom[] atoms, CESymmParameters params)
}
case ANGLE:
// Does not work for OPEN alignments
- if (result.getType() == SymmetryType.CLOSED) {
+ if (type == SymmetryType.CLOSED) {
orderDetector = new AngleOrderDetectorPlus(
params.getMaxSymmOrder());
order = orderDetector.calculateOrder(
@@ -300,7 +300,7 @@ protected static CeSymmResult align(Atom[] atoms, CESymmParameters params)
atoms);
break;
}
- result.setSymmOrder(order);
+ result.setNumRepeats(order);
// REFINEMENT
SymmetryRefiner refiner = null;
@@ -309,7 +309,7 @@ protected static CeSymmResult align(Atom[] atoms, CESymmParameters params)
return result;
case SEQUENCE_FUNCTION:
// Does not work for OPEN alignments
- if (result.getType() == SymmetryType.CLOSED) {
+ if (type == SymmetryType.CLOSED) {
refiner = new SequenceFunctionRefiner();
break;
}
@@ -323,7 +323,7 @@ protected static CeSymmResult align(Atom[] atoms, CESymmParameters params)
// Refinement succeeded, store results
result.setMultipleAlignment(msa);
- result.setSymmOrder(msa.size());
+ result.setNumRepeats(msa.size());
result.setRefined(true);
} catch (RefinerFailedException e) {
@@ -331,41 +331,13 @@ protected static CeSymmResult align(Atom[] atoms, CESymmParameters params)
return result;
}
- // STEP 4: determine the symmetry axis and its repeat dependencies
+ // STEP 4: symmetry axes
SymmetryAxes axes = new SymmetryAxes();
int order = result.getMultipleAlignment().size();
Matrix4d axis = result.getMultipleAlignment().getBlockSet(0)
.getTransformations().get(1);
-
- List> superposition = new ArrayList>();
- List chain1 = new ArrayList();
- List chain2 = new ArrayList();
- superposition.add(chain1);
- superposition.add(chain2);
- List repeatTrans = new ArrayList();
-
- switch (result.getType()) {
- case CLOSED:
-
- for (int bk = 0; bk < order; bk++) {
- chain1.add(bk);
- chain2.add((bk + 1) % order);
- repeatTrans.add(bk);
- }
- axes.addAxis(axis, superposition, repeatTrans, order);
- break;
-
- default: // case OPEN:
-
- repeatTrans.add(0);
- for (int bk = 0; bk < order - 1; bk++) {
- chain1.add(bk);
- chain2.add(bk + 1);
- repeatTrans.add(bk + 1);
- }
- axes.addAxis(axis, superposition, repeatTrans, order);
- break;
- }
+ axes.addAxis(axis, order, type);
+
result.setAxes(axes);
return result;
}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/CeSymmIterative.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/CeSymmIterative.java
index 0a55d6d2f1..669cefcfe4 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/CeSymmIterative.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/CeSymmIterative.java
@@ -29,6 +29,7 @@
import javax.vecmath.Matrix4d;
import org.biojava.nbio.structure.Atom;
+import org.biojava.nbio.structure.ResidueNumber;
import org.biojava.nbio.structure.StructureException;
import org.biojava.nbio.structure.StructureIdentifier;
import org.biojava.nbio.structure.align.multiple.Block;
@@ -42,6 +43,7 @@
import org.biojava.nbio.structure.secstruc.SecStrucTools;
import org.biojava.nbio.structure.secstruc.SecStrucType;
import org.biojava.nbio.structure.symmetry.internal.CESymmParameters.RefineMethod;
+import org.biojava.nbio.structure.symmetry.internal.CESymmParameters.SymmetryType;
import org.biojava.nbio.structure.symmetry.utils.SymmetryTools;
import org.jgrapht.UndirectedGraph;
import org.jgrapht.alg.ConnectivityInspector;
@@ -51,8 +53,8 @@
import org.slf4j.LoggerFactory;
/**
- * Iterative version of CeSymm that aims at identifying all symmetry axis
- * (internal or quaternary) of a particular structure.
+ * Iterative version of CeSymm that aims at identifying all symmetry axis of a
+ * structure.
*
* Works in the following way:
*
@@ -61,7 +63,6 @@
* - Run CeSymm on one of the symmetric units to find further symmetries.
*
- Repeat the last two steps until no more significant results are found.
*
- Map back all residues in a multiple alignment of the repeats.
- *
- Run a final optimization of all symmetric units correctly superimposed.
*
*
*
@@ -75,10 +76,8 @@ public class CeSymmIterative {
.getLogger(CeSymmIterative.class);
private CESymmParameters params;
- private Atom[] allAtoms;
- private UndirectedGraph alignGraph; // alignment graph
- private List levels; // msa at each level
- private CeSymmResult result;
+ private UndirectedGraph alignGraph; // cumulative
+ private List levels; // symmetry at each level
/**
* For the iterative algorithm to work properly the refinement and
@@ -91,7 +90,7 @@ public class CeSymmIterative {
public CeSymmIterative(CESymmParameters param) {
params = param;
alignGraph = new SimpleGraph(DefaultEdge.class);
- levels = new ArrayList();
+ levels = new ArrayList();
}
/**
@@ -107,29 +106,10 @@ public CeSymmIterative(CESymmParameters param) {
*/
public CeSymmResult execute(Atom[] atoms) throws StructureException {
- allAtoms = atoms;
+ // First iterate through all levels and then reconstruct all repeats
+ iterate(atoms);
+ return reconstructSymmResult(atoms);
- // True if symmetry found
- boolean symm = iterate(atoms);
-
- if (symm) {
- if (!buildAlignment())
- return result;
-
- recoverAxes();
-
- // Set the transformations and scores of the final alignment
- MultipleAlignment msa = result.getMultipleAlignment();
- SymmetryTools.updateSymmetryTransformation(result.getAxes(), msa,
- atoms);
- double tmScore = MultipleAlignmentScorer.getAvgTMScore(msa)
- * msa.size();
- double rmsd = MultipleAlignmentScorer.getRMSD(msa);
- msa.putScore(MultipleAlignmentScorer.AVGTM_SCORE, tmScore);
- msa.putScore(MultipleAlignmentScorer.RMSD, rmsd);
- }
-
- return result;
}
/**
@@ -141,60 +121,62 @@ public CeSymmResult execute(Atom[] atoms) throws StructureException {
* @return true if any symmetry was found, false if asymmetric
* @throws StructureException
*/
- private boolean iterate(Atom[] atoms) throws StructureException {
+ private void iterate(Atom[] atoms) throws StructureException {
logger.debug("Starting new iteration...");
// Return if the Atom array is too short
- if (atoms.length <= params.getWinSize()
- || atoms.length <= params.getMinCoreLength()) {
- if (result != null) {
- logger.debug("Aborting iteration due to insufficient Atom "
- + "array length: %d", atoms.length);
- return !levels.isEmpty();
- }
+ if ((atoms.length <= params.getWinSize()
+ || atoms.length <= params.getMinCoreLength())
+ && !levels.isEmpty()) {
+ logger.debug("Aborting iteration due to insufficient Atom "
+ + "array length: %d", atoms.length);
+ return;
}
// Return if the maximum levels of symmetry have been reached
if (params.getSymmLevels() > 0) {
if (levels.size() == params.getSymmLevels())
- return true;
+ return;
}
// Perform one level CeSymm alignment
- CeSymmResult r = CeSymm.analyzeLevel(atoms, params);
- if (result == null)
- result = r;
+ CeSymmResult result = CeSymm.analyzeLevel(atoms, params);
- if (params.getRefineMethod() == RefineMethod.NOT_REFINED)
- return false;
- else if (!r.isSignificant())
- return !levels.isEmpty();
+ if (params.getRefineMethod() == RefineMethod.NOT_REFINED
+ || !result.isSignificant()) {
+ if (levels.isEmpty())
+ levels.add(result);
+ return;
+ }
// Generate the Atoms of one of the symmetric repeat
Integer start = null;
int it = 0;
while (start == null) {
- start = r.getMultipleAlignment().getBlocks().get(0).getAlignRes()
- .get(0).get(it);
+ start = result.getMultipleAlignment().getBlocks().get(0)
+ .getAlignRes().get(0).get(it);
it++;
}
Integer end = null;
- it = r.getMultipleAlignment().getBlocks().get(0).getAlignRes().get(0)
- .size() - 1;
+ it = result.getMultipleAlignment().getBlocks().get(0).getAlignRes()
+ .get(0).size() - 1;
while (end == null) {
- end = r.getMultipleAlignment().getBlocks().get(0).getAlignRes()
- .get(0).get(it);
+ end = result.getMultipleAlignment().getBlocks().get(0)
+ .getAlignRes().get(0).get(it);
it--;
}
Atom[] atomsR = Arrays.copyOfRange(atoms, start, end + 1);
// Check the SSE requirement
- if (countHelixStrandSSE(atomsR) < params.getSSEThreshold())
- return !levels.isEmpty();
+ if (countHelixStrandSSE(atomsR) < params.getSSEThreshold()) {
+ if (levels.isEmpty())
+ levels.add(result);
+ return;
+ }
// If symmetric store the residue dependencies in alignment graph
- Block b = r.getMultipleAlignment().getBlock(0);
+ Block b = result.getMultipleAlignment().getBlock(0);
for (int pos = 0; pos < b.length(); pos++) {
for (int su = 0; su < b.size() - 1; su++) {
Integer pos1 = b.getAlignRes().get(su).get(pos);
@@ -209,26 +191,32 @@ else if (!r.isSignificant())
}
// Iterate further on those Atoms (of the first repeat only)
- levels.add(r.getMultipleAlignment());
- return iterate(atomsR);
+ levels.add(result);
+ iterate(atomsR);
}
/**
- * After all the analysis iteratives have finished, the final
- * MultipleAlignment object is constructed using the alignment graph.
+ * After all the analysis iterations have finished, the final Result object
+ * is reconstructed using the cumulative alignment graph.
*
- * @return true if the MultipleAlignment could be reconstructed, false
- * otherwise
+ * @param atoms
+ * the original structure atoms
+ * @return CeSymmResult reconstructed symmetry result
* @throws StructureException
*/
- private boolean buildAlignment() throws StructureException {
-
- // If one level, nothing to build
- if (levels.size() == 1) {
- result.setSymmLevels(1);
- return false;
- }
+ private CeSymmResult reconstructSymmResult(Atom[] atoms)
+ throws StructureException {
+
+ // If one level, nothing to build or calculate
+ if (levels.size() == 1)
+ return levels.get(0);
+ CeSymmResult result = new CeSymmResult();
+ result.setSelfAlignment(levels.get(0).getSelfAlignment());
+ result.setStructureId(levels.get(0).getStructureId());
+ result.setAtoms(levels.get(0).getAtoms());
+ result.setParams(levels.get(0).getParams());
+
// Initialize a new multiple alignment
MultipleAlignment msa = new MultipleAlignmentImpl();
msa.getEnsemble().setAtomArrays(new ArrayList());
@@ -249,10 +237,10 @@ private boolean buildAlignment() throws StructureException {
for (Set comp : comps)
groups.add(new ResidueGroup(comp));
- // Calculate thr order of symmetry from levels
+ // Calculate the total number of repeats
int order = 1;
- for (MultipleAlignment m : levels)
- order *= m.size();
+ for (CeSymmResult sr : levels)
+ order *= sr.getMultipleAlignment().size();
for (int su = 0; su < order; su++)
b.getAlignRes().add(new ArrayList());
@@ -262,71 +250,57 @@ private boolean buildAlignment() throws StructureException {
continue;
group.combineWith(b.getAlignRes());
}
+
+ // The reconstruction failed, so the top level is returned
if (b.length() == 0)
- return false;
+ return levels.get(0);
for (int su = 0; su < order; su++) {
Collections.sort(b.getAlignRes().get(su));
- msa.getEnsemble().getAtomArrays().add(allAtoms);
+ msa.getEnsemble().getAtomArrays().add(atoms);
msa.getEnsemble().getStructureIdentifiers()
.add(result.getStructureId());
}
result.setMultipleAlignment(msa);
result.setRefined(true);
- result.setSymmOrder(order);
- result.setSymmLevels(levels.size());
+ result.setNumRepeats(order);
+
+ SymmetryAxes axes = recoverAxes(result);
+ result.setAxes(axes);
- return true;
+ // Set the transformations and scores of the final alignment
+ SymmetryTools
+ .updateSymmetryTransformation(result.getAxes(), msa);
+ double tmScore = MultipleAlignmentScorer.getAvgTMScore(msa)
+ * msa.size();
+ double rmsd = MultipleAlignmentScorer.getRMSD(msa);
+ msa.putScore(MultipleAlignmentScorer.AVGTM_SCORE, tmScore);
+ msa.putScore(MultipleAlignmentScorer.RMSD, rmsd);
+
+ return result;
}
/**
* The symmetry axes of each level are recovered after the symmetry analysis
* iterations have finished, using the stored MultipleAlignment at each
* symmetry level.
+ * @return SymmetryAxes
*/
- private void recoverAxes() {
+ private SymmetryAxes recoverAxes(CeSymmResult result) {
SymmetryAxes axes = new SymmetryAxes();
- int size = result.getMultipleAlignment().size();
- int parents = 1;
-
for (int m = 0; m < levels.size(); m++) {
- MultipleAlignment align = levels.get(m);
+ MultipleAlignment align = levels.get(m).getMultipleAlignment();
Matrix4d axis = align.getBlockSet(0).getTransformations().get(1);
+ SymmetryType type = levels.get(m).getAxes().getElementaryAxis(0).getSymmType();
+ int order = align.size();
- int subsize = align.size();
- parents *= subsize;
- size /= subsize;
-
- List repeatTransform = new ArrayList();
- for (int i = 0; i < size * parents; i++) {
- repeatTransform.add(0);
- }
-
- List> superpose = new ArrayList>();
- superpose.add(new ArrayList());
- superpose.add(new ArrayList());
-
- for (int su = 0; su < subsize - 1; su++) {
- for (int s = 0; s < size; s++) {
- Integer subIndex1 = su * size + s;
- Integer subIndex2 = (su + 1) * size + s;
- superpose.get(0).add(subIndex1);
- superpose.get(1).add(subIndex2);
- }
- }
-
- for (int p = 0; p < parents; p++) {
- for (int s = 0; s < size; s++) {
- repeatTransform.set(p * size + s, p % subsize);
- }
- }
- axes.addAxis(axis, superpose, repeatTransform, subsize);
+ axes.addAxis(axis, order, type);
}
- result.setAxes(axes);
+ return axes;
}
/**
@@ -341,11 +315,27 @@ private static int countHelixStrandSSE(Atom[] atoms) {
List sses = SecStrucTools
.getSecStrucElements(SymmetryTools.getGroups(atoms));
int count = 0;
+
+ //keep track of different helix types
+ boolean helix = false;
+ int hEnd = 0;
+
for (SecStrucElement sse : sses) {
SecStrucType t = sse.getType();
- if (t.isBetaStrand() || t.isHelixType()) {
+ if (t.isBetaStrand()) {
+ helix = false;
count++;
- }
+ } else if (t.isHelixType()){
+ if (helix){
+ // If this helix is contiguous to the previous
+ if (sse.getRange().getStart().getSeqNum() + 1 == hEnd)
+ hEnd = sse.getRange().getEnd().getSeqNum();
+ else
+ count++;
+ } else
+ count++;
+ } else
+ helix = false;
}
return count;
}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/CeSymmResult.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/CeSymmResult.java
index 27647c341a..8574c2e984 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/CeSymmResult.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/CeSymmResult.java
@@ -56,24 +56,22 @@ public class CeSymmResult {
private Atom[] atoms;
private CESymmParameters params;
- private SymmetryAxes axes;
+ private SymmetryAxes axes = new SymmetryAxes();
private String symmGroup;
- private int symmOrder;
- private int symmLevels;
+ private int numRepeats;
private boolean refined;
- private SymmetryType type;
/**
- * Conditions checked are: score above the threshold, order higher than 1
- * and refinement succeeded.
+ * Conditions checked are: score above the threshold, number of repeats
+ * higher than 1 and refinement succeeded.
*
* @return true if significant, false otherwise
*/
public boolean isSignificant() {
// In any case if the order is 1 it is asymmetric
- if (symmOrder < 2)
+ if (numRepeats < 2)
return false;
// If the TM-Score before refinement is below the threshold
@@ -108,12 +106,12 @@ public List getRepeatsID() throws StructureException {
return null;
List repeats = new ArrayList(
- symmOrder);
+ numRepeats);
String pdbId = structureId.toCanonical().getPdbId();
Block align = multipleAlignment.getBlocks().get(0);
- for (int su = 0; su < symmOrder; su++) {
+ for (int su = 0; su < numRepeats; su++) {
// Get the start and end residues of the repeat
ResidueNumber res1 = atoms[align.getStartResidue(su)].getGroup()
.getResidueNumber();
@@ -131,9 +129,9 @@ public List getRepeatsID() throws StructureException {
@Override
public String toString() {
- return structureId + ", symmGroup=" + getSymmGroup() + ", symmOrder="
- + symmOrder + ", symmLevels=" + symmLevels + ", refined="
- + refined + ", type=" + type + " | " + params;
+ return structureId + ", symmGroup=" + getSymmGroup() + ", numRepeats="
+ + numRepeats + ", symmLevels=" + axes.getNumLevels()
+ + ", refined=" + refined + " | " + params;
}
public MultipleAlignment getMultipleAlignment() {
@@ -174,15 +172,15 @@ public void setAxes(SymmetryAxes axes) {
*
* @return the order of symmetry if the result is significant
*/
- public int getSymmOrder() {
+ public int getNumRepeats() {
if (isSignificant())
- return symmOrder;
+ return numRepeats;
else
return 1;
}
- public void setSymmOrder(int symmOrder) {
- this.symmOrder = symmOrder;
+ public void setNumRepeats(int symmOrder) {
+ this.numRepeats = symmOrder;
}
public boolean isRefined() {
@@ -208,8 +206,9 @@ public String getSymmGroup() {
symmGroup = "R"; // could not find group
} else {
// in case significant but not refined
- if (type.equals(SymmetryType.CLOSED))
- symmGroup = "C" + symmOrder;
+ if (axes.getElementaryAxis(0).getSymmType()
+ .equals(SymmetryType.CLOSED))
+ symmGroup = "C" + numRepeats;
else
symmGroup = "R";
}
@@ -224,14 +223,6 @@ public void setSymmGroup(String symmGroup) {
this.symmGroup = symmGroup;
}
- public SymmetryType getType() {
- return type;
- }
-
- public void setType(SymmetryType type) {
- this.type = type;
- }
-
public Atom[] getAtoms() {
return atoms;
}
@@ -241,11 +232,7 @@ public void setAtoms(Atom[] atoms) {
}
public int getSymmLevels() {
- return symmLevels;
- }
-
- public void setSymmLevels(int symmLevels) {
- this.symmLevels = symmLevels;
+ return axes.getNumLevels();
}
public StructureIdentifier getStructureId() {
@@ -257,8 +244,8 @@ public void setStructureId(StructureIdentifier structureId) {
}
/**
- * Return a String describing the reasons for the CE-Symm final decision
- * in this particular result.
+ * Return a String describing the reasons for the CE-Symm final decision in
+ * this particular result.
*
* @return String decision reason
*/
@@ -270,8 +257,9 @@ public String getReason() {
return String.format("Insignificant self-alignment (TM=%.2f)", tm);
}
// 2. Asymmetric because order detector returned 1
- if (symmOrder == 1) {
- return String.format("Order detector found asymmetric alignment (TM=%.2f)", tm);
+ if (numRepeats == 1) {
+ return String.format(
+ "Order detector found asymmetric alignment (TM=%.2f)", tm);
}
// Check that the user requested refinement
@@ -280,8 +268,8 @@ public String getReason() {
if (!refined) {
return "Refinement failed";
}
- tm = multipleAlignment.getScore(
- MultipleAlignmentScorer.AVGTM_SCORE);
+ tm = multipleAlignment
+ .getScore(MultipleAlignmentScorer.AVGTM_SCORE);
// 4. Asymmetric because refinement & optimization were not
// significant
if (!isSignificant()) {
@@ -297,15 +285,15 @@ public String getReason() {
}
String hierarchical = "";
- if (symmLevels > 1) {
+ if (axes.getNumLevels() > 1) {
hierarchical = String.format("; Contains %d levels of symmetry",
- symmLevels);
+ axes.getNumLevels());
}
// 5. Symmetric.
// a. Open. Give # repeats (1n0r.A)
- if (type == SymmetryType.OPEN) {
+ if (axes.getElementaryAxis(0).getSymmType() == SymmetryType.OPEN) {
return String.format("Contains %d open repeats (TM=%.2f)%s",
- getSymmOrder(), tm, hierarchical);
+ getNumRepeats(), tm, hierarchical);
}
// b. Closed, non-hierarchical (1itb.A)
// c. Closed, heirarchical (4gcr)
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/SymmOptimizer.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/SymmOptimizer.java
index b10e41a00b..6f24fefa6d 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/SymmOptimizer.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/SymmOptimizer.java
@@ -351,7 +351,7 @@ private void updateMultipleAlignment() throws StructureException,
throw new RefinerFailedException(
"Optimization converged to length 0");
- SymmetryTools.updateSymmetryTransformation(axes, msa, atoms);
+ SymmetryTools.updateSymmetryTransformation(axes, msa);
}
/**
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/SymmetryAxes.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/SymmetryAxes.java
index fc0af1f14e..1f09fd2f70 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/SymmetryAxes.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/internal/SymmetryAxes.java
@@ -21,19 +21,33 @@
package org.biojava.nbio.structure.symmetry.internal;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Arrays;
+import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import javax.vecmath.Matrix4d;
-import org.biojava.nbio.structure.symmetry.utils.SymmetryTools;
+import org.biojava.nbio.structure.align.multiple.MultipleAlignment;
+import org.biojava.nbio.structure.align.util.RotationAxis;
+import org.biojava.nbio.structure.symmetry.internal.CESymmParameters.SymmetryType;
/**
* Data Structure that stores all the symmetry axis that describe
* the symmetry of a structure. Generalizes to all types of symmetry,
* the classic ones (Cn, Dn) and any hierarchical or local symmetries.
*
+ * Hierarchical symmetry can be visualized as a tree, where each level
+ * has a fixed branching factor. Each level of the tree is associated
+ * with a transformation operator, whose order determines the degree of
+ * nodes at that level of the tree. Leaves of the tree implicitly
+ * represent aligned repeats (indexed 0 to n-1), so care must be taken to
+ * keep external references to the repeats (e.g. rows of a
+ * {@link MultipleAlignment} in the same order implied by the tree.
+ *
+ * Each node of the tree specifies an alignment between those repeats
+ * below each of its children. It is also associated with a symmetry axis,
+ * which is calculated based on the associated operator as well as any parent
+ * operators.
* It also stores the parts of the structure (symmetric units) involved
* in each axis, in addition to the way to calculate them.
*
@@ -47,49 +61,138 @@
*
*/
public class SymmetryAxes {
-
- /**
- * List of all symmetry axis. They are sorted from higher to lower
- * in the symmetry hierarchy, where higher means that they apply
- * more globally and lower means that they apply to a local region
- * of the higher axis division.
+ /*
+ * Implementation note: The tree is a nice explanation and a good image
+ * for developing algorithms, but it is not constructed explicitly.
+ * Instead, we just store one elementary axis for each level and reconstruct
+ * which operators apply to a particular leaf based on that leaf's index.
*/
- private List axes;
-
+
/**
- * Tree of the symmetry axes hierarchy of a structure. Every index
- * is the axis index and the integer stored means the number of parts
- * this axis divides the structure in.
+ * Represents an axis of symmetry
+ * @author Spencer Bliven
+ *
*/
- private List tree;
+ public static class Axis {
+ private Matrix4d operator;
+ private int order;
+ private SymmetryType symmType;
+ private int level;
+ //private int indexInLevel;
+ private int firstRepeat;
+ private RotationAxis rotAxis;
- /**
- * Matrix of size [repeats][axes]. The first index of the matrix
- * indicates which repeat is considered, and the second index
- * indicates which axis. The integer stored means how many times
- * the transformation has to be applied to the repeat, and a value
- * of 0 means that this repeat is not affected by the axis.
- */
- private List> repeatTransforms;
+ public Axis(Matrix4d operator, int order, SymmetryType type, int level, int firstRepeat) {
+ if (order < 2) {
+ throw new IllegalArgumentException("A symmetry axis should divide a structure in > 2 parts");
+ }
+ if(type != SymmetryType.OPEN && type != SymmetryType.CLOSED) {
+ throw new IllegalArgumentException("Invalid symmetry type. Only OPEN and CLOSED are allowed");
+ }
+ this.operator = operator;
+ this.order = order;
+ this.symmType = type;
+ setLevel(level);
+ setFirstRepeat(firstRepeat);
+ rotAxis = null;
+ }
+ /**
+ * Get the transformation operator for this axis as an homogeneous matrix
+ * @return the transformation operator
+ */
+ public Matrix4d getOperator() {
+ return operator;
+ }
+ public void setOperator(Matrix4d op) {
+ this.operator = op;
+ }
+ /**
+ * Get the order of this axis (closed symm) or the number of repeats
+ * (open symm)
+ * @return the order
+ */
+ public int getOrder() {
+ return order;
+ }
+ /**
+ * @return the symmType (OPEN or CLOSED only)
+ */
+ public SymmetryType getSymmType() {
+ return symmType;
+ }
+
+ /**
+ * Get the transformation operator as a rotation axis. For open
+ * symmetry this will have a non-zero screw component.
+ * @return a RotationAxis for this Axis
+ */
+ public RotationAxis getRotationAxis() {
+ if( rotAxis == null) {
+ rotAxis = new RotationAxis(operator);
+ }
+ return rotAxis;
+ }
+ /**
+ * @return The level of this axis within it's parent hierarchy, or -1 if unset
+ */
+ public int getLevel() {
+ return level;
+ }
+ /**
+ *
+ * @param level The level of this axis within it's parent hierarchy. Must be positive
+ */
+ public void setLevel(int level) {
+ if(level < 0) throw new IndexOutOfBoundsException("Level must be positive");
+ this.level = level;
+ }
+// /**
+// * Each level can contain multiple equivalent axes. This index is
+// * used to distinguish them.
+// * @return the index of this axis relative to others at the same level
+// */
+// public int getIndexInLevel() {
+// return indexInLevel;
+// }
+// /**
+// *
+// * @param indexInLevel the index of this axis relative to others at the same level
+// */
+// public void setIndexInLevel(int indexInLevel) {
+// if( indexInLevel < 0 || getOrder() <= indexInLevel )
+// throw new IndexOutOfBoundsException("Invalid index for order "+getOrder());
+// this.indexInLevel = indexInLevel;
+// }
+ /**
+ * Get the index of the first repeat used by this axis
+ * @return the firstRepeat
+ */
+ public int getFirstRepeat() {
+ return firstRepeat;
+ }
+ /**
+ * @param firstRepeat the index of the first repeat used by this axis
+ */
+ public void setFirstRepeat(int firstRepeat) {
+ this.firstRepeat = firstRepeat;
+ }
+ }
+
/**
- * The list of integers defines which repeats are involved in this axis
- * and how the axis transformation is computed. The list has size 2 for
- * the first index and any size for the second index. Describes that all
- * repeats in the first list superimposed to all repeats of the second
- * list should generate the axis transformation.
+ * List of all symmetry axis. They are sorted from higher to lower
+ * in the symmetry hierarchy, where higher means that they apply
+ * more globally and lower means that they apply to a local region
+ * of the higher axis division.
*/
- private Map>> mapAxisRepeats;
+ private final List axes;
/**
* Constructor.
* Initializes variables only.
*/
public SymmetryAxes(){
- axes = new ArrayList();
- mapAxisRepeats = new HashMap>>();
- repeatTransforms = new ArrayList>();
- tree = new ArrayList();
+ axes = new ArrayList<>();
}
/**
@@ -105,7 +208,10 @@ public SymmetryAxes(){
*
* @throws IllegalArgumentException if the repeat relation is in the
* wrong format: should be double List of equal sizes.
+ * @deprecated Use {@link #addAxis(Matrix4d, int, SymmetryType)} instead.
+ * Repeats and Superposition are now inferred automatically.
*/
+ @Deprecated
public void addAxis(Matrix4d axis, List> superposition,
List repeats, Integer division) {
@@ -117,41 +223,65 @@ public void addAxis(Matrix4d axis, List> superposition,
throw new IllegalArgumentException(
"Wrong superposition format: not equal List sizes.");
}
- if (division < 2) throw new IllegalArgumentException(
- "A symmetry axis should divide a structure in > 2 parts");
-
- axes.add(axis);
- tree.add(division);
-
- //Extend the double List by the necessary rows
- while (repeatTransforms.size() < repeats.size()){
- List list = new ArrayList();
- for (int a=0; a superPos1 = superposition.get(1);
+ if(superPos1.get(0) > superPos1.get(superPos1.size()-1)) {
+ type = SymmetryType.CLOSED;
+ } else {
+ type = SymmetryType.OPEN;
}
+ this.addAxis(axis,division,type);
+ }
+ /**
+ * Adds a new axis of symmetry to the bottom level of the tree
+ *
+ * @param axis the new axis of symmetry found
+ * @param order number of parts that this axis divides the structure in
+ * @param type indicates whether the axis has OPEN or CLOSED symmetry
+ */
+ public void addAxis(Matrix4d axis, int order, SymmetryType type) {
+ axes.add(new Axis(axis,order,type,axes.size(),0));
+ }
- //Check that the repeat indices match
- for (int c=0; c<2; c++){
- for (int p=0; prepeatTransforms.size()){
- throw new IllegalArgumentException(
- "Repeat indicex in superposition out of bounds");
- }
- }
+ /**
+ * Return a list giving the number of times each axis must be applied
+ * to generate the given repeat.
+ *
+ * For instance, for a D3 case getAxisCounts(4) would return [2,0],
+ * indicating that repeat 4 is generated by two applications of the 3-fold
+ * axis followed by 0 applications of the two-fold axis.
+ *
+ * @param repeat Index of the desired repeat
+ * @return array of the same length as axes giving the number of times
+ * to apply each axis.
+ */
+ private int[] getAxisCounts(int repeat) {
+ int[] counts = new int[getNumLevels()];
+
+ for(int i = counts.length-1; i >= 0; i--) {
+ int d = axes.get(i).getOrder();
+ counts[i] = repeat % d;
+ repeat /= d;
}
- mapAxisRepeats.put(axes.size()-1, superposition);
+ assert repeat == 0 : "Invalid repeat index";
+ return counts;
}
+// /**
+// * Inverse of {@link #getAxisCounts(int)}; Calculates the repeat for a
+// * particular number of applications of each axis
+// * @param counts Number of times to apply each axis
+// * @return Repeat index
+// */
+// private int getRepeatIndex(int[] counts) {
+// int repeat = 0;
+// for(int i = 0; i< counts.length; i++) {
+// repeat += counts[i]*axes.get(i).getOrder();
+// }
+// return repeat;
+// }
/**
* Updates an axis of symmetry, after the superposition changed.
*
@@ -159,62 +289,194 @@ public void addAxis(Matrix4d axis, List> superposition,
* @param newAxis
*/
public void updateAxis(Integer index, Matrix4d newAxis){
- axes.set(index, newAxis);
+ axes.get(index).setOperator(newAxis);
}
/**
- * Return all elementary axes of symmetry of the structure, that is,
+ * Return the operator for all elementary axes of symmetry of the structure, that is,
* the axes stored in the List as unique and from which all the symmetry
* axes are constructed.
*
* @return axes elementary axes of symmetry.
*/
public List getElementaryAxes(){
+ List ops = new ArrayList(getNumLevels());
+ for(Axis axis : axes) {
+ ops.add(axis.getOperator());
+ }
+ return ops;
+ }
+
+ /**
+ * Return all elementary axes of symmetry of the structure, that is,
+ * the axes stored in the List as unique and from which all the symmetry
+ * axes are constructed.
+ *
+ * @return axes elementary axes of symmetry.
+ */
+ public List getElementaryAxesObjects() {
return axes;
}
/**
- * Return the repeat superposition relation needed to obtain the
- * axis of symmetry (which repeats and in which order have to be
- * superimposed to obtain the axis).
+ * Get the indices of participating repeats in Cauchy two-line form.
+ *
+ * Returns two lists of the same length.
+ * The first gives a list of all repeat indices which are aligned
+ * at the specified level of symmetry (e.g. 0 through the degree of this level).
+ * The second list gives the corresponding repeats after applying the
+ * operator once.
*
- * @param index the axis index
+ * @param level the axis index
* @return the double List of repeat relations, or null if the
- * axis is not already stored.
+ * level is invalid
+ * @see #getRepeatsCyclicForm(int, int) for an equivalent specification with half the memory
*/
- public List> getRepeatRelation(Integer index){
- return mapAxisRepeats.get(index);
+ public List> getRepeatRelation(int level){
+ return getRepeatRelation(level,0);
}
+ public List> getRepeatRelation(Axis axis){
+ return getRepeatRelation(axis.getLevel(),axis.getFirstRepeat());
+ }
+
+ public List> getRepeatRelation(int level, int firstRepeat) {
+ Axis axis = axes.get(level);
+ int m = getNumRepeats(level+1);//size of the children
+ int d = axis.getOrder(); // degree of this node
+ int n = m*d; // number of repeats included
+ if(firstRepeat % n != 0)
+ throw new IllegalArgumentException(String.format("Repeat %d cannot start a block at level %s of this tree",firstRepeat,level));
+ if(axis.getSymmType() == SymmetryType.OPEN) {
+ n -= m; // leave off last child for open symm
+ }
+ List repeats = new ArrayList<>(n);
+ List equiv = new ArrayList<>(n);
+ for(int i=0;i
+ * Each inner list gives a set of equivalent repeats and should have length
+ * equal to the order of the axis' operator.
+ * @param level
+ * @param firstRepeat
+ * @return
+ */
+ public List> getRepeatsCyclicForm(int level, int firstRepeat) {
+ Axis axis = axes.get(level);
+ int m = getNumRepeats(level+1);//size of the children
+ int d = axis.getOrder(); // degree of this node
+ int n = m*d; // number of repeats included
+ if(firstRepeat % n != 0) {
+ throw new IllegalArgumentException(String.format("Repeat %d cannot start a block at level %s of this tree",firstRepeat,level));
+ }
+ if(axis.getSymmType() == SymmetryType.OPEN) {
+ n -= m; // leave off last child for open symm
+ }
+
+ List> repeats = new ArrayList<>(m);
+ for(int i=0;i cycle = new ArrayList<>(d);
+ for(int j=0;j> getRepeatsCyclicForm(Axis axis) {
+ return getRepeatsCyclicForm(axis.getLevel(),axis.getFirstRepeat());
+ }
+ public List> getRepeatsCyclicForm(int level) {
+ return getRepeatsCyclicForm(level,0);
+ }
+ public String getRepeatsCyclicForm(Axis axis, List> repeats) {
+ if(repeats.size() != getNumRepeats()) {
+ throw new IllegalArgumentException("Mismatch in the number of repeats");
+ }
+ return getRepeatsCyclicForm(getRepeatsCyclicForm(axis), repeats);
+ }
+ public static String getRepeatsCyclicForm(List> cycleForm, List> repeats) {
+ StringBuilder str = new StringBuilder();
+ for(List cycle : cycleForm) {
+ str.append("(");
+ Iterator cycleIt = cycle.iterator();
+ str.append(repeats.get(cycleIt.next())); //should be at least one
+ while(cycleIt.hasNext()) {
+ str.append(";")
+ .append(repeats.get( cycleIt.next() ));
+ }
+ str.append(")");
+ }
+ return str.toString();
+ }
+
+ /**
+ * Return the transformation that needs to be applied to a
+ * repeat in order to superimpose onto repeat 0.
*
* @param repeat the repeat index
* @return transformation matrix for the repeat
*/
public Matrix4d getRepeatTransform(int repeat){
- List allTransforms = new ArrayList();
Matrix4d transform = new Matrix4d();
transform.setIdentity();
- for (int a=0; a=0; t--) {
+ if( counts[t] == 0 )
+ continue;
+ Matrix4d axis = new Matrix4d(axes.get(t).getOperator());
+ for(int i=0;i0) allTransforms.add(clone);
- }
- //Multiply the matrices in the inverse order as they have to be applied
- //for (int t=0; t=0; t--){
- transform.mul(allTransforms.get(t));
}
+ return transform;
+ }
+
+ /**
+ * Return the transformation that needs to be applied to
+ * repeat x in order to superimpose onto repeat y.
+ *
+ * @param x the first repeat index (transformed)
+ * @param y the second repeat index (fixed)
+ * @return transformation matrix for the repeat x
+ */
+ public Matrix4d getRepeatTransform(int x, int y){
+ Matrix4d transform = new Matrix4d();
+ transform.setIdentity();
+
+ int[] iCounts = getAxisCounts(x);
+ int[] jCounts = getAxisCounts(y);
+
+ int[] counts = new int[iCounts.length];
+ for (int k = 0; k < iCounts.length; k++)
+ counts[k] = iCounts[k] - jCounts[k];
+
+ for(int t = counts.length-1; t>=0; t--) {
+ if(counts[t] == 0)
+ continue;
+ if (counts[t] > 0) {
+ Matrix4d axis = new Matrix4d(axes.get(t).getOperator());
+ for(int i=0;i getSymmetryAxes(){
+ public List getSymmetryAxes(){
- List symmAxes = new ArrayList();
+ List symmAxes = new ArrayList<>();
- //For every repeat do
- for (int su=0; su symmAxes, Matrix4d prior, int level, int firstRepeat) {
+ if(level >= getNumLevels() ) {
+ return;
+ }
- //Consider all the axes, in the inverse order
- for (int t=repeatTransforms.get(su).size()-1; t>=0; t--){
- int repeats = repeatTransforms.get(su).get(t);
- Matrix4d clone = (Matrix4d) axes.get(t).clone();
- Matrix4d invert = (Matrix4d) clone.clone();
- invert.invert();
+ Axis elem = axes.get(level);
+ Matrix4d elemOp = elem.getOperator();
- //Do for every repeat
- for (int n=0; n A
+ // prior maps I -> A and J -> B
+ // want J -> I = J -> B -> A <- I= inv(prior) * elementary * prior
+ Matrix4d currAxisOp = new Matrix4d(prior);
+ currAxisOp.invert();
+ currAxisOp.mul(elemOp);
+ currAxisOp.mul(prior);
+ Axis currAxis = new Axis(currAxisOp,elem.getOrder(),elem.getSymmType(),level,firstRepeat);
+ symmAxes.add(currAxis);
+
+ //Remember that all degrees are at least 2
+ getSymmetryAxes(symmAxes,prior,level+1,firstRepeat);
+ //New prior is elementary^d*prior
+ Matrix4d newPrior = new Matrix4d(elemOp);
+ newPrior.mul(prior);
+ int childSize = getNumRepeats(level+1);
+ getSymmetryAxes(symmAxes,newPrior,level+1,firstRepeat+childSize);
+ for(int d=2;d= degrees.get(level-1) )
+// throw new IndexOutOfBoundsException("Axis number out of bounds");
+// // Convert axisNum into a count of
+//
+// }
+ /**
+ * Get the number of repeats. This is equal to the product of all degrees.
+ * @return Number of repeats (leaves of the tree).
+ */
+ public int getNumRepeats() {
+ return getNumRepeats(0);
+ }
- //Ensure the axis are not equivalent
- for (int a=0; a getFirstRepeats(int level) {
+ List firstRepeats = new ArrayList();
+ int m = getNumRepeats(level+1); //size of the level
+ int d = axes.get(level).getOrder(); //degree of this level
+ int n = m*d; // number of repeats included in each axis
+ for (int firstRepeat = 0; firstRepeat < getNumRepeats(); firstRepeat+=n)
+ firstRepeats.add(firstRepeat);
+ return firstRepeats;
+ }
+
+ public Axis getElementaryAxis(int level) {
+ return axes.get(level);
+ }
+
+ public int getNumLevels() {
+ return axes.size();
+ }
+
}
diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/utils/SymmetryTools.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/utils/SymmetryTools.java
index 697533690f..417a7dde95 100644
--- a/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/utils/SymmetryTools.java
+++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/symmetry/utils/SymmetryTools.java
@@ -30,6 +30,7 @@
import javax.vecmath.Point3d;
import org.biojava.nbio.structure.Atom;
+import org.biojava.nbio.structure.Calc;
import org.biojava.nbio.structure.Chain;
import org.biojava.nbio.structure.ChainImpl;
import org.biojava.nbio.structure.Group;
@@ -493,32 +494,31 @@ public static UndirectedGraph buildSymmetryGraph(
/**
* Method that converts the symmetric units of a structure into different
- * chains, so that internal symmetry can be translated into quaternary.
- *
- * Application: obtain the internal symmetry axis with the quaternary
- * symmetry code in biojava or calculate independent repeat properties.
+ * structures, so that they can be individually visualized.
*
* @param symmetry
* CeSymmResult
- * @return Structure with different chains for every symmetric unit
+ * @throws StructureException
+ * @result List of structures, by repeat index sequentially
+ *
*/
- public static Structure getQuaternaryStructure(CeSymmResult symmetry) {
+ public static List divideStructure(CeSymmResult symmetry)
+ throws StructureException {
if (!symmetry.isRefined())
throw new IllegalArgumentException("The symmetry result "
+ "is not refined, repeats cannot be defined");
- Atom[] atoms = symmetry.getAtoms();
-
- Structure symm = new StructureImpl();
- symm.setStructureIdentifier(symmetry.getStructureId());
- symm.setChains(new ArrayList());
- char chainID = 'A';
+ int order = symmetry.getMultipleAlignment().size();
+ Atom[] atoms = StructureTools.cloneAtomArray(symmetry.getAtoms());
+ List repeatsId = symmetry.getRepeatsID();
+ List repeats = new ArrayList(order);
// Create new structure containing the repeat atoms
- for (int i = 0; i < symmetry.getMultipleAlignment().size(); i++) {
+ for (int i = 0; i < order; i++) {
- Chain newCh = new ChainImpl();
+ Structure s = new StructureImpl();
+ s.setStructureIdentifier(repeatsId.get(i));
Block align = symmetry.getMultipleAlignment().getBlock(0);
@@ -528,16 +528,17 @@ public static Structure getQuaternaryStructure(CeSymmResult symmetry) {
Atom[] repeat = Arrays.copyOfRange(atoms, res1, res2 + 1);
+ Chain newCh = new ChainImpl();
+ newCh.setChainID(repeat[0].getGroup().getChainId());
+
for (int k = 0; k < repeat.length; k++) {
Group g = (Group) repeat[k].getGroup().clone();
newCh.addGroup(g);
}
- newCh.setChainID(chainID + "");
- chainID++;
- symm.addChain(newCh);
-
+ s.addChain(newCh);
+ repeats.add(s);
}
- return symm;
+ return repeats;
}
/**
@@ -593,22 +594,16 @@ public static MultipleAlignment toRepeatsAlignment(CeSymmResult result)
MultipleAlignment msa = result.getMultipleAlignment();
MultipleAlignmentEnsemble newEnsemble = msa.getEnsemble().clone();
- newEnsemble.setStructureIdentifiers(result.getRepeatsID());
- // Modify atom arrays to include the repeat atoms only
- List atomArrays = new ArrayList();
- Structure divided = SymmetryTools.getQuaternaryStructure(result);
+ List repSt = SymmetryTools.divideStructure(result);
MultipleAlignment repeats = newEnsemble.getMultipleAlignment(0);
Block block = repeats.getBlock(0);
+ List atomArrays = new ArrayList();
+
+ for (Structure s : repSt)
+ atomArrays.add(StructureTools.getRepresentativeAtomArray(s));
- for (int i = 0; i < result.getMultipleAlignment().size(); i++) {
- Structure newStr = new StructureImpl();
- Chain newCh = divided.getChain(i);
- newStr.addChain(newCh);
- Atom[] repeat = StructureTools.getRepresentativeAtomArray(newCh);
- atomArrays.add(repeat);
- }
newEnsemble.setAtomArrays(atomArrays);
for (int su = 0; su < block.size(); su++) {
@@ -695,6 +690,7 @@ public static MultipleAlignment fromAFP(AFPChain symm, Atom[] atoms)
* error allowed in the axis comparison
* @return true if equivalent, false otherwise
*/
+ @Deprecated
public static boolean equivalentAxes(Matrix4d axis1, Matrix4d axis2,
double epsilon) {
@@ -735,10 +731,10 @@ public static QuatSymmetryResults getQuaternarySymmetry(CeSymmResult result)
throws StructureException {
// Obtain the clusters of aligned Atoms and repeat variables
- MultipleAlignment repeats = SymmetryTools.toRepeatsAlignment(result);
- List alignedCA = repeats.getAtomArrays();
- List corePos = MultipleAlignmentTools.getCorePositions(repeats
- .getBlock(0));
+ List alignedCA = result.getMultipleAlignment().getAtomArrays();
+ MultipleAlignment msa = result.getMultipleAlignment();
+ List corePos = MultipleAlignmentTools.getCorePositions(result
+ .getMultipleAlignment().getBlock(0));
List caCoords = new ArrayList();
List folds = new ArrayList();
@@ -753,8 +749,7 @@ public static QuatSymmetryResults getQuaternarySymmetry(CeSymmResult result)
for (int str = 0; str < alignedCA.size(); str++) {
Atom[] array = alignedCA.get(str);
List points = new ArrayList();
- List alignedRes = repeats.getBlock(0).getAlignRes()
- .get(str);
+ List alignedRes = msa.getBlock(0).getAlignRes().get(str);
for (int pos = 0; pos < alignedRes.size(); pos++) {
Integer residue = alignedRes.get(pos);
if (residue == null)
@@ -802,6 +797,7 @@ else if (!corePos.contains(pos))
* the symmetry alignment
* @return true if the alignment is refined
*/
+ @Deprecated
public static boolean isRefined(MultipleAlignment symm) {
if (symm.getBlocks().size() > 1) {
@@ -841,6 +837,7 @@ public static boolean isRefined(MultipleAlignment symm) {
* @return
* @throws StructureException
*/
+ @Deprecated
public static boolean isSignificant(MultipleAlignment msa,
double symmetryThreshold) throws StructureException {
@@ -899,36 +896,42 @@ public static List getGroups(Atom[] rAtoms) {
* SymmetryAxes object. It will be modified.
* @param msa
* MultipleAlignment. It will be modified.
- * @param atoms
- * Atom array of the structure
*/
public static void updateSymmetryTransformation(SymmetryAxes axes,
- MultipleAlignment msa, Atom[] atoms) throws StructureException {
+ MultipleAlignment msa) throws StructureException {
List> block = msa.getBlocks().get(0).getAlignRes();
int length = block.get(0).size();
if (axes != null) {
- for (int t = 0; t < axes.getElementaryAxes().size(); t++) {
+ for (int level = 0; level < axes.getNumLevels(); level++) {
- Matrix4d axis = axes.getElementaryAxes().get(t);
- List chain1 = axes.getRepeatRelation(t).get(0);
- List chain2 = axes.getRepeatRelation(t).get(1);
-
- // Calculate the aligned atom arrays
+ // Calculate the aligned atom arrays to superimpose
List list1 = new ArrayList();
List list2 = new ArrayList();
- for (int pair = 0; pair < chain1.size(); pair++) {
- int p1 = chain1.get(pair);
- int p2 = chain2.get(pair);
-
- for (int k = 0; k < length; k++) {
- Integer pos1 = block.get(p1).get(k);
- Integer pos2 = block.get(p2).get(k);
- if (pos1 != null && pos2 != null) {
- list1.add(atoms[pos1]);
- list2.add(atoms[pos2]);
+ for (int firstRepeat : axes.getFirstRepeats(level)) {
+
+ Matrix4d transform = axes.getRepeatTransform(firstRepeat);
+
+ List> relation = axes.getRepeatRelation(
+ level, firstRepeat);
+
+ for (int index = 0; index < relation.get(0).size(); index++) {
+ int p1 = relation.get(0).get(index);
+ int p2 = relation.get(1).get(index);
+
+ for (int k = 0; k < length; k++) {
+ Integer pos1 = block.get(p1).get(k);
+ Integer pos2 = block.get(p2).get(k);
+ if (pos1 != null && pos2 != null) {
+ Atom a = (Atom) msa.getAtomArrays().get(p1)[pos1].clone();
+ Atom b = (Atom) msa.getAtomArrays().get(p2)[pos2].clone();
+ Calc.transform(a, transform);
+ Calc.transform(b, transform);
+ list1.add(a);
+ list2.add(b);
+ }
}
}
}
@@ -939,8 +942,8 @@ public static void updateSymmetryTransformation(SymmetryAxes axes,
// Calculate the new transformation information
if (arr1.length > 0 && arr2.length > 0) {
SVDSuperimposer svd = new SVDSuperimposer(arr1, arr2);
- axis = svd.getTransformation();
- axes.updateAxis(t, axis);
+ Matrix4d axis = svd.getTransformation();
+ axes.updateAxis(level, axis);
}
// Get the transformations from the SymmetryAxes
@@ -977,4 +980,31 @@ public static void updateSymmetryScores(MultipleAlignment symm)
symm.putScore(MultipleAlignmentScorer.RMSD, rmsd);
}
+ /**
+ * Returns the representative Atom Array of the first model, if the
+ * structure is NMR, or the Array for each model, if it is a biological
+ * assembly with multiple models.
+ *
+ * @param structure
+ * @return representative Atom[]
+ */
+ public static Atom[] getRepresentativeAtoms(Structure structure) {
+
+ if (structure.isNmr())
+ return StructureTools.getRepresentativeAtomArray(structure);
+
+ else {
+
+ // Get Atoms of all models
+ List atomList = new ArrayList();
+ for (int m = 0; m < structure.nrModels(); m++) {
+ for (Chain c : structure.getModel(m))
+ atomList.addAll(Arrays.asList(StructureTools
+ .getRepresentativeAtomArray(c)));
+ }
+ return atomList.toArray(new Atom[0]);
+ }
+
+ }
+
}
diff --git a/biojava-structure/src/main/resources/org/biojava/nbio/structure/bond_distance_limits.cif.gz b/biojava-structure/src/main/resources/org/biojava/nbio/structure/bond_distance_limits.cif.gz
new file mode 100644
index 0000000000..1401654e26
Binary files /dev/null and b/biojava-structure/src/main/resources/org/biojava/nbio/structure/bond_distance_limits.cif.gz differ
diff --git a/biojava-structure/src/main/resources/org/biojava/nbio/structure/standardaminos.pdb b/biojava-structure/src/main/resources/org/biojava/nbio/structure/standardaminos.pdb
deleted file mode 100644
index 78f8524785..0000000000
--- a/biojava-structure/src/main/resources/org/biojava/nbio/structure/standardaminos.pdb
+++ /dev/null
@@ -1,167 +0,0 @@
-ATOM 1 N ALA 1 0.494 1.023 2.147 1 24.49
-ATOM 2 CA ALA 1 0.525 1.231 0.716 1 23.9
-ATOM 3 C ALA 1 -0.304 2.448 0.321 1 25.03
-ATOM 4 O ALA 1 -1.387 2.694 0.877 1 24.08
-ATOM 5 CB ALA 1 0.000 0.000 0.000 1 21.78
-ATOM 1 N ARG 2 0.925 -2.028 1.045 1 22.4
-ATOM 2 CA ARG 2 1.051 -1.110 -0.098 1 26.71
-ATOM 3 C ARG 2 2.426 -0.479 -0.387 1 27.34
-ATOM 4 O ARG 2 2.847 -0.401 -1.545 1 28.25
-ATOM 5 CB ARG 2 0.000 0.000 0.000 1 28.07
-ATOM 6 CG ARG 2 -0.504 0.455 -1.363 1 34.03
-ATOM 7 CD ARG 2 -0.933 1.930 -1.348 1 38.88
-ATOM 8 NE ARG 2 -2.373 2.147 -1.237 1 41.65
-ATOM 9 CZ ARG 2 -3.061 2.912 -2.079 1 45.41
-ATOM 10 NH1 ARG 2 -2.438 3.516 -3.083 1 45.25
-ATOM 11 NH2 ARG 2 -4.371 3.066 -1.933 1 48.63
-ATOM 1 N ASN 3 1.486 -0.416 1.992 1 48.91
-ATOM 2 CA ASN 3 1.423 0.110 0.619 1 49.54
-ATOM 3 C ASN 3 1.842 1.587 0.732 1 49.06
-ATOM 4 O ASN 3 2.799 1.859 1.507 1 49.25
-ATOM 5 CB ASN 3 0.000 0.000 0.000 1 49.64
-ATOM 6 CG ASN 3 0.014 0.096 -1.537 1 50.26
-ATOM 7 OD1 ASN 3 1.082 0.141 -2.156 1 51.27
-ATOM 8 ND2 ASN 3 -1.172 0.096 -2.154 1 50.95
-ATOM 1 N ASP 4 -0.024 2.139 1.216 1 31.73
-ATOM 2 CA ASP 4 0.796 0.984 0.867 1 32.49
-ATOM 3 C ASP 4 2.073 1.394 0.128 1 31.55
-ATOM 4 O ASP 4 2.317 0.937 -0.988 1 33.23
-ATOM 5 CB ASP 4 0.000 0.000 0.000 1 35
-ATOM 6 CG ASP 4 -1.157 -0.643 0.738 1 38.92
-ATOM 7 OD1 ASP 4 -1.115 -0.722 1.992 1 39.91
-ATOM 8 OD2 ASP 4 -2.111 -1.080 0.053 1 41.36
-ATOM 1 N CYS 5 0.553 1.877 1.446 1 21.01
-ATOM 2 CA CYS 5 0.356 1.481 0.057 1 22.79
-ATOM 3 C CYS 5 -0.764 2.272 -0.622 1 25.08
-ATOM 4 O CYS 5 -1.065 2.042 -1.802 1 24.55
-ATOM 5 CB CYS 5 0.000 0.000 0.000 1 25.21
-ATOM 6 SG CYS 5 -1.474 -0.396 0.997 1 21.67
-ATOM 1 N GLN 6 2.420 -0.279 0.030 1 24.67
-ATOM 2 CA GLN 6 1.330 0.521 -0.519 1 26.3
-ATOM 3 C GLN 6 1.458 1.986 -0.138 1 26.72
-ATOM 4 O GLN 6 1.693 2.319 1.035 1 24.44
-ATOM 5 CB GLN 6 0.000 0.000 0.000 1 31.06
-ATOM 6 CG GLN 6 -1.209 0.562 -0.709 1 37.02
-ATOM 7 CD GLN 6 -1.535 -0.211 -1.959 1 41.56
-ATOM 8 OE1 GLN 6 -1.658 0.360 -3.038 1 44.84
-ATOM 9 NE2 GLN 6 -1.692 -1.525 -1.821 1 44.22
-ATOM 1 N GLU 7 1.408 -2.006 -0.385 1 40.19
-ATOM 2 CA GLU 7 0.232 -1.252 -0.876 1 44.66
-ATOM 3 C GLU 7 0.028 -0.871 -2.343 1 46.61
-ATOM 4 O GLU 7 -0.799 -1.486 -3.026 1 48.2
-ATOM 5 CB GLU 7 0.000 0.000 0.000 1 44.57
-ATOM 6 CG GLU 7 1.190 0.964 0.119 1 45.57
-ATOM 7 CD GLU 7 1.024 1.925 1.283 1 47.38
-ATOM 8 OE1 GLU 7 -0.068 2.466 1.505 1 48.84
-ATOM 9 OE2 GLU 7 2.106 2.154 2.031 1 46.92
-ATOM 1 N GLY 8 47.669 21.580 -36.546 1 21.01
-ATOM 2 CA GLY 8 46.339 21.191 -36.982 1 19.83
-ATOM 3 C GLY 8 46.235 20.890 -38.469 1 21.21
-ATOM 4 O GLY 8 46.924 21.503 -39.280 1 23.09
-ATOM 1 N HIS 9 -0.346 2.373 -0.412 1 13.88
-ATOM 2 CA HIS 9 -0.784 1.040 -0.785 1 14.13
-ATOM 3 C HIS 9 -2.270 0.972 -0.435 1 15.38
-ATOM 4 O HIS 9 -2.641 1.020 0.748 1 16.86
-ATOM 5 CB HIS 9 0.000 0.000 0.000 1 13.14
-ATOM 6 CG HIS 9 1.456 -0.006 -0.327 1 17.5
-ATOM 7 ND1 HIS 9 1.931 -0.575 -1.488 1 17.25
-ATOM 8 CD2 HIS 9 2.493 0.500 0.384 1 17.69
-ATOM 9 CE1 HIS 9 3.239 -0.400 -1.454 1 17.77
-ATOM 10 NE2 HIS 9 3.631 0.244 -0.345 1 17.75
-ATOM 1 N ILE 10 -0.417 -2.192 1.096 1 27.83
-ATOM 2 CA ILE 10 -0.325 -0.750 1.314 1 29.53
-ATOM 3 C ILE 10 -1.665 -0.275 1.884 1 30.09
-ATOM 4 O ILE 10 -2.727 -0.689 1.415 1 28.53
-ATOM 5 CB ILE 10 0.000 0.000 0.000 1 31.6
-ATOM 6 CG1 ILE 10 1.331 -0.514 -0.578 1 33.16
-ATOM 7 CG2 ILE 10 0.112 1.496 0.269 1 33.17
-ATOM 8 CD1 ILE 10 1.778 0.187 -1.868 1 29.72
-ATOM 1 N LEU 11 0.768 -1.147 -2.027 1 32.16
-ATOM 2 CA LEU 11 -0.420 -0.644 -1.333 1 34.34
-ATOM 3 C LEU 11 -1.389 0.304 -2.047 1 36.35
-ATOM 4 O LEU 11 -0.972 1.222 -2.760 1 36.15
-ATOM 5 CB LEU 11 0.000 0.000 0.000 1 33.58
-ATOM 6 CG LEU 11 0.686 -0.899 1.040 1 33.51
-ATOM 7 CD1 LEU 11 1.216 -0.065 2.194 1 34.43
-ATOM 8 CD2 LEU 11 -0.295 -1.940 1.540 1 33.17
-ATOM 1 N LYS 12 1.245 -0.586 -2.092 1 26.29
-ATOM 2 CA LYS 12 0.174 0.249 -1.517 1 27.52
-ATOM 3 C LYS 12 0.425 1.736 -1.757 1 26.38
-ATOM 4 O LYS 12 -0.516 2.509 -1.859 1 25.33
-ATOM 5 CB LYS 12 0.000 0.000 0.000 1 27.61
-ATOM 6 CG LYS 12 -0.549 -1.378 0.339 1 29.49
-ATOM 7 CD LYS 12 -1.376 -1.393 1.617 1 31.39
-ATOM 8 CE LYS 12 -0.556 -1.734 2.857 1 35.62
-ATOM 9 NZ LYS 12 0.535 -0.759 3.199 1 38.15
-ATOM 1 N MET 13 -0.112 -1.808 1.638 1 23.36
-ATOM 2 CA MET 13 -0.811 -0.634 1.147 1 22.77
-ATOM 3 C MET 13 -2.170 -1.118 0.657 1 21.54
-ATOM 4 O MET 13 -2.270 -2.218 0.112 1 21.32
-ATOM 5 CB MET 13 0.000 0.000 0.000 1 23.08
-ATOM 6 CG MET 13 -0.745 1.066 -0.782 1 25.23
-ATOM 7 SD MET 13 0.221 1.816 -2.120 1 25.75
-ATOM 8 CE MET 13 1.111 3.085 -1.200 1 24
-ATOM 1 N PHE 14 0.105 1.537 -1.930 1 14.86
-ATOM 2 CA PHE 14 0.834 1.043 -0.752 1 16.7
-ATOM 3 C PHE 14 2.160 0.325 -1.063 1 17.28
-ATOM 4 O PHE 14 2.348 -0.241 -2.141 1 17.93
-ATOM 5 CB PHE 14 0.000 0.000 0.000 1 16.18
-ATOM 6 CG PHE 14 -1.184 0.543 0.739 1 14.73
-ATOM 7 CD1 PHE 14 -1.016 1.241 1.930 1 13.41
-ATOM 8 CD2 PHE 14 -2.474 0.302 0.272 1 12.61
-ATOM 9 CE1 PHE 14 -2.132 1.689 2.651 1 14.44
-ATOM 10 CE2 PHE 14 -3.596 0.750 0.978 1 15.3
-ATOM 11 CZ PHE 14 -3.422 1.442 2.171 1 11.23
-ATOM 1 N PRO 15 2.003 0.020 1.242 1 15.52
-ATOM 2 CA PRO 15 0.545 -0.046 1.435 1 15.69
-ATOM 3 C PRO 15 0.034 -1.273 2.208 1 17.62
-ATOM 4 O PRO 15 -1.034 -1.211 2.839 1 18.07
-ATOM 5 CB PRO 15 0.000 0.000 0.000 1 19.34
-ATOM 6 CG PRO 15 1.118 0.656 -0.790 1 18.17
-ATOM 7 CD PRO 15 2.342 0.017 -0.191 1 15.87
-ATOM 1 N SER 16 -0.873 2.106 0.865 1 25.64
-ATOM 2 CA SER 16 -0.070 0.936 1.201 1 25.41
-ATOM 3 C SER 16 1.330 1.207 1.719 1 25.19
-ATOM 4 O SER 16 2.139 0.284 1.812 1 26.74
-ATOM 5 CB SER 16 0.000 0.000 0.000 1 24.96
-ATOM 6 OG SER 16 -1.312 -0.288 -0.461 1 27.94
-ATOM 1 N THR 17 -1.248 1.785 -1.139 1 26.68
-ATOM 2 CA THR 17 -0.956 1.197 0.166 1 26.57
-ATOM 3 C THR 17 -0.398 2.109 1.258 1 27.97
-ATOM 4 O THR 17 -0.107 1.647 2.365 1 31.7
-ATOM 5 CB THR 17 0.000 0.000 0.000 1 25.88
-ATOM 6 OG1 THR 17 1.179 0.416 -0.706 1 27.09
-ATOM 7 CG2 THR 17 -0.679 -1.099 -0.789 1 26.06
-ATOM 1 N TRP 18 -2.343 0.032 -0.696 1 18.87
-ATOM 2 CA TRP 18 -1.106 -0.700 -0.785 1 22.26
-ATOM 3 C TRP 18 -1.492 -1.984 -0.056 1 24.88
-ATOM 4 O TRP 18 -1.876 -1.925 1.105 1 25.15
-ATOM 5 CB TRP 18 0.000 0.000 0.000 1 24.8
-ATOM 6 CG TRP 18 1.349 -0.707 -0.051 1 30.99
-ATOM 7 CD1 TRP 18 2.377 -0.468 -0.933 1 30.98
-ATOM 8 CD2 TRP 18 1.820 -1.727 0.848 1 33.1
-ATOM 9 NE1 TRP 18 3.460 -1.268 -0.628 1 33.72
-ATOM 10 CE2 TRP 18 3.144 -2.047 0.460 1 34.08
-ATOM 11 CE3 TRP 18 1.255 -2.394 1.941 1 34.23
-ATOM 12 CZ2 TRP 18 3.916 -3.016 1.136 1 36.51
-ATOM 13 CZ3 TRP 18 2.022 -3.364 2.618 1 36.78
-ATOM 14 CH2 TRP 18 3.335 -3.659 2.212 1 38.2
-ATOM 1 N TYR 19 0.795 -2.206 0.735 1 22.33
-ATOM 2 CA TYR 19 -0.396 -1.400 0.492 1 20.17
-ATOM 3 C TYR 19 -1.258 -2.073 -0.559 1 21.55
-ATOM 4 O TYR 19 -0.744 -2.545 -1.569 1 22.81
-ATOM 5 CB TYR 19 0.000 0.000 0.000 1 20.33
-ATOM 6 CG TYR 19 0.498 0.934 1.084 1 16.84
-ATOM 7 CD1 TYR 19 -0.398 1.570 1.947 1 15.4
-ATOM 8 CD2 TYR 19 1.854 1.200 1.237 1 16.24
-ATOM 9 CE1 TYR 19 0.048 2.439 2.924 1 16.13
-ATOM 10 CE2 TYR 19 2.310 2.072 2.215 1 18.35
-ATOM 11 CZ TYR 19 1.398 2.690 3.058 1 18.09
-ATOM 12 OH TYR 19 1.835 3.555 4.042 1 18.05
-ATOM 1 N VAL 20 -0.471 2.212 1.093 1 25.64
-ATOM 2 CA VAL 20 -0.282 1.529 -0.188 1 24.65
-ATOM 3 C VAL 20 -1.485 1.721 -1.109 1 26.31
-ATOM 4 O VAL 20 -2.612 1.916 -0.639 1 25.36
-ATOM 5 CB VAL 20 0.000 0.000 0.000 1 22.87
-ATOM 6 CG1 VAL 20 1.274 -0.205 0.796 1 24.53
-ATOM 7 CG2 VAL 20 -1.148 -0.679 0.715 1 21.34
diff --git a/biojava-structure/src/main/resources/org/biojava/nbio/structure/standardaminos.pdb.gz b/biojava-structure/src/main/resources/org/biojava/nbio/structure/standardaminos.pdb.gz
new file mode 100644
index 0000000000..992ef78592
Binary files /dev/null and b/biojava-structure/src/main/resources/org/biojava/nbio/structure/standardaminos.pdb.gz differ
diff --git a/biojava-structure/src/test/java/org/biojava/nbio/structure/symmetry/internal/TestCeSymm.java b/biojava-structure/src/test/java/org/biojava/nbio/structure/symmetry/internal/TestCeSymm.java
index 830e593d40..f9d829b5c3 100644
--- a/biojava-structure/src/test/java/org/biojava/nbio/structure/symmetry/internal/TestCeSymm.java
+++ b/biojava-structure/src/test/java/org/biojava/nbio/structure/symmetry/internal/TestCeSymm.java
@@ -55,7 +55,7 @@ public void testEasyCases() throws IOException, StructureException {
CeSymmResult result = CeSymm.analyze(atoms);
assertTrue(result.isSignificant());
- assertEquals(result.getSymmOrder(), orders[i]);
+ assertEquals(result.getNumRepeats(), orders[i]);
}
}
}
diff --git a/biojava-structure/src/test/java/org/biojava/nbio/structure/symmetry/internal/TestSymmetryAxes.java b/biojava-structure/src/test/java/org/biojava/nbio/structure/symmetry/internal/TestSymmetryAxes.java
new file mode 100644
index 0000000000..779185479b
--- /dev/null
+++ b/biojava-structure/src/test/java/org/biojava/nbio/structure/symmetry/internal/TestSymmetryAxes.java
@@ -0,0 +1,370 @@
+package org.biojava.nbio.structure.symmetry.internal;
+
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.vecmath.AxisAngle4d;
+import javax.vecmath.Matrix4d;
+import javax.vecmath.Point3d;
+import javax.vecmath.Vector3d;
+
+import org.biojava.nbio.structure.symmetry.internal.CESymmParameters.SymmetryType;
+import org.biojava.nbio.structure.symmetry.internal.SymmetryAxes.Axis;
+import org.junit.Test;
+
+
+public class TestSymmetryAxes {
+
+ @Test
+ public void testClosedCase() {
+ // D4 case
+ SymmetryAxes axes = new SymmetryAxes();
+
+ // Level 1 is C4 along Z
+ Matrix4d r90 = new Matrix4d();
+ r90.set(new AxisAngle4d(0, 0, 1, -Math.PI/2));
+ axes.addAxis(r90, 4, SymmetryType.CLOSED);
+
+ // Level 2 is C2 along X
+ Matrix4d r180 = new Matrix4d();
+ r180.set(new AxisAngle4d(1, 0, 0, Math.PI));
+ axes.addAxis(r180, 2, SymmetryType.CLOSED);
+
+ assertEquals(2,axes.getElementaryAxes().size());
+
+ Matrix4d expectedEven = new Matrix4d();
+ expectedEven.setIdentity();
+ Matrix4d expectedOdd = new Matrix4d(r180);
+ assertEquals(expectedEven, axes.getRepeatTransform(0));
+ assertEquals(expectedOdd, axes.getRepeatTransform(1));
+ expectedEven.mul(r90);
+ expectedOdd.mul(r180,expectedEven);
+ assertEquals(expectedEven, axes.getRepeatTransform(2));
+ assertEquals(expectedOdd, axes.getRepeatTransform(3));
+ expectedEven.mul(r90);
+ expectedOdd.mul(r180,expectedEven);
+ assertEquals(expectedEven, axes.getRepeatTransform(4));
+ assertEquals(expectedOdd, axes.getRepeatTransform(5));
+ expectedEven.mul(r90);
+ expectedOdd.mul(r180,expectedEven);
+ assertEquals(expectedEven, axes.getRepeatTransform(6));
+ assertEquals(expectedOdd, axes.getRepeatTransform(7));
+
+ // Test Cauchy Form
+ List> relation = Arrays.asList(
+ Arrays.asList(0,1,2,3,4,5,6,7),
+ Arrays.asList(2,3,4,5,6,7,0,1)
+ );
+ assertEquals(relation,axes.getRepeatRelation(0));
+ relation = Arrays.asList(
+ Arrays.asList(0,1),
+ Arrays.asList(1,0)
+ );
+ assertEquals(relation,axes.getRepeatRelation(1));
+ relation = Arrays.asList(
+ Arrays.asList(2,3),
+ Arrays.asList(3,2)
+ );
+ assertEquals(relation,axes.getRepeatRelation(1,2));
+ try {
+ axes.getRepeatRelation(2);
+ fail("Invalid level");
+ } catch(IndexOutOfBoundsException e) {}
+ try {
+ axes.getRepeatRelation(1,1);
+ fail("Invalid firstRepeat");
+ } catch(IllegalArgumentException e) {}
+
+ // Test Cyclic Form
+ relation = Arrays.asList(
+ Arrays.asList(0,2,4,6),
+ Arrays.asList(1,3,5,7)
+ );
+ assertEquals(relation,axes.getRepeatsCyclicForm(0));
+ relation = Arrays.asList(
+ Arrays.asList(0,1)
+ );
+ assertEquals(relation,axes.getRepeatsCyclicForm(1));
+ relation = Arrays.asList(
+ Arrays.asList(2,3)
+ );
+ assertEquals(relation,axes.getRepeatsCyclicForm(1,2));
+ try {
+ axes.getRepeatsCyclicForm(2);
+ fail("Invalid level");
+ } catch(IndexOutOfBoundsException e) {}
+ try {
+ axes.getRepeatsCyclicForm(1,1);
+ fail("Invalid firstRepeat");
+ } catch(IllegalArgumentException e) {}
+
+
+ // Expected location of each repeat
+ Point3d[] repeats = new Point3d[] {
+ new Point3d(1,1,1),
+ new Point3d(1,-1,-1),
+ new Point3d(-1,1,1),
+ new Point3d(1,1,-1),
+ new Point3d(-1,-1,1),
+ new Point3d(-1,1,-1),
+ new Point3d(1,-1,1),
+ new Point3d(-1,-1,-1)
+ };
+ // Inverse of (1,1,1) should give above points
+ for(int i=0;i<8;i++) {
+ Matrix4d m = axes.getRepeatTransform(i);
+ m.invert();
+ Point3d x = new Point3d(repeats[0]);
+ m.transform(x);
+ assertTrue("Transformation "+i+"^-1 of "+repeats[0]+ "="+x+" not "+repeats[i],x.epsilonEquals(repeats[i], 1e-5));
+ }
+ // Forward should map the above points onto the first one
+ for(int i=0;i<8;i++) {
+ Matrix4d m = axes.getRepeatTransform(i);
+ Point3d x = new Point3d(repeats[i]);
+ m.transform(x);
+ assertTrue("Transformation "+i+" of "+repeats[i]+ "="+x+" not 1,1,1",x.epsilonEquals(repeats[0], 1e-5));
+ }
+
+ Point3d x;
+
+ List symmetryAxes = axes.getSymmetryAxes();
+ assertEquals(5,symmetryAxes.size());
+ int axisNum = 0;
+ // Repeat 2 -> 0 (90 deg around z)
+ x = new Point3d(repeats[2]);
+ symmetryAxes.get(axisNum).getOperator().transform(x);
+ assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[2]),round(x),round(repeats[0])),x.epsilonEquals(repeats[0], 1e-5));
+ assertEquals(0,symmetryAxes.get(axisNum).getFirstRepeat());
+ axisNum++;
+ // Repeat 1 -> 0 (180 deg around x)
+ x = new Point3d(repeats[1]);
+ symmetryAxes.get(axisNum).getOperator().transform(x);
+ assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[1]),round(x),round(repeats[0])),x.epsilonEquals(repeats[0], 1e-5));
+ assertEquals(0,symmetryAxes.get(axisNum).getFirstRepeat());
+ axisNum++;
+ // Repeat 3 -> 2 (180 deg around y)
+ x = new Point3d(repeats[3]);
+ symmetryAxes.get(axisNum).getOperator().transform(x);
+ assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[3]),round(x),round(repeats[2])),x.epsilonEquals(repeats[2], 1e-5));
+ assertEquals(2,symmetryAxes.get(axisNum).getFirstRepeat());
+ axisNum++;
+ // Repeat 5 -> 4 (180 deg around x)
+ x = new Point3d(repeats[5]);
+ symmetryAxes.get(axisNum).getOperator().transform(x);
+ assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[5]),round(x),round(repeats[4])),x.epsilonEquals(repeats[4], 1e-5));
+ assertEquals(4,symmetryAxes.get(axisNum).getFirstRepeat());
+ axisNum++;
+ // Repeat 7 -> 6 (180 deg around y)
+ x = new Point3d(repeats[7]);
+ symmetryAxes.get(axisNum).getOperator().transform(x);
+ assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[7]),round(x),round(repeats[6])),x.epsilonEquals(repeats[6], 1e-5));
+ assertEquals(6,symmetryAxes.get(axisNum).getFirstRepeat());
+ axisNum++;
+ }
+ private static Point3d round(Point3d p) {
+ return new Point3d(Math.round(p.x*100)/100.,Math.round(p.y*100)/100.,Math.round(p.z*100)/100.);
+ }
+
+ @Test
+ public void testOpenCase() {
+ // D4 case
+ SymmetryAxes axes = new SymmetryAxes();
+
+ // Level 1 is R4 along X
+ Matrix4d t10 = new Matrix4d();
+ t10.set(1,new Vector3d(-10,0,0));
+ axes.addAxis(t10, 4, SymmetryType.OPEN);
+
+ // Level 2 is C2 along X
+ Matrix4d r180 = new Matrix4d();
+ r180.set(new AxisAngle4d(1, 0, 0, Math.PI));
+ axes.addAxis(r180, 2, SymmetryType.CLOSED);
+
+ assertEquals(2,axes.getElementaryAxes().size());
+
+ Matrix4d expectedEven = new Matrix4d();
+ expectedEven.setIdentity();
+ Matrix4d expectedOdd = new Matrix4d(r180);
+ assertEquals(expectedEven, axes.getRepeatTransform(0));
+ assertEquals(expectedOdd, axes.getRepeatTransform(1));
+ expectedEven.mul(t10);
+ expectedOdd.mul(r180,expectedEven);
+ assertEquals(expectedEven, axes.getRepeatTransform(2));
+ assertEquals(expectedOdd, axes.getRepeatTransform(3));
+ expectedEven.mul(t10);
+ expectedOdd.mul(r180,expectedEven);
+ assertEquals(expectedEven, axes.getRepeatTransform(4));
+ assertEquals(expectedOdd, axes.getRepeatTransform(5));
+ expectedEven.mul(t10);
+ expectedOdd.mul(r180,expectedEven);
+ assertEquals(expectedEven, axes.getRepeatTransform(6));
+ assertEquals(expectedOdd, axes.getRepeatTransform(7));
+
+ // Test Cauchy Form
+ List> relation = Arrays.asList(
+ Arrays.asList(0,1,2,3,4,5),
+ Arrays.asList(2,3,4,5,6,7)
+ );
+ assertEquals(relation,axes.getRepeatRelation(0));
+ relation = Arrays.asList(
+ Arrays.asList(0,1),
+ Arrays.asList(1,0)
+ );
+ assertEquals(relation,axes.getRepeatRelation(1));
+ try {
+ axes.getRepeatRelation(2);
+ fail("Invalid level");
+ } catch(IndexOutOfBoundsException e) {}
+
+ // Test Cyclic Form
+ relation = Arrays.asList(
+ Arrays.asList(0,2,4,6),
+ Arrays.asList(1,3,5,7)
+ );
+ assertEquals(relation,axes.getRepeatsCyclicForm(0));
+ relation = Arrays.asList(
+ Arrays.asList(0,1)
+ );
+ assertEquals(relation,axes.getRepeatsCyclicForm(1));
+ relation = Arrays.asList(
+ Arrays.asList(2,3)
+ );
+ assertEquals(relation,axes.getRepeatsCyclicForm(1,2));
+ try {
+ axes.getRepeatsCyclicForm(2);
+ fail("Invalid level");
+ } catch(IndexOutOfBoundsException e) {}
+ try {
+ axes.getRepeatsCyclicForm(1,1);
+ fail("Invalid firstRepeat");
+ } catch(IllegalArgumentException e) {}
+
+
+ // Expected location of each repeat
+ Point3d[] repeats = new Point3d[] {
+ new Point3d(-15,1,1),
+ new Point3d(-15,-1,-1),
+ new Point3d( -5,1,1),
+ new Point3d( -5,-1,-1),
+ new Point3d( 5,1,1),
+ new Point3d( 5,-1,-1),
+ new Point3d( 15,1,1),
+ new Point3d( 15,-1,-1),
+
+ };
+ // Inverse of first point should give above points
+ for(int i=0;i<8;i++) {
+ Matrix4d m = axes.getRepeatTransform(i);
+ m.invert();
+ Point3d x = new Point3d(repeats[0]);
+ m.transform(x);
+ assertTrue("Transformation "+i+"^-1 of "+repeats[0]+ "="+x+" not "+repeats[i],x.epsilonEquals(repeats[i], 1e-5));
+ }
+ // Forward should map the above points onto the first one
+ for(int i=0;i<8;i++) {
+ Matrix4d m = axes.getRepeatTransform(i);
+ Point3d x = new Point3d(repeats[i]);
+ m.transform(x);
+ assertTrue("Transformation "+i+" of "+repeats[i]+ "="+x+" not "+repeats[0],x.epsilonEquals(repeats[0], 1e-5));
+ }
+
+ Point3d x;
+
+ List symmetryAxes = axes.getSymmetryAxes();
+ assertEquals(5,symmetryAxes.size());
+ int axisNum = 0;
+ // Repeat 2 -> 0 (shift 1)
+ x = new Point3d(repeats[2]);
+ symmetryAxes.get(axisNum).getOperator().transform(x);
+ assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[2]),round(x),round(repeats[0])),x.epsilonEquals(repeats[0], 1e-5));
+ axisNum++;
+ // All of these are actually equivalent
+ // Repeat 1 -> 0 (180 deg around x)
+ x = new Point3d(repeats[1]);
+ symmetryAxes.get(axisNum).getOperator().transform(x);
+ assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[1]),round(x),round(repeats[0])),x.epsilonEquals(repeats[0], 1e-5));
+ axisNum++;
+ // Repeat 3 -> 2 (180 deg around x)
+ x = new Point3d(repeats[3]);
+ symmetryAxes.get(axisNum).getOperator().transform(x);
+ assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[3]),round(x),round(repeats[2])),x.epsilonEquals(repeats[2], 1e-5));
+ axisNum++;
+ // Repeat 5 -> 4 (180 deg around x)
+ x = new Point3d(repeats[5]);
+ symmetryAxes.get(axisNum).getOperator().transform(x);
+ assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[5]),round(x),round(repeats[4])),x.epsilonEquals(repeats[4], 1e-5));
+ axisNum++;
+ // Repeat 7 -> 6 (180 deg around x)
+ x = new Point3d(repeats[7]);
+ symmetryAxes.get(axisNum).getOperator().transform(x);
+ assertTrue(String.format("SymmAxis %d of %s=%s not %s",axisNum,round(repeats[7]),round(x),round(repeats[6])),x.epsilonEquals(repeats[6], 1e-5));
+ axisNum++;
+ }
+ /**
+ * Test that the deprecated addAxis still works
+ */
+ @SuppressWarnings("deprecation")
+ @Test
+ public void testOpenCaseOld() {
+ // D4 case
+ SymmetryAxes axes = new SymmetryAxes();
+
+ // Level 1 is R4 along X
+ Matrix4d t10 = new Matrix4d();
+ t10.set(1,new Vector3d(1,0,0));
+ List repeats = Arrays.asList(0,0,1,1,2,2,3,3);
+ List> superposition = Arrays.asList(
+ Arrays.asList(0,1,2,3,4,5),
+ Arrays.asList(2,3,4,5,6,7));
+ axes.addAxis(t10, superposition, repeats, 4);
+
+ // Level 2 is C2 along X
+ Matrix4d r180 = new Matrix4d();
+ r180.set(new AxisAngle4d(1, 0, 0, Math.PI));
+ repeats = Arrays.asList(0,1,0,1,0,1,0,1);
+ superposition = Arrays.asList(
+ Arrays.asList(0,1),
+ Arrays.asList(1,0));
+ axes.addAxis(r180, superposition, repeats, 2);
+
+
+ assertEquals(2,axes.getElementaryAxes().size());
+
+ Matrix4d expectedEven = new Matrix4d();
+ expectedEven.setIdentity();
+ Matrix4d expectedOdd = new Matrix4d(r180);
+ assertEquals(expectedEven, axes.getRepeatTransform(0));
+ assertEquals(expectedOdd, axes.getRepeatTransform(1));
+ expectedEven.mul(t10);
+ expectedOdd.mul(r180,expectedEven);
+ assertEquals(expectedEven, axes.getRepeatTransform(2));
+ assertEquals(expectedOdd, axes.getRepeatTransform(3));
+ expectedEven.mul(t10);
+ expectedOdd.mul(r180,expectedEven);
+ assertEquals(expectedEven, axes.getRepeatTransform(4));
+ assertEquals(expectedOdd, axes.getRepeatTransform(5));
+ expectedEven.mul(t10);
+ expectedOdd.mul(r180,expectedEven);
+ assertEquals(expectedEven, axes.getRepeatTransform(6));
+ assertEquals(expectedOdd, axes.getRepeatTransform(7));
+
+ List> relation = Arrays.asList(
+ Arrays.asList(0,1,2,3,4,5),
+ Arrays.asList(2,3,4,5,6,7)
+ );
+ assertEquals(relation,axes.getRepeatRelation(0));
+ relation = Arrays.asList(
+ Arrays.asList(0,1),
+ Arrays.asList(1,0)
+ );
+ assertEquals(relation,axes.getRepeatRelation(1));
+ try {
+ axes.getRepeatRelation(2);
+ fail("Invalid level");
+ } catch(IndexOutOfBoundsException e) {}
+
+ }
+}
diff --git a/biojava-survival/pom.xml b/biojava-survival/pom.xml
index 5bffa2139e..3b57f7242f 100644
--- a/biojava-survival/pom.xml
+++ b/biojava-survival/pom.xml
@@ -4,7 +4,7 @@
org.biojava
biojava
- 4.2.1
+ 4.2.2
biojava-survival
diff --git a/biojava-ws/pom.xml b/biojava-ws/pom.xml
index 9d643a2368..fb469e0d69 100644
--- a/biojava-ws/pom.xml
+++ b/biojava-ws/pom.xml
@@ -3,7 +3,7 @@
biojava
org.biojava
- 4.2.1
+ 4.2.2
biojava-ws
biojava-ws
@@ -19,7 +19,7 @@
org.biojava
biojava-core
- 4.2.1
+ 4.2.2
compile
diff --git a/pom.xml b/pom.xml
index 330c0798a3..864b9d9ff4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
org.biojava
biojava
pom
- 4.2.1
+ 4.2.2
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.1
+ biojava-4.2.2
forked-path
+
+
+ true
+ -Pgpg-release