memprod 0.0.1__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.
memprod/MemPrOD.py ADDED
@@ -0,0 +1,1272 @@
1
+ import os
2
+ import sys
3
+ import warnings
4
+ import jax.numpy as jnp
5
+ from jax.config import config
6
+ from jax import tree_util
7
+ import jax
8
+ import jax.profiler
9
+ from enum import Enum
10
+ import numpy as np
11
+ from functools import partial
12
+ import matplotlib.pyplot as plt
13
+ import time
14
+ import MemPrO as ori
15
+ import argparse
16
+ from jax.sharding import PositionalSharding
17
+ from jax.experimental import mesh_utils
18
+ from scipy.optimize import minimize
19
+
20
+
21
+
22
+ #We define some enumerations for use later
23
+ class Reses(Enum):
24
+ ALA = 0
25
+ GLY = 1
26
+ ILE = 2
27
+ LEU = 3
28
+ PRO = 4
29
+ VAL = 5
30
+ PHE = 6
31
+ TYR = 7
32
+ TRP = 8
33
+ ARG = 9
34
+ LYS = 10
35
+ HIS = 11
36
+ SER = 12
37
+ THR = 13
38
+ ASP = 14
39
+ GLU = 15
40
+ ASN = 16
41
+ GLN = 17
42
+ CYS = 18
43
+ MET = 19
44
+
45
+ class Beads(Enum):
46
+ BB = 0
47
+ SC1 = 1
48
+ SC2 = 2
49
+ SC3 = 3
50
+ SC4 = 4
51
+ SC5 = 5
52
+ SC6 = 6
53
+
54
+ class Beadtype(Enum):
55
+ SP2 = 0 #p4
56
+ TC3 = 1 #p4
57
+ SP1 = 2 #P1
58
+ P2 = 3 #p5
59
+ SC2 = 4 #AC2
60
+ SP2a = 5 #p5
61
+ SC3 = 6 #c3
62
+ SC4 = 7 #SC5
63
+ TC5 = 8 #SC5
64
+ TC4 = 9 #SC4
65
+ TN6 = 10 #SP1
66
+ TN6d = 11 #SNd
67
+ SQ3p = 12 #Qp
68
+ SQ4p = 13 #Qp
69
+ TN5a = 14 #SP1
70
+ TP1 = 15 #P1
71
+ SQ5n = 16 #Qa
72
+ Q5n = 17 #Qa
73
+ TC6 = 18 #c5
74
+ C6 = 19 #c5
75
+ P5 = 20 #p5
76
+ SP5 = 21 #p4
77
+ GHOST = 22
78
+
79
+ def main():
80
+
81
+ warnings.filterwarnings('ignore')
82
+ os.environ["TF_CPP_MIN_LOG_LEVEL"]="3"
83
+ config.update("jax_enable_x64",True)
84
+
85
+ martini_default_path = os.environ["PATH_TO_MARTINI"]
86
+
87
+ #Reading command line args
88
+ parser = argparse.ArgumentParser(prog="MemPrOD",description="This is a program for the prediction of deformations caused by membrane proteins.")
89
+ parser.add_argument("-f", "--file_name",help = "Input file name (.pdb)")
90
+ parser.add_argument("-o","--output",help="Name of the output directory (Default: Deformations)")
91
+ parser.add_argument("-ni","--iters",help="Number of minimisation iterations (Default: 75)")
92
+ parser.set_defaults(iters=75)
93
+ parser.add_argument("-ng","--grid_density",help="Spacing of grid points (Default: 3)")
94
+ parser.set_defaults(grid_density=3)
95
+ parser.add_argument("-ncav","--no_cavity_surface",action="store_false",help="Toggle use of a surface finder that is more accurate but more expensive.")
96
+ parser.set_defaults(no_cavity_surface=True)
97
+ parser.add_argument("-itp","--itp_file",help="Path to force field (martini_v3.itp)")
98
+ parser.set_defaults(itp_file=martini_default_path)
99
+ parser.add_argument("-bd","--build_system",help = "Build a MD ready CG-system for ranks < n (Default: n=0)")
100
+ parser.set_defaults(build_system=False)
101
+ parser.add_argument("-bd_args","--build_arguments",help="Arguments to pass to insane when building system")
102
+ parser.set_defaults(build_arguments="")
103
+ parser.add_argument("-cut","--cutoff",help="Cutoff for LJ interactions (Deafult: 12)")
104
+ parser.set_defaults(cutoff=12)
105
+ parser.add_argument("-k1","--k1_const",help="Spring constant for neighbouring grid point Z deviations (Deafult: 0.25)")
106
+ parser.set_defaults(k1_const=0.25)
107
+ parser.add_argument("-k2","--k2_const",help="Spring constant for membrane compression (Deafult: 0)")
108
+ parser.set_defaults(k2_const=0)
109
+ parser.add_argument("-zshift","--zshift",help="Z shift of membrane for proteins that are missoriented due to lack of deformations.")
110
+ parser.set_defaults(zshift=0)
111
+ parser.add_argument("-mt","--membrane_thickness",help="Initial thickness of membrane in Angstroms (Deafult: 38)")
112
+ parser.set_defaults(membrane_thickness=38.0)
113
+ parser.add_argument("-wb","--write_bfactors",action="store_true",help="Toggle writing charge at each membrane segment instead of z position.")
114
+ parser.set_defaults(write_bfactors=False)
115
+ args = parser.parse_args()
116
+
117
+ #Error checking user inputs
118
+
119
+ mem_data = [0,0]
120
+
121
+ try:
122
+ mem_data[1] = float(args.membrane_thickness)-10
123
+ except:
124
+ print("ERROR: Could not read value of -mt. Must be a float > 10.")
125
+ exit()
126
+ if(mem_data[1] <= 0):
127
+ print("ERROR: Could not read value of -mt. Must be a float > 10.")
128
+ exit()
129
+
130
+
131
+
132
+ try:
133
+ iters = int(args.iters)
134
+ except:
135
+ print("ERROR: Could not read value of -ni. Must be an integer >= 0.")
136
+ exit()
137
+ if(iters < 0):
138
+ print("ERROR: Could not read value of -ni. Must be an integer >= 0.")
139
+ exit()
140
+
141
+
142
+ try:
143
+ build_system = int(args.build_system)
144
+ except:
145
+ print("ERROR: Could not read value of -bd. Must be an integer > -1.")
146
+ exit()
147
+ if(build_system < 0):
148
+ print("ERROR: Could not read value of -bd. Must be an integer > -1.")
149
+ exit()
150
+
151
+
152
+
153
+ fn = args.file_name
154
+
155
+ if(not os.path.exists(fn)):
156
+ print("ERROR: Cannot find file: "+fn)
157
+ exit()
158
+
159
+ orient_dir = args.output
160
+
161
+ #Setting Martini itp file
162
+ martini_file = args.itp_file
163
+
164
+ if(not os.path.exists(martini_file)):
165
+ print("ERROR: Cannot find file: "+martini_file)
166
+ exit()
167
+
168
+
169
+ #Creating folders to hold data
170
+ if(orient_dir == None):
171
+ if(not os.path.exists("Deformations/")):
172
+ os.mkdir("Deformations/")
173
+ orient_dir = "Deformations/"
174
+ else:
175
+ if orient_dir[-1] != "/":
176
+ orient_dir += "/"
177
+ if(not os.path.exists(orient_dir)):
178
+ os.mkdir(orient_dir)
179
+
180
+
181
+ locdir = orient_dir+"LocData/"
182
+ if(not os.path.exists(locdir)):
183
+ os.mkdir(locdir)
184
+
185
+ memdir = orient_dir+"Membrane_Data/"
186
+ if(not os.path.exists(memdir)):
187
+ os.mkdir(memdir)
188
+
189
+ timer = time.time()
190
+ tot_time = timer
191
+
192
+ #Some useful functions
193
+
194
+ @jax.jit
195
+ def flat_ind(ind1,ind2,max_ind1):
196
+ return ind2*max_ind1+ind1
197
+ @jax.jit
198
+
199
+ def unflat_ind(indf,max_ind1):
200
+ ind1 = indf%max_ind1
201
+ ind2 = jnp.array((indf-ind1)/max_ind1,dtype=int)
202
+ return ind1,ind2
203
+
204
+ @jax.jit
205
+ def put_into_grid(x,r,n,s):
206
+ cx = x[0]-s[0]
207
+ cy = x[1]-s[1]
208
+ norm_x = cx/r[0]
209
+ norm_y = cy/r[1]
210
+ grid_x = n[0]*norm_x
211
+ grid_y = n[1]*norm_y
212
+ return jnp.array(jnp.floor(grid_x),dtype=int),jnp.array(jnp.floor(grid_y),dtype=int)
213
+
214
+ twopowsixth = jnp.power(2,1/6)
215
+
216
+ def write_point(points,fn):
217
+ new_file = open(fn,"w")
218
+ count = 0
219
+ for i in points:
220
+ count += 1
221
+ count_str = (6-len(str(count)))*" "+str(count)
222
+ c = "ATOM "+count_str+" BB DUM 1 0.000 0.000 15.000 1.00 0.00"
223
+ xp = np.format_float_positional(i[0],precision=3)
224
+ yp = np.format_float_positional(i[1],precision=3)
225
+ zp = np.format_float_positional(i[2],precision=3)
226
+ xp += "0"*(3-len((xp.split(".")[1])))
227
+ yp += "0"*(3-len((yp.split(".")[1])))
228
+ zp += "0"*(3-len((zp.split(".")[1])))
229
+ new_c = c[:30]+(" "*(8-len(xp)))+xp+(" "*(8-len(yp)))+yp+(" "*(8-len(zp))) +zp+c[54:]+"\n"
230
+ new_file.write(new_c)
231
+ new_file.close()
232
+
233
+ def write_protein(bfacs,fn,ofn):
234
+ new_file = open(fn,"r")
235
+ n_lines = new_file.readlines()
236
+ new_file.close()
237
+ out_file = open(ofn,"w")
238
+ bc = 0
239
+ for c in n_lines:
240
+ if(len(c) > 46):
241
+ if("[" not in c and c[:4]=="ATOM"):
242
+ bbp = np.format_float_positional(bfacs[map_to_beads[bc]],precision=3)
243
+ bbp += "0"*(3-len((bbp.split(".")[1])))
244
+ new_c = c[:60]+(" "*(8-len(bbp)))+bbp+c[68:]
245
+ bc+=1
246
+ out_file.write(new_c)
247
+ else:
248
+ out_file.write(c)
249
+ else:
250
+ out_file.write(c)
251
+ out_file.close()
252
+
253
+
254
+ #lennard jones function with values <r cutoff
255
+ @jax.jit
256
+ def lj(r,min_pos):
257
+ ret_val = 0
258
+ def lmp(r):
259
+ return min_pos*twopowsixth
260
+ def nlmp(r):
261
+ return r
262
+ r = jax.lax.cond(r<min_pos*twopowsixth,lmp,nlmp,r)
263
+ ret_val = 4*(jnp.power((min_pos/r),12)-jnp.power((min_pos/r),6))
264
+ return ret_val
265
+
266
+
267
+ def get_loop_inds(n,nx,ny):
268
+ indsx = np.arange(nx-2*n+2)+(n-1)
269
+ indsy = np.arange(ny-2*n+2)+(n-1)
270
+ y0 = np.zeros(nx-2*n+2)+indsy[0]
271
+ yn = np.zeros(nx-2*n+2)+indsy[-1]
272
+ p0 = np.zeros(nx-2*n+2)-1
273
+ pp0 = np.zeros(nx-2*n+2)
274
+ pp0[0] += 1
275
+ pp0[-1] -= 1
276
+ pn = np.zeros(nx-2*n+2)+1
277
+ line1 = np.concatenate((indsx[:,None],y0[:,None],pp0[:,None],pn[:,None]),axis=1)
278
+ line2 = np.concatenate((indsx[:,None],yn[:,None],pp0[:,None],p0[:,None]),axis=1)
279
+ x0 = np.zeros(ny-2*n)+indsx[0]
280
+ xn = np.zeros(ny-2*n)+indsx[-1]
281
+ p0 = np.zeros(ny-2*n)-1
282
+ pp0 = np.zeros(ny-2*n)
283
+ pn = np.zeros(ny-2*n)+1
284
+ line3 = np.concatenate((x0[:,None],indsy[1:-1,None],pn[:,None],pp0[:,None]),axis=1)
285
+ line4 = np.concatenate((xn[:,None],indsy[1:-1,None],p0[:,None],pp0[:,None]),axis=1)
286
+ return np.concatenate((line1,line2,line3,line4))
287
+
288
+ def get_all_loop_inds(k,nx,ny):
289
+ all_inds = np.empty((0,4))
290
+ for i in range(k):
291
+ all_inds = np.concatenate((get_loop_inds(i+1,nx,ny),all_inds))
292
+ return all_inds
293
+
294
+ def get_new_zs(new_zs,loop_inds):
295
+ nx = new_zs.shape[0]
296
+ ny = new_zs.shape[1]
297
+ def loop1(new_zs,ind):
298
+ inder = jnp.array(loop_inds[ind],dtype=int)
299
+ ix = inder[0]
300
+ iy = inder[1]
301
+ inderm1 = inder.at[:2].set(inder[:2]+inder[2:])
302
+ ixl = inderm1[0]
303
+ iyl = inderm1[1]
304
+ new_zs = new_zs.at[ix,iy,0].set(new_zs[ix,iy,0]+new_zs[ixl,iyl,0])
305
+ return new_zs , ind
306
+ new_zs,_ = jax.lax.scan(loop1,new_zs,jnp.arange(loop_inds.shape[0]))
307
+ return new_zs
308
+
309
+
310
+
311
+
312
+
313
+
314
+ #Sigmoid function
315
+ @jax.jit
316
+ def sj(x,grad):
317
+ ret_val = -x*grad
318
+ def overflow_pos(ret_val):
319
+ ret_val = 100.0
320
+ return ret_val
321
+ def overflow_neg(ret_val):
322
+ ret_val = -100.0
323
+ return ret_val
324
+ def not_overflow(ret_val):
325
+ return ret_val
326
+
327
+ ret_val = jax.lax.cond(-x*grad>100,overflow_pos,not_overflow,ret_val)
328
+ ret_val = jax.lax.cond(-x*grad<-100,overflow_neg,not_overflow,ret_val)
329
+ return 1.0/(1.0+jnp.exp(ret_val))
330
+
331
+
332
+ #Two variations of the mean field function
333
+ @jax.jit
334
+ def smj(x,grad,bead_num,mem_structure):
335
+ l1min = (W_B_mins[bead_num]+LH1_B_mins[bead_num]-jnp.abs(W_B_mins[bead_num]-LH1_B_mins[bead_num]))/2
336
+ l2min = (W_B_mins[bead_num]+LH2_B_mins[bead_num]-jnp.abs(W_B_mins[bead_num]-LH2_B_mins[bead_num]))/2
337
+ l3min = (W_B_mins[bead_num]+LH3_B_mins[bead_num]-jnp.abs(W_B_mins[bead_num]-LH3_B_mins[bead_num]))/2
338
+ bd1 = (1.0-sj(x-mem_structure[0],grad))*W_B_mins[bead_num]+sj(x-mem_structure[0],grad)*l1min
339
+ bd2 = (1.0-sj(x-mem_structure[1],grad))*bd1+sj(x-mem_structure[1],grad)*l2min
340
+ bd3 = (1.0-sj(x-mem_structure[2],grad))*bd2+sj(x-mem_structure[2],grad)*l3min
341
+ bd4 = (1.0-sj(x-mem_structure[3],grad))*bd3+sj(x-mem_structure[3],grad)*LT1_B_mins[bead_num]
342
+ bd5 = (1.0-sj(x-mem_structure[4],grad))*bd4+sj(x-mem_structure[4],grad)*l3min
343
+ bd6 = (1.0-sj(x-mem_structure[5],grad))*bd5+sj(x-mem_structure[5],grad)*l2min
344
+ bd7 = (1.0-sj(x-mem_structure[6],grad))*bd6+sj(x-mem_structure[6],grad)*l1min
345
+ bd8 = (1.0-sj(x-mem_structure[7],grad))*bd7+sj(x-mem_structure[7],grad)*W_B_mins[bead_num]
346
+ return bd8-W_B_mins[bead_num]
347
+
348
+
349
+ @jax.jit
350
+ def smjh(x,grad,bead_num,mem_structure):
351
+ bd1 = (1.0-sj(x-mem_structure[0],grad))*W_B_mins[bead_num]+sj(x-mem_structure[0],grad)*LH1_B_mins[bead_num]
352
+ bd2 = (1.0-sj(x-mem_structure[1],grad))*bd1+sj(x-mem_structure[1],grad)*LH2_B_mins[bead_num]
353
+ bd3 = (1.0-sj(x-mem_structure[2],grad))*bd2+sj(x-mem_structure[2],grad)*LH3_B_mins[bead_num]
354
+ bd4 = (1.0-sj(x-mem_structure[3],grad))*bd3+sj(x-mem_structure[3],grad)*LT1_B_mins[bead_num]
355
+ bd5 = (1.0-sj(x-mem_structure[4],grad))*bd4+sj(x-mem_structure[4],grad)*LH3_B_mins[bead_num]
356
+ bd6 = (1.0-sj(x-mem_structure[5],grad))*bd5+sj(x-mem_structure[5],grad)*LH2_B_mins[bead_num]
357
+ bd7 = (1.0-sj(x-mem_structure[6],grad))*bd6+sj(x-mem_structure[6],grad)*LH1_B_mins[bead_num]
358
+ bd8 = (1.0-sj(x-mem_structure[7],grad))*bd7+sj(x-mem_structure[7],grad)*W_B_mins[bead_num]
359
+ return bd8-W_B_mins[bead_num]
360
+
361
+ #Creates a list containing the membrane structure for a given membrane thickness
362
+ def get_mem_struc(mt):
363
+ memt_tails = mt
364
+ memt_heads = 10.0
365
+ memt_total = memt_tails+memt_heads
366
+
367
+ h1_w = memt_heads/6.0
368
+ h2_w = memt_heads/6.0
369
+ h3_w = memt_heads/6.0
370
+
371
+ l_w = memt_tails
372
+ meml = -l_w/2.0 -h1_w -h2_w-h3_w
373
+ mem_structure = jnp.array([meml,meml+h1_w,meml+h2_w+h1_w,meml+h2_w+h1_w+h3_w,meml+h2_w+h1_w+h3_w+l_w,meml+h2_w+h1_w+2*h3_w+l_w,meml+2*h2_w+h1_w+2*h3_w+l_w,meml+2*h2_w+2*h1_w+2*h3_w+l_w])
374
+ return mem_structure
375
+
376
+ #A fucntion that reads a martini file to get interaction strengths
377
+ def get_int_strength(bead_1,bead_2,martini_file):
378
+ if(bead_2 == "GHOST"):
379
+ return 0
380
+ string = " "*(6-len(bead_1))+bead_1+" "*(6-len(bead_2))+bead_2
381
+ string2 = " "*(6-len(bead_2))+bead_2+" "*(6-len(bead_1))+bead_1
382
+ mfile = open(martini_file,"r")
383
+ content = mfile.readlines()
384
+ for i,line in enumerate(content):
385
+ if(string in line or string2 in line):
386
+ return -float(line[32:45])
387
+
388
+ #Gets the interations between protein beads and the enviroment. This is used to create the mean fields
389
+ def get_mem_def(martini_file):
390
+ #We use interactions strengths from martini using a POPE(Q4p)/POPG(P4)/POPC(Q1)? lipid as a template
391
+ W_B_mins = jnp.array([get_int_strength("W",Beadtype(i).name,martini_file)-get_int_strength("W",Beadtype(i).name,martini_file) for i in range(23)])
392
+ LH1_B_mins = jnp.array([get_int_strength("P4",Beadtype(i).name,martini_file)-get_int_strength("W",Beadtype(i).name,martini_file) for i in range(23)])
393
+ LH2_B_mins = jnp.array([get_int_strength("Q5",Beadtype(i).name,martini_file)-get_int_strength("W",Beadtype(i).name,martini_file) for i in range(23)])
394
+ LH3_B_mins = jnp.array([get_int_strength("SN4a",Beadtype(i).name,martini_file)-get_int_strength("W",Beadtype(i).name,martini_file) for i in range(23)])
395
+ LH4_B_mins = jnp.array([get_int_strength("N4a",Beadtype(i).name,martini_file)-get_int_strength("W",Beadtype(i).name,martini_file) for i in range(23)])
396
+ LT1_B_mins = jnp.array([get_int_strength("C1",Beadtype(i).name,martini_file)-get_int_strength("W",Beadtype(i).name,martini_file) for i in range(23)])
397
+ LT2_B_mins = jnp.array([get_int_strength("C4h",Beadtype(i).name,martini_file)-get_int_strength("W",Beadtype(i).name,martini_file) for i in range(23)])
398
+ Charge_B_mins =jnp.array([0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,-1,-1,0,0,0,0,0],dtype="float64")
399
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 # #
400
+ return (W_B_mins,LH1_B_mins,LH2_B_mins,LH3_B_mins,LH4_B_mins,LT1_B_mins,LT2_B_mins,Charge_B_mins)
401
+
402
+ #Gets the n closest neighbours in a grid
403
+ def get_nbh_inds(inder,nx,ny,n):
404
+ ix,iy = unflat_ind(inder,nx)
405
+
406
+ defs = jnp.arange(2*n+1)-n
407
+ nbh_inds = jnp.zeros(defs.shape[0]*defs.shape[0])
408
+ def l1(nbh_inds,ind):
409
+ ind1 = ind
410
+ def l2(nbh_inds,ind):
411
+ new_x = ix+defs[ind1]
412
+ new_y = iy+defs[ind]
413
+ def wrap_up(new_ind,ind_x):
414
+ return new_ind+ind_x
415
+ def wrap_down(new_ind,ind_x):
416
+ return new_ind-ind_x
417
+ def nothing(new_ind,ind_x):
418
+ return new_ind
419
+
420
+ new_x = jax.lax.cond(new_x>=nx,wrap_down,nothing,new_x,nx)
421
+ new_y = jax.lax.cond(new_y>=ny,wrap_down,nothing,new_y,ny)
422
+ new_x = jax.lax.cond(new_x<0,wrap_up,nothing,new_x,nx)
423
+ new_y = jax.lax.cond(new_y<0,wrap_up,nothing,new_y,ny)
424
+
425
+ nbh_inds = nbh_inds.at[ind1*defs.shape[0]+ind].set(flat_ind(new_x,new_y,nx))
426
+ return nbh_inds,ind
427
+ nbh_inds,_=jax.lax.scan(l2,nbh_inds,jnp.arange(defs.shape[0]))
428
+ return nbh_inds,ind
429
+ nbh_inds,_=jax.lax.scan(l1,nbh_inds,jnp.arange(defs.shape[0]))
430
+ return nbh_inds
431
+
432
+ #Writes the deformations pdb file
433
+ def write_pdb(start_z,grid_in,grid_ban,nx,ny,exx,exy,gc,defo_dir,locdir,memdir,bfacs,memdata,rot_mat_inv):
434
+ BanGrid = np.zeros((nx,ny,2))
435
+ Data = np.zeros((nx,ny,2))
436
+ new_file = open(defo_dir+"Deformations.pdb","w")
437
+ grid_in = np.array(grid_in)
438
+ count = 0
439
+ xs = np.linspace(-exx,exx,nx)
440
+ ys = np.linspace(-exy,exy,ny)
441
+ np.savez(locdir+"Xlin.npz",xs)
442
+ np.savez(locdir+"Ylin.npz",ys)
443
+ np.savez(memdir+"Xlin.npz",xs)
444
+ np.savez(memdir+"Ylin.npz",ys)
445
+ for i in range(nx):
446
+ for j in range(ny):
447
+ if(grid_ban[i,j] == 1):
448
+ ms = get_mem_struc(grid_in[i,j,1])
449
+ ms_av = get_mem_struc(grid_in[0,0,1])
450
+ z_pluss = [ms[0],ms[7]]
451
+ z_pluss_av = [ms_av[0],ms_av[7]]
452
+ for nn,zz in enumerate(z_pluss):
453
+ pm1 = (nn-0.5)*2
454
+ zp = zz+start_z/5
455
+ z_dev = np.mean(grid_in[0,:,0]+z_pluss_av[nn]+start_z/5)
456
+ zp_vpos = jnp.array(((grid_in[i,j,0]+zp+vext)/(2*vext))*vert_grid_size,dtype=int)
457
+ zp_vposc = jnp.array(((grid_in[i,j,0]+vext)/(2*vext))*vert_grid_size,dtype=int)
458
+ if(zp_vpos < zp_vposc):
459
+ lb = zp_vpos
460
+ rb = zp_vposc
461
+ else:
462
+ lb = zp_vposc
463
+ rb = zp_vpos
464
+ lenny = rb-lb
465
+ if(lb > 49):
466
+ lb = 49
467
+ if(rb > 49):
468
+ rb=49
469
+ if(lb<0):
470
+ lb=0
471
+ if(rb<0):
472
+ rb=0
473
+ covp = jnp.sum(bgrid_o[i,j,lb:rb])/lenny
474
+ if(covp > 0.6):
475
+ BanGrid[i,j,nn] = 1
476
+ Data[i,j,nn] = grid_in[i,j,0]+zp
477
+ if(bfacs):
478
+ bbp = np.format_float_positional(gc[i,j,nn],precision=3)
479
+ else:
480
+ bbp = np.format_float_positional((grid_in[i,j,0]+zp-z_dev)*pm1,precision=3)
481
+ bbp += "0"*(3-len((bbp.split(".")[1])))
482
+ count += 1
483
+ count_str = (6-len(str(count)))*" "+str(count)
484
+ c = "ATOM "+count_str+" BB DUM Z 1 0.000 0.000 15.000 1.00 0.00"
485
+
486
+ pos = np.array([xs[i],ys[j],0])
487
+ pos = np.dot(rot_mat_inv,pos)
488
+ xp = np.format_float_positional(pos[0],precision=3)
489
+ yp = np.format_float_positional(pos[1],precision=3)
490
+ zp = np.format_float_positional(grid_in[i,j,0]+zp,precision=3)
491
+ xp += "0"*(3-len((xp.split(".")[1])))
492
+ yp += "0"*(3-len((yp.split(".")[1])))
493
+ zp += "0"*(3-len((zp.split(".")[1])))
494
+ new_c = c[:30]+(" "*(8-len(xp)))+xp+(" "*(8-len(yp)))+yp+(" "*(8-len(zp))) +zp+c[54:60]+(" "*(8-len(bbp)))+bbp+c[66:]+"\n"
495
+ new_file.write(new_c)
496
+ new_file.close()
497
+ np.savez(locdir+"BotBan.npz",BanGrid[:,:,0])
498
+ np.savez(locdir+"TopBan.npz",BanGrid[:,:,1])
499
+ np.savez(locdir+"BotData.npz",Data[:,:,0])
500
+ np.savez(locdir+"TopData.npz",Data[:,:,1])
501
+ return BanGrid[:,:,0],BanGrid[:,:,1]
502
+
503
+ #calcualtes the eleectrostatic force using below
504
+ def calc_esf(start_z,grid_in,grid_ban,nx,ny,exx,exy,cposes,ctypes):
505
+ grid_in = np.array(grid_in)
506
+ grid_charge = np.zeros((nx,ny,2))
507
+ count = 0
508
+ xs = np.linspace(-exx,exx,nx)
509
+ ys = np.linspace(-exy,exy,ny)
510
+ for i in range(nx):
511
+ for j in range(ny):
512
+ if(grid_ban[i,j] == 1):
513
+ ms = get_mem_struc(grid_in[i,j,1])
514
+ z_pluss = [ms[0],ms[7]]
515
+ for nn,zz in enumerate(z_pluss):
516
+ zp = zz+start_z/5
517
+ x_pos = xs[i]
518
+ y_pos = ys[j]
519
+ z_pos = grid_in[i,j,0]+zp
520
+ grid_charge[i][j][nn] = calc_esf_p(jnp.array([x_pos,y_pos,z_pos]),cposes,ctypes)
521
+ return grid_charge
522
+
523
+ #calcues the electrostatic force
524
+ @jax.jit
525
+ def calc_esf_p(pos,cposes,ctypes):
526
+ ctypes = jnp.array(ctypes,dtype=int)
527
+ charge_const = 92.64
528
+ Charge_B_mins =jnp.array([0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,-1,-1,0,0,0,0,0],dtype="float64")
529
+ def esf_loop(carry,ind):
530
+ charge_cont = Charge_B_mins[ctypes[ind]]*charge_const/jnp.linalg.norm(pos-cposes[ind])
531
+ carry += charge_cont
532
+ return carry,ind
533
+ tot_c,_ = jax.lax.scan(esf_loop,0,jnp.arange(cposes.shape[0]))
534
+ return tot_c
535
+
536
+
537
+
538
+
539
+
540
+ #Creating a helper class that deals with loading the PDB files
541
+ PDB_helper_test = ori.PDB_helper(fn,False,0,np.array([]),args.no_cavity_surface,True)
542
+
543
+ #Loading PDB
544
+ pos_mean = PDB_helper_test.load_pdb()
545
+
546
+
547
+ #Getting surface
548
+ print("Getting surface residues...")
549
+ timer = time.time()
550
+ jax.block_until_ready(PDB_helper_test.get_surface())
551
+ PDB_helper_test.recenter_bvals()
552
+ data = PDB_helper_test.get_data()
553
+ int_data = get_mem_def(martini_file)
554
+ print("Done in:", str(np.format_float_positional(time.time()-timer,precision=3))+"s")
555
+
556
+ #storing important data
557
+ surf_poses = data[2]+pos_mean
558
+ poses = data[5]+pos_mean
559
+ surf_bvals = data[4]
560
+ bead_types = data[3]
561
+ surface_no = data[0]
562
+ map_to_beads = data[9]
563
+
564
+
565
+ #Rotates the protein to minimise the overall size of the grid. This improves efficiency for wide proteins.
566
+ print("Optimising grid...")
567
+ timer = time.time()
568
+
569
+ angs = jnp.linspace(0,jnp.pi,200)
570
+ def min_extent(carry,ind):
571
+ nang = angs[ind]
572
+ rot_mat = jnp.array([[jnp.cos(nang),-jnp.sin(nang),0],[jnp.sin(nang),jnp.cos(nang),0],[0,0,1]])
573
+ test_surf_poses = jnp.dot(rot_mat,poses.T).T
574
+ x_ext = jnp.maximum(-jnp.min(test_surf_poses[:,0]),jnp.max(test_surf_poses[:,0]))
575
+ y_ext = jnp.maximum(-jnp.min(test_surf_poses[:,1]),jnp.max(test_surf_poses[:,1]))
576
+ def lower(carry):
577
+ carry[0] = nang
578
+ carry[1] = x_ext*y_ext
579
+ return carry
580
+ def higher(carry):
581
+ return carry
582
+ carry = jax.lax.cond(carry[1] > x_ext*y_ext,lower,higher,carry)
583
+ return carry,ind
584
+
585
+ carry,_ = jax.lax.scan(min_extent,[0.0,jnp.inf],jnp.arange(200))
586
+ nang = carry[0]
587
+ rot_mat = jnp.array([[jnp.cos(nang),-jnp.sin(nang),0],[jnp.sin(nang),jnp.cos(nang),0],[0,0,1]])
588
+ rot_mat_inv = jnp.array([[jnp.cos(-nang),-jnp.sin(-nang),0],[jnp.sin(-nang),jnp.cos(-nang),0],[0,0,1]])
589
+ surf_poses = jnp.dot(rot_mat,surf_poses.T).T
590
+ poses = jnp.dot(rot_mat,poses.T).T
591
+
592
+
593
+ print("Done in:", str(np.format_float_positional(time.time()-timer,precision=3))+"s")
594
+ timer = time.time()
595
+
596
+ #Getting the chared residues for charge calculations later
597
+ print("Getting charged residues...")
598
+
599
+ surf_cposes = jnp.zeros((surf_poses.shape[0],3))
600
+ cbead_types = jnp.zeros(bead_types.shape[0])
601
+
602
+ def cloop(carry,ind):
603
+ def charged(carry):
604
+ new0 = carry[0].at[carry[2]].set(surf_poses[ind])
605
+ new1 = carry[1].at[carry[2]].set(bead_types[ind])
606
+ new2 = carry[2] + 1
607
+ return (new0,new1,new2)
608
+ def ncharged(carry):
609
+ return carry
610
+ carry = jax.lax.cond((bead_types[ind] == 12)+(bead_types[ind] == 13)+(bead_types[ind] == 16)+(bead_types[ind] == 17),charged,ncharged,carry)
611
+ return carry,ind
612
+
613
+ carry = (surf_cposes,cbead_types,0)
614
+ carry,_ = jax.lax.scan(cloop,carry,jnp.arange(surf_poses.shape[0]))
615
+ cposes = carry[0][:carry[2]]
616
+ ctypes = carry[1][:carry[2]]
617
+
618
+ print("Done in:", str(np.format_float_positional(time.time()-timer,precision=3))+"s")
619
+
620
+
621
+ #setting up variables used later
622
+
623
+ vert_grid_size = 50
624
+ vext = 50
625
+ vlin = jnp.linspace(-vext,vext,vert_grid_size)
626
+
627
+ indexer = np.nonzero((np.array(surf_poses[:,2]) < 50)*(np.array(surf_poses[:,2] > -50)))
628
+
629
+ surf_poses = surf_poses[indexer]
630
+ surf_bvals = surf_bvals[indexer]
631
+ bead_types = bead_types[indexer]
632
+
633
+ indexer2 = np.nonzero((np.array(poses[:,2]) < 50)*(np.array(poses[:,2] > -50)))
634
+
635
+ all_poses = poses.copy()
636
+ poses = poses[indexer2]
637
+
638
+ cutoff = int(args.cutoff)
639
+
640
+ x_ext = max(-jnp.min(surf_poses[:,0]),jnp.max(surf_poses[:,0]))+20
641
+ y_ext = max(-jnp.min(surf_poses[:,1]),jnp.max(surf_poses[:,1]))+20
642
+
643
+ grid_den = float(args.grid_density)
644
+
645
+ rad = int(4.0/grid_den)
646
+
647
+ grid_size_x = int(2*x_ext/grid_den)
648
+ grid_size_y = int(2*y_ext/grid_den)
649
+
650
+ loop_inds = jnp.array(get_all_loop_inds(12,grid_size_x,grid_size_y))
651
+ loop_inds_end = np.array(get_loop_inds(1,grid_size_x,grid_size_y),dtype=int)
652
+
653
+ nxx = jnp.array(x_ext/cutoff,dtype=int)
654
+ nyy = jnp.array(y_ext/cutoff,dtype=int)
655
+
656
+ no_beads = surf_poses.shape[0]
657
+
658
+ #Putting beads into bins for more efficient allocation of beads to membrane segments later on
659
+ print("Binning surface... (This could take a short while)")
660
+ timer = time.time()
661
+ @jax.jit
662
+ def allo_bead(surf_poses):
663
+ no_beads = surf_poses.shape[0]
664
+ big_grid = jnp.zeros((grid_size_x,grid_size_y,no_beads+1),dtype=int)-1
665
+ big_grid = big_grid.at[:,:,no_beads].set(0)
666
+ def allocacte_beads(big_grid,ind):
667
+ bind = ind
668
+ x_pos = surf_poses[bind][0]
669
+ y_pos = surf_poses[bind][1]
670
+ xgrid,ygrid = put_into_grid([x_pos,y_pos],[2*x_ext,2*y_ext],[nxx,nyy],[-x_ext,-y_ext])
671
+ big_grid = big_grid.at[xgrid,ygrid,big_grid[xgrid,ygrid,-1]].set(bind)
672
+ big_grid = big_grid.at[xgrid,ygrid,-1].set(big_grid[xgrid,ygrid,-1]+1)
673
+ return big_grid,ind
674
+ big_grid,_ = jax.lax.scan(allocacte_beads,big_grid,jnp.arange(no_beads))
675
+ return big_grid
676
+
677
+ big_grid = allo_bead(surf_poses)
678
+ big_gridb = allo_bead(poses)
679
+
680
+ max_beads = jnp.max(big_grid[:,:,-1])
681
+
682
+ print("Done in:", str(np.format_float_positional(time.time()-timer,precision=3))+"s")
683
+ timer = time.time()
684
+
685
+ #Allocating beads to membrane segments for use when calculating the potential. This takes some time and so is pre-calculated.
686
+ print("Allocating beads to membrane segments... (This could take a short while)")
687
+
688
+ xs = jnp.linspace(-x_ext,x_ext,grid_size_x)
689
+ ys = jnp.linspace(-y_ext,y_ext,grid_size_y)
690
+ indxes = jnp.zeros((grid_size_x,grid_size_y,2),dtype=int)
691
+ def indloop1(indxes,ind):
692
+ def indloop2(indxes,ind2):
693
+ indxes = indxes.at[ind,ind2].set(jnp.array([ind,ind2]))
694
+ return indxes,ind2
695
+ indxes,_ = jax.lax.scan(indloop2,indxes,jnp.arange(grid_size_y))
696
+ return indxes,ind
697
+ indxes,_=jax.lax.scan(indloop1,indxes,jnp.arange(grid_size_x))
698
+
699
+ indxes = indxes.reshape((grid_size_x*grid_size_y,2))
700
+
701
+ def allo_grid_vmap(cutoff_val,big_grid,surf_poses):
702
+ max_beads = jnp.max(big_grid[:,:,-1])
703
+ @partial(jax.vmap,in_axes=0)
704
+ def agrid_vmap(inds):
705
+ grid_p = jnp.zeros((no_beads+1,2),dtype=float)-1
706
+ grid_p = grid_p.at[no_beads,:].set(0)
707
+ ind2 = inds[0]
708
+ ind3 = inds[1]
709
+ indx,indy = put_into_grid([xs[ind2],ys[ind3]],[2*x_ext,2*y_ext],[nxx,nyy],[-x_ext,-y_ext])
710
+ sq = jnp.array([[0,0],[-1,0],[1,0],[0,-1],[0,1],[-1,1],[-1,-1],[1,1],[1,-1]],dtype=int)
711
+ def allocate_grid3(grid_p,ind):
712
+ def allocate_grid4(grid_p,sind):
713
+ bgind = big_grid[(indx+sq[sind,0])%grid_size_x,(indy+sq[sind,1])%grid_size_y][ind]
714
+ def close(grid_p,dist):
715
+ indeex = jnp.array(grid_p[-1,0],dtype=int)
716
+ grid_p = grid_p.at[indeex,0].set(bgind)
717
+ grid_p = grid_p.at[indeex,1].set(dist)
718
+ grid_p = grid_p.at[-1,0].set(grid_p[-1,0]+1)
719
+ return grid_p
720
+ def far(grid_p,dist):
721
+ return grid_p
722
+ def is_bead(grid_p):
723
+ pos = surf_poses[bgind][0:2]
724
+ grid_pos = jnp.array([xs[ind2],ys[ind3]])
725
+ dist = jnp.linalg.norm(pos-grid_pos)
726
+ grid_p = jax.lax.cond(dist < cutoff_val, close,far,grid_p,dist)
727
+ return grid_p
728
+ def isn_bead(grid_p):
729
+ return grid_p
730
+ grid_p= jax.lax.cond(bgind != -1,is_bead,isn_bead,grid_p)
731
+ return grid_p,sind
732
+ grid_p,_ = jax.lax.scan(allocate_grid4,grid_p,jnp.arange(9))
733
+ return grid_p,ind
734
+ grid_p,_ = jax.lax.scan(allocate_grid3,grid_p,jnp.arange(max_beads))
735
+ return grid_p
736
+ grid_p = agrid_vmap(indxes)
737
+ grid = grid_p.reshape((grid_size_x,grid_size_y,no_beads+1,2))
738
+ return grid
739
+
740
+ grid = allo_grid_vmap(cutoff,big_grid,surf_poses).block_until_ready()
741
+ grid_block = allo_grid_vmap(3.0,big_gridb,poses)
742
+
743
+ print("Done in:", str(np.format_float_positional(time.time()-timer,precision=3))+"s")
744
+ timer = time.time()
745
+
746
+ #Creating a smooth function that indicates if a point is with the protein or not.
747
+ print("Blocking membrane inside protein...")
748
+
749
+ max_beads_block = jnp.array(jnp.max(grid_block[:,:,-1,0]),dtype=int)
750
+ bgrid = jnp.zeros((grid_size_x,grid_size_y,vert_grid_size))+1
751
+
752
+ def gblock1(bgrid,ind):
753
+ ind2 = ind
754
+ def gblock2(bgrid,ind):
755
+ ind3 = ind
756
+ def bloop(bgrid,ind):
757
+ bind = jnp.array(grid_block[ind2,ind3,ind,0],dtype=int)
758
+ def mins(bgrid):
759
+ return bgrid
760
+ def nmins(bgrid):
761
+ atom_pos = poses[bind,2]
762
+ indap = jnp.array(((atom_pos+vext)/(2*vext))*vert_grid_size,dtype=int)
763
+ bgrid = bgrid.at[ind2,ind3,indap].set(0)
764
+ bgrid = bgrid.at[ind2,ind3,indap-1].set(0)
765
+ bgrid = bgrid.at[ind2,ind3,indap+1].set(0)
766
+ return bgrid
767
+ bgrid = jax.lax.cond(bind != -1,nmins,mins,bgrid)
768
+ return bgrid,ind
769
+ bgrid,_ = jax.lax.scan(bloop,bgrid,jnp.arange(max_beads_block))
770
+ return bgrid,ind
771
+ bgrid,_ = jax.lax.scan(gblock2,bgrid,jnp.arange(grid_size_y))
772
+ return bgrid,ind
773
+ bgrid,_ = jax.lax.scan(gblock1,bgrid,jnp.arange(grid_size_x))
774
+
775
+
776
+ mem_structure = get_mem_struc(mem_data[1])
777
+
778
+ def accessable(grid):
779
+ ngrid = jnp.zeros_like(grid)
780
+ def aloop1(ngrid,ind1):
781
+ def aloop2(ngrid,ind2):
782
+ t1 = jnp.sum(jnp.array([grid[ind1,ind2],grid[ind1-1,ind2],grid[ind1-1,ind2-1],grid[ind1,ind2-1]]))
783
+ t2 = jnp.sum(jnp.array([grid[ind1,ind2],grid[ind1+1,ind2],grid[ind1+1,ind2-1],grid[ind1,ind2-1]]))
784
+ t3 = jnp.sum(jnp.array([grid[ind1,ind2],grid[ind1-1,ind2],grid[ind1-1,ind2+1],grid[ind1,ind2+1]]))
785
+ t4 = jnp.sum(jnp.array([grid[ind1,ind2],grid[ind1+1,ind2],grid[ind1+1,ind2+1],grid[ind1,ind2+1]]))
786
+ def good(ngrid):
787
+ ngrid = ngrid.at[ind1,ind2].set(1)
788
+ return ngrid
789
+ def bad(ngrid):
790
+ return ngrid
791
+ ngrid = jax.lax.cond(jnp.logical_or(jnp.logical_or(t1==4,t2==4),jnp.logical_or(t3==4,t4==4)),good,bad,ngrid)
792
+ return ngrid,ind2
793
+ ngrid,_= jax.lax.scan(aloop2,ngrid,jnp.arange(ngrid.shape[1]))
794
+ return ngrid,ind1
795
+ ngrid,_ = jax.lax.scan(aloop1,ngrid,jnp.arange(ngrid.shape[0]))
796
+ return ngrid
797
+
798
+ grid_ban = jnp.zeros((grid_size_x,grid_size_y),dtype=int)+1
799
+ @jax.jit
800
+ def fill_mid(grid_ban,tol):
801
+ rdic_carry = jnp.zeros((grid_size_x*grid_size_y,3))
802
+ numer = grid_size_x*grid_size_y
803
+ rdic_carry = rdic_carry.at[0,0].set(1)
804
+ def remove_disc(rdic_carry,ind):
805
+ def check(rdic_carry):
806
+ rdic_carry = rdic_carry.at[ind,2].set(1)
807
+ def is_block(rdic_carry):
808
+ return rdic_carry
809
+ def is_no_block(rdic_carry):
810
+ nb_inds = jnp.array(get_nbh_inds(ind,grid_size_x,grid_size_y,1),dtype=int)
811
+ rdic_carry = rdic_carry.at[nb_inds,0].set(rdic_carry[nb_inds,0]+1)
812
+ rdic_carry = rdic_carry.at[ind,1].set(1)
813
+ return rdic_carry
814
+ rdic_carry = jax.lax.cond(grid_ban[unflat_ind(ind,grid_size_x)]>tol,is_block,is_no_block,rdic_carry)
815
+ return rdic_carry
816
+ def no_check(rdic_carry):
817
+ return rdic_carry
818
+ rdic_carry = jax.lax.cond((rdic_carry[ind,0]>0)*(rdic_carry[ind,2]==0),check,no_check,rdic_carry)
819
+ return rdic_carry,ind
820
+
821
+ rdic_carry,_ = jax.lax.scan(remove_disc,rdic_carry,jnp.arange(numer))
822
+ rdic_carry,_ = jax.lax.scan(remove_disc,rdic_carry,-jnp.arange(numer)+(numer-1))
823
+ transp_arange = jnp.arange(numer).reshape(grid_size_x,grid_size_y)
824
+ transp_arange = transp_arange.T
825
+ transp_arange = transp_arange.reshape(numer)
826
+ rdic_carry,_ = jax.lax.scan(remove_disc,rdic_carry,transp_arange)
827
+ rdic_carry,_ = jax.lax.scan(remove_disc,rdic_carry,-transp_arange+(numer-1))
828
+ return rdic_carry[:,2].reshape(grid_size_y,grid_size_x).T
829
+
830
+ bgrid_o = jnp.zeros_like(bgrid)
831
+
832
+ def fill_out_all(carry,ind):
833
+ bgrid = carry[0]
834
+ bgrid_o = carry[1]
835
+ tempb = fill_mid(1-accessable(bgrid[:,:,ind]),0.5)
836
+ bgrid_o = bgrid_o.at[:,:,ind].set(tempb)
837
+ bgrid = bgrid.at[:,:,ind].set(fill_mid(1-tempb,0.5))
838
+ return (bgrid,bgrid_o),ind
839
+
840
+ carryb,_ = jax.lax.scan(fill_out_all,(bgrid,bgrid_o),jnp.arange(vert_grid_size))
841
+ bgrid = carryb[0]
842
+ bgrid_o = carryb[1]
843
+
844
+ print("Done in:", str(np.format_float_positional(time.time()-timer,precision=3))+"s")
845
+ timer = time.time()
846
+
847
+ #This function indicates if grid point (i,j) and height z is within the protein.
848
+ @jax.jit
849
+ def bgrid_weight(i,j,z):
850
+ zind = ((z+vext)/(2*vext))*vert_grid_size
851
+ zind_l = jnp.array(jnp.floor(zind),dtype=int)-5
852
+ tot = 0
853
+
854
+ def above(zindy):
855
+ return vert_grid_size-1
856
+ def below(zindy):
857
+ return 0
858
+ def nab(zindy):
859
+ return jnp.array(zindy,dtype=int)
860
+
861
+ def bwloop(tot,ind):
862
+ zind_u = zind_l+ind
863
+ zind_u = jax.lax.cond(zind_u > vert_grid_size-1,above,nab,zind_u)
864
+ zind_u = jax.lax.cond(zind_u < 0,below,nab,zind_u)
865
+ tot += bgrid[i,j,zind_u]
866
+
867
+ return tot,ind
868
+ tot,_ = jax.lax.scan(bwloop,tot,jnp.arange(10))
869
+
870
+ zind_u = jax.lax.cond(zind_l+10 > vert_grid_size-1,above,nab,zind_l+10)
871
+ zind_u = jax.lax.cond(zind_l+10 < 0,below,nab,zind_l+10)
872
+
873
+ zind_l = jax.lax.cond(zind_l > vert_grid_size-1,above,nab,zind_l)
874
+ zind_l = jax.lax.cond(zind_l < 0,below,nab,zind_l)
875
+
876
+ tot += (bgrid[i,j,zind_u]-bgrid[i,j,zind_l])*(zind-zind_l-5)
877
+ return (1-jnp.cos(jnp.pi*(tot/10)))/2.0
878
+
879
+ max_beads = jnp.array(jnp.max(grid[:,:,-1,0]),dtype=int)
880
+ W_B_mins = int_data[0]
881
+ LH1_B_mins = int_data[1]
882
+ LH2_B_mins = int_data[2]
883
+ LH3_B_mins = int_data[3]
884
+ LH4_B_mins = int_data[4]
885
+ LT1_B_mins = int_data[5]
886
+ LT2_B_mins = int_data[6]
887
+ Charge_B_mins =int_data[7]
888
+
889
+ #Prevents gaps between protein and membrane
890
+ def intbgrid(ind2,ind3,zt,mt,zd):
891
+ mem_structure = get_mem_struc(mt)
892
+ z_disp = zt+zd
893
+ logs = jnp.linspace(mem_structure[0],mem_structure[-1],10)
894
+ sumer = 0
895
+ def z_range(sumer,ind):
896
+ zr = logs[ind]+z_disp
897
+ sumer += bgrid_weight(ind2,ind3,zr)
898
+ return sumer, ind
899
+ sumer,_ =jax.lax.scan(z_range,sumer,jnp.arange(10))
900
+ return (sj(-sumer+4,3))*(-sumer-200)/5.0
901
+
902
+
903
+
904
+ #Potential function. If surface bead or membrane segment is within the protein it's contribution is ignored
905
+ def get_pot(ind2,ind3,zt,mt,zd):
906
+ no_beads = grid[ind2,ind3,-1,0]
907
+ z_disp = zt+zd
908
+ def calc_grid3(tot,ind):
909
+ mem_structure = get_mem_struc(mt)
910
+ bind = jnp.array(grid[ind2,ind3,ind,0],dtype=int)
911
+ dist = grid[ind2,ind3,ind,1]
912
+ def nomin(tot):
913
+ z_pos = surf_poses[bind][2]-z_disp
914
+ xy_pos = surf_poses[bind][0:2]
915
+ indx,indy = put_into_grid([xy_pos[0],xy_pos[1]],[2*x_ext,2*y_ext],[nxx,nyy],[-x_ext,-y_ext])
916
+ bead_num = bead_types[bind]
917
+ disterz = jnp.sqrt(dist*dist)
918
+ def close(tot):
919
+ def upper(tot):
920
+ tot = tot.at[0].set(tot[0]+smj(z_pos,0.5,bead_num,mem_structure)*-1*lj(disterz,8.0)*bgrid_weight(ind2,ind3,z_pos)*bgrid_weight(indx,indy,z_pos))
921
+ return tot
922
+ def lower(tot):
923
+ tot = tot.at[1].set(tot[1]+smj(z_pos,0.5,bead_num,mem_structure)*-1*lj(disterz,8.0)*bgrid_weight(ind2,ind3,z_pos)*bgrid_weight(indx,indy,z_pos))
924
+ return tot
925
+ tot = jax.lax.cond(z_pos>0,upper,lower,tot)
926
+ return tot
927
+ def far(tot):
928
+ return tot
929
+ tot = jax.lax.cond((dist<float(args.cutoff))*(dist > 0),close,far,tot)
930
+ return tot
931
+ def miner(tot):
932
+ return tot
933
+ tot = jax.lax.cond(bind > -1e-1,nomin,miner,tot)
934
+ return tot,ind
935
+ def edge():
936
+ return (zt*zt)*1e-7+((mt-mem_data[1])*(mt-mem_data[1]))*1e-7
937
+ def nedge():
938
+ return (zt*zt)*1e-6+((mt-mem_data[1])*(mt-mem_data[1]))*1e-6
939
+ s_val = jax.lax.cond(jnp.logical_or(jnp.logical_or(ind3==0,ind3==grid.shape[1]-1),jnp.logical_or(ind2==0,ind2==grid.shape[0]-1)),edge,nedge)
940
+ tot,_ = jax.lax.scan(calc_grid3,jnp.array([s_val,s_val]),jnp.arange(max_beads))
941
+ tot += intbgrid(ind2,ind3,zt,mt,zd)
942
+ return tot,no_beads
943
+
944
+ #Calculates contacts with head groups and acyl tails
945
+ def calc_contacts(new_zs,poses,zdisp,xs,ys):
946
+ bfacsH = jnp.zeros(poses.shape[0])
947
+ bfacsT = jnp.zeros(poses.shape[0])
948
+ mindd = 3
949
+ def ccloop1(bfacs,ind1):
950
+ def ccloop2(bfacs,ind2):
951
+ mt = new_zs[ind1,ind2,1]
952
+ z = new_zs[ind1,ind2,0]
953
+ pos1 = jnp.array([xs[ind1],ys[ind2],z-mt/2.0-4+zdisp])
954
+ pos2 = jnp.array([xs[ind1],ys[ind2],z+mt/2.0+4+zdisp])
955
+ def ccloop3(bfacs,ind3):
956
+ bfacsH = bfacs[0]
957
+ bfacsT = bfacs[1]
958
+ posprot = poses[ind3]
959
+ dist1 = jnp.linalg.norm(posprot-pos1)/10
960
+ dist2 = jnp.linalg.norm(posprot-pos2)/10
961
+
962
+ bfacsH = bfacsH.at[ind3].set(bfacsH[ind3]+jnp.exp(-jnp.max(jnp.array([dist1*dist1,mindd])))*bgrid_weight(ind1,ind2,z-mt/2.0+4+zdisp)+jnp.exp(-jnp.max(jnp.array([dist2*dist2,mindd])))*bgrid_weight(ind1,ind2,z-mt/2.0-4+zdisp))
963
+ zscan = jnp.linspace(pos1[2],pos2[2],40)
964
+ def ccloop4(bfacsT,ind4):
965
+ pos3 = pos1.copy()
966
+ pos3 = pos3.at[2].set(zscan[ind4])
967
+ dist3 = jnp.linalg.norm(posprot-pos3)/10
968
+ bfacsT = bfacsT.at[ind3].set(bfacsT[ind3]+jnp.exp(-jnp.max(jnp.array([dist3*dist3,mindd])))*bgrid_weight(ind1,ind2,zscan[ind4]))
969
+ return bfacsT,ind4
970
+ bfacsT,_ = jax.lax.scan(ccloop4,bfacsT,jnp.arange(40))
971
+ return (bfacsH,bfacsT),ind3
972
+ bfacs,_ = jax.lax.scan(ccloop3,bfacs,jnp.arange(poses.shape[0]))
973
+ return bfacs,ind2
974
+ bfacs,_ = jax.lax.scan(ccloop2,bfacs,jnp.arange(new_zs.shape[1]))
975
+ return bfacs,ind1
976
+ bfacs,_ = jax.lax.scan(ccloop1,(bfacsH,bfacsT),jnp.arange(new_zs.shape[0]))
977
+ return bfacs
978
+
979
+ PhtoW = get_int_strength("C1","W",martini_file)-get_int_strength("C1","W",martini_file)
980
+ PhtoPh = get_int_strength("C1","C1",martini_file)-get_int_strength("C1","W",martini_file)
981
+ PhtoH = get_int_strength("P4","C1",martini_file)-get_int_strength("C1","W",martini_file)
982
+ HtoH = get_int_strength("P4","P4",martini_file)-get_int_strength("C1","W",martini_file)
983
+ HtoW = get_int_strength("P4","W",martini_file)-get_int_strength("C1","W",martini_file)
984
+ WtoW = get_int_strength("W","W",martini_file)-get_int_strength("C1","W",martini_file)
985
+
986
+
987
+ #A smooth function that describes the membrane seegment (0 water, 1 head, 2 acyl tails)
988
+ @jax.jit
989
+ def lip_sm(x,grad,lower,upper):
990
+ bd1 = (1.0-sj(x-lower+5,grad))*2+sj(x-lower+5,grad)*1
991
+ bd2 = (1.0-sj(x-lower,grad))*bd1+sj(x-lower,grad)*0
992
+ bd3 = (1.0-sj(x-upper,grad))*bd2+sj(x-upper,grad)*1
993
+ bd4 = (1.0-sj(x-upper-5,grad))*bd3+sj(x-upper-5,grad)*2
994
+ return bd4
995
+
996
+ int_mat = jnp.array([[PhtoPh,PhtoH,PhtoW],[PhtoH,HtoH,HtoW],[PhtoW,HtoW,WtoW]])
997
+
998
+ #This function calculates the potential between two membrane segments via 3d linear interpolations using membrane descriptions as above
999
+ @jax.jit
1000
+ def rpot_col(new_zs,inda1,indb1,inda2,indb2,dist,zd,k1):
1001
+ dist = jnp.sqrt((inda1-inda2)*(inda1-inda2)+(indb1-indb2)*(indb1-indb2))
1002
+ def close():
1003
+
1004
+
1005
+ posi1 = new_zs[inda1,indb1]
1006
+ upper1 = zd+posi1[0]+0.5*posi1[1]
1007
+ lower1 = zd+posi1[0]-0.5*posi1[1]
1008
+
1009
+ posi2 = new_zs[inda2,indb2]
1010
+ upper2 = zd+posi2[0]+0.5*posi2[1]
1011
+ lower2 = zd+posi2[0]-0.5*posi2[1]
1012
+
1013
+ lupper = jnp.min(jnp.array([upper1,upper2]))
1014
+ ulower = jnp.max(jnp.array([lower1,lower2]))
1015
+
1016
+ uupper = jnp.max(jnp.array([upper1,upper2]))
1017
+ llower = jnp.min(jnp.array([lower1,lower2]))
1018
+
1019
+ poverlap = posi1[0]-posi2[0]
1020
+ up_dist = upper1-upper2
1021
+ lo_dist = lower1-lower2
1022
+
1023
+
1024
+ def small():
1025
+ return jnp.linspace(lower1,upper1,30)
1026
+ def nsmall():
1027
+ return jnp.linspace(lower2,upper2,30)
1028
+
1029
+ test1 = jax.lax.cond(upper1-lower1<upper2-lower2,small,nsmall)
1030
+ test1 = jnp.concatenate((test1,jnp.array([lower1-2,upper1+2])))
1031
+ test1 = jnp.concatenate((test1,jnp.array([lower2-2,upper2+2])))
1032
+
1033
+ overlap = 0
1034
+ def rloop(overlap,ind):
1035
+ mta = lip_sm(test1[ind],4,lower1,upper1)
1036
+ mtb = lip_sm(test1[ind],4,lower2,upper2)
1037
+ mtbL = jnp.floor(mtb)
1038
+ mtaI = jnp.array(mta,dtype=int)
1039
+ partb = mtb-mtbL
1040
+ mtbU = jnp.ceil(mtb)
1041
+
1042
+ mtaL = jnp.floor(mta)
1043
+ mtbI = jnp.array(mtb,dtype=int)
1044
+ parta = mta-mtaL
1045
+ mtaU = jnp.ceil(mta)
1046
+
1047
+ intLL = int_mat[jnp.array(mtaL,dtype=int),jnp.array(mtbL,dtype=int)]
1048
+ intLU = int_mat[jnp.array(mtaL,dtype=int),jnp.array(mtbU,dtype=int)]
1049
+ intUL = int_mat[jnp.array(mtaU,dtype=int),jnp.array(mtbL,dtype=int)]
1050
+ intUU = int_mat[jnp.array(mtaU,dtype=int),jnp.array(mtbU,dtype=int)]
1051
+
1052
+ intLLS = int_mat[jnp.array(mtbL,dtype=int),jnp.array(mtbL,dtype=int)]
1053
+ intLUS = int_mat[jnp.array(mtbL,dtype=int),jnp.array(mtbU,dtype=int)]
1054
+ intULS = int_mat[jnp.array(mtbU,dtype=int),jnp.array(mtbL,dtype=int)]
1055
+ intUUS = int_mat[jnp.array(mtbU,dtype=int),jnp.array(mtbU,dtype=int)]
1056
+
1057
+ intVL = intLL*(1-partb)+partb*intLU
1058
+
1059
+ intVU = intUL*(1-partb)+partb*intUU
1060
+
1061
+ intV = intVL*(1-parta)+parta*intVU
1062
+
1063
+ intVLS = intLLS*(1-partb)+partb*intLUS
1064
+
1065
+ intVUS = intULS*(1-partb)+partb*intUUS
1066
+
1067
+ intVS = intVLS*(1-parta)+parta*intVUS
1068
+
1069
+ overlap += intV
1070
+
1071
+ return overlap,ind
1072
+ overlap,_ = jax.lax.scan(rloop,overlap,jnp.arange(test1.shape[0]))
1073
+
1074
+ return overlap,poverlap,up_dist,lo_dist
1075
+ def nclose():
1076
+ return 0.0,0.0,0.0,0.0
1077
+ overlap,poverlap,up_dist,lo_dist = jax.lax.cond(dist<100,close,nclose)
1078
+ flat_d = 10
1079
+ usplit = sj(up_dist-flat_d,1)*jnp.power(up_dist,2)+(1-sj(up_dist+flat_d,1))*jnp.power(up_dist,2)
1080
+ lsplit = sj(lo_dist-flat_d,1)*jnp.power(lo_dist,2)+(1-sj(lo_dist+flat_d,1))*jnp.power(lo_dist,2)
1081
+ return k1*overlap*-lj(dist,1.0)+lsplit+usplit
1082
+
1083
+ #calculates the full potential due to membrane-membrane interactions
1084
+ @jax.jit
1085
+ def nbh_calc(new_zs,k,k2,zd):
1086
+ new_zs = get_new_zs(new_zs,loop_inds)
1087
+ grad_grid = jnp.zeros((grid_size_x,grid_size_y,2))
1088
+ def nbh_grad_calc1(grad_grid,ind2):
1089
+ def nbh_grad_calc2(grad_grid,ind3):
1090
+ inder = flat_ind(ind2,ind3,grid_size_x)
1091
+ all_nbhs = jnp.array(get_nbh_inds(inder,grid_size_x,grid_size_y,1),dtype=int)
1092
+ tot = jnp.zeros(2)
1093
+ posi1 = new_zs[ind2,ind3]
1094
+ upper1 = zd+posi1[0]+0.5*posi1[1]
1095
+ lower1 = zd+posi1[0]-0.5*posi1[1]
1096
+ u_mult1 = bgrid_weight(ind2,ind3,upper1)
1097
+ l_mult1 = bgrid_weight(ind2,ind3,lower1)
1098
+ min_mult = (jnp.abs(u_mult1-l_mult1)+u_mult1+l_mult1)/2
1099
+
1100
+ tot = tot.at[1].set(tot[1]+min_mult*0.5*k2*(mem_data[1]-new_zs[ind2,ind3,1])*(mem_data[1]-new_zs[ind2,ind3,1]))
1101
+
1102
+ def nbh_grad_calc3(tot,ind):
1103
+ inda,indb = unflat_ind(all_nbhs[ind],grid_size_x)
1104
+ def diff(tot):
1105
+ tot = tot.at[0].set(tot[0]+rpot_col(new_zs,inda,indb,ind2,ind3,0,zd,k))
1106
+ return tot
1107
+ def ndiff(tot):
1108
+ return tot
1109
+ tot = jax.lax.cond(jnp.logical_and(inda==ind2,indb==ind3),ndiff,diff,tot)
1110
+ return tot,ind
1111
+ tot,_ = jax.lax.scan(nbh_grad_calc3,tot,jnp.arange(all_nbhs.shape[0]))
1112
+ grad_grid = grad_grid.at[ind2,ind3].set(tot)
1113
+ return grad_grid,ind3
1114
+ grad_grid,_ = jax.lax.scan(nbh_grad_calc2,grad_grid,jnp.arange(grid_size_y))
1115
+ return grad_grid,ind2
1116
+ grad_grid,_ = jax.lax.scan(nbh_grad_calc1,grad_grid,jnp.arange(grid_size_x))
1117
+ return grad_grid
1118
+
1119
+
1120
+ #calculates the potential over all membrane segments
1121
+ @jax.jit
1122
+ def calc_graphs(xy,zd):
1123
+ xy = get_new_zs(xy,loop_inds)
1124
+ grid_vals = jnp.zeros((grid_size_x,grid_size_y,2))
1125
+ def calc_grid(grid_vals,ind):
1126
+ ind2 = ind
1127
+ def calc_grid2(grid_vals,ind):
1128
+ ind3 = ind
1129
+ z_disp = xy[ind2,ind3,0]+zd
1130
+ mt = xy[ind2,ind3,1]
1131
+ tot,_ = get_pot(ind2,ind3,xy[ind2,ind3,0],mt,zd)
1132
+ grid_vals = grid_vals.at[ind2,ind3].set(tot)
1133
+ return grid_vals,ind
1134
+ grid_vals,_ = jax.lax.scan(calc_grid2,grid_vals,jnp.arange(grid_size_y))
1135
+ return grid_vals,ind
1136
+ grid_vals,_ = jax.lax.scan(calc_grid,grid_vals,jnp.arange(grid_size_x))
1137
+ return grid_vals
1138
+
1139
+ #used for evaluating potential over all membrane segments for creating Potential graphs
1140
+ def get_pot_graph(in_xy):
1141
+ k = float(args.k1_const)
1142
+ k2 = float(args.k2_const)
1143
+ xy = in_xy[:grid_size_x*grid_size_y*2]
1144
+ zd = in_xy[-1]/5
1145
+ xy = xy.reshape((grid_size_x,grid_size_y,2))
1146
+ return calc_graphs(xy,zd)
1147
+
1148
+ #setting up the total potential function
1149
+ @jax.jit
1150
+ def total_pot_fun(in_xy):
1151
+ k = float(args.k1_const)
1152
+ k2 = float(args.k2_const)
1153
+ xy = in_xy[:grid_size_x*grid_size_y*2]
1154
+ zd = in_xy[-1]/5
1155
+ xy = xy.reshape((grid_size_x,grid_size_y,2))
1156
+ return jnp.sum(calc_graphs(xy,zd))+jnp.sum(nbh_calc(xy,k,k2,zd))
1157
+
1158
+ #differentiating using jax
1159
+ ac_grad_fun = jax.grad(total_pot_fun,argnums=0)
1160
+
1161
+
1162
+ #wrapping for use with numpy based minimisation algorithm (As the jax.numpy one had issues at time of writing - this could be updated once this works)
1163
+ def nwrap_tpot(in_xy):
1164
+ in_xyj = jnp.array(in_xy)
1165
+ return total_pot_fun(in_xyj)
1166
+
1167
+ def nwrap_grad(in_xy):
1168
+ in_xyj = jnp.array(in_xy)
1169
+ test = np.array(ac_grad_fun(in_xyj))
1170
+ return test
1171
+
1172
+
1173
+
1174
+ new_zs = jnp.zeros((grid_size_x,grid_size_y,2))
1175
+ new_zs = new_zs.at[:,:,1].set(mem_data[1])
1176
+ start_z = float(args.zshift)*5
1177
+ start_oz = 0
1178
+
1179
+
1180
+ print("Misc..")
1181
+ print("Done in:", str(np.format_float_positional(time.time()-timer,precision=3))+"s")
1182
+ print("Minimisation... (This will take a while)")
1183
+
1184
+ timer = time.time()
1185
+
1186
+ #writing bead positions for debugging purposes
1187
+ write_point(np.array(surf_poses),memdir+"Surface.pdb")
1188
+ write_point(np.array(all_poses),memdir+"All_beads.pdb")
1189
+
1190
+ #main minimisation loop
1191
+ try_again=True
1192
+ while try_again:
1193
+ min_out = minimize(nwrap_tpot, np.concatenate((np.array(new_zs.flatten()),np.array([start_z]))),jac = nwrap_grad ,method='BFGS', tol=2e-4,options={"gtol":0.002,"maxiter":iters})
1194
+ new_zs = min_out.x[:grid_size_x*grid_size_y*2]
1195
+ start_z = min_out.x[-1]
1196
+ new_zs = new_zs.reshape((grid_size_x,grid_size_y,2))
1197
+ new_zs = np.array(get_new_zs(jnp.array(new_zs),loop_inds))
1198
+ total_z = np.mean(new_zs[loop_inds_end[:,0],loop_inds_end[:,1],0])
1199
+ new_zs[:,:,0] -= total_z
1200
+ start_z += total_z*5
1201
+ if(min_out.status == 2):
1202
+ try_again = False
1203
+ elif(min_out.status == 1):
1204
+ try_again = False
1205
+ else:
1206
+ try_again=not min_out.success
1207
+
1208
+
1209
+ print("Done in:", str(np.format_float_positional(time.time()-timer,precision=3))+"s")
1210
+
1211
+ #calcuating graphs, contacts and general post processing
1212
+ print("Post processing...")
1213
+ timer = time.time()
1214
+
1215
+ np.savez(memdir+"Membrane_pos.npz",new_zs)
1216
+ np.savez(memdir+"Z_change.npz",start_z/5.0)
1217
+ np.savez(memdir+"Rotation_matrix.npz",rot_mat)
1218
+
1219
+
1220
+ bfacs = calc_contacts(jnp.array(new_zs),jnp.array(all_poses),start_z/5.0,xs,ys)
1221
+ bfacs_at = np.array(bfacs[1])
1222
+ bfacs_hg = np.array(bfacs[0])
1223
+
1224
+ bfacs_at /= np.max(bfacs_at)
1225
+ bfacs_hg /= np.max(bfacs_hg)
1226
+
1227
+ write_protein(bfacs_hg,fn,orient_dir+"HeadGroup_contacts.pdb")
1228
+ write_protein(bfacs_at,fn,orient_dir+"AcylTail_contacts.pdb")
1229
+
1230
+
1231
+ gc = calc_esf(start_z,new_zs,grid_ban,grid_size_x,grid_size_y,x_ext,y_ext,cposes,ctypes)
1232
+ potg = get_pot_graph(min_out.x)
1233
+ plt.imshow(potg[:,:,0])
1234
+ plt.savefig(orient_dir+"Potential_Upper.svg")
1235
+ plt.clf()
1236
+ plt.imshow(potg[:,:,1])
1237
+ plt.savefig(orient_dir+"Potential_Lower.svg")
1238
+ plt.clf()
1239
+
1240
+
1241
+ BotBan, TopBan = write_pdb(start_z,new_zs,grid_ban,grid_size_x,grid_size_y,x_ext,y_ext,gc,orient_dir,locdir,memdir,args.write_bfactors,mem_data,rot_mat_inv)
1242
+
1243
+ print("Z change:",np.format_float_positional(start_z/5.0,precision=3))
1244
+ plt.imshow((new_zs[:,:,0]+0.5*new_zs[:,:,1])*TopBan)
1245
+ plt.savefig(orient_dir+"Deformations_Upper.svg")
1246
+ plt.clf
1247
+ plt.imshow((new_zs[:,:,0]-0.5*new_zs[:,:,1])*BotBan)
1248
+ plt.savefig(orient_dir+"Deformations_Lower.svg")
1249
+ plt.clf
1250
+
1251
+
1252
+
1253
+ print("Done in:", str(np.format_float_positional(time.time()-timer,precision=3))+"s")
1254
+
1255
+
1256
+
1257
+ plt.imshow(gc[:,:,0]*BotBan)
1258
+ plt.savefig(orient_dir+"Charge_Lower.svg")
1259
+ plt.clf
1260
+ plt.imshow(gc[:,:,1]*TopBan)
1261
+ plt.savefig(orient_dir+"Charge_Upper.svg")
1262
+ plt.clf
1263
+
1264
+
1265
+ run_txt = open(orient_dir+"Run_command.txt","w")
1266
+ run_txt.write(" ".join(sys.argv))
1267
+ run_txt.close()
1268
+
1269
+ print("Total time:",str(np.format_float_positional(time.time()-tot_time,precision=3))+"s")
1270
+
1271
+ if __name__ == "__main__":
1272
+ main()