Réimplémentation du programme DSSP en Python

structure.py 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. import math
  2. import numpy as np
  3. class Structure:
  4. def __init__(self, res):
  5. self.res = res
  6. class Turn(Structure):
  7. def __init__(self, turn_type, res):
  8. self.turn_type = turn_type
  9. Structure.res = res
  10. class Bridge(Structure):
  11. def __init__(self, bridge_type, res_num, res_partner):
  12. self.bridge_type = bridge_type
  13. self.res_num = res_num
  14. self.res_partner = res_partner
  15. Structure.res = res_num
  16. class Helix(Structure):
  17. def __init__(self, residues, res_num):
  18. self.residues = residues
  19. self.res_num = res_num
  20. Structure.res = res_num
  21. def get_turns(residues):
  22. # TODO : prevent redondency of overlapping turns
  23. turns = {}
  24. for i,res in enumerate(residues):
  25. for j in range(3,6):
  26. if(i+j<len(residues)):
  27. if(res.h_bond(residues[i+j])<-0.5):
  28. print(j,"TURN", residues[i].resid, residues[i+j].resid)
  29. turns[i] = Turn(j,residues[i].resid)
  30. return(turns)
  31. def get_bridges(residues):
  32. bridges = {}
  33. bridge = {}
  34. strongest_bridge = {}
  35. for i in range(1,len(residues)-4):
  36. E_min = 0
  37. for j in range(i+2,len(residues)-1):
  38. # select triplet with the minimal energy
  39. if(residues[i-1].h_bond(residues[j])<-0.5
  40. and residues[j].h_bond(residues[i+1])<-0.5):
  41. bridge = {'res1':residues[i-1].h_bond(residues[j]),
  42. 'res2':residues[j].h_bond(residues[i+1]),
  43. 'ipos':residues[i].resid,
  44. 'jpos':residues[j].resid,
  45. 'btype':"para"}
  46. if(residues[j-1].h_bond(residues[i])<-0.5
  47. and residues[i].h_bond(residues[j+1])<-0.5):
  48. bridge = {'res1':residues[j-1].h_bond(residues[i]),
  49. 'res2':residues[i].h_bond(residues[j+1]),
  50. 'ipos':residues[i].resid,
  51. 'jpos':residues[j].resid,
  52. 'btype':"para"}
  53. if(residues[i].h_bond(residues[j])<-0.5
  54. and residues[j].h_bond(residues[i])<-0.5):
  55. bridge = {'res1':residues[i].h_bond(residues[j]),
  56. 'res2':residues[j].h_bond(residues[i]),
  57. 'ipos':residues[i].resid,
  58. 'jpos':residues[j].resid,
  59. 'btype':"anti"}
  60. if(residues[i-1].h_bond(residues[j+1])<-0.5
  61. and residues[j-1].h_bond(residues[i+1])<-0.5):
  62. bridge = {'res1':residues[i-1].h_bond(residues[j+1]),
  63. 'res2':residues[j-1].h_bond(residues[i+1]),
  64. 'ipos':residues[i].resid,
  65. 'jpos':residues[j].resid,
  66. 'btype':"anti"}
  67. if(bridge):
  68. if(bridge['res1']+bridge['res2']<E_min):
  69. E_min = bridge['res1']+bridge['res2']
  70. strongest_bridge = bridge
  71. bridge = {}
  72. # finally add the strongest bridge at i and j pos
  73. if(strongest_bridge):
  74. bridges[strongest_bridge['ipos']] = (Bridge(strongest_bridge['btype'],
  75. strongest_bridge['ipos'],
  76. strongest_bridge['jpos']))
  77. # bridges[strongest_bridge['jpos']] = (Bridge(strongest_bridge['btype'],
  78. # strongest_bridge['jpos'],
  79. # strongest_bridge['ipos']))
  80. if(len(bridges)>0):
  81. return(bridges)
  82. else:
  83. return(False)
  84. # def get_bonds(residues):
  85. # for i,res1 in enumerate(residues):
  86. # E_min = 0
  87. # strongest_bridge = []
  88. # for j in range(-5,6):
  89. # if(i+j < len(residues)):
  90. # res2 = residues[i+j]
  91. # if(res1.h_bond(res2)<-0.5) and (res1.h_bond(res2)<E_min):
  92. # E_min = res1.h_bond(res2)
  93. # strongest_bridge = [res1, res2]
  94. # if(len(strongest_bridge)>0):
  95. # diff = strongest_bridge[0].resid - strongest_bridge[1].resid
  96. # if( abs (diff) > 1 and abs(diff)<=5):
  97. # print(diff)
  98. def get_bonds(residues):
  99. bonds = {}
  100. k = 0
  101. for i,res in enumerate(residues):
  102. E_min = 0
  103. for j in range(-5,-2):
  104. if(i+j<len(residues)):
  105. if(residues[i+j].h_bond(res)<-0.5):
  106. k+=1
  107. #if(res.h_bond(residues[i+j])<E_min):
  108. E_min = res.h_bond(residues[i+j])
  109. res_a = res
  110. res_b = residues[i+j]
  111. if j not in bonds:
  112. bonds[j] = []
  113. bonds[j].append([res_a.resid, res_b.resid])
  114. #turns[residues[i].resid] = Turn(j,residues[i].resid)
  115. for key in bonds.keys():
  116. print(key, len(bonds[key]))
  117. print("LH",k)
  118. def get_helix(residues, turns):
  119. i = 1
  120. helix = []
  121. while i <= len(residues):
  122. if(i in turns.keys() and i-1 in turns.keys()):
  123. k = 0
  124. temp_res = []
  125. while(i+k in turns):
  126. k+=1
  127. temp_res.append(residues[i])
  128. if(k>2):
  129. print(k,"- HELIX at", residues[i].resid)
  130. helix.append(Helix(temp_res,residues[i].resid))
  131. i = i+k
  132. else:
  133. i+=1
  134. return(helix)
  135. def get_ladders(bridges):
  136. ladders = {}
  137. i = 1
  138. while i < len(bridges):
  139. k = 1
  140. if i in bridges.keys():
  141. temp_bridges = [bridges[i]]
  142. while ((i+k in bridges.keys()) and
  143. (bridges[i].bridge_type == bridges[i+k].bridge_type)):
  144. temp_bridges.append(bridges[i+k])
  145. k+=1
  146. if k>1:
  147. ladders[bridges[i].res_num] = k-1
  148. print("ladder", bridges[i].res_num, bridges[i+k-1].res_num)
  149. ladders[bridges[i].res_num] = {'start':bridges[i].res_num,
  150. 'end':bridges[i+k-1].res_num,
  151. 'bridges':temp_bridges}
  152. i+=k-1
  153. else:
  154. i+=1
  155. return ladders
  156. def get_sheets(ladders):
  157. """
  158. Bridges between ladders.
  159. Check if 1 bridge between one ladder and one or more other ladders.
  160. Iterate over all residues of one ladder and check if bridge with other residues
  161. of the other ladders.
  162. """
  163. for ladder in ladders:
  164. for bridge in ladders[ladder]['bridges']:
  165. for ladd2 in ladders:
  166. if bridge.res_partner in res_list(ladders[ladd2]):
  167. print("ladder",ladders[ladder]['start'], ladders[ladder]['end'],"bridge",bridge.res_num, bridge.res_partner,
  168. "ladder 2",ladders[ladd2]['start'], ladders[ladd2]['end'])
  169. def res_list(ladder):
  170. # TODO : method in ladder class
  171. l=[]
  172. for i in range(ladder['start'], ladder['end']):
  173. l.append(i)
  174. return(l)
  175. def get_bends(residues):
  176. bends = {}
  177. for i in range(2,len(residues)-2):
  178. angle = vector_angles(vectors_substr(position_vector(residues[i].atoms["CA"].coords),
  179. position_vector(residues[i-2].atoms["CA"].coords)),
  180. vectors_substr(position_vector(residues[i+2].atoms["CA"].coords),
  181. position_vector(residues[i].atoms["CA"].coords)))
  182. if(angle>70):
  183. print("angle", residues[i].resid, angle)
  184. bends[residues[i].resid] = angle
  185. return(bends)
  186. def vector_from_pos(a, b):
  187. xAB = b[0]-a[0]
  188. yAB = b[1]-a[1]
  189. zAB = b[2]-a[2]
  190. coord_AB = [xAB,yAB,zAB]
  191. return coord_AB
  192. def vector_norm(v):
  193. norm = math.sqrt(v[0]**2 + v[1]**2 + v[2]**2)
  194. return norm
  195. def dot_product(v1,v2):
  196. dot_product = v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]
  197. return(dot_product)
  198. def position_vector(c):
  199. vector = vector_from_pos([0,0,0],c)
  200. return vector
  201. def vectors_substr(v1, v2):
  202. return ([v1[0]-v2[0],
  203. v1[1]-v2[1],
  204. v1[2]-v2[2]])
  205. def vector_angles(v1,v2):
  206. dot_prod = dot_product(v1,v2)
  207. norm_v1 = vector_norm(v1)
  208. norm_v2 = vector_norm(v2)
  209. term = dot_prod/(abs(norm_v1)*abs(norm_v2))
  210. rad_angle = math.acos(term)
  211. deg_angle = rad_angle*(180/math.pi)
  212. return deg_angle
  213. def calc_dihedral(u1, u2, u3, u4):
  214. """ Calculate dihedral angle method. From bioPython.PDB
  215. (adapted to np.array)
  216. Calculate the dihedral angle between 4 vectors
  217. representing 4 connected points. The angle is in
  218. [-pi, pi].
  219. Adapted function of dihedral_angle_from_coordinates.py
  220. by Eric Alcaide.
  221. Source : https://gist.github.com/EricAlcaide
  222. URL : https://gist.github.com/EricAlcaide/30d6bfdb8358d3a57d010c9a501fda56
  223. """
  224. #convert coords to numpy arrays
  225. u1 = np.array(u1)
  226. u2 = np.array(u2)
  227. u3 = np.array(u3)
  228. u4 = np.array(u4)
  229. a1 = u2 - u1
  230. a2 = u3 - u2
  231. a3 = u4 - u3
  232. v1 = np.cross(a1, a2)
  233. v1 = v1 / (v1 * v1).sum(-1)**0.5
  234. v2 = np.cross(a2, a3)
  235. v2 = v2 / (v2 * v2).sum(-1)**0.5
  236. porm = np.sign((v1 * a3).sum(-1))
  237. rad = np.arccos((v1*v2).sum(-1) / ((v1**2).sum(-1) * (v2**2).sum(-1))**0.5)
  238. if not porm == 0:
  239. rad = rad * porm
  240. deg_angle = rad*(180/math.pi)
  241. return deg_angle
  242. def get_chirality(residues):
  243. for i in range(1,len(residues)-2):
  244. chirality = {}
  245. angle = calc_dihedral(residues[i-1].atoms["CA"].coords,
  246. residues[i].atoms["CA"].coords,
  247. residues[i+1].atoms["CA"].coords,
  248. residues[i+2].atoms["CA"].coords)
  249. if(angle>0 and angle<=180):
  250. sign="+"
  251. print("chirality", residues[i].resid, "+", angle)
  252. if(angle<=0 and angle > -180):
  253. sign="-"
  254. print("chirality", residues[i].resid, "-", angle)
  255. chirality[residues[i].resid] = sign
  256. return chirality