| 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_) |