package org.biojava.nbio.structure.io.mmtf;
import org.junit.Test;
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.vecmath.Matrix4d;
import org.biojava.nbio.structure.AminoAcidImpl;
import org.biojava.nbio.structure.Atom;
import org.biojava.nbio.structure.AtomImpl;
import org.biojava.nbio.structure.BondImpl;
import org.biojava.nbio.structure.Chain;
import org.biojava.nbio.structure.ChainImpl;
import org.biojava.nbio.structure.ExperimentalTechnique;
import org.biojava.nbio.structure.Group;
import org.biojava.nbio.structure.HetatomImpl;
import org.biojava.nbio.structure.NucleotideImpl;
import org.biojava.nbio.structure.PDBCrystallographicInfo;
import org.biojava.nbio.structure.Structure;
import org.biojava.nbio.structure.StructureException;
import org.biojava.nbio.structure.StructureIO;
import org.biojava.nbio.structure.StructureImpl;
import org.biojava.nbio.structure.io.mmtf.MmtfUtils;
import org.biojava.nbio.structure.quaternary.BioAssemblyInfo;
import org.biojava.nbio.structure.quaternary.BiologicalAssemblyTransformation;
import org.biojava.nbio.structure.xtal.BravaisLattice;
import org.biojava.nbio.structure.xtal.CrystalCell;
import org.biojava.nbio.structure.xtal.SpaceGroup;
/**
* Test the MMTF utils class
* @author Anthony Bradley
*
*/
public class TestMmtfUtils {
/**
* Integration test to see that the microheterogenity is being dealt with correctly.
* @throws IOException
* @throws StructureException
*/
@Test
public void microHeterogenity() throws IOException, StructureException {
MmtfUtils.setUpBioJava();
Structure inputStructure = StructureIO.getStructure("4ck4");
// Count the number of groups
Group before = inputStructure.getChains().get(0).getAtomGroup(17);
assertTrue(inputStructure.getChains().get(0).getAtomGroup(17).hasAltLoc());
List<Atom> totalAtoms = new ArrayList<>(getAllAtoms(inputStructure));
int totGroups = 0;
int totAtomsCounter = 0;
Set<Atom> totAtoms = new HashSet<>();
for (Chain c : inputStructure.getChains()) {
totGroups += c.getAtomGroups().size();
for (Group g: c.getAtomGroups() ){
totAtomsCounter+=g.getAtoms().size();
totAtoms.addAll(g.getAtoms());
for (Group alt : g.getAltLocs()) {
totAtomsCounter+=alt.getAtoms().size();
totAtoms.addAll(alt.getAtoms());
}
}
}
// Now "fix" the microheterogenity
MmtfUtils.fixMicroheterogenity(inputStructure);
assertEquals(before, inputStructure.getChains().get(0).getAtomGroup(17));
assertFalse(inputStructure.getChains().get(0).getAtomGroup(17).hasAltLoc());
assertFalse(inputStructure.getChains().get(0).getAtomGroup(18).hasAltLoc());
int totGroupsAfter = 0;
int totAtomsCounterAfter = 0;
Set<Atom> totAtomsAfter = new HashSet<>();
for (Chain c : inputStructure.getChains()) {
totGroupsAfter += c.getAtomGroups().size();
for (Group g: c.getAtomGroups() ){
totAtomsCounterAfter+=g.getAtoms().size();
totAtomsAfter.addAll(g.getAtoms());
for (Group alt : g.getAltLocs()) {
totAtomsAfter.addAll(alt.getAtoms());
totAtomsCounterAfter+=alt.getAtoms().size();
}
}
}
// Find the atoms after the fix.
List<Atom> totalAtomsAfter = new ArrayList<>(getAllAtoms(inputStructure));
// Get all of the duplicate atoms
Set<Atom> duplicates = findDuplicates(totalAtomsAfter);
for (Atom a : duplicates) {
System.out.println(a);
}
// There should be no duplicates
assertEquals(duplicates.size(), 0);
assertEquals(totalAtoms.size(), totalAtomsAfter.size());
// Check there are two more groups afterwards
assertEquals(totGroupsAfter-2, totGroups);
// Check there are no more atoms afterwards
assertEquals(totAtomsAfter.size(), totAtoms.size());
// Check the counter are the same too
assertEquals(totAtomsCounterAfter, totAtomsCounter);
}
/**
* Function to get all the atoms in the strucutre as a list.
* @param bioJavaStruct the biojava structure
* @return a list of all the unique atoms in the structure
*/
private List<Atom> getAllAtoms(Structure bioJavaStruct) {
// Get all the atoms
List<Atom> theseAtoms = new ArrayList<Atom>();
for (int i=0; i<bioJavaStruct.nrModels(); i++){
List<Chain> chains = bioJavaStruct.getModel(i);
for (Chain c : chains) {
for (Group g : c.getAtomGroups()) {
for(Atom a: MmtfUtils.getAtomsForGroup(g)){
theseAtoms.add(a);
}
}
}
}
return theseAtoms;
}
/**
* Test that getting the space group info as a string works.
*/
@Test
public void testGetSpaceGroupAsString() {
assertEquals("NA", MmtfUtils.getSpaceGroupAsString(null));
SpaceGroup spaceGroup = new SpaceGroup(21, 1, 1, "P212121", "P 21 21 21", BravaisLattice.TRICLINIC);
assertEquals("P212121", MmtfUtils.getSpaceGroupAsString(spaceGroup));
}
/**
* Test that getting the unit cell as an array of doubles works.
*/
@Test
public void testGetUnitCellAsArray() {
PDBCrystallographicInfo xtalInfo = new PDBCrystallographicInfo();
CrystalCell cell = new CrystalCell();
cell.setA(1.0);
cell.setB(2.0);
cell.setC(3.0);
cell.setAlpha(4.0);
cell.setBeta(5.0);
cell.setGamma(6.0);
float[] testArray = new float[] {1.0f,2.0f,3.0f,4.0f,5.0f,6.0f};
xtalInfo.setCrystalCell(cell);
float[] outputArray = MmtfUtils.getUnitCellAsArray(xtalInfo);
assertArrayEquals(testArray, outputArray, 0.0f);
}
/**
* Test getting the list of experimental methods as string array.
*/
@Test
public void testGetExperimentalMethods() {
Set<ExperimentalTechnique> experimentalTechniques = new HashSet<>();
experimentalTechniques.add(ExperimentalTechnique.XRAY_DIFFRACTION);
experimentalTechniques.add(ExperimentalTechnique.ELECTRON_MICROSCOPY);
String[] techniques = MmtfUtils.techniquesToStringArray(experimentalTechniques);
String[] testTechniques = {"X-RAY DIFFRACTION", "ELECTRON MICROSCOPY"};
Arrays.sort(techniques);
Arrays.sort(testTechniques);
assertArrayEquals(testTechniques, techniques);
}
/**
* Test the conversion of a matrix to an array of doubles.
*/
@Test
public void testConvertToDoubleArray() {
Matrix4d matrix4d = new Matrix4d();
matrix4d.m00 = 0.0;
matrix4d.m01 = 0.1;
matrix4d.m02 = 0.2;
matrix4d.m03 = 0.3;
matrix4d.m10 = 1.0;
matrix4d.m11 = 1.1;
matrix4d.m12 = 1.2;
matrix4d.m13 = 1.3;
matrix4d.m20 = 2.0;
matrix4d.m21 = 2.1;
matrix4d.m22 = 2.2;
matrix4d.m23 = 2.3;
matrix4d.m30 = 3.0;
matrix4d.m31 = 3.1;
matrix4d.m32 = 3.2;
matrix4d.m33 = 3.3;
double[] testData = new double[] {0.0, 0.1, 0.2, 0.3,
1.0, 1.1, 1.2, 1.3,
2.0, 2.1, 2.2, 2.3,
3.0, 3.1, 3.2, 3.3};
assertArrayEquals(testData,MmtfUtils.convertToDoubleArray(matrix4d), 0.0);
}
/**
* Test to check the conversion of BioassemblyInfo to a primitive map.
*/
@Test
public void testMakePrimitiveBioasembly() {
double[] testData = new double[] {0.0, 0.1, 0.2, 0.3,
1.0, 1.1, 1.2, 1.3,
2.0, 2.1, 2.2, 2.3,
3.0, 3.1, 3.2, 3.3};
BioAssemblyInfo bioAssemblyInfo = new BioAssemblyInfo();
List<BiologicalAssemblyTransformation> transforms = new ArrayList<>();
BiologicalAssemblyTransformation biologicalAssemblyTransformation = new BiologicalAssemblyTransformation();
biologicalAssemblyTransformation.setChainId("C");
biologicalAssemblyTransformation.setTransformationMatrix(new Matrix4d(testData));
transforms.add(biologicalAssemblyTransformation);
bioAssemblyInfo.setTransforms(transforms);
// Map the chain to the second index
Map<String, Integer> chainIdToIndexMap = new HashMap<>();
chainIdToIndexMap.put("C", 2);
// Now do the conversion and test they are the same
Map<double[], int[]> transMap = MmtfUtils.getTransformMap(bioAssemblyInfo, chainIdToIndexMap);
assertArrayEquals(testData, (double[]) transMap.keySet().toArray()[0], 0.0);
assertArrayEquals(new int[] {2} , (int[]) transMap.values().toArray()[0]);
}
/**
* Test getting the data as an appropriately formatted string.
*/
public void testGetIsoDateString() {
Date inputDate = new Date();
inputDate.setTime(86500);
// One day after
assertEquals("1970-01-02",MmtfUtils.dateToIsoString(inputDate));
}
/**
* Test getting the number of groups from a structure.
*/
@Test
public void testGetNumGroups() {
Structure structure = new StructureImpl();
Chain chain = new ChainImpl();
Group groupOne = new AminoAcidImpl();
Group groupTwo = new HetatomImpl();
Group groupThree = new NucleotideImpl();
structure.addChain(chain);
chain.addGroup(groupOne);
chain.addGroup(groupTwo);
chain.addGroup(groupThree);
assertEquals(3,MmtfUtils.getNumGroups(structure));
}
/**
* Test getting the correct atoms from a group
*/
@Test
public void testGetAtomsForGroup() {
Group group = new AminoAcidImpl();
Group altLoc = new AminoAcidImpl();
Atom atomOne = new AtomImpl();
atomOne.setX(1.00);
Atom atomTwo = new AtomImpl();
atomTwo.setX(2.00);
Atom atomThree = new AtomImpl();
atomThree.setX(3.00);
atomThree.setAltLoc('B');
Atom atomFour = new AtomImpl();
atomFour.setX(4.00);
List<Atom> inputList = new ArrayList<>();
inputList.add(atomOne);
inputList.add(atomTwo);
inputList.add(atomFour);
inputList.add(atomThree);
group.addAtom(atomOne);
group.addAtom(atomTwo);
group.addAtom(atomFour);
altLoc.addAtom(atomOne);
altLoc.addAtom(atomTwo);
altLoc.addAtom(atomThree);
group.addAltLoc(altLoc);
List<Atom> atomList = MmtfUtils.getAtomsForGroup(group);
assertEquals(inputList, atomList);
}
/**
* Test getting the number of bonds from a list of atoms.
*/
@Test
public void testGetNumBondsFromGroup() {
List<Atom> atoms = new ArrayList<>();
Atom atomOne = new AtomImpl();
Atom atomTwo = new AtomImpl();
Atom atomThree = new AtomImpl();
atoms.add(atomOne);
atoms.add(atomTwo);
atoms.add(atomThree);
// Make the same bond twice iwth different atom orders
new BondImpl(atomOne, atomTwo, 2);
new BondImpl(atomTwo, atomOne, 2);
// Make the same bond twice
new BondImpl(atomOne, atomThree, 2);
new BondImpl(atomOne, atomThree, 2);
// Make this bond twice with different orders
new BondImpl(atomTwo, atomThree, 2);
new BondImpl(atomTwo, atomThree, 1);
assertEquals(3, MmtfUtils.getNumBondsInGroup(atoms));
}
/**
* Test that getting the secondary structure type works.
*/
@Test
public void testGetSetSecStructType() {
Group group = new AminoAcidImpl();
MmtfUtils.setSecStructType(group, 0);
assertEquals(MmtfUtils.getSecStructType(group), 0);
MmtfUtils.setSecStructType(group, 1);
assertEquals(MmtfUtils.getSecStructType(group), 1);
MmtfUtils.setSecStructType(group, 2);
assertEquals(MmtfUtils.getSecStructType(group), 2);
MmtfUtils.setSecStructType(group, 3);
assertEquals(MmtfUtils.getSecStructType(group), 3);
MmtfUtils.setSecStructType(group, 4);
assertEquals(MmtfUtils.getSecStructType(group), 4);
MmtfUtils.setSecStructType(group, 5);
assertEquals(MmtfUtils.getSecStructType(group), 5);
MmtfUtils.setSecStructType(group, 6);
assertEquals(MmtfUtils.getSecStructType(group), 6);
MmtfUtils.setSecStructType(group, 7);
assertEquals(MmtfUtils.getSecStructType(group), 7);
// Now test two null possibilities
Group newGroup = new AminoAcidImpl();
MmtfUtils.setSecStructType(newGroup, -1);
assertEquals(MmtfUtils.getSecStructType(newGroup), -1);
// Now test two null possibilities
Group newerGroup = new AminoAcidImpl();
MmtfUtils.setSecStructType(newerGroup, 10);
assertEquals(MmtfUtils.getSecStructType(newerGroup), -1);
}
/**
* Test that setting the secondary structure types behaves as expected.
*/
@Test
public void testGetSecStructTypeFromDsspIndex(){
assertEquals(MmtfUtils.getSecStructTypeFromDsspIndex(0).name,"pi Helix");
assertEquals(MmtfUtils.getSecStructTypeFromDsspIndex(1).name,"Bend");
assertEquals(MmtfUtils.getSecStructTypeFromDsspIndex(2).name,"alpha Helix");
assertEquals(MmtfUtils.getSecStructTypeFromDsspIndex(3).name,"Extended");
assertEquals(MmtfUtils.getSecStructTypeFromDsspIndex(4).name,"3-10 Helix");
assertEquals(MmtfUtils.getSecStructTypeFromDsspIndex(5).name,"Bridge");
assertEquals(MmtfUtils.getSecStructTypeFromDsspIndex(6).name,"Turn");
assertEquals(MmtfUtils.getSecStructTypeFromDsspIndex(7).name,"Coil");
assertEquals(MmtfUtils.getSecStructTypeFromDsspIndex(-1), null);
assertEquals(MmtfUtils.getSecStructTypeFromDsspIndex(10), null);
}
/**
* Test that getting the structure data info works.
*/
@Test
public void testGetStructureInfo() {
Structure structure = new StructureImpl();
Chain chain = new ChainImpl();
chain.setId("A");
Map<String,Integer> testMap = new HashMap<>();
testMap.put("A", 0);
List<Chain> chainList = new ArrayList<>();
chainList.add(chain);
Group group = new AminoAcidImpl();
chain.addGroup(group);
Atom atomOne = new AtomImpl();
Atom atomTwo = new AtomImpl();
List<Atom> atomList = new ArrayList<>();
atomList.add(atomOne);
atomList.add(atomTwo);
new BondImpl(atomOne, atomTwo, 1);
structure.addChain(chain);
group.addAtom(atomOne);
group.addAtom(atomTwo);
// Get the structure
MmtfSummaryDataBean mmtfSummaryDataBean = MmtfUtils.getStructureInfo(structure);
assertEquals(mmtfSummaryDataBean.getAllAtoms(), atomList);
assertEquals(testMap, mmtfSummaryDataBean.getChainIdToIndexMap());
assertEquals(chainList, mmtfSummaryDataBean.getAllChains());
assertEquals(1, mmtfSummaryDataBean.getNumBonds());
}
private Set<Atom> findDuplicates(List<Atom> listContainingDuplicates)
{
final Set<Atom> setToReturn = new HashSet<>();
final Set<Atom> set1 = new HashSet<>();
for (Atom yourInt : listContainingDuplicates)
{
if (!set1.add(yourInt))
{
setToReturn.add(yourInt);
}
}
return setToReturn;
}
/**
* Test that the NCS data can be roundtripped.
*/
@Test
public void testGetNcsMatrix() {
double[][] testData = new double[][] {{1.0, 2.0,3.0,4.0,
11.0,12.0,13.0,14.0,
21.0,22.0,23.0,24.0,
31.0,32.0,33.0,34.0}};
testInput(testData);
}
/**
* Test that the NCS data can be roundtripped.
*/
@Test
public void testEmptyNcsMatrix() {
double[][] testData = new double[0][0];
testInput(testData);
double[][] output = MmtfUtils.getNcsAsArray(new Matrix4d[0]);
assertNotNull(output);
}
/**
* Test what happens if the NCS is null
*/
@Test
public void testNullNcsMatrix(){
double[][] output = MmtfUtils.getNcsAsArray(null);
assertNotNull(output);
Matrix4d[] outputMat = MmtfUtils.getNcsAsMatrix4d(null);
assertNull(outputMat);
double[][] outputMatArr = MmtfUtils.getNcsAsArray(outputMat);
assertNotNull(outputMatArr);
}
/**
* Test that the NCS data can be roundtripped - when two matrices are present.
*/
@Test
public void testGetNcsMatrixHard() {
double[][] testData = new double[][] {{1.0, 2.0,3.0,4.0,
11.0,12.0,13.0,14.0,
21.0,22.0,23.0,24.0,
31.0,32.0,33.0,34.0,},{
1.0, 2.0,3.0,4.0,
11.0,12.0,13.0,14.0,
21.0,22.0,23.0,24.0,
31.0,32.0,33.0,34.0}};
testInput(testData);
}
private void testInput(double[][] testData) {
Matrix4d[] matArr = MmtfUtils.getNcsAsMatrix4d(testData);
double[][] roundTrippedData = MmtfUtils.getNcsAsArray(matArr);
for(int i=0; i<testData.length; i++){
assertArrayEquals(testData[i], roundTrippedData[i], 0.0);
}
}
}