diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/PDBHeader.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/PDBHeader.java index ea0f36115c..a948e3281a 100644 --- a/biojava-structure/src/main/java/org/biojava/nbio/structure/PDBHeader.java +++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/PDBHeader.java @@ -580,6 +580,18 @@ public void setCrystallographicInfo(PDBCrystallographicInfo crystallographicInfo this.crystallographicInfo = crystallographicInfo; } + /** + * Returns the resolution (or effective resolution) of the experiment. This is + * related to _refine.ls_d_res_high (DIFFRACTION) or + * _em_3d_reconstruction.resolution (ELECTRON MICROSCOPY) for mmCif + * format, or to REMARK 2 or REMARK 3 for PDB legacy + * format. If more than one value is available (in rare cases), the last one is + * reported. If no value is available, it defaults to + * {@link #DEFAULT_RESOLUTION} ({@value #DEFAULT_RESOLUTION}). + * + * @return The reported experiment resolution, {@link #DEFAULT_RESOLUTION} + * ({@value #DEFAULT_RESOLUTION}) if no value is available. + */ public float getResolution() { return resolution; } diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/io/PDBFileParser.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/io/PDBFileParser.java index c3dcc330e0..db6669cc75 100644 --- a/biojava-structure/src/main/java/org/biojava/nbio/structure/io/PDBFileParser.java +++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/io/PDBFileParser.java @@ -1351,7 +1351,7 @@ private void pdb_REMARK_Handler(String line) { if (line.startsWith("REMARK 800")) { pdb_REMARK_800_Handler(line); - } else if ( line.startsWith("REMARK 350")){ + } else if ( line.startsWith("REMARK 350")){ if ( params.isParseBioAssembly()) { @@ -1361,6 +1361,10 @@ private void pdb_REMARK_Handler(String line) { bioAssemblyParser.pdb_REMARK_350_Handler(line); } + } else if (line.startsWith("REMARK 2")) { + //REMARK 2 RESOLUTION. + Pattern pR = Pattern.compile("^REMARK 2 RESOLUTION.\\s+(\\d+\\.\\d+)\\s+ANGSTROMS\\..*"); + handleResolutionLine(line, pR); // REMARK 3 (for R free) // note: if more than 1 value present (occurring in hybrid experimental technique entries, e.g. 3ins, 4n9m) @@ -1396,21 +1400,29 @@ private void pdb_REMARK_Handler(String line) { // then last one encountered will be taken } else if (line.startsWith("REMARK 3 RESOLUTION RANGE HIGH")){ Pattern pR = Pattern.compile("^REMARK 3 RESOLUTION RANGE HIGH \\(ANGSTROMS\\) :\\s+(\\d+\\.\\d+).*"); - Matcher mR = pR.matcher(line); - if (mR.matches()) { - try { - float res = Float.parseFloat(mR.group(1)); - if (pdbHeader.getResolution()!=PDBHeader.DEFAULT_RESOLUTION) { - logger.warn("More than 1 resolution value present, will use last one {} and discard previous {} " - ,mR.group(1), String.format("%4.2f",pdbHeader.getResolution())); - } - pdbHeader.setResolution(res); - } catch (NumberFormatException e) { - logger.info("Could not parse resolution '{}', ignoring it",mR.group(1)); + handleResolutionLine(line, pR); + } else if (line.startsWith("REMARK 3 EFFECTIVE RESOLUTION")){ + Pattern pR = Pattern.compile("^REMARK 3 EFFECTIVE RESOLUTION \\(ANGSTROMS\\)\\s+:\\s+(\\d+\\.\\d+).*"); + handleResolutionLine(line, pR); + } + } + + public void handleResolutionLine(String line, Pattern pR) { + Matcher mR = pR.matcher(line); + if (mR.matches()) { + final String resString = mR.group(1); + try { + float res = Float.parseFloat(resString); + final float resInHeader = pdbHeader.getResolution(); + if (resInHeader!=PDBHeader.DEFAULT_RESOLUTION && resInHeader != res) { + logger.warn("More than 1 resolution value present, will use last one {} and discard previous {} " + ,resString, String.format("%4.2f",resInHeader)); } + pdbHeader.setResolution(res); + } catch (NumberFormatException e) { + logger.info("Could not parse resolution '{}', ignoring it",resString); } } - } diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/io/cif/CifStructureConsumer.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/io/cif/CifStructureConsumer.java index c6c5318217..8472bc8056 100644 --- a/biojava-structure/src/main/java/org/biojava/nbio/structure/io/cif/CifStructureConsumer.java +++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/io/cif/CifStructureConsumer.java @@ -10,6 +10,7 @@ import org.rcsb.cif.schema.mm.DatabasePDBRemark; import org.rcsb.cif.schema.mm.DatabasePDBRev; import org.rcsb.cif.schema.mm.DatabasePDBRevRecord; +import org.rcsb.cif.schema.mm.Em3dReconstruction; import org.rcsb.cif.schema.mm.Entity; import org.rcsb.cif.schema.mm.EntityPoly; import org.rcsb.cif.schema.mm.EntityPolySeq; @@ -107,7 +108,13 @@ public interface CifStructureConsumer extends CifFileConsumer { */ void consumeDatabasePDBRevRecord(DatabasePDBRevRecord databasePDBrevRecord); - /** + /** + * Consume Electron Microscopy 3D reconstruction data + * @param em3dReconstruction + */ + void consumeEm3dReconstruction(Em3dReconstruction em3dReconstruction); + + /** * Consume a particular Cif category. * @param entity data */ diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/io/cif/CifStructureConsumerImpl.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/io/cif/CifStructureConsumerImpl.java index eb56b9a59a..debadc4c08 100644 --- a/biojava-structure/src/main/java/org/biojava/nbio/structure/io/cif/CifStructureConsumerImpl.java +++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/io/cif/CifStructureConsumerImpl.java @@ -69,6 +69,7 @@ import org.rcsb.cif.schema.mm.DatabasePDBRemark; import org.rcsb.cif.schema.mm.DatabasePDBRev; import org.rcsb.cif.schema.mm.DatabasePDBRevRecord; +import org.rcsb.cif.schema.mm.Em3dReconstruction; import org.rcsb.cif.schema.mm.Entity; import org.rcsb.cif.schema.mm.EntityPoly; import org.rcsb.cif.schema.mm.EntityPolySeq; @@ -128,6 +129,7 @@ public class CifStructureConsumerImpl implements CifStructureConsumer { private List currentModel; private PDBHeader pdbHeader; private String currentNmrModelNumber; + private Em3dReconstruction em3dReconstruction; private List entityChains; private Entity entity; @@ -644,6 +646,18 @@ public void consumeDatabasePDBRevRecord(DatabasePDBRevRecord databasePDBrevRecor revRecords.add(new org.biojava.nbio.structure.DatabasePDBRevRecord(databasePDBrevRecord, i)); } } + + @Override + public void consumeEm3dReconstruction(Em3dReconstruction em3dReconstruction) { + this.em3dReconstruction = em3dReconstruction; + + for (int rowIndex = 0; rowIndex < em3dReconstruction.getRowCount(); rowIndex++) { //can it have more than 1 value? + final FloatColumn resolution = em3dReconstruction.getResolution(); + if (ValueKind.PRESENT.equals(resolution.getValueKind(rowIndex))) + pdbHeader.setResolution((float) resolution.get(rowIndex)); + } + //TODO other fields (maybe RFree)? + } @Override public void consumeEntity(Entity entity) { @@ -831,6 +845,10 @@ public void consumePdbxStructOperList(PdbxStructOperList pdbxStructOperList) { public void consumeRefine(Refine refine) { for (int rowIndex = 0; rowIndex < refine.getRowCount(); rowIndex++) { // RESOLUTION + ValueKind valueKind = refine.getLsDResHigh().getValueKind(rowIndex); + if (! ValueKind.PRESENT.equals(valueKind)) { + continue; + } // in very rare cases (for instance hybrid methods x-ray + neutron diffraction, e.g. 3ins, 4n9m) // there are 2 resolution values, one for each method // we take the last one found so that behaviour is like in PDB file parsing diff --git a/biojava-structure/src/main/java/org/biojava/nbio/structure/io/cif/CifStructureConverter.java b/biojava-structure/src/main/java/org/biojava/nbio/structure/io/cif/CifStructureConverter.java index 1351223982..4f3a1f403a 100644 --- a/biojava-structure/src/main/java/org/biojava/nbio/structure/io/cif/CifStructureConverter.java +++ b/biojava-structure/src/main/java/org/biojava/nbio/structure/io/cif/CifStructureConverter.java @@ -118,6 +118,7 @@ public static Structure fromCifFile(CifFile cifFile, FileParsingParameters param consumer.consumeDatabasePDBRemark(cifBlock.getDatabasePDBRemark()); consumer.consumeDatabasePDBRev(cifBlock.getDatabasePDBRev()); consumer.consumeDatabasePDBRevRecord(cifBlock.getDatabasePDBRevRecord()); + consumer.consumeEm3dReconstruction(cifBlock.getEm3dReconstruction()); consumer.consumeEntity(cifBlock.getEntity()); consumer.consumeEntityPoly(cifBlock.getEntityPoly()); consumer.consumeEntitySrcGen(cifBlock.getEntitySrcGen());