Metadata-Version: 2.4
Name: pdblib
Version: 2.1.0
Summary: A simple Python package to manipulate PDB files
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: numpy
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"

# pdblib 使用说明

**版本**: 2.1
**作者**: Yi Xue (Skrynnikov's group @ Purdue University, Tsinghua University)
**更新日期**: 2022-11-15

---

## 目录

1. [简介](#1-简介)
2. [安装与依赖](#2-安装与依赖)
3. [核心类](#3-核心类)
   - [Atom 类](#atom-类)
   - [Residue 类](#residue-类)
   - [Segment 类](#segment-类)
   - [Mol 类](#mol-类)
   - [Pdb 类](#pdb-类)
   - [Axis 类](#axis-类)
4. [几何计算函数](#4-几何计算函数)
5. [坐标操作函数](#5-坐标操作函数)
6. [原子选择](#6-原子选择)
7. [文件读写](#7-文件读写)
8. [实用示例](#8-实用示例)

---

## 1. 简介

`pdblib` 是一个简洁的 Python 包，用于操作 PDB（蛋白质数据库）文件。它提供了：

- 读取和写入 PDB、CIF、PDBQT、PQR 格式文件
- 分子结构的层次化表示（Pdb → Mol → Segment → Residue → Atom）
- 原子选择和过滤
- 几何计算（距离、角度、二面角）
- 坐标变换（平移、旋转、重定向）
- 结构对齐（最小二乘拟合）

---

## 2. 安装与依赖

### 依赖项

- **必需**: 无（基础版本 `base.py` 无外部依赖）
- **可选**: NumPy（启用高级功能如旋转、对齐等）

### 导入方式

```python
# 方式1：直接导入（自动检测 NumPy）
from codelib.pdblib import *

# 方式2：显式导入 NumPy 版本
from codelib.pdblib.num import *

# 方式3：基础版本（无 NumPy）
from codelib.pdblib.base import *
```

---

## 3. 核心类

### Atom 类

表示分子中的一个原子。

#### 属性

| 属性 | 类型 | 说明 |
|------|------|------|
| `name` | str | 原子名称（如 'CA', 'H1'） |
| `atid` | int | 原子序号 |
| `resn` | str | 残基名称（如 'ALA', 'GLY'） |
| `resi` | int | 残基序号 |
| `r` | tuple | 坐标 (x, y, z) |
| `elem` | str | 元素符号（如 'C', 'H', 'O'） |
| `chid` | str | 链标识符 |
| `sgid` | str | 片段标识符 |
| `loc` | str | 位置指示符 |
| `oc` | float | 占据率 |
| `bf` | float | 温度因子 |

#### 方法

```python
atom = Atom()
atom.name = 'CA'
atom.r = (10.0, 20.0, 30.0)

# 获取原子类型（取名称首字符）
atom_type = atom.gettype()  # 'C'

# 显示原子信息
atom.show()
```

---

### Residue 类

表示一个残基（氨基酸或核苷酸）。

#### 属性

| 属性 | 类型 | 说明 |
|------|------|------|
| `name` | str | 残基名称 |
| `resi` | int | 残基序号 |
| `atoms` | list | 原子列表 |

#### 方法

```python
# 创建残基
res = Residue(atom_list)

# 获取指定名称的原子
ca = res.getat('CA')  # 返回 CA 原子，不存在则返回 None

# 获取残基标签（如 'A.ALA123'）
tag = res.gettag()

# 显示残基信息
res.show(fmt='s')  # fmt: 's' 简洁格式, 'd' 详细格式

# 同步原子属性
res.atsync()

# 移除指定原子
res.rmats('@H*')  # 移除所有氢原子
```

---

### Segment 类

表示一个片段（通常是蛋白质链）。

#### 属性

| 属性 | 类型 | 说明 |
|------|------|------|
| `sgid` | str | 片段标识符 |
| `chid` | str | 链标识符 |
| `reses` | list | 残基列表 |
| `nter` | bool | 是否为 N 端 |
| `cter` | bool | 是否为 C 端 |

#### 方法

```python
seg = Segment()

# 获取所有原子
atoms = seg.getats()

# 获取残基索引
idx = seg.getindex(123)  # 返回残基序号 123 的索引

# 获取序列（单字母代码）
seq = seg.seq(fmt='s')  # 如 'MKFLILLFNILCLFPVLAADNH'

# 重新编号
seg.renumber(iat=1, ires=1)  # 从 1 开始编号

# 显示片段信息
seg.show()
```

---

### Mol 类

表示一个分子/模型。

#### 构造函数

```python
# 从文件读取
mol = Mol('protein.pdb')

# 空分子
mol = Mol()

# 从片段创建
mol = Mol(segment)
```

#### 方法

```python
# 读取文件
mol.read('protein.pdb')
mol.read('structure.cif', fmt='cif')

# 写入文件
mol.write('output.pdb')
mol.write('output.cif', fmt='cif')

# 获取所有原子
atoms = mol.getats()

# 获取所有残基
residues = mol.getreses()

# 同步原子属性
mol.atsync()

# 重新编号
mol.renumber(iat=1, ires=1)

# 检查兼容性（序号是否在 PDB 格式范围内）
if mol.compatible():
    print("兼容标准 PDB 格式")

# 显示分子信息
mol.show()
```

---

### Pdb 类

表示一个完整的 PDB 文件（可包含多个模型）。

#### 构造函数

```python
pdb = Pdb('multi_model.pdb')
```

#### 方法

```python
# 访问模型
model1 = pdb.mds[0]  # 第一个模型（Mol 对象）

# 读取文件
pdb.read('trajectory.pdb')

# 写入文件
pdb.write('output.pdb')

# 获取所有原子
atoms = pdb.getats()

# 获取所有残基
residues = pdb.getreses()

# 重新编号所有模型
pdb.renumber(iat=1, ires=1)

# 显示 PDB 信息
pdb.show()
```

---

### Axis 类

预定义的坐标轴对象。

```python
from pdblib.num import Ax

# 坐标原点
Ax.o  # array([0., 0., 0.])

# 坐标轴方向向量
Ax.x  # array([1., 0., 0.])  X轴
Ax.y  # array([0., 1., 0.])  Y轴
Ax.z  # array([0., 0., 1.])  Z轴
```

---

## 4. 几何计算函数

### dist() - 距离计算

计算两个原子或坐标点之间的距离。

```python
# 原子间距离
d = dist(atom1, atom2)

# 坐标点间距离
d = dist((0, 0, 0), (1, 1, 1))

# 两组原子间的距离矩阵
D = groupdist(atoms1, atoms2)  # 返回 NxM 矩阵
```

### angle() - 角度计算

计算由三个原子形成的角度（弧度）。

```python
# 计算角度 a1-a2-a3
ang = angle(atom1, atom2, atom3)
ang = angle((0, 0, 0), (1, 0, 0), (1, 1, 0))  # π/2

# 转换为度
import math
ang_deg = ang * 180 / math.pi
```

### dihe() - 二面角计算

计算由四个原子形成的二面角（弧度）。

```python
# 计算二面角 a1-a2-a3-a4
phi = dihe(atom1, atom2, atom3, atom4)

# 计算 φ 二面角（主链）
phi = dihe(mol.getat(i, 'N'), mol.getat(i, 'CA'),
           mol.getat(i, 'C'), mol.getat(i+1, 'N'))

# 计算 ψ 二面角
psi = dihe(mol.getat(i-1, 'C'), mol.getat(i, 'N'),
           mol.getat(i, 'CA'), mol.getat(i, 'C'))
```

### com() - 质心计算

计算一组原子的几何中心。

```python
# 计算分子质心
center = com(mol)  # 返回 array([x, y, z])

# 计算残基质心
center = com(residue)

# 计算原子列表质心
center = com(atom_list)
```

### inertia() - 惯性主轴

计算分子的惯性主轴。

```python
# 返回特征值和特征向量
eigvals, eigvecs = inertia(mol)

# eigvals: 三个惯性值（从大到小排序）
# eigvecs: 对应的特征向量（3x3 矩阵）
```

### vect() - 向量计算

计算两个原子间的向量。

```python
v = vect(atom1, atom2)  # atom2.r - atom1.r
v = vect((0, 0, 0), (1, 2, 3))  # array([1, 2, 3])
```

---

## 5. 坐标操作函数

### translate() - 平移

将分子沿指定向量平移。

```python
# 将 mol 从 atom1 平移到 atom2
translate(mol, atom1, atom2)

# 将 mol 平移到原点
translate(mol, com(mol), (0, 0, 0))

# 使用坐标点
translate(mol, (0, 0, 0), (10, 10, 10))
```

### rotate() - 旋转

围绕指定轴旋转分子。

```python
# 围绕 Z 轴旋转 90 度
rotate(mol, Ax.o, Ax.z, math.pi/2)

# 围绕原子连线旋转
rotate(mol, atom1, atom2, math.pi/4)  # 旋转 45 度

# 旋转单个残基
rotate(residue, (0, 0, 0), (1, 0, 0), math.pi)
```

### reorient() - 重定向

将分子重定向，使其向量与参考向量对齐。

```python
# 将 mol 的向量 a1-a0 对齐到 b1-b0
reorient(mol, a0, a1, b0, b1)

# 示例：将螺旋轴对齐到 Z 轴
reorient(helix, start_atom, end_atom, (0, 0, 0), (0, 0, 1))
```

### align() - 结构对齐

将一个结构叠加到另一个结构上（最小二乘拟合）。

```python
# 使用原子掩码对齐
rmsd, info = align(mol1, mol0, ':1-100@CA')  # 用 CA 原子对齐

# 使用不同的掩码
rmsd, info = align(mol1, mol0, ':1-50@CA,C,O,N', ':51-100@CA,C,O,N')

# 计算对齐后的 RMSD
rmsd, (ats1, ats0, out_ats1, out_ats0) = align(
    mol1, mol0,
    ':1-100@CA',      # 用于对齐的原子
    outmask1=':101-150@CA'  # 计算 RMSD 的原子
)

print(f"RMSD: {rmsd:.3f} Å")
```

### join() - 片段连接

连接两个片段。

```python
# 将 seg2 连接到 seg1
# resi1: seg1 中连接点的残基序号
# resi2: seg2 中连接点的残基序号
join(seg1, resi1, seg2, resi2)
```

---

## 6. 原子选择

### selats() - 选择原子

使用掩码语法选择原子。

```python
# 选择残基 1-100 的 CA 原子
atoms = selats(mol, ':1-100@CA')

# 选择多个残基范围和原子
atoms = selats(mol, ':1-10,20,30@CA,C,O,N')

# 选择特定残基的所有原子
atoms = selats(mol, ':1-100')

# 选择特定原子名称
atoms = selats(mol, '@CA,CB')

# 使用通配符
atoms = selats(mol, '@H*')   # 所有以 H 开头的原子
atoms = selats(mol, '@C*')   # 所有以 C 开头的原子

# 显示详细信息
atoms = selats(mol, ':1-10@CA', verbose=2)
```

### 原子掩码语法

```
:残基范围@原子名称

残基范围: 1-10,20,30-40
原子名称: CA,C,O,N 或 H* (通配符)
```

| 示例 | 说明 |
|------|------|
| `:1-100@CA` | 残基 1-100 的 CA 原子 |
| `:1-10,20,30@CA,C,O` | 多个残基的多个原子 |
| `@CA` | 所有 CA 原子 |
| `:1-100` | 残基 1-100 的所有原子 |
| `@H*` | 所有氢原子 |

---

## 7. 文件读写

### 支持的格式

| 格式 | 扩展名 | 说明 |
|------|--------|------|
| PDB | .pdb | 标准 PDB 格式 |
| mmCIF | .cif | mmCIF 格式 |
| PDBQT | .pdbqt | AutoDock 格式 |
| PQR | .pqr | PQR 格式 |

### 读取文件

```python
# 读取单模型 PDB
mol = Mol('protein.pdb')

# 读取多模型 PDB
pdb = Pdb('trajectory.pdb')
for mol in pdb.mds:
    print(f"模型 {mol.mdid}: {len(mol.getats())} 原子")

# 读取 CIF 文件
mol = Mol()
mol.read('structure.cif', fmt='cif')
```

### 写入文件

```python
# 写入 PDB
mol.write('output.pdb')

# 自定义头部
mol.write('output.pdb', header=['REMARK My custom header\n'])

# 不自动同步原子属性
mol.write('output.pdb', sync=False)
```

---

## 8. 实用示例

### 示例 1: 读取并修改 PDB 文件

```python
from codelib.pdblib import *

# 读取 PDB 文件
mol = Mol('protein.pdb')

# 获取原子数量
print(f"原子数: {len(mol.getats())}")
print(f"残基数: {len(mol.getreses())}")

# 修改残基名称
res = mol.getreses()[0]
res.name = 'ALA'
res.atsync()

# 写入新文件
mol.write('modified.pdb')
```

### 示例 2: 计算分子几何

```python
from codelib.pdblib import *
import math

mol = Mol('protein.pdb')

# 计算两个 CA 原子间的距离
ca1 = mol.getat(10, 'CA')
ca2 = mol.getat(20, 'CA')
print(f"CA10-CA20 距离: {dist(ca1, ca2):.2f} Å")

# 计算角度
n = mol.getat(10, 'N')
ca = mol.getat(10, 'CA')
c = mol.getat(10, 'C')
ang = angle(n, ca, c)
print(f"N-CA-C 角度: {ang*180/math.pi:.1f}°")

# 计算 φ 二面角
phi = dihe(
    mol.getat(10, 'N'),
    mol.getat(10, 'CA'),
    mol.getat(10, 'C'),
    mol.getat(11, 'N')
)
print(f"残基 10 的 φ: {phi*180/math.pi:.1f}°")
```

### 示例 3: 分子旋转

```python
from codelib.pdblib import *
import math

mol = Mol('molecule.pdb')

# 围绕原点的 Z 轴旋转 90 度
rotate(mol, Ax.o, Ax.z, math.pi/2)

# 围绕自定义轴旋转
axis_start = (0, 0, 0)
axis_end = (1, 1, 0)
rotate(mol, axis_start, axis_end, math.pi/4)

# 保存旋转后的分子
mol.write('rotated.pdb')
```

### 示例 4: 结构对齐

```python
from codelib.pdblib import *

# 读取两个结构
mol1 = Mol('structure1.pdb')
mol2 = Mol('structure2.pdb')

# 用 CA 原子对齐
rmsd, info = align(mol1, mol2, '@CA')
print(f"整体 RMSD: {rmsd:.3f} Å")

# 对齐后保存
mol1.write('aligned.pdb')
```

### 示例 5: 选择特定原子

```python
from codelib.pdblib import *

mol = Mol('protein.pdb')

# 选择活性位点原子
active_site = selats(mol, ':50-60@CA,CB')

# 选择疏水残基
hydrophobic = ['ALA', 'VAL', 'LEU', 'ILE', 'MET', 'PHE', 'TRP', 'PRO']
hydro_atoms = []
for res in mol.getreses():
    if res.name in hydrophobic:
        hydro_atoms.extend(res.atoms)

# 计算质心
center = com(active_site)
print(f"活性位点中心: ({center[0]:.2f}, {center[1]:.2f}, {center[2]:.2f})")
```

### 示例 6: 处理多模型 PDB

```python
from codelib.pdblib import *

pdb = Pdb('trajectory.pdb')

print(f"模型数: {len(pdb.mds)}")

# 分析每个模型
for mol in pdb.mds:
    ca_atoms = selats(mol, '@CA')
    print(f"模型 {mol.mdid}: 质心 = {com(mol)}")

# 写入新文件
pdb.write('processed.pdb')
```

---

## 附录: 常用残基缩写

### 氨基酸

| 三字母 | 单字母 | 名称 |
|--------|--------|------|
| ALA | A | 丙氨酸 |
| ARG | R | 精氨酸 |
| ASN | N | 天冬酰胺 |
| ASP | D | 天冬氨酸 |
| CYS | C | 半胱氨酸 |
| GLN | Q | 谷氨酰胺 |
| GLU | E | 谷氨酸 |
| GLY | G | 甘氨酸 |
| HIS | H | 组氨酸 |
| ILE | I | 异亮氨酸 |
| LEU | L | 亮氨酸 |
| LYS | K | 赖氨酸 |
| MET | M | 甲硫氨酸 |
| PHE | F | 苯丙氨酸 |
| PRO | P | 脯氨酸 |
| SER | S | 丝氨酸 |
| THR | T | 苏氨酸 |
| TRP | W | 色氨酸 |
| TYR | Y | 酪氨酸 |
| VAL | V | 缬氨酸 |

---

## 联系方式

如有问题或建议，请联系原作者 Yi Xue。

---

*文档生成日期: 2026-03-08*
