diff --git a/modules/io/src/mol/sdf_writer.cc b/modules/io/src/mol/sdf_writer.cc index 8deaf9a7819f0fff6c069b721af7b55e446a0245..e39444d0cdd394b568f82568622c6b4fbc006545 100644 --- a/modules/io/src/mol/sdf_writer.cc +++ b/modules/io/src/mol/sdf_writer.cc @@ -50,7 +50,12 @@ namespace { << format("%10.4f") % atom.GetPos()[1] << format("%10.4f ") % atom.GetPos()[2] << format("%-3s") % SDFAtomWriter::FormatEle(atom.GetElement()) - << " 0 0 0 0 0 0" + << " 0" // Mass difference + << format("%-3s") % SDFAtomWriter::FormatCharge(atom.GetCharge()) // Charge + << " 0" // Atom stereo parity + << " 0" // Hydrogen count + 1 + << " 0" // Stereo care box + << " 0" // Valence << std::endl; return true; } @@ -66,6 +71,24 @@ namespace { } return return_ele; } + + static String FormatCharge(const Real& chg) { + // Format charge according to https://doi.org/10.1021/ci00007a012 + // 0 = uncharged or value other than these, 1 = +3, 2 = +2, 3 = +1, + // 4 doublet (A), 5 = -1, 6 = -2, 7 = -3 + // Doublet means radical. This function would never return 4. + if (chg == 0) { + return " 0"; + } + else if (abs(chg) > 3) { + String msg = "SDF format only supports charges from -3 to +3, not %g"; + throw IOException(str(format(msg) % chg)); + } + else { + Real chg_sdf = 4 - chg; + return str(format("%3.0f") % chg_sdf); + } + } private: std::ostream& ostr_; std::map<long, int>& atom_indices_; diff --git a/modules/io/tests/test_io_sdf.py b/modules/io/tests/test_io_sdf.py index 718ac0691192f24ddbc04c71d2ef71d15fa631cf..735158fc3c38f8ed2345415ae913143f8b7d1bf1 100644 --- a/modules/io/tests/test_io_sdf.py +++ b/modules/io/tests/test_io_sdf.py @@ -16,6 +16,28 @@ class TestSDF(unittest.TestCase): ent = io.LoadSDF('testfiles/sdf/6d5w_rank1_crlf.sdf.gz') self.assertEqual(len(ent.atoms), 21) self.assertEqual(len(ent.bonds), 24) + + def test_Charge(self): + ent = io.LoadSDF('testfiles/sdf/simple.sdf') + self.assertEqual(ent.FindAtom("00001_Simple Ligand", 1, "6").charge, 0) + + # Write and read charges properly + for chg in range(-3, 4): + ent.FindAtom("00001_Simple Ligand", 1, "6").charge = chg + sdf_str = io.EntityToSDFStr(ent) + ent = io.SDFStrToEntity(sdf_str) + self.assertEqual(ent.FindAtom("00001_Simple Ligand", 1, "6").charge, chg) + + # Only -3 to +3 is supported + # If M CHG is implemented the following tests can be removed + with self.assertRaises(Exception): + ent.FindAtom("00001_Simple Ligand", 1, "6").charge = 4 + io.EntityToSDFStr(ent) + + with self.assertRaises(Exception): + ent.FindAtom("00001_Simple Ligand", 1, "6").charge = -4 + io.EntityToSDFStr(ent) + if __name__== '__main__': from ost import testutils