news 2026/10/16 6:18:49

RDKit 增强立体化学(Enhanced Stereochemistry)完全指南:StereoGroup 表示、枚举、反应与文件往返

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RDKit 增强立体化学(Enhanced Stereochemistry)完全指南:StereoGroup 表示、枚举、反应与文件往返
  • 科学计算
  • 科研
  • 机器学习

【免费下载链接】rdkit

The official sources for the RDKit library

项目地址:https://gitcode.com/gh_mirrors/rd/rdkit
点击查看免费下载

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。两者参数一致:

参数默认值含义
onlyUnassignedTrue只扰动"未指定"立体化学的中心;已指定构型的中心不改变(除非它属于某个相对立体化学组)
onlyStereoGroupsFalse若为True,只枚举在分子 StereoGroup 处存在差异的异构体——对应原文档"只枚举 Stereo Groups"的能力
uniqueTrue只返回 canonical SMILES 不同的异构体(去除冗余)
maxIsomers1024(Python)/0(C++)最大产出数;超出时随机抽样子集;0表示全部产出。每个额外立体中心会使结果数翻倍,需注意控制
tryEmbeddingFalse对每个异构体尝试用距离几何生成构象,失败则视为"不可物理存在"而丢弃。计算开销大,且只是启发式,可能误删异构体
rand/randomSeedNone/-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

项目地址:https://gitcode.com/gh_mirrors/rd/rdkit
点击查看免费下载

相关推荐

上一篇:MLflow LlamaIndex Flavor 实战指南:从索引日志、引擎部署到自动追踪
下一篇:Qwen Code DaemonSessionClient 的 clientId 自愈机制:基于 `invalid_client_id` 的会话重注册与单次重试设计

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 6:16:31

3D模型渲染从建出来到渲染对:计算机图形学原理与实操排查指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/16 6:16:28

MP2642GR-Z与PIC18F47J53协同实现2S电池动态均衡方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/16 6:16:11

CMP终点检测:磨削速率与膜厚的实时控制

一、痛点背景&#xff1a;从一次真实的生产事故说起CMP终点检测&#xff1a;磨削速率与膜厚的实时控制这个问题&#xff0c;在FAB里不是一天两天了。我见过太多工程师踩坑&#xff1a;要么是方法用错导致数据误判&#xff0c;要么是工具选型失误导致项目延期&#xff0c;要么是…

作者头像 李华
网站建设 2026/10/16 6:16:11

良率管理系统YMS:选型要点与实施路线

一、痛点背景&#xff1a;从一次真实的生产事故说起良率管理系统YMS&#xff1a;选型要点与实施路线这个问题&#xff0c;在FAB里不是一天两天了。我见过太多工程师踩坑&#xff1a;要么是方法用错导致数据误判&#xff0c;要么是工具选型失误导致项目延期&#xff0c;要么是流…

作者头像 李华
网站建设 2026/10/16 6:11:49

KVM虚拟磁盘格式选型:qcow2与raw性能、快照与适用场景全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华