Skip to content

Commit a917ec8

Browse files
authored
Merge pull request #1156 from josemduarte/jd/fixcaonly-cif
Fix: CIF parser wasn't respecting parseCAOnly
2 parents 9ae550c + 679ebf0 commit a917ec8

4 files changed

Lines changed: 93 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ BioJava 7.3.0
3838
write-then-read round trip #1144 #1143
3939
* The ECOD read lock is left balanced when a download fails, so the original error is no longer
4040
replaced by `IllegalMonitorStateException` #1150
41+
* `FileParsingParameters.setParseCAOnly(true)` keeps only C-alpha atoms when reading mmCIF and
42+
BinaryCIF, as it does for PDB files. Since the unified CIF parser it had dropped only non-CA
43+
carbons, keeping every N, O and S atom. Groups and chains that hold no C-alpha (waters,
44+
ligands, nucleotides) are no longer created at all in this mode
4145
* Resolution parsing warns only when the values actually differ
4246

4347
### Changed

biojava-structure/src/main/java/org/biojava/nbio/structure/io/BondMaker.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,14 +463,24 @@ public void formBondsFromStructConn(StructConn conn) {
463463

464464
} catch (StructureException e) {
465465

466-
logger.warn("Could not find atom specified in struct_conn record: {}{}({}) in chain {}, atom {} {}", seqId1, insCode1, resName1, chainId1, atomName1, altLocStr1);
466+
// Note, in Calpha only mode the struct_conn atoms may not be present.
467+
if (! params.isParseCAOnly()) {
468+
logger.warn("Could not find atom specified in struct_conn record: {}{}({}) in chain {}, atom {} {}", seqId1, insCode1, resName1, chainId1, atomName1, altLocStr1);
469+
} else {
470+
logger.debug("Could not find atom specified in struct_conn record while parsing in parseCAonly mode: {}{}({}) in chain {}, atom {} {}", seqId1, insCode1, resName1, chainId1, atomName1, altLocStr1);
471+
}
467472
continue;
468473
}
469474
try {
470475
a2 = getAtomFromRecord(atomName2, altLoc2, chainId2, seqId2, insCode2);
471476
} catch (StructureException e) {
472477

473-
logger.warn("Could not find atom specified in struct_conn record: {}{}({}) in chain {}, atom {} {}", seqId2, insCode2, resName2, chainId2, atomName2, altLocStr2);
478+
// Note, in Calpha only mode the struct_conn atoms may not be present.
479+
if (! params.isParseCAOnly()) {
480+
logger.warn("Could not find atom specified in struct_conn record: {}{}({}) in chain {}, atom {} {}", seqId2, insCode2, resName2, chainId2, atomName2, altLocStr2);
481+
} else {
482+
logger.debug("Could not find atom specified in struct_conn record while parsing in parseCAonly mode: {}{}({}) in chain {}, atom {} {}", seqId2, insCode2, resName2, chainId2, atomName2, altLocStr2);
483+
}
474484
continue;
475485
}
476486

biojava-structure/src/main/java/org/biojava/nbio/structure/io/cif/CifStructureConsumerImpl.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,13 @@ public void consumeAtomSite(AtomSite atomSite) {
205205
IntColumn pdbx_pdb_model_num = atomSite.getPdbxPDBModelNum();
206206

207207
for (int atomIndex = 0; atomIndex < atomSite.getRowCount(); atomIndex++) {
208+
// skip before any chain or group is set up, so that groups and chains without a
209+
// C-alpha (waters, ligands, nucleotides) are not created at all
210+
if (params.isParseCAOnly() &&
211+
!(labelAtomId.get(atomIndex).equals(StructureTools.CA_ATOM_NAME) && "C".equals(typeSymbol.get(atomIndex)))) {
212+
continue;
213+
}
214+
208215
boolean startOfNewChain = false;
209216
Character oneLetterCode = StructureTools.get1LetterCodeAmino(labelCompId.get(atomIndex));
210217

@@ -318,12 +325,6 @@ public void consumeAtomSite(AtomSite atomSite) {
318325
}
319326
}
320327

321-
if (params.isParseCAOnly()) {
322-
if (!labelAtomId.get(atomIndex).equals(StructureTools.CA_ATOM_NAME) && "C".equals(typeSymbol.get(atomIndex))) {
323-
continue;
324-
}
325-
}
326-
327328
Atom atom = new AtomImpl();
328329

329330
atom.setPDBserial(id.get(atomIndex));

biojava-structure/src/test/java/org/biojava/nbio/structure/io/cif/CifFileConsumerImplTest.java

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package org.biojava.nbio.structure.io.cif;
22

3+
import org.biojava.nbio.structure.Atom;
34
import org.biojava.nbio.structure.Chain;
5+
import org.biojava.nbio.structure.Element;
6+
import org.biojava.nbio.structure.Group;
7+
import org.biojava.nbio.structure.StructureTools;
48
import org.biojava.nbio.structure.EntityInfo;
59
import org.biojava.nbio.structure.EntityType;
610
import org.biojava.nbio.structure.Structure;
@@ -17,6 +21,7 @@
1721
import java.io.ByteArrayInputStream;
1822
import java.io.IOException;
1923
import java.io.InputStream;
24+
import java.nio.charset.StandardCharsets;
2025
import java.text.ParseException;
2126
import java.text.SimpleDateFormat;
2227
import java.util.Date;
@@ -267,4 +272,68 @@ public void testAtomSiteWithMissingAuthFields() throws IOException {
267272
assertEquals(2, s.getPolyChain("A").getAtomGroups().size());
268273
assertEquals(2, s.getPolyChainByPDB("A").getAtomGroups().size());
269274
}
270-
}
275+
276+
/**
277+
* With parseCAOnly, only C-alpha atoms must be kept: no N/O/S or other non-carbon atoms,
278+
* and no calcium ions (atom name CA, element Ca).
279+
*/
280+
@Test
281+
public void testParseCAOnly() throws IOException {
282+
String resource = "/org/biojava/nbio/structure/io/mmcif/1stp_v5.cif";
283+
String mmcifStr;
284+
try (InputStream inputStream = getClass().getResourceAsStream(resource)) {
285+
Objects.requireNonNull(inputStream, "could not acquire test resource " + resource);
286+
mmcifStr = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
287+
}
288+
// turn the last water oxygen into an atom named CA with element Ca, like a calcium ion
289+
String waterRow = "HETATM 1001 O O . HOH C 3 . ? 19.892 14.908 -13.679 0.90 40.00 ? 449 HOH A O 1";
290+
assertTrue(mmcifStr.contains(waterRow));
291+
mmcifStr = mmcifStr.replace(waterRow, "HETATM 1001 CA CA . HOH C 3 . ? 19.892 14.908 -13.679 0.90 40.00 ? 449 HOH A CA 1");
292+
293+
FileParsingParameters fullParams = new FileParsingParameters();
294+
fullParams.setCreateAtomBonds(true);
295+
Structure full = CifStructureConverter.fromInputStream(
296+
new ByteArrayInputStream(mmcifStr.getBytes(StandardCharsets.UTF_8)), fullParams);
297+
298+
FileParsingParameters caParams = new FileParsingParameters();
299+
caParams.setCreateAtomBonds(true);
300+
caParams.setParseCAOnly(true);
301+
Structure caOnly = CifStructureConverter.fromInputStream(
302+
new ByteArrayInputStream(mmcifStr.getBytes(StandardCharsets.UTF_8)), caParams);
303+
304+
int expected = 0;
305+
boolean hasCalcium = false;
306+
for (int model = 0; model < full.nrModels(); model++) {
307+
for (Chain chain : full.getChains(model)) {
308+
for (Group group : chain.getAtomGroups()) {
309+
Atom ca = group.getAtom(StructureTools.CA_ATOM_NAME);
310+
if (group.isAminoAcid() && ca != null) {
311+
expected++;
312+
} else if (ca != null && ca.getElement() == Element.Ca) {
313+
hasCalcium = true;
314+
}
315+
}
316+
}
317+
}
318+
assertTrue(expected > 0);
319+
assertTrue("test input should contain a calcium named CA", hasCalcium);
320+
321+
int count = 0;
322+
for (int model = 0; model < caOnly.nrModels(); model++) {
323+
// the water and ligand chains hold no C-alpha, so they should not have been created
324+
assertEquals(full.getPolyChains(model).size(), caOnly.getChains(model).size());
325+
for (Chain chain : caOnly.getChains(model)) {
326+
for (Group group : chain.getAtomGroups()) {
327+
// no group without a C-alpha should have been created either
328+
assertEquals(1, group.getAtoms().size());
329+
for (Atom atom : group.getAtoms()) {
330+
assertEquals(StructureTools.CA_ATOM_NAME, atom.getName());
331+
assertEquals(Element.C, atom.getElement());
332+
count++;
333+
}
334+
}
335+
}
336+
}
337+
assertEquals(expected, count);
338+
}
339+
}

0 commit comments

Comments
 (0)