Browse Source

hydrogen interaction formula + turns and bridges first implementation

Thomas Forest 4 years ago
parent
commit
e80fdb57ab
4 changed files with 146 additions and 32 deletions
  1. 34 0
      src/atom.py
  2. 18 0
      src/dssp.py
  3. 45 32
      src/pdb.py
  4. 49 0
      src/structure.py

+ 34 - 0
src/atom.py View File

@@ -1,4 +1,12 @@
1
+import math
1 2
 class Atom:
3
+
4
+    def dist_atoms(self, atom2):
5
+        return(math.sqrt((self.coord_x-atom2.coord_x)**2 +
6
+                         (self.coord_y-atom2.coord_y)**2 +
7
+                         (self.coord_z-atom2.coord_z)**2))
8
+
9
+
2 10
     def __init__(self, atom_id, atom_name, res_name, chain_id,
3 11
                  res_seq_nb, coordinates):
4 12
         self.atom_id = atom_id
@@ -15,5 +23,31 @@ class Residue:
15 23
         self.atoms = {}
16 24
         for atom in atoms_list:
17 25
             self.atoms[atom.atom_name] = atom
26
+            self.resid = atom.res_seq_nb
27
+            self.res_name = atom.res_name
28
+            self.chain_id = atom.chain_id
18 29
             
19 30
             
31
+    def h_bond(self, res2):
32
+        if("H" not in res2.atoms.keys()):
33
+            return(False)
34
+        # elementary charge in Coulomb
35
+        #e = 1.602176634 * 10*math.exp(-19)
36
+        # dimensionnal factor f
37
+        f = 332
38
+        q1 = 0.42
39
+        q2 = 0.20
40
+        # r, distance between O-N atoms, in angströms
41
+        r_ON = self.atoms["O"].dist_atoms(res2.atoms["N"])
42
+        # r, distance between C-H atoms, in angströms
43
+        r_CH = self.atoms["C"].dist_atoms(res2.atoms["H"])
44
+        # r, distance between O-H atoms, in angströms
45
+        r_OH = self.atoms["O"].dist_atoms(res2.atoms["H"])
46
+        # r, distance between C-N atoms, in angströms
47
+        r_CN = self.atoms["C"].dist_atoms(res2.atoms["N"])
48
+        # Electrostatic interaction energy, in kcal/mole
49
+        E = q1*q2*(1/r_ON + 1/r_CH - 1/r_OH - 1/r_CN)*f
50
+        if(E<-0.5):
51
+            return(True)
52
+        else:
53
+            return(False)

+ 18 - 0
src/dssp.py View File

@@ -0,0 +1,18 @@
1
+import pdb
2
+import atom
3
+import sys
4
+from structure import *
5
+
6
+if(len(sys.argv)<2):
7
+    print("Not enough arguments! Run with --help to learn more about proper"
8
+          "call structure and parameters.")
9
+else:
10
+    pdb_file = pdb.PDBFile(sys.argv[1])
11
+   # print(pdb_file.residues[15].atoms["C"].coord_x)
12
+    #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)
13
+    #print(pdb_file.residues[2].atoms["H"].coord_x)
14
+    #print(pdb_file.residues[2].h_bond(pdb_file.residues[40]))
15
+    #print(get_turns(pdb_file.residues))
16
+    #print(pdb_file.residues[27].h_bond(pdb_file.residues[28]))
17
+    get_bridges(pdb_file.residues)
18
+

+ 45 - 32
src/pdb.py View File

@@ -1,33 +1,33 @@
1 1
 # custom imports
2 2
 from atom import *
3
+# import libs
3 4
 import sys
4
-import pymol 
5
-#import collections
5
+import pymol
6
+
6 7
 class PDBFile:
7
-    def getContent(self, filename):
8
+    def get_content(self, filename):
8 9
         with open(filename) as f:
9 10
             return(f.readlines())
10 11
         
11
-    def getHeader(self):
12
-        #Metadata = collections.namedtuple("Metadata", ["header", "compound", "source", "author"])
13
-        Metadata = {}
12
+    def get_header(self):
13
+        metadata = {}
14 14
         for line in self.rawLines:
15 15
             # no need to continue if meta are complete
16
-            if(len(Metadata) <4):
16
+            if(len(metadata) <4):
17 17
                 if(line[0:10] == "HEADER    "):
18
-                    Metadata['header']=line
18
+                    metadata['header']=line
19 19
                 elif(line[0:10] == "COMPND   2"):
20
-                    Metadata['compound']=line
20
+                    metadata['compound']=line
21 21
                 elif(line[0:10] == "SOURCE   2"):
22
-                    Metadata['source']=line
22
+                    metadata['source']=line
23 23
                 elif(line[0:10] == "AUTHOR    "):
24
-                    Metadata['author']=line
24
+                    metadata['author']=line
25 25
             else:
26 26
                 # if meta are complete, stop parsing
27 27
                 break     
28
-        return(Metadata)
28
+        return(metadata)
29 29
 
30
-    def getAtoms(self, filename):
30
+    def get_atoms(self, filename):
31 31
         self.atoms = []
32 32
         self.residues = []
33 33
         temp_atoms = []
@@ -56,10 +56,12 @@ class PDBFile:
56 56
                 temp_atoms.append(atom)
57 57
         # last residue
58 58
         self.residues.append(Residue(temp_atoms))
59
-        # hydrogens should represent in average 50% of total atoms... We use 30% threshold...
59
+        # hydrogens should represent in average 50% of total atoms...
60
+        # We use 30% threshold...
60 61
         if(count_h/len(temp_atoms)<0.30):
61 62
             #if(output_pdb==None):
62
-            print("Need to add hydrogens ! If you want the modified PDB file, please use the -o output.pdb argument")
63
+            print("Need to add hydrogens ! If you want the modified PDB file, " 
64
+                  "please use the -o output.pdb argument")
63 65
             self.add_hydrogens(filename)
64 66
 
65 67
     def check_hydrogens(self, atoms):
@@ -71,25 +73,36 @@ class PDBFile:
71 73
         pymol.cmd.load(filename)
72 74
         pymol.cmd.select("nitrogens",'name n')  
73 75
         pymol.cmd.h_add("nitrogens")
74
-        pymol.stored.pos = []
75
-        pymol.cmd.iterate_state(1, "hydrogens", 'stored.pos.append([name,resi,x,y,z])')
76
+        pymol.stored.pos = {}
77
+        pymol.cmd.iterate_state(1, "hydrogens",
78
+                                'stored.pos[resi] = []; ' \
79
+                                'stored.pos[resi].append(name,resi,x,y,z) '\
80
+                                'if resi not in stored.pos.keys() ' \
81
+                                'else ' \
82
+                                'stored.pos[resi].append([name,resi,x,y,z])')
76 83
         if(output_pdb!=None):
77 84
             pymol.cmd.save(output_file)
85
+        for resi in self.residues:
86
+            if(str(resi.resid) in pymol.stored.pos.keys()):
87
+                # iterate over residue H atoms
88
+                for hydrogen in pymol.stored.pos[str(resi.resid)]:
89
+                    atom = Atom(atom_id = len(self.atoms)+1,
90
+                                atom_name = "H", 
91
+                                res_name = resi.res_name,
92
+                                chain_id = resi.chain_id,
93
+                                res_seq_nb = resi.resid,
94
+                                coordinates = [hydrogen[2],
95
+                                               hydrogen[3],
96
+                                               hydrogen[4]])
97
+                    # add hydrogen to atoms list
98
+                    self.atoms.append(atom)
99
+                    resi.atoms[atom.atom_name] = atom
78 100
         return(pymol.stored.pos)
79
-        
101
+
80 102
     def __init__(self, filename, output_pdb=None):
81
-        self.rawLines = self.getContent(filename)
82
-        self.Metadata = self.getHeader()
83
-        self.getAtoms(filename)
84
-        # for elem in self.Metadata : 
85
-        #     print(self.Metadata[elem], end="")
103
+        self.rawLines = self.get_content(filename)
104
+        self.metadata = self.get_header()
105
+        self.get_atoms(filename)
106
+        # for elem in self.metadata : 
107
+        #     print(self.metadata[elem], end="")
86 108
         
87
-
88
-if __name__ == "__main__":
89
-    if(len(sys.argv)<2):
90
-        print("Not enough arguments! Run with --help to learn more about proper"
91
-              "call structure and parameters.")
92
-    else:
93
-        pdbFile = PDBFile(sys.argv[1])
94
-        print(pdbFile.residues[15].atoms["C"].coord_x)
95
-        print(pdbFile.add_hydrogens(sys.argv[1])[3])

+ 49 - 0
src/structure.py View File

@@ -0,0 +1,49 @@
1
+
2
+class Turn:
3
+
4
+    def __init__(self, turn_type):
5
+        self.turn_type = turn_type
6
+                        
7
+class Bridge:
8
+
9
+    def __init__(self, bridge_type):
10
+        self.bridge_type = bridge_type
11
+
12
+class Helix:
13
+
14
+    def __init__(self, residues):
15
+        self.residues = residues
16
+        
17
+def get_turns(residues):
18
+    turns = []
19
+    for i,res in enumerate(residues):
20
+        for j in range(3,6):
21
+            if(i+j<len(residues)):
22
+                if(res.h_bond(residues[i+j])):
23
+                    turns.append(Turn(j))
24
+    return(turns)
25
+
26
+def get_bridges(residues):
27
+    # TODO : non-overlaping check to add
28
+    bridges = []
29
+    for i,res in enumerate(residues):
30
+        for j, res in enumerate(residues):
31
+            if(i-1>=0 and i+1<len(residues)
32
+               and j-1>=0 and j+1<len(residues)):
33
+                if((residues[i-1].h_bond(residues[j])
34
+                    and residues[j].h_bond(residues[i+1]))
35
+                   or(residues[j-1].h_bond(residues[i])
36
+                      and residues[i].h_bond(residues[j+1]))):
37
+                    bridges.append(Bridge("para"))
38
+                    
39
+            if(i-1>=0 and i+1<len(residues)
40
+               and j-1>=0 and j+1<len(residues)):
41
+                if((residues[i].h_bond(residues[j])
42
+                    and residues[j].h_bond(residues[i]))
43
+                   or(residues[i-1].h_bond(residues[j+1])
44
+                      and residues[j-1].h_bond(residues[i+1]))):
45
+                    bridges.append(Bridge("anti"))
46
+    return(bridges)
47
+
48
+def get_helix(turns):
49
+    pass