diff --git a/package/CHANGELOG b/package/CHANGELOG index 7f78ac7982..83bff74002 100644 --- a/package/CHANGELOG +++ b/package/CHANGELOG @@ -14,14 +14,15 @@ The rules for this file: ------------------------------------------------------------------------------- -??/??/?? IAlibay, ChiahsinChu +??/??/?? IAlibay, ChiahsinChu, RMeli * 2.9.0 Fixes Enhancements - * Added `precision` for XYZWriter (Issue #4775, PR #4771) + * Add check and warning for empty (all zero) coordinates in RDKit converter (PR #4824) + * Added `precision` for XYZWriter (Issue #4775, PR #4771) Changes diff --git a/package/MDAnalysis/converters/RDKit.py b/package/MDAnalysis/converters/RDKit.py index 85f55b7900..aa78a7ea0c 100644 --- a/package/MDAnalysis/converters/RDKit.py +++ b/package/MDAnalysis/converters/RDKit.py @@ -363,9 +363,12 @@ def convert(self, obj, cache=True, NoImplicit=True, max_iter=200, # add a conformer for the current Timestep if hasattr(ag, "positions"): - if np.isnan(ag.positions).any(): - warnings.warn("NaN detected in coordinates, the output " - "molecule will not have 3D coordinates assigned") + if np.isnan(ag.positions).any() or np.allclose( + ag.positions, 0.0, rtol=0.0, atol=1e-12 + ): + warnings.warn("NaN or empty coordinates detected in coordinates, " + "the output molecule will not have 3D coordinates " + "assigned") else: # assign coordinates conf = Chem.Conformer(mol.GetNumAtoms()) diff --git a/testsuite/MDAnalysisTests/converters/test_rdkit.py b/testsuite/MDAnalysisTests/converters/test_rdkit.py index 16793a4484..1d56c4c5f6 100644 --- a/testsuite/MDAnalysisTests/converters/test_rdkit.py +++ b/testsuite/MDAnalysisTests/converters/test_rdkit.py @@ -331,7 +331,7 @@ def test_nan_coords(self): xyz = u.atoms.positions xyz[0][2] = np.nan u.atoms.positions = xyz - with pytest.warns(UserWarning, match="NaN detected"): + with pytest.warns(UserWarning, match="NaN .* detected"): mol = u.atoms.convert_to("RDKIT") with pytest.raises(ValueError, match="Bad Conformer Id"): mol.GetConformer() @@ -692,6 +692,18 @@ def test_reorder_atoms(self, smi): expected = [a.GetSymbol() for a in mol.GetAtoms()] assert values == expected + @pytest.mark.parametrize("smi", [ + "O=S(C)(C)=NC", + ]) + def test_warn_empty_coords(self, smi): + mol = Chem.MolFromSmiles(smi) + mol = Chem.AddHs(mol) + # remove bond order and charges info + pdb = Chem.MolToPDBBlock(mol) + u = mda.Universe(StringIO(pdb), format="PDB") + with pytest.warns(match="NaN or empty coordinates detected"): + u.atoms.convert_to.rdkit() + def test_pdb_names(self): u = mda.Universe(PDB_helix) mol = u.atoms.convert_to.rdkit()