Spaces:
Sleeping
Sleeping
from rdkit.Chem.rdmolfiles import MolToPDBBlock, MolToPDBFile | |
import rdkit.Chem | |
from rdkit import Geometry | |
from collections import defaultdict | |
import copy | |
import numpy as np | |
import torch | |
class PDBFile: | |
def __init__(self, mol): | |
self.parts = defaultdict(dict) | |
self.mol = copy.deepcopy(mol) | |
[self.mol.RemoveConformer(j) for j in range(mol.GetNumConformers()) if j] | |
def add(self, coords, order, part=0, repeat=1): | |
if type(coords) in [rdkit.Chem.Mol, rdkit.Chem.RWMol]: | |
block = MolToPDBBlock(coords).split('\n')[:-2] | |
self.parts[part][order] = {'block': block, 'repeat': repeat} | |
return | |
elif type(coords) is np.ndarray: | |
coords = coords.astype(np.float64) | |
elif type(coords) is torch.Tensor: | |
coords = coords.double().numpy() | |
for i in range(coords.shape[0]): | |
self.mol.GetConformer(0).SetAtomPosition(i, Geometry.Point3D(coords[i, 0], coords[i, 1], coords[i, 2])) | |
block = MolToPDBBlock(self.mol).split('\n')[:-2] | |
self.parts[part][order] = {'block': block, 'repeat': repeat} | |
def write(self, path=None, limit_parts=None): | |
is_first = True | |
str_ = '' | |
for part in sorted(self.parts.keys()): | |
if limit_parts and part >= limit_parts: | |
break | |
part = self.parts[part] | |
keys_positive = sorted(filter(lambda x: x >=0, part.keys())) | |
keys_negative = sorted(filter(lambda x: x < 0, part.keys())) | |
keys = list(keys_positive) + list(keys_negative) | |
for key in keys: | |
block = part[key]['block'] | |
times = part[key]['repeat'] | |
for _ in range(times): | |
if not is_first: | |
block = [line for line in block if 'CONECT' not in line] | |
is_first = False | |
str_ += 'MODEL\n' | |
str_ += '\n'.join(block) | |
str_ += '\nENDMDL\n' | |
if not path: | |
return str_ | |
with open(path, 'w') as f: | |
f.write(str_) |