- 科学计算
- 科研
- 机器学习
【免费下载链接】rdkit
The official sources for the RDKit library
RDKit 的增强立体化学(Enhanced Stereochemistry)机制用于表达样品中立体化学信息不确定的情形:一个分子是多种非对映体的混合物,还是立体化学"只知其相对、不知其绝对"的单一未知物。本文以仓库设计文档 Docs/Code/EnhancedStereo.md 为骨架,结合 StereoGroup.h、EnumerateStereoisomers.py、ReactionRunner.cpp 等源码实现,系统讲解其数据结构、V3000 mol 文件往返、异构体枚举、反应传递、搜索与描绘能力。读完本文,你将掌握如何在 RDKit 中读入、检查、枚举并写出带ABS/AND/OR立体化学标记的分子。
设计动机:V3000 mol 文件中的增强立体化学
该特性最初由 Greg Landrum 于 2018 年 9 月提出(Docs/Code/EnhancedStereo.md,原文档标注为 DRAFT,但仓库内已形成完整实现)。初始实现遵循V3k(V3000)mol 文件中的增强立体化学表示:将具有指定立体化学关系的原子构成一组,并用ABS、AND或OR标记说明我们对这组原子立体化学的已知程度。
其核心语义非常明确:
AND表示混合物(mixture):样品中同时存在多种立体异构体;OR表示未知的单一物质(unknown single substance):样品是某一种异构体,但不确定是哪一种;ABS表示绝对构型(absolute):这组原子的立体化学是确定的。
例如,"AND 两组各 1 个手性中心"意味着 4 种组合都存在;"OR 组"则只可能是其中某一种构型。这一区分对药物研发中的"外消旋体 vs 单一未知构型"场景至关重要:前者应表示为混合物,后者虽然构型未知,但样品本身是纯的。
各种组合的语义对照
原文档用一组"所画结构 → 展开含义"的对照图说明了AND/OR/ABS各组合的语义。下表完整保留该对照关系("Mixture?" 列表示该表示是否描述混合物):
| 所画结构 | 是否为混合物 | 含义(展开) |
|---|---|---|
| mixture | ||
| mixture | ||
| mixture | ||
| single | ||
| single | ||
| single | ||
| mixture | ||
| single |
可见OR组虽然"所画结构"与AND组相同,但语义完全不同:AND展开后是并存(mixture),OR展开后仍是单一化合物(single)。ABS则表达"这组原子中某些构型已知为绝对、其余为相对未知"的混合信息,例如ABS + AND是绝对构型确定部分与混合部分的组合。
核心数据结构:StereoGroup
枚举类型与成员
在分子内部,增强立体化学存储为一个StereoGroup对象的向量(原文档"Representation"一节:Stored as a vector ofStereoGroupobjects)。其定义位于 Code/GraphMol/StereoGroup.h:
enum class StereoGroupType { STEREO_ABSOLUTE = 0, // ABS STEREO_OR = 1, // OR STEREO_AND = 2 // AND };StereoGroup类的成员包括:
d_grouptype:组类型(ABS/OR/AND);d_atoms:参与该立体化学关系的原子指针向量;d_bonds:参与该关系的键指针向量(在后续版本中加入,用于支持 atropisomer 等轴手性场景);d_readId/d_writeId:组 ID。读取 ID来自输入文件(V3000 的STEREL1、STERAC1等后缀编号),写入 ID在输出时使用。0表示未定义。注意组 ID 在ABS组中没有意义(StereoGroup.h中注释:The group ID for AND/OR groups (it has no meaning in ABS groups))。
存取与 ABS 组自动合并
ROMol通过getStereoGroups()/setStereoGroups()存取这些组(见 Code/GraphMol/ROMol.h 的d_stereo_groups成员)。setStereoGroups的实现(Code/GraphMol/ROMol.cpp)有一个值得注意的行为:当传入多个ABS组时,会自动合并为单个ABS组(原子与键分别拼接),以保持"一个分子至多一个绝对构型组"的语义一致性。
原子/键被移除时的维护
原文档指出:"We will need to adjust this when atoms are removed or replaced."(原子被移除或替换时需要调整组)。这一需求在 StereoGroup.cpp 中实现为一组自由函数:
removeAtomFromGroups(atom, groups):从各组中删除该原子,若组同时为空则整体移除;removeBondFromGroups(bond, groups):从各组中删除该键;removeGroupsWithAtom(atom, groups)/removeGroupsWithAtoms(atoms, groups):删除包含该原子(任一原子)的整个组;- 对应地还有
removeGroupsWithBond/removeGroupsWithBonds。
这些函数在ROMol的原子/键删除流程中被调用,确保分子编辑后立体化学组不会悬挂失效指针。此外构造函数会对原子、键做重复检查,重复成员会抛出ValueErrorException("Duplicate atom/bond in StereoGroup")。
组 ID 的分配与转发
assignStereoGroupIds(groups):为所有未分配写 ID 的AND/OR组按顺序分配输出 ID;若发现重复 ID 会警告并重新分配(StereoGroup.cpp中storeIdsInUse/assignMissingIds逻辑)。forwardStereoGroupIds(mol):将各组的读 ID 复制为写 ID,保证"读入的组编号在导出时不丢失"(这正是原文档"round trip 不丢数据"目标的直接实现)。
StereoGroup还重载了operator<<,可将组以ABS/OR /AND rId: x wId: y atoms: { 1 2 } bonds: { }形式输出到流,便于调试。
文件往返:V3000 mol 文件解析与写出
原文档的首要目标(Use cases)是V3k mol → RDKit → V3k mol 往返不丢数据,操作、描绘与搜索为次要目标。
解析:MDLV30/STEABS、STEREL、STERAC
V3000 mol 文件中增强立体化学位于M V30 BEGIN COLLECTION块内,行格式如下:
M V30 MDLV30/STEABS ATOMS=(2 2 3) M V30 MDLV30/STEREL1 ATOMS=(1 12) M V30 MDLV30/STERAC1 ATOMS=(1 12)STEABS→ABS组;STERELn→OR组,编号n;STERACn→AND组,编号n。
解析器parseEnhancedStereo位于 Code/GraphMol/FileParsers/MolFileParser.cpp,使用正则MDLV30/STE(...)([0-9]*) +ATOMS=\(([0-9]+) +(.*)\)匹配。其行为细节:
- 原子在 mol 文件中是 1 索引的,解析时转换为 0 索引(
index - 1); - 同一个原子在组中出现两次会发出警告(严格解析模式下抛
FileParseException); - 一个分子中出现第二个
ABS组会给出警告(严格模式下报错); - 不认识的 collection 类型(如
MDLV30/HILITE)会被跳过并警告。
写出:appendEnhancedStereoGroups
写出逻辑位于 Code/GraphMol/FileParsers/MolFileWriter.cpp:先调用assignStereoGroupIds确保每个AND/OR组都有合法写 ID,然后按类型写出STEABS/STEREL{id}/STERAC{id},ATOMS=(n ...)中原子为 1 索引;行长度接近 78 字符时自动续行(-\n+M V30)。对于 atropisomer 场景还会通过Atropisomers::getAllAtomIdsForStereoGroup展开相关的轴原子。
MolPickler(RDKit 二进制 pickle)
增强立体化学也已纳入 RDKit 自身的分子 pickle 协议(MolPickler::_pickleStereo/_depickleStereo,见 Code/GraphMol/MolPickler.cpp):序列化组类型、写 ID(对非ABS组)、原子索引和键索引。其中键列表自 pickle 版本> 16000起支持;AND/OR组的组 ID 自版本>= 14010起读写。因此无需依赖 mol 文件即可在 RDKit 内部完整保留立体化学组。
CXSMILES 扩展
在 SMILES 的 CXSMILES 扩展中,增强立体化学组通过/sg:语法表达,解析与写出分别位于 Code/GraphMol/SmilesParse/CXSmilesOps.cpp 与 Code/GraphMol/SmilesParse/SmilesWrite.cpp。例如NC@HC@@HO |sg:1:2,3|表示原子 2、3(0 索引)构成 1 号组(默认AND)。此外 CanonicalizeStereoGroups.cpp 实现了组的标准排序与去重,使同一组的不同内部顺序能输出为一致的标准 SMILES。
立体异构体枚举:把AND/OR展开为具体异构体
原文档"Enumeration"一节指出:Python 函数rdkit.Chem.EnumerateStereoisomers.EnumerateStereoisomers可枚举 StereoGroup 所代表的全部立体异构体,并且可以只枚举 StereoGroup 相关的异构体,忽略其它未指定立体中心。
选项参数(StereoEnumerationOptions)
Python 版定义于 rdkit/Chem/EnumerateStereoisomers.py,C++ 版(David Cosgrove 于 2025 年移植,额外支持 atropisomer)定义于 Code/GraphMol/EnumerateStereoisomers/EnumerateStereoisomers.h。两者参数一致:
| 参数 | 默认值 | 含义 |
|---|---|---|
onlyUnassigned | True | 只扰动"未指定"立体化学的中心;已指定构型的中心不改变(除非它属于某个相对立体化学组) |
onlyStereoGroups | False | 若为True,只枚举在分子 StereoGroup 处存在差异的异构体——对应原文档"只枚举 Stereo Groups"的能力 |
unique | True | 只返回 canonical SMILES 不同的异构体(去除冗余) |
maxIsomers | 1024(Python)/0(C++) | 最大产出数;超出时随机抽样子集;0表示全部产出。每个额外立体中心会使结果数翻倍,需注意控制 |
tryEmbedding | False | 对每个异构体尝试用距离几何生成构象,失败则视为"不可物理存在"而丢弃。计算开销大,且只是启发式,可能误删异构体 |
rand/randomSeed | None/-1 | 随机数种子(Python 版为rand,C++ 版为randomSeed),用于可复现的随机采样 |
实现原理:Flipper 机制
EnumerateStereoisomers的实现基于"翻转器(flipper)":
_AtomFlipper:翻转四面体手性原子的CHI_TETRAHEDRAL_CW/CHI_TETRAHEDRAL_CCW标记;_BondFlipper:翻转双键的STEREOCIS/STEREOTRANS;_StereoGroupFlipper:整体翻转组内所有原子的手性标记(原构型 ↔ 镜像构型),这正是展开AND/OR组的机制。
组合这些翻转器的位掩码,即可遍历全部构型组合。默认onlyUnassigned=True时,已指定构型的中心不被扰动;但对AND/OR组,_getFlippers会额外添加_StereoGroupFlipper(见 EnumerateStereoisomers.py)。枚举出的每个异构体随后会移除自身携带的 StereoGroup(isomer.SetStereoGroups([])),因为此时组信息已被具体构型替代。
使用示例
from rdkit import Chem from rdkit.Chem.EnumerateStereoisomers import ( EnumerateStereoisomers, StereoEnumerationOptions, GetStereoisomerCount, ) # 估计(上界)立体异构体数量,含双键立体化学 m = Chem.MolFromSmiles('BrC(Cl)(F)C=CC(O)C') print(GetStereoisomerCount(m)) # 8 # 枚举全部异构体:3 个手性原子 + 1 个手性双键 = 16 种理论异构体 m = Chem.MolFromSmiles('BrC=CC1OC(C2)(F)C2(Cl)C1') isomers = tuple(EnumerateStereoisomers(m)) print(len(isomers)) # 16 # 用距离几何过滤掉无法成构象(不物理)的异构体 opts = StereoEnumerationOptions(tryEmbedding=True) isomers = tuple(EnumerateStereoisomers(m, options=opts)) print(len(isomers)) # 8 # 只展开 StereoGroup 相关的立体化学,忽略其它未指定中心 opts = StereoEnumerationOptions(onlyStereoGroups=True) # 大规模分子:惰性生成器逐条产出,或随机抽样固定数量(带种子保证可复现) m = Chem.MolFromSmiles('Br' + 'CH' * 20 + 'F') opts = StereoEnumerationOptions(maxIsomers=3, rand=0xf00d) for smi in EnumerateStereoisomers(m, options=opts): print(Chem.MolToSmiles(smi))从源码 doctest(同一文件的文档字符串)可以看到,GetStereoisomerCount返回的是上界估计(2 ** len(flippers)),实际可存在的异构体可能更少——用tryEmbedding=True可进一步筛选。
化学反应中的传递规则
原文档"Reactions"一节给出三条规则:① 反应执行器感知分子上的 StereoGroup,反应物组中的原子会复制到所有包含该原子的产物中,除非反应在该原子处创建或破坏了立体化学;② 若反应物组中的某个原子在产物中出现多次,其所有副本进入同一个产物 StereoGroup;③ 反应模板(RXN)文件中的组也会被复制到产物。
实现位于 Code/GraphMol/ChemReactions/ReactionRunner.cpp 的copyEnhancedStereoGroups:
- 依据
ReactantProductAtomMapping将反应物原子映射到产物原子; - 若产物原子的手性标记变为
CHI_UNSPECIFIED(立体化学被反应破坏),跳过该原子; - 若产物原子带有
molInversionFlag == 4(反应明确定义了该原子的立体化学/构型翻转),跳过该原子——即"反应创建了立体化学"时不再继承反应物的组关系; - 其余产物原子连同原组类型(
sg.getGroupType())与读 ID(sg.getReadId())一起重建为新的StereoGroup,并合并进产物已有的组。
此外copyTemplateStereoGroupsToMol(同文件第 1414 行起)处理 RXN 模板自身的 StereoGroup:模板组中的原子会复制到对应的产物原子,并确保不与从反应物继承的组冲突。源码注释也诚实指出:"虽然已为 atropisomer 增加了存储与 canonicalization,搜索尚未支持,届时需要将组的键部分按需复制到产物"——即键类组在反应传递中目前仍未完整实现。
搜索:从枚举到 MolBundle
原文档"Searching"一节给出的方案是:通过枚举代码生成 MolBundle 对象,再对 MolBundle 进行搜索。也就是把"带增强立体化学的分子匹配"转化为"对枚举展开得到的若干具体异构体进行匹配"——若查询分子能匹配其中任意一个展开异构体,则命中。
原文档同时说明:"Substructure searching and canonicalization do not yet support stereo groups."从当前仓库源码看,这一限制在后续版本中已有部分解除:
- canonicalization 已支持:
CanonicalizeStereoGroups.cpp提供canonicalizeStereoGroups(含StereoGroupAbsOptions、maxStereoGroups等选项)与cleanupStereoGroups,可将异构体枚举的结果规范化输出; - 子结构搜索仍以 MolBundle 为主要路径:
SubstructMatch中已包含StereoGroup相关引用(见 Code/GraphMol/Substruct/SubstructMatch.cpp),仓库注释明确表示搜索尚待完整支持,实际操作中应沿用"先枚举、再匹配 MolBundle"的路线。
描绘:让组在结构图中可见
原文档"Depiction"一节指出需要在描绘代码中"添加让组可见的能力"。当前实现位于 Code/GraphMol/MolDraw2D/DrawMol.cpp:
DrawOptions.addStereoGroupAnnotation:在结构图上绘制立体化学组的注释(extractStereoGroups会遍历组并标注类型与编号);DrawOptions.simplifiedStereoGroupLabel:对非ABS组使用简化标签;- 若开启简化标签,会调用
Chirality::simplifyEnhancedStereo(Code/GraphMol/Chirality.cpp)在绘制副本上合并/简化组,并可选择移除受影响组。
Python 端对应rdkit.Chem.Draw.MolDraw2DOptions的addStereoGroupAnnotation/simplifiedStereoGroupLabel属性。这使研究者可以在图上直观看到AND/OR组及其成员原子,而无需依赖文本文件。
从 2018 草案到当前实现:能力现状小结
原文档是 2018 年的草案,仓库中的实现已远超其描述。按"设计文档为纲、源码为证"的视角,当前状态可归纳为:
| 原文档要点 | 当前实现状态 |
|---|---|
采用 V3k mol 的ABS/AND/OR表示 | ✅ 已实现:解析/写出见MolFileParser.cpp、MolFileWriter.cpp |
存储为StereoGroup对象向量 | ✅StereoGroup.h+ROMol::get/setStereoGroups |
| 原子移除/替换时调整组 | ✅removeAtomFromGroups等辅助函数,并在ROMol删除流程中调用 |
| V3k mol → RDKit → V3k mol 往返不丢数据 | ✅ 读 ID → 写 ID 转发(forwardStereoGroupIds)+ pickle 协议支持 |
EnumerateStereoisomers枚举组代表的异构体 | ✅ Python 版(含onlyStereoGroups)+ C++ 版(2025 年移植,支持 atropisomer) |
| 反应执行器感知并传递组 | ✅copyEnhancedStereoGroups(破坏/新建立体化学时不继承) |
| 搜索:枚举生成 MolBundle 后匹配 | ✅ 作为推荐路径;canonicalization 亦已支持 |
| 描绘:让组可见 | ✅addStereoGroupAnnotation/simplifiedStereoGroupLabel |
实用建议:若你的数据源是 V3000 mol 文件(含MDLV30/STE*collection 块),RDKit 现在可以无损读入并写出;若需基于立体化学组做下游分析(如混合物展开、反应产物预测),可组合使用GetStereoGroups()检查、EnumerateStereoisomers(必要时onlyStereoGroups=True)枚举、以及 MolBundle 匹配完成检索。需要注意的是,本文所描述的行为以当前仓库(Code/GraphMol与rdkit/Chem)的实现为准,maxIsomers默认值在 Python 版与 C++ 版之间存在差异(1024 vs 0),跨语言使用时需显式指定。
- 科学计算
- 科研
- 机器学习
【免费下载链接】rdkit
The official sources for the RDKit library
相关推荐
RDKit rdkit.Chem.rdEnumerateStereoisomers:C++ 驱动的立体异构体枚举模块详解
RDKit rdkit.Chem.rdEnumerateStereoisomers:C++ 驱动的立体异构体枚举模块详解 本篇技术指南围绕 RDKit 中由 C
科学计算科研机器学习RDKit SimpleEnum 虚拟库枚举:基于化学反应与功能基团的化合物库快速生成指南
RDKit SimpleEnum 虚拟库枚举:基于化学反应与功能基团的化合物库快速生成指南 导读 rdkit.Chem.SimpleEnum 是 RDKit 中
科学计算科研机器学习TypeScript 枚举(Enum)完全指南:数字枚举、字符串枚举、常量枚举与反向映射
TypeScript 枚举(Enum)完全指南:数字枚举、字符串枚举、常量枚举与反向映射 枚举( enum )是 TypeScript 提供的一组具名常量值集合
文档教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考