小分子 pdb准化为sdf

python 复制代码
import os
from rdkit import Chem
import subprocess


small_mol_path = "pdbs"

from rdkit.Chem import rdDetermineBonds

def load_pdb_with_adaptive_bonds(pdb_file):
    # ==========================================
    # STRATEGY 1: RDKit with Strict CONECT Rules
    # ==========================================
    # IMPORTANT: proximityBonding=False forces RDKit to ONLY use the CONECT block, 
    # preventing false bonds from compressed 3D coordinates.
    mol = Chem.MolFromPDBFile(pdb_file, removeHs=False, sanitize=False, proximityBonding=False)
    
    if mol is None:
        print(f"[{pdb_file}] Warning: Initial RDKit read failed.")
    else:
        mol.UpdatePropertyCache(strict=False)
        possible_charges = [0, 1, -1, 2, -2]
        
        for charge in possible_charges:
            try:
                mol_test = Chem.Mol(mol)
                rdDetermineBonds.DetermineBondOrders(mol_test, charge=charge)
                Chem.SanitizeMol(mol_test)
                # print(f"[{pdb_file}] Success via RDKit! Charge: {charge}")
                return mol_test
            except Exception:
                continue

    # ==========================================
    # STRATEGY 2: OpenBabel Fallback (Robust)
    # ==========================================
    # If RDKit's strict 3D geometry checker rejects the strained molecule,
    # fallback to OpenBabel's heuristic bond assigner.
    print(f"[{pdb_file}] RDKit bond determination failed with posssible_charges {possible_charges}. Falling back to OpenBabel...")
    
    base_name, ext = os.path.splitext(pdb_file)
    temp_mol2 = f"{base_name}_temp_ob.mol2"
    
    # Use OpenBabel to convert PDB to MOL2 (which hardcodes the bond orders)
    command = ["~/anaconda3/envs/UniMoMo/bin/obabel", pdb_file, "-O", temp_mol2]
    
    try:
        subprocess.run(command, check=True, capture_output=True)
        # Read the resulting MOL2 file back into RDKit
        fallback_mol = Chem.MolFromMol2File(temp_mol2, removeHs=False, sanitize=True)
        
        # Clean up temp file
        if os.path.exists(temp_mol2):
            os.remove(temp_mol2)
            
        if fallback_mol is not None:
            print(f"[{pdb_file}] Success via OpenBabel Fallback!")
            return fallback_mol
            
    except subprocess.CalledProcessError as e:
        print(f"[{pdb_file}] OpenBabel Fallback Error: {e.stderr.decode('utf-8')}")

    # If both strategies fail
    print(f"[{pdb_file}] CRITICAL: Could not process molecule via any method.")
    return None
        
def save_mol_to_sdf(mol, output_path):
    # Ensure the molecule object exists
    if mol is None:
        print("Molecule object is None, cannot save.")
        return
    
    # Create an SDWriter object
    writer = Chem.SDWriter(output_path)
    # Write the molecule to the file
    writer.write(mol)
    writer.close()
    # print(f"Successfully saved bond-complete molecule to {output_path}")    
python 复制代码
ligand_mol = load_pdb_with_adaptive_bonds("ligand_with_h.pdb")
save_mol_to_sdf(ligand_mol, "refined_ligand.sdf")
相关推荐
m0_6174939427 分钟前
Python OpenCV 透视变换(Perspective Transform)详解与实战
开发语言·python·opencv
小李不困还能学30 分钟前
PyCharm下载安装与配置教程
ide·python·pycharm
博观而约取厚积而薄发40 分钟前
Pytest 从入门到精通,一篇就够(超详细实战教程)
python·测试工具·单元测试·自动化·pytest
imzed1 小时前
使用 Playwright + Pytest 构建 Web UI 自动化测试框架
python·自动化·pytest
普通网友1 小时前
pytest一些常见的插件
开发语言·python·pytest
时空系1 小时前
Python 高性能高压缩打包器 —— 基于 JianPy 语义分析引擎
python
cndes1 小时前
给Miniconda换源,让包下载更迅速
开发语言·python
Metaphor6922 小时前
使用 Python 添加、隐藏和删除 PDF 图层
python·pdf·图层
丨白色风车丨2 小时前
【Python 计算机视觉】基于 Dlib+OpenCV 实现实时人眼疲劳检测(闭眼预警)
python·opencv·计算机视觉