计算化学公社

 找回密码 Forget password
 注册 Register
Views: 1733|回复 Reply: 39
打印 Print 上一主题 Last thread 下一主题 Next thread

[算法与编程] 如何使用rdkit正确产生高斯坐标

[复制链接 Copy URL]

19

帖子

0

威望

29

eV
积分
48

Level 2 能力者

跳转到指定楼层 Go to specific reply
楼主
由于我需要在复杂的pandas库中方便多维操作。我的分子对象rdkit mol保存在pandas内,现在我需要让rdkit的mol对象合理的转换成xyz坐标,以及高斯输入文件。如何批量生成呢?
之前尝试用

try:
        # 从SMILES创建分子
        mol = Chem.MolFromSmiles(smiles)
        if mol is None:
            if logger:
                logger.warning(f"无效的SMILES字符串: {smiles}")
            return False

        # 添加氢原子
        mol = Chem.AddHs(mol)

        # 尝试多种方法生成3D构象
        success = False
        method_used = None

        # 方法1: ETKDG
        try:
            result = AllChem.EmbedMolecule(mol, AllChem.ETKDG())
            if result == 0:  # 成功
                AllChem.UFFOptimizeMolecule(mol)
                success = True
                method_used = "ETKDG"
        except Exception as e:
            if logger:
                logger.info(f"ETKDG方法失败: {str(e)}")

但是之前发现生成的坐标,有严重的高斯输入不合理性,这些输入可以视为高斯的初猜结构。是为了后面能避免Gaussian运算。请问大家有没有什么好办法,用Python代码解决坐标输入和电荷、自旋多重度的计算


150

帖子

0

威望

726

eV
积分
876

Level 4 (黑子)

2#
发表于 Post on 2025-5-29 10:16:57 | 只看该作者 Only view this author
但是之前发现生成的坐标,有严重的高斯输入不合理性,这些输入可以视为高斯的初猜结构。是为了后面能避免Gaussian运算。请问大家有没有什么好办法,用Python代码解决坐标输入和电荷、自旋多重度的计算


有严重的高斯输入不合理性,可以视为高斯的初猜结构. 不合理为什么还视为高斯输入. 后面又到底要不要进行Gaussian运算rdkit应该是没有办法给mol对象添加自旋的属性.

19

帖子

0

威望

29

eV
积分
48

Level 2 能力者

3#
 楼主 Author| 发表于 Post on 2025-5-29 10:21:57 | 只看该作者 Only view this author
是这样的,我因为是放在ssh上,想通过python生成的rdkit mol对象,去产生高斯的输入文件。当时比较着急,ssh没有图形界面。所以希望有一个比较好鲁棒性的代码,能正确的生成三维构象,同时填入正确的电荷和多重度数值。有一篇文章https://github.com/mitkeng/CCS_Focusing/ 这里人家是生成xyz,然后在生成高斯坐标。我要处理的反应数目(反应物、产物)比较多,一个个看过去确实很麻烦。希望从代码上增强鲁棒性解决。

212

帖子

0

威望

887

eV
积分
1099

Level 4 (黑子)

4#
发表于 Post on 2025-5-29 10:31:13 | 只看该作者 Only view this author
smi生成的结构 如果是有机物并且不包含连2个/4个的氮 连奇数的氧
都是电中性的
直接 0 1就行
如果含过渡金属 非人工不可。

410

帖子

5

威望

1630

eV
积分
2140

Level 5 (御坂)

鸩羽

5#
发表于 Post on 2025-5-29 10:40:31 | 只看该作者 Only view this author
如果是纯有机分子 做ML的 没有构象搜索的条件 那ETKDGv3算法生成构象 力场优化一下应该差不多
要是正儿八经算 那没有图形界面是不行的 你无法预知代码会在什么地方给你整什么活 早期我尝试偷懒的时候甚至遇到过把羧基搞成C-O-O-H的情况
某不知名实验组从苞米地里长出来的计算选手

19

帖子

0

威望

29

eV
积分
48

Level 2 能力者

6#
 楼主 Author| 发表于 Post on 2025-5-29 10:47:39 | 只看该作者 Only view this author
wal 发表于 2025-5-29 10:40
如果是纯有机分子 做ML的 没有构象搜索的条件 那ETKDGv3算法生成构象 力场优化一下应该差不多
要是正儿八 ...

谢谢,当时也是用GPT辅助,力场优化用的是UFF。我不知道rdkit还有没有其他的代码。确实下一步要接入ML的考虑, 没有构象搜索的条件,后期如何评价模型,有的人是把高斯的DFT高精度当作输入(前期耗时具大),也有人是把DFT做验证。目前是原先做的输入有30%不好,主要的问题是addHs还有二面角的问题。(也许有可能是从平面smiles到立体的过程有问题)

19

帖子

0

威望

29

eV
积分
48

Level 2 能力者

7#
 楼主 Author| 发表于 Post on 2025-5-29 10:48:45 | 只看该作者 Only view this author
18217265596 发表于 2025-5-29 10:31
smi生成的结构 如果是有机物并且不包含连2个/4个的氮 连奇数的氧
都是电中性的
直接 0 1就行

有生物体系的磷酸O-存在,还有N3,非天然脂质

410

帖子

5

威望

1630

eV
积分
2140

Level 5 (御坂)

鸩羽

8#
发表于 Post on 2025-5-29 10:53:00 | 只看该作者 Only view this author
sjkcn 发表于 2025-5-29 10:47
谢谢,当时也是用GPT辅助,力场优化用的是UFF。我不知道rdkit还有没有其他的代码。确实下一步要接入ML的 ...

可以试试MMFF94力场
某不知名实验组从苞米地里长出来的计算选手

150

帖子

0

威望

726

eV
积分
876

Level 4 (黑子)

9#
发表于 Post on 2025-5-29 13:35:51 | 只看该作者 Only view this author
rdkit, openbabel, autodE 多试几个,然后得到xyz结构之后用XTB跑个单点,这样筛选能量最低的? 如果及结构比较大的话,就用分子力场

19

帖子

0

威望

29

eV
积分
48

Level 2 能力者

10#
 楼主 Author| 发表于 Post on 2025-5-29 16:38:38 | 只看该作者 Only view this author
Loading0760 发表于 2025-5-29 13:35
rdkit, openbabel, autodE 多试几个,然后得到xyz结构之后用XTB跑个单点,这样筛选能量最低的? 如果及结构比 ...

是这样的,我之前利用rdkit smarts 跑出rdkit mol对象。如果用除了rdkit 其他工具,可能还要单独写Python代码。
其他软件如openbabel autodE 生成三维坐标的过程我不是很懂,是不是也是用力场来建立坐标?

150

帖子

0

威望

726

eV
积分
876

Level 4 (黑子)

11#
发表于 Post on 2025-5-29 17:28:02 | 只看该作者 Only view this author
sjkcn 发表于 2025-5-29 16:38
是这样的,我之前利用rdkit smarts 跑出rdkit mol对象。如果用除了rdkit 其他工具,可能还要单独写Python ...

代码部分其实很好实现,假设你的两个变量一个是smiles,一个是xyz文件的名称
  1. import subprocess
  2. cmd = f'obabel -:"{smiles}" -O {xyz_filename}.xyz -h --gen3d'
  3. subprocess.run(cmd, shell=True, check=True)
复制代码
用autodE的话功能更多
  1. import autode as ade
  2. molecular = ade.Molecule(name=xyz_filename, smiles=smiles)
  3. molecular.optimise(method=ade.methods.XTB())

  4. print(molecular.charge,molecular.mult)
  5. molecular.print_xyz_file()
复制代码
都可以保存一个xyz文件

19

帖子

0

威望

29

eV
积分
48

Level 2 能力者

12#
 楼主 Author| 发表于 Post on 2025-5-29 19:23:39 | 只看该作者 Only view this author
Loading0760 发表于 2025-5-29 17:28
代码部分其实很好实现,假设你的两个变量一个是smiles,一个是xyz文件的名称
用autodE的话功能更多
都可 ...
  1. def generate_molecule_hash(smiles):
  2.     """
  3.     生成分子SMILES的哈希值,用于避免重复生成相同分子的XYZ文件
  4.     """
  5.     return hashlib.md5(smiles.encode('utf-8')).hexdigest()[:8]

  6. def mol_to_xyz_with_smiles(mol, file_path, smiles=None, molecule_type=None):
  7.     """
  8.     将rdkit分子对象写为xyz文件,并在文件头部添加SMILES注释和分子类型信息。
  9.    
  10.     参数:
  11.         mol: RDKit Mol对象
  12.         file_path: 输出文件路径
  13.         smiles: SMILES字符串(用于备注)
  14.         molecule_type: 分子类型(Lipid, Probe或Product)
  15.     """
  16.     try:
  17.         # 检查输入分子是否有效
  18.         if mol is None:
  19.             raise ValueError("输入分子对象为空")
  20.             
  21.         # 确保分子有氢原子
  22.         mol = Chem.AddHs(mol)
  23.         
  24.         # 检查并生成3D坐标
  25.         conf = None
  26.         conformer_error = None
  27.         
  28.         # 步骤1: 尝试获取现有构象
  29.         try:
  30.             conf = mol.GetConformer()
  31.             if not conf.Is3D():
  32.                 print(f"警告: 分子已有构象但不是3D构象,将尝试生成3D坐标")
  33.                 conformer_error = "现有构象不是3D"
  34.                 conf = None
  35.         except Exception as e:
  36.             print(f"信息: 分子没有现有构象 ({str(e)}),将尝试生成3D坐标")
  37.             conformer_error = str(e)
  38.             conf = None
  39.         
  40.         # 步骤2: 如果没有有效构象,尝试ETKDG方法生成(更高级的构象生成方法)
  41.         if conf is None:
  42.             try:
  43.                 print(f"尝试使用ETKDG方法为分子生成3D构象...")
  44.                 AllChem.EmbedMolecule(mol, AllChem.ETKDG())
  45.                 AllChem.UFFOptimizeMolecule(mol)
  46.                 conf = mol.GetConformer()
  47.                 if not conf.Is3D():
  48.                     raise ValueError("ETKDG方法生成的构象不是3D")
  49.                 print(f"ETKDG方法成功生成3D构象")
  50.             except Exception as e:
  51.                 print(f"ETKDG方法失败: {str(e)},尝试基本嵌入方法...")
  52.                 conformer_error = f"{conformer_error} -> ETKDG失败: {str(e)}"
  53.         
  54.         # 步骤3: 如果ETKDG失败,尝试基本的嵌入方法
  55.         if conf is None or not conf.Is3D():
  56.             try:
  57.                 print(f"尝试使用基本嵌入方法生成3D构象...")
  58.                 # 先清除所有构象
  59.                 while mol.GetNumConformers() > 0:
  60.                     mol.RemoveConformer(0)
  61.                
  62.                 # 尝试多次随机种子
  63.                 for seed in [42, 123, 987, 555]:
  64.                     ps = AllChem.ETKDGv3()
  65.                     ps.randomSeed = seed
  66.                     cid = AllChem.EmbedMolecule(mol, ps)
  67.                     if cid >= 0:  # 成功嵌入
  68.                         conf = mol.GetConformer(cid)
  69.                         if conf.Is3D():
  70.                             print(f"基本嵌入方法在种子{seed}下成功")
  71.                             # 优化构象
  72.                             AllChem.UFFOptimizeMolecule(mol, confId=cid)
  73.                             break
  74.                
  75.                 if conf is None or not conf.Is3D():
  76.                     raise ValueError("多次尝试后仍无法生成有效的3D构象")
  77.             except Exception as e:
  78.                 print(f"所有嵌入方法均失败: {str(e)}")
  79.                 conformer_error = f"{conformer_error} -> 基本嵌入失败: {str(e)}"
  80.                 raise ValueError(f"无法生成3D构象: {conformer_error}")
  81.         
  82.         # 确认我们有有效的3D构象
  83.         if conf is None or not conf.Is3D():
  84.             raise ValueError("尝试所有方法后仍无法获得有效的3D构象")
  85.             
  86.         # 写入XYZ文件
  87.         with open(file_path, 'w') as f:
  88.             f.write(f"{mol.GetNumAtoms()}\n")
  89.             comments = []
  90.             if molecule_type:
  91.                 comments.append(f"Type: {molecule_type}")
  92.             if smiles:
  93.                 comments.append(f"SMILES: {smiles}")
  94.             f.write(f"{' | '.join(comments)}\n")
  95.             
  96.             for atom in mol.GetAtoms():
  97.                 pos = conf.GetAtomPosition(atom.GetIdx())
  98.                 f.write(f"{atom.GetSymbol()} {pos.x:.6f} {pos.y:.6f} {pos.z:.6f}\n")
  99.         
  100.         return True
  101.     except Exception as e:
  102.         print(f"警告: 无法将分子转换为XYZ格式: {e}")
  103.         return False

  104. def smiles_to_xyz(smiles, file_path, molecule_type=None):
  105.     """
  106.     从SMILES生成XYZ文件(备用方法)
  107.     """
  108.     if not smiles:
  109.         return False
  110.    
  111.     try:
  112.         mol = Chem.MolFromSmiles(smiles)
  113.         if mol is None:
  114.             raise ValueError("无效的SMILES字符串")
  115.         
  116.         return mol_to_xyz_with_smiles(mol, file_path, smiles, molecule_type)
  117.     except Exception as e:
  118.         print(f"警告: 无法从SMILES生成XYZ文件: {e}")
  119.         return False

  120. def safe_write_xyz(mol, smiles, filename, output_dir, molecule_type):
  121.     """
  122.     安全地生成XYZ文件,优先使用RDKit Mol对象,失败时尝试使用SMILES
  123.    
  124.     返回:
  125.         tuple: (文件名, 成功状态, 使用的方法)
  126.     """
  127.     file_path = os.path.join(output_dir, filename)
  128.    
  129.     # 检查文件是否已存在
  130.     if os.path.exists(file_path):
  131.         return filename, True, "existing"
  132.    
  133.     # 尝试使用RDKit Mol对象生成XYZ
  134.     if mol is not None:
  135.         success = mol_to_xyz_with_smiles(mol, file_path, smiles, molecule_type)
  136.         if success:
  137.             return filename, True, "mol"
  138.    
  139.     # 如果Mol对象失败或不存在,尝试使用SMILES
  140.     if smiles:
  141.         success = smiles_to_xyz(smiles, file_path, molecule_type)
  142.         if success:
  143.             return filename, True, "smiles"
  144.    
  145.     # 如果都失败了,返回失败信息
  146.     return filename, False, "failed"
复制代码
这个是我原先写的,利用您的第三方的代码,适合放在我的代码的哪部分呢?出现失败的smile是带这TCO的结构,如CCCOCOC1CC/C=C\CCC1

465

帖子

1

威望

2318

eV
积分
2803

Level 5 (御坂)

13#
发表于 Post on 2025-5-30 11:35:05 | 只看该作者 Only view this author
之前搞一些纯有机的分子的时候试过Open Babel和RDKit,当时处理一些小分子时没感觉到差别,但分子较大时(如一些天然产物),发现Open Babel比RDKit容易出问题。

目前对于纯有机的分子批量生成构象,我都是用RDKit中的ETKDG v3,这个功能是RDKit 2020.03开始有的。

以下是一段简单的代码供参考,其功能是利用RDKit从SMILES字符串生成xyz文件,仅适用于纯有机的体系。
  1. '''
  2. This script generates xyz files from a SMILES string. This script requires
  3. RDKit which should be at least version 2020.03. Cite the following paper
  4. if you use this script in any published work.
  5. S. Wang, J. Witek, G. A. Landrum, S. Riniker, J. Chem. Inf. Model. 2020, 60(4), 2044–2058

  6. Generate one conformer for a molecule with the following command:
  7.   python smiles2xyz.py -s "CC(CC1=CC=CC=C1)[N+]2=NOC(=C2)/N=C(/NC3=CC=CC=C3)\[O-]" -c mesocarb
  8. Generate ten conformers for a molecule with the following command:
  9.   python smiles2xyz.py -s "CC(CC1=CC=CC=C1)[N+]2=NOC(=C2)/N=C(/NC3=CC=CC=C3)\[O-]" -c mesocarb -n 10
  10. '''

  11. import sys
  12. import argparse
  13. from rdkit import Chem
  14. from rdkit.Chem import AllChem

  15. def write_xyz_file(fragment, fragment_name):
  16.     number_of_atoms = fragment.GetNumAtoms()
  17.     symbols = [a.GetSymbol() for a in fragment.GetAtoms()]
  18.     fNames = []
  19.     for i,conf in enumerate(fragment.GetConformers()):
  20.         file_name = fragment_name+"_"+str(i)+".xyz"
  21.         fNames.append(file_name)
  22.         with open(file_name, "w") as file:
  23.             file.write(str(number_of_atoms)+"\n")
  24.             file.write("\n")
  25.             for atom,symbol in enumerate(symbols):
  26.                 p = conf.GetAtomPosition(atom)
  27.                 line = " ".join((symbol,str(p.x),str(p.y),str(p.z),"\n"))
  28.                 file.write(line)
  29.     return fNames

  30. parser = argparse.ArgumentParser(usage=__doc__)
  31. parser.add_argument('--string', '-s', required=True, type=str, help='SMILES string')
  32. parser.add_argument('--compound', '-c', required=True, type=str, help='Compound name, which will be used as the prefix for xyz file')
  33. parser.add_argument('--number', '-n', default=argparse.SUPPRESS, type=int, help='Number of conformers for a compound')
  34. args = parser.parse_args()

  35. mol = Chem.MolFromSmiles(args.string)
  36. mol_h = Chem.AddHs(mol)

  37. params = Chem.rdDistGeom.srETKDGv3()
  38. params.randomSeed = 0xf00d
  39. params.clearConfs = True
  40. if 'number' in args:
  41.     if args.number > 0:
  42.         number_of_conformers = args.number
  43.     else:
  44.         print("The argument for number of conformers in the input cannot be used.")
  45.         sys.exit(1)
  46. else:
  47.     number_of_conformers = 1
  48. cids = AllChem.EmbedMultipleConfs(mol_h, number_of_conformers, params)
  49. fn = write_xyz_file(mol_h, args.compound)
复制代码


19

帖子

0

威望

29

eV
积分
48

Level 2 能力者

14#
 楼主 Author| 发表于 Post on 2025-5-31 09:09:05 | 只看该作者 Only view this author
Daniel_Arndt 发表于 2025-5-30 11:35
之前搞一些纯有机的分子的时候试过Open Babel和RDKit,当时处理一些小分子时没感觉到差别,但分子较大时( ...

好的,坐标问题其实针对脂质可能不一定好解决。如果分子变大。另外自旋多重度和电荷,如果是针对大批量工作,你有什么好办法吗?

19

帖子

0

威望

29

eV
积分
48

Level 2 能力者

15#
 楼主 Author| 发表于 Post on 2025-6-4 09:32:10 | 只看该作者 Only view this author
Daniel_Arndt 发表于 2025-5-30 11:35
之前搞一些纯有机的分子的时候试过Open Babel和RDKit,当时处理一些小分子时没感觉到差别,但分子较大时( ...

pip show rdkit
Name: rdkit
Version: 2024.9.6
Summary: A collection of chemoinformatics and machine-learning software written in C++ and Python
Home-page: https://github.com/kuelumbus/rdkit-pypi
Author: Christopher Kuenneth
Author-email: chris@kuenneth.dev
License: BSD-3-Clause
Location: c:\programdata\anaconda3\envs\chemagent\lib\site-packages
Requires: numpy, Pillow
Required-by: deepchem, scikit-mol 这个是我现在用的版本。我想如果是批量设计,流程是不是先用这个生成xyz坐标,然后自己设置电荷和自旋多重度。最后输入回去生成高斯坐标?

本版积分规则 Credits rule

手机版 Mobile version|北京科音自然科学研究中心 Beijing Kein Research Center for Natural Sciences|京公网安备 11010502035419号|计算化学公社 — 北京科音旗下高水平计算化学交流论坛 ( 京ICP备14038949号-1 )|网站地图

GMT+8, 2025-8-12 15:18 , Processed in 0.527053 second(s), 21 queries , Gzip On.

快速回复 返回顶部 返回列表 Return to list