Skip to content

Commit 975d5c6

Browse files
authored
Merge pull request biojava#571 from lafita/quatalign
Quaternary Structural Alignment Algorithm (QsAlign)
2 parents 74e3dd6 + 167750e commit 975d5c6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2135
-737
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package org.biojava.nbio.structure.test.align.qsalign;
2+
3+
import static org.junit.Assert.*;
4+
5+
import java.io.IOException;
6+
7+
import org.biojava.nbio.structure.Structure;
8+
import org.biojava.nbio.structure.StructureException;
9+
import org.biojava.nbio.structure.StructureIO;
10+
import org.biojava.nbio.structure.align.quaternary.QsAlign;
11+
import org.biojava.nbio.structure.align.quaternary.QsAlignParameters;
12+
import org.biojava.nbio.structure.align.quaternary.QsAlignResult;
13+
import org.biojava.nbio.structure.align.quaternary.QsRelation;
14+
import org.biojava.nbio.structure.cluster.SubunitClustererParameters;
15+
import org.junit.Test;
16+
17+
/**
18+
* Test the correctness of the {@link QsAlign} algorithm with some examples of
19+
* different levels of quaternary structure similarity.
20+
*
21+
* @author Aleix Lafita
22+
* @since 5.0.0
23+
*
24+
*/
25+
public class TestQsAlignExamples {
26+
27+
/**
28+
* Identity: test hemoglobin (4HHB) against itself.
29+
*/
30+
@Test
31+
public void testIdentity() throws StructureException, IOException {
32+
33+
Structure s1 = StructureIO.getStructure("4hhb");
34+
Structure s2 = s1;
35+
36+
SubunitClustererParameters clusterParams = new SubunitClustererParameters();
37+
QsAlignParameters alignParams = new QsAlignParameters();
38+
39+
QsAlignResult result = QsAlign
40+
.align(s1, s2, clusterParams, alignParams);
41+
42+
assertEquals(result.length(), 4);
43+
assertEquals(result.getRelation(), QsRelation.EQUIVALENT);
44+
assertEquals(result.getRmsd(), 0.0, 0.01);
45+
46+
}
47+
48+
/**
49+
* Different: test two completely different proteins (4HHB, 3IFV).
50+
*/
51+
@Test
52+
public void testDifferent() throws StructureException, IOException {
53+
54+
Structure s1 = StructureIO.getStructure("4hhb");
55+
Structure s2 = StructureIO.getStructure("3ifv");
56+
57+
SubunitClustererParameters clusterParams = new SubunitClustererParameters();
58+
QsAlignParameters alignParams = new QsAlignParameters();
59+
60+
QsAlignResult result = QsAlign
61+
.align(s1, s2, clusterParams, alignParams);
62+
63+
assertEquals(result.length(), 0);
64+
assertEquals(result.getRelation(), QsRelation.DIFFERENT);
65+
66+
}
67+
68+
/**
69+
* Proliferating cell nuclear antigens (3IFV, 3HI8) are structurally
70+
* equivalent C3 homotrimers.
71+
*/
72+
@Test
73+
public void testHomoEquivalent() throws StructureException, IOException {
74+
75+
Structure s1 = StructureIO.getStructure("3ifv");
76+
Structure s2 = StructureIO.getStructure("BIO:3hi8:1");
77+
78+
SubunitClustererParameters clusterParams = new SubunitClustererParameters();
79+
QsAlignParameters alignParams = new QsAlignParameters();
80+
81+
QsAlignResult result = QsAlign
82+
.align(s1, s2, clusterParams, alignParams);
83+
84+
assertEquals(result.length(), 3);
85+
assertEquals(result.getRelation(), QsRelation.EQUIVALENT);
86+
assertTrue(result.getRmsd() < 10.0);
87+
88+
}
89+
90+
/**
91+
* Phycocyanins (2VML, 2BV8) are equivalent D3 heterododecamers with A6B6
92+
* stoichiometry.
93+
*/
94+
@Test
95+
public void testHeteroEquivalent() throws StructureException, IOException {
96+
97+
Structure s1 = StructureIO.getStructure("2vml");
98+
Structure s2 = StructureIO.getStructure("2bv8");
99+
100+
SubunitClustererParameters clusterParams = new SubunitClustererParameters();
101+
QsAlignParameters alignParams = new QsAlignParameters();
102+
103+
QsAlignResult result = QsAlign
104+
.align(s1, s2, clusterParams, alignParams);
105+
106+
assertEquals(result.length(), 12);
107+
assertEquals(result.getRelation(), QsRelation.EQUIVALENT);
108+
assertTrue(result.getRmsd() < 10.0);
109+
}
110+
111+
/**
112+
* Hydratases (2B3M dimer, 1Q6W hexamer). The C2 dimer is
113+
* triplicated into a D3 assembly.
114+
*/
115+
@Test
116+
public void testPartialComplete() throws StructureException,
117+
IOException {
118+
119+
Structure s1 = StructureIO.getStructure("BIO:2b3m:1");
120+
Structure s2 = StructureIO.getStructure("BIO:1Q6W:7");
121+
122+
SubunitClustererParameters clusterParams = new SubunitClustererParameters();
123+
QsAlignParameters alignParams = new QsAlignParameters();
124+
125+
QsAlignResult result = QsAlign
126+
.align(s1, s2, clusterParams, alignParams);
127+
128+
assertEquals(result.length(), 2);
129+
assertEquals(result.getRelation(), QsRelation.PARTIAL_COMPLETE);
130+
assertTrue(result.getRmsd() < 10.0);
131+
132+
}
133+
134+
/**
135+
* Cytochrome bc1 complexes (1BCC, 1KB9) have some equivalent Chains and
136+
* some unmatched.
137+
*/
138+
@Test
139+
public void testPartialIncomplete() throws StructureException,
140+
IOException {
141+
142+
Structure s1 = StructureIO.getStructure("1bcc");
143+
Structure s2 = StructureIO.getStructure("1kb9");
144+
145+
SubunitClustererParameters clusterParams = new SubunitClustererParameters();
146+
QsAlignParameters alignParams = new QsAlignParameters();
147+
148+
QsAlignResult result = QsAlign
149+
.align(s1, s2, clusterParams, alignParams);
150+
151+
assertEquals(result.length(), 8);
152+
assertEquals(result.getRelation(), QsRelation.PARTIAL_INCOMPLETE);
153+
assertTrue(result.getRmsd() < 10.0);
154+
}
155+
156+
}

biojava-structure/src/test/java/org/biojava/nbio/structure/cluster/TestSubunitClusterer.java renamed to biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/cluster/TestSubunitClustererExamples.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* http://www.biojava.org/
1919
*
2020
*/
21-
package org.biojava.nbio.structure.cluster;
21+
package org.biojava.nbio.structure.test.cluster;
2222

2323
import static org.junit.Assert.*;
2424

@@ -28,6 +28,10 @@
2828
import org.biojava.nbio.structure.Structure;
2929
import org.biojava.nbio.structure.StructureException;
3030
import org.biojava.nbio.structure.StructureIO;
31+
import org.biojava.nbio.structure.cluster.SubunitCluster;
32+
import org.biojava.nbio.structure.cluster.SubunitClusterer;
33+
import org.biojava.nbio.structure.cluster.SubunitClustererMethod;
34+
import org.biojava.nbio.structure.cluster.SubunitClustererParameters;
3135
import org.junit.Test;
3236

3337
/**
@@ -37,7 +41,7 @@
3741
* @author Aleix Lafita
3842
*
3943
*/
40-
public class TestSubunitClusterer {
44+
public class TestSubunitClustererExamples {
4145

4246
/**
4347
* Test modified residues: 1HIV
@@ -112,7 +116,8 @@ public void testInternalSymmetry() throws StructureException, IOException {
112116
assertEquals(clusters.get(0).getClustererMethod(),
113117
SubunitClustererMethod.IDENTITY);
114118

115-
params.setClustererMethod(SubunitClustererMethod.INTERNAL_SYMMETRY);
119+
params.setClustererMethod(SubunitClustererMethod.STRUCTURE);
120+
params.setInternalSymmetry(true);
116121
params.setRmsdThreshold(3.0);
117122

118123
clusters = SubunitClusterer.cluster(s, params);
@@ -122,6 +127,6 @@ public void testInternalSymmetry() throws StructureException, IOException {
122127
assertEquals(clusters.get(0).size(), 6);
123128
assertTrue(clusters.get(0).length() < 177);
124129
assertEquals(clusters.get(0).getClustererMethod(),
125-
SubunitClustererMethod.INTERNAL_SYMMETRY);
130+
SubunitClustererMethod.STRUCTURE);
126131
}
127132
}

biojava-structure/src/test/java/org/biojava/nbio/structure/symmetry/core/TestQuatSymmetryDetector.java renamed to biojava-integrationtest/src/test/java/org/biojava/nbio/structure/test/symmetry/TestQuatSymmetryDetectorExamples.java

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* http://www.biojava.org/
1919
*
2020
*/
21-
package org.biojava.nbio.structure.symmetry.core;
21+
package org.biojava.nbio.structure.test.symmetry;
2222

2323
import static org.junit.Assert.*;
2424

@@ -37,14 +37,14 @@
3737
import org.junit.Test;
3838

3939
/**
40-
* Test the algorithm for symmetry detection on a variety of structures with
41-
* different symmetries.
40+
* Test the {@link QuatSymmetryDetector} algorithm for symmetry detection on a
41+
* variety of structures with different symmetries.
4242
*
4343
* @author Peter Rose
4444
* @author Aleix Lafita
4545
*
4646
*/
47-
public class TestQuatSymmetryDetector {
47+
public class TestQuatSymmetryDetectorExamples {
4848

4949
/**
5050
* An NMR multi-model entry: 1B4C
@@ -56,16 +56,16 @@ public class TestQuatSymmetryDetector {
5656
public void testNMR() throws IOException, StructureException {
5757

5858
Structure pdb = StructureIO.getStructure("BIO:1b4c:1");
59-
59+
6060
SubunitClustererParameters clusterParams = new SubunitClustererParameters();
6161
QuatSymmetryParameters symmParams = new QuatSymmetryParameters();
6262
QuatSymmetryResults symmetry = QuatSymmetryDetector.calcGlobalSymmetry(
6363
pdb, symmParams, clusterParams);
64-
64+
6565
// C2 symmetry non pseudosymmetric
6666
assertEquals("C2", symmetry.getSymmetry());
67-
assertEquals("A2", symmetry.getSubunits().getStoichiometry());
68-
assertFalse(symmetry.getSubunits().isPseudoStoichiometric());
67+
assertEquals("A2", symmetry.getStoichiometry());
68+
assertFalse(symmetry.isPseudoStoichiometric());
6969

7070
}
7171

@@ -89,7 +89,7 @@ public void testPseudosymmetry() throws IOException, StructureException {
8989

9090
// C2 symmetry
9191
assertEquals("C2", symmetry.getSymmetry());
92-
assertEquals("A2B2", symmetry.getSubunits().getStoichiometry());
92+
assertEquals("A2B2", symmetry.getStoichiometry());
9393

9494
// Use pseudosymmetry (structural clustering)
9595
clusterParams.setClustererMethod(SubunitClustererMethod.STRUCTURE);
@@ -98,7 +98,7 @@ public void testPseudosymmetry() throws IOException, StructureException {
9898

9999
// D2 pseudo-symmetry
100100
assertEquals("D2", symmetry.getSymmetry());
101-
assertEquals("A4", symmetry.getSubunits().getStoichiometry());
101+
assertEquals("A4", symmetry.getStoichiometry());
102102
}
103103

104104
/**
@@ -120,7 +120,7 @@ public void testLocal() throws IOException, StructureException {
120120

121121
// C1 global symmetry
122122
assertEquals("C1", symmetry.getSymmetry());
123-
assertEquals("A5B5C", symmetry.getSubunits().getStoichiometry());
123+
assertEquals("A5B5C", symmetry.getStoichiometry());
124124

125125
// Local symmetry
126126
List<QuatSymmetryResults> localSymm = QuatSymmetryDetector
@@ -133,8 +133,8 @@ public void testLocal() throws IOException, StructureException {
133133
assertEquals("C5", localSymm.get(2).getSymmetry());
134134

135135
// Two A5 and one A5B5 stoichiometries as local symmetry
136-
List<String> stoich = localSymm.stream().map(
137-
t -> t.getSubunits().getStoichiometry()).collect(Collectors.toList());
136+
List<String> stoich = localSymm.stream().map(t -> t.getStoichiometry())
137+
.collect(Collectors.toList());
138138

139139
assertTrue(stoich.contains("A5"));
140140
assertTrue(stoich.contains("A5B5"));
@@ -151,21 +151,22 @@ public void testInternalSymmetry() throws IOException, StructureException {
151151

152152
Structure pdb = StructureIO.getStructure("BIO:4e3e:1");
153153

154-
// Internal symmetry analysis
154+
// Internal symmetry analysis, use structural clustering
155155
SubunitClustererParameters cp = new SubunitClustererParameters();
156-
cp.setClustererMethod(SubunitClustererMethod.INTERNAL_SYMMETRY);
157-
cp.setCoverageThreshold(0.8); // Lower coverage for internal symm
156+
cp.setClustererMethod(SubunitClustererMethod.STRUCTURE);
157+
cp.setInternalSymmetry(true);
158+
cp.setCoverageThreshold(0.75); // Lower coverage for internal symm
158159

159160
QuatSymmetryParameters symmParams = new QuatSymmetryParameters();
160161
QuatSymmetryResults symmetry = QuatSymmetryDetector.calcGlobalSymmetry(
161162
pdb, symmParams, cp);
162163

163164
// D2 combined internal and quaternary symmetry
164165
assertEquals("D3", symmetry.getSymmetry());
165-
assertEquals("A6", symmetry.getSubunits().getStoichiometry());
166+
assertEquals("A6", symmetry.getStoichiometry());
166167

167168
}
168-
169+
169170
/**
170171
* A structure with helical symmetry: 1B47
171172
*
@@ -184,7 +185,29 @@ public void testHelical() throws IOException, StructureException {
184185

185186
// H symmetry A3 stoichiometry
186187
assertEquals("H", symmetry.getSymmetry());
187-
assertEquals("A3", symmetry.getSubunits().getStoichiometry());
188+
assertEquals("A3", symmetry.getStoichiometry());
189+
190+
}
191+
192+
/**
193+
* A structure with local helical symmetry: 5JLF
194+
*
195+
* @throws IOException
196+
* @throws StructureException
197+
*/
198+
@Test
199+
public void testHelicalLocal() throws IOException, StructureException {
200+
201+
Structure pdb = StructureIO.getStructure("BIO:5JLF:1");
202+
203+
SubunitClustererParameters cp = new SubunitClustererParameters();
204+
QuatSymmetryParameters symmParams = new QuatSymmetryParameters();
205+
List<QuatSymmetryResults> results = QuatSymmetryDetector
206+
.calcLocalSymmetries(pdb, symmParams, cp);
207+
208+
// H symmetry A5 stoichiometry
209+
assertEquals("H", results.get(0).getSymmetry());
210+
assertEquals("A5", results.get(0).getStoichiometry());
188211

189212
}
190213
}

biojava-structure-gui/src/main/java/demo/DemoQuatSymmetryJmol.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public class DemoQuatSymmetryJmol {
6161
public static void main(String[] args) throws IOException,
6262
StructureException {
6363

64-
String name = "4hhb";
64+
String name = "1VYM";
6565

6666
// Download the biological assembly
6767
AtomCache cache = new AtomCache();
@@ -92,10 +92,10 @@ public static void main(String[] args) throws IOException,
9292
private static void showResults(Structure s, String name,
9393
QuatSymmetryResults results) {
9494

95-
String title = name + ": " + results.getSubunits().getStoichiometry()
95+
String title = name + ": " + results.getStoichiometry()
9696
+ ", " + results.getSymmetry();
9797

98-
if (results.getSubunits().isPseudoSymmetric())
98+
if (results.isPseudosymmetric())
9999
title += ", pseudosymmetric";
100100

101101
if (results.isLocal())

0 commit comments

Comments
 (0)