Réimplémentation du programme DSSP en Python

structure.py 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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. coord_bridge = [i,j]
  73. # finally add the strongest bridge at i and j pos
  74. if(strongest_bridge):
  75. bridges[coord_bridge[0]] = (Bridge(strongest_bridge['btype'],
  76. strongest_bridge['ipos'],
  77. strongest_bridge['jpos']))
  78. bridges[coord_bridge[1]] = (Bridge(strongest_bridge['btype'],
  79. strongest_bridge['jpos'],
  80. strongest_bridge['ipos']))
  81. if(len(bridges)>0):
  82. return(bridges)
  83. else:
  84. return(False)
  85. # def get_bonds(residues):
  86. # for i,res1 in enumerate(residues):
  87. # E_min = 0
  88. # strongest_bridge = []
  89. # for j in range(-5,6):
  90. # if(i+j < len(residues)):
  91. # res2 = residues[i+j]
  92. # if(res1.h_bond(res2)<-0.5) and (res1.h_bond(res2)<E_min):
  93. # E_min = res1.h_bond(res2)
  94. # strongest_bridge = [res1, res2]
  95. # if(len(strongest_bridge)>0):
  96. # diff = strongest_bridge[0].resid - strongest_bridge[1].resid
  97. # if( abs (diff) > 1 and abs(diff)<=5):
  98. # print(diff)
  99. def get_bonds(residues):
  100. bonds = {}
  101. k = 0
  102. for i,res in enumerate(residues):
  103. E_min = 0
  104. for j in range(-5,-2):
  105. if(i+j<len(residues)):
  106. if(residues[i+j].h_bond(res)<-0.5):
  107. k+=1
  108. #if(res.h_bond(residues[i+j])<E_min):
  109. E_min = res.h_bond(residues[i+j])
  110. res_a = res
  111. res_b = residues[i+j]
  112. if j not in bonds:
  113. bonds[j] = []
  114. bonds[j].append([res_a.resid, res_b.resid])
  115. #turns[residues[i].resid] = Turn(j,residues[i].resid)
  116. for key in bonds.keys():
  117. print(key, len(bonds[key]))
  118. print("LH",k)
  119. def get_helix(residues, turns):
  120. i = 1
  121. helix = []
  122. while i <= len(residues):
  123. if(i in turns.keys() and i-1 in turns.keys()):
  124. k = 0
  125. temp_res = []
  126. while(i+k in turns):
  127. k+=1
  128. temp_res.append(residues[i])
  129. if(k>=1):
  130. print(k,"- HELIX at", residues[i].resid)
  131. helix.append(Helix(temp_res,residues[i].resid))
  132. i = i+k
  133. else:
  134. i+=1
  135. return(helix)
  136. def get_ladders(bridges, residues):
  137. ladders = {}
  138. i = 1
  139. while i < len(residues):
  140. k = 1
  141. if i in bridges.keys():
  142. temp_bridges = [bridges[i]]
  143. while ((i+k in bridges.keys()) and
  144. (bridges[i].bridge_type == bridges[i+k].bridge_type)):
  145. temp_bridges.append(bridges[i+k])
  146. k+=1
  147. if k>1:
  148. ladders[i] = k-1
  149. print("ladder", bridges[i].res_num, bridges[i+k-1].res_num)
  150. ladders[i] = {'start':bridges[i].res_num,
  151. 'end':bridges[i+k-1].res_num,
  152. 'bridges':temp_bridges}
  153. i+=k-1
  154. else:
  155. i+=1
  156. return ladders
  157. def get_sheets(ladders):
  158. """
  159. Bridges between ladders.
  160. Check if 1 bridge between one ladder and one or more other ladders.
  161. Iterate over all residues of one ladder and check if bridge with other residues
  162. of the other ladders.
  163. """
  164. sheets = {}
  165. for ladder in ladders:
  166. for ladd2 in ladders:
  167. for bridge in ladders[ladder]['bridges']:
  168. if bridge.res_partner in res_list(ladders[ladd2]):
  169. print("ladder",ladders[ladder]['start'], ladders[ladder]['end'],"bridge",bridge.res_num, bridge.res_partner,
  170. "ladder 2",ladders[ladd2]['start'], ladders[ladd2]['end'])
  171. #print("stop ladder 2")
  172. print("stop ladder 1")
  173. def res_list(ladder):
  174. # TODO : method in ladder class
  175. l=[]
  176. for i in range(ladder['start'], ladder['end']):
  177. l.append(i)
  178. return(l)
  179. def get_bends(residues):
  180. bends = {}
  181. for i in range(2,len(residues)-2):
  182. angle = vector_angles(vectors_substr(position_vector(residues[i].atoms["CA"].coords),
  183. position_vector(residues[i-2].atoms["CA"].coords)),
  184. vectors_substr(position_vector(residues[i+2].atoms["CA"].coords),
  185. position_vector(residues[i].atoms["CA"].coords)))
  186. if(angle>70):
  187. print("angle", residues[i].resid, angle)
  188. bends[residues[i].resid] = angle
  189. return(bends)
  190. def vector_from_pos(a, b):
  191. xAB = b[0]-a[0]
  192. yAB = b[1]-a[1]
  193. zAB = b[2]-a[2]
  194. coord_AB = [xAB,yAB,zAB]
  195. return coord_AB
  196. def vector_norm(v):
  197. norm = math.sqrt(v[0]**2 + v[1]**2 + v[2]**2)
  198. return norm
  199. def dot_product(v1,v2):
  200. dot_product = v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]
  201. return(dot_product)
  202. def position_vector(c):
  203. vector = vector_from_pos([0,0,0],c)
  204. return vector
  205. def vectors_substr(v1, v2):
  206. return ([v1[0]-v2[0],
  207. v1[1]-v2[1],
  208. v1[2]-v2[2]])
  209. def vector_angles(v1,v2):
  210. dot_prod = dot_product(v1,v2)
  211. norm_v1 = vector_norm(v1)
  212. norm_v2 = vector_norm(v2)
  213. term = dot_prod/(abs(norm_v1)*abs(norm_v2))
  214. rad_angle = math.acos(term)
  215. deg_angle = rad_angle*(180/math.pi)
  216. return deg_angle
  217. def calc_dihedral(u1, u2, u3, u4):
  218. """ Calculate dihedral angle method. From bioPython.PDB
  219. (adapted to np.array)
  220. Calculate the dihedral angle between 4 vectors
  221. representing 4 connected points. The angle is in
  222. [-pi, pi].
  223. Adapted function of dihedral_angle_from_coordinates.py
  224. by Eric Alcaide.
  225. Source : https://gist.github.com/EricAlcaide
  226. URL : https://gist.github.com/EricAlcaide/30d6bfdb8358d3a57d010c9a501fda56
  227. """
  228. #convert coords to numpy arrays
  229. u1 = np.array(u1)
  230. u2 = np.array(u2)
  231. u3 = np.array(u3)
  232. u4 = np.array(u4)
  233. a1 = u2 - u1
  234. a2 = u3 - u2
  235. a3 = u4 - u3
  236. v1 = np.cross(a1, a2)
  237. v1 = v1 / (v1 * v1).sum(-1)**0.5
  238. v2 = np.cross(a2, a3)
  239. v2 = v2 / (v2 * v2).sum(-1)**0.5
  240. porm = np.sign((v1 * a3).sum(-1))
  241. rad = np.arccos((v1*v2).sum(-1) / ((v1**2).sum(-1) * (v2**2).sum(-1))**0.5)
  242. if not porm == 0:
  243. rad = rad * porm
  244. deg_angle = rad*(180/math.pi)
  245. return deg_angle
  246. def get_chirality(residues):
  247. for i in range(1,len(residues)-2):
  248. chirality = {}
  249. angle = calc_dihedral(residues[i-1].atoms["CA"].coords,
  250. residues[i].atoms["CA"].coords,
  251. residues[i+1].atoms["CA"].coords,
  252. residues[i+2].atoms["CA"].coords)
  253. if(angle>0 and angle<=180):
  254. sign="+"
  255. print("chirality", residues[i].resid, "+", angle)
  256. if(angle<=0 and angle > -180):
  257. sign="-"
  258. print("chirality", residues[i].resid, "-", angle)
  259. chirality[residues[i].resid] = sign
  260. return chirality