Réimplémentation du programme DSSP en Python

chem.py 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. import math
  2. from geom import *
  3. class Atom:
  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. def __init__(self, atom_id, atom_name, res_name, chain_id,
  9. res_seq_nb, insertion_code, coordinates):
  10. self.atom_id = atom_id
  11. self.atom_name = atom_name
  12. self.res_name = res_name
  13. self.chain_id = chain_id
  14. self.res_seq_nb = res_seq_nb
  15. self.insertion_code = insertion_code
  16. self.coord_x = coordinates[0]
  17. self.coord_y = coordinates[1]
  18. self.coord_z = coordinates[2]
  19. self.coords = coordinates
  20. class Structure:
  21. def __init__(self, res):
  22. self.res = res
  23. class Turn(Structure):
  24. def __init__(self, turn_type, res):
  25. self.turn_type = turn_type
  26. Structure.res = res
  27. class Bridge(Structure):
  28. def __init__(self, bridge_type, res_num, res_partner, indices):
  29. self.bridge_type = bridge_type
  30. self.res_num = res_num
  31. self.res_partner = res_partner
  32. Structure.res = res_num
  33. self.i = indices[0]
  34. self.j = indices[1]
  35. class Helix(Structure):
  36. def __init__(self, residues, res_num, helix_type):
  37. self.residues = residues
  38. self.res_num = res_num
  39. Structure.res = res_num
  40. self.helix_type = helix_type
  41. class Residue:
  42. def __init__(self, atoms_list, indice):
  43. self.atoms = {}
  44. for atom in atoms_list:
  45. self.atoms[atom.atom_name] = atom
  46. self.resid = atom.res_seq_nb
  47. self.res_name = atom.res_name
  48. self.res_letter = self.get_amino_letter(atom.res_name)
  49. self.chain_id = atom.chain_id
  50. self.insertion_code = atom.insertion_code
  51. self.indice = indice
  52. def get_amino_letter(self, res_name):
  53. code3 = ['ALA', 'ARG', 'ASN', 'ASP', 'CYS', 'GLU', 'GLN', 'GLY',
  54. 'HIS', 'ILE', 'LEU', 'LYS', 'MET', 'PHE', 'PRO', 'SER',
  55. 'THR', 'TRP', 'TYR', 'VAL']
  56. code1 = ['A','R','N','D','C','E','Q','G','H','I','L','K','M','F','P',
  57. 'S','T','W','Y','V']
  58. return code1[code3.index(res_name)]
  59. def h_bond(self, res2):
  60. if("H" not in res2.atoms.keys()):
  61. return(False)
  62. # dimensionnal factor, in kcal/mole
  63. f = 332
  64. # partial charges
  65. q1 = 0.42
  66. q2 = 0.20
  67. # distance between O-N atoms, in angströms
  68. r_ON = self.atoms["O"].dist_atoms(res2.atoms["N"])
  69. # distance between C-H atoms, in angströms
  70. r_CH = self.atoms["C"].dist_atoms(res2.atoms["H"])
  71. # distance between O-H atoms, in angströms
  72. r_OH = self.atoms["O"].dist_atoms(res2.atoms["H"])
  73. # distance between C-N atoms, in angströms
  74. r_CN = self.atoms["C"].dist_atoms(res2.atoms["N"])
  75. # electrostatic interaction energy, in kcal/mole
  76. E = q1*q2*(1/r_ON + 1/r_CH - 1/r_OH - 1/r_CN)*f
  77. return(E)
  78. def get_turns(self, residues):
  79. """
  80. Get all the turns from a specific residue.
  81. """
  82. turns = {}
  83. i = residues.index(self)
  84. k = 0
  85. for j in range(3,6):
  86. if(i+j<len(residues)):
  87. if(self.h_bond(residues[i+j])<-0.5):
  88. k = j
  89. if k != 0:
  90. return Turn(k,residues[i].resid)
  91. return False
  92. def get_bends(self, residues):
  93. i = residues.index(self)
  94. if i >=2 and i <len(residues)-2:
  95. angle = math.degrees(vector_angles(
  96. vectors_substr(position_vector(residues[i].atoms["CA"].coords),
  97. position_vector(residues[i-2].atoms["CA"].coords)),
  98. vectors_substr(position_vector(residues[i+2].atoms["CA"].coords),
  99. position_vector(residues[i].atoms["CA"].coords))))
  100. if(angle>70):
  101. return [angle, 'S']
  102. return [angle, '']
  103. else:
  104. return [360.0, '']
  105. def get_helix(self, residues):
  106. """
  107. Return if there is an helix at a given residue,
  108. as well as its type.
  109. """
  110. i = residues.index(self)
  111. # if there are no turns or it is the first residue, skip
  112. if i == 0:
  113. return False
  114. if(self.get_turns(residues) and residues[i-1].get_turns(residues)):
  115. return(self.get_turns(residues).turn_type, residues[i].indice)
  116. return(False)
  117. def get_ladder(self, residues):
  118. i = residues.index(self)
  119. if i != 0:
  120. if self.get_bridges(residues):
  121. if (residues[i-1].get_bridges(residues)):
  122. local_bridge = self.get_bridges(residues)
  123. consec_bridge = residues[i-1].get_bridges(residues)
  124. if local_bridge.bridge_type == consec_bridge.bridge_type:
  125. ladder = {'start':consec_bridge.res_num,
  126. 'end':local_bridge.res_num,
  127. 'bridges':[consec_bridge, local_bridge]}
  128. return ladder
  129. return False
  130. def get_tco(self, residues):
  131. i = residues.index(self)
  132. if(i!=0):
  133. res2 = residues[i-1]
  134. CO_res1 = vector_from_pos(self.atoms["C"].coords,
  135. self.atoms["O"].coords)
  136. CO_res2 = vector_from_pos(res2.atoms["C"].coords,
  137. res2.atoms["O"].coords)
  138. angle = vector_angles(CO_res1, CO_res2)
  139. else:
  140. angle = math.pi/2
  141. return(math.cos(angle))
  142. def get_chirality(self, residues):
  143. i = residues.index(self)
  144. if (i >=1 and i < len(residues)-2):
  145. chirality = {}
  146. angle = calc_dihedral(residues[i-1].atoms["CA"].coords,
  147. residues[i].atoms["CA"].coords,
  148. residues[i+1].atoms["CA"].coords,
  149. residues[i+2].atoms["CA"].coords)
  150. if(angle>0 and angle<=180):
  151. sign="+"
  152. if(angle<=0 and angle > -180):
  153. sign="-"
  154. else:
  155. angle = 360.0
  156. sign = ''
  157. return [angle, sign]
  158. def get_phi_psi(self, residues):
  159. i = residues.index(self)
  160. if(i==0):
  161. phi = 360.0
  162. else:
  163. phi = calc_dihedral(residues[i-1].atoms["C"].coords,
  164. residues[i].atoms["N"].coords,
  165. residues[i].atoms["CA"].coords,
  166. residues[i].atoms["C"].coords)
  167. if(i==len(residues)-1):
  168. psi = 360.0
  169. else:
  170. psi = calc_dihedral(residues[i].atoms["N"].coords,
  171. residues[i].atoms["CA"].coords,
  172. residues[i].atoms["C"].coords,
  173. residues[i+1].atoms["N"].coords)
  174. return((phi, psi))
  175. def get_bridges(residues):
  176. bridges = {}
  177. bridge = {}
  178. strongest_bridge = {}
  179. for i in range(1,len(residues)-4):
  180. E_min = 0
  181. for j in range(i+2,len(residues)-1):
  182. # select triplet with the minimal energy
  183. if(residues[i-1].h_bond(residues[j])<-0.5
  184. and residues[j].h_bond(residues[i+1])<-0.5):
  185. bridge = {'res1':residues[i-1].h_bond(residues[j]),
  186. 'res2':residues[j].h_bond(residues[i+1]),
  187. 'ipos':residues[i].resid,
  188. 'jpos':residues[j].resid,
  189. 'i':residues[i].indice,
  190. 'j':residues[j].indice,
  191. 'btype':"para"}
  192. if(residues[j-1].h_bond(residues[i])<-0.5
  193. and residues[i].h_bond(residues[j+1])<-0.5):
  194. bridge = {'res1':residues[j-1].h_bond(residues[i]),
  195. 'res2':residues[i].h_bond(residues[j+1]),
  196. 'ipos':residues[i].resid,
  197. 'jpos':residues[j].resid,
  198. 'i':residues[i].indice,
  199. 'j':residues[j].indice,
  200. 'btype':"para"}
  201. if(residues[i].h_bond(residues[j])<-0.5
  202. and residues[j].h_bond(residues[i])<-0.5):
  203. bridge = {'res1':residues[i].h_bond(residues[j]),
  204. 'res2':residues[j].h_bond(residues[i]),
  205. 'ipos':residues[i].resid,
  206. 'jpos':residues[j].resid,
  207. 'i':residues[i].indice,
  208. 'j':residues[j].indice,
  209. 'btype':"anti"}
  210. if(residues[i-1].h_bond(residues[j+1])<-0.5
  211. and residues[j-1].h_bond(residues[i+1])<-0.5):
  212. bridge = {'res1':residues[i-1].h_bond(residues[j+1]),
  213. 'res2':residues[j-1].h_bond(residues[i+1]),
  214. 'ipos':residues[i].resid,
  215. 'jpos':residues[j].resid,
  216. 'i':residues[i].indice,
  217. 'j':residues[j].indice,
  218. 'btype':"anti"}
  219. if(bridge):
  220. if(bridge['res1']+bridge['res2']<E_min):
  221. E_min = bridge['res1']+bridge['res2']
  222. strongest_bridge = bridge
  223. coord_bridge = [i,j]
  224. bridge = {}
  225. # finally add the strongest bridge at i and j pos
  226. if(strongest_bridge):
  227. bridges[strongest_bridge['i']] = (Bridge(strongest_bridge['btype'],
  228. strongest_bridge['ipos'],
  229. strongest_bridge['jpos'],
  230. [strongest_bridge['i'],
  231. strongest_bridge['j']]))
  232. bridges[strongest_bridge['j']] = (Bridge(strongest_bridge['btype'],
  233. strongest_bridge['ipos'],
  234. strongest_bridge['jpos'],
  235. [strongest_bridge['i'],
  236. strongest_bridge['j']]))
  237. if(len(bridges)>0):
  238. return(bridges)
  239. else:
  240. return(False)
  241. def get_ladders(bridges, residues):
  242. ladders = {}
  243. i = 1
  244. while i < len(residues):
  245. k = 1
  246. if i in bridges.keys():
  247. temp_bridges = [bridges[i]]
  248. while ((i+k in bridges.keys()) and
  249. (bridges[i].bridge_type == bridges[i+k].bridge_type)):
  250. temp_bridges.append(bridges[i+k])
  251. k+=1
  252. if k>1:
  253. ladders[i] = {'start':bridges[i].res_num,
  254. 'end':bridges[i+k-1].res_num,
  255. 'bridges':temp_bridges,
  256. 'i':i,
  257. 'j':i+k-1}
  258. i+=k-1
  259. else:
  260. i+=1
  261. return ladders
  262. def connected_ladders(ladd_1, ladd_2):
  263. links = []
  264. for bridge in ladd_1['bridges']:
  265. if bridge.res_partner in res_list(ladd_2):
  266. return ladd_2
  267. return False
  268. def get_sheets(ladders):
  269. """
  270. Bridges between ladders.
  271. Check if 1 bridge between one ladder and one or more other ladders.
  272. Iterate over all residues of one ladder and check if bridge with other residues
  273. of the other ladders.
  274. """
  275. ladds = [ elem for elem in ladders.values() ]
  276. sheets = {}
  277. corresp = {}
  278. for ladd1 in ladds:
  279. for ladd2 in ladds:
  280. if connected_ladders(ladd1, ladd2)!=False:
  281. corresp_list = [ elem for elem in corresp.keys() ]
  282. if ladd1['i'] not in corresp_list and ladd2['i'] not in corresp_list:
  283. ind = len(sheets.keys())
  284. sheets[ind] = []
  285. sheets[ind].append(ladd1)
  286. sheets[ind].append(ladd2)
  287. corresp[ladd1['i']] = ind
  288. corresp[ladd2['i']] = ind
  289. elif ladd2 not in corresp_list and ladd1 in corresp_list:
  290. sheets[corresp[ladd1['i']]].append(ladd2)
  291. corresp[ladd2['i']] = corresp[ladd1['i']]
  292. elif ladd1 not in corresp_list and ladd2 in corresp_list:
  293. sheets[corresp[ladd2['i']]].append(ladd1)
  294. corresp[ladd1['i']] = corresp[ladd2['i']]
  295. return sheets
  296. def res_list(ladder):
  297. l=[]
  298. for i in range(ladder['i'], ladder['j']):
  299. l.append(i)
  300. return(l)
  301. def build_turns_patterns(residues):
  302. turns_3 = {}
  303. turns_4 = {}
  304. turns_5 = {}
  305. for i,res in enumerate(residues):
  306. turn = residues[i].get_turns(residues)
  307. if(turn):
  308. for k in range(turn.turn_type):
  309. if turn.turn_type == 3:
  310. turns_3[i+1+k] = turn.turn_type
  311. if turn.turn_type == 4:
  312. turns_4[i+1+k] = turn.turn_type
  313. if turn.turn_type == 5:
  314. turns_5[i+1+k] = turn.turn_type
  315. return[turns_3, turns_4, turns_5]
  316. def build_helix_patterns(residues):
  317. helix_3 = {}
  318. helix_4 = {}
  319. helix_5 = {}
  320. for i,res in enumerate(residues):
  321. helix = residues[i].get_helix(residues)
  322. if(helix):
  323. helix_type = residues[i].get_helix(residues)[0]
  324. helix_pos = residues[i].get_helix(residues)[1]
  325. for k in range(helix_type):
  326. if helix_type == 3:
  327. helix_3[i+1+k] = "G"
  328. if helix_type == 4:
  329. helix_4[i+1+k] = "H"
  330. if helix_type == 5:
  331. helix_5[i+1+k] = "I"
  332. return[helix_3, helix_4, helix_5]
  333. def print_helix_pattern(residues, res, helix):
  334. i = residues.index(res)+1
  335. if i in helix.keys():
  336. return (helix[i])
  337. else:
  338. return(' ')
  339. def print_turn_pattern(residues, res, turns):
  340. i = residues.index(res)+1
  341. if i in turns.keys() and not i-1 in turns.keys():
  342. return(">")
  343. elif i in turns.keys() and i-1 in turns.keys():
  344. return(turns[i])
  345. elif i not in turns.keys() and i-1 in turns.keys():
  346. return("<")
  347. else:
  348. return(' ')
  349. def raw_ladders_print(ladders, ):
  350. for ladd1 in ladders:
  351. ladd_1 = ladders[ladd1]
  352. for ladd2 in ladders:
  353. ladd_2 = ladders[ladd2]
  354. for bridge in ladd_1['bridges']:
  355. if bridge.j in res_list(ladd_2):
  356. print("ladder", ladd_1['i'],"-", ladd_1['j'], "|",
  357. bridge.i, "...", bridge.j, "| ladder",
  358. ladd_2['i'], ladd_2['j'])