Chainsaw / model /utils /secondary_structure.py
wuxing0105's picture
Upload folder using huggingface_hub
80a72c3 verified
Raw
History Blame Contribute Delete
3.92 kB
"""
Created by Jude Wells 2023-04-20
Objective is to create a secondary structure matrix for each protein
1) renumbers the pdb file (1-indexed)
2) runs stride to get secondary structure file
3) parses the secondary structure file to create a matrix of secondary structure
# should take around 3 minutes for 1000 structures
"""
import os
import re
import subprocess
import sys
import numpy as np
from model.constants import REPO_ROOT
import logging
LOG = logging.getLogger(__name__)
def calculate_ss(pdbfile, chain, stride_path, ssfile='pdb_ss'):
assert os.path.exists(pdbfile)
with open(ssfile, 'w') as ssout_file:
args = [stride_path, pdbfile, '-r' + chain]
LOG.info(f"Running command: {' '.join(args)}")
try:
subprocess.run(args,
stdout=ssout_file,
stderr=subprocess.DEVNULL,
check=True)
except subprocess.CalledProcessError as e:
LOG.warning(f"Stride failed on {pdbfile}, creating empty file")
pass
def make_ss_matrix(ss_path, nres):
# create matrices for helix and strad residues where entry ij = 1 if i and j are in the same helix or strand
with open(ss_path) as f:
lines = f.readlines()
type_set = set()
helix = np.zeros([nres, nres], dtype=np.float32)
strand = np.zeros([nres, nres], dtype=np.float32)
for line in lines:
if line.startswith('LOC'):
start = int(re.sub(r'\D', '', line[22:28].strip()))
end = int(re.sub(r'\D', '', line[40:46].strip()))
type = line[5:17].strip()
type_set.add(type)
if type in ['AlphaHelix', '310Helix']:
helix[start-1:end, start-1:end] = 1
elif type == 'Strand':
strand[start-1:end, start-1:end] = 1
elif line.startswith('ASG'):
break
return helix, strand
def renum_pdb_file(pdb_path, output_pdb_path):
pdb_reres_path = REPO_ROOT / 'model/utils/pdb_reres.py'
with open(output_pdb_path, "w") as output_file:
subprocess.run([sys.executable, str(pdb_reres_path), pdb_path],
stdout=output_file,
check=True,
text=True)
def main(chain_ids, pdb_dir, feature_dir, stride_path, reres_path, savedir, job_index=0):
os.makedirs(savedir, exist_ok=True)
os.makedirs(os.path.join(savedir, '2d_features'), exist_ok=True)
for chain_id in chain_ids:
try:
pdb_path = os.path.join(pdb_dir, chain_id + '.pdb')
if os.path.exists(pdb_path):
features = np.load(os.path.join(feature_dir, chain_id + '.npz'))['arr_0']
nres = features.shape[-1]
LOG.info("Processing", pdb_path)
chain = chain_id[4]
output_pdb_path = os.path.join(savedir, f"{job_index}.pdb") # this gets overwritten to save memory
file_nres = renum_pdb_file(pdb_path, reres_path, output_pdb_path)
if nres != file_nres:
with open(os.path.join(savedir, 'error.txt'), 'a') as f:
msg = f' residue number mismatch (from features) {nres}, (from pdb file) {file_nres}'
f.write(chain_id + msg + '\n')
ss_filepath = os.path.join(savedir, f'pdb_ss{job_index}.txt') # this gets overwritten to save memory
calculate_ss(output_pdb_path, chain, stride_path, ssfile=ss_filepath)
helix, strand = make_ss_matrix(ss_filepath, nres=nres)
np.savez_compressed(
os.path.join(*[savedir, '2d_features', chain_id + '.npz']),
np.stack((features, helix, strand), axis=0))
except Exception as e:
with open(os.path.join(savedir, 'error.txt'), 'a') as f:
f.write(chain_id + str(e) + '\n')