hydrogen interaction formula + turns and bridges first implementation

master
Thomas Forest 2019-09-13 19:09:15 +02:00
parent 488dfa74a1
commit e80fdb57ab
4 changed files with 147 additions and 33 deletions

View File

@ -1,4 +1,12 @@
import math
class Atom: class Atom:
def dist_atoms(self, atom2):
return(math.sqrt((self.coord_x-atom2.coord_x)**2 +
(self.coord_y-atom2.coord_y)**2 +
(self.coord_z-atom2.coord_z)**2))
def __init__(self, atom_id, atom_name, res_name, chain_id, def __init__(self, atom_id, atom_name, res_name, chain_id,
res_seq_nb, coordinates): res_seq_nb, coordinates):
self.atom_id = atom_id self.atom_id = atom_id
@ -15,5 +23,31 @@ class Residue:
self.atoms = {} self.atoms = {}
for atom in atoms_list: for atom in atoms_list:
self.atoms[atom.atom_name] = atom self.atoms[atom.atom_name] = atom
self.resid = atom.res_seq_nb
self.res_name = atom.res_name
self.chain_id = atom.chain_id
def h_bond(self, res2):
if("H" not in res2.atoms.keys()):
return(False)
# elementary charge in Coulomb
#e = 1.602176634 * 10*math.exp(-19)
# dimensionnal factor f
f = 332
q1 = 0.42
q2 = 0.20
# r, distance between O-N atoms, in angströms
r_ON = self.atoms["O"].dist_atoms(res2.atoms["N"])
# r, distance between C-H atoms, in angströms
r_CH = self.atoms["C"].dist_atoms(res2.atoms["H"])
# r, distance between O-H atoms, in angströms
r_OH = self.atoms["O"].dist_atoms(res2.atoms["H"])
# r, distance between C-N atoms, in angströms
r_CN = self.atoms["C"].dist_atoms(res2.atoms["N"])
# Electrostatic interaction energy, in kcal/mole
E = q1*q2*(1/r_ON + 1/r_CH - 1/r_OH - 1/r_CN)*f
if(E<-0.5):
return(True)
else:
return(False)

18
src/dssp.py Normal file
View File

@ -0,0 +1,18 @@
import pdb
import atom
import sys
from structure import *
if(len(sys.argv)<2):
print("Not enough arguments! Run with --help to learn more about proper"
"call structure and parameters.")
else:
pdb_file = pdb.PDBFile(sys.argv[1])
# print(pdb_file.residues[15].atoms["C"].coord_x)
#print(pdb_file.residues[2].atoms["N"].res_seq_nb, pdb_file.residues[2].atoms["N"].coord_x, pdb_file.residues[2].atoms["N"].coord_y, pdb_file.residues[2].atoms["N"].coord_z)
#print(pdb_file.residues[2].atoms["H"].coord_x)
#print(pdb_file.residues[2].h_bond(pdb_file.residues[40]))
#print(get_turns(pdb_file.residues))
#print(pdb_file.residues[27].h_bond(pdb_file.residues[28]))
get_bridges(pdb_file.residues)

View File

@ -1,33 +1,33 @@
# custom imports # custom imports
from atom import * from atom import *
# import libs
import sys import sys
import pymol import pymol
#import collections
class PDBFile: class PDBFile:
def getContent(self, filename): def get_content(self, filename):
with open(filename) as f: with open(filename) as f:
return(f.readlines()) return(f.readlines())
def getHeader(self): def get_header(self):
#Metadata = collections.namedtuple("Metadata", ["header", "compound", "source", "author"]) metadata = {}
Metadata = {}
for line in self.rawLines: for line in self.rawLines:
# no need to continue if meta are complete # no need to continue if meta are complete
if(len(Metadata) <4): if(len(metadata) <4):
if(line[0:10] == "HEADER "): if(line[0:10] == "HEADER "):
Metadata['header']=line metadata['header']=line
elif(line[0:10] == "COMPND 2"): elif(line[0:10] == "COMPND 2"):
Metadata['compound']=line metadata['compound']=line
elif(line[0:10] == "SOURCE 2"): elif(line[0:10] == "SOURCE 2"):
Metadata['source']=line metadata['source']=line
elif(line[0:10] == "AUTHOR "): elif(line[0:10] == "AUTHOR "):
Metadata['author']=line metadata['author']=line
else: else:
# if meta are complete, stop parsing # if meta are complete, stop parsing
break break
return(Metadata) return(metadata)
def getAtoms(self, filename): def get_atoms(self, filename):
self.atoms = [] self.atoms = []
self.residues = [] self.residues = []
temp_atoms = [] temp_atoms = []
@ -56,10 +56,12 @@ class PDBFile:
temp_atoms.append(atom) temp_atoms.append(atom)
# last residue # last residue
self.residues.append(Residue(temp_atoms)) self.residues.append(Residue(temp_atoms))
# hydrogens should represent in average 50% of total atoms... We use 30% threshold... # hydrogens should represent in average 50% of total atoms...
# We use 30% threshold...
if(count_h/len(temp_atoms)<0.30): if(count_h/len(temp_atoms)<0.30):
#if(output_pdb==None): #if(output_pdb==None):
print("Need to add hydrogens ! If you want the modified PDB file, please use the -o output.pdb argument") print("Need to add hydrogens ! If you want the modified PDB file, "
"please use the -o output.pdb argument")
self.add_hydrogens(filename) self.add_hydrogens(filename)
def check_hydrogens(self, atoms): def check_hydrogens(self, atoms):
@ -71,25 +73,36 @@ class PDBFile:
pymol.cmd.load(filename) pymol.cmd.load(filename)
pymol.cmd.select("nitrogens",'name n') pymol.cmd.select("nitrogens",'name n')
pymol.cmd.h_add("nitrogens") pymol.cmd.h_add("nitrogens")
pymol.stored.pos = [] pymol.stored.pos = {}
pymol.cmd.iterate_state(1, "hydrogens", 'stored.pos.append([name,resi,x,y,z])') pymol.cmd.iterate_state(1, "hydrogens",
'stored.pos[resi] = []; ' \
'stored.pos[resi].append(name,resi,x,y,z) '\
'if resi not in stored.pos.keys() ' \
'else ' \
'stored.pos[resi].append([name,resi,x,y,z])')
if(output_pdb!=None): if(output_pdb!=None):
pymol.cmd.save(output_file) pymol.cmd.save(output_file)
for resi in self.residues:
if(str(resi.resid) in pymol.stored.pos.keys()):
# iterate over residue H atoms
for hydrogen in pymol.stored.pos[str(resi.resid)]:
atom = Atom(atom_id = len(self.atoms)+1,
atom_name = "H",
res_name = resi.res_name,
chain_id = resi.chain_id,
res_seq_nb = resi.resid,
coordinates = [hydrogen[2],
hydrogen[3],
hydrogen[4]])
# add hydrogen to atoms list
self.atoms.append(atom)
resi.atoms[atom.atom_name] = atom
return(pymol.stored.pos) return(pymol.stored.pos)
def __init__(self, filename, output_pdb=None):
self.rawLines = self.getContent(filename)
self.Metadata = self.getHeader()
self.getAtoms(filename)
# for elem in self.Metadata :
# print(self.Metadata[elem], end="")
if __name__ == "__main__": def __init__(self, filename, output_pdb=None):
if(len(sys.argv)<2): self.rawLines = self.get_content(filename)
print("Not enough arguments! Run with --help to learn more about proper" self.metadata = self.get_header()
"call structure and parameters.") self.get_atoms(filename)
else: # for elem in self.metadata :
pdbFile = PDBFile(sys.argv[1]) # print(self.metadata[elem], end="")
print(pdbFile.residues[15].atoms["C"].coord_x)
print(pdbFile.add_hydrogens(sys.argv[1])[3])

49
src/structure.py Normal file
View File

@ -0,0 +1,49 @@
class Turn:
def __init__(self, turn_type):
self.turn_type = turn_type
class Bridge:
def __init__(self, bridge_type):
self.bridge_type = bridge_type
class Helix:
def __init__(self, residues):
self.residues = residues
def get_turns(residues):
turns = []
for i,res in enumerate(residues):
for j in range(3,6):
if(i+j<len(residues)):
if(res.h_bond(residues[i+j])):
turns.append(Turn(j))
return(turns)
def get_bridges(residues):
# TODO : non-overlaping check to add
bridges = []
for i,res in enumerate(residues):
for j, res in enumerate(residues):
if(i-1>=0 and i+1<len(residues)
and j-1>=0 and j+1<len(residues)):
if((residues[i-1].h_bond(residues[j])
and residues[j].h_bond(residues[i+1]))
or(residues[j-1].h_bond(residues[i])
and residues[i].h_bond(residues[j+1]))):
bridges.append(Bridge("para"))
if(i-1>=0 and i+1<len(residues)
and j-1>=0 and j+1<len(residues)):
if((residues[i].h_bond(residues[j])
and residues[j].h_bond(residues[i]))
or(residues[i-1].h_bond(residues[j+1])
and residues[j-1].h_bond(residues[i+1]))):
bridges.append(Bridge("anti"))
return(bridges)
def get_helix(turns):
pass