Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
89e340f
Bugfix: Unpickled ring data wrong when done consecutively
rietmann-nv Oct 31, 2025
a648f8b
Remove commented cerr outputs
rietmann-nv Oct 31, 2025
b550511
Recompute RingInfo instead of saving previous RingInfo
rietmann-nv Nov 3, 2025
bfafc04
Set owning molecule before setting bond bookmark
rietmann-nv Nov 5, 2025
9d2df3c
Switch back to restoring ringinfo
rietmann-nv Nov 5, 2025
eec0c96
Fixes segfault in testPickler
rietmann-nv Nov 5, 2025
14e14df
Added pickle/unpickle support for properties
rietmann-nv Nov 11, 2025
8911e87
(mostly) Match behavior in PR#8934
rietmann-nv Nov 13, 2025
d729d44
Fixed error around ignoring bond properties when pickling
rietmann-nv Nov 14, 2025
d3f4e27
Handle pickle/unpickle of explicit properties
rietmann-nv Nov 17, 2025
6a49637
Fixed a problem writing pickle data where string query data wasn't co…
rietmann-nv Nov 18, 2025
8106736
Cached compat ringInfo pointer causing trouble in catch_adjustquery.
rietmann-nv Nov 24, 2025
b130275
Current thinking: don't satisfy old proplist requirement
rietmann-nv Nov 24, 2025
38d97d2
Fixes bug in catch_canon.cpp. Properties weren't being copied correctly
rietmann-nv Nov 28, 2025
e11db4b
Fixed a regression in romolcompatTestsCatch
rietmann-nv Nov 28, 2025
9db3cec
Initial implementation of SmilesToMol with RDMol as output.
rietmann-nv Dec 10, 2025
8d694f5
Fixed failure in smiTestCatch: Update backend after expandQuery
rietmann-nv Dec 10, 2025
f47b295
Fix fileParsersTest1 failure: PropToken handling
rietmann-nv Dec 12, 2025
2ac6209
Fix pickling of PropTokens
rietmann-nv Dec 12, 2025
e4d46fc
Fixed MaeWriter code for Properties and PropTokens
rietmann-nv Dec 12, 2025
9c7aaa4
Previously free'd query was causing a segfault
rietmann-nv Dec 15, 2025
690de13
Fixing testSubstructMatch failure by removing numAtomRings check
rietmann-nv Dec 19, 2025
40e08ab
Removed unused code that shouldn't be in public interface
rietmann-nv Dec 22, 2025
d14428c
Modified existing property compatibility testing to use new interface
rietmann-nv Dec 22, 2025
0cc47fa
Fixed testChemTransforms by fixing an iterator invalidation
rietmann-nv Dec 23, 2025
ce60f18
Fix a regression in graphMol tests
rietmann-nv Dec 23, 2025
8944ed8
Added updatePropertyCache to 'constructForceField' to avoid error
rietmann-nv Dec 23, 2025
ff8e70e
Fix SVG output in case of 0 atomic number.
rietmann-nv Dec 23, 2025
220c5de
Fixed ordering issue in non-bison smarts parser
rietmann Dec 23, 2025
8755382
Fixed SynthonSpaceSearch: The ringInfo compat needed an update
rietmann Dec 31, 2025
5af2880
Fixed testRGroupDecomp: need to add props after atom has owning mol
rietmann-nv Jan 5, 2026
60453b3
Fix error in testSLNParse: Remove check preventing multi-setOwningMol
rietmann-nv Jan 6, 2026
6a89510
Fixed molStandardizeCatchTest: Test used getDict API which no longer …
rietmann-nv Jan 6, 2026
e43c38d
Fixed testAbbreviations: Iterator invalidation causing problems
rietmann-nv Jan 7, 2026
3bf0d2a
Fixed pyChemReactions: Re-implemented GetPropsAsDict() avoidng "GetDi…
rietmann-nv Jan 7, 2026
bfe80d6
Fixed pyDeprotect: Move string property conversion down, to avoid con…
rietmann-nv Jan 7, 2026
3e605d4
Fix a regression in when to autoconvert prop to string
rietmann-nv Jan 7, 2026
6c96dd3
Fixed pyTestPropertyLists: Try Property for uint before int
rietmann-nv Jan 7, 2026
22200d4
Fixed pythonProjectTests: Needed to updatePropertyCache after pickling
rietmann-nv Jan 8, 2026
c52d7ca
Added handling for inner being a nullptr when calling makeNewNonCompa…
mnoack-nvidia Jan 8, 2026
612977a
Fixing part of pyGraphMolWrap: better python property overflow handling
rietmann-nv Jan 9, 2026
b007785
Fixing pyGraphMolWrap: large fix to stereo groups compat interface
rietmann-nv Jan 9, 2026
9f9b6c3
Merge remote-tracking branch 'github-rietmann-nv/minimal_rdmol' into …
rietmann-nv Jan 9, 2026
58c9d9e
Small regression fix: update stereoGroups compat when 0 size
rietmann-nv Jan 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Code/DataStructs/ExplicitBitVect.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
*/
class RDKIT_DATASTRUCTS_EXPORT ExplicitBitVect : public BitVect {
public:
ExplicitBitVect() {}
ExplicitBitVect() : dp_bits(nullptr), d_size(0), d_numOnBits(0) {
_initForSize(0);
}
//! initialize with a particular size;
explicit ExplicitBitVect(unsigned int size)
: dp_bits(nullptr), d_size(0), d_numOnBits(0) {
Expand Down
24 changes: 17 additions & 7 deletions Code/GraphMol/Abbreviations/Abbreviations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ void applyMatches(RWMol &mol, const std::vector<AbbreviationMatch> &matches) {
std::vector<unsigned int> prevBondMapping;
std::vector<unsigned int> addedBonds;
addedBonds.reserve(mol.getNumBonds());
// Store bonds to add - pairs of (atom1, atom2, originalBondIdx)
std::vector<std::tuple<unsigned int, unsigned int, unsigned int>> bondsToAdd;
bool hasPrevMapping =
mol.getPropIfPresent(common_properties::origAtomMapping,
prevAtomMapping) &&
Expand Down Expand Up @@ -74,10 +76,10 @@ void applyMatches(RWMol &mol, const std::vector<AbbreviationMatch> &matches) {
[nbrIdx](const std::pair<int, int> &tpr) {
return tpr.second == rdcast<int>(nbrIdx);
})) {
mol.addBond(nbrIdx, connectIdx, Bond::BondType::SINGLE);
addedBonds.push_back(hasPrevMapping
? prevBondMapping.at(bond->getIdx())
: bond->getIdx());
// Defer bond addition to avoid iterator invalidation
bondsToAdd.emplace_back(nbrIdx, connectIdx,
hasPrevMapping ? prevBondMapping.at(bond->getIdx())
: bond->getIdx());
}
}
}
Expand All @@ -92,11 +94,19 @@ void applyMatches(RWMol &mol, const std::vector<AbbreviationMatch> &matches) {
}
}
CHECK_INVARIANT(bondIdx != -1, "bondIdx not found");
mol.addBond(oaidx, connectIdx, Bond::BondType::SINGLE);
addedBonds.push_back(hasPrevMapping ? prevBondMapping.at(bondIdx)
: bondIdx);
// Defer bond addition to avoid iterator invalidation
bondsToAdd.emplace_back(oaidx, connectIdx,
hasPrevMapping ? prevBondMapping.at(bondIdx)
: bondIdx);
}
}

// Now add all the deferred bonds, checking for duplicates
for (const auto &[atom1, atom2, origBondIdx] : bondsToAdd) {
mol.addBond(atom1, atom2, Bond::BondType::SINGLE);
addedBonds.push_back(origBondIdx);
}

std::vector<unsigned int> atomMapping;
atomMapping.reserve(mol.getNumAtoms());
std::vector<unsigned int> bondMapping;
Expand Down
20 changes: 17 additions & 3 deletions Code/GraphMol/AddHs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -549,12 +549,27 @@ void addHs(RWMol &mol, const AddHsParameters &params,
} else {
onAtoms.set();
}
std::vector<unsigned int> numExplicitHs(mol.getNumAtoms(), 0);
std::vector<unsigned int> numImplicitHs(mol.getNumAtoms(), 0);

// Ensure all atoms have implicit valence calculated (e.g., after unpickling)
// If noImplicit is false, the atom may need implicit valence calculated
// Skip query atoms (or atoms connected to query bonds) as they are handled separately
for (auto at : mol.atoms()) {
if (!at->getNoImplicit() && !isQueryAtom(mol, *at)) {
at->updatePropertyCache(false);
}
}

for (auto at : mol.atoms()) {
numExplicitHs[at->getIdx()] = at->getNumExplicitHs();
numImplicitHs[at->getIdx()] = at->getNumImplicitHs();
if (onAtoms[at->getIdx()]) {
if (params.skipQueries && isQueryAtom(mol, *at)) {
onAtoms.set(at->getIdx(), 0);
continue;
}

numAddHyds += at->getNumExplicitHs();
if (!params.explicitOnly) {
numAddHyds += at->getNumImplicitHs();
Expand Down Expand Up @@ -586,7 +601,7 @@ void addHs(RWMol &mol, const AddHsParameters &params,
unsigned int newIdx;
newAt->clearComputedProps();
// always convert explicit Hs
unsigned int onumexpl = newAt->getNumExplicitHs();
unsigned int onumexpl = numExplicitHs[aidx];
for (unsigned int i = 0; i < onumexpl; i++) {
newIdx = mol.addAtom(new Atom(1), false, true);
mol.addBond(aidx, newIdx, Bond::SINGLE);
Expand All @@ -605,8 +620,7 @@ void addHs(RWMol &mol, const AddHsParameters &params,

if (!params.explicitOnly) {
// take care of implicits
for (unsigned int i = 0; i < mol.getAtomWithIdx(aidx)->getNumImplicitHs();
i++) {
for (unsigned int i = 0; i < mol.getAtomWithIdx(aidx)->getNumImplicitHs(); i++) {
newIdx = mol.addAtom(new Atom(1), false, true);
mol.addBond(aidx, newIdx, Bond::SINGLE);
// set the isImplicit label so that we can strip these back
Expand Down
4 changes: 2 additions & 2 deletions Code/GraphMol/AdjustQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,16 +349,16 @@ void adjustQueryProperties(RWMol &mol, const AdjustQueryParameters *inParams) {
if (inParams) {
params = *inParams;
}
const auto ringInfo = mol.getRingInfo();

if (params.aromatizeIfPossible) {
unsigned int failed;
sanitizeMol(mol, failed, SANITIZE_SYMMRINGS | SANITIZE_SETAROMATICITY);
} else {
const auto ringInfo = mol.getRingInfo();
if (!ringInfo->isSymmSssr()) {
MolOps::symmetrizeSSSR(mol);
}
}
const auto ringInfo = mol.getRingInfo();
QueryAtom qaTmpl;
QueryBond qbTmpl;

Expand Down
29 changes: 15 additions & 14 deletions Code/GraphMol/Atom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,14 +286,14 @@ void Atom::setAtomicNum(int newNum) {
}
std::string Atom::getSymbol() const {
int atomicNum = getAtomicNum();
if (atomicNum == 0) {
// handle dummies differently:
std::string res;
dp_dataMol->getAtomPropIfPresent<std::string>(
common_properties::dummyLabelToken, d_index, res);
return res;
std::string res;
// handle dummies differently:
if (atomicNum != 0 ||
!dp_dataMol->getAtomPropIfPresent<std::string>(
common_properties::dummyLabelToken, d_index, res)) {
res = PeriodicTable::getTable()->getElementSymbol(atomicNum);
}
return PeriodicTable::getTable()->getElementSymbol(atomicNum);
return res;
}
ROMol &Atom::getOwningMol() const {
PRECONDITION(dp_owningMol != nullptr, "no owner");
Expand Down Expand Up @@ -412,13 +412,14 @@ bool Atom::Match(Atom const* what) const {
// [*] matches [*],[1*],[2*],etc.
// [1*] only matches [*] and [1*]
if (res) {
if (hasOwningMol() && what->hasOwningMol() &&
this->getOwningMol().getRingInfo()->isInitialized() &&
what->getOwningMol().getRingInfo()->isInitialized() &&
this->getOwningMol().getRingInfo()->numAtomRings(d_index) >
what->getOwningMol().getRingInfo()->numAtomRings(what->d_index)) {
res = false;
} else if (!this->getAtomicNum()) {
// if (hasOwningMol() && what->hasOwningMol() &&
// this->getOwningMol().getRingInfo()->isInitialized() &&
// what->getOwningMol().getRingInfo()->isInitialized() &&
// this->getOwningMol().getRingInfo()->numAtomRings(d_index) >
// what->getOwningMol().getRingInfo()->numAtomRings(what->d_index)) {
// res = false;
// } else if (!this->getAtomicNum()) {
if (!this->getAtomicNum()) {
// this is the new behavior, based on the isotopes:
int tgt = this->getIsotope();
int test = what->getIsotope();
Expand Down
2 changes: 0 additions & 2 deletions Code/GraphMol/Bond.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,6 @@ void Bond::setOwningMol(ROMol *other) {
}

void Bond::setOwningMol(RDMol* other) {
PRECONDITION(dp_owningMol == nullptr || dp_owningMol == other,
"setOwningMol called twice");
dp_owningMol = other;
}

Expand Down
2 changes: 1 addition & 1 deletion Code/GraphMol/ChemReactions/ReactionRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1546,7 +1546,7 @@ generateOneProductSet(const ChemicalReaction &rxn,
if (!(*pTemplIt)->getStereoGroups().empty()) {
copyTemplateStereoGroupsToMol(**pTemplIt, product);
}

product->updatePropertyCache(false);
res[prodId] = product;
++prodId;
}
Expand Down
14 changes: 10 additions & 4 deletions Code/GraphMol/ChemTransforms/ChemTransforms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,19 +227,25 @@ std::vector<ROMOL_SPTR> replaceSubstructs(

// loop over the central atom's (the first atom in match) bonds
// and duplicate any that connect to the remainder of the molecule:
// Collect neighbor indices first since addBond will invalidate iterators
Atom *origAtom = newMol->getAtomWithIdx(match[0]);
std::vector<unsigned int> neighbors;
ROMol::ADJ_ITER nbrIdx, endNbrs;
boost::tie(nbrIdx, endNbrs) = newMol->getAtomNeighbors(origAtom);
while (nbrIdx != endNbrs) {
neighbors.push_back(*nbrIdx);
nbrIdx++;
}

for (auto neighborIdx : neighbors) {
// we don't want to duplicate any "intra-match" bonds:
if (!std::binary_search(sortMatch.begin(), sortMatch.end(),
int(*nbrIdx))) {
Bond *oBond = newMol->getBondBetweenAtoms(match[0], *nbrIdx);
int(neighborIdx))) {
Bond *oBond = newMol->getBondBetweenAtoms(match[0], neighborIdx);
CHECK_INVARIANT(oBond, "required bond not found");
newMol->addBond(numOrigAtoms + replacementConnectionPoint, *nbrIdx,
newMol->addBond(numOrigAtoms + replacementConnectionPoint, neighborIdx,
oBond->getBondType());
}
nbrIdx++;
}

if (replaceAll) {
Expand Down
24 changes: 19 additions & 5 deletions Code/GraphMol/FileParsers/MaeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,28 @@ void copyProperties(
continue;
}

switch (prop.getRDValueTag()) {
// Get the RDValue tag based on scope
auto tag = (scope == RDMol::Scope::MOL) ? prop.getRDValueTag() : prop.getRDValueTag(idx);

// Helper lambda to get property value based on scope
auto getPropValue = [&](const auto& token) -> RDValue {
if (scope == RDMol::Scope::MOL) {
return mol.getMolProp<RDValue>(token);
} else if (scope == RDMol::Scope::ATOM) {
return mol.getAtomProp<RDValue>(token, idx);
} else { // BOND
return mol.getBondProp<RDValue>(token, idx);
}
};

switch (tag) {
case RDTypeTag::BoolTag: {
auto propName = prop.name().getString();
if (!std::regex_match(prop.name().getString(), MMCT_PROP_REGEX)) {
propName.insert(0, "b_rdkit_");
}

bool v = mol.getAtomProp<bool>(prop.name(), idx);
bool v = rdvalue_cast<bool>(getPropValue(prop.name()));
boolSetter(propName, idx, v);
break;
}
Expand All @@ -182,7 +196,7 @@ void copyProperties(
propName.insert(0, "i_rdkit_");
}

int v = mol.getAtomProp<int>(prop.name(), idx);
int v = rdvalue_cast<int>(getPropValue(prop.name()));
intSetter(propName, idx, v);
break;
}
Expand All @@ -194,7 +208,7 @@ void copyProperties(
propName.insert(0, "r_rdkit_");
}

double v = mol.getAtomProp<double>(prop.name(), idx);
double v = rdvalue_cast<double>(getPropValue(prop.name()));
realSetter(propName, idx, v);
break;
}
Expand All @@ -205,7 +219,7 @@ void copyProperties(
propName.insert(0, "s_rdkit_");
}

std::string v = mol.getAtomProp<std::string>(prop.name(), idx);
std::string v = rdvalue_cast<std::string>(getPropValue(prop.name()));
stringSetter(propName, idx, v);
break;
}
Expand Down
5 changes: 2 additions & 3 deletions Code/GraphMol/FileParsers/MolFileParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1348,7 +1348,7 @@ void ParseAtomAlias(RWMol *mol, std::string text, const std::string &nextLine,
}
URANGE_CHECK(idx, mol->getNumAtoms());
Atom *at = mol->getAtomWithIdx(idx);
at->setProp(common_properties::molFileAlias, nextLine);
setAtomAlias(at, nextLine);
}

void ParseAtomValue(RWMol *mol, std::string text, unsigned int line) {
Expand All @@ -1367,8 +1367,7 @@ void ParseAtomValue(RWMol *mol, std::string text, unsigned int line) {
}
URANGE_CHECK(idx, mol->getNumAtoms());
Atom *at = mol->getAtomWithIdx(idx);
at->setProp(common_properties::molFileValue,
text.substr(7, text.length() - 7));
setAtomValue(at, text.substr(7, text.length() - 7));
}

namespace {
Expand Down
Loading