CG2AT-lite 0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
cg2at_lite/__init__.py ADDED
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,673 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import os, sys
4
+ import numpy as np
5
+ import itertools
6
+ import math
7
+ from scipy.spatial import cKDTree
8
+ import gen, g_var, at_mod_p, read_in, gro
9
+
10
+
11
+ ### sanity checking
12
+
13
+ def sanity_check_fragments(res, cg, sin_bead):
14
+ #### fetches bead and atom info from fragment database
15
+ location = gen.fragment_location(res)
16
+ residue, fragment_mass = get_atomistic(location, res)
17
+ atom_list = []
18
+ bead_list = []
19
+ for group in residue.values():
20
+ for bead in group:
21
+ bead_list.append(bead)
22
+ if not sin_bead:
23
+ for atom in group[bead]:
24
+ atom_list.append(atom)
25
+ else:
26
+ if bead == sin_bead:
27
+ for atom in group[bead]:
28
+ atom_list.append(atom)
29
+ return sorted(bead_list), atom_list
30
+
31
+ def sanity_check_atoms(atom_list, res):
32
+ #### checks atom order
33
+ for at_num in range(1, len(atom_list)+1):
34
+ if at_num not in atom_list:
35
+ sys.exit('atom number '+str(at_num)+' is missing from fragment library: '+res+'\n')
36
+
37
+ def sanity_check_beads(bead_list, cg, res):
38
+ #### checks if bead is in fragment library
39
+ bead_list_new=[]
40
+ for bead in cg:
41
+ if bead not in bead_list:
42
+ new_bead = bead[1:]+bead[0]
43
+ if new_bead in bead_list and new_bead not in cg:
44
+ pass
45
+ else:
46
+ sys.exit('The bead '+bead+' is missing from the fragment library: '+res+'\n')
47
+ bead_list_new.append(bead)
48
+ return bead_list_new
49
+
50
+ def sanity_check_protein_other(res_type, test=False):
51
+ bead_list, atom_list = {},{}
52
+ for residue in g_var.cg_residues[res_type]:
53
+ for bead in g_var.cg_residues[res_type][residue]:
54
+ resname = g_var.cg_residues[res_type][residue][bead]['residue_name']
55
+ break
56
+ if resname not in bead_list or resname not in atom_list:
57
+ bead_list[resname], atom_list[resname] = sanity_check_fragments(resname, g_var.cg_residues[res_type][residue], False)
58
+ sanity_check_atoms(atom_list[resname], resname)
59
+ bead_list_cg = sanity_check_beads(bead_list[resname], g_var.cg_residues[res_type][residue], resname)
60
+ if bead_list[resname] != sorted(bead_list_cg):
61
+ if len(bead_list[resname]) == len(bead_list_cg):
62
+ fix_atom_wrap(bead_list[resname], bead_list_cg, res_type, residue)
63
+ else:
64
+ if not test:
65
+ print('There is a issue with residue: '+resname+' '+str(residue+1)+'. If expected ignore this message.' )
66
+ if res_type != 'OTHER':
67
+ sys.exit('number of atomistic fragments: '+str(len(bead_list[resname]))+' does not equal number of CG beads: '+str(len(bead_list_cg)))
68
+
69
+ def sanity_check_solvent(res_type):
70
+ bead_list, atom_list = {},{}
71
+ for residue in g_var.cg_residues[res_type]:
72
+ for bead in g_var.cg_residues[res_type][residue]:
73
+ sin_bead=bead
74
+ break
75
+ if sin_bead not in bead_list or sin_bead not in atom_list:
76
+ bead_list[sin_bead], atom_list[sin_bead] = sanity_check_fragments(res_type, g_var.cg_residues[res_type][residue], sin_bead)
77
+ sanity_check_atoms(atom_list[sin_bead], res_type)
78
+ sanity_check_beads(bead_list[sin_bead], g_var.cg_residues[res_type][residue], res_type)
79
+
80
+ def sanity_check_non_protein(res_type):
81
+ bead_list, atom_list = {},{}
82
+ if res_type not in bead_list or res_type not in atom_list:
83
+ bead_list[res_type], atom_list[res_type] = sanity_check_fragments(res_type, g_var.cg_residues[res_type], False)
84
+ sanity_check_atoms(atom_list[res_type], res_type)
85
+ for residue in g_var.cg_residues[res_type]:
86
+ bead_list_cg = sanity_check_beads(bead_list[res_type], g_var.cg_residues[res_type][residue], res_type)
87
+ if bead_list[res_type] != sorted(bead_list_cg):
88
+ if len(bead_list[res_type]) == len(bead_list_cg):
89
+ fix_atom_wrap(bead_list[res_type], bead_list_cg, res_type, residue)
90
+ else:
91
+ print('There is a issue with residue: '+res_type+' '+str(residue+1))
92
+ sys.exit('number of atomistic fragments: '+str(len(bead_list[res_type]))+' does not equal number of CG beads: '+str(len(bead_list_cg)))
93
+
94
+ def sanity_check():
95
+ #### runs through every bead and checks whether it exists
96
+ for res_type in g_var.cg_residues:
97
+ if res_type in ['PROTEIN', 'OTHER']:
98
+ sanity_check_protein_other(res_type)
99
+ elif res_type in g_var.sol_residues or res_type in g_var.ion_residues:
100
+ sanity_check_solvent(res_type)
101
+ else:
102
+ sanity_check_non_protein(res_type)
103
+
104
+ def fix_atom_wrap(bead_list_frag, bead_list_cg, section, resid):
105
+ for bead in bead_list_cg:
106
+ if bead not in bead_list_frag:
107
+ new_bead = bead[1:]+bead[0]
108
+ if new_bead in bead_list_frag and new_bead not in bead_list_cg:
109
+ g_var.cg_residues[section][resid][new_bead] = g_var.cg_residues[section][resid][bead]
110
+ del g_var.cg_residues[section][resid][bead]
111
+ else:
112
+ print('There is a issue with residue: '+section+' '+str(resid+1))
113
+ print('input file list:\n',sorted(bead_list_cg))
114
+ print('\ncannot find: '+bead+' or '+new_bead+' in fragment list:')
115
+ sys.exit(sorted(bead_list_frag))
116
+
117
+ ##### Sanity check end
118
+
119
+ #### rotations section
120
+
121
+ def rotate_atom(coord, center,xyz_rot_apply):
122
+ #### rotates atom around center
123
+ coord = coord-center #### centers COM coordinates to 0,0,0
124
+ if np.any(xyz_rot_apply):
125
+ coord=np.array(coord).dot(xyz_rot_apply)
126
+ coord = coord+center #### translates coord back by original offset
127
+ return coord
128
+
129
+ def kabsch_rotate(at_connections,cg_connections):
130
+ ## A solution for the best rotation to relate two sets of vectors. By WOLFGANG KABSCH
131
+ ## http://en.wikipedia.org/wiki/Kabsch_algorithm
132
+ Cov_mat = np.dot(np.transpose(at_connections), cg_connections)
133
+ V, S, W = np.linalg.svd(Cov_mat)
134
+ reflection = np.linalg.det(V) * np.linalg.det(W)
135
+ if reflection < 0:
136
+ S[-1] = -S[-1]
137
+ V[:, -1] = -V[:, -1]
138
+ rot_mat = np.dot(V, W)
139
+ return rot_mat
140
+
141
+ ## rotations end
142
+ ## alignments
143
+
144
+ def find_cross_vector(ca):
145
+ #### finds cross vector of the atoms CA, CA+1, CA+2
146
+ AB = ca[0]-ca[1]
147
+ AC = ca[0]-ca[2]
148
+ cross_vector = np.cross(AB, AC)
149
+ cross_vector = cross_vector/np.linalg.norm(cross_vector)
150
+ return cross_vector
151
+
152
+ def noramlised_vector(c1, c2):
153
+ initial_vector= c1-c2
154
+ initial_vector = initial_vector/np.linalg.norm(initial_vector)
155
+ return initial_vector
156
+
157
+
158
+ def align_to_vector(v1, v2):
159
+ #### returns the rotation matrix to rotate v1 to v2
160
+ v = np.cross(v1,v2)
161
+ c = np.dot(v1,v2)
162
+ s = np.linalg.norm(v)
163
+
164
+ rotation=np.array([[ 0, -v[2], v[1]],
165
+ [v[2], 0, -v[0]],
166
+ [-v[1], v[0], 0],
167
+ ])
168
+
169
+ r = np.identity(3) - rotation + np.matmul(rotation,rotation) * ((1 - c)/(s**2))
170
+ return r
171
+
172
+ def align_at_frag_to_CG_frag(at_com, cg_com, group):
173
+ #### aligns atomistic fragment to cg bead
174
+ COM_vector=at_com-cg_com ### gets vector between COM of atoms in fragment and cg bead
175
+ for bead in group:
176
+ for atom in group[bead]: ### runs through atoms in fragments and centers on the cg bead
177
+ group[bead][atom]['coord']=group[bead][atom]['coord']-COM_vector
178
+ return group, COM_vector
179
+
180
+ def COM(mass, fragment):
181
+ #### returns center of mass of fragment
182
+ try:
183
+ if np.any(np.array(mass)[:,3]):
184
+ return np.average(np.array(mass)[:,:3], axis=0, weights=np.array(mass)[:,3])
185
+ except:
186
+ for bead in fragment:
187
+ print(bead, fragment[bead], '\n')
188
+ print(mass)
189
+ sys.exit('missing the mass one of the atoms in '+fragment[bead][1]['res_type'])
190
+
191
+ def rigid_fit(group, frag_mass, resid, cg):
192
+ #### rigid fits group to CG beads
193
+ rigid_mass_at = []
194
+ rigid_mass_cg = []
195
+ for bead in group:
196
+ rigid_mass_at+=frag_mass[bead]
197
+ rigid_mass_cg.append(cg[bead]['coord'])
198
+ rigid_mass_at = COM(rigid_mass_at, group)
199
+ rigid_mass_cg = np.mean(rigid_mass_cg, axis=0)
200
+
201
+ group, COM_vector = align_at_frag_to_CG_frag(rigid_mass_at, rigid_mass_cg, group)
202
+ at_frag_centers = {}
203
+ cg_frag_centers = {}
204
+ for bead in group:
205
+ cg_frag_centers[bead] = cg[bead]['coord']
206
+ at_frag_centers[bead] = COM(frag_mass[bead], bead)
207
+ at_frag_centers[bead] -= COM_vector
208
+ rigid_mass_cg, at_frag_centers, cg_frag_centers, group
209
+ return rigid_mass_cg, at_frag_centers, cg_frag_centers, group
210
+
211
+ ## alignment end
212
+
213
+ ## overlap checker
214
+
215
+ def overlapping_atoms(tree):
216
+ overlapped_ndx = tree.query_ball_tree(tree, r=g_var.args.ov)
217
+ overlapped_cut = [ndx for ndx in overlapped_ndx if len(ndx) >1]
218
+ overlapped_cut.sort()
219
+ overlapped=list(overlapped_cut for overlapped_cut,_ in itertools.groupby(overlapped_cut))
220
+ return overlapped
221
+
222
+ def check_atom_overlap(coordinates):
223
+ #### creates tree of atom coordinates
224
+ tree = cKDTree(coordinates)
225
+ overlapped = overlapping_atoms(tree)
226
+ #### runs through overlapping atoms and moves atom in a random diection until it is no longer overlapping
227
+ while len(overlapped) > 0:
228
+ for ndx_val, ndx in enumerate(overlapped):
229
+ if np.round((ndx_val/len(overlapped))*100,2).is_integer() and len(overlapped) > 30:
230
+ print('fixing '+str(len(overlapped))+' overlapped atoms: '+str(np.round((ndx_val/len(overlapped))*100,2))+' %', end='\r')
231
+ xyz_check = np.array([coordinates[ndx[0]][0]+np.random.uniform(-0.2, 0.2), coordinates[ndx[0]][1]+np.random.uniform(-0.2, 0.2),coordinates[ndx[0]][2]+np.random.uniform(-0.2, 0.2)])
232
+ while len(tree.query_ball_point(xyz_check, r=g_var.args.ov)) > 1:
233
+ xyz_check = np.array([coordinates[ndx[0]][0]+np.random.uniform(-0.2, 0.2), coordinates[ndx[0]][1]+np.random.uniform(-0.2, 0.2),coordinates[ndx[0]][2]+np.random.uniform(-0.2, 0.2)])
234
+ coordinates[ndx[0]]=xyz_check
235
+ tree = cKDTree(coordinates)
236
+ if len(overlapped) > 30:
237
+ print('{:<100}'.format(''), end='\r')
238
+ overlapped = overlapping_atoms(tree)
239
+ return coordinates
240
+
241
+ ## overlap end
242
+ ## get fragment information
243
+
244
+ def split_fragment_names(line, residue, resname):
245
+ bead = gen.strip_header(line)
246
+ group = g_var.res_top[resname]['GROUPS'][bead]
247
+ if group not in residue:
248
+ residue[group] = {}
249
+ if bead not in residue[group]:
250
+ residue[group][bead]={}
251
+ return residue, group, bead
252
+
253
+ def get_atomistic(frag_location, resname=False):
254
+ if not resname:
255
+ resname = frag_location.split('/')[-1][:-4]
256
+ #### read in atomistic fragments into dictionary
257
+ residue = {} ## a dictionary of bead in each residue eg residue[group][bead][atom number(1)][residue_name(ASP)/coordinates(coord)/atom name(C)/connectivity(2)/atom_mass(12)]
258
+ fragment_mass = {}
259
+ with open(frag_location, 'r') as pdb_input:
260
+ for line_nr, line in enumerate(pdb_input.readlines()):
261
+ if line.startswith('['):
262
+ residue, group, bead = split_fragment_names(line, residue, resname)
263
+ fragment_mass[bead]=[]
264
+ if line.startswith('ATOM'):
265
+ line_sep = gen.pdbatom(line) ## splits up pdb line
266
+ residue[group][bead][line_sep['atom_number']]={'coord':np.array([line_sep['x']*g_var.sf,line_sep['y']*g_var.sf,line_sep['z']*g_var.sf]),
267
+ 'atom':line_sep['atom_name'],'resid':1, 'resid_ori':line_sep['residue_id'],'res_type':line_sep['residue_name'],
268
+ 'frag_mass':1}
269
+ #### updates fragment mass
270
+ if not gen.is_hydrogen(line_sep['atom_name']):
271
+ if line_sep['atom_name'] in g_var.res_top[resname]['atom_masses']:
272
+ residue[group][bead][line_sep['atom_number']]['frag_mass']=g_var.res_top[resname]['atom_masses'][line_sep['atom_name']] ### updates atom masses with crude approximations
273
+ fragment_mass[bead].append([line_sep['x']*g_var.sf,line_sep['y']*g_var.sf,line_sep['z']*g_var.sf,g_var.res_top[resname]['atom_masses'][line_sep['atom_name']]])
274
+ else:
275
+ fragment_mass[bead].append([line_sep['x']*g_var.sf,line_sep['y']*g_var.sf,line_sep['z']*g_var.sf,1])
276
+ return residue, fragment_mass
277
+
278
+ def connectivity(cg, at_frag_centers, cg_frag_centers, group, group_number):
279
+ #### returns the connections between the atomistic and coarse grain beads
280
+ at_connection, cg_connection=[],[]
281
+ for bead in cg:
282
+ resname = cg[bead]['residue_name']
283
+ break
284
+ if resname in g_var.sorted_connect:
285
+ if len(g_var.sorted_connect[resname]) > 0:
286
+ for group_bead in group:
287
+ for bead_atom in group[group_bead]:
288
+ if bead_atom in g_var.sorted_connect[resname][int(group_number)]:
289
+ skip = False
290
+ for bead_connect in g_var.sorted_connect[resname][int(group_number)][bead_atom]:
291
+ if 'cg_connect' not in locals():
292
+ if bead_connect in cg:
293
+ cg_connect = [cg[bead_connect]['coord']]
294
+ else:
295
+ skip = True
296
+ else:
297
+ if bead_connect in cg:
298
+ cg_connect.append(cg[bead_connect]['coord'])
299
+ if not skip:
300
+ at_connection.append(group[group_bead][bead_atom]['coord'])
301
+ cg_connection.append(np.mean(np.array(cg_connect), axis=0))
302
+ if len(at_frag_centers) > 1:
303
+ for bead in at_frag_centers:
304
+ cg_connection.append(cg_frag_centers[bead])
305
+ at_connection.append(at_frag_centers[bead])
306
+ return at_connection, cg_connection
307
+
308
+ def get_rotation(cg_connect, at_connect, center, resname, group, cg_resid):
309
+ if len(at_connect) == len(cg_connect):
310
+ if len(cg_connect) == 0:
311
+ return gen.AnglesToRotMat([np.random.uniform(0, math.pi*2), np.random.uniform(0, math.pi*2), np.random.uniform(0, math.pi*2)])
312
+ else:
313
+ return kabsch_rotate(np.array(at_connect)-center, np.array(cg_connect)-center)
314
+ else:
315
+ print('atom connections: '+str(len(at_connect))+' does not match CG connections: '+str(len(cg_connect)))
316
+ sys.exit('residue number: '+str(cg_resid)+', residue type: '+str(resname)+', group: '+group)
317
+
318
+ def apply_rotations(atomistic_fragments,cg_resid, group_fit, center, xyz_rot_apply):
319
+ for bead in group_fit:
320
+ for atom in group_fit[bead]:
321
+ group_fit[bead][atom]['coord'] = rotate_atom(group_fit[bead][atom]['coord'], center, xyz_rot_apply)
322
+ atomistic_fragments[cg_resid][atom] = group_fit[bead][atom].copy()
323
+ return atomistic_fragments
324
+
325
+ ### end fragment information
326
+ ### linked residue connectivity start
327
+
328
+ def BB_connectivity(at_connections,cg_connections, cg_residues, at_residues, residue_number, BB_bead, resname):
329
+ con_atoms = {}
330
+ for atom in at_residues:
331
+ # resname = at_residues[atom]['res_type']
332
+ if at_residues[atom]['atom'] in g_var.res_top[resname]['CONNECT'][BB_bead]['atom']:
333
+ con_atoms[g_var.res_top[resname]['CONNECT'][BB_bead]['atom'].index(at_residues[atom]['atom'])]=atom
334
+ new_chain=False
335
+ for con in con_atoms:
336
+ con_resid = residue_number+g_var.res_top[resname]['CONNECT'][BB_bead]['dir'][con]
337
+ if con_resid in cg_residues:
338
+ xyz_cur = cg_residues[residue_number][BB_bead]['coord']
339
+ if g_var.res_top[resname]['CONNECT'][BB_bead]['Con_Bd'][con] in cg_residues[con_resid]:
340
+ xyz_con = cg_residues[con_resid][g_var.res_top[resname]['CONNECT'][BB_bead]['Con_Bd'][con]]['coord']
341
+ if gen.calculate_distance(xyz_con, xyz_cur) < 6:
342
+ cg_connections.append(xyz_con)
343
+ at_connections.append(at_residues[con_atoms[con]]['coord'])
344
+ else:
345
+ if g_var.res_top[resname]['CONNECT'][BB_bead]['dir'][con] > 0:
346
+ new_chain=True
347
+ else:
348
+ if g_var.res_top[resname]['CONNECT'][BB_bead]['dir'][con] > 0:
349
+ new_chain=True
350
+ else:
351
+ if g_var.res_top[resname]['CONNECT'][BB_bead]['dir'][con] > 0:
352
+ new_chain=True
353
+ return at_connections,cg_connections, new_chain
354
+
355
+ ################################################################### Merged system
356
+
357
+ def merge_indivdual_chain_pdbs(file, end, res_type):
358
+ #### reads in each chain into merge list
359
+ merge, merged_coords = [],[]
360
+ count = 0
361
+ restraint_count = -1
362
+ for chain in range(0,g_var.system[res_type]):
363
+ merge_temp = []
364
+ if os.path.exists(file+'_'+str(chain)+end):
365
+ with open(file+'_'+str(chain)+end, 'r') as pdb_input:
366
+ merge_temp += read_in.filter_input(pdb_input.readlines(), False)
367
+ else:
368
+ sys.exit('cannot find chain: '+file+'_'+str(chain)+end)
369
+ if res_type+'_aligned' in file:
370
+ count, restraint_count = at_mod_p.create_disres(merge_temp, chain, file, count, restraint_count)
371
+ merge, merge_coords = fix_chirality(merge,merge_temp,merged_coords, res_type)
372
+ if res_type+'_aligned' not in file:
373
+ coords, index_conversion = index_conversion_generate(merge, merge_coords)
374
+ if 'aligned' in file.split('/')[-1]:
375
+ write_pdb(merge, merge_coords, {}, g_var.working_dir+'PROTEIN/PROTEIN_aligned_merged.pdb')
376
+ else:
377
+ write_pdb(merge, coords,index_conversion, g_var.working_dir+res_type+'/'+res_type+'_de_novo_merged.pdb')
378
+
379
+ def index_conversion_generate(merge, merge_coords):
380
+ index_conversion = {}
381
+ coords = []
382
+ for at_val, atom in enumerate(merge):
383
+ if not atom['atom_name'].startswith('M'):
384
+ index_conversion[at_val] = len(coords)
385
+ coords.append(merge_coords[at_val])
386
+ coords = check_atom_overlap(coords)
387
+ return coords, index_conversion
388
+
389
+ def write_pdb(merge, merge_coords, index_conversion, write_file):
390
+ #### creates merged pdb and writes chains to it
391
+ if not os.path.exists(write_file):
392
+ pdb_output=gen.create_pdb(write_file)
393
+ atom_counter=0
394
+ for line_val, line in enumerate(merge):
395
+ if line_val in index_conversion:
396
+ x, y, z = gen.trunc_coord(merge_coords[index_conversion[line_val]])
397
+ else:
398
+ if 'coord' in line:
399
+ x, y, z = gen.trunc_coord(line['coord'])
400
+ else:
401
+ x, y, z = gen.trunc_coord([line['x'],line['y'],line['z']])
402
+ if atom_counter >= 99_999:
403
+ atom_counter=1
404
+ else:
405
+ atom_counter+=1
406
+ pdb_output.write(g_var.pdbline%((atom_counter, line['atom_name'], line['residue_name'],' ',line['residue_id'],\
407
+ x,y,z,1,0))+'\n')
408
+ pdb_output.close()
409
+
410
+ def merge_system_pdbs(protein):
411
+ os.chdir(g_var.merged_directory)
412
+ #### create merged pdb
413
+ if not os.path.exists(g_var.merged_directory+'merged_cg2at'+protein+'.pdb'):
414
+ merge=[]
415
+ merge_coords=[]
416
+ #### run through every residue type in cg_residues
417
+ done = []
418
+ if 'novo' in protein:
419
+ print('checking for atom overlap in : '+protein[1:])
420
+ for segment, residue_type in enumerate(g_var.system):
421
+ if residue_type not in done:
422
+ if residue_type not in ['PROTEIN', 'OTHER']:
423
+ start_num = len(merge_coords)
424
+ merge, merge_coords = read_in_merged_pdbs(merge, merge_coords,
425
+ g_var.working_dir+residue_type+'/'+residue_type+'_merged.pdb')
426
+ g_var.np_blocks[residue_type]=[start_num,len(merge_coords)]
427
+ elif residue_type == 'OTHER':
428
+ merge, merge_coords = read_in_merged_pdbs(merge, merge_coords,
429
+ g_var.working_dir+residue_type+'/'+residue_type+'_de_novo_merged.pdb')
430
+ elif residue_type == 'PROTEIN':
431
+ merge, merge_coords = read_in_merged_pdbs(merge, merge_coords,
432
+ g_var.working_dir+residue_type+'/'+residue_type+protein+'_merged.pdb')
433
+ done.append(residue_type)
434
+ index_conversion = {}
435
+ if 'novo' in protein:
436
+ coords, index_conversion = index_conversion_generate(merge, merge_coords)
437
+ write_pdb(merge, coords, index_conversion, g_var.merged_directory+'merged_cg2at'+protein+'.pdb')
438
+ else:
439
+ write_pdb(merge, merge_coords, {}, g_var.merged_directory+'merged_cg2at'+protein+'.pdb')
440
+
441
+ def read_in_merged_pdbs(merge, merge_coords, location):
442
+ if os.path.exists(location):
443
+ #### opens pdb files and writes straight to merged_cg2at pdb
444
+ with open(location, 'r') as pdb_input:
445
+ read_in_atoms = read_in.filter_input(pdb_input.readlines(), False)
446
+ merge_coords += [[line_sep['x'],line_sep['y'],line_sep['z']] for line_sep in read_in_atoms ]
447
+ return merge+read_in_atoms, merge_coords
448
+ else:
449
+ sys.exit('cannot find minimised residue: \n'+ location)
450
+
451
+ def check_overlap_chain(chain, input,res_type):
452
+ if not os.path.exists(g_var.working_dir+res_type+'/'+res_type+'_'+input+str(chain)+'_gmx_checked.pdb'):
453
+ lines, coords = read_in_merged_pdbs([], [], res_type+'_'+input+str(chain)+'_gmx.pdb')
454
+ if res_type == 'PROTEIN':
455
+ coords = at_mod_p.correct_amide_h(lines, coords)
456
+
457
+ coords, index_conversion = index_conversion_generate(lines, coords)
458
+ write_pdb(lines, coords, index_conversion, g_var.working_dir+res_type+'/'+res_type+'_'+input+str(chain)+'_gmx_checked.pdb')
459
+
460
+ ## fix chirality errors
461
+
462
+ def fetch_chiral_coord(merge_temp, residue_type):
463
+ chiral_atoms={}
464
+ coord=[]
465
+ for atom in range(len(merge_temp)):
466
+ if residue_type in ['PROTEIN', 'OTHER']:
467
+ resname = gen.check_alternate_resname(merge_temp[atom]['residue_name'])
468
+ else:
469
+ resname = gen.check_alternate_resname(residue_type)
470
+ if len(g_var.res_top[resname]['CHIRAL']['atoms']) > 0:
471
+ if merge_temp[atom]['atom_name'] in g_var.res_top[resname]['CHIRAL']['atoms']:
472
+ if merge_temp[atom]['residue_id'] not in chiral_atoms:
473
+ chiral_atoms[merge_temp[atom]['residue_id']]={}
474
+ chiral_atoms[merge_temp[atom]['residue_id']][merge_temp[atom]['atom_name']]=atom
475
+ coord.append(np.array([merge_temp[atom]['x'],merge_temp[atom]['y'],merge_temp[atom]['z']]))
476
+ return chiral_atoms, coord
477
+
478
+
479
+ def get_atom_move(merge_temp, resname, residue, chiral_group, chiral_atoms):
480
+ stat = merge_temp[chiral_atoms[residue][chiral_group]].copy()
481
+ atom_move = {'stat':np.array([stat['x'],stat['y'],stat['z']]), 'm':'', 'c1':'', 'c2':'', 'c3':''}
482
+ for chir_atom in atom_move:
483
+ if chir_atom != 'stat':
484
+ test = merge_temp[chiral_atoms[residue][g_var.res_top[resname]['CHIRAL'][chiral_group][chir_atom]]].copy()
485
+ atom_move[chir_atom]= np.array([test['x'],test['y'],test['z']])
486
+ if gen.calculate_distance(atom_move['stat'], atom_move[chir_atom]) > 10:
487
+ atom_move[chir_atom] = np.array(read_in.brute_mic(atom_move['stat'],atom_move[chir_atom]))
488
+ return atom_move
489
+
490
+
491
+ def fix_chirality(merge, merge_temp, merged_coords, residue_type):
492
+ #### fixes chiral groups
493
+ chiral_atoms, coord = fetch_chiral_coord(merge_temp, residue_type)
494
+ for residue in chiral_atoms:
495
+ if residue_type in ['PROTEIN', 'OTHER']:
496
+ for atom in chiral_atoms[residue]:
497
+ resname = merge_temp[chiral_atoms[residue][atom]]['residue_name']
498
+ resname = gen.check_alternate_resname(resname)
499
+ break
500
+ else:
501
+ resname = gen.check_alternate_resname(residue_type)
502
+
503
+ for chiral_group in g_var.res_top[resname]['CHIRAL']:
504
+ if chiral_group != 'atoms':
505
+ atom_move = get_atom_move(merge_temp, resname, residue, chiral_group, chiral_atoms)
506
+
507
+ S_M = atom_move['m'] - atom_move['stat']
508
+ rotation = align_to_vector(S_M, [0,0,1])
509
+ c1_coord = (atom_move['c1'] - atom_move['stat']).dot(rotation)
510
+ c2_coord = (atom_move['c2'] - atom_move['stat']).dot(rotation)
511
+ c3_coord = (atom_move['c3'] - atom_move['stat']).dot(rotation)
512
+
513
+ if gen.angle_clockwise(c1_coord[0:2], c2_coord[0:2]) > gen.angle_clockwise(c1_coord[0:2], c3_coord[0:2]):
514
+ for ax_val, axis in enumerate(['x', 'y', 'z']):
515
+ merge_temp[chiral_atoms[residue][g_var.res_top[resname]['CHIRAL'][chiral_group]['m']]][axis] = merge_temp[chiral_atoms[residue][g_var.res_top[resname]['CHIRAL'][chiral_group]['m']]][axis] - (3*S_M[ax_val])
516
+ merge_temp[chiral_atoms[residue][chiral_group]][axis] = merge_temp[chiral_atoms[residue][chiral_group]][axis] - (S_M[ax_val])
517
+ coord[chiral_atoms[residue][g_var.res_top[resname]['CHIRAL'][chiral_group]['m']]] -= (2*S_M) #move_coord -
518
+ coord[chiral_atoms[residue][chiral_group]] -= (0.25*S_M)
519
+ merge+=merge_temp
520
+ merged_coords+=coord
521
+ return merge, merged_coords
522
+
523
+ def get_chiral_non_carbonyl(at):
524
+ chiral = {}
525
+ for atom in at:
526
+ if at[atom]['atom'] in g_var.res_top[at[atom]['res_type']]['CHIRAL']['atoms']:
527
+ chiral[at[atom]['atom']] = atom
528
+ return chiral
529
+
530
+ def correct_chiral_atoms(at, chiral):
531
+ for chiral_group in g_var.res_top[at[1]['res_type']]['CHIRAL']:
532
+ if chiral_group != 'atoms':
533
+ atom_list = [chiral[chiral_group]]
534
+ for chiral_atoms in ['c1','c2','c3']:
535
+ atom_list.append(chiral[g_var.res_top[at[1]['res_type']]['CHIRAL'][chiral_group][chiral_atoms]])
536
+ cross_vector_chiral = find_cross_vector( [at[atom_list[3]]['coord'], at[atom_list[2]]['coord'], at[atom_list[1]]['coord']])
537
+ norm_vector_chiral = noramlised_vector(at[chiral[g_var.res_top[at[1]['res_type']]['CHIRAL'][chiral_group]['m']]]['coord'], at[atom_list[0]]['coord'])
538
+ if not np.dot(cross_vector_chiral, norm_vector_chiral) > 0.5:
539
+ if g_var.res_top[at[1]['res_type']]['CHIRAL'][chiral_group]['m'] in chiral:
540
+ at[atom_list[0]]['coord'] = at[atom_list[0]]['coord'] + cross_vector_chiral*0.5
541
+ m = chiral[g_var.res_top[at[1]['res_type']]['CHIRAL'][chiral_group]['m']]
542
+ at[m]['coord'] = at[m]['coord'] + cross_vector_chiral*2
543
+ return at
544
+
545
+ ## chirality end
546
+ ## hydrogen orientaion checker
547
+
548
+ def check_hydrogens(residue):
549
+ #### finds the connecting carbons and their associated carbons [carbon atom, hydrogen ref number, connecting ref number]
550
+ for atom_num, atom in enumerate(residue):
551
+ resname=residue[atom]['res_type']
552
+ break
553
+ for atom in g_var.hydrogen[resname]:
554
+ h_coord = []
555
+ for group in g_var.sorted_connect[resname]:
556
+ if atom in g_var.sorted_connect[resname][group]:
557
+ for hydrogen in g_var.hydrogen[resname][atom]:
558
+ h_coord.append(residue[hydrogen]['coord'])
559
+ h_com=np.mean(np.array(h_coord), axis=0)
560
+ for heavy_bond in g_var.heavy_bond[resname][atom]:
561
+ for group_check in g_var.sorted_connect[resname]:
562
+ if heavy_bond in g_var.sorted_connect[resname][group_check] and group_check != group:
563
+ skip = False
564
+ if heavy_bond in residue:
565
+ con_heavy_atom = heavy_bond
566
+ con_heavy_atom_co = residue[con_heavy_atom]['coord']
567
+ else:
568
+ skip = True
569
+ if not skip:
570
+ #### vector between H COM and bonded carbon
571
+ vector=np.array([h_com[0]-residue[atom]['coord'][0],h_com[1]-residue[atom]['coord'][1],h_com[2]-residue[atom]['coord'][2]])
572
+ h_com_f=h_com+vector*2
573
+ d1 = gen.calculate_distance(h_com, con_heavy_atom_co)
574
+ d2 = gen.calculate_distance(h_com_f, con_heavy_atom_co)
575
+ if d2 < d1:
576
+ for h_at in g_var.hydrogen[resname][atom]:
577
+ residue[h_at]['coord']=residue[h_at]['coord']-vector*2
578
+ return residue
579
+
580
+ ## check for threaded lipids
581
+ def check_ringed_lipids(protein):
582
+ print('Checking for ringed lipids')
583
+ if not os.path.exists(g_var.merged_directory+'checked_ringed_lipid_de_novo.pdb'):
584
+ if not os.path.exists(g_var.merged_directory+'merged_cg2at_threaded.pdb'):
585
+ os.chdir(g_var.merged_directory)
586
+ merge, merge_coords = read_in_merged_pdbs([], [], protein)
587
+ ringed=False
588
+ lipid_atoms = []
589
+ with open(g_var.merged_directory+'threaded_lipids.dat', 'w') as ring_ouput:
590
+ for at_val, atom in enumerate(merge):
591
+ resname = get_np_resname(at_val)
592
+ if resname in g_var.np_residues:
593
+ offset = fetch_start_of_residue_np(at_val, resname)
594
+ if atom['atom_number']-offset in g_var.heavy_bond[resname]:
595
+ for at_bond in g_var.heavy_bond[resname][atom['atom_number']-offset]:
596
+ at_bond -=1
597
+ if merge[at_bond+offset]['atom_number'] > merge[at_val]['atom_number']:
598
+ merge[at_bond+offset]['x'], merge[at_bond+offset]['y'], merge[at_bond+offset]['z'] = np.array(read_in.brute_mic(merge_coords[at_val],merge_coords[at_bond+offset]))
599
+ merge_coords[at_bond+offset] = merge[at_bond+offset]['x'], merge[at_bond+offset]['y'], merge[at_bond+offset]['z']
600
+ dist = gen.calculate_distance(merge_coords[at_val], merge_coords[at_bond+offset])
601
+ if 2 < dist < 6:
602
+ lipid_atoms.append([at_val, at_bond+offset, (np.array(merge_coords[at_val])+np.array(merge_coords[at_bond+offset]))/2])
603
+ ring_ouput.write('{0:6}{1:6}{2:2}{3:4}{4:2}{5:7}{6:5}{7:5}{8:5}{9:5}{10:5}{11:5}\n'.format(
604
+ 'distance: ',str(np.round(dist,2)),'residue: ', merge[at_val]['residue_name'], merge[at_val]['residue_id'],
605
+ ' atom_1: ', merge[at_val]['atom_name'],
606
+ 'atom_2: ', merge[at_bond+offset]['atom_name'], 'rough line num: ', at_val, at_bond+offset))
607
+ ringed = True
608
+ if ringed or os.path.exists(g_var.merged_directory+'merged_cg2at_threaded.pdb'):
609
+ print('Found '+str(len(lipid_atoms))+' abnormal bonds, now attempting to fix.')
610
+ print('See this file for a complete list: '+g_var.merged_directory+'threaded_lipids.dat')
611
+ fix_threaded_lipids(lipid_atoms, merge, merge_coords)
612
+ else:
613
+ gen.file_copy_and_check(g_var.merged_directory+'MIN/merged_cg2at_de_novo_minimised.pdb', g_var.merged_directory+'checked_ringed_lipid_de_novo.pdb')
614
+
615
+ def fetch_start_of_residue(at, merge):
616
+ count = at
617
+ while True:
618
+ if merge[count]['residue_id'] != merge[at]['residue_id']:
619
+ count+=1
620
+ return count
621
+ else:
622
+ count-=1
623
+
624
+ def fetch_start_of_residue_np(atom, resname):
625
+ prev=g_var.np_blocks[resname][0]
626
+ range_np_block = g_var.np_blocks[resname][1]-g_var.np_blocks[resname][0]
627
+ for range_np_block_ind in range(g_var.np_blocks[resname][0],g_var.np_blocks[resname][1]+1, int(range_np_block/g_var.system[resname])):
628
+ if prev <= atom < range_np_block_ind:
629
+ return prev
630
+ prev = range_np_block_ind
631
+
632
+ def get_np_resname(atom):
633
+ for res_check in g_var.np_blocks:
634
+ if g_var.np_blocks[res_check][0] <= atom < g_var.np_blocks[res_check][1]:
635
+ return res_check
636
+
637
+ def fix_threaded_lipids(lipid_atoms, merge, merge_coords):
638
+ if not os.path.exists(g_var.merged_directory+'merged_cg2at_threaded.pdb'):
639
+ tree = cKDTree(merge_coords)
640
+ for threaded in lipid_atoms:
641
+ resname = get_np_resname(threaded[0])
642
+
643
+ atoms = tree.query_ball_point(threaded[2], r=3)
644
+ for at in atoms:
645
+ if merge[at]['residue_id'] != merge[threaded[0]]['residue_id']:
646
+ P_count = fetch_start_of_residue(at, merge)
647
+ break
648
+
649
+ NP_count = fetch_start_of_residue_np(threaded[0], resname)
650
+ bb = []
651
+ if 'P_count' not in locals():
652
+ sys.exit('There is an issue with the bond length detection')
653
+ for at in merge[P_count:]:
654
+ if at['residue_id'] != merge[P_count]['residue_id']:
655
+ break
656
+ if at['atom_name'] in g_var.res_top[at['residue_name']]['ATOMS']:
657
+ bb.append([at['x'], at['y'], at['z']])
658
+ bb = np.mean(np.array(bb), axis=0)
659
+ BB_M3 = (threaded[2]-bb)/np.linalg.norm((threaded[2]-bb))
660
+
661
+ for heavy_atom in threaded[:2]:
662
+ merge_coords[heavy_atom] += BB_M3*3
663
+ merge[heavy_atom]['x'], merge[heavy_atom]['y'], merge[heavy_atom]['z'] = merge_coords[heavy_atom]
664
+ for hydrogen in g_var.hydrogen[resname][heavy_atom-NP_count+1]:
665
+ merge_coords[NP_count+hydrogen-1] += BB_M3*3
666
+ merge[NP_count+hydrogen-1]['x'], merge[NP_count+hydrogen-1]['y'], merge[NP_count+hydrogen-1]['z'] = merge_coords[NP_count+hydrogen-1]
667
+
668
+ coords, index_conversion = index_conversion_generate(merge, merge_coords)
669
+ write_pdb(merge, coords, index_conversion, g_var.merged_directory+'merged_cg2at_threaded.pdb')
670
+
671
+ if not os.path.exists(g_var.merged_directory+'MIN/merged_cg2at_threaded_minimised.pdb'):
672
+ gro.minimise_merged_pdbs('_threaded')
673
+ gen.file_copy_and_check(g_var.merged_directory+'MIN/merged_cg2at_threaded_minimised.pdb', g_var.merged_directory+'checked_ringed_lipid_de_novo.pdb')