Skip to content

Commit 3ce3a4d

Browse files
authored
Merge pull request #300 from OpenBioSim/backport_299
Backport fixes from #299
2 parents c2eb501 + 379bc10 commit 3ce3a4d

File tree

7 files changed

+158
-1
lines changed

7 files changed

+158
-1
lines changed

corelib/src/libs/SireIO/amberrst7.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,15 @@ void AmberRst7::parse(const PropertyMap &map)
357357
// we have already validated that there are enough lines
358358
const QString &line = l[linenum];
359359

360+
if (natoms <= 2 and line.trimmed().isEmpty())
361+
{
362+
// if there are only two atoms, then the final line might not be reserved
363+
// for velocities
364+
vels.clear();
365+
366+
return;
367+
}
368+
360369
if (line.length() < column + 36)
361370
{
362371
errors.append(QObject::tr("Cannot read the velocities for the atom at index %1 as "

corelib/src/libs/SireIO/sdf.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -1898,6 +1898,9 @@ MolEditor SDF::getMolecule(int imol, const PropertyMap &map) const
18981898
mol.setProperty(map["sdf_counts"], SireBase::wrap(sdf_counts));
18991899
}
19001900

1901+
// set the name of the molecule
1902+
mol.rename(MolName(sdfmol.name));
1903+
19011904
return mol.setProperty(map["coordinates"], coords)
19021905
.setProperty(map["formal_charge"], charges)
19031906
.setProperty(map["element"], elements)

doc/source/changelog.rst

+9
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ Development was migrated into the
1212
`OpenBioSim <https://github.com/openbiosim>`__
1313
organisation on `GitHub <https://github.com/openbiosim/sire>`__.
1414

15+
`2024.4.2 <https://github.com/openbiosim/sire/compare/2024.4.1...2024.4.2>`__ - Feb 2025
16+
----------------------------------------------------------------------------------------
17+
18+
* Preserve molecule name when reading from SDF format.
19+
20+
* Handle missing velocity data for ``AMBER`` RST7 files with only a few atoms.
21+
22+
* Preserve SDF metadata when converting to ``RDKIt`` format.
23+
1524
`2024.4.1 <https://github.com/openbiosim/sire/compare/2024.4.0...2024.4.1>`__ - Feb 2025
1625
----------------------------------------------------------------------------------------
1726

tests/conftest.py

+5
Original file line numberDiff line numberDiff line change
@@ -243,3 +243,8 @@ def openmm_platform():
243243
@pytest.fixture(scope="session")
244244
def thrombin_complex():
245245
return sr.load_test_files("thrombin.top", "thrombin.rst7")
246+
247+
248+
@pytest.fixture(scope="session")
249+
def tagged_sdf():
250+
return sr.load_test_files("sdf_tags.sdf")[0]

tests/convert/test_rdkit.py

+31
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,34 @@ def test_rdkit_force_infer():
179179

180180
assert bond == "SINGLE"
181181
assert bond_infer == "TRIPLE"
182+
183+
184+
@pytest.mark.skipif(
185+
"rdkit" not in sr.convert.supported_formats(),
186+
reason="rdkit support is not available",
187+
)
188+
def test_rdkit_sdf_tags(tagged_sdf):
189+
190+
# store the sdf data property
191+
sdf_data = tagged_sdf.property("sdf_data")
192+
193+
# convert to rdkit
194+
rdmol = sr.convert.to_rdkit(tagged_sdf)
195+
196+
# convert back to sire
197+
mol = sr.convert.to_sire(rdmol)
198+
199+
# get the rdf data property
200+
rdkit_data = mol.property("rdkit_data")
201+
202+
# check that the data is the same
203+
for prop in sdf_data.keys():
204+
assert prop in rdkit_data.keys()
205+
assert sdf_data[prop] == rdkit_data[prop]
206+
207+
# convert back to rdkit
208+
rdmol2 = sr.convert.to_rdkit(mol)
209+
210+
# check that the data is the same on the rdkit molecule
211+
for prop in rdmol.GetPropNames():
212+
assert rdmol.GetProp(prop) == rdmol2.GetProp(prop)

tests/io/test_sdf.py

+7
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,10 @@ def test_charge():
4141
# Read back in and check that the charges are still correct.
4242
for c0, c1 in zip(mol.property("formal_charge").to_list(), mapping.values()):
4343
assert isclose(c0.value(), c1)
44+
45+
46+
def test_name(tagged_sdf):
47+
"""
48+
Make sure that the molecule takes its name from the SDF title field.
49+
"""
50+
assert tagged_sdf.name().value() == tagged_sdf.property("name").value()

wrapper/Convert/SireRDKit/sire_rdkit.cpp

+94-1
Original file line numberDiff line numberDiff line change
@@ -597,8 +597,71 @@ namespace SireRDKit
597597
RDKit::RWMol molecule;
598598
molecule.beginBatchEdit();
599599

600+
// set the name of the molecule
600601
molecule.setProp<std::string>("_Name", mol.name().value().toStdString());
601602

603+
// set any SDF tags as properties
604+
std::string sdf_tag;
605+
if (mol.hasProperty("sdf_data"))
606+
{
607+
const auto sdf_data = mol.property("sdf_data").asA<SireBase::Properties>();
608+
609+
for (const auto &tag : sdf_data.propertyKeys())
610+
{
611+
try
612+
{
613+
molecule.setProp<std::string>(tag.toStdString(), sdf_data.property(tag).asAString().toStdString());
614+
}
615+
catch (...)
616+
{
617+
const auto string_array = sdf_data.property(tag).asA<SireBase::StringArrayProperty>();
618+
619+
QString string;
620+
for (int i=0; i<string_array.size(); i++)
621+
{
622+
string.append(string_array[i]);
623+
if (i < string_array.size() - 1)
624+
{
625+
string.append("\n");
626+
}
627+
}
628+
629+
molecule.setProp<std::string>(tag.toStdString(), string.toStdString());
630+
}
631+
}
632+
}
633+
634+
// set and existing RDKit data as properties
635+
std::string rdkit_tag;
636+
if (mol.hasProperty("rdkit_data"))
637+
{
638+
const auto rdkit_data = mol.property("rdkit_data").asA<SireBase::Properties>();
639+
640+
for (const auto &tag : rdkit_data.propertyKeys())
641+
{
642+
try
643+
{
644+
molecule.setProp<std::string>(tag.toStdString(), rdkit_data.property(tag).asAString().toStdString());
645+
}
646+
catch (...)
647+
{
648+
const auto string_array = rdkit_data.property(tag).asA<SireBase::StringArrayProperty>();
649+
650+
QString string;
651+
for (int i=0; i<string_array.size(); i++)
652+
{
653+
string.append(string_array[i]);
654+
if (i < string_array.size() - 1)
655+
{
656+
string.append("\n");
657+
}
658+
}
659+
660+
molecule.setProp<std::string>(tag.toStdString(), string.toStdString());
661+
}
662+
}
663+
}
664+
602665
const auto atoms = mol.atoms();
603666

604667
QList<SireMol::Element> elements;
@@ -793,7 +856,6 @@ namespace SireRDKit
793856
try
794857
{
795858
RDKit::MolOps::sanitizeMol(molecule);
796-
797859
}
798860
catch (...)
799861
{
@@ -997,6 +1059,37 @@ namespace SireRDKit
9971059
}
9981060
}
9991061

1062+
// copy additional properties from the molecule
1063+
SireBase::Properties props;
1064+
1065+
for (const auto &prop : mol->getPropList())
1066+
{
1067+
const auto sire_prop = QString::fromStdString(prop);
1068+
1069+
// skip internal properties
1070+
if (sire_prop.startsWith("_"))
1071+
continue;
1072+
1073+
const auto value = QString::fromStdString(mol->getProp<std::string>(prop));
1074+
const auto list = value.split("\n");
1075+
1076+
// there is a list of values
1077+
if (list.count() > 1)
1078+
{
1079+
props.setProperty(sire_prop, SireBase::wrap(list));
1080+
}
1081+
// there is a single value
1082+
else
1083+
{
1084+
props.setProperty(sire_prop, SireBase::wrap(value));
1085+
}
1086+
}
1087+
1088+
if (not props.isEmpty())
1089+
{
1090+
molecule.setProperty("rdkit_data", props);
1091+
}
1092+
10001093
return molecule.commit();
10011094
}
10021095

0 commit comments

Comments
 (0)