mempro 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.
@@ -0,0 +1,4533 @@
1
+ import sys,math,random,os
2
+ import numpy as np
3
+ import matplotlib.pyplot as plt
4
+ import scipy as sp
5
+ import jax
6
+ import jax.numpy as jnp
7
+ from functools import partial
8
+
9
+
10
+ def main():
11
+
12
+ jax.config.update("jax_enable_x64",True)
13
+ jax.config.update("jax_platform_name","cpu")
14
+
15
+ # Modify insane to take in arbitary lipid definition strings and use them as a template for lipids
16
+ # Also take in lipid name
17
+ # Edits: by Helgi I. Ingolfsson (all edits are marked with: # HII edit - lipid definition )
18
+
19
+ #This is a heavily modified version of Insane, called Insane4MemPrO, written to work with the orientation software MemPrO.
20
+ #Modifications were made by Matyas Parrag.
21
+
22
+
23
+ # PROTOLIPID (diacylglycerol), 18 beads
24
+ #
25
+ # 1-3-4-6-7--9-10-11-12-13-14
26
+ # \| |/ |
27
+ # 2 5 8-15-16-17-18-19-20
28
+ #
29
+
30
+ lipidsx = {}
31
+ lipidsy = {}
32
+ lipidsz = {}
33
+ lipidsa = {}
34
+
35
+
36
+ #Detergent
37
+
38
+ moltype = "type_DDM"
39
+ lipidsx[moltype] = (0.27, -0.18, 0.43, 0.17, -0.48, -0.03, 0.42, -0.03, 0.09, 0.03, 0.01)
40
+ lipidsy[moltype] = (-0.32, -0.53, -0.29, -0.34, -0.04, 0.29, 0.46, 0.21, 0.21, 0.06, 0.02)
41
+ lipidsz[moltype] = (3.58, 3.07, 2.68, 3.10, 3.68, 3.05, 3.78, 3.50, 2.04, 1.06, 0.06)
42
+ lipidsa.update({ "DDM":(moltype, "A1 B1 C1 VS1 A2 B2 C2 VS2 L1 L2 L3")})
43
+
44
+
45
+
46
+ #For building of PG layers in CG, This is a test and currently uses M2 beads
47
+ moltype = "type_PEP"
48
+ lipidsy[moltype] = (-0.03, 0.39, -0.03, -0.03, -0.03, -0.61, -0.93, -0.03, 0.40, -0.03, -0.45, -0.04, -0.41, -0.04, -0.03, -0.03, -0.03, -0.03, -0.66, -0.79)
49
+ lipidsz[moltype] = (0.02, 0.15, 0.02, 0.03, 0.04, -0.12, 0.12, 0.05, 0.12, 0.06, -0.12, 0.10, -0.13, 0.10, 0.09, 0.08, 0.07, 0.06, -0.11, -0.14)
50
+ lipidsx[moltype] = (4.41, 4.41, 3.64, 2.93, 2.23, 2.17, 2.65, 1.44, 1.32, 0.57, 0.69, -3.69, -3.71, -2.91, -2.21, -1.50, -0.77, -0.02, -1.60, -2.02)
51
+ lipidsa.update({ "PEP":(moltype, "B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20")})
52
+ lipidsa.update({ "SPEP":(moltype, "B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 - - - - - - - - -")})
53
+ lipidsa.update({ "UPEP":(moltype, "B1 B2 B3 B4 B5 B6 B7 B8 B9 - - - - - - - - - - -")})
54
+ lipidsa.update({ "UUPEP":(moltype, "B1 B2 B3 B4 B5 B6 B7 - - - - - - - - - - - - -")})
55
+
56
+
57
+
58
+ moltype = "type_NAM"
59
+ lipidsx[moltype] = (-0.00, 0.60, -0.58, 0.01, -0.52)
60
+ lipidsz[moltype] = (0.03, -0.00, 0.04, 0.03, 0.05)
61
+ lipidsy[moltype] = (4.70, 4.44, 4.74, 4.07, 3.81)
62
+ lipidsa.update({ "NAM":(moltype, "B1 B2 B3 B4 B5")})
63
+
64
+
65
+ moltype = "type_NAG"
66
+ lipidsx[moltype] = (0.06, 0.65, -0.51, 0.02)
67
+ lipidsz[moltype] = (0.00, -0.02, 0.00, 0.00)
68
+ lipidsy[moltype] = (3.04, 2.74, 3.22, 2.42)
69
+ lipidsa.update({ "NAG":(moltype, "B1 B2 B3 B4")})
70
+
71
+
72
+
73
+
74
+ #
75
+ ## Diacyl glycerols
76
+ moltype = "lipid"
77
+ lipidsx[moltype] = ( 0, .5, 0, 0, .5, 0, 0, .5, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1)
78
+ lipidsy[moltype] = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
79
+ lipidsz[moltype] = ( 10, 9, 9, 8, 8, 7, 6, 6, 5, 4, 3, 2.5, 1, 0, 5, 4, 3, 2.5, 1, 0)
80
+ lipidsa.update({ # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
81
+ ## Phospholipids
82
+ "DTPC": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A C2A - - - - C1B C2B - - - - "),
83
+ "DLPC": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A C2A C3A - - - C1B C2B C3B - - - "),
84
+ "DPPC": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A C2A C3A C4A - - C1B C2B C3B C4B - - "),
85
+ "DBPC": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A C2A C3A C4A C5A - C1B C2B C3B C4B C5B - "),
86
+ "POPC": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A D2A C3A C4A - - C1B C2B C3B C4B - - "),
87
+ "DOPC": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A D2A C3A C4A - - C1B D2B C3B C4B - - "),
88
+ "DAPC": (moltype, " - - - NC3 - PO4 GL1 GL2 D1A D2A D3A D4A C5A - D1B D2B D3B D4B C5B - "),
89
+ "DIPC": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A D2A D3A C4A - - C1B D2B D3B C4B - - "),
90
+ "DGPC": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A C2A D3A C4A C5A - C1B C2B D3B C4B C5B - "),
91
+ "DNPC": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A C2A C3A D4A C5A C6A C1B C2B C3B D4B C5B C6B"),
92
+ "DTPE": (moltype, " - - - NH3 - PO4 GL1 GL2 C1A C2A - - - - C1B C2B - - - - "),
93
+ "DLPE": (moltype, " - - - NH3 - PO4 GL1 GL2 C1A C2A C3A - - - C1B C2B C3B - - - "),
94
+ "DPPE": (moltype, " - - - NH3 - PO4 GL1 GL2 C1A C2A C3A C4A - - C1B C2B C3B C4B - - "),
95
+ "DBPE": (moltype, " - - - NH3 - PO4 GL1 GL2 C1A C2A C3A C4A C5A - C1B C2B C3B C4B C5B - "),
96
+ "POPE": (moltype, " - - - NH3 - PO4 GL1 GL2 C1A D2A C3A C4A - - C1B C2B C3B C4B - - "),
97
+ "DOPE": (moltype, " - - - NH3 - PO4 GL1 GL2 C1A D2A C3A C4A - - C1B D2B C3B C4B - - "),
98
+ "POPG": (moltype, " - - - GL0 - PO4 GL1 GL2 C1A D2A C3A C4A - - C1B C2B C3B C4B - - "),
99
+ "DOPG": (moltype, " - - - GL0 - PO4 GL1 GL2 C1A D2A C3A C4A - - C1B D2B C3B C4B - - "),
100
+ "POPS": (moltype, " - - - CN0 - PO4 GL1 GL2 C1A D2A C3A C4A - - C1B C2B C3B C4B - - "),
101
+ "DOPS": (moltype, " - - - CN0 - PO4 GL1 GL2 C1A D2A C3A C4A - - C1B D2B C3B C4B - - "),
102
+ "DPSM": (moltype, " - - - NC3 - PO4 AM1 AM2 T1A C2A C3A - - - C1B C2B C3B C4B - - "),
103
+ "DBSM": (moltype, " - - - NC3 - PO4 AM1 AM2 T1A C2A C3A C4A - - C1B C2B C3B C4B C5B - "),
104
+ "BNSM": (moltype, " - - - NC3 - PO4 AM1 AM2 T1A C2A C3A C4A - - C1B C2B C3B C4B C5B C6B"),
105
+ "APG": (moltype, " - - ALA GLX - PO4 GL1 GL2 C1A D2A C3A C4A - - C1B C2B C3B C4B - - "),
106
+ "KPG": (moltype, "LY1 LY2 LY3 GLX - PO4 GL1 GL2 C1A D2A C3A C4A - - C1B C2B C3B C4B - - "),
107
+ # PG for thylakoid membrane
108
+ "OPPG": (moltype, " - - - GL0 - PO4 GL1 GL2 C1A C2A C3A C4A - - C1B D2B C3B C4B - - "),
109
+ # PG for thylakoid membrane of spinach (PPT with a trans-unsaturated bond at sn1 and a triple-unsaturated bond at sn2,
110
+ # and PPG with a transunsaturated bond at sn1 and a palmitoyl tail at sn2)
111
+ "JPPG": (moltype, " - - - GL0 - PO4 GL1 GL2 C1A C2A C3A C4A - - D1B C2B C3B C4B - - "),
112
+ "JFPG": (moltype, " - - - GL0 - PO4 GL1 GL2 C1A D2A D3A D4A - - D1B C2B C3B C4B - - "),
113
+ ## Monoacylglycerol
114
+ "GMO": (moltype, " - - - - - - GL1 GL2 C1A C2A D3A C4A C5A - - - - - - - "),
115
+ ## Templates using the old lipid names and definitions
116
+ "DHPC.o": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A C2A - - - - C1B C2B - - - - "),
117
+ "DMPC.o": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A C2A C3A - - - C1B C2B C3B - - - "),
118
+ "DSPC.o": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A C2A C3A C4A C5A - C1B C2B C3B C4B C5B - "),
119
+ "POPC.o": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A C2A C3A C4A - - C1B C2B D3B C4B C5B - "),
120
+ "DOPC.o": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A C2A D3A C4A C5A - C1B C2B D3B C4B C5B - "),
121
+ "DUPC.o": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A D2A D3A C4A - - C1B D2B D3B C4B - - "),
122
+ "DEPC.o": (moltype, " - - - NC3 - PO4 GL1 GL2 C1A C2A C3A D4A C5A C6A C1B C2B C3B D4B C5B C6B"),
123
+ "DHPE.o": (moltype, " - - - NH3 - PO4 GL1 GL2 C1A C2A - - - - C1B C2B - - - - "),
124
+ "DLPE.o": (moltype, " - - - NH3 - PO4 GL1 GL2 C1A C2A C3A - - - C1B C2B C3B - - - "),
125
+ "DMPE.o": (moltype, " - - - NH3 - PO4 GL1 GL2 C1A C2A C3A - - - C1B C2B C3B - - - "),
126
+ "DSPE.o": (moltype, " - - - NH3 - PO4 GL1 GL2 C1A C2A C3A C4A C5A - C1B C2B C3B C4B C5B - "),
127
+ "POPE.o": (moltype, " - - - NH3 - PO4 GL1 GL2 C1A C2A C3A C4A - - C1B C2B D3B C4B C5B - "),
128
+ "DOPE.o": (moltype, " - - - NH3 - PO4 GL1 GL2 C1A C2A D3A C4A C5A - C1B C2B D3B C4B C5B - "),
129
+ "PPCS.o": (moltype, " - - - NC3 - PO4 AM1 AM2 C1A C2A C3A C4A - - D1B C2B C3B C4B - - "),
130
+ "DOPG.o": (moltype, " - - - GL0 - PO4 GL1 GL2 C1A C2A D3A C4A C5A - C1B C2B D3B C4B C5B - "),
131
+ "POPG.o": (moltype, " - - - GL0 - PO4 GL1 GL2 C1A C2A C3A C4A - - C1B C2B D3B C4B C5B - "),
132
+ "DOPS.o": (moltype, " - - - CN0 - PO4 GL1 GL2 C1A C2A D3A C4A C5A - C1B C2B D3B C4B C5B - "),
133
+ "POPS.o": (moltype, " - - - CN0 - PO4 GL1 GL2 C1A C2A C3A C4A - - C1B C2B D3B C4B C5B - "),
134
+ "CPG.o": (moltype, " - - - GL0 - PO4 GL1 GL2 C1A C2A C3A C4A - - C1B C2B D3B C4B - - "),
135
+ "PPG.o": (moltype, " - - - GL0 - PO4 GL1 GL2 C1A C2A C3A C4A - - D1B C2B C3B C4B - - "),
136
+ "PPT.o": (moltype, " - - - GL0 - PO4 GL1 GL2 C1A D2A D3A D4A - - D1B C2B C3B C4B - - "),
137
+ "DSMG.o": (moltype, " - - - C6 C4 C1 GL1 GL2 C1A C2A C3A C4A C5A - C1B C2B C3B C4B C5B - "),
138
+ "DSDG.o": (moltype, "C61 C41 C11 C62 C42 C12 GL1 GL2 C1A C2A C3A C4A C5A - C1B C2B C3B C4B C5B - "),
139
+ "DSSQ.o": (moltype, " - - S6 C6 C4 C1 GL1 GL2 C1A C2A C3A C4A C5A - C1B C2B C3B C4B C5B - "),
140
+ })
141
+
142
+
143
+
144
+ # HII fix for PI templates and new templates PI(s) with diffrent tails, PO-PIP1(3) and POPIP2(4,5)
145
+ #Prototopology for phosphatidylinositol type lipids 5,6,7 are potentail phosphates (PIP1,PIP2 and PIP3)
146
+ # 1,2,3 - is the inositol and 4 is the phosphate that links to the tail part.
147
+ # 5
148
+ # \
149
+ # 6-2-1-4-8--10-11-12-13-14-15
150
+ # |/ |
151
+ # 7-3 9--16-17-18-19-20-21
152
+ moltype = "INOSITOLLIPIDS"
153
+ lipidsx[moltype] = ( .5, .5, 0, 0, 1, .5, 0, 0, .5, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1)
154
+ lipidsy[moltype] = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
155
+ lipidsz[moltype] = ( 8, 9, 9, 7, 10, 10, 10, 6, 6, 5, 4, 3, 2, 1, 0, 5, 4, 3, 2, 1, 0)
156
+ lipidsa.update({ # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
157
+ "DPPI": (moltype, " C1 C2 C3 CP - - - GL1 GL2 C1A C2A C3A C4A - - C1B C2B C3B C4B - - "),
158
+ "POPI": (moltype, " C1 C2 C3 CP - - - GL1 GL2 C1A D2A C3A C4A - - C1B C2B C3B C4B - - "),
159
+ "PIPI": (moltype, " C1 C2 C3 CP - - - GL1 GL2 C1A D2A D3A C4A - - C1B C2B C3B C4B - - "),
160
+ "PAPI": (moltype, " C1 C2 C3 CP - - - GL1 GL2 D1A D2A D3A D4A C5A - C1B C2B C3B C4B - - "),
161
+ "PUPI": (moltype, " C1 C2 C3 CP - - - GL1 GL2 D1A D2A D3A D4A D5A - C1B C2B C3B C4B - - "),
162
+ "POP1": (moltype, " C1 C2 C3 CP P1 - - GL1 GL2 C1A C2A D3A C4A - - C1B C2B C3B C4B - - "),
163
+ "POP2": (moltype, " C1 C2 C3 CP P1 P2 - GL1 GL2 C1A C2A D3A C4A - - C1B C2B C3B C4B - - "),
164
+ "POP3": (moltype, " C1 C2 C3 CP P1 P2 P3 GL1 GL2 C1A C2A D3A C4A - - C1B C2B C3B C4B - - "),
165
+ ## Templates using the old lipid names and definitions
166
+ "PI.o" : (moltype, " C1 C2 C3 CP - - - GL1 GL2 C1A C2A C3A C4A - - CU1 CU2 CU3 CU4 CU5 - "),
167
+ "PI34.o": (moltype, " C1 C2 C3 CP PO1 PO2 - GL1 GL2 C1A C2A C3A C4A - - CU1 CU2 CU3 CU4 CU5 - "),
168
+ })
169
+
170
+
171
+ #Prototopology for longer and branched glycosil and ceramide based glycolipids
172
+ #
173
+ # 17-15-14-16
174
+ # |/
175
+ # 13
176
+ # |
177
+ # 12-10-9-7-6-4-3-1--18--20-21-22-23-24
178
+ # |/ |/ |/ |/ |
179
+ # 11 8 5 2 19--25-26-27-28-29
180
+ moltype = "GLYCOLIPIDS"
181
+ lipidsx[moltype] = ( 0, .5, 0, 0, .5, 0, 0, .5, 0, 0, .5, 0, 0, 0, 0, 0, 0, 0, .5, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1)
182
+ lipidsy[moltype] = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, .5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
183
+ lipidsz[moltype] = ( 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13, 13, 10, 9, 10, 8, 11, 5, 5, 4, 3, 2, 1, 0, 4, 3, 2, 1, 0)
184
+ lipidsa.update({ # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
185
+ "DPG1": (moltype, "GM1 GM2 GM3 GM4 GM5 GM6 GM7 GM8 GM9 GM10 GM11 GM12 GM13 GM14 GM15 GM16 GM17 AM1 AM2 T1A C2A C3A - - - C1B C2B C3B C4B - - "),
186
+ "DXG1": (moltype, "GM1 GM2 GM3 GM4 GM5 GM6 GM7 GM8 GM9 GM10 GM11 GM12 GM13 GM14 GM15 GM16 GM17 AM1 AM2 T1A C2A C3A C4A C5A - C1B C2B C3B C4B C5B C6B"),
187
+ "PNG1": (moltype, "GM1 GM2 GM3 GM4 GM5 GM6 GM7 GM8 GM9 GM10 GM11 GM12 GM13 GM14 GM15 GM16 GM17 AM1 AM2 T1A C2A C3A - - - C1B C2B C3B D4B C5B C6B"),
188
+ "XNG1": (moltype, "GM1 GM2 GM3 GM4 GM5 GM6 GM7 GM8 GM9 GM10 GM11 GM12 GM13 GM14 GM15 GM16 GM17 AM1 AM2 T1A C2A C3A C4A C5A - C1B C2B C3B D4B C5B C6B"),
189
+ "DPG3": (moltype, "GM1 GM2 GM3 GM4 GM5 GM6 - - - - - - GM13 GM14 GM15 GM16 GM17 AM1 AM2 T1A C2A C3A - - - C1B C2B C3B C4B - - "),
190
+ "DXG3": (moltype, "GM1 GM2 GM3 GM4 GM5 GM6 - - - - - - GM13 GM14 GM15 GM16 GM17 AM1 AM2 T1A C2A C3A C4A C5A - C1B C2B C3B C4B C5B C6B"),
191
+ "PNG3": (moltype, "GM1 GM2 GM3 GM4 GM5 GM6 - - - - - - GM13 GM14 GM15 GM16 GM17 AM1 AM2 T1A C2A C3A - - - C1B C2B C3B D4B C5B C6B"),
192
+ "XNG3": (moltype, "GM1 GM2 GM3 GM4 GM5 GM6 - - - - - - GM13 GM14 GM15 GM16 GM17 AM1 AM2 T1A C2A C3A C4A C5A - C1B C2B C3B D4B C5B C6B"),
193
+ "DPCE": (moltype, " - - - - - - - - - - - - - - - - - AM1 AM2 T1A C2A C3A - - C1B C2B C3B C4B - "),
194
+ "DPGS": (moltype, " C1 C2 C3 - - - - - - - - - - - - - - AM1 AM2 T1A C2A C3A - - C1B C2B C3B C4B - "),
195
+ "DPMG": (moltype, " C1 C2 C3 - - - - - - - - - - - - - - GL1 GL2 C1A C2A C3A C4A - C1B C2B C3B C4B - "),
196
+ "DPSG": (moltype, " S1 C1 C2 C3 - - - - - - - - - - - - - GL1 GL2 C1A C2A C3A C4A - C1B C2B C3B C4B - "),
197
+ "DPGG": (moltype, "GB2 GB3 GB1 GA1 GA2 GA3 - - - - - - - - - - - GL1 GL2 C1A C2A C3A C4A - C1B C2B C3B C4B - "),
198
+ #lipids for thylakoid membrane of cyanobacteria: oleoyl tail at sn1 and palmiotyl chain at sn2. SQDG no double bonds
199
+ "OPMG": (moltype, " C1 C2 C3 - - - - - - - - - - - - - - GL1 GL2 C1A C2A C3A C4A - C1B D2B C3B C4B - "),
200
+ "OPSG": (moltype, " S1 C1 C2 C3 - - - - - - - - - - - - - GL1 GL2 C1A C2A C3A C4A - C1B D2B C3B C4B - "),
201
+ "OPGG": (moltype, "GB2 GB3 GB1 GA1 GA2 GA3 - - - - - - - - - - - GL1 GL2 C1A C2A C3A C4A - C1B D2B C3B C4B - "),
202
+ #lipids for thylakoid membrane of spinach: for the *T both chains are triple unsaturated and the *G have a triple unsaturated chain at sn1 and a palmitoyl chain at sn2.
203
+ "FPMG": (moltype, " C1 C2 C3 - - - - - - - - - - - - - - GL1 GL2 C1A C2A C3A C4A - C1B D2B D3B D4B - "),
204
+ "DFMG": (moltype, " C1 C2 C3 - - - - - - - - - - - - - - GL1 GL2 C1A D2A D3A D4A - C1B D2B D3B D4B - "),
205
+ "FPSG": (moltype, " S1 C1 C2 C3 - - - - - - - - - - - - - GL1 GL2 C1A C2A C3A C4A - C1B D2B D3B D4B - "),
206
+ "FPGG": (moltype, "GB2 GB3 GB1 GA1 GA2 GA3 - - - - - - - - - - - GL1 GL2 C1A C2A C3A C4A - C1B D2B D3B D4B - "),
207
+ "DFGG": (moltype, "GB2 GB3 GB1 GA1 GA2 GA3 - - - - - - - - - - - GL1 GL2 C1A D2A D3A D4A - C1B D2B D3B D4B - "),
208
+ ## Templates using the old lipid names and definitions
209
+ "GM1.o" : (moltype, "GM1 GM2 GM3 GM4 GM5 GM6 GM7 GM8 GM9 GM10 GM11 GM12 GM13 GM14 GM15 GM16 GM17 AM1 AM2 C1A C2A C3A C4A C5A C1B C2B C3B C4B - "),
210
+ "DGDG.o": (moltype, "GB2 GB3 GB1 GA1 GA2 GA3 - - - - - - - - - - - GL1 GL2 C1A C2A C3A C4A - C1B C2B C3B C4B - "),
211
+ "MGDG.o": (moltype, " C1 C2 C3 - - - - - - - - - - - - - - GL1 GL2 C1A C2A C3A C4A - C1B C2B C3B C4B - "),
212
+ "SQDG.o": (moltype, " S1 C1 C2 C3 - - - - - - - - - - - - - GL1 GL2 C1A C2A C3A C4A - C1B C2B C3B C4B - "),
213
+ "CER.o" : (moltype, " - - - - - - - - - - - - - - - - - AM1 AM2 C1A C2A C3A C4A - C1B C2B C3B C4B - "),
214
+ "GCER.o": (moltype, " C1 C2 C3 - - - - - - - - - - - - - - AM1 AM2 C1A C2A C3A C4A - C1B C2B C3B C4B - "),
215
+ "DPPI.o": (moltype, " C1 C2 C3 - CP - - - - - - - - - - - - GL1 GL2 C1A C2A C3A C4A - C1B C2B C3B C4B - "),
216
+ })
217
+
218
+
219
+ moltype = "QUINONES"
220
+ lipidsx[moltype] = ( 0, .5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
221
+ lipidsy[moltype] = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
222
+ lipidsz[moltype] = ( 6, 7, 7, 5.5, 5, 4.5, 4, 3.5, 2.5, 2, 1.5, 1)
223
+ lipidsa.update({ # 1 2 3 4 5 6 7 8 9 10 11 12
224
+ "PLQ": (moltype, " PLQ3 PLQ2 PLQ1 PLQ4 PLQ5 PLQ6 PLQ7 PLQ8 PLQ9 PLQ10 PLQ11 PLQ12"),
225
+ })
226
+
227
+ moltype = "CYSTEINES"
228
+ lipidsx[moltype] = ( 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1)
229
+ lipidsy[moltype] = ( 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0)
230
+ lipidsz[moltype] = ( 6, 7, 6, 6, 5, 4, 3, 2, 1, 0, 5, 4, 3, 2, 1, 0, 7, 6, 6, 5, 4, 3, 2, 1, 0)
231
+ lipidsa.update({ # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
232
+ "CYST": (moltype, " BB SC1 GL1 GL2 C1A D2A C3A C4A - - C1B C2B C3B C4B - - - - - C1C C2C C3C C4C - -"),
233
+ "CYSD": (moltype, " BB SC1 GL1 GL2 C1A D2A C3A C4A - - C1B C2B C3B C4B - - - - - - - - - - -"),
234
+ })
235
+
236
+ # Prototopology for cardiolipins
237
+ #
238
+ # 4-11-12-13-14-15-16
239
+ # |
240
+ # 2---3--5--6--7--8--9-10
241
+ # /
242
+ # 1
243
+ # \
244
+ # 17-18-20-21-22-23-24-25
245
+ # |
246
+ # 19-26-27-28-29-30-31
247
+ #
248
+ moltype = "CARDIOLIPINS"
249
+ lipidsx[moltype] = ( 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
250
+ lipidsy[moltype] = ( 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1)
251
+ lipidsz[moltype] = ( 8, 7, 6, 6, 5, 4, 3, 2, 1, 0, 5, 4, 3, 2, 1, 0, 7, 6, 6, 5, 4, 3, 2, 1, 0, 5, 4, 3, 2, 1, 0)
252
+ lipidsa.update({ # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
253
+ "CDL0": (moltype, "GL5 PO41 GL1 GL2 C1A D2A C3A C4A - - C1B C2B C3B C4B - - PO42 GL3 GL4 C1C D2C D3C C4C - - C1D C2D C3D C4D - -"), # Warning not the same names is in .itp
254
+ "CDL1": (moltype, "GL5 PO41 GL1 GL2 C1A D2A C3A C4A - - C1B C2B C3B C4B - - PO42 GL3 GL4 C1C D2C D3C C4C - - C1D C2D C3D C4D - -"), # Warning not the same names is in .itp
255
+ "CDL2": (moltype, "GL5 PO41 GL1 GL2 C1A D2A C3A C4A - - C1B C2B C3B C4B - - PO42 GL3 GL4 C1C D2C D3C C4C - - C1D C2D C3D C4D - -"), # Warning not the same names is in .itp
256
+ "CL4P": (moltype, "GL5 PO41 GL1 GL2 C1A D2A C3A C4A - - C1B C2B C3B C4B - - PO42 GL3 GL4 C1C D2C C3C C4C - - C1D C2D C3D C4D - -"),
257
+ "CL4M": (moltype, "GL5 PO41 GL1 GL2 C1A D2A C3A - - - C1B C2B C3B - - - PO42 GL3 GL4 C1C D2C C3C - - - C1D C2D C3D - - -"),
258
+ "CARD": (moltype, "GL0 PO1 GL1 GL2 C1A D2A C3A C4A - - C1B C2B C3B C4B - - PO2 GL3 GL4 C1C D2C C3C C4C - - C1D C2D C3D C4D - -"),
259
+ ## Templates using the old lipid names and definitions
260
+ "CL4.o" : (moltype, "GL5 PO41 GL1 GL2 C1A C2A D3A C4A C5A - C1B C2B D3B C4B C5B - PO42 GL3 GL4 C1C C2C D3C C4C C5C - C1D C2D D3D C4D C5D -"),
261
+ "CL4O.o": (moltype, "GL5 PO41 GL1 GL2 C1A C2A D3A C4A C5A - C1B C2B D3B C4B C5B - PO42 GL3 GL4 C1C C2C D3C C4C C5C - C1D C2D D3D C4D C5D -"),
262
+ })
263
+
264
+
265
+
266
+ moltype = "LPS"
267
+ lipidsx[moltype] = (-7.97, -8.52, -7.94, -8.14, -8.52, -7.87, -8.75, -8.77, -8.61, -8.58, -8.58, -7.69, -7.53, -7.47, -7.58, -7.45, -7.46, -7.37, -7.42, -6.88, -7.56, -7.11, -7.53, -7.26, -7.32, -7.42, -7.54, -8.07, -8.19, -8.44, -7.19, -6.72, -6.82, -6.81, -7.53, -7.74, -7.88, -7.67, -7.41, -7.86, -7.65, -7.51, -7.25, -7.68, -7.39, -7.84, -7.63, -7.18, -7.29)
268
+ lipidsy[moltype] = (0.73, 0.52, 0.60, 0.62, 0.07, 0.51, 0.27, 0.54, 0.70, 0.96, 1.25, 0.51, 0.52, 0.58, 0.76, 0.49, 0.22, 0.10, 0.27, -0.31, -0.04, 0.72, -0.20, -0.29, -0.41, -0.51, -0.60, -0.35, -0.32, -0.13, 1.00, 1.26, 1.42, 1.75, 1.32, 1.56, 1.78, 0.33, 0.52, 0.52, 0.45, 0.85, 0.02, 0.31, -0.05, 0.19, 0.15, 0.58, -0.14)
269
+ lipidsz[moltype] = (5.76, 5.32, 5.25, 5.44, 5.95, 4.51, 4.75, 4.25, 3.59, 2.78, 1.97, 4.00, 3.31, 2.47, 1.63, 6.12, 6.82, 6.30, 6.41, 6.10, 5.61, 5.60, 5.04, 4.41, 3.69, 2.97, 2.11, 4.54, 3.72, 2.80, 5.03, 4.58, 3.76, 2.85, 4.46, 3.68, 2.75, 7.59, 8.18, 8.03, 7.93, 7.36, 8.26, 8.81, 9.30, 9.27, 9.13, 8.95, 9.81)
270
+ lipidsa.update({ "KLA":(moltype, "ZM1 ZM2 ZM3 VS1 PO1 ZM4 ZM5 CF C1F C2F C3F CE C1E C2E C3E GM1 GM2 GM3 VS2 PO2 GM4 GM5 CAB C1A C2A C3A C4A C1B C2B C3B CCD C1C C2C C3C C1D C2D C3D KR1 KR2 KR3 VS3 KS1 KS2 KR4 KR5 KR6 VS4 KS3 KS4")})
271
+
272
+ moltype = "LPS2"
273
+ lipidsx[moltype] = ( 0, 0, 1, 0, 0, 0, 0, 1, 2, 2, 1, 2, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 3, 3, 3, 1, 2, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 2, 2, 2, 2, 0, 1, 0, 0, 1, 1, 1, 1, 2, 1, 1, 1, 0, 0, 0 )
274
+ lipidsy[moltype] = ( 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 2, 1, 1, 1, 1, 2, 3, 2, 2, 2, 3, 3, 3, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0 )
275
+ lipidsz[moltype] = ( 5, 5, 5, 6, 5, 6, 7, 5, 5, 5, 5, 5, 7, 8, 4, 3, 2, 1, 4, 3, 2, 1, 0, 4, 3, 2, 1, 0, 3, 2, 1, 0, 4, 4, 3, 2, 1, 0, 3, 3, 2, 1, 0, 3, 2, 1, 9, 9, 8, 10, 11, 11, 12, 11, 12, 12, 13, 13, 13, 13, 13, 12, 14, 14, 14, 15, 16, 16, 15, 15, 16, 16, 17, 18, 17, 17, 18, 17 )
276
+ lipidsa.update({ # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 )
277
+ "PGIN": (moltype, " GM1 GM2 GM3 GM4 PO1 - - GM6 GM7 GM8 GM9 - - - GL1 C1A C2A C3A GL2 C1B C2B C3B C4B GL3 C1C C2C C3C C4C C1D C2D C3D C4D GL4 - C1E C2E C3E - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
278
+ "BPER": (moltype, " GM1 GM2 GM3 GM4 PO1 - - GM6 GM7 GM8 GM9 PO2 - - GL1 C1A C2A - GL2 C1B C2B - - GL3 C1C C2C C3C - C1D C2D C3D - GL4 - C1E C2E C3E - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
279
+ "BFRA": (moltype, " GM1 GM2 GM3 GM4 PO1 - - GM6 GM7 GM8 GM9 - - - GL1 C1A C2A C3A GL2 C1B C2B C3B - GL3 C1C C2C C3C C4C C1D C2D C3D - GL4 - C1E C2E C3E C4E - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
280
+ "CTRA": (moltype, " GM1 GM2 GM3 GM4 PO1 - - GM6 GM7 GM8 GM9 PO2 - - GL1 C1A C2A C3A GL2 C1B C2B C3B - GL3 C1C C2C C3C C4C C1D C2D C3D C4D GL4 - C1E C2E C3E - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
281
+ "CJEJ": (moltype, " GM1 GM2 GM3 GM4 PO1 - - GM6 GM7 GM8 GM9 PO2 - - GL1 C1A C2A - GL2 C1B C2B C3B - GL3 C1C C2C C3C - C1D C2D C3D C4D GL4 GL5 C1E C2E C3E - C1F - C2F C3F C4F - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
282
+ "HPYL": (moltype, " GM1 GM2 GM3 GM4 PO1 - - GM6 GM7 GM8 GM9 - - - GL1 C1A C2A C3A GL2 C1B C2B C3B C4B GL3 C1C C2C C3C C4C C1D C2D C3D C4D - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
283
+ "NMEN": (moltype, " GM1 GM2 GM3 GM4 PO1 PO2 QD1 GM6 GM7 GM8 GM9 PO3 PO4 QD2 GL1 C1A C2A C3A - C1B C2B C3B - GL2 C1C C2C C3C - GL3 C1D C2D C3D - - C1E C2E C3E - GL4 - C1F C2F C3F - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
284
+ "SMIN": (moltype, " GM1 GM2 GM3 GM4 PO1 - - GM6 GM7 GM8 GM9 PO2 - - GL1 GL2 C1A C2A - C1B C2B C3B C4B GL3 C1C C2C C3C - GL4 C1D C2D C3D - - C1E C2E C3E - GL5 GL6 C1F C2F C3F C1G C2G C3G - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
285
+ })
286
+
287
+
288
+ # Prototopology for mycolic acid(s)
289
+ #
290
+ # 1--2--3--4--5--6--7--8
291
+ # |
292
+ # 16-15-14-13-12-11-10--9
293
+ # |
294
+ # 17-18-19-20-21-22-23-24
295
+ # /
296
+ # 32-31-30-29-28-27-25-26
297
+ #
298
+
299
+ moltype = "MYCOLIC ACIDS"
300
+ lipidsx[moltype] = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
301
+ lipidsy[moltype] = ( 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0)
302
+ lipidsz[moltype] = ( 7, 6, 5, 4, 3, 2, 1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0, 1, 0, 2, 3, 4, 5, 6, 7)
303
+ lipidsa.update({ # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
304
+ "AMA": (moltype, " - - - C1A C2A C3A C4A C5A M1A C1B C2B C3B C4B - - - - - M1B C1C C2C C3C - - COH OOH C1D C2D C3D C4D C5D C6D"),
305
+ "AMA.w": (moltype, " - - - C1A C2A C3A C4A C5A M1A C1B C2B C3B C4B - - - - - M1B C1C C2C C3C - - COH OOH C1D C2D C3D C4D C5D C6D"),
306
+ "KMA": (moltype, " - - - C1A C2A C3A C4A C5A M1A C1B C2B C3B C4B - - - - - M1B C1C C2C C3C - - COH OOH C1D C2D C3D C4D C5D C6D"),
307
+ "MMA": (moltype, " - - - C1A C2A C3A C4A C5A M1A C1B C2B C3B C4B - - - - - M1B C1C C2C C3C - - COH OOH C1D C2D C3D C4D C5D C6D"),
308
+ })
309
+
310
+
311
+ # Sterols
312
+ moltype = "sterol"
313
+ lipidsx[moltype] = ( 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0)
314
+ lipidsy[moltype] = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
315
+ lipidsz[moltype] = ( 0, 0, 0, 0, 0, 0, 5.3,4.5,3.9,3.3, 3 ,2.6,1.4, 0, 0, 0, 0, 0)
316
+ lipidsa.update({
317
+ "CHOL": (moltype, " - - - - - - ROH R1 R2 R3 R4 R5 C1 C2 - - - - "),
318
+ "ERGO": (moltype, " - - - - - - ROH R1 R2 R3 R4 R5 C1 C2 - - - - "),
319
+ })
320
+
321
+
322
+ # Hopanoids
323
+ moltype = "Hopanoids"
324
+ lipidsx[moltype] = ( 0, 0, 0, 0, 0.5,-0.5, 0, 0, 0.5, 0.5, 0, 0, 0, 0, 0, 0, 0, 0)
325
+ lipidsy[moltype] = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
326
+ lipidsz[moltype] = ( 0, 0, 0, 0, 0.5, 1.4, 2.6, 3, 3.3, 3.9, 4.5, 5.0, 5.5, 6.0, 0, 0, 0, 0)
327
+ lipidsa.update({
328
+ "HOPR": (moltype, " - - - R1 R2 R3 R4 R5 R6 R7 R8 - - - - - - - "),
329
+ "HHOP": (moltype, " - - - R1 R2 R3 R4 R5 R6 R7 R8 C1 - - - - - - "),
330
+ "HDPT": (moltype, " - - - R1 R2 R3 R4 R5 R6 R7 R8 C1 - - - - - - "),
331
+ "HBHT": (moltype, " - - - R1 R2 R3 R4 R5 R6 R7 R8 C1 C2 C3 - - - - "),
332
+ })
333
+
334
+
335
+ #Higher lipids in a different order
336
+ moltype = "Isoprenyls-m3-further"
337
+ lipidsx[moltype] = ( 0, 0.5, 0, 0, 0, 0, 0,0.5, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 2, 1,1.5, 2, 2, 2, 1, 1, 2,2.5, 2,2.5, 1, 1, 0, 0, 0, 1, 0, 1, 2, 1, 1.5, 2, 2, 2, 1, 1, 2,2.5, 2,2.5, 1, 1, 0, 0, 0, 1, 0, 1, 2, 1,1.5, 2, 2, 2, 1, 1, 2,1.5, 2,2.5, 1, 1, 0, 0, 0, 1, 0, 1, 2, 1,1.5, 2, 2, 2, 1, 1, 2,2.5, 2,2.5, 1, 1, 0, 0, 0, 1, 0, 1, 2, 1,1.5, 2, 2, 2, 1, 1, 2,2.5, 2,2.5, 1, 1, 0, 0, 0, 1, 0, 1, 2, 1,1.5, 2, 2, 2, 1, 1, 2,2.5, 2,2.5, 1, 1, 0, 0, 0, 1, 0, 1, 2, 1,1.5, 2, 2, 2, 1, 1, 2,2.5, 2,2.5, 1, 1, 0, 0, 0, 1, 0, 1, 2, 1,1.5, 2, 2, 2, 1, 1, 2,2.5, 2,2.5, 1, 1, 0, 0, 0, 1, 0, 1, 2, 1,1.5, 2, 2, 2, 1, 1, 2,2.5, 2,2.5, 1, 1, 0, 0, 0, 1, 0, 1, 2, 1,1.5, 2, 2, 2, 1, 1, 2,2.5, 2,2.5, 1, 1, 0, 0, 0, 1, 0, 1, 2, 1,1.5, 2, 2, 2, 1, 1, 2,2.5, 2,2.5)
338
+ lipidsy[moltype] = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 2,1.5, 2, 2, 1, 2, 2, 1,1.5, 2,2.5, 1, 0, 1, 0, 0, 0, 1, 1, 1, 2, 1.5, 2, 2, 1, 2, 2, 1,1.5, 2,2.5, 1, 0, 1, 0, 0, 0, 1, 1, 1, 2,1.5, 2, 2, 1, 2, 2, 1,1.5, 2,2.5, 1, 0, 1, 0, 0, 0, 1, 1, 1, 2,1.5, 2, 2, 1, 2, 2, 1,1.5, 2,2.5, 1, 0, 1, 0, 0, 0, 1, 1, 1, 2,1.5, 2, 2, 1, 2, 2, 1,1.5, 2,2.5, 1, 0, 1, 0, 0, 0, 1, 1, 1, 2,1.5, 2, 2, 1, 2, 2, 1,1.5, 2,2.5, 1, 0, 1, 0, 0, 0, 1, 1, 1, 2,1.5, 2, 2, 1, 2, 2, 1,1.5, 2,2.5, 1, 0, 1, 0, 0, 0, 1, 1, 1, 2,1.5, 2, 2, 1, 2, 2, 1,1.5, 2,2.5, 1, 0, 1, 0, 0, 0, 1, 1, 1, 2,1.5, 2, 2, 1, 2, 2, 1,1.5, 2,2.5, 1, 0, 1, 0, 0, 0, 1, 1, 1, 2,1.5, 2, 2, 1, 2, 2, 1,1.5, 2,2.5, 1, 0, 1, 0, 0, 0, 1, 1, 1, 2,1.5, 2, 2, 1, 2, 2, 1,1.5, 2,2.5)
339
+ lipidsz[moltype] = ( 8, 7, 6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 11, 11, 11, 11, 11, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, 14, 14, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 17, 17, 17, 17, 17, 19, 19, 19, 19, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 20, 20, 20, 20, 20, 22, 22, 22, 22, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 23, 23, 23, 23, 23, 25, 25, 25, 25, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 26, 26, 26, 26, 26, 28, 28, 28, 28, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 29, 29, 29, 29, 29, 31, 31, 31, 31, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 32, 32, 32, 32, 32, 34, 34, 34, 34, 33, 33, 33, 33, 33, 33, 33, 33, 34, 34, 34, 35, 35, 35, 35, 35, 37, 37, 37, 37, 36, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 38, 38, 38, 38, 38, 40, 40, 40, 40, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 41, 41, 41, 41, 41)
340
+ lipidsa.update({ # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
341
+ # "LIP2": (moltype,"PO1 PO2 CP1 CP2 CP3 CP4 CP5 CP6 CP7 CP8 CP9 CP10 CP11 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
342
+ "LIP4": (moltype,"PO1 PO2 CP1 CP2 CP3 CP4 CP5 CP6 CP7 CP8 CP9 CP10 CP11 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 B39 B40 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
343
+ "LIP6": (moltype,"PO1 PO2 CP1 CP2 CP3 CP4 CP5 CP6 CP7 CP8 CP9 CP10 CP11 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 B39 B40 B41 B42 B43 B44 B45 B46 B47 B48 B49 B50 B51 B52 B53 B54 B55 B56 B57 B58 B59 B60 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
344
+ "LIP8": (moltype,"PO1 PO2 CP1 CP2 CP3 CP4 CP5 CP6 CP7 CP8 CP9 CP10 CP11 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 B39 B40 B41 B42 B43 B44 B45 B46 B47 B48 B49 B50 B51 B52 B53 B54 B55 B56 B57 B58 B59 B60 B61 B62 B63 B64 B65 B66 B67 B68 B69 B70 B71 B72 B73 B74 B75 B76 B77 B78 B79 B80 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
345
+ "LI10": (moltype,"PO1 PO2 CP1 CP2 CP3 CP4 CP5 CP6 CP7 CP8 CP9 CP10 CP11 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 B39 B40 B41 B42 B43 B44 B45 B46 B47 B48 B49 B50 B51 B52 B53 B54 B55 B56 B57 B58 B59 B60 B61 B62 B63 B64 B65 B66 B67 B68 B69 B70 B71 B72 B73 B74 B75 B76 B77 B78 B79 B80 B81 B82 B83 B84 B85 B86 B87 B88 B89 B90 B91 B92 B93 B94 B95 B96 B97 B98 B99 B00 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
346
+ "LI12": (moltype,"PO1 PO2 CP1 CP2 CP3 CP4 CP5 CP6 CP7 CP8 CP9 CP10 CP11 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 B39 B40 B41 B42 B43 B44 B45 B46 B47 B48 B49 B50 B51 B52 B53 B54 B55 B56 B57 B58 B59 B60 B61 B62 B63 B64 B65 B66 B67 B68 B69 B70 B71 B72 B73 B74 B75 B76 B77 B78 B79 B80 B81 B82 B83 B84 B85 B86 B87 B88 B89 B90 B91 B92 B93 B94 B95 B96 B97 B98 B99 B00 B01 B02 B03 B04 B05 B06 B07 B08 B09 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
347
+ "LI14": (moltype,"PO1 PO2 CP1 CP2 CP3 CP4 CP5 CP6 CP7 CP8 CP9 CP10 CP11 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 B39 B40 B41 B42 B43 B44 B45 B46 B47 B48 B49 B50 B51 B52 B53 B54 B55 B56 B57 B58 B59 B60 B61 B62 B63 B64 B65 B66 B67 B68 B69 B70 B71 B72 B73 B74 B75 B76 B77 B78 B79 B80 B81 B82 B83 B84 B85 B86 B87 B88 B89 B90 B91 B92 B93 B94 B95 B96 B97 B98 B99 B00 B01 B02 B03 B04 B05 B06 B07 B08 B09 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 B39 B40 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
348
+ "LI16": (moltype,"PO1 PO2 CP1 CP2 CP3 CP4 CP5 CP6 CP7 CP8 CP9 CP10 CP11 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 B39 B40 B41 B42 B43 B44 B45 B46 B47 B48 B49 B50 B51 B52 B53 B54 B55 B56 B57 B58 B59 B60 B61 B62 B63 B64 B65 B66 B67 B68 B69 B70 B71 B72 B73 B74 B75 B76 B77 B78 B79 B80 B81 B82 B83 B84 B85 B86 B87 B88 B89 B90 B91 B92 B93 B94 B95 B96 B97 B98 B99 B00 B01 B02 B03 B04 B05 B06 B07 B08 B09 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 B39 B40 B41 B42 B43 B44 B45 B46 B47 B48 B49 B50 B51 B52 B53 B54 B55 B56 B57 B58 B59 B60 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
349
+ "LI18": (moltype,"PO1 PO2 CP1 CP2 CP3 CP4 CP5 CP6 CP7 CP8 CP9 CP10 CP11 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 B39 B40 B41 B42 B43 B44 B45 B46 B47 B48 B49 B50 B51 B52 B53 B54 B55 B56 B57 B58 B59 B60 B61 B62 B63 B64 B65 B66 B67 B68 B69 B70 B71 B72 B73 B74 B75 B76 B77 B78 B79 B80 B81 B82 B83 B84 B85 B86 B87 B88 B89 B90 B91 B92 B93 B94 B95 B96 B97 B98 B99 B00 B01 B02 B03 B04 B05 B06 B07 B08 B09 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 B39 B40 B41 B42 B43 B44 B45 B46 B47 B48 B49 B50 B51 B52 B53 B54 B55 B56 B57 B58 B59 B60 B61 B62 B63 B64 B65 B66 B67 B68 B69 B70 B71 B72 B73 B74 B75 B76 B77 B78 B79 B80 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "),
350
+ "LI20": (moltype,"PO1 PO2 CP1 CP2 CP3 CP4 CP5 CP6 CP7 CP8 CP9 CP10 CP11 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 B39 B40 B41 B42 B43 B44 B45 B46 B47 B48 B49 B50 B51 B52 B53 B54 B55 B56 B57 B58 B59 B60 B61 B62 B63 B64 B65 B66 B67 B68 B69 B70 B71 B72 B73 B74 B75 B76 B77 B78 B79 B80 B81 B82 B83 B84 B85 B86 B87 B88 B89 B90 B91 B92 B93 B94 B95 B96 B97 B98 B99 B00 B01 B02 B03 B04 B05 B06 B07 B08 B09 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 B39 B40 B41 B42 B43 B44 B45 B46 B47 B48 B49 B50 B51 B52 B53 B54 B55 B56 B57 B58 B59 B60 B61 B62 B63 B64 B65 B66 B67 B68 B69 B70 B71 B72 B73 B74 B75 B76 B77 B78 B79 B80 B81 B82 B83 B84 B85 B86 B87 B88 B89 B90 B91 B92 B93 B94 B95 B96 B97 B98 B99 B00 - - - - - - - - - - - - - - - - - - - - "),
351
+ "LI22": (moltype,"PO1 PO2 CP1 CP2 CP3 CP4 CP5 CP6 CP7 CP8 CP9 CP10 CP11 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 B39 B40 B41 B42 B43 B44 B45 B46 B47 B48 B49 B50 B51 B52 B53 B54 B55 B56 B57 B58 B59 B60 B61 B62 B63 B64 B65 B66 B67 B68 B69 B70 B71 B72 B73 B74 B75 B76 B77 B78 B79 B80 B81 B82 B83 B84 B85 B86 B87 B88 B89 B90 B91 B92 B93 B94 B95 B96 B97 B98 B99 B00 B01 B02 B03 B04 B05 B06 B07 B08 B09 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 B39 B40 B41 B42 B43 B44 B45 B46 B47 B48 B49 B50 B51 B52 B53 B54 B55 B56 B57 B58 B59 B60 B61 B62 B63 B64 B65 B66 B67 B68 B69 B70 B71 B72 B73 B74 B75 B76 B77 B78 B79 B80 B81 B82 B83 B84 B85 B86 B87 B88 B89 B90 B91 B92 B93 B94 B95 B96 B97 B98 B99 B00 B01 B02 B03 B04 B05 B06 B07 B08 B09 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 B20"),
352
+ })
353
+
354
+
355
+ # Lists for automatic charge determination
356
+ charges = {"HPPA":-1,"4HPA":-1,"UDP2":-2,"UDP1":-1, "GLYP":-1, "GLYM":-1, "ARG":1, "LYS":1, "ASP":-1, "GLU":-1, "DOPG":-1, "POPG":-1, "DOPS":-1, "POPS":-1, "DSSQ":-1, "KPG":+1, "LIPA":-2, "PGIN":-1, "REMP":-6, "RAMP":-10, "OANT":-10, "CARD":-2, "A2P2":-1, "APM2":-1, "APM6":-1, "LIP2":-4, "LIP4":-6, "LIP6":-8, "LIP8":-10, "LI10":-12, "LI12":-14, "LI14":-16, "LI16":-18, "LI18":-20, "LI20":-22, "LI22":-24,"UPEP":-1,"SPEP":-2,"UUPEP":-1,"KLA":-6}
357
+ ion_charges = {"NA" :1,"CL":-1,"CA":2}
358
+
359
+
360
+ a, b = math.sqrt(2)/20, math.sqrt(2)/60
361
+ ct, st = math.cos(math.pi*109.47/180), math.sin(math.pi*109.47/180) # Tetrahedral
362
+
363
+ # Get a set of coordinates for a solvent particle with a given name
364
+ # Dictionary of solvents; First only those with multiple atoms
365
+ solventParticles = {
366
+ "PW": (("W",(-0.07,0,0)), # Polarizable water
367
+ ("WP",(0.07,0,0)),
368
+ ("WM",(0.07,0,0))),
369
+ "BMW": (("C",(0,0,0)),
370
+ ("Q1",(0.12,0,0)),
371
+ ("Q2",(-0.06,math.cos(math.pi/6)*0.12,0))), # BMW water
372
+ "SPC": (("OW",(0,0,0)), # SPC
373
+ ("HW1",(0.01,0,0)),
374
+ ("HW2",(0.01*ct,0.01*st,0))),
375
+ "SPCM": (("OW",(0,0,0)), # Multiscale/Martini SPC
376
+ ("HW1",(0.01,0,0)),
377
+ ("HW2",(0.01*ct,0.01*st,0)),
378
+ ("vW",(0,0,0))),
379
+ "FG4W": (("OW1",(a,a,a)), # Bundled water
380
+ ("HW11",(a,a-b,a-b)),
381
+ ("HW12",(a,a+b,a+b)),
382
+ ("OW2",(a,-a,-a)),
383
+ ("HW21",(a-b,-a,-a+b)),
384
+ ("HW22",(a+b,-a,-a-b)),
385
+ ("OW3",(-a,-a,a)),
386
+ ("HW31",(-a,-a+b,a-b)),
387
+ ("HW32",(-a,-a-b,a+b)),
388
+ ("OW4",(-a,a,-a)),
389
+ ("HW41",(-a+b,a,-a+b)),
390
+ ("HW42",(-a-b,a,-a-b))),
391
+ "FG4W-MS": (("OW1",(a,a,a)), # Bundled water, multiscaled
392
+ ("HW11",(a,a-b,a-b)),
393
+ ("HW12",(a,a+b,a+b)),
394
+ ("OW2",(a,-a,-a)),
395
+ ("HW21",(a-b,-a,-a+b)),
396
+ ("HW22",(a+b,-a,-a-b)),
397
+ ("OW3",(-a,-a,a)),
398
+ ("HW31",(-a,-a+b,a-b)),
399
+ ("HW32",(-a,-a-b,a+b)),
400
+ ("OW4",(-a,a,-a)),
401
+ ("HW41",(-a+b,a,-a+b)),
402
+ ("HW42",(-a-b,a,-a-b)),
403
+ ("VZ",(0,0,0))),
404
+ "GLUC": (("B1",(-0.11, 0, 0)),
405
+ ("B2",( 0.05, 0.16,0)),
406
+ ("B3",( 0.05,-0.16,0))),
407
+ "FRUC": (("B1",(-0.11, 0, 0)),
408
+ ("B2",( 0.05, 0.16,0)),
409
+ ("B3",( 0.05,-0.16,0))),
410
+ "SUCR": (("B1",(-0.25, 0.25,0)),
411
+ ("B2",(-0.25, 0, 0)),
412
+ ("B3",(-0.25,-0.25,0)),
413
+ ("B4",( 0.25, 0, 0)),
414
+ ("B5",( 0.25, 0.25,0)),
415
+ ("B6",( 0.25,-0.25,0))),
416
+ "MALT": (("B1",(-0.25, 0.25,0)),
417
+ ("B2",(-0.25, 0, 0)),
418
+ ("B3",(-0.25,-0.25,0)),
419
+ ("B4",( 0.25, 0, 0)),
420
+ ("B5",( 0.25, 0.25,0)),
421
+ ("B6",( 0.25,-0.25,0))),
422
+ "CELL": (("B1",(-0.25, 0.25,0)),
423
+ ("B2",(-0.25, 0, 0)),
424
+ ("B3",(-0.25,-0.25,0)),
425
+ ("B4",( 0.25, 0, 0)),
426
+ ("B5",( 0.25, 0.25,0)),
427
+ ("B6",( 0.25,-0.25,0))),
428
+ "KOJI": (("B1",(-0.25, 0.25,0)),
429
+ ("B2",(-0.25, 0, 0)),
430
+ ("B3",(-0.25,-0.25,0)),
431
+ ("B4",( 0.25, 0, 0)),
432
+ ("B5",( 0.25, 0.25,0)),
433
+ ("B6",( 0.25,-0.25,0))),
434
+ "SOPH": (("B1",(-0.25, 0.25,0)),
435
+ ("B2",(-0.25, 0, 0)),
436
+ ("B3",(-0.25,-0.25,0)),
437
+ ("B4",( 0.25, 0, 0)),
438
+ ("B5",( 0.25, 0.25,0)),
439
+ ("B6",( 0.25,-0.25,0))),
440
+ "NIGE": (("B1",(-0.25, 0.25,0)),
441
+ ("B2",(-0.25, 0, 0)),
442
+ ("B3",(-0.25,-0.25,0)),
443
+ ("B4",( 0.25, 0, 0)),
444
+ ("B5",( 0.25, 0.25,0)),
445
+ ("B6",( 0.25,-0.25,0))),
446
+ "LAMI": (("B1",(-0.25, 0.25,0)),
447
+ ("B2",(-0.25, 0, 0)),
448
+ ("B3",(-0.25,-0.25,0)),
449
+ ("B4",( 0.25, 0, 0)),
450
+ ("B5",( 0.25, 0.25,0)),
451
+ ("B6",( 0.25,-0.25,0))),
452
+ "TREH": (("B1",(-0.25, 0.25,0)),
453
+ ("B2",(-0.25, 0, 0)),
454
+ ("B3",(-0.25,-0.25,0)),
455
+ ("B4",( 0.25, 0, 0)),
456
+ ("B5",( 0.25, 0.25,0)),
457
+ ("B6",( 0.25,-0.25,0))),
458
+ # Loose aminoacids
459
+ "GLY": (("BB", ( 0, 0, 0)),),
460
+ "ALA": (("BB", ( 0, 0, 0)),),
461
+ "ASN": (("BB", ( 0.25, 0, 0)),
462
+ ("SC1",(-0.25, 0, 0))),
463
+ "ASP": (("BB", ( 0.25, 0, 0)),
464
+ ("SC1",(-0.25, 0, 0))),
465
+ "GLU": (("BB", ( 0.25, 0, 0)),
466
+ ("SC1",(-0.25, 0, 0))),
467
+ "GLN": (("BB", ( 0.25, 0, 0)),
468
+ ("SC1",(-0.25, 0, 0))),
469
+ "LEU": (("BB", ( 0.25, 0, 0)),
470
+ ("SC1",(-0.25, 0, 0))),
471
+ "ILE": (("BB", ( 0.25, 0, 0)),
472
+ ("SC1",(-0.25, 0, 0))),
473
+ "VAL": (("BB", ( 0.25, 0, 0)),
474
+ ("SC1",(-0.25, 0, 0))),
475
+ "SER": (("BB", ( 0.25, 0, 0)),
476
+ ("SC1",(-0.25, 0, 0))),
477
+ "THR": (("BB", ( 0.25, 0, 0)),
478
+ ("SC1",(-0.25, 0, 0))),
479
+ "CYS": (("BB", ( 0.25, 0, 0)),
480
+ ("SC1",(-0.25, 0, 0))),
481
+ "MET": (("BB", ( 0.25, 0, 0)),
482
+ ("SC1",(-0.25, 0, 0))),
483
+ "LYS": (("BB", ( 0.25, 0, 0)),
484
+ ("SC1",(-0.25, 0, 0))),
485
+ "PRO": (("BB", ( 0.25, 0, 0)),
486
+ ("SC1",(-0.25, 0, 0))),
487
+ "HYP": (("BB", ( 0.25, 0, 0)),
488
+ ("SC1",(-0.25, 0, 0))),
489
+ "ARG": (("BB", ( 0.25, 0, 0)),
490
+ ("SC1",( 0, 0, 0)),
491
+ ("SC2",(-0.25, 0.125, 0))),
492
+ "PHE": (("BB", ( 0.25, 0, 0)),
493
+ ("SC1",( 0, 0, 0)),
494
+ ("SC2",(-0.25,-0.125, 0)),
495
+ ("SC3",(-0.25, 0.125, 0))),
496
+ "TYR": (("BB", ( 0.25, 0, 0)),
497
+ ("SC1",( 0, 0, 0)),
498
+ ("SC2",(-0.25,-0.125, 0)),
499
+ ("SC3",(-0.25, 0.125, 0))),
500
+ "TRP": (("BB", ( 0.25, 0.125, 0)),
501
+ ("SC1",( 0.25, 0, 0)),
502
+ ("SC2",( 0, -0.125, 0)),
503
+ ("SC3",( 0, 0.125, 0)),
504
+ ("SC4",(-0.25, 0, 0))),
505
+ }
506
+
507
+ # Update the solvents dictionary with single atom ones
508
+ for s in ["W","NA","CL","Mg","K","BUT"]:
509
+ solventParticles[s] = ((s,(0,0,0)),)
510
+
511
+ # Apolar amino acids nd stuff for orienting proteins in membrane
512
+ apolar = "ALA CYS PHE ILE LEU MET VAL TRP PLM CLR".split()
513
+
514
+ ## PRIVATE PARTS FROM THIS POINT ON ##
515
+
516
+ S = str
517
+ F = float
518
+ I = int
519
+ R = random.random
520
+
521
+ def vector(v):
522
+ if type(v) == str and "," in v:
523
+ return [float(i) for i in v.split(",")]
524
+ return float(v)
525
+
526
+ def vvadd(a,b):
527
+ if type(b) in (int,float):
528
+ return [i+b for i in a]
529
+ return [i+j for i,j in list(zip(a,b))]
530
+
531
+ def vvsub(a,b):
532
+ if type(b) in (int,float):
533
+ return [i-b for i in a]
534
+ return [i-j for i,j in list(zip(a,b))]
535
+
536
+ def isPDBAtom(l):
537
+ return l.startswith("ATOM") or l.startswith("HETATM")
538
+
539
+ def pdbAtom(a):
540
+ ##01234567890123456789012345678901234567890123456789012345678901234567890123456789
541
+ ##ATOM 2155 HH11 ARG C 203 116.140 48.800 6.280 1.00 0.00
542
+ ## ===> atom name, res name, res id, chain, x, y, z
543
+ return (S(a[12:16]),S(a[17:21]),I(a[22:26]),a[21],F(a[30:38])/10,F(a[38:46])/10,F(a[46:54])/10)
544
+
545
+ d2r = 3.14159265358979323846264338327950288/180
546
+ def pdbBoxRead(a):
547
+ # Convert a PDB CRYST1 entry to a lattice definition.
548
+ # Convert from Angstrom to nanometer
549
+ fa, fb, fc, aa, ab, ac = [float(i) for i in a.split()[1:7]]
550
+ ca, cb, cg, sg = math.cos(d2r*aa), math.cos(d2r*ab), math.cos(d2r*ac) , math.sin(d2r*ac)
551
+ wx, wy = 0.1*fc*cb, 0.1*fc*(ca-cb*cg)/sg
552
+ wz = math.sqrt(0.01*fc*fc - wx*wx - wy*wy)
553
+ return [0.1*fa, 0, 0, 0.1*fb*cg, 0.1*fb*sg, 0, wx, wy, wz]
554
+
555
+ def groAtom(a):
556
+ #012345678901234567890123456789012345678901234567890
557
+ # 1PRN N 1 4.168 11.132 5.291
558
+ ## ===> atom name, res name, res id, chain, x, y, z
559
+ return (S(a[10:15]), S(a[5:10]), I(a[:5]), " ", F(a[20:28]),F(a[28:36]),F(a[36:44]))
560
+
561
+ def groBoxRead(a):
562
+ b = [F(i) for i in a.split()] + 6*[0] # Padding for rectangular boxes
563
+ return b[0],b[3],b[4],b[5],b[1],b[6],b[7],b[8],b[2]
564
+
565
+ def readBox(a):
566
+ x = [ float(i) for i in a.split(",") ] + 6*[0]
567
+ if len(x) == 12: # PDB format
568
+ return pdbBoxRead("CRYST1 "+" ".join([str(i) for i in x]))
569
+ else: # GRO format
570
+ return x[0],x[3],x[4],x[5],x[1],x[6],x[7],x[8],x[2]
571
+ #A helper function the writes and arbritrary PDB file
572
+ def write_point(points,fn):
573
+ new_file = open(fn,"w")
574
+ count = 0
575
+ for i in points:
576
+ count += 1
577
+ count_str = (6-len(str(count)))*" "+str(count)
578
+ c = "ATOM "+count_str+" BB DUM 1 0.000 0.000 15.000 1.00 0.00"
579
+ xp = np.format_float_positional(i[0],precision=3)
580
+ yp = np.format_float_positional(i[1],precision=3)
581
+ zp = np.format_float_positional(i[2],precision=3)
582
+ xp += "0"*(3-len((xp.split(".")[1])))
583
+ yp += "0"*(3-len((yp.split(".")[1])))
584
+ zp += "0"*(3-len((zp.split(".")[1])))
585
+ new_c = c[:30]+(" "*(8-len(xp)))+xp+(" "*(8-len(yp)))+yp+(" "*(8-len(zp))) +zp+c[54:]+"\n"
586
+ new_file.write(new_c)
587
+ new_file.close()
588
+
589
+ class Structure:
590
+ def __init__(self,filename=None):
591
+ self.title = ""
592
+ self.atoms = []
593
+ self.coord = []
594
+ self.rest = []
595
+ self.box = []
596
+ self._center = None
597
+
598
+ if filename:
599
+ lines = open(filename).readlines()
600
+ # Try extracting PDB atom/hetatm definitions
601
+ self.rest = []
602
+ self.atoms = [pdbAtom(i) for i in lines if isPDBAtom(i) or self.rest.append(i)]
603
+ if self.atoms:
604
+ # This must be a PDB file
605
+ self.title = "THIS IS INSANE!\n"
606
+ for i in self.rest:
607
+ if i.startswith("TITLE"):
608
+ self.title = i
609
+ self.box = [0,0,0,0,0,0,0,0,0]
610
+ for i in self.rest:
611
+ if i.startswith("CRYST1"):
612
+ self.box = pdbBoxRead(i)
613
+ else:
614
+ # This should be a GRO file
615
+ self.atoms = [groAtom(i) for i in lines[2:-1]]
616
+ self.rest = [lines[0],lines[1],lines[-1]]
617
+ self.box = groBoxRead(lines[-1])
618
+ self.title = lines[0]
619
+ self.coord = [i[4:7] for i in self.atoms]
620
+ self.center()
621
+
622
+ def __nonzero__(self):
623
+ return bool(self.atoms)
624
+
625
+ def __len__(self):
626
+ return len(self.atoms)
627
+
628
+ def __iadd__(self,s):
629
+ for i in range(len(self)):
630
+ self.coord[i] = vvadd(self.coord[i],s)
631
+ return self
632
+
633
+ def center(self,other=None):
634
+ if not self._center:
635
+ self._center = [ sum(i)/len(i) for i in list(zip(*self.coord))]
636
+ if other:
637
+ s = vvsub(other,self._center)
638
+ for i in range(len(self)):
639
+ self.coord[i] = vvadd(self.coord[i],s)
640
+ self._center = other
641
+ return s # return the shift
642
+ return self._center
643
+
644
+ def diam(self):
645
+ if self._center != (0,0,0):
646
+ self.center((0,0,0))
647
+ return 2*math.sqrt(max([i*i+j*j+k*k for i,j,k in self.coord]))
648
+
649
+ def diamxy(self):
650
+ if self._center != (0,0,0):
651
+ self.center((0,0,0))
652
+ return 2*math.sqrt(max([i*i+j*j for i,j,k in self.coord]))
653
+
654
+ def fun(self,fn):
655
+ return [fn(i) for i in list(zip(*self.coord))]
656
+
657
+ # Mean of deviations from initial value
658
+ def meand(v):
659
+ return sum([i-v[0] for i in v])/len(v)
660
+
661
+ # Sum of squares/crossproducts of deviations
662
+ def ssd(u,v):
663
+ return sum([(i-u[0])*(j-v[0]) for i,j in list(zip(u,v))])/(len(u)-1)
664
+
665
+ # Parse a string for a lipid as given on the command line (LIPID[:NUMBER])
666
+ def parse_mol(x):
667
+ l = x.split(":")
668
+ return l[0], len(l) == 1 and 1 or float(l[1])
669
+
670
+ ## MIJN EIGEN ROUTINE ##
671
+
672
+ # Quite short piece of code for diagonalizing symmetric 3x3 matrices :)
673
+
674
+ # Analytic solution for third order polynomial
675
+ def solve_p3( a, b, c ):
676
+ Q,R,a3 = (3*b-a**2)/9.0, (-27*c+a*(9*b-2*a**2))/54.0, a/3.0
677
+ if Q**3 + R**2:
678
+ t,R13 = math.acos(R/math.sqrt(-Q**3))/3, 2*math.sqrt(-Q)
679
+ u,v,w = math.cos(t), math.sin(t+math.pi/6), math.cos(t+math.pi/3)
680
+ return R13*u-a3, -R13*v-a3, -R13*w-a3
681
+ else:
682
+ R13 = math.sqrt3(R)
683
+ return 2*R13-a3, -R13-a3, -R13-a3
684
+
685
+ # Normalization of 3-vector
686
+ def normalize(a):
687
+ f = 1.0/math.sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2])
688
+ return f*a[0],f*a[1],f*a[2]
689
+
690
+ # Eigenvectors for a symmetric 3x3 matrix:
691
+ # For symmetric matrix A the eigenvector v with root r satisfies
692
+ # v.Aw = Av.w = rv.w = v.rw
693
+ # v.(A-rI)w = v.Aw - v.rw = 0 for all w
694
+ # This means that for any two vectors p,q the eigenvector v follows from:
695
+ # (A-rI)p x (A-rI)q
696
+ # The input is var(x),var(y),var(z),cov(x,y),cov(x,z),cov(y,z)
697
+ # The routine has been checked and yields proper eigenvalues/-vectors
698
+ def mijn_eigen_sym_3x3(a,d,f,b,c,e):
699
+ a,d,f,b,c,e=1,d/a,f/a,b/a,c/a,e/a
700
+ b2, c2, e2, df = b*b, c*c, e*e, d*f
701
+ roots = list(solve_p3(-a-d-f, df-b2-c2-e2+a*(f+d), a*e2+d*c2+f*b2-a*df-2*b*c*e))
702
+ roots.sort(reverse=True)
703
+ ux, uy, uz = b*e-c*d, b*c-a*e, a*d-b*b
704
+ u = (ux+roots[0]*c,uy+roots[0]*e,uz+roots[0]*(roots[0]-a-d))
705
+ v = (ux+roots[1]*c,uy+roots[1]*e,uz+roots[1]*(roots[1]-a-d))
706
+ w = u[1]*v[2]-u[2]*v[1],u[2]*v[0]-u[0]*v[2],u[0]*v[1]-u[1]*v[0] # Cross product
707
+ return normalize(u),normalize(v),normalize(w),roots
708
+
709
+ # Very simple option class
710
+ class Option:
711
+ def __init__(self,func=str,num=1,default=None,description=""):
712
+ self.func = func
713
+ self.num = num
714
+ self.value = default
715
+ self.description = description
716
+ def __nonzero__(self):
717
+ return self.value != None
718
+ def __str__(self):
719
+ return self.value and str(self.value) or ""
720
+ def setvalue(self,v):
721
+ if len(v) == 1:
722
+ self.value = self.func(v[0])
723
+ else:
724
+ self.value = [ self.func(i) for i in v ]
725
+
726
+
727
+ def SphereGrid(n):
728
+ grid_points = []
729
+ for k in range(n):
730
+ y = (2.*k+1)/n-1
731
+ phi = k*2.3999632297286531
732
+ r = math.sqrt(1-y*y)
733
+ grid_points.append([math.cos(phi)*r, math.sin(phi)*r,y])
734
+ return grid_points
735
+
736
+ def SphereGridAng(n,ang):
737
+ phi = (1+np.sqrt(5))/2.0
738
+ grid_points = np.zeros((n,3))
739
+ ycut = np.sin(ang)
740
+ for k in range(n):
741
+ xi = np.modf((k/phi))[0]
742
+ yi = np.clip((k/(n-1))*(ycut/2),0,2)
743
+ grid_points[k] = np.array([np.cos(2*np.pi*xi)*np.sin(np.arccos(1-2*yi)),np.sin(2*np.pi*xi)*np.sin(np.arccos(1-2*yi)),1-2*yi])
744
+ return grid_points
745
+
746
+ def DiskGridFib(n,rad):
747
+ phi = (1+np.sqrt(5))/2.0
748
+ grid_points = np.zeros((n,3))
749
+ for k in range(n):
750
+ xi = np.modf((k/phi))[0]
751
+ yi = np.clip((k/(n-1)),0,2)
752
+ grid_points[k] = np.array([np.sin(2*np.pi*xi)*np.sqrt(yi)*rad,np.cos(2*np.pi*xi)*np.sqrt(yi)*rad,0])
753
+ return grid_points
754
+
755
+ #All functions that follow return a set of 3d coordinates and normals. This is all that is needs for later in the code
756
+ #where the actaul lipids are built
757
+
758
+ #This function creates a set of points with inverted curvature. The points are placed such that they are evenly distributed.
759
+ def InvSphereGrid(den,inner_rad,start_ang,orad):
760
+ grid_points = []
761
+ direcs = []
762
+ frden = int(-orad*den*2*(start_ang-np.pi/2)/np.pi)+1
763
+ rings = np.linspace(start_ang,np.pi/2,frden)
764
+ for xr,r in enumerate(rings[1:]):
765
+ rad = inner_rad+(1-np.cos(r))*orad
766
+ rden = int(rad*den)+1
767
+ new_ring = np.linspace(0,np.pi*2,4*rden)[:-1]
768
+ rrand = random.random()
769
+ for nr in new_ring:
770
+ ang1 = xr*rrand+nr
771
+ grid_points.append([np.cos(ang1)*rad,np.sin(ang1)*rad,orad*np.sin(r)])
772
+ direcs.append([np.cos(ang1)*np.cos(r),np.sin(ang1)*np.cos(r),np.sin(r)])
773
+ return grid_points,direcs
774
+
775
+ #Same as above but for the usual curvature
776
+ def SphereGridN(den,end_ang,orad):
777
+ grid_points = []
778
+ direcs = []
779
+ frden = int(orad*den*2*(end_ang)/np.pi)+1
780
+ rings = np.linspace(0,end_ang,frden)
781
+ for xr,r in enumerate(rings):
782
+ rad = np.sin(r)*orad
783
+ rden = int(rad*den)
784
+ new_ring = np.linspace(0,np.pi*2,4*rden+2)[:-1]
785
+ rrand = random.random()
786
+ for nr in new_ring:
787
+ ang1 = xr*rrand+nr
788
+ grid_points.append([np.cos(ang1)*rad,np.sin(ang1)*rad,orad-orad*np.cos(r)])
789
+ direcs.append([np.cos(ang1)*np.sin(r),np.sin(ang1)*np.sin(r),np.cos(r)])
790
+
791
+ return grid_points,direcs
792
+
793
+
794
+ #Same as above two but for a disk
795
+ def DiskGridFB(den,outer_rad):
796
+ gr = (1+np.sqrt(5))/2.0
797
+ grid_points = []
798
+ direcs = []
799
+ N = int((outer_rad*outer_rad*np.pi)*den)
800
+ for i in range(N):
801
+ ang1 = 2*np.pi*np.fmod((i/gr),1)
802
+ rad = np.sqrt(i/(N-1))*outer_rad
803
+ grid_points.append([np.cos(ang1)*rad,np.sin(ang1)*rad,0])
804
+ direcs.append([0,0,1])
805
+ return grid_points,direcs
806
+
807
+ #Same as above two but for a disk
808
+ def DiskGrid(den,inner_rad,xbox,ybox,outer_rad):
809
+ grid_points = []
810
+ direcs = []
811
+ if outer_rad<0:
812
+ outer_rad = np.sqrt(xbox*xbox+ybox*ybox)
813
+ else:
814
+ new_den =2*den/np.pi
815
+ new_den = new_den*new_den
816
+ return DiskGridFB(new_den,outer_rad)
817
+ frden = int(den*2*(outer_rad-inner_rad)/np.pi)
818
+ rings = np.linspace(inner_rad,outer_rad,frden)
819
+ for xr,r in enumerate(rings[1:]):
820
+ rad = r
821
+ rden = int(rad*den)+1
822
+ new_ring = np.linspace(0,np.pi*2,4*rden)[:-1]
823
+ rrand = random.random()
824
+ for nr in new_ring:
825
+ ang1 = xr*rrand+nr
826
+ if(-xbox <np.cos(ang1)*rad < xbox-0.2 and -ybox < np.sin(ang1)*rad < ybox-0.2):
827
+ grid_points.append([np.cos(ang1)*rad,np.sin(ang1)*rad,0])
828
+ direcs.append([0,0,1])
829
+ return grid_points,direcs
830
+
831
+
832
+ #Same as above but for a tube
833
+ def TubeGrid(den,rad,leng,keep_end):
834
+ grid_points = []
835
+ direcs = []
836
+ frden = int(den*2*(leng)/np.pi)+1
837
+ rings = np.linspace(0,leng,frden)
838
+ if(not keep_end):
839
+ rings = rings[:-1]
840
+ for xr,r in enumerate(rings):
841
+ lenny = r
842
+ rden = int(rad*den)+1
843
+ new_ring = np.linspace(0,np.pi*2,4*rden)[:-1]
844
+ rrand = random.random()
845
+ for nr in new_ring:
846
+ ang1 = xr*rrand+nr
847
+ grid_points.append([np.cos(ang1)*rad,np.sin(ang1)*rad,-lenny])
848
+ direcs.append([np.cos(ang1),np.sin(ang1),0])
849
+ return grid_points,direcs
850
+
851
+ #standard deviation for gaussians
852
+ stand = 0.5
853
+
854
+ #function that evalualtes a gaussian on a grid (points)
855
+ def eval_gaussian(points,cen,std,height):
856
+ return height*np.exp(-np.linalg.norm((points-cen[None,None,:]),axis=2)/(2*std*std))
857
+
858
+
859
+ #function that evaluates a sum of gaussians at a single point
860
+ @jax.jit
861
+ def eval_gaussianj(point,all_cens,std,height):
862
+ ret_val = 0
863
+ def egj_loop(ret_val,ind):
864
+ ret_val += height*jnp.exp(-jnp.linalg.norm(point-all_cens[ind])/(2*std*std))
865
+ return ret_val,ind
866
+ ret_val,_ = jax.lax.scan(egj_loop,ret_val,jnp.arange(all_cens.shape[0]))
867
+ return ret_val
868
+
869
+
870
+
871
+ #gradient of above
872
+ eval_g_grad = jax.grad(eval_gaussianj,argnums=0)
873
+
874
+ #this function evalualtes a sum of gaussians on a grid
875
+ def gaussian_grid(points,xstart,ystart,xend,yend,xnum,ynum):
876
+ grid_vals = np.zeros((xnum,ynum,2))
877
+ grid_vals[:,:,0] += np.linspace(xstart,xend,xnum)[None,:]
878
+ grid_vals[:,:,1] += np.linspace(ystart,yend,ynum)[:,None]
879
+
880
+ ret_vals = np.zeros((xnum,ynum))
881
+ count =0
882
+ for i in points:
883
+ count += 1
884
+ ret_vals += eval_gaussian(grid_vals,i,stand,1)
885
+ return ret_vals,grid_vals
886
+
887
+
888
+ #This takes a grid of values and draws along a contour at value coff, points are places along this with a given spacing
889
+ #This contour can be draw further a constant width out from coff. This is the main part of building a micelle
890
+ #This works by taking a step defined by (df/dy,-df/dx )*ds which by definition os along the contour
891
+ def draw_along(spacing,all_cens,grid,grid_vals,coff,rad_plus,z):
892
+ max_iter = 100000
893
+ tol = 0.1
894
+ ds = 0.01
895
+ tot_ds = 0
896
+ start = jnp.array(grid_vals[jnp.logical_and(grid > coff-tol,grid < coff+tol)][0])
897
+ grad = eval_g_grad(start,all_cens,stand,1)
898
+ grad_dir = -grad/jnp.linalg.norm(grad)
899
+ start_p = start+rad_plus*grad_dir
900
+ prev_start = start_p.copy()
901
+ all_cens = jnp.array(all_cens)
902
+ path=jnp.zeros((int(max_iter*ds/spacing)+1,2))
903
+ normals=jnp.zeros((int(max_iter*ds/spacing)+1,2))
904
+ def da_loop(path_data,ind):
905
+ path = path_data[0]
906
+ tot_ds = path_data[1]
907
+ count = path_data[2]
908
+ normals = path_data[3]
909
+ start = path_data[4]
910
+ prev_start = path_data[5]
911
+ def early_term(path,tot_ds,count,normals,start,prev_start):
912
+ return path,tot_ds,count,normals,start,prev_start
913
+ def nearly_term(path,tot_ds,count,normals,start,prev_start):
914
+ grad = eval_g_grad(start,all_cens,stand,1)
915
+ grad_dir = -grad/jnp.linalg.norm(grad)
916
+ norm = jnp.array([grad[1],-grad[0]])
917
+ norm /= jnp.linalg.norm(norm)
918
+ start += norm*ds
919
+ tot_ds += jnp.linalg.norm(prev_start-(start+rad_plus*grad_dir))
920
+ prev_start = start+rad_plus*grad_dir
921
+ def adder(path,tot_ds,count,normals):
922
+ path = path.at[count].set(start+rad_plus*grad_dir)
923
+ normals = normals.at[count].set(grad_dir)
924
+ count +=1
925
+ tot_ds = 0.0
926
+ return path,tot_ds,count,normals
927
+ def nadder(path,tot_ds,count,normals):
928
+ return path,tot_ds,count,normals
929
+
930
+ path,tot_ds,count,normals = jax.lax.cond(tot_ds>spacing,adder,nadder,path,tot_ds,count,normals)
931
+ return path,tot_ds,count,normals,start,prev_start
932
+ path,tot_ds,count,normals,start,prev_start = jax.lax.cond(jnp.logical_and(jnp.linalg.norm(path[count-1]-start_p) < spacing/2,count > 5),early_term,nearly_term,path,tot_ds,count,normals,start,prev_start)
933
+ return (path,tot_ds,count,normals,start,prev_start),ind
934
+ path_data,_=jax.lax.scan(da_loop,(path,0.0,0,normals,start,prev_start),jnp.arange(max_iter))
935
+ path = np.array(path_data[0])[:path_data[2]]
936
+ normals = np.array(path_data[3])[:path_data[2]]
937
+ path = np.pad(path,((0,0),(0,1)),"constant",constant_values=(z,z))
938
+ return path,normals
939
+
940
+
941
+ #gets the average length of lipids for building an accurate micelle.
942
+ def get_avlip_len(lipids):
943
+ liplens = 0
944
+ for lipid in lipids:
945
+ lipidsplit = lipid.split(":")[0]
946
+ atoms = list(zip(lipidsa[lipidsplit][1].split(),lipidsx[lipidsa[lipidsplit][0]],lipidsy[lipidsa[lipidsplit][0]],lipidsz[lipidsa[lipidsplit][0]]))
947
+ at,ax,ay,az = list(zip(*[i for i in atoms if i[0] != "-"]))
948
+ az = [(0.5+(i-min(az)))*options["-bd"].value for i in az ]
949
+
950
+ lipLen = max(az)-min(az)
951
+ liplens += lipLen
952
+ return liplens/len(lipids)
953
+
954
+
955
+ #This uses all the above to build the micelle. Using contours with radius and height varing as a semi circle
956
+ #Additionally the center is filled with a disc of lipids
957
+ def build_micelle(area_l,all_cens,grid,grid_vals,coff,pbcx,pbcy,avlip_len):
958
+ dims = np.array([pbcx,pbcy,0])
959
+ orad = 2.2
960
+ end_ang = np.pi
961
+ den = np.pi/2*np.sqrt(1/area_l)
962
+ frden = int(orad*den*2*(end_ang)/np.pi)+1
963
+ rings = np.linspace(0,end_ang,frden)
964
+ gpoints = np.zeros((0,3))
965
+ normals = np.zeros((0,3))
966
+ sp = (0.5*(1.15-avlip_len)/(-0.65))+(0.15*(1.8-avlip_len)/0.65)
967
+ if sp < 0.15:
968
+ sp = 0.15
969
+ zpush = 1.8-avlip_len
970
+ for xr,r in enumerate(rings):
971
+ rad = np.sin(r)*orad
972
+ rad_a = sp*(frden/2)-np.abs(sp*(frden/2)-sp*xr)
973
+ rad_z = zpush*np.cos(r)
974
+ znorm = np.array([0,0,1])
975
+ z = np.cos(r)*orad
976
+ r1,nms = draw_along(np.sqrt(area_l),all_cens,grid,grid_vals,coff,rad,z)
977
+ nms_a = np.pad(nms,((0,0),(0,1)),"constant",constant_values=(0,0))
978
+ gpoints = np.concatenate((gpoints,np.array(r1+nms_a*rad_a+znorm*rad_z)))
979
+ norms = nms*np.sin(r)
980
+ norms = np.pad(norms,((0,0),(0,1)),"constant",constant_values=(np.cos(r),np.cos(r)))
981
+ normals = np.concatenate((normals,norms))
982
+
983
+ disk_lips = []
984
+ disk_dirs = []
985
+ disk_grid,disc_direcs = DiskGrid(den,0,pbcx,pbcy,-1)
986
+ disc_direcs = np.array(disc_direcs)
987
+
988
+ for i,d in enumerate(disk_grid):
989
+ val = eval_gaussianj(jnp.array(d[:2]),jnp.array(all_cens),stand,1)
990
+ if(val > coff+5):
991
+ disk_lips.append(d-np.array([0,0,2+zpush]))
992
+ disk_dirs.append(-disc_direcs[i])
993
+ disk_lips.append(d+np.array([0,0,2+zpush]))
994
+ disk_dirs.append(disc_direcs[i])
995
+ disk_lips = np.array(disk_lips)
996
+ disk_dirs = np.array(disk_dirs)
997
+ gpoints = np.concatenate((gpoints,disk_lips))
998
+ normals = np.concatenate((normals,disk_dirs))
999
+
1000
+ gpoints_max_rad = np.max(np.linalg.norm(disk_lips[:,:2]-dims[:2]/2,axis=1))
1001
+
1002
+ return gpoints,normals,gpoints_max_rad+1.5
1003
+
1004
+ #This is an implementation of the KL divergence
1005
+ def kl_d(a,b):
1006
+ kl = np.where(a != 0, a * np.log(a / b), 0)
1007
+ kl = kl[np.isfinite(kl)]
1008
+ return np.sum(kl)
1009
+ #another gaussian
1010
+ def gaussian(x,sig,mu):
1011
+ return (1/(sig*np.sqrt(2*np.pi)))*np.exp(-0.5*np.power(((x-mu)/sig),2))
1012
+ #The distribution of glycan strands in ecoli
1013
+ def ecoli_gdist(x):
1014
+ return 0.75*gaussian(x,4,8.9)+0.25*gaussian(x,10,45)
1015
+
1016
+ #a function that evalualtes a custom glycan distribution
1017
+ def glycan_dist(x,gdist):
1018
+ total = 0
1019
+ for gd in gdist:
1020
+ total += gd[0]*gaussian(x,gd[1],gd[2])
1021
+ return total
1022
+
1023
+ #a function that gets the KDE for a given set of glycan lengths
1024
+ def eval_kde(all_linesT):
1025
+ lengs = []
1026
+ leng = 0
1027
+ zero = False
1028
+ prev = 2
1029
+ for line in all_linesT:
1030
+ pos_start = np.where(line == 0)[0]
1031
+ if(len(list(pos_start)) < 1):
1032
+ start = 0
1033
+ else:
1034
+ start = pos_start[0]
1035
+ for ind in range(line.shape[0]):
1036
+ sind = (ind+start)%(line.shape[0])
1037
+ if(line[sind] == 1):
1038
+ leng += 1
1039
+ zero = False
1040
+ elif(line[sind] == 0):
1041
+ lengs.append(leng)
1042
+ leng = 0
1043
+ zero = True
1044
+ else:
1045
+ if(prev != 2):
1046
+ lengs.append(leng)
1047
+ leng = 0
1048
+ zero = True
1049
+ prev = line[sind]
1050
+ if(not zero):
1051
+ lengs.append(leng)
1052
+ return sp.stats.gaussian_kde(lengs)
1053
+
1054
+ #MCMC to obtain a glycan strand distribution close to the target
1055
+ def MC_Glycan_Strands(pbcy,pbcx,zpos,xoff,yoff,prot_coords,gdist,num):
1056
+ no_gly = int(pbcy/0.9)-2
1057
+ no_lines = int(pbcx/2.8)
1058
+ all_linesT = np.zeros((no_lines-1,no_gly-1))+1
1059
+ prot_block = np.zeros((no_lines-1,no_gly-1))
1060
+
1061
+ yspace = np.linspace(0,pbcy,all_linesT.shape[1]+1)[:-1]
1062
+ xspace = np.linspace(0,pbcx,all_linesT.shape[0]+1)[:-1]
1063
+
1064
+ if(prot_coords.size > 0):
1065
+ prot_coords_zslice = prot_coords[prot_coords[:,2] > zpos-0.5]
1066
+ prot_coords_zslice = prot_coords_zslice[prot_coords_zslice[:,2] < zpos+0.5]
1067
+
1068
+
1069
+
1070
+ for l in range(prot_block.shape[0]):
1071
+ for g in range(prot_block[l].shape[0]):
1072
+ for pc in prot_coords_zslice:
1073
+ pos = np.array([xspace[l]+xoff,yspace[g]+yoff+0.5,zpos])
1074
+ if(np.linalg.norm(pc-pos) < 1):
1075
+ prot_block[l,g] = 1
1076
+ for l in range(prot_block.shape[0]):
1077
+ ones = False
1078
+ ones_end = False
1079
+ indg = 0
1080
+ for g in range(prot_block[l].shape[0]):
1081
+ if prot_block[l,g] == 1:
1082
+ if ones_end:
1083
+ prot_block[l,indg:g] = 1
1084
+ ones = True
1085
+ ones_end = False
1086
+ else:
1087
+ ones = True
1088
+ if ones:
1089
+ if prot_block[l,g] != 1:
1090
+ indg = g
1091
+ ones_end = True
1092
+
1093
+
1094
+
1095
+ #plt.imshow(prot_block)
1096
+ #plt.show()
1097
+
1098
+ line_index = np.arange(no_gly-1)
1099
+
1100
+ all_linesT += prot_block
1101
+
1102
+ test_kde = eval_kde(all_linesT)
1103
+ testx = np.linspace(0,65,100)
1104
+ prev_kld = kl_d(glycan_dist(testx,gdist),test_kde(testx))
1105
+ for i in range(30000):
1106
+ rlind = random.randint(0,no_lines-2)
1107
+
1108
+ line_block = prot_block[rlind]
1109
+ none_blocked = line_block[line_block==0]
1110
+ nb_ind = random.randint(0,none_blocked.shape[0]-1)
1111
+ glind = line_index[line_block==0][nb_ind]
1112
+
1113
+ all_linesT[rlind][glind] = (all_linesT[rlind][glind]+1)%2
1114
+
1115
+ test_kde = eval_kde(all_linesT)
1116
+ testx = np.linspace(0,65,100)
1117
+ kld = kl_d(glycan_dist(testx,gdist),test_kde(testx))
1118
+
1119
+ kT = 0.0025
1120
+
1121
+ accept = 1-np.exp(-(kld-prev_kld)/kT)
1122
+
1123
+ if(np.random.random() < accept):
1124
+ all_linesT[rlind][glind] = (all_linesT[rlind][glind]+1)%2
1125
+ else:
1126
+ prev_kld = kld
1127
+ test_kde = eval_kde(all_linesT)
1128
+ testx = np.linspace(0,65,100)
1129
+ plt.plot(test_kde(testx))
1130
+ plt.plot(glycan_dist(testx,gdist))
1131
+ plt.savefig(out_folder+"Dist"+str(num)+".svg")
1132
+ plt.clf()
1133
+
1134
+ for l in all_linesT:
1135
+ l[l==2] = 0
1136
+ if(np.sum(l) == l.shape[0]):
1137
+ l[random.randint(0,l.shape[0]-1)] = 0
1138
+
1139
+ return all_linesT,prot_coords_zslice
1140
+
1141
+
1142
+ #This function uses data from the above to generate the coordinates for glycan strands
1143
+ def Create_Glycan_strands2(pgl_no,pbcy,pbcx,z_poses,xoff,yoff,pcoords, gdist):
1144
+ #x y z dir type place linked 3-3
1145
+ no_gly = int(pbcy/0.9)-2-1
1146
+ no_lines = int(pbcx/2.8)-1
1147
+ all_lines = np.zeros((pgl_no,no_lines,no_gly*2,14))
1148
+ all_pc_slices = []
1149
+ if pcoords.shape[0] == 0:
1150
+ pcoords = np.zeros((1,3))
1151
+ for pn in range(pgl_no):
1152
+ z = pbcz/2+z_poses[pn]+Pos_PGL
1153
+ chain_lens,pc_zslice = MC_Glycan_Strands(pbcy,pbcx,z,1.25*(pn%2)+xoff,yoff,pcoords+np.array([0,0,pbcz/2]),gdist,pn)
1154
+ all_pc_slices.append(pc_zslice)
1155
+ yspace = np.linspace(0,pbcy,chain_lens.shape[1]*2+1)[:-1]
1156
+ xspace = np.linspace(0,pbcx,chain_lens.shape[0]+1)[:-1]
1157
+
1158
+ for l in range(chain_lens.shape[0]):
1159
+ y_shift = 0#np.random.random()*0.5
1160
+ for g in range(chain_lens[l].shape[0]):
1161
+ direc = random.randint(0,1)*2-1
1162
+ x = xspace[l]+1.25*(pn%2)
1163
+ y2 = yspace[2*g+1]+y_shift
1164
+ y1 = yspace[2*g]+y_shift
1165
+ all_lines[pn,l,2*g] = np.array([x+xoff,y1+yoff,z,direc,1,chain_lens[l,g],-1,-1,-1,-1,-1,-1,0,0])
1166
+ all_lines[pn,l,2*g+1] = np.array([x+xoff,y2+yoff,z,direc,0,chain_lens[l,g],-1,-1,-1,-1,-1,-1,0,0])
1167
+ return all_lines,all_pc_slices
1168
+
1169
+
1170
+
1171
+ #enforces pbc
1172
+ def enforce_pbc(pbcv,points):
1173
+ points = np.where(points >= pbcv, points-pbcv, points)
1174
+ points = np.where(points <0, points+pbcv, points)
1175
+ return points
1176
+
1177
+ #This function joins cross-links that are already cross-linked. (This flips that way they are linked)
1178
+ def flip_link(all_lines,lyind,lind,bind):
1179
+ done = False
1180
+ all_linesT = all_lines.copy()
1181
+ if(all_linesT[lyind][lind][bind][13] == 1):
1182
+ return all_lines, False
1183
+ tmp = all_linesT[lyind,lind,bind,6:9].copy()
1184
+ all_linesT[lyind,lind,bind,6:9] = all_linesT[lyind,lind,bind,9:12].copy()
1185
+ all_linesT[lyind,lind,bind,9:12] = tmp.copy()
1186
+ if(all_linesT[lyind,lind,bind,6] > -0.5):
1187
+ tnlind = int(all_linesT[lyind,lind,bind,6])
1188
+ tnbind = int(all_linesT[lyind,lind,bind,7])
1189
+ tnlyind = int(all_linesT[lyind,lind,bind,8])
1190
+ nlind = tnlind
1191
+ nbind = tnbind
1192
+ nlyind = tnlyind
1193
+ switcher = 6
1194
+ elif(all_linesT[lyind,lind,bind,9] > -0.5):
1195
+ tnlind = int(all_linesT[lyind,lind,bind,9])
1196
+ tnbind = int(all_linesT[lyind,lind,bind,10])
1197
+ tnlyind = int(all_linesT[lyind,lind,bind,11])
1198
+ nlind = tnlind
1199
+ nbind = tnbind
1200
+ nlyind = tnlyind
1201
+ switcher = 9
1202
+ while not done:
1203
+ if(all_linesT[nlyind,nlind,nbind,13] == 1):
1204
+ return all_lines,False
1205
+ tmp = all_linesT[nlyind,nlind,nbind,6:9].copy()
1206
+ all_linesT[nlyind,nlind,nbind,6:9] = all_linesT[nlyind,nlind,nbind,9:12].copy()
1207
+ all_linesT[nlyind,nlind,nbind,9:12] = tmp.copy()
1208
+ tnlind = int(all_linesT[nlyind,nlind,nbind,switcher])
1209
+ tnbind = int(all_linesT[nlyind,nlind,nbind,switcher+1])
1210
+ tnlyind = int(all_linesT[nlyind,nlind,nbind,switcher+2])
1211
+ nlind = tnlind
1212
+ nbind = tnbind
1213
+ nlyind = tnlyind
1214
+ if(nlind < 0):
1215
+ done = True
1216
+ break
1217
+ return all_linesT, True
1218
+
1219
+ #Similar algo to above, but doesn't flip. This is used to determin the length of oligomers
1220
+ def count_olig(all_lines,lyind,lind,bind):
1221
+ done = False
1222
+ count = 1
1223
+ all_linesT = all_lines.copy()
1224
+ if(all_linesT[lyind][lind][bind][13] == 1):
1225
+ return 2, False
1226
+ if(all_linesT[lyind,lind,bind,6] > -0.5):
1227
+ tnlind = int(all_linesT[lyind,lind,bind,6])
1228
+ tnbind = int(all_linesT[lyind,lind,bind,7])
1229
+ tnlyind = int(all_linesT[lyind,lind,bind,8])
1230
+ nlind = tnlind
1231
+ nbind = tnbind
1232
+ nlyind = tnlyind
1233
+ switcher = 6
1234
+ elif(all_linesT[lyind,lind,bind,9] > -0.5):
1235
+ tnlind = int(all_linesT[lyind,lind,bind,9])
1236
+ tnbind = int(all_linesT[lyind,lind,bind,10])
1237
+ tnlyind = int(all_linesT[lyind,lind,bind,11])
1238
+ nlind = tnlind
1239
+ nbind = tnbind
1240
+ nlyind = tnlyind
1241
+ switcher = 9
1242
+ else:
1243
+ return 1,False
1244
+ while not done:
1245
+ count += 1
1246
+ if(all_linesT[nlyind,nlind,nbind,13] == 1):
1247
+ return count,False
1248
+
1249
+ tnlind = int(all_linesT[nlyind,nlind,nbind,switcher])
1250
+ tnbind = int(all_linesT[nlyind,nlind,nbind,switcher+1])
1251
+ tnlyind = int(all_linesT[nlyind,nlind,nbind,switcher+2])
1252
+ nlind = tnlind
1253
+ nbind = tnbind
1254
+ nlyind = tnlyind
1255
+ if(nlind < 0):
1256
+ done = True
1257
+ break
1258
+ return count, True
1259
+
1260
+
1261
+ #This function prevents knotting of the cross-links
1262
+ def get_allowed_beads(cind,clinks_np,bead,inder,no_gly):
1263
+ eq = np.where(clinks_np[cind][:,inder] == bead)[0]
1264
+ greater = np.where(clinks_np[cind][:,inder] > bead)[0]
1265
+ less = np.where(clinks_np[cind][:,inder] < bead)[0]
1266
+ if(len(greater) == 0):
1267
+ if(len(less) == 0):
1268
+ urange = 0
1269
+ else:
1270
+ urange = less[0]
1271
+ else:
1272
+ urange = greater[0]
1273
+ if(len(less) == 0):
1274
+ if(len(greater) == 0):
1275
+ lrange = -1
1276
+ else:
1277
+ lrange = greater[-1]
1278
+ else:
1279
+ lrange = less[-1]
1280
+ if(clinks_np[cind].size > 0):
1281
+ if(clinks_np[cind].shape[0] == 1):
1282
+ other_bead = clinks_np[cind][0,(inder+1)%2]
1283
+ if(bead > clinks_np[cind][0,inder]):
1284
+ if(other_bead > no_gly-2):
1285
+ allowed_beads = np.arange(0,int(no_gly/2))
1286
+ else:
1287
+ allowed_beads = np.arange(other_bead,no_gly)
1288
+ elif(bead < clinks_np[cind][0,inder]):
1289
+ if(other_bead < 3):
1290
+ allowed_beads = np.arange(int(no_gly/2),no_gly)
1291
+ else:
1292
+ allowed_beads = np.arange(0,other_bead)
1293
+ else:
1294
+ allowed_beads = np.arange(0,no_gly)
1295
+ return allowed_beads
1296
+ else:
1297
+
1298
+
1299
+ lrange_b2 = clinks_np[cind][lrange,inder]
1300
+ urange_b2 = clinks_np[cind][urange,inder]
1301
+
1302
+ db_l = np.where(clinks_np[cind][:,inder] == lrange_b2)[0]
1303
+ db_u = np.where(clinks_np[cind][:,inder] == urange_b2)[0]
1304
+
1305
+ poss_lrb = clinks_np[cind][db_l,(inder+1)%2]
1306
+ poss_urb = clinks_np[cind][db_u,(inder+1)%2]
1307
+
1308
+ if(np.min(poss_lrb) == 1):
1309
+ lrange_b = no_gly+1
1310
+ else:
1311
+ lrange_b = np.max(poss_lrb)
1312
+ lrange_b = np.max((poss_lrb+3)%no_gly-3)%no_gly
1313
+
1314
+
1315
+
1316
+
1317
+ if(np.max(poss_urb) == no_gly-1):
1318
+ urange_b = 0
1319
+ else:
1320
+ urange_b = np.min(poss_urb)
1321
+ urange_b = np.min((poss_urb-3)%no_gly+3)%no_gly
1322
+
1323
+ inc_l = np.where(clinks_np[cind][:,(inder+1)%2] == lrange_b)[0]
1324
+ inc_u = np.where(clinks_np[cind][:,(inder+1)%2] == urange_b)[0]
1325
+
1326
+
1327
+ if(len(inc_l) == 2):
1328
+ lrange_b_adj = (lrange_b + 1)%no_gly
1329
+ else:
1330
+ lrange_b_adj = lrange_b
1331
+ if(len(inc_u) == 2):
1332
+ urange_b_adj = (urange_b - 1)%no_gly
1333
+ else:
1334
+ urange_b_adj = urange_b
1335
+ if(lrange_b != urange_b):
1336
+ if(lrange_b_adj < urange_b_adj):
1337
+ allowed_beads = np.arange(lrange_b_adj,urange_b_adj+1)
1338
+ elif(lrange_b_adj > urange_b_adj):
1339
+ allowed_beads = np.concatenate([np.arange(0,urange_b_adj+1),np.arange(lrange_b_adj,no_gly)])
1340
+ else:
1341
+ allowed_beads = np.array([lrange_b_adj])
1342
+ else:
1343
+ if((len(greater) >= 1 and len(less) > 0) or (len(greater) > 0 and len(less) >= 1)):
1344
+ allowed_beads = np.array([2])
1345
+ else:
1346
+ allowed_beads = np.arange(0,no_gly)
1347
+ if(len(eq) > 0):
1348
+ not_allow = clinks_np[cind][eq[0],(inder+1)%2]
1349
+ delind = np.where(allowed_beads == not_allow)[0]
1350
+ if(len(delind > 0)):
1351
+ allowed_beads = np.delete(allowed_beads,delind[0])
1352
+ return allowed_beads
1353
+ else:
1354
+ return np.arange(0,no_gly)
1355
+
1356
+ #Uses all of the above to create cross-links between glycan strands
1357
+ #This is fairly complicated to describe so I will not for now
1358
+ def cross_link(all_lines,pbcy,cper,per33,lper,oper):
1359
+ no_layers = all_lines.shape[0]
1360
+ no_lines = all_lines.shape[1]
1361
+ no_gly = all_lines.shape[2]
1362
+ clinks = []
1363
+ clinks_np0 = []
1364
+ clinks_np1 = []
1365
+ for l in range(no_lines):
1366
+ clinks.append([])
1367
+ for cl in clinks:
1368
+ if(len(cl) > 0):
1369
+ cl_np = np.array(cl)
1370
+ sort_ind0 = np.lexsort((cl_np[:,1],cl_np[:,0]))
1371
+ sort_ind1 = np.lexsort((cl_np[:,0],cl_np[:,1]))
1372
+ clinks_np0.append(cl_np[sort_ind0])
1373
+ clinks_np1.append(cl_np[sort_ind1])
1374
+ else:
1375
+ clinks_np0.append(np.empty((0,2)))
1376
+ clinks_np1.append(np.empty((0,2)))
1377
+ for i in range(20*no_layers*no_gly*no_lines):
1378
+ layer_ind = random.randint(0,no_layers-1)
1379
+ line_ind = random.randint(0,no_lines-1)
1380
+ line1 = all_lines[layer_ind,line_ind]
1381
+ line1_nam = line1[line1[:,4]==0]
1382
+ line1_nam = line1_nam[line1_nam[:,5]==1]
1383
+ line1_nam = line1_nam[line1_nam[:,12]<2]
1384
+ try:
1385
+ b1ind = random.randint(0,line1_nam.shape[0]-1)
1386
+ except:
1387
+ continue
1388
+ passed = False
1389
+ flipped = 1
1390
+ for fl in [1,-1]:
1391
+ bead1 = line1_nam[b1ind]
1392
+ direc = bead1[3]*fl
1393
+ layer_ind2 = layer_ind
1394
+ if(layer_ind != no_layers-1 and random.random() < lper and bead1[12] == 0):
1395
+ layer_ind2 = layer_ind+1
1396
+ if(layer_ind%2 == 0):
1397
+ acc_direc = (direc+1)/2
1398
+ else:
1399
+ acc_direc = (direc-1)/2
1400
+ else:
1401
+ acc_direc = direc
1402
+ ypos = bead1[1]
1403
+ bead1_t = np.where(np.logical_and(all_lines[layer_ind,line_ind][:,1] > ypos-1e-7,all_lines[layer_ind,line_ind][:,1] < ypos+1e-7))[0][0]
1404
+ if(layer_ind == layer_ind2):
1405
+ if(direc == -1):
1406
+ allowed_beads = get_allowed_beads(line_ind,clinks_np0,bead1_t,0,no_gly)
1407
+ elif(direc == 1):
1408
+ allowed_beads = get_allowed_beads((line_ind-int(direc))%no_lines,clinks_np1,bead1_t,1,no_gly)
1409
+ else:
1410
+ allowed_beads = np.arange(0,no_gly)
1411
+ line2 = all_lines[layer_ind2,(line_ind-int(acc_direc))%no_lines,allowed_beads]
1412
+ line2_nam = line2[line2[:,4]==0]
1413
+ line2_nam = line2_nam[line2_nam[:,5]==1]
1414
+ if(layer_ind != layer_ind2):
1415
+ line2_nam = line2_nam[line2_nam[:,12]<1]
1416
+ else:
1417
+ line2_nam = line2_nam[line2_nam[:,12]<2]
1418
+ line2_nam[:,1] -= ypos-pbcy/2
1419
+ line2_nam[:,1] = enforce_pbc(pbcy,line2_nam[:,1])
1420
+ rangee = 1.5
1421
+ if(layer_ind != layer_ind2):
1422
+ rangee = 0.75
1423
+ line2_seg = line2_nam[line2_nam[:,1] > pbcy/2-rangee]
1424
+ line2_seg = line2_seg[line2_seg[:,1] < pbcy/2+rangee]
1425
+ line2_seg = line2_seg[np.logical_or(line2_seg[:,3] == -direc,np.logical_and(line2_seg[:,6] < 0,line2_seg[:,9] < 0))]
1426
+ line2_seg[:,1] += ypos-pbcy/2
1427
+ line2_seg[:,1] = enforce_pbc(pbcy,line2_seg[:,1])
1428
+ try:
1429
+ bead2_ind = random.randint(0,line2_seg.shape[0]-1)
1430
+ passed = True
1431
+ break
1432
+ except:
1433
+ bead1_t = np.where(np.logical_and(all_lines[layer_ind,line_ind][:,1] > ypos-1e-7,all_lines[layer_ind,line_ind][:,1] < ypos+1e-7))[0][0]
1434
+ if(all_lines[layer_ind,line_ind,bead1_t,6] > -1 or all_lines[layer_ind,line_ind,bead1_t,9] > -1):
1435
+ break
1436
+ flipped = -1
1437
+ continue
1438
+ if(not passed):
1439
+ bead1_t = np.where(np.logical_and(all_lines[layer_ind,line_ind][:,1] > ypos-1e-7,all_lines[layer_ind,line_ind][:,1] < ypos+1e-7))[0][0]
1440
+ if(layer_ind == layer_ind2):
1441
+ all_lines[layer_ind,line_ind,bead1_t,12] += 2
1442
+ continue
1443
+ bead2 = line2_seg[bead2_ind]
1444
+ ypos2 = bead2[1]
1445
+
1446
+
1447
+
1448
+ all_lines[layer_ind,line_ind,bead1_t,3] *= flipped
1449
+ ndirec = all_lines[layer_ind,line_ind,bead1_t,3]
1450
+ if(layer_ind != layer_ind2):
1451
+ if(layer_ind%2 == 0):
1452
+ ndirec = (ndirec+1)/2
1453
+ else:
1454
+ ndirec = (ndirec-1)/2
1455
+ fndirec = all_lines[layer_ind,line_ind,bead1_t,3]
1456
+ bead2_t = np.where(np.logical_and(all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines][:,1] > ypos2-1e-7,all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines][:,1] < ypos2+1e-7))[0][0]
1457
+
1458
+
1459
+
1460
+ lind1 = line_ind
1461
+ lind2 = (line_ind-int(ndirec))%no_lines
1462
+
1463
+ if(abs(lind1-lind2) > 1):
1464
+ if(lind1 > lind2):
1465
+ clind = lind1
1466
+ bind1 = bead1_t
1467
+ bind2 = bead2_t
1468
+ else:
1469
+ clind = lind2
1470
+ bind1 = bead2_t
1471
+ bind2 = bead1_t
1472
+ else:
1473
+ if(lind1 < lind2):
1474
+ clind = lind1
1475
+ bind1 = bead1_t
1476
+ bind2 = bead2_t
1477
+ else:
1478
+ clind = lind2
1479
+ bind1 = bead2_t
1480
+ bind2 = bead1_t
1481
+ rand33 = random.random()
1482
+ if(random.random() < cper):
1483
+ if(all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,6] < 0 and all_lines[layer_ind,line_ind,bead1_t,9] < 0):
1484
+ if(all_lines[layer_ind,line_ind,bead1_t,6] != lind2 or all_lines[layer_ind,line_ind,bead1_t,7] != bead2_t):
1485
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,6] = lind1
1486
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,7] = bead1_t
1487
+ if(all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] == 0 and rand33 < per33 and all_lines[layer_ind,line_ind,bead1_t,9] < 0):
1488
+ all_lines[layer_ind,line_ind,bead1_t,12] +=1
1489
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] +=2
1490
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,13] = 1
1491
+ all_lines[layer_ind,line_ind,bead1_t,13] = 2
1492
+ else:
1493
+ all_lines[layer_ind,line_ind,bead1_t,12] +=1
1494
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] +=1
1495
+
1496
+ if(layer_ind != layer_ind2 or random.random() > oper):
1497
+ all_lines[layer_ind,line_ind,bead1_t,12] = 2
1498
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] = 2
1499
+
1500
+ all_lines[layer_ind,line_ind,bead1_t,9] = lind2
1501
+ all_lines[layer_ind,line_ind,bead1_t,10] = bead2_t
1502
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,8] = layer_ind
1503
+ all_lines[layer_ind,line_ind,bead1_t,11] = layer_ind2
1504
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,3] =-fndirec
1505
+ clinks[clind].append([bind1,bind2])
1506
+ elif(all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,9] < 0 and all_lines[layer_ind,line_ind,bead1_t,6] < 0):
1507
+ if(all_lines[layer_ind,line_ind,bead1_t,9] != lind2 or all_lines[layer_ind,line_ind,bead1_t,10] != bead2_t):
1508
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,9] = lind1
1509
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,10] = bead1_t
1510
+ if(all_lines[layer_ind,line_ind,bead1_t,12] == 0 and rand33 < per33 and all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,9] < 0):
1511
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] +=1
1512
+ all_lines[layer_ind,line_ind,bead1_t,12] +=2
1513
+ all_lines[layer_ind,line_ind,bead1_t,13] = 1
1514
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,13] = 2
1515
+ else:
1516
+ all_lines[layer_ind,line_ind,bead1_t,12] +=1
1517
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] +=1
1518
+
1519
+ if(layer_ind != layer_ind2 or random.random() > oper):
1520
+ all_lines[layer_ind,line_ind,bead1_t,12] = 2
1521
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] = 2
1522
+
1523
+ all_lines[layer_ind,line_ind,bead1_t,6] = lind2
1524
+ all_lines[layer_ind,line_ind,bead1_t,7] = bead2_t
1525
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,11] = layer_ind
1526
+ all_lines[layer_ind,line_ind,bead1_t,8] = layer_ind2
1527
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,3] =-fndirec
1528
+ clinks[clind].append([bind1,bind2])
1529
+ else:
1530
+ all_lines,is_flipped = flip_link(all_lines,layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t)
1531
+ if(not is_flipped):
1532
+ all_lines,is_flipped = flip_link(all_lines,layer_ind,line_ind,bead1_t)
1533
+ if(not is_flipped):
1534
+ all_lines[layer_ind,line_ind,bead1_t,3] *= flipped
1535
+ continue
1536
+ if(all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,6] < 0 and all_lines[layer_ind,line_ind,bead1_t,9] < 0):
1537
+ if(all_lines[layer_ind,line_ind,bead1_t,6] != lind2 or all_lines[layer_ind,line_ind,bead1_t,7] != bead2_t):
1538
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,6] = lind1
1539
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,7] = bead1_t
1540
+ if(all_lines[layer_ind,line_ind,bead1_t,12] == 0 and rand33 < per33 and all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,9] < 0):
1541
+ all_lines[layer_ind,line_ind,bead1_t,12] +=2
1542
+ all_lines[layer_ind,line_ind,bead1_t,13] = 1
1543
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,11] = 2
1544
+ else:
1545
+ all_lines[layer_ind,line_ind,bead1_t,12] +=1
1546
+ if(all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] == 0 and rand33 < per33 and all_lines[layer_ind,line_ind,bead1_t,9] < 0):
1547
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] +=2
1548
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,13] = 1
1549
+ all_lines[layer_ind,line_ind,bead1_t,13] = 2
1550
+ else:
1551
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] +=1
1552
+
1553
+ if(layer_ind != layer_ind2 or random.random() > oper):
1554
+ all_lines[layer_ind,line_ind,bead1_t,12] = 2
1555
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] = 2
1556
+ all_lines[layer_ind,line_ind,bead1_t,9] = lind2
1557
+ all_lines[layer_ind,line_ind,bead1_t,10] = bead2_t
1558
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,8] = layer_ind
1559
+ all_lines[layer_ind,line_ind,bead1_t,11] = layer_ind2
1560
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,3] =-fndirec
1561
+ clinks[clind].append([bind1,bind2])
1562
+ elif(all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,9] < 0 and all_lines[layer_ind,line_ind,bead1_t,6] < 0):
1563
+ if(all_lines[layer_ind,line_ind,bead1_t,9] != lind2 or all_lines[layer_ind,line_ind,bead1_t,10] != bead2_t):
1564
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,9] = lind1
1565
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,10] = bead1_t
1566
+ if(all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] == 0 and rand33 < per33 and all_lines[layer_ind,line_ind,bead1_t,9] < 0):
1567
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] +=2
1568
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,13] = 1
1569
+ all_lines[layer_ind,line_ind,bead1_t,13] = 2
1570
+ else:
1571
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] +=1
1572
+ if(all_lines[layer_ind,line_ind,bead1_t,12] == 0 and rand33 < per33 and all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,9] < 0):
1573
+ all_lines[layer_ind,line_ind,bead1_t,12] +=2
1574
+ all_lines[layer_ind,line_ind,bead1_t,13] = 1
1575
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,13] = 2
1576
+ else:
1577
+ all_lines[layer_ind,line_ind,bead1_t,12] +=1
1578
+ if(layer_ind != layer_ind2 or random.random() > oper):
1579
+ all_lines[layer_ind,line_ind,bead1_t,12] = 2
1580
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] = 2
1581
+ all_lines[layer_ind,line_ind,bead1_t,6] = lind2
1582
+ all_lines[layer_ind,line_ind,bead1_t,7] = bead2_t
1583
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,11] = layer_ind
1584
+ all_lines[layer_ind,line_ind,bead1_t,8] = layer_ind2
1585
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,3] =-fndirec
1586
+ clinks[clind].append([bind1,bind2])
1587
+
1588
+ else:
1589
+ all_lines[layer_ind,line_ind,bead1_t,3] *= flipped
1590
+ all_lines[layer_ind2,(line_ind-int(ndirec))%no_lines,bead2_t,12] += 1
1591
+ all_lines[layer_ind,line_ind,bead1_t,12] +=1
1592
+
1593
+ clinks_np0 = []
1594
+ clinks_np1 = []
1595
+ for cl in clinks:
1596
+ if(len(cl) > 0):
1597
+ cl_np = np.array(cl)
1598
+ sort_ind0 = np.lexsort((cl_np[:,1],cl_np[:,0]))
1599
+ sort_ind1 = np.lexsort((cl_np[:,0],cl_np[:,1]))
1600
+ clinks_np0.append(cl_np[sort_ind0])
1601
+ clinks_np1.append(cl_np[sort_ind1])
1602
+ else:
1603
+ clinks_np0.append(np.empty((0,2)))
1604
+ clinks_np1.append(np.empty((0,2)))
1605
+
1606
+ return all_lines
1607
+
1608
+ #uses count_olig to determin distribution of oligomer lengths
1609
+ def count_all_olig(all_lines):
1610
+ test_lines = all_lines[np.logical_and(all_lines[:,:,:,5] == 1,all_lines[:,:,:,4] == 0),:]
1611
+ olig_lens = np.zeros(test_lines.shape[0])
1612
+ olig_count = 0
1613
+ for ly in range(all_lines.shape[0]):
1614
+ for l in range(all_lines[ly].shape[0]):
1615
+ for b in range(all_lines[ly,l].shape[0]):
1616
+ if(all_lines[ly,l,b,5] == 1 and all_lines[ly,l,b,4] == 0):
1617
+ num,_ = count_olig(all_lines,ly,l,b)
1618
+ olig_lens[olig_count] = num
1619
+ olig_count += 1
1620
+ return olig_lens
1621
+
1622
+ #loads an itp file
1623
+ def load_itp(fn):
1624
+ tmp_f = open(fn,"r")
1625
+ tmp_lines = tmp_f.readlines()
1626
+ tmp_f.close()
1627
+
1628
+ data = [[],[],[],[],[]]
1629
+
1630
+ data_ind = -1
1631
+ for lines in tmp_lines:
1632
+ if lines == "[ atoms ]\n":
1633
+ data_ind = 0
1634
+ elif lines == "[ bonds ]\n":
1635
+ data_ind = 1
1636
+ elif lines == "[ constraints ]\n":
1637
+ data_ind = 2
1638
+ elif lines == "[ angles ]\n":
1639
+ data_ind = 3
1640
+ elif lines == "[ dihedrals ]\n":
1641
+ data_ind = 4
1642
+ elif len(lines) < 5:
1643
+ data_ind = -1
1644
+ elif lines[0] != ";":
1645
+ if(data_ind > -1):
1646
+ data[data_ind].append(lines.split())
1647
+ return data
1648
+
1649
+ #flattens glycan strand data into 2d array
1650
+ def lines_to_coords(all_lines):
1651
+ old_shape = all_lines.shape
1652
+ all_lines = all_lines.reshape(int(all_lines.size/14),14)
1653
+ #sind = np.argsort(all_lines[:,4])
1654
+ return all_lines,old_shape
1655
+
1656
+ #Writes the itp file for PG
1657
+ def write_PGL_itp(all_lines,nam_itp,nag_itp,spep_itp,upep_itp,uupep_itp,prev_str,prev_nos):
1658
+ nam_data = load_itp(nam_itp)
1659
+ nag_data = load_itp(nag_itp)
1660
+ upep_data = load_itp(upep_itp)
1661
+ uupep_data = load_itp(uupep_itp)
1662
+ spep_data = load_itp(spep_itp)
1663
+
1664
+
1665
+ data = [nam_data,nag_data]
1666
+ atoms_str = prev_str[0]#"[ atoms ]\n"
1667
+ bonds_str = prev_str[1]#"[ bonds ]\n"
1668
+ constraints_str = prev_str[2]#"[ constraints ]\n"
1669
+ angles_str = prev_str[3]#"[ angles ]\n"
1670
+ dihedrals_str = prev_str[4]#"[ dihedrals ]\n"
1671
+
1672
+ resno = prev_nos[0]
1673
+ atm_no = prev_nos[1]
1674
+ #x y z dir type place linked
1675
+ #0 1 2 3 4 5 6
1676
+ ang_link1=[
1677
+ [2, 1, 8, 2, 90.000, 130.00],
1678
+ [3, 1, 8, 2, 118.000, 100.00],
1679
+ [4, 1, 8, 10, 151.000, 170.00],
1680
+ [1, 8, 6, 10, 70.000, 600.00],
1681
+ [1, 8, 9, 10, 93.000, 180.00],
1682
+ [1, 8, 5, 10, 160.000, 555.00]]
1683
+ a_link_add1 = [[0,0,-1],[0,0,-1],[0,0,-1],[0,-1,-1],[0,-1,-1],[0,-1,-1]]
1684
+ dihedral_link1=[
1685
+ [2, 1, 8, 5, 9, 0.000, 3.50, 1],
1686
+ [2, 1, 8, 5, 9, 0.000, 3.00, 2],
1687
+ [2, 1, 8, 6, 9, 0.000, 3.50, 1],
1688
+ [2, 1, 8, 6, 9, 0.000, 3.00, 2],
1689
+ [3, 1, 8, 9, 9, 0.000, 8.00, 1],
1690
+ [3, 1, 8, 9, 9, 0.000, 2.00, 2],
1691
+ [4, 1, 8, 6, 9, 0.000, 7.00, 1],
1692
+ [4, 1, 8, 6, 9, 0.000, 3.00, 2],
1693
+ [4, 1, 8, 9, 9, 180.000, 2.00, 2],
1694
+ [4, 1, 8, 9, 9, 180.000, 3.00, 3]]
1695
+ ang_link2=[
1696
+ [2, 1, 9, 10, 113.000, 90.00],
1697
+ [3, 1, 9, 10, 99.000, 100.00],
1698
+ [4, 1, 9, 10, 145.000, 250.00],
1699
+ [1, 9, 7, 10, 76.000, 400.00],
1700
+ [1, 9, 6, 10, 135.000, 970.00]]
1701
+
1702
+ a_link_add2 = [[0,0,-1],[0,0,-1],[0,0,-1],[0,-1,-1],[0,-1,-1]]
1703
+
1704
+ dihedral_link2=[
1705
+ [4, 1, 9, 6, 9, 0.000, 8.00, 1],
1706
+ [4, 1, 9, 6, 9, 0.000, 2.00, 2],
1707
+ [4, 1, 9, 7, 9, 0.000, 7.00, 1],
1708
+ [4, 1, 9, 7, 9, 0.000, 3.00, 2],
1709
+ [2, 1, 9, 6, 9, 180.000, 6.00, 1],
1710
+ [2, 1, 9, 6, 9, 0.000, 4.00, 2]]
1711
+
1712
+ atm_start = []
1713
+ for layer in all_lines:
1714
+ atm_start_p1 = []
1715
+ for line in layer:
1716
+ atm_start_p2 = []
1717
+ prev_p = 0
1718
+ for res in line:
1719
+ atm_start_p2.append(atm_no)
1720
+ if(res[5] == 1):
1721
+ r4 = int(res[4])
1722
+
1723
+ if(prev_p == 1):
1724
+ if(r4 == 0):
1725
+ bonds_str += "\t"+str(1+atm_no-4)+"\t"+str(8+atm_no-4)+"\t"+str(1)+"\t"+str(0.316)+"\t"+str(28500.00)+"\n"
1726
+ for ang in ang_link1:
1727
+ angles_str += "\t"+str(ang[0]+atm_no-4)+"\t"+str(ang[1]+atm_no-4)+"\t"+str(ang[2]+atm_no-4)+"\t"+str(ang[3])+"\t"+str(ang[4])+"\t"+str(ang[5])+"\n"
1728
+ for dih in dihedral_link1:
1729
+ dihedrals_str += "\t"+str(dih[0]+atm_no-4)+"\t"+str(dih[1]+atm_no-4)+"\t"+str(dih[2]+atm_no-4)+"\t"+str(dih[3]+atm_no-4)+"\t"+str(dih[4])+"\t"+str(dih[5])+"\t"+str(dih[6])+"\t"+str(dih[7])+"\n"
1730
+ else:
1731
+ bonds_str += "\t"+str(1+atm_no-5)+"\t"+str(9+atm_no-5)+"\t"+str(1)+"\t"+str(0.288)+"\t"+str(32000.00)+"\n"
1732
+ for ang in ang_link2:
1733
+ angles_str += "\t"+str(ang[0]+atm_no-5)+"\t"+str(ang[1]+atm_no-5)+"\t"+str(ang[2]+atm_no-5)+"\t"+str(ang[3])+"\t"+str(ang[4])+"\t"+str(ang[5])+"\n"
1734
+ for dih in dihedral_link2:
1735
+ dihedrals_str += "\t"+str(dih[0]+atm_no-5)+"\t"+str(dih[1]+atm_no-5)+"\t"+str(dih[2]+atm_no-5)+"\t"+str(dih[3]+atm_no-5)+"\t"+str(dih[4])+"\t"+str(dih[5])+"\t"+str(dih[6])+"\t"+str(dih[7])+"\n"
1736
+
1737
+
1738
+ for bd in data[r4][1]:
1739
+ bonds_str += "\t"+str(int(bd[0])+atm_no)+"\t"+str(int(bd[1])+atm_no)+"\t"+bd[2]+"\t"+bd[3]+"\t"+bd[4]+"\n"
1740
+
1741
+
1742
+ for cd in data[r4][2]:
1743
+ constraints_str += "\t"+str(int(cd[0])+atm_no)+"\t"+str(int(cd[1])+atm_no)+"\t"+cd[2]+"\t"+cd[3]+"\t"+cd[4]+"\n"
1744
+ for ad in data[r4][3]:
1745
+ angles_str += "\t"+str(int(ad[0])+atm_no)+"\t"+str(int(ad[1])+atm_no)+"\t"+str(int(ad[2])+atm_no)+"\t"+ad[3]+"\t"+ad[4]+"\t"+ad[5]+"\n"
1746
+ for dd in data[r4][4]:
1747
+ dihedrals_str += "\t"+str(int(dd[0])+atm_no)+"\t"+str(int(dd[1])+atm_no)+"\t"+str(int(dd[2])+atm_no)+"\t"+str(int(dd[3])+atm_no)+"\t"+dd[4]+"\t"+dd[5]+"\t"+dd[6]+"\t"+dd[7]+"\n"
1748
+
1749
+ for ad in data[r4][0]:
1750
+ atoms_str += "\t"+str(atm_no+1)+"\t"+ad[1]+"\t"+str(resno)+"\t"+ad[3]+"\t"+ad[4]+"\t"+str(atm_no+1)+"\t"+ad[6]+"\t"+ad[7]+"\n"
1751
+ atm_no += 1
1752
+
1753
+
1754
+
1755
+ resno += 1
1756
+ prev_p = res[5]
1757
+
1758
+ if(line[0][5] == 1 and line[-1][5] == 1):
1759
+ if(int(line[0][4]) == 0):
1760
+ bonds_str += "\t"+str(1+atm_start_p2[0])+"\t"+str(8+atm_start_p2[-1]-4)+"\t"+str(1)+"\t"+str(0.316)+"\t"+str(28500.00)+"\n"
1761
+ for nn,ang in enumerate(ang_link1):
1762
+ angles_str += "\t"+str(ang[0]+atm_start_p2[a_link_add1[nn][0]]+4*a_link_add1[nn][0])+"\t"+str(ang[1]+atm_start_p2[a_link_add1[nn][1]]+4*a_link_add1[nn][1])+"\t"+str(ang[2]+atm_start_p2[a_link_add1[nn][2]]+4*a_link_add1[nn][2])+"\t"+str(ang[3])+"\t"+str(ang[4])+"\t"+str(ang[5])+"\n"
1763
+ for dih in dihedral_link1:
1764
+ dihedrals_str += "\t"+str(dih[0]+atm_start_p2[0])+"\t"+str(dih[1]+atm_start_p2[0])+"\t"+str(dih[2]+atm_start_p2[-1]-4)+"\t"+str(dih[3]+atm_start_p2[-1]-4)+"\t"+str(dih[4])+"\t"+str(dih[5])+"\t"+str(dih[6])+"\t"+str(dih[7])+"\n"
1765
+ else:
1766
+ bonds_str += "\t"+str(1+atm_start_p2[0])+"\t"+str(9+atm_start_p2[-1]-5)+"\t"+str(1)+"\t"+str(0.288)+"\t"+str(32000.00)+"\n"
1767
+ for nn,ang in enumerate(ang_link2):
1768
+ angles_str += "\t"+str(ang[0]+atm_start_p2[a_link_add2[nn][0]]+5*a_link_add1[nn][0])+"\t"+str(ang[1]+atm_start_p2[a_link_add2[nn][1]]+5*a_link_add1[nn][1])+"\t"+str(ang[2]+atm_start_p2[a_link_add2[nn][2]]+5*a_link_add1[nn][2])+"\t"+str(ang[3])+"\t"+str(ang[4])+"\t"+str(ang[5])+"\n"
1769
+ for dih in dihedral_link2:
1770
+ dihedrals_str += "\t"+str(dih[0]+atm_start_p2[0])+"\t"+str(dih[1]+atm_start_p2[0])+"\t"+str(dih[2]+atm_start_p2[-1]-5)+"\t"+str(dih[3]+atm_start_p2[-1]-5)+"\t"+str(dih[4])+"\t"+str(dih[5])+"\t"+str(dih[6])+"\t"+str(dih[7])+"\n"
1771
+
1772
+
1773
+ atm_start_p1.append(atm_start_p2)
1774
+ atm_start.append(atm_start_p1)
1775
+
1776
+
1777
+ blink3 = [[5, 1, 1, 0.319, 14800.00]]
1778
+
1779
+ ang_link3 =[[ 4, 5, 1, 10, 104.000, 80.00],
1780
+ [5, 1, 3, 10, 107.000, 60.00],
1781
+ [5, 1, 2, 2, 100.000, 25.00]]
1782
+
1783
+ dih_link3 = [[4, 5, 1, 3, 9, 60.000, 3.00, 2],
1784
+ [5, 1, 3, 4, 9, 140.000, 3.00, 2]]
1785
+
1786
+ iplink = [8, 7, 1, 0.350, 1100.00]
1787
+ ang_iplink = [[5,8,7,10,114,75],[8,7,6,10,95,75]]
1788
+
1789
+ cl_atm_start = []
1790
+
1791
+ for lyind,layer in enumerate(all_lines):
1792
+ cl_atm_start_p1 = []
1793
+ for lind,line in enumerate(layer):
1794
+ cl_atm_start_p2 = []
1795
+ for bind,res in enumerate(line):
1796
+ cl_atm_start_p2.append(atm_no)
1797
+ if(res[5] == 1):
1798
+ r4 = int(res[4])
1799
+ if(r4 == 0):
1800
+ if(res[13] == 1):
1801
+ data = uupep_data
1802
+ else:
1803
+ if(res[6] != -1 or res[13] == 2):
1804
+ data = upep_data
1805
+ else:
1806
+ data = spep_data
1807
+
1808
+ b1_s = atm_start[lyind][lind][bind]
1809
+ for bd in blink3:
1810
+ bonds_str += "\t"+str(bd[0]+b1_s)+"\t"+str(bd[1]+atm_no)+"\t"+str(bd[2])+"\t"+str(bd[3])+"\t"+str(bd[4])+"\n"
1811
+
1812
+ angles_str += "\t"+str(ang_link3[0][0]+b1_s)+"\t"+str(ang_link3[0][1]+b1_s)+"\t"+str(ang_link3[0][2]+atm_no)+"\t"+str(ang_link3[0][3])+"\t"+str(ang_link3[0][4])+"\t"+str(ang_link3[0][5])+"\n"
1813
+ angles_str += "\t"+str(ang_link3[1][0]+b1_s)+"\t"+str(ang_link3[1][1]+atm_no)+"\t"+str(ang_link3[1][2]+atm_no)+"\t"+str(ang_link3[1][3])+"\t"+str(ang_link3[1][4])+"\t"+str(ang_link3[1][5])+"\n"
1814
+ angles_str += "\t"+str(ang_link3[2][0]+b1_s)+"\t"+str(ang_link3[2][1]+atm_no)+"\t"+str(ang_link3[2][2]+atm_no)+"\t"+str(ang_link3[2][3])+"\t"+str(ang_link3[2][4])+"\t"+str(ang_link3[2][5])+"\n"
1815
+
1816
+ dihedrals_str += "\t"+str(dih_link3[0][0]+b1_s)+"\t"+str(dih_link3[0][1]+b1_s)+"\t"+str(dih_link3[0][2]+atm_no)+"\t"+str(dih_link3[0][3]+atm_no)+"\t"+str(dih_link3[0][4])+"\t"+str(dih_link3[0][5])+"\t"+str(dih_link3[0][6])+"\t"+str(dih_link3[0][7])+"\n"
1817
+ dihedrals_str += "\t"+str(dih_link3[0][0]+b1_s)+"\t"+str(dih_link3[0][1]+atm_no)+"\t"+str(dih_link3[0][2]+atm_no)+"\t"+str(dih_link3[0][3]+atm_no)+"\t"+str(dih_link3[0][4])+"\t"+str(dih_link3[0][5])+"\t"+str(dih_link3[0][6])+"\t"+str(dih_link3[0][7])+"\n"
1818
+
1819
+ for bd in data[1]:
1820
+ bonds_str += "\t"+str(int(bd[0])+atm_no)+"\t"+str(int(bd[1])+atm_no)+"\t"+bd[2]+"\t"+bd[3]+"\t"+bd[4]+"\n"
1821
+ for cd in data[2]:
1822
+ constraints_str += "\t"+str(int(cd[0])+atm_no)+"\t"+str(int(cd[1])+atm_no)+"\t"+cd[2]+"\t"+cd[3]+"\t"+cd[4]+"\n"
1823
+ for ad in data[3]:
1824
+ angles_str += "\t"+str(int(ad[0])+atm_no)+"\t"+str(int(ad[1])+atm_no)+"\t"+str(int(ad[2])+atm_no)+"\t"+ad[3]+"\t"+ad[4]+"\t"+ad[5]+"\n"
1825
+ for dd in data[4]:
1826
+ dihedrals_str += "\t"+str(int(dd[0])+atm_no)+"\t"+str(int(dd[1])+atm_no)+"\t"+str(int(dd[2])+atm_no)+"\t"+str(int(dd[3])+atm_no)+"\t"+dd[4]+"\t"+dd[5]+"\t"+dd[6]+"\t"+dd[7]+"\n"
1827
+
1828
+ for ad in data[0]:
1829
+ atoms_str += "\t"+str(atm_no+1)+"\t"+ad[1]+"\t"+str(resno)+"\t"+ad[3]+"\t"+ad[4]+"\t"+str(atm_no+1)+"\t"+ad[6]+"\t"+ad[7]+"\n"
1830
+ atm_no += 1
1831
+ resno += 1
1832
+ cl_atm_start_p1.append(cl_atm_start_p2)
1833
+ cl_atm_start.append(cl_atm_start_p1)
1834
+
1835
+ for lyind,layer in enumerate(all_lines):
1836
+ for lind,line in enumerate(layer):
1837
+ for bind,res in enumerate(line):
1838
+ c_atm1 = cl_atm_start[lyind][lind][bind]
1839
+ ly2ind = int(res[8])
1840
+ l2ind = int(res[6])
1841
+ b2ind = int(res[7])
1842
+ if(l2ind != -1):
1843
+ c_atm2 = cl_atm_start[ly2ind][l2ind][b2ind]
1844
+ if(all_lines[lyind][lind][bind][13] == 1 or all_lines[ly2ind][l2ind][b2ind][13] == 1):
1845
+ iplink[0] = 7
1846
+ else:
1847
+ pass
1848
+ #angles_str += "\t"+str(ang_iplink[0][0]+c_atm1)+"\t"+str(ang_iplink[0][1]+c_atm1)+"\t"+str(ang_iplink[0][2]+c_atm2)+"\t"+str(ang_iplink[0][3])+"\t"+str(ang_iplink[0][4])+"\t"+str(ang_iplink[0][5])+"\n"
1849
+ angles_str += "\t"+str(ang_iplink[1][0]+c_atm1)+"\t"+str(ang_iplink[1][1]+c_atm2)+"\t"+str(ang_iplink[1][2]+c_atm2)+"\t"+str(ang_iplink[1][3])+"\t"+str(ang_iplink[1][4])+"\t"+str(ang_iplink[1][5])+"\n"
1850
+
1851
+ bonds_str += "\t"+str(iplink[0]+c_atm1)+"\t"+str(iplink[1]+c_atm2)+"\t"+str(iplink[2])+"\t"+str(iplink[3])+"\t"+str(iplink[4])+"\n"
1852
+
1853
+ return [atoms_str,bonds_str,constraints_str,angles_str,dihedrals_str],[resno,atm_no]
1854
+
1855
+
1856
+
1857
+
1858
+
1859
+ #write the PG itp
1860
+ def write_all_itp(itp_str,out_folder):
1861
+ pgl_file = open(out_folder+"PGL.itp","w")
1862
+ pgl_file.write("[ moleculetype ]\n")
1863
+ pgl_file.write("PGL 1\n\n")
1864
+ pgl_file.write(itp_str[0]+"\n")
1865
+ pgl_file.write(itp_str[1]+"\n")
1866
+ pgl_file.write(itp_str[2]+"\n")
1867
+ pgl_file.write(itp_str[3]+"\n")
1868
+ pgl_file.write(itp_str[4]+"\n")
1869
+ pgl_file.close()
1870
+
1871
+
1872
+ #Function that creates a leaflet using all of the above
1873
+ def create_leaflet(den,xbox,ybox,curv_A,curv_B,ch_ang,pore,leng,keep_end,mem_outer_red):
1874
+ if(curv_A < 1e-5 or curv_B < 1e-5):
1875
+ gpoints3,direcs3 = np.array(DiskGrid(den,0,xbox,ybox,mem_outer_red))
1876
+ return gpoints3,direcs3
1877
+ rad_A = 1.0/curv_A
1878
+ rad_B = 1.0/curv_B
1879
+
1880
+ if(pore):
1881
+ ch_ang=np.pi/2
1882
+
1883
+ c1 = np.cos(ch_ang)
1884
+ s1 = np.sin(ch_ang)
1885
+
1886
+ c2 = np.cos(np.pi/2-ch_ang)
1887
+ s2 = np.sin(np.pi/2-ch_ang)
1888
+
1889
+ in_rad = rad_A*s1+rad_B*(c2-1)
1890
+
1891
+
1892
+ if(not pore):
1893
+ gpoints,direcs = np.array(SphereGridN(den,ch_ang,rad_A))
1894
+ else:
1895
+ gpoints,direcs = np.array(TubeGrid(den,in_rad,leng,keep_end))
1896
+
1897
+
1898
+
1899
+ gpoints2,direcs2 = np.array(InvSphereGrid(den,in_rad,(np.pi/2-ch_ang),rad_B))
1900
+ gpoints3,direcs3 = np.array(DiskGrid(den,rad_B+in_rad,xbox,ybox,mem_outer_red))
1901
+ shift = -gpoints[-1,2]+s2*rad_B-rad_B
1902
+ if(pore):
1903
+ gpoints[:,2] = gpoints[:,2]-rad_B
1904
+ gpoints2[:,2] = gpoints2[:,2]-rad_B
1905
+ gpoints3[:,2] = gpoints3[:,2]
1906
+ else:
1907
+ gpoints2[:,2] = gpoints2[:,2]-rad_B -shift
1908
+ gpoints3[:,2] = gpoints3[:,2] -shift
1909
+
1910
+ gpoints = np.concatenate([gpoints,gpoints2,gpoints3])
1911
+ direcs = np.concatenate([direcs,direcs2,direcs3])
1912
+ return gpoints,direcs
1913
+
1914
+
1915
+ #A fully analytic function of the leaflet. This is very useful for accurate exclusion of solute
1916
+ def leaflet_function(x,y,curv_A,curv_B,ch_ang,pore,leng):
1917
+ if(curv_A < 1e-5 or curv_B < 1e-5):
1918
+ return 0,np.array([0,0,1])
1919
+ rad_p = np.sqrt(x*x+y*y)
1920
+ if(pore):
1921
+ ch_ang=np.pi/2
1922
+
1923
+ c1 = np.cos(ch_ang)
1924
+ s1 = np.sin(ch_ang)
1925
+
1926
+ c2 = np.cos(np.pi/2-ch_ang)
1927
+ s2 = np.sin(np.pi/2-ch_ang)
1928
+ rad_A = 1.0/curv_A
1929
+ rad_B = 1.0/curv_B
1930
+ sphere_rad = s1*rad_A
1931
+ in_rad = rad_A*s1+rad_B*(c2-1)
1932
+ shift = (1-c1)*rad_B-(s2*rad_A-rad_A)
1933
+ if(pore):
1934
+ shift = 0
1935
+ if(rad_p< sphere_rad):
1936
+ if(pore):
1937
+ z = leng
1938
+ direc = np.array([-x,-y,0])
1939
+ return z,direc/np.linalg.norm(direc)
1940
+ else:
1941
+ z = np.sqrt(rad_A*rad_A-rad_p*rad_p)-rad_A
1942
+ direc = np.array([-x,-y,z+rad_A])
1943
+ return z,direc/np.linalg.norm(direc)
1944
+ elif(rad_p < in_rad+rad_B):
1945
+ z = -np.sqrt(rad_B*rad_B-(rad_p-rad_B-in_rad)*(rad_p-rad_B-in_rad))+rad_B-shift
1946
+ xydirec = np.array([x,y])
1947
+ xydirec /= np.linalg.norm(xydirec)
1948
+ direc = np.array([(x-xydirec[0]*(rad_B+in_rad)),(y-xydirec[1]*(rad_B+in_rad)),-(z+shift-rad_B)])
1949
+ return z,direc/np.linalg.norm(direc)
1950
+ else:
1951
+ return -shift,np.array([0,0,1])
1952
+
1953
+ #Get the minimum dimensions required to fit all the curvature
1954
+ def get_box_size(curv_A,curv_B,ch_ang,pore):
1955
+ if(curv_A < 1e-5 or curv_B < 1e-5):
1956
+ return 0,0
1957
+ if(pore):
1958
+ ch_ang=np.pi/2
1959
+
1960
+ c1 = np.cos(ch_ang)
1961
+ s1 = np.sin(ch_ang)
1962
+
1963
+ c2 = np.cos(np.pi/2-ch_ang)
1964
+ s2 = np.sin(np.pi/2-ch_ang)
1965
+ rad_A = 1.0/curv_A
1966
+ rad_B = 1.0/curv_B
1967
+
1968
+ in_rad = rad_A*s1+rad_B*(c2-1)
1969
+ height = rad_A*(1-c1)+rad_B*(1-c1)
1970
+ return in_rad+rad_B,height
1971
+
1972
+ #A function for binning points into a fixed grid
1973
+ def put_into_grid(x,r,n,s):
1974
+ cx = x[0]-s[0]
1975
+ cy = x[1]-s[1]
1976
+ norm_x = cx/r[0]
1977
+ norm_y = cy/r[1]
1978
+ grid_x = n[0]*norm_x
1979
+ grid_y = n[1]*norm_y
1980
+ return int(np.floor(grid_x)),int(np.floor(grid_y))
1981
+
1982
+ #Used with above
1983
+ def bin_grid(grid_in,r,n,s):
1984
+ grid_final = np.zeros((n[0],n[1]))
1985
+ grid = np.zeros((n[0],n[1],grid_in.shape[0]+1))
1986
+ for k in range(grid_in.shape[0]):
1987
+ gx,gy = put_into_grid(grid_in[k,:2],r,n,s)
1988
+ grid[gx,gy,int(grid[gx,gy,-1])] = grid_in[k,2]
1989
+ grid[gx,gy,-1] += 1
1990
+ for i in range(n[0]):
1991
+ for j in range(n[1]):
1992
+ if(grid[i,j,-1] == 0):
1993
+ grid_final[i,j] = np.nan
1994
+ else:
1995
+ grid_final[i,j] = np.sum(grid[i,j,:-1])/grid[i,j,-1]
1996
+ return grid_final
1997
+
1998
+ #Another method of binning points.
1999
+ def get_box_slice(points,p,r):
2000
+ pslice = points[points[:,0]>p[0]-r[0]]
2001
+ pslice = pslice[pslice[:,0]<p[0]+r[0]]
2002
+ pslice = pslice[pslice[:,1]>p[1]-r[1]]
2003
+ pslice = pslice[pslice[:,1]<p[1]+r[1]]
2004
+ pslice = pslice[pslice[:,2]>p[2]-r[2]]
2005
+ pslice = pslice[pslice[:,2]<p[2]+r[2]]
2006
+ return pslice
2007
+
2008
+
2009
+ #This is a function for sorting atoms for a neater topology file
2010
+ def reorder_atoms(atoms,coords):
2011
+ lip_names = []
2012
+ lip_split = []
2013
+ lip_split_coords = []
2014
+ for i,a in enumerate(atoms):
2015
+ if(a[1] in lip_names):
2016
+ lip_split[lip_names.index(a[1])].append(list(a))
2017
+ lip_split_coords[lip_names.index(a[1])].append(coords[i])
2018
+ else:
2019
+ lip_names.append(a[1])
2020
+ lip_split.append([])
2021
+ lip_split_coords.append([])
2022
+ lip_split[-1].append(list(a))
2023
+ lip_split_coords[-1].append(coords[i])
2024
+ count = 1
2025
+ prev = 1
2026
+ for i in lip_split:
2027
+ for k in i:
2028
+ if(k[2] == prev):
2029
+ k[2] = count
2030
+ else:
2031
+ prev = k[2]
2032
+ count += 1
2033
+ k[2] = count
2034
+ new_atoms = []
2035
+ new_coords = []
2036
+ for i in range(len(lip_split)):
2037
+ for k in range(len(lip_split[i])):
2038
+ new_atoms.append(lip_split[i][k])
2039
+ new_coords.append(lip_split_coords[i][k])
2040
+ return new_atoms,new_coords
2041
+
2042
+ #Ignore this
2043
+ def LocBias(coords,lnums,lipids,steps,loc_lipids,bias_grid):
2044
+ lipids=list(lipids)
2045
+ lip_ranges = []
2046
+ total = 0
2047
+ for l in range(len(lipids)):
2048
+ lip_ranges.append([total,total+lnums[l]])
2049
+ total += lnums[l]
2050
+ swap = []
2051
+ nswap = []
2052
+ for l in range(len(lipids)):
2053
+ if lipids[l] in loc_lipids:
2054
+ swap.append(l)
2055
+ else:
2056
+ nswap.append(l)
2057
+ for i in range(steps):
2058
+ bulk = random.choice(nswap)
2059
+ swaper = random.choice(swap)
2060
+ bstart,bend = lip_ranges[bulk]
2061
+ sstart,send = lip_ranges[swaper]
2062
+ blip = random.randint(bstart,bend-1)
2063
+ slip = random.randint(sstart,send-1)
2064
+ bcoord = coords[blip]
2065
+ scoord = coords[slip]
2066
+ binda,bindb = put_into_grid(bcoord[:2],[pbcx, pbcy],[bias_grid.shape[0],bias_grid.shape[1]],[0,0])
2067
+ sinda,sindb = put_into_grid(scoord[:2],[pbcx, pbcy],[bias_grid.shape[0],bias_grid.shape[1]],[0,0])
2068
+
2069
+ swap_val = -bias_grid[sinda,sindb]+bias_grid[binda,bindb]
2070
+ swap_prob = 1/(1+np.exp(-0.3*swap_val))
2071
+
2072
+ if random.random() < swap_prob:
2073
+ coords[slip]=bcoord
2074
+ coords[blip]=scoord
2075
+ return coords
2076
+
2077
+ #gets charge between a lower and upper bound, for neutralising compartments
2078
+ def get_charge(lz,uz):
2079
+ last = None
2080
+ mcharge = 0
2081
+ for ind,j in enumerate(membrane.atoms):
2082
+ pos = membrane.coord[ind]
2083
+ if not j[0].strip().startswith('v') and j[1:3] != last:
2084
+ if(pos[2] > lz and pos[2] < uz):
2085
+ mcharge += charges.get(j[1].strip(),0)
2086
+ last = j[1:3]
2087
+
2088
+ last = None
2089
+ pgcharge = 0
2090
+ for ind,j in enumerate(PGL.atoms):
2091
+ pos = PGL.coord[ind]
2092
+ if not j[0].strip().startswith('v') and j[1:3] != last:
2093
+ if(pos[2] > lz and pos[2] < uz):
2094
+ pgcharge += charges.get(j[1].strip(),0)
2095
+ last = j[1:3]
2096
+
2097
+ last = None
2098
+ pcharge = 0
2099
+ for ind,j in enumerate(protein.atoms):
2100
+ pos = protein.coord[ind]
2101
+ if not j[0].strip().startswith('v') and j[1:3] != last:
2102
+ if(pos[2] > lz and pos[2] < uz):
2103
+ pcharge += charges.get(j[1].strip(),0)
2104
+ last = j[1:3]
2105
+ total_charge = mcharge+pgcharge+pcharge
2106
+ return total_charge,pcharge,mcharge,pgcharge
2107
+
2108
+
2109
+ #This function creates a list of indicies containing a PG oligomer
2110
+ def count_olig_list(all_lines,lyind,lind,bind):
2111
+ done = False
2112
+ count = 1
2113
+ all_linesT = all_lines.copy()
2114
+ pposes = [int(all_linesT[lyind,lind,bind,12])]
2115
+ if(all_linesT[lyind][lind][bind][13] == 1):
2116
+ if(all_linesT[lyind,lind,bind,6] > -0.5):
2117
+ tnlind = int(all_linesT[lyind,lind,bind,6])
2118
+ tnbind = int(all_linesT[lyind,lind,bind,7])
2119
+ tnlyind = int(all_linesT[lyind,lind,bind,8])
2120
+ nlind = tnlind
2121
+ nbind = tnbind
2122
+ nlyind = tnlyind
2123
+ switcher = 6
2124
+ elif(all_linesT[lyind,lind,bind,9] > -0.5):
2125
+ tnlind = int(all_linesT[lyind,lind,bind,9])
2126
+ tnbind = int(all_linesT[lyind,lind,bind,10])
2127
+ tnlyind = int(all_linesT[lyind,lind,bind,11])
2128
+ nlind = tnlind
2129
+ nbind = tnbind
2130
+ nlyind = tnlyind
2131
+ switcher = 9
2132
+ pposes.append(int(all_linesT[nlyind,nlind,nbind,12]))
2133
+ return pposes, False
2134
+ if(all_linesT[lyind,lind,bind,6] > -0.5):
2135
+ tnlind = int(all_linesT[lyind,lind,bind,6])
2136
+ tnbind = int(all_linesT[lyind,lind,bind,7])
2137
+ tnlyind = int(all_linesT[lyind,lind,bind,8])
2138
+ nlind = tnlind
2139
+ nbind = tnbind
2140
+ nlyind = tnlyind
2141
+ switcher = 6
2142
+ elif(all_linesT[lyind,lind,bind,9] > -0.5):
2143
+ tnlind = int(all_linesT[lyind,lind,bind,9])
2144
+ tnbind = int(all_linesT[lyind,lind,bind,10])
2145
+ tnlyind = int(all_linesT[lyind,lind,bind,11])
2146
+ nlind = tnlind
2147
+ nbind = tnbind
2148
+ nlyind = tnlyind
2149
+ switcher = 9
2150
+ else:
2151
+ return pposes,False
2152
+ while not done:
2153
+ count += 1
2154
+ pposes.append(int(all_linesT[nlyind,nlind,nbind,12]))
2155
+ if(all_linesT[nlyind,nlind,nbind,13] == 1):
2156
+ return pposes,False
2157
+
2158
+ tnlind = int(all_linesT[nlyind,nlind,nbind,switcher])
2159
+ tnbind = int(all_linesT[nlyind,nlind,nbind,switcher+1])
2160
+ tnlyind = int(all_linesT[nlyind,nlind,nbind,switcher+2])
2161
+ nlind = tnlind
2162
+ nbind = tnbind
2163
+ nlyind = tnlyind
2164
+ if(nlind < 0):
2165
+ done = True
2166
+ break
2167
+ return pposes, True
2168
+
2169
+ #Applies the above to all
2170
+ def count_all_olig_list(all_lines):
2171
+ test_lines = all_lines[np.logical_and(all_lines[:,:,:,5] == 1,all_lines[:,:,:,4] == 0),:]
2172
+ olig_lens = []
2173
+ olig_count = 0
2174
+ for ly in range(all_lines.shape[0]):
2175
+ for l in range(all_lines[ly].shape[0]):
2176
+ for b in range(all_lines[ly,l].shape[0]):
2177
+ if(all_lines[ly,l,b,5] == 1 and all_lines[ly,l,b,4] == 0):
2178
+ num,_ = count_olig_list(all_lines,ly,l,b)
2179
+ olig_lens.append(num)
2180
+ olig_count += 1
2181
+ return olig_lens
2182
+
2183
+ #Gets the distance and periodic copy that is closest
2184
+ def get_closest_pos(pos1,pos2,box_size):
2185
+ min_dist = 100000
2186
+ part_copy = np.array([0,0])
2187
+ for i in [-1,0,1]:
2188
+ for k in [-1,0,1]:
2189
+ dister = np.linalg.norm(pos1-(pos2+np.array([i,k])*box_size))
2190
+ if(dister< min_dist):
2191
+ min_dist = dister
2192
+ part_copy[0] = i
2193
+ part_copy[1] = k
2194
+
2195
+ return min_dist,part_copy
2196
+
2197
+ #a version of the above for use in jitted parts
2198
+ @jax.jit
2199
+ def get_closest_pos_jax(pos1,pos2,box_size):
2200
+ min_dist = 100000.0
2201
+ part_copy = jnp.array([0,0])
2202
+ def loop1(carry,ind1):
2203
+ def loop2(carry,ind2):
2204
+ part_copy = carry[0]
2205
+ min_dist = carry[1]
2206
+ dister = jnp.linalg.norm(pos1-(pos2+jnp.array([ind1,ind2])*box_size))
2207
+ def leq(part_copy,min_dist):
2208
+ part_copy = jnp.array([ind1,ind2])
2209
+ min_dist= dister
2210
+ return part_copy,min_dist
2211
+ def geq(part_copy,min_dist):
2212
+ return part_copy,min_dist
2213
+ part_copy,min_dist = jax.lax.cond(dister<min_dist,leq,geq,part_copy,min_dist)
2214
+ return (part_copy,min_dist),ind2
2215
+ carry,_ =jax.lax.scan(loop2,carry,jnp.array([-1,0,1]))
2216
+ return carry,ind1
2217
+ carry,_ = jax.lax.scan(loop1,(part_copy,min_dist),jnp.array([-1,0,1]))
2218
+ return carry[1],carry[0]
2219
+
2220
+ #function that constrains values to cell
2221
+ def enforce_pbc2(ppos,box_size):
2222
+ box = [0,0,box_size[0],box_size[1]]
2223
+ for p in range(ppos.shape[0]):
2224
+ if(ppos[p,0]-box[0] < 0):
2225
+ ppos[p,0] += box[2]
2226
+ if(ppos[p,1]-box[1] < 0):
2227
+ ppos[p,1] += box[3]
2228
+ ppos[p,0] = np.fmod(ppos[p,0]-box[0],box[2])+box[0]
2229
+ ppos[p,1] = np.fmod(ppos[p,1]-box[1],box[3])+box[1]
2230
+ return ppos
2231
+
2232
+ #a jitted version of the above
2233
+ @jax.jit
2234
+ def enforce_pbc_jax(ppos,box_size):
2235
+ box = jnp.array([box_size[0],box_size[1]])
2236
+ def pos_loop(ppos,ind):
2237
+ def lzero1(val):
2238
+ return val+box[0]
2239
+ def gzero(val):
2240
+ return val
2241
+ def lzero2(val):
2242
+ return val+box[1]
2243
+ ppos = ppos.at[ind,0].set(jax.lax.cond(ppos[ind,0]<0,lzero1,gzero,ppos[ind,0]))
2244
+ ppos = ppos.at[ind,1].set(jax.lax.cond(ppos[ind,1]<0,lzero2,gzero,ppos[ind,1]))
2245
+ ppos = ppos.at[ind,0].set(jnp.fmod(ppos[ind,0],box[0]))
2246
+ ppos = ppos.at[ind,1].set(jnp.fmod(ppos[ind,1],box[1]))
2247
+ return ppos,ind
2248
+ ppos,_ = jax.lax.scan(pos_loop,ppos,jnp.arange(ppos.shape[0]))
2249
+ return ppos
2250
+
2251
+ #calculation of the acceleration given position and bonds
2252
+ @jax.jit
2253
+ def calc_acc_jax(ppos,bonds,box_size):
2254
+ pacc = jnp.zeros_like(ppos)
2255
+ def bond_loop(pacc,ind):
2256
+ bind1 = jnp.array(bonds[ind,0],dtype=int)
2257
+ bind2 = jnp.array(bonds[ind,1],dtype=int)
2258
+ pa = ppos[bind1]
2259
+ pb = ppos[bind2]
2260
+ min_dist,part_copy = get_closest_pos_jax(pa,pb,box_size)
2261
+ err_dist = bonds[ind,2]-min_dist
2262
+ direc = (pa-(pb+part_copy*box_size))/min_dist
2263
+ force = err_dist*direc
2264
+ pacc = pacc.at[bind1].set(pacc[bind1]+force)
2265
+ pacc = pacc.at[bind2].set(pacc[bind2]-force)
2266
+ return pacc,ind
2267
+ pacc,_ = jax.lax.scan(bond_loop,pacc,jnp.arange(bonds.shape[0]))
2268
+ return pacc
2269
+
2270
+ #some minor protein repulsion to avoid major clashes
2271
+ @jax.jit
2272
+ def prot_repul_jax(all_p_pad,ppos,plys,all_p_lens):
2273
+ pacc = jnp.zeros_like(ppos)
2274
+ ls = jnp.zeros(all_p_lens.shape[0])
2275
+ def loop1(ls,ind):
2276
+ ls = ls.at[ind].set(jnp.sum(all_p_pad[ind,:,2])/all_p_lens[ind])
2277
+ return ls,ind
2278
+ ls,_ = jax.lax.scan(loop1,ls,jnp.arange(all_p_lens.shape[0]))
2279
+
2280
+ def loop2(pacc,ind1):
2281
+ def loop3(layer,ind2):
2282
+ def close(layer):
2283
+ layer = ind2
2284
+ return layer
2285
+ def far(layer):
2286
+ return layer
2287
+ layer = jax.lax.cond(jnp.abs(plys[ind1]-ls[ind2]) < 1, close,far,layer)
2288
+ return layer,ind2
2289
+ layer,_ = jax.lax.scan(loop3,0,jnp.arange(ls.shape[0]))
2290
+
2291
+ def loop4(pacc,ind2):
2292
+ direc = ppos[ind1]-all_p_pad[layer,ind2,:2]*50
2293
+ dirlen = jnp.linalg.norm(direc)
2294
+ direc /= dirlen
2295
+ def cutoff():
2296
+ return 0.0
2297
+ def ncutoff():
2298
+ return 170.0
2299
+ force = jax.lax.cond(jnp.logical_or(dirlen > 70,ind2>all_p_lens[layer]), cutoff,ncutoff)
2300
+ pacc = pacc.at[ind1].set(pacc[ind1]+force*direc/dirlen)
2301
+ return pacc,ind2
2302
+ pacc,_ = jax.lax.scan(loop4,pacc,jnp.arange(all_p_pad.shape[1]))
2303
+ return pacc,ind1
2304
+ pacc,_ = jax.lax.scan(loop2,pacc,jnp.arange(ppos.shape[0]))
2305
+
2306
+ return pacc
2307
+
2308
+ #core update function
2309
+ @partial(jax.jit,static_argnums=9)
2310
+ def update_pos_jax(ppos,pvel,pacc,bonds,dt,box_size,plys,all_p_pad,all_p_lens,ngly):
2311
+ pacc = calc_acc_jax(ppos,bonds,box_size)+prot_repul_jax(all_p_pad,ppos,plys,all_p_lens)
2312
+ pvel += pacc*dt+(-0.9*pvel*dt)
2313
+ ppos += pvel*dt
2314
+ ppos = enforce_pbc_jax(ppos,box_size)
2315
+ return ppos,pvel,pacc
2316
+
2317
+ #getting the total contraction/extention force over each bond
2318
+ @jax.jit
2319
+ def get_boxforce_jax(bonds,ppos,box_size):
2320
+ total_force = jnp.zeros(2)
2321
+
2322
+ def bfor_loop(total_force,ind):
2323
+ bind1 = jnp.array(bonds[ind,0],dtype=int)
2324
+ bind2 = jnp.array(bonds[ind,1],dtype=int)
2325
+ pa = ppos[bind1]
2326
+ pb = ppos[bind2]
2327
+ min_dist,part_copy = get_closest_pos_jax(pa,pb,box_size)
2328
+
2329
+ err_dist = bonds[ind,2]-min_dist
2330
+ direc = (pa-(pb+part_copy*box_size))/min_dist
2331
+
2332
+ force = err_dist*jnp.abs(direc)
2333
+ total_force += force
2334
+ return total_force,ind
2335
+ total_force,_ = jax.lax.scan(bfor_loop,total_force,jnp.arange(bonds.shape[0]))
2336
+ return total_force
2337
+
2338
+
2339
+ #resecaling coordinates when the box size changes
2340
+ @jax.jit
2341
+ def rescale_to_new_box_jax(ppos,old_boxsize,new_boxsize):
2342
+ def nbloop(ppos,ind):
2343
+ ppos = ppos.at[ind,0].set(((ppos[ind,0])/old_boxsize[0])*new_boxsize[0])
2344
+ ppos = ppos.at[ind,1].set(((ppos[ind,1])/old_boxsize[1])*new_boxsize[1])
2345
+ return ppos,ind
2346
+ ppos,_ = jax.lax.scan(nbloop,ppos,jnp.arange(ppos.shape[0]))
2347
+ return ppos
2348
+
2349
+
2350
+ #This is a large function that uses a basic physics model to relax the PG layer such that tension is 0 and there are no clashed with the protein
2351
+ def relax_pg(gposes,box_size,tol,all_p):
2352
+ nly = gposes.shape[0]
2353
+ gposes_temp = gposes.reshape((int(gposes.size/14),14))
2354
+
2355
+ particles_pos = []
2356
+ particle_layer = []
2357
+ bonds = []
2358
+ gly_lens = 1.0*50
2359
+ spep_lens = 1.5*50
2360
+ upep_lens = 1.2*50
2361
+ tupep_lens = 0.2*50
2362
+
2363
+ bond_next = False
2364
+ prev_x = 0
2365
+ prev_z = -1
2366
+ chx = 0
2367
+ pind_chx = 0
2368
+ for ind,pgpos in enumerate(gposes_temp):
2369
+ if pgpos[5] == 1:
2370
+ if pgpos[4] == 0:
2371
+ if bond_next and pgpos[0] == prev_x and pgpos[2] == prev_z:
2372
+ bonds.append([len(particles_pos),len(particles_pos)-1,gly_lens])
2373
+ if pgpos[0] != prev_x:
2374
+ a = gposes_temp[-1]
2375
+ b = gposes_temp[chx]
2376
+ if(a[5] == 1 and b[5] == 1):
2377
+ bonds.append([pind_chx,len(particles_pos)-1,gly_lens])
2378
+ chx = ind
2379
+ pind_chx = len(particles_pos)
2380
+ inder = np.unravel_index(ind,(gposes.shape[0],gposes.shape[1],gposes.shape[2]))
2381
+ gposes[inder[0],inder[1],inder[2],12] = len(particles_pos)
2382
+ particles_pos.append(pgpos[:2]*50)
2383
+ particle_layer.append(pgpos[2])
2384
+ bond_next = True
2385
+ prev_x = pgpos[0]
2386
+ prev_z = pgpos[2]
2387
+ else:
2388
+ bond_next = False
2389
+
2390
+ ngly = len(particles_pos)
2391
+
2392
+ a = gposes_temp[np.logical_and(gposes_temp[:,5] == 1,gposes_temp[:,4] == 0)][-1]
2393
+ b = gposes_temp[chx]
2394
+ if(a[5] == 1 and b[5] == 1):
2395
+ bonds.append([pind_chx,len(particles_pos)-1,gly_lens])
2396
+
2397
+ groups = count_all_olig_list(gposes)
2398
+
2399
+ nover_groups = []
2400
+ replace_ind = 0
2401
+ for xi,i in enumerate(groups):
2402
+ replace = False
2403
+ add = True
2404
+ for xk,k in enumerate(nover_groups):
2405
+ if(set(i) >= set(k)):
2406
+ replace = True
2407
+ replace_ind = xk
2408
+ add = False
2409
+ break
2410
+ if(set(i) <= set(k)):
2411
+ add = False
2412
+ break
2413
+ if add:
2414
+ nover_groups.append(i)
2415
+ if replace:
2416
+ nover_groups[replace_ind] = i
2417
+
2418
+ for i in nover_groups:
2419
+ if(len(i) == 2):
2420
+ _,part_copy = get_closest_pos(particles_pos[i[0]],particles_pos[i[1]],box_size)
2421
+ mean_part = (particles_pos[i[0]]+particles_pos[i[1]]+part_copy*box_size)/2.0
2422
+ bonds.append([len(particles_pos),i[0],spep_lens])
2423
+ bonds.append([len(particles_pos),i[1],upep_lens])
2424
+ particles_pos.append(mean_part)
2425
+ particle_layer.append(particle_layer[i[0]])
2426
+ if(len(i) > 2):
2427
+ part_in_group = []
2428
+ for k in i:
2429
+ part_in_group.append(particles_pos[k])
2430
+ part_in_group = np.array(part_in_group)
2431
+ ind_in_group = np.array(i)
2432
+ side1 = part_in_group[part_in_group[:,0] == part_in_group[0,0]]
2433
+ side2 = part_in_group[part_in_group[:,0] != part_in_group[0,0]]
2434
+ iside1 = ind_in_group[part_in_group[:,0] == part_in_group[0,0]]
2435
+ iside2 = ind_in_group[part_in_group[:,0] != part_in_group[0,0]]
2436
+ sind1 = np.argsort(side1[:,1])
2437
+ sind2 = np.argsort(side2[:,1])
2438
+ side1 = side1[sind1]
2439
+ side2 = side2[sind2]
2440
+ iside1 = iside1[sind1]
2441
+ iside2 = iside2[sind2]
2442
+ inter_group = np.empty((side1.shape[0] + side2.shape[0],2), dtype=side1.dtype)
2443
+ ind_inter_group = np.empty((iside1.size + iside2.size,), dtype=iside1.dtype)
2444
+ if(side1.size > side2.size):
2445
+ inter_group[0::2,:] = side1
2446
+ inter_group[1::2,:] = side2
2447
+ ind_inter_group[0::2] = iside1
2448
+ ind_inter_group[1::2] = iside2
2449
+ else:
2450
+ inter_group[0::2,:] = side2
2451
+ inter_group[1::2,:] = side1
2452
+ ind_inter_group[0::2] = iside2
2453
+ ind_inter_group[1::2] = iside1
2454
+ for k in range(len(i)-1):
2455
+ if(k != 0):
2456
+ bonds.append([len(particles_pos),ind_inter_group[k],upep_lens-tupep_lens])
2457
+ bonds.append([len(particles_pos),len(particles_pos)-1,tupep_lens])
2458
+ else:
2459
+ bonds.append([len(particles_pos),ind_inter_group[k],upep_lens])
2460
+ _,part_copy = get_closest_pos(inter_group[k],inter_group[k+1],box_size)
2461
+ mean_part = (inter_group[k]+inter_group[k+1]+part_copy*box_size)/2.0
2462
+ particles_pos.append(mean_part)
2463
+ particle_layer.append(particle_layer[ind_inter_group[k]])
2464
+ bonds.append([len(particles_pos)-1,ind_inter_group[-1],spep_lens])
2465
+
2466
+ ppos = jnp.array(particles_pos)
2467
+ plys = jnp.array(particle_layer)
2468
+ pvel = jnp.zeros_like(ppos)
2469
+ pacc = jnp.zeros_like(ppos)
2470
+
2471
+ box_size = jnp.array(box_size)
2472
+ bonds = jnp.array(bonds)
2473
+
2474
+
2475
+ ppos = enforce_pbc_jax(ppos,box_size)
2476
+ box_vel = jnp.zeros(2)
2477
+ box_dt = 0.2
2478
+ count = 0
2479
+ tforce_add = jnp.zeros(2)
2480
+
2481
+ tforce = get_boxforce_jax(bonds,ppos,box_size)/nly
2482
+ tcheck = tforce.copy()
2483
+
2484
+ all_p_lens = []
2485
+ max_len = 0
2486
+ for ap in all_p:
2487
+ if(ap.shape[0] > max_len):
2488
+ max_len = ap.shape[0]
2489
+ all_p_lens.append(ap.shape[0])
2490
+ all_p_lens = np.array(all_p_lens)
2491
+ for ap in range(all_p_lens.shape[0]):
2492
+ all_p[ap] = np.pad(all_p[ap],((0,max_len-all_p[ap].shape[0]),(0,0)),"constant",constant_values=((0,0),(0,0)))
2493
+ all_p_pad = jnp.array(all_p)
2494
+ all_p_lens = jnp.array(all_p_lens,dtype=int)
2495
+ if all_p_pad.shape[1] == 0:
2496
+ all_p_pad = jnp.zeros((all_p_pad.shape[0],1,3))
2497
+
2498
+ while np.linalg.norm(tcheck) > tol:
2499
+ try:
2500
+ count += 1
2501
+ ppos,pvel,pacc = update_pos_jax(ppos,pvel,pacc,bonds,0.3,box_size,plys,all_p_pad,all_p_lens,ngly)
2502
+ tforce = get_boxforce_jax(bonds,ppos,box_size)/nly
2503
+ old_box_size = box_size.copy()
2504
+ if(count % 40 == 0):
2505
+ #sc += 10
2506
+ box_vel += (tforce_add-box_vel*0.5)*box_dt
2507
+ box_size += (tforce_add)*box_dt
2508
+ ppos = rescale_to_new_box_jax(ppos,old_box_size,box_size)
2509
+ tforce_add = jnp.zeros(2)
2510
+ tcheck = tforce.copy()
2511
+ else:
2512
+ tforce_add = tforce
2513
+ except KeyboardInterrupt:
2514
+ break
2515
+
2516
+ ppos = np.array(ppos)
2517
+ box_size = np.array(box_size)
2518
+
2519
+ cind = 0
2520
+ for ind,pgpos in enumerate(gposes_temp):
2521
+ if pgpos[5] == 1:
2522
+ if pgpos[4] == 0:
2523
+ inder = np.unravel_index(ind,(gposes.shape[0],gposes.shape[1],gposes.shape[2]))
2524
+ gposes[inder[0],inder[1],inder[2],:2] = ppos[cind]
2525
+ cind += 1
2526
+
2527
+ for ly in gposes:
2528
+ for line in ly:
2529
+ for ind,pos in enumerate(line):
2530
+ if pos[5] == 1:
2531
+ if pos[4] == 1:
2532
+ ll = line.shape[0]
2533
+ if line[(ind+1)%ll][5] == 1:
2534
+ if line[(ind-1)%ll][5] == 1:
2535
+ _,pcpy = get_closest_pos(line[(ind+1)%ll][:2],line[(ind-1)%ll][:2],box_size)
2536
+ line[ind][:2] = enforce_pbc2(np.array([(line[(ind+1)%ll][:2]+line[(ind-1)%ll][:2]+pcpy*box_size)/2]),box_size)[0]
2537
+ else:
2538
+ _,pcpy = get_closest_pos(line[(ind+1)%ll][:2],line[(ind+3)%ll][:2],box_size)
2539
+ direc = line[(ind+1)%ll][:2]-(line[(ind+3)%ll][:2]+pcpy*box_size)
2540
+ direc /= np.linalg.norm(direc)
2541
+ direc = np.array([0,-1])
2542
+ line[ind][:2]=enforce_pbc2(np.array([50*0.5*direc+line[(ind+1)%ll][:2]]),box_size)[0]
2543
+
2544
+ gposes[:,:,:,:2] /= 50
2545
+ return box_size,gposes
2546
+
2547
+
2548
+ #This function uses a flood fill algorithm to identifiy the inside of a protein. This works better than the basic method used in ring.
2549
+ def flood_fill(grid,add_in):
2550
+ to_test = [[0,0]]
2551
+ done = []
2552
+ flagged = np.zeros_like(grid)
2553
+ while len(to_test) > 0:
2554
+ ct = to_test[0]
2555
+ if add_in:
2556
+ flagged[ct[0],ct[1]] = 1
2557
+ if grid[ct[0],ct[1]] == 0:
2558
+ flagged[ct[0],ct[1]] = 1
2559
+ poss_tests = [[ct[0]-1,ct[1]],[ct[0]+1,ct[1]],[ct[0],ct[1]+1],[ct[0],ct[1]-1]]
2560
+ for i in poss_tests:
2561
+ if i[0] >= 0 and i[1] >= 0 and i[0] < grid.shape[0] and i[1] < grid.shape[1]:
2562
+ already_done = False
2563
+ for d in done:
2564
+ if d[0] == i[0] and d[1] == i[1]:
2565
+ already_done = True
2566
+ break
2567
+ for d in to_test:
2568
+ if d[0] == i[0] and d[1] == i[1]:
2569
+ already_done = True
2570
+ break
2571
+ if not already_done:
2572
+ to_test.append(i)
2573
+ done.append(to_test[0])
2574
+ del to_test[0]
2575
+ return flagged
2576
+
2577
+ @jax.jit
2578
+ def place_bead(cen,rad,direc,SpGrid,points,tol):
2579
+ start_place = True
2580
+ def loop2(start_place,ind2):
2581
+ def placed(start_place):
2582
+ return start_place
2583
+ def nplaced(start_place):
2584
+ start_place = False
2585
+ return start_place
2586
+ start_place = jax.lax.cond(jnp.linalg.norm(cen-points[ind2])<tol,nplaced,placed,start_place)
2587
+ return start_place,ind2
2588
+ start_place,_ = jax.lax.scan(loop2,start_place,jnp.arange(points.shape[0]))
2589
+ def ncoll():
2590
+ upp = jnp.array([0,0,1])
2591
+ direc2 = direc+1e-4*jnp.linalg.norm(upp+direc)
2592
+ direc2 /= jnp.linalg.norm(direc2)
2593
+ angl = jnp.dot(-direc2,upp)
2594
+
2595
+
2596
+ v = jnp.cross(upp,-direc2)
2597
+ vmat = jnp.array([[0,-v[2],v[1]],[v[2],0,-v[0]],[-v[1],v[0],0]])
2598
+ rot_mat = jnp.eye(3)+vmat+jnp.dot(vmat,vmat)*1/(1+angl)
2599
+
2600
+ newSpGrid = jnp.dot(rot_mat,SpGrid.T).T
2601
+ newSpGrid = newSpGrid*rad+cen
2602
+ can_place = True
2603
+ stop = False
2604
+ new_pos = jnp.zeros(3,dtype=float)
2605
+ def loop1(carry,ind1):
2606
+ can_place = carry[1]
2607
+ new_pos = carry[0]
2608
+ stop = carry[2]
2609
+ def stopped(can_place,new_pos,stop):
2610
+ return can_place,new_pos,stop
2611
+ def nstopped(can_place,new_pos,stop):
2612
+ can_place = True
2613
+ def loop2(can_place,ind2):
2614
+ def placed(can_place):
2615
+ return can_place
2616
+ def nplaced(can_place):
2617
+ can_place = False
2618
+ return can_place
2619
+ can_place = jax.lax.cond(jnp.linalg.norm(newSpGrid[ind1]-points[ind2])<tol,nplaced,placed,can_place)
2620
+ return can_place,ind2
2621
+ can_place,_ = jax.lax.scan(loop2,can_place,jnp.arange(points.shape[0]))
2622
+ def cplace(new_pos,stop):
2623
+ new_pos = newSpGrid[ind1]
2624
+ stop = True
2625
+ return new_pos,stop
2626
+ def ncplace(new_pos,stop):
2627
+ return new_pos,stop
2628
+ new_pos,stop = jax.lax.cond(can_place,cplace,ncplace,new_pos,stop)
2629
+ return can_place,new_pos,stop
2630
+ can_place,new_pos,stop = jax.lax.cond(stop,stopped,nstopped,can_place,new_pos,stop)
2631
+ return (new_pos,can_place,stop),ind1
2632
+ carry,_=jax.lax.scan(loop1,(new_pos,can_place,stop),jnp.arange(newSpGrid.shape[0]))
2633
+ new_pos = carry[0]
2634
+ can_place = carry[1]
2635
+ return new_pos,can_place
2636
+ def coll():
2637
+ return jnp.zeros(3),False
2638
+ new_pos,can_place = jax.lax.cond(start_place,ncoll,coll)
2639
+ return new_pos,can_place
2640
+
2641
+ tm = []
2642
+ lipL = []
2643
+ lipU = []
2644
+ lipL_loc = []
2645
+ lipU_loc = []
2646
+ lipLO = []
2647
+ lipUO = []
2648
+ solv = []
2649
+ pos_ions = [[],[],[]]
2650
+ neg_ions = [[],[],[]]
2651
+
2652
+ # HII edit - lipid definition, for extra lipid definitaions
2653
+ usrmols = []
2654
+ usrheads = []
2655
+ usrlinks = []
2656
+ usrtails = []
2657
+ usrLipHeadMapp = { # Define supported lipid head beads. One letter name mapped to atom name
2658
+ "C": ('NC3'), # NC3 = Choline
2659
+ "E": ('NH3'), # NH3 = Ethanolamine
2660
+ "G": ('GL0'), # GL0 = Glycerol
2661
+ "S": ('CNO'), # CNO = Serine
2662
+ "P": ('PO4'), # PO4 = Phosphate
2663
+ "O": ('PO4') # PO4 = Phosphate acid
2664
+ }
2665
+ usrIndexToLetter = "A B C D E F G H I J K L M N".split() # For naming lipid tail beads
2666
+
2667
+ # Description
2668
+ desc = ""
2669
+
2670
+ # Option list
2671
+ options = [
2672
+ # option type number default description
2673
+ # HII edit - lipid definition (last options are for additional lipid specification)
2674
+ """
2675
+ Input/output related options
2676
+ """,
2677
+ ("-f", Option(tm.append, 1, None, "Input GRO or PDB file 1: Protein")),
2678
+ ("-o", Option(str, 1, None, "Output GRO file: Membrane with Protein")),
2679
+ ("-o_f", Option(str, 1, None, "Folder for additional files (Default: InsaneData)")),
2680
+ ("-p", Option(str, 1, None, "Optional rudimentary topology file")),
2681
+ ("-ct", Option(str, 1, None, "This will create a template of the membrane only.")),
2682
+ ("-in_t", Option(str, 1, None, "Input template for placement of multiple proteins.")),
2683
+ ("-fs", Option(str, 1, None, "Input text file with multiple proteins")),
2684
+ """
2685
+ Options related to system size. It is reccomended to use -x, -y, -z only.
2686
+ Many options that were available here have been removed and will be readded
2687
+ at a later date.
2688
+ """,
2689
+ ("-d", Option(float, 1, 0, "Distance between periodic images (nm)")),
2690
+ ("-dz", Option(float, 1, 0, "Z distance between periodic images (nm)")),
2691
+ ("-x", Option(vector, 1, 0, "X dimension or first lattice vector of system (nm)")),
2692
+ ("-y", Option(vector, 1, 0, "Y dimension or first lattice vector of system (nm)")),
2693
+ ("-z", Option(vector, 1, 0, "Z dimension or first lattice vector of system (nm)")),
2694
+ ("-box", Option(readBox, 1, None, "Box in GRO (3 or 9 floats) or PDB (6 floats) format, comma separated")),
2695
+ ("-n", Option(str, 1, None, "Index file --- TO BE IMPLEMENTED")),
2696
+ """
2697
+ Membrane/lipid related options.
2698
+ The options -l and -u can be given multiple times. Option -u can be
2699
+ used to set the lipid type and abundance for the upper leaflet. Option
2700
+ -l sets the type and abundance for the lower leaflet if option -u is
2701
+ also given, or for both leaflets if option -u is not given. -lo and -uo
2702
+ behave as -l and -u except -l can set abundance for -lo and -uo is these
2703
+ are not specified. Curvature can be specified using -curv.
2704
+ """,
2705
+ ("-l", Option(lipL.append, 1, None, "Lipid type and relative abundance (NAME[:#])")),
2706
+ ("-u", Option(lipU.append, 1, None, "Lipid type and relative abundance (NAME[:#])")),
2707
+ ("-lo", Option(lipLO.append, 1, None, "Lipid type and relative abundance (For double membrane definitions) (NAME[:#])")),
2708
+ ("-uo", Option(lipUO.append, 1, None, "Lipid type and relative abundance (For double membrane definitions) (NAME[:#])")),
2709
+ ("-a", Option(float, 1, 0.60, "Area per lipid (nm*nm)")),
2710
+ ("-au", Option(float, 1, None, "Area per lipid (nm*nm) for upper layer")),
2711
+ ("-ao", Option(float, 1, None, "Area per lipid (nm*nm) for outer membrane")),
2712
+ ("-auo", Option(float, 1, None, "Area per lipid (nm*nm) for outer membrane upper layer")),
2713
+ ("-asym", Option(int, 1, None, "Membrane asymmetry (number of lipids)")),
2714
+ ("-rand", Option(float, 1, 0.1, "Random kick size (maximum atom displacement)")),
2715
+ ("-bd", Option(float, 1, 0.3, "Bead distance unit for scaling z-coordinates (nm)")),
2716
+ ("-ps", Option(float, 1, 0, "Specifies the distance (nm) between inner and outer membrane, when set to 0 only a single membrane is built")),
2717
+ ("-curv", Option(str, 1, "0,0,1", "Curvature of the membrane, consists of 3 comma separated values. The curvature at the middle the curvature as it relaxes back to planar and the direction of the curvature.")),
2718
+ ("-curv_o", Option(str, 1, "0,0,1", "Curvature of the outer membrane, see -curv")),
2719
+ ("-curv_ext", Option(float, 1, 3, "Extent of curved region in the absence of a protein.")),
2720
+ #("-pore", Option(bool, 0, None, "Create a pore, with inner radius equal to -curv_ext and length equal to -ps")),
2721
+ ("-loc", Option(str, 1, None, "Currently WIP do not use. Input .npz for localisation data to bias lipid arangment.")),
2722
+ ("-l_loc", Option(lipL_loc.append, 1, None, "Currently WIP do not use. Lipid type for localisation")),
2723
+ ("-u_loc", Option(lipU_loc.append, 1, None, "Currently WIP do not use. Lipid type for localisation")),
2724
+ ("-micelle", Option(bool, 0, None, "Builds a micelle around a protein instead of a bilayer")),
2725
+ ("-radius", Option(float, 1, -1, "Radius of membrane outer disk. This is by default the whole cell")),
2726
+ ("-no_lipids", Option(int, 1, -1, "Number of lipids that make up a micelle, this will override area per lipid. Only for use with -micelle")),
2727
+ ("-def", Option(str, 1, None, "Input folder containing deformation data from MemPrOD, This cannot be used with -ps or -curv.")),
2728
+ """
2729
+ Peptidoglycan layer related options.
2730
+ """,
2731
+
2732
+ ("-pgl", Option(int, 1, 0, "Number of PG layers to place at -pgl_z.")),
2733
+ ("-pgl_z", Option(float, 1, 0, "Z position of PG layer relative to center of periplasmic space.")),
2734
+ ("-cper", Option(float, 1, 0.4, "Percentage of crosslinks.")),
2735
+ ("-lper", Option(float, 1, 0.1, "Percentage of crosslinks that are between layers.")),
2736
+ ("-per33", Option(float, 1, 0.03, "Percentage of 3-3 crosslinks, all other crosslinks will be 3-4.")),
2737
+ ("-oper", Option(float, 1, 1, "Percentage chance of a monomer linking with a oligomer. (Actual change of link is cper*oper)")),
2738
+ ("-gdist", Option(str, 1, "0.75,4,8.9,0.25,10,45", "Distribution of glycan strand lengths. Format as weight 1,standard deviation 1,mean 1,weight 2..., were each triple describes a gaussian. The sum of these forms the distribution.")),
2739
+ """
2740
+ Protein related options. -fudge gives the exclusion radius around the protein.
2741
+ """,
2742
+ ("-center", Option(bool, 0, None, "Center the protein on z")),
2743
+ ("-rotate", Option(str, 1, None, "Rotate protein (random|princ|angle(float))")),
2744
+ ("-fudge", Option(float, 1, 0.3, "Fudge factor for allowing lipid-protein overlap. Recommended value when using -def is 0.15")),
2745
+ ("-ring", Option(bool, 0, None, "Put lipids inside the protein")),
2746
+ ("-dm", Option(float, 1, None, "Shift protein with respect to membrane")),
2747
+ """
2748
+ Solvent related options.
2749
+ """,
2750
+ ("-sol", Option(solv.append, 1, None, "Solvent type and relative abundance (NAME[:#])")),
2751
+ ("-sold", Option(float, 1, 0.5, "Solvent diameter")),
2752
+ ("-solr", Option(float, 1, 0.1, "Solvent random kick")),
2753
+ ("-excl", Option(float, 1, 1.5, "Exclusion range (nm) for solvent addition relative to membrane center")),
2754
+ ("-anti_freeze", Option(float, 1, 0.2, "Rate at which to remove solvent to avoid freezing due to hexagonal lattice.")),
2755
+ """
2756
+ Charge related options.
2757
+ """,
2758
+ ("-posi_c0", Option(pos_ions[0].append, 1, None, "Positive ion type and relative abundance (NAME[:#]) in compartment 0")),
2759
+ ("-negi_c0", Option(neg_ions[0].append, 1, None, "Negative ion type and relative abundance (NAME[:#]) in compartment 0")),
2760
+ ("-posi_c1", Option(pos_ions[1].append, 1, None, "Positive ion type and relative abundance (NAME[:#]) in compartment 1")),
2761
+ ("-negi_c1", Option(neg_ions[1].append, 1, None, "Negative ion type and relative abundance (NAME[:#]) in compartment 1")),
2762
+ ("-posi_c2", Option(pos_ions[2].append, 1, None, "Positive ion type and relative abundance (NAME[:#]) in compartment 2")),
2763
+ ("-negi_c2", Option(neg_ions[2].append, 1, None, "Negative ion type and relative abundance (NAME[:#]) in compartment 2")),
2764
+ ("-ion_conc", Option(str, 1, "0.15,0.15,0.15", "Concentration of ions in each compartment")),
2765
+ ("-charge", Option(str, 1, "auto", "Charge of system. Set to auto to infer from residue names")),
2766
+ ("-charge_ratio", Option(str, 1, None, "Ratios of charge in each compartment")),
2767
+ ("-zpbc", Option(bool, 0, None, "Toggles if water compartments are determined with pbc in the Z axis.")),
2768
+ """
2769
+ Define additional lipid types (same format as in lipid-martini-itp-v01.py)
2770
+ """,
2771
+ ("-alname", Option(usrmols.append, 1, None, "Additional lipid name, x4 letter")),
2772
+ ("-alhead", Option(usrheads.append, 1, None, "Additional lipid head specification string")),
2773
+ ("-allink", Option(usrlinks.append, 1, None, "Additional lipid linker specification string")),
2774
+ ("-altail", Option(usrtails.append, 1, None, "Additional lipid tail specification string")),
2775
+ ]
2776
+
2777
+ args = sys.argv[1:]
2778
+
2779
+ if '-h' in args or '--help' in args:
2780
+ print("\n",__file__)
2781
+ print(desc or "\nSomeone ought to write a description for this script...\n")
2782
+ for thing in options:
2783
+ print(type(thing) != str and "%10s %s"%(thing[0],thing[1].description) or thing)
2784
+ print("")
2785
+ sys.exit()
2786
+
2787
+
2788
+ # Convert the option list to a dictionary, discarding all comments
2789
+ options = dict([i for i in options if not type(i) == str])
2790
+
2791
+
2792
+
2793
+ # Process the command line
2794
+ while args:
2795
+ ar = args.pop(0)
2796
+ options[ar].setvalue([args.pop(0) for i in range(options[ar].num)])
2797
+
2798
+
2799
+
2800
+ absoluteNumbers = not options["-d"]
2801
+
2802
+
2803
+ out_folder = options["-o_f"].value
2804
+ if not out_folder:
2805
+ out_folder = "InsaneData/"
2806
+
2807
+ if out_folder[-1] != "/":
2808
+ out_folder += "/"
2809
+ if(not os.path.exists(out_folder)):
2810
+ os.mkdir(out_folder)
2811
+
2812
+ SpGrid = jnp.array(SphereGridAng(20,np.pi/2))
2813
+ #print(SpGrid)
2814
+
2815
+ memdata = options["-def"].value
2816
+ if memdata:
2817
+ mdata = np.load(memdata+"Membrane_pos.npz")
2818
+ membrane_pos = mdata["arr_0"]
2819
+ mdata2 = np.load(memdata+"Rotation_matrix.npz")
2820
+ rot_mat_def = mdata2["arr_0"]
2821
+ mdata5 = np.load(memdata+"Z_change.npz")
2822
+ z_change = mdata5["arr_0"]
2823
+ mdata3 = np.load(memdata+"Xlin.npz")
2824
+ xlin_def = mdata3["arr_0"]
2825
+ mdata4 = np.load(memdata+"Ylin.npz")
2826
+ ylin_def = mdata4["arr_0"]
2827
+ else:
2828
+ membrane_pos = 0
2829
+ rot_mat_def = np.eye(3)
2830
+ xlin_def = 0
2831
+ ylin_def = 0
2832
+ z_change = 0
2833
+
2834
+
2835
+
2836
+ # HII edit - lipid definition
2837
+ # Add specified lipid definition to insane lipid library
2838
+ for name, head, link, tail in list(zip(usrmols,usrheads,usrlinks,usrtails)):
2839
+ moltype = "usr_"+name
2840
+ lipidsx[moltype] = []
2841
+ lipidsy[moltype] = []
2842
+ lipidsz[moltype] = []
2843
+ headArray = (head).split()
2844
+ linkArray = (link).split()
2845
+ tailsArray = (tail).split()
2846
+ lipidDefString = ""
2847
+
2848
+ if len(tailsArray) != len(linkArray):
2849
+ print("Error, Number of tails has to equal number of linkers")
2850
+ sys.exit()
2851
+
2852
+ # Find longest tail
2853
+ maxTail = 0
2854
+ for cTail in tailsArray:
2855
+ if len(cTail) > maxTail:
2856
+ maxTail = len(cTail)
2857
+ cBeadZ = maxTail + len(headArray) # longest tail + linker (always x1) + lengths of all heads - 1 (as it starts on 0)
2858
+
2859
+ # Add head beads
2860
+ for cHead in headArray:
2861
+ lipidsx[moltype].append(0)
2862
+ lipidsy[moltype].append(0)
2863
+ lipidsz[moltype].append(cBeadZ)
2864
+ cBeadZ -= 1
2865
+ lipidDefString += usrLipHeadMapp[cHead] + " "
2866
+
2867
+ # Add linkers
2868
+ for i,cLinker in enumerate(linkArray):
2869
+ lipidsx[moltype].append(max(i-0.5,0))
2870
+ lipidsy[moltype].append(0)
2871
+ lipidsz[moltype].append(cBeadZ)
2872
+ if cLinker == 'G':
2873
+ lipidDefString += "GL" + str(i+1) + " "
2874
+ elif cLinker == 'A':
2875
+ lipidDefString += "AM" + str(i+1) + " "
2876
+ else:
2877
+ print("Error, linker type not supported")
2878
+ sys.exit()
2879
+
2880
+ # Add tails
2881
+ for i,cTail in enumerate(tailsArray):
2882
+ cBeadZ = maxTail - 1
2883
+
2884
+ for j,cTailBead in enumerate(cTail):
2885
+ lipidsx[moltype].append(i)
2886
+ lipidsy[moltype].append(0)
2887
+ lipidsz[moltype].append(cBeadZ)
2888
+ cBeadZ -= 1
2889
+ lipidDefString += cTailBead + str(j+1) + usrIndexToLetter[i] + " "
2890
+
2891
+ lipidsa[name] = (moltype,lipidDefString)
2892
+ # End user lipid definition
2893
+
2894
+
2895
+ # HII edit - lipid definition, had to move this one below the user lipid definitions to scale them to.
2896
+ # First all X/Y coordinates of templates are centered and scaled (magic numbers!)
2897
+ for i in lipidsx.keys():
2898
+ cx = (min(lipidsx[i])+max(lipidsx[i]))/2
2899
+ lipidsx[i] = [0.25*(j-cx) for j in lipidsx[i]]
2900
+ cy = (min(lipidsy[i])+max(lipidsy[i]))/2
2901
+ lipidsy[i] = [0.25*(j-cy) for j in lipidsy[i]]
2902
+
2903
+
2904
+ # Periodic boundary conditions
2905
+
2906
+ # option -box overrides everything
2907
+ if options["-box"].value:
2908
+ options["-x"].value = options["-box"].value[:3]
2909
+ options["-y"].value = options["-box"].value[3:6]
2910
+ options["-z"].value = options["-box"].value[6:]
2911
+
2912
+
2913
+ mem_outer_red = options["-radius"].value
2914
+
2915
+ Num_PGL = options["-pgl"].value
2916
+ Pos_PGL = options["-pgl_z"].value
2917
+ cper = options["-cper"].value
2918
+ lper = options["-lper"].value
2919
+ per33 = options["-per33"].value
2920
+ oper = options["-oper"].value
2921
+ gdist_str = options["-gdist"].value
2922
+
2923
+ gdist = gdist_str.split(",")
2924
+ gdist = np.array(gdist,dtype=float)
2925
+ gdist = gdist.reshape(int(gdist.size/3),3)
2926
+
2927
+
2928
+
2929
+ anti_freeze = options["-anti_freeze"].value
2930
+
2931
+ is_micelle = options["-micelle"].value
2932
+
2933
+ if(is_micelle is not None):
2934
+ is_micelle = True
2935
+ else:
2936
+ is_micelle = False
2937
+
2938
+
2939
+ # options -x, -y, -z take precedence over automatic determination
2940
+ pbcSetX = 0
2941
+ if type(options["-x"].value) in (list,tuple):
2942
+ pbcSetX = options["-x"].value
2943
+ elif options["-x"].value:
2944
+ pbcSetX = [options["-x"].value,0,0]
2945
+
2946
+ pbcSetY = 0
2947
+ if type(options["-y"].value) in (list,tuple):
2948
+ pbcSetY = options["-y"].value
2949
+ elif options["-y"].value:
2950
+ pbcSetY = [0,options["-y"].value,0]
2951
+
2952
+ pbcSetZ = 0
2953
+ if type(options["-z"].value) in (list,tuple):
2954
+ pbcSetZ = options["-z"].value
2955
+ elif options["-z"].value:
2956
+ pbcSetZ = [0,0,options["-z"].value]
2957
+
2958
+
2959
+
2960
+
2961
+ ################
2962
+ ## I. PROTEIN ##
2963
+ ################
2964
+
2965
+
2966
+ protein = Structure()
2967
+ protein_lip = Structure()
2968
+ prot = []
2969
+ xshifts = [0] # Shift in x direction per protein
2970
+
2971
+ #Reading and processing inputs
2972
+
2973
+ double_mem = False
2974
+ if(options["-ps"].value > 1e-5):
2975
+ double_mem = True
2976
+ using_temp = False
2977
+ if(options["-fs"].value is not None):
2978
+ using_temp = True
2979
+
2980
+ zpbc = False
2981
+ if(options["-zpbc"].value is not None):
2982
+ zpbc = True
2983
+
2984
+
2985
+ #add_pore = options["-pore"].value
2986
+ #if(add_pore is not None):
2987
+ # add_pore = True
2988
+ #else:
2989
+ # add_pore = False
2990
+ add_pore = False
2991
+
2992
+ zdist = float(options["-ps"].value)
2993
+
2994
+ curv_vals = options["-curv"].value.split(",")
2995
+ curvo_vals = options["-curv_o"].value.split(",")
2996
+
2997
+
2998
+ curv_vals_np = np.zeros(3)
2999
+ curv_vals_np[2] += 1
3000
+
3001
+ if(len(curv_vals) == 1):
3002
+ curv_vals_np[0] = float(curv_vals[0])
3003
+ curv_vals_np[1] = float(curv_vals[0])
3004
+ elif(len(curv_vals) == 2):
3005
+ curv_vals_np[0] = float(curv_vals[0])
3006
+ curv_vals_np[1] = float(curv_vals[1])
3007
+ elif(len(curv_vals) == 3):
3008
+ curv_vals_np[0] = float(curv_vals[0])
3009
+ curv_vals_np[1] = float(curv_vals[1])
3010
+ curv_vals_np[2] = float(curv_vals[2])
3011
+
3012
+ curvo_vals_np = np.zeros(3)
3013
+ curvo_vals_np[2] += 1
3014
+
3015
+ if(len(curvo_vals) == 1):
3016
+ curvo_vals_np[0] = float(curvo_vals[0])
3017
+ curvo_vals_np[1] = float(curvo_vals[0])
3018
+ elif(len(curvo_vals) == 2):
3019
+ curvo_vals_np[0] = float(curvo_vals[0])
3020
+ curvo_vals_np[1] = float(curvo_vals[1])
3021
+ elif(len(curvo_vals) == 3):
3022
+ curvo_vals_np[0] = float(curvo_vals[0])
3023
+ curvo_vals_np[1] = float(curvo_vals[1])
3024
+ curvo_vals_np[2] = float(curvo_vals[2])
3025
+
3026
+
3027
+
3028
+
3029
+ rcurvs_mid = np.array([curv_vals_np[1],curvo_vals_np[1]])
3030
+ curvs_mid = np.array([curv_vals_np[0],curvo_vals_np[0]])
3031
+
3032
+ if(add_pore):
3033
+ if(rcurvs_mid[0] < 1e-5):
3034
+ print("WARNING: Return curvature (inner) cannot be 0 setting to 0.1")
3035
+ rcurvs_mid[0] = 0.1
3036
+ if(rcurvs_mid[1] < 1e-5):
3037
+ print("WARNING: Return curvature (outer) cannot be 0 setting to 0.1")
3038
+ rcurvs_mid[1] = 0.1
3039
+
3040
+ if(add_pore):
3041
+ cdirs = [1,-1]
3042
+ else:
3043
+ cdirs = [float(curv_vals[2]),float(curvo_vals[2])]
3044
+
3045
+ if(curvs_mid[0] < 1e-5):
3046
+ ncurves = np.zeros(2)
3047
+ else:
3048
+ ncurves = np.array([1/((1/curvs_mid[0])+2),1/((1/curvs_mid[0])-2)])
3049
+
3050
+ if(curvs_mid[1] < 1e-5):
3051
+ ncurves_o = np.zeros(2)
3052
+ else:
3053
+ ncurves_o = np.array([1/((1/curvs_mid[1])+2),1/((1/curvs_mid[1])-2)])
3054
+
3055
+ curv_up = np.array([ncurves[0],ncurves_o[0]])
3056
+ curv_lo = np.array([ncurves[1],ncurves_o[1]])
3057
+
3058
+ if(rcurvs_mid[0] < 1e-5):
3059
+ nrcurves = np.zeros(2)
3060
+ else:
3061
+ nrcurves = np.array([1/((1/rcurvs_mid[0])+2),1/((1/rcurvs_mid[0])-2)])
3062
+
3063
+ if(rcurvs_mid[1] < 1e-5):
3064
+ nrcurves_o = np.zeros(2)
3065
+ else:
3066
+ nrcurves_o = np.array([1/((1/rcurvs_mid[1])+2),1/((1/rcurvs_mid[1])-2)])
3067
+
3068
+ rcurv_up = np.array([nrcurves[1],nrcurves_o[1]])
3069
+ rcurv_lo = np.array([nrcurves[0],nrcurves_o[0]])
3070
+
3071
+
3072
+ extent= float(options["-curv_ext"].value)
3073
+ if(add_pore):
3074
+ for i in range(2):
3075
+ curvs_mid[i] = 1/extent
3076
+
3077
+ prot_dirs = []
3078
+ prot_rings = []
3079
+
3080
+
3081
+
3082
+
3083
+ if not tm or options["-ct"].value != None or using_temp:
3084
+
3085
+ ang_exts = np.array([np.arcsin(curvs_mid[0]*extent),np.arcsin(curvs_mid[1]*extent)])
3086
+ resi = 0
3087
+ bsize,bheight = get_box_size(curvs_mid[0],rcurvs_mid[0],ang_exts[0],add_pore)
3088
+
3089
+
3090
+ if(pbcSetX[0] < bsize*2+2):
3091
+ pbcSetX[0] = bsize*2+2
3092
+ if(pbcSetY[1] < bsize*2+2):
3093
+ pbcSetY[1] = bsize*2+2
3094
+
3095
+ pbcx = pbcSetX and pbcSetX[0]
3096
+ pbcy = pbcSetY and pbcSetY[1]
3097
+ pbcz = pbcSetZ and pbcSetZ[2]
3098
+
3099
+ ## B. PROTEIN ---
3100
+ #for writing a template for muliple protein placments
3101
+ if(options["-ct"].value != None):
3102
+ print("Writing template file...")
3103
+ new_file = open(options["-ct"].value,"w")
3104
+ count = 0
3105
+ trufal = [True,False]
3106
+ ang_exts = np.array([np.arcsin(curvs_mid[0]*extent),np.arcsin(curvs_mid[1]*extent)])
3107
+ for i in range(2):
3108
+ if(i == 0 or double_mem):
3109
+ if(add_pore):
3110
+ inner_leng = zdist-(1/rcurvs_mid[i])
3111
+ else:
3112
+ inner_leng = 0
3113
+ temp_points,direcs = create_leaflet(4,pbcx/2,pbcy/2,curvs_mid[i],rcurvs_mid[i],ang_exts[i],add_pore,inner_leng,trufal[i],mem_outer_red)
3114
+ if(cdirs[i] > 0):
3115
+ temp_points[:,2] = -temp_points[:,2]
3116
+ direcs[:,2] = -direcs[:,2]
3117
+
3118
+ temp_points =(temp_points+np.array([pbcx/2,pbcy/2,zdist*(2*i-1)]))*10
3119
+ for gp in temp_points:
3120
+ count += 1
3121
+ count_str = (6-len(str(count)))*" "+str(count)
3122
+ c = "ATOM "+count_str+" BB DUM 1 0.000 0.000 15.000 1.00 0.00"
3123
+ xp = np.format_float_positional(gp[0],precision=3)
3124
+ yp = np.format_float_positional(gp[1],precision=3)
3125
+ zp = np.format_float_positional(gp[2],precision=3)
3126
+ xp += "0"*(3-len((xp.split(".")[1])))
3127
+ yp += "0"*(3-len((yp.split(".")[1])))
3128
+ zp += "0"*(3-len((zp.split(".")[1])))
3129
+ new_c = c[:30]+(" "*(8-len(xp)))+xp+(" "*(8-len(yp)))+yp+(" "*(8-len(zp))) +zp+c[54:]+"\n"
3130
+ new_file.write(new_c)
3131
+
3132
+ new_file.close()
3133
+ info_fn = options["-ct"].value.split(".")[0]+".txt"
3134
+ info_file = open(info_fn,"w")
3135
+ info_file.write("Curvature values:"+options["-curv"].value+"\n")
3136
+ info_file.write("Outer curvature values:"+options["-curv_o"].value+"\n")
3137
+ info_file.write("Pore:"+str(add_pore)+"\n")
3138
+ info_file.write("X Y Z:"+str(options["-x"].value)+","+str(options["-y"].value)+","+str(options["-z"].value)+"\n")
3139
+ info_file.write("Box:"+str(options["-box"].value))
3140
+ info_file.close()
3141
+ print("Done!")
3142
+ exit()
3143
+
3144
+
3145
+
3146
+ if(using_temp):
3147
+ print("Extracting data from template...")
3148
+ #WHen a template is present it used to build membrane
3149
+ in_prots = options["-fs"].value
3150
+ prot_file = open(in_prots,"r")
3151
+ lines = prot_file.read().split("\n")
3152
+ prot_file.close()
3153
+
3154
+
3155
+
3156
+ temp_file = open(options["-in_t"].value,"r")
3157
+ temp_lines = temp_file.read().split("\n")
3158
+ temp_file.close()
3159
+ poses = np.zeros((len(lines),3))
3160
+ for tl in temp_lines:
3161
+ stl = tl.split()
3162
+ if(len(stl)>2):
3163
+ prot_no = int(float(stl[-2]))-1
3164
+ if(prot_no> -1):
3165
+ zpos = float(tl[46:54])
3166
+ ypos = float(tl[38:46])
3167
+ xpos = float(tl[30:38])
3168
+ poses[prot_no] = np.array([xpos,ypos,zpos])/10
3169
+ for pr in lines:
3170
+ pr_list = pr.split()
3171
+ prot = pr_list[0]
3172
+ direction = float(pr_list[1])
3173
+ rings = int(pr_list[2])
3174
+ if(rings == 0):
3175
+ rings = False
3176
+ else:
3177
+ rings = True
3178
+ tm.append(prot)
3179
+ prot_dirs.append(direction)
3180
+ prot_rings.append(rings)
3181
+ tm_lip = [ Structure(i) for i in tm ]
3182
+ tm = [ Structure(i) for i in tm ]
3183
+
3184
+ def accessable(grid):
3185
+ ngrid = jnp.zeros_like(grid)
3186
+ def aloop1(ngrid,ind1):
3187
+ def aloop2(ngrid,ind2):
3188
+ t1 = jnp.sum(jnp.array([grid[ind1,ind2],grid[ind1-1,ind2],grid[ind1-1,ind2-1],grid[ind1,ind2-1]]))
3189
+ t2 = jnp.sum(jnp.array([grid[ind1,ind2],grid[ind1+1,ind2],grid[ind1+1,ind2-1],grid[ind1,ind2-1]]))
3190
+ t3 = jnp.sum(jnp.array([grid[ind1,ind2],grid[ind1-1,ind2],grid[ind1-1,ind2+1],grid[ind1,ind2+1]]))
3191
+ t4 = jnp.sum(jnp.array([grid[ind1,ind2],grid[ind1+1,ind2],grid[ind1+1,ind2+1],grid[ind1,ind2+1]]))
3192
+ def good(ngrid):
3193
+ ngrid = ngrid.at[ind1,ind2].set(1)
3194
+ return ngrid
3195
+ def bad(ngrid):
3196
+ return ngrid
3197
+ ngrid = jax.lax.cond(jnp.logical_or(jnp.logical_or(t1==4,t2==4),jnp.logical_or(t3==4,t4==4)),good,bad,ngrid)
3198
+ return ngrid,ind2
3199
+ ngrid,_= jax.lax.scan(aloop2,ngrid,jnp.arange(ngrid.shape[1]))
3200
+ return ngrid,ind1
3201
+ ngrid,_ = jax.lax.scan(aloop1,ngrid,jnp.arange(ngrid.shape[0]))
3202
+ return ngrid
3203
+
3204
+ if(using_temp or tm):
3205
+ if(not using_temp):
3206
+ #when not using a template
3207
+ tm_lip = [ Structure(i) for i in tm ]
3208
+ tm = [ Structure(i) for i in tm ]
3209
+
3210
+
3211
+
3212
+ xmax = np.max(np.array(tm[0].coord)[:,0])
3213
+ ymax = np.max(np.array(tm[0].coord)[:,1])
3214
+ xmin = np.min(np.array(tm[0].coord)[:,0])
3215
+ ymin = np.min(np.array(tm[0].coord)[:,1])
3216
+ xrang = xmax-xmin
3217
+ yrang = ymax-ymin
3218
+
3219
+ rang = np.max([xrang,yrang])/2
3220
+ extent = rang
3221
+ ang_exts = np.array([np.arcsin(curvs_mid[0]*extent),np.arcsin(curvs_mid[1]*extent)])
3222
+
3223
+ bsize,bheight = get_box_size(curvs_mid[0],rcurvs_mid[0],ang_exts[0],add_pore)
3224
+ if(pbcSetX[0] < bsize*2+2):
3225
+ pbcSetX[0] = bsize*2+2
3226
+ if(pbcSetY[1] < bsize*2+2):
3227
+ pbcSetY[1] = bsize*2+2
3228
+ if(pbcSetZ[2] < bheight*2+10):
3229
+ pbcSetZ[2] = bheight*2+10
3230
+
3231
+
3232
+ pbcx = pbcSetX and pbcSetX[0]
3233
+ pbcy = pbcSetY and pbcSetY[1]
3234
+ pbcz = pbcSetZ and pbcSetZ[2]
3235
+
3236
+
3237
+ poses = np.zeros((1,3))
3238
+ prot_dirs.append(1)
3239
+ if(options["-ring"].value != None):
3240
+ rings = True
3241
+ else:
3242
+ rings = False
3243
+ prot_rings.append(rings)
3244
+
3245
+ poses[0][0] = pbcx/2
3246
+ poses[0][1] = pbcy/2
3247
+
3248
+ print("Building protein(s)...")
3249
+ for pind,prot in enumerate(tm):
3250
+
3251
+ prot_lip = tm_lip[pind]
3252
+ ## a. NO MEMBRANE --
3253
+ if not lipL:
3254
+ pass
3255
+ ## b. PROTEIN AND MEMBRANE --
3256
+ else:
3257
+
3258
+ # Have to build a membrane around the protein.
3259
+ # So first put the protein in properly.
3260
+
3261
+
3262
+ # Center the protein and store the shift
3263
+ shift = prot.center((0,0,0))
3264
+ shift_lip = prot_lip.center((0,0,0))
3265
+
3266
+ ## 5. Determine the minimum and maximum x and y of the protein
3267
+ pmin, pmax = prot.fun(min), prot.fun(max)
3268
+ prng = (pmax[0]-pmin[0],pmax[1]-pmin[1],pmax[2]-pmin[2])
3269
+ center = (0.5*(pmin[0]+pmax[0]),0.5*(pmin[1]+pmax[1]))
3270
+
3271
+
3272
+ pbcz += options["-dz"].value or options["-d"].value or 0
3273
+
3274
+
3275
+ ## 2. Shift of protein relative to the membrane center
3276
+ zshift = 0
3277
+ if not options["-center"].value:
3278
+ zshift = -shift[2]
3279
+ if options["-dm"].value:
3280
+ if options["-dm"].value < 0:
3281
+ zshift += options["-dm"].value # - max(list(zip(*prot.coord))[2])
3282
+ else:
3283
+ zshift += options["-dm"].value # - min(list(zip(*prot.coord))[2])
3284
+
3285
+
3286
+ if(poses[pind][2] < 0):
3287
+ mind = 0
3288
+ else:
3289
+ mind = 1
3290
+ if(add_pore):
3291
+ inner_leng = zdist-(1/rcurvs_mid[mind])
3292
+ else:
3293
+ inner_leng = 0
3294
+ fun_pos,normal = leaflet_function(poses[pind][0]-pbcx/2,poses[pind][1]-pbcy/2,curvs_mid[mind],rcurvs_mid[mind],ang_exts[mind],add_pore,inner_leng)
3295
+ if(cdirs[mind] > 0):
3296
+ fun_pos = -fun_pos
3297
+ normal[2] = -normal[2]
3298
+
3299
+ downn = np.array([0,0,-1*prot_dirs[pind]])
3300
+ angl = np.dot(normal,downn)
3301
+ if(angl < -1+1e-5):
3302
+ downn = np.array([0,1e-4,-1*prot_dirs[pind]])
3303
+ downn = downn/np.linalg.norm(downn)
3304
+ angl = np.dot(normal,downn)
3305
+
3306
+ v = np.cross(downn,normal)
3307
+ vmat = np.array([[0,-v[2],v[1]],[v[2],0,-v[0]],[-v[1],v[0],0]])
3308
+ rot_mat = np.eye(3)+vmat+np.dot(vmat,vmat)*1/(1+angl)
3309
+
3310
+ prot += [0,0,zshift]
3311
+ prot_lip.coord = list(np.array(prot_lip.coord)+[0,0,zshift])
3312
+
3313
+ if(not prot_rings[pind]):
3314
+ for dmi in range(2):
3315
+ if(dmi == 0 or (not using_temp and zdist > 1e-5)):
3316
+ if(not using_temp and zdist > 1e-5):
3317
+ ztestpos = zdist*(2*dmi-1)
3318
+ else:
3319
+ ztestpos = 0
3320
+
3321
+
3322
+ for zt in np.linspace(ztestpos-4,ztestpos+4,25):
3323
+ in_mem = get_box_slice(np.array(prot.coord),[0,0,zt],[100,100,0.5])
3324
+ if in_mem.size > 0:
3325
+ xmin = np.min(in_mem[:,0])
3326
+ xmax = np.max(in_mem[:,0])
3327
+ ymin = np.min(in_mem[:,1])
3328
+ ymax = np.max(in_mem[:,1])
3329
+ xext = xmax-xmin
3330
+ yext = ymax-ymin
3331
+
3332
+ gridd = np.zeros((20,20))
3333
+
3334
+ xxs = np.linspace(xmin-1,xmax+1,20)
3335
+ yys = np.linspace(ymin-1,ymax+1,20)
3336
+ dx = xxs[1]-xxs[0]
3337
+ dy = yys[1]-yys[0]
3338
+ for im in in_mem:
3339
+ gridx,gridy = put_into_grid(im[:2],[xext+4,yext+4],[20,20],[xmin-2,ymin-2])
3340
+ gridd[gridx,gridy] =1
3341
+
3342
+ gridd = 1-np.array(accessable(1-jnp.array(gridd)))
3343
+ gridd = 1-flood_fill(gridd,True)
3344
+ gridd = 1-flood_fill(gridd,True)
3345
+
3346
+ rad = np.sqrt(dx*dx+dy*dy)/3
3347
+ packer= DiskGridFib(10,rad)
3348
+ for xi in range(20):
3349
+ for yi in range(20):
3350
+ if gridd[xi,yi] == 1:
3351
+ for pi in range(10):
3352
+ new_coord = np.array([xxs[xi],yys[yi],zt])+packer[pi]
3353
+ prot_lip.coord.extend([new_coord])
3354
+
3355
+ prot.coord = np.dot(rot_mat,np.array(prot.coord).T).T
3356
+ prot_lip.coord = np.dot(rot_mat,np.array(prot_lip.coord).T).T
3357
+ prot += poses[pind]
3358
+ prot_lip.coord = list(np.array(prot_lip.coord)+poses[pind])
3359
+
3360
+
3361
+ # And we collect the atoms
3362
+ protein.atoms.extend(prot.atoms)
3363
+ protein.coord.extend(np.array([0,0,-z_change/10])+(np.dot(rot_mat_def,(np.array(prot.coord)-poses[0]).T).T)+poses[0])
3364
+
3365
+
3366
+ protein_lip.atoms.extend(prot_lip.atoms)
3367
+ protein_lip.coord.extend(np.array([0,0,-z_change/10])+(np.dot(rot_mat_def,(np.array(prot_lip.coord)-poses[0]).T).T)+poses[0])
3368
+
3369
+
3370
+ prot_up,prot_lo,prot_up_a,prot_up_b,prot_lo_a,prot_lo_b = [],[],[],[],[],[]
3371
+
3372
+
3373
+ # Current residue ID is set to that of the last atom
3374
+ resi = protein.atoms[-1][2]
3375
+
3376
+ atid = len(protein)+1
3377
+ molecules = []
3378
+
3379
+ # The box dimensions are now (likely) set.
3380
+ # If a protein was given, it is positioned in the center of the
3381
+ # rectangular brick.
3382
+
3383
+
3384
+ # Override lattice vectors if they were set explicitly
3385
+ box = [[0,0,0],[0,0,0],[0,0,0]]
3386
+ box[0] = pbcSetX
3387
+ box[1] = pbcSetY
3388
+ box[2] = pbcSetZ
3389
+
3390
+ grobox = (box[0][0],box[1][1],box[2][2],
3391
+ box[0][1],box[0][2],box[1][0],
3392
+ box[1][2],box[2][0],box[2][1])
3393
+
3394
+ pbcx, pbcy, pbcz = box[0][0], box[1][1], box[2][2]
3395
+
3396
+
3397
+
3398
+ rx, ry, rz = pbcx+1e-8, pbcy+1e-8, pbcz+1e-8
3399
+
3400
+ print("Done")
3401
+
3402
+ #PG layer
3403
+
3404
+ PGL = Structure()
3405
+ if(Num_PGL > 0):
3406
+ print("Begining to build PG layer...")
3407
+ spaceing = 2.5
3408
+ z_poses = np.linspace(-spaceing*(Num_PGL-1)/2,spaceing*(Num_PGL-1)/2,Num_PGL)
3409
+ exprot = float(options["-fudge"].value)
3410
+ prev_str = ["[ atoms ]\n","[ bonds ]\n","[ constraints ]\n","[ angles ]\n","[ dihedrals ]\n"]
3411
+ prev_nos = [1,0]
3412
+ print("Creating glycan strands...")
3413
+ Gposes,pc_zslice = Create_Glycan_strands2(Num_PGL,pbcy,pbcx,z_poses,0,0,np.array(protein.coord),gdist)
3414
+ print("Cross-linking...")
3415
+ Gposes = cross_link(Gposes,pbcy,cper,per33,lper,oper)
3416
+ print("Counting resulting oligomers...")
3417
+ olig_lens = count_all_olig(Gposes)
3418
+ total_clink = olig_lens.shape[0]
3419
+ mono = olig_lens[olig_lens == 1].shape[0]/total_clink
3420
+ dimer = olig_lens[olig_lens == 2].shape[0]/total_clink
3421
+ olig_plus = olig_lens[olig_lens > 2].shape[0]/total_clink
3422
+ print("Momomer:",mono)
3423
+ print("Dimer:",dimer)
3424
+ print("Higher oligomer:",olig_plus)
3425
+ print("Writing ITP for PG layer...")
3426
+ prev_str,prev_nos = write_PGL_itp(Gposes,"NAM.itp","NAG.itp","SNPEP.itp","UNPEP.itp","UUNPEP.itp",prev_str,prev_nos)
3427
+ print("Relaxing the PG layer (This will change the cell size slightly)...")
3428
+ box_size,Gposes = relax_pg(Gposes,np.array([pbcx*50,pbcy*50]),5,pc_zslice)
3429
+ box[0] = [box_size[0]/50,0,0]
3430
+ box[1] = [0,box_size[1]/50,0]
3431
+ #box[2] = pbcSetZ
3432
+
3433
+ grobox = (box[0][0],box[1][1],box[2][2],
3434
+ box[0][1],box[0][2],box[1][0],
3435
+ box[1][2],box[2][0],box[2][1])
3436
+
3437
+ pbcx, pbcy, pbcz = box[0][0], box[1][1], box[2][2]
3438
+
3439
+
3440
+
3441
+ rx, ry, rz = pbcx+1e-8, pbcy+1e-8, pbcz+1e-8
3442
+
3443
+
3444
+
3445
+
3446
+
3447
+
3448
+
3449
+
3450
+ Gposes,Gshape = lines_to_coords(Gposes)
3451
+
3452
+ No_Nag = Gposes[Gposes[:,4] == 0].shape[0]
3453
+ No_Nam = Gposes[Gposes[:,4] == 1].shape[0]
3454
+
3455
+ PG_Glycan = ["NAG:"+str(No_Nag),"NAM:"+str(No_Nam)]
3456
+
3457
+
3458
+ Gly_new, numG = list(zip(*[ parse_mol(i) for i in PG_Glycan ]))
3459
+ totG = float(sum(numG))
3460
+ num_g = [int(len(Gposes)*i/totG) for i in numG]
3461
+
3462
+ Gly = [l for i,l in list(zip(num_g,Gly_new)) for j in range(i)]
3463
+
3464
+
3465
+ Gly_s = (list(zip(Gly,Gposes)))
3466
+ print("Building the PG layer...")
3467
+ glycans = ["NAM","NAG"]
3468
+ #Placing templates of components at each point defined
3469
+ for pos in Gposes:
3470
+ glycan = glycans[int(pos[4])]
3471
+ if(pos[5] > 0):
3472
+ resi += 1
3473
+ atoms = list(zip(lipidsa[glycan][1].split(),lipidsx[lipidsa[glycan][0]],lipidsy[lipidsa[glycan][0]],lipidsz[lipidsa[glycan][0]]))
3474
+ at,ax,ay,az = list(zip(*[i for i in atoms if i[0] != "-"]))
3475
+ az = [ i+pos[2] for i in az ]
3476
+ xx = list(zip( ax,ay ))
3477
+ nx = [pos[3]*i+pos[0] for i in ax]
3478
+ ny = [j+pos[1] for j in ay]
3479
+ for i in range(len(at)):
3480
+ atom = "%5d%-5s%5s%5d"%(resi,glycan,at[i],atid)
3481
+ PGL.coord.append((nx[i],ny[i],az[i]))
3482
+ PGL.atoms.append((at[i],glycan,resi,0,0,0))
3483
+ atid += 1
3484
+
3485
+
3486
+ atoms_nam = list(zip(lipidsa["NAM"][1].split(),lipidsx[lipidsa["NAM"][0]],lipidsy[lipidsa["NAM"][0]],lipidsz[lipidsa["NAM"][0]]))
3487
+ atn,axn,ayn,azn = list(zip(*[i for i in atoms_nam if i[0] != "-"]))
3488
+ nam_temp = np.array([axn[-1],ayn[-1],azn[-1]])
3489
+ for pos in Gposes:
3490
+ glycan = glycans[int(pos[4])]
3491
+ b1_pos = pos[:3]+np.array([pos[3],1,1])*nam_temp
3492
+ if(pos[13] == 1):
3493
+ atm = "UUPEP"
3494
+ atm = "UUPEP"
3495
+ else:
3496
+ if(pos[6] != -1 or pos[13] ==2):
3497
+ atm = "UPEP"
3498
+ else:
3499
+ atm = "SPEP"
3500
+ if(pos[5] > 0 and glycan == "NAM"):
3501
+ resi += 1
3502
+ atoms = list(zip(lipidsa[atm][1].split(),lipidsx[lipidsa[atm][0]],lipidsy[lipidsa[atm][0]],lipidsz[lipidsa[atm][0]]))
3503
+ if(pos[6] > -0.5 and pos[9] > -0.5):
3504
+ lind1 = int(pos[6])
3505
+ bind1 = int(pos[7])
3506
+ lyind1 = int(pos[8])
3507
+ lind2 = int(pos[9])
3508
+ bind2 = int(pos[10])
3509
+ lyind2 = int(pos[11])
3510
+ b2_posA = Gposes[lyind1*Gshape[1]*Gshape[2]+lind1*Gshape[2]+bind1][:3]
3511
+ b2_posB = Gposes[lyind2*Gshape[1]*Gshape[2]+lind2*Gshape[2]+bind2][:3]
3512
+ b2_posB = b2_posB-b2_posA+np.array([pbcx/2,pbcy/2,0])
3513
+ while(b2_posB[0]<0):
3514
+ b2_posB[0] += pbcx
3515
+ while(b2_posB[0]>=pbcx):
3516
+ b2_posB[0] -= pbcx
3517
+ while(b2_posB[1]<0):
3518
+ b2_posB[1] += pbcy
3519
+ while(b2_posB[1]>=pbcy):
3520
+ b2_posB[1] -= pbcy
3521
+ b2_pos = (b2_posB+np.array([pbcx/2,pbcy/2,0]))/2+b2_posA-np.array([pbcx/2,pbcy/2,0])
3522
+ elif(pos[6] > -0.5):
3523
+ lind1 = int(pos[6])
3524
+ bind1 = int(pos[7])
3525
+ lyind1 = int(pos[8])
3526
+ b2_pos = Gposes[lyind1*Gshape[1]*Gshape[2]+lind1*Gshape[2]+bind1][:3]
3527
+ elif(pos[9] > -0.5):
3528
+ lind1 = int(pos[9])
3529
+ bind1 = int(pos[10])
3530
+ lyind1 = int(pos[11])
3531
+ b2_pos = Gposes[lyind1*Gshape[1]*Gshape[2]+lind1*Gshape[2]+bind1][:3]
3532
+ else:
3533
+ b2_pos = b1_pos-np.array([pos[3],0,0])*2.5
3534
+
3535
+
3536
+ pbcb2= b2_pos-b1_pos+np.array([pbcx/2,pbcy/2,0])
3537
+ while(pbcb2[0]<0):
3538
+ pbcb2[0] += pbcx
3539
+ while(pbcb2[0]>=pbcx):
3540
+ pbcb2[0] -= pbcx
3541
+ while(pbcb2[1]<0):
3542
+ pbcb2[1] += pbcy
3543
+ while(pbcb2[1]>=pbcy):
3544
+ pbcb2[1] -= pbcy
3545
+ leng = np.linalg.norm(pbcb2-np.array([pbcx/2,pbcy/2,0]))-0.64
3546
+ if(leng < 1.5):
3547
+ leng = 1.5 #changed this maybe change back idk
3548
+
3549
+ v2 = pbcb2-np.array([pbcx/2,pbcy/2,0])
3550
+ v2 = v2/np.linalg.norm(v2)
3551
+ v1 = [-1,0,0]
3552
+ vcross = np.cross(v1,v2)
3553
+ vmat = np.array([[0,-vcross[2],vcross[1]],[vcross[2],0,-vcross[0]],[-vcross[1],vcross[0],0]])
3554
+ asin = np.linalg.norm(vcross)
3555
+ acos = np.dot(v1,v2)
3556
+ if(np.abs(1+acos) < 1e-6):
3557
+ rot_mat = np.array([[-1,0,0],[0,1,0],[0,0,1]])
3558
+ else:
3559
+ rot_mat = np.eye(3)+vmat+np.dot(vmat,vmat)*(1/(1+acos))
3560
+
3561
+
3562
+
3563
+ npos = (np.array([pbcx/2,pbcy/2,0])+pbcb2)/2+b1_pos-np.array([pbcx/2,pbcy/2,0])
3564
+
3565
+ dil = leng/2.03
3566
+
3567
+
3568
+
3569
+ at,ax,ay,az = list(zip(*[i for i in atoms if i[0] != "-"]))
3570
+ xx = list(zip( ax,ay,az ))
3571
+ nx = [rot_mat[0,0]*i*dil+rot_mat[0,1]*j+rot_mat[0,2]*k+npos[0] for i,j,k in xx]
3572
+ ny = [rot_mat[1,0]*i*dil+rot_mat[1,1]*j+rot_mat[1,2]*k+npos[1] for i,j,k in xx]
3573
+ nz = [rot_mat[2,0]*i*dil+rot_mat[2,1]*j+rot_mat[2,2]*k+npos[2] for i,j,k in xx]
3574
+ for i in range(len(at)):
3575
+ atom = "%5d%-5s%5s%5d"%(resi,glycan,at[i],atid)
3576
+ PGL.coord.append((nx[i],ny[i],nz[i]))
3577
+ PGL.atoms.append((at[i],atm,resi,0,0,0))
3578
+ atid += 1
3579
+
3580
+
3581
+
3582
+ molecules.extend(list(zip(["PGL"],[1])))
3583
+ write_all_itp(prev_str,out_folder)
3584
+ print("Done")
3585
+
3586
+
3587
+ #################
3588
+ ## 2. MEMBRANE ##
3589
+ #################
3590
+
3591
+ membrane = Structure()
3592
+ mi_rad = 0
3593
+ if lipL:
3594
+ print("Begining to build lipid bilayer(s)...")
3595
+ #reading inputs
3596
+ area_l = float(options["-a"].value)
3597
+ if(not options["-au"].value is None):
3598
+ area_u = float(options["-au"].value)
3599
+ else:
3600
+ area_u = float(options["-a"].value)
3601
+
3602
+ if(not options["-ao"].value is None):
3603
+ area_lo = float(options["-ao"].value)
3604
+ else:
3605
+ area_lo = float(options["-a"].value)
3606
+
3607
+
3608
+ if(not options["-auo"].value is None):
3609
+ area_uo = float(options["-auo"].value)
3610
+ else:
3611
+ if(not options["-ao"].value is None):
3612
+ area_uo = float(options["-ao"].value)
3613
+ else:
3614
+ area_uo = float(options["-a"].value)
3615
+
3616
+ density_l = [np.pi/2*np.sqrt(1/area_l),np.pi/2*np.sqrt(1/area_lo)]
3617
+ density_u = [np.pi/2*np.sqrt(1/area_u),np.pi/2*np.sqrt(1/area_uo)]
3618
+ area_ls = [area_l,area_lo]
3619
+
3620
+
3621
+
3622
+
3623
+ up_grids = []
3624
+ lo_grids = []
3625
+ direcss = []
3626
+ direcs2s = []
3627
+
3628
+ lipU = lipU or lipL
3629
+ trufal = [True,False]
3630
+ #building membrae grid points and normals based on inputs
3631
+ print("Creating leaflet shape...")
3632
+ for i in range(2):
3633
+ if(options["-ps"].value > 1e-5 or i == 0):
3634
+ if(add_pore):
3635
+ inner_leng = zdist-(1/rcurvs_mid[i])
3636
+ curv_up[i] = 1/(extent+2)
3637
+ curv_lo[i] = 1/(extent-2)
3638
+ else:
3639
+ inner_leng = 0
3640
+ if(is_micelle):
3641
+ prot_points = np.array(protein.coord)
3642
+ prot_points = prot_points[np.logical_and(prot_points[:,2]+zdist*(i*2-1) < 2,prot_points[:,2]+zdist*(i*2-1) > -2)]
3643
+ prot_points = prot_points[:,:2]
3644
+ prot_points = prot_points[::2]
3645
+ prot_points = jnp.array(prot_points)
3646
+
3647
+
3648
+ ret_val,grid_vals = gaussian_grid(prot_points,-pbcx/2,-pbcx/2,pbcx/2,pbcx/2,300,300)
3649
+ av_liplen = get_avlip_len(lipU)
3650
+ up_grid,direcs,mi_rad = build_micelle(area_ls[i],prot_points,ret_val,grid_vals,8,pbcx,pbcy,av_liplen)
3651
+ if(options["-no_lipids"].value != -1):
3652
+ no_lips = int(options["-no_lipids"].value)
3653
+ acc_lips = len(direcs)
3654
+ new_area = area_ls[i]*acc_lips/no_lips
3655
+ up_grid,direcs,mi_rad = build_micelle(new_area,prot_points,ret_val,grid_vals,8,pbcx,pbcy,av_liplen)
3656
+
3657
+ #up_grid,direcs,mi_rad = build_micelle(area_ls[i],prot_points,ret_val,grid_vals,8,pbcx,pbcy)
3658
+
3659
+
3660
+ lo_grid = np.zeros((0,3))
3661
+ direcs2 = np.zeros((0,3))
3662
+ else:
3663
+ up_grid,direcs = create_leaflet(density_u[i],pbcx/2,pbcy/2,curv_up[i],rcurv_up[i],ang_exts[i],add_pore,inner_leng,trufal[i],mem_outer_red)
3664
+ lo_grid,direcs2 = create_leaflet(density_l[i],pbcx/2,pbcy/2,curv_lo[i],rcurv_lo[i],ang_exts[i],add_pore,inner_leng,trufal[i],mem_outer_red)
3665
+ up_grid[:,2] = -up_grid[:,2]+2
3666
+ lo_grid[:,2] = -lo_grid[:,2]-2
3667
+
3668
+
3669
+ if(cdirs[i] < 0):
3670
+ temp = up_grid
3671
+ up_grid = lo_grid
3672
+ lo_grid= temp
3673
+
3674
+ dtemp = -direcs
3675
+ direcs = -direcs2
3676
+ direcs2= dtemp
3677
+
3678
+ up_grid[:,2] = -up_grid[:,2]
3679
+ lo_grid[:,2] = -lo_grid[:,2]
3680
+ direcs[:,2] = -direcs[:,2]
3681
+ direcs2[:,2] = -direcs2[:,2]
3682
+ if(not is_micelle):
3683
+ up_grid = up_grid+np.array([pbcx/2,pbcy/2,0])
3684
+ lo_grid = lo_grid+np.array([pbcx/2,pbcy/2,0])
3685
+ else:
3686
+ up_grid = np.zeros((0,3))
3687
+ direcs = np.zeros((0,3))
3688
+ lo_grid = np.zeros((0,3))
3689
+ direcs2 = np.zeros((0,3))
3690
+
3691
+ up_grids.append(up_grid)
3692
+ lo_grids.append(lo_grid)
3693
+ direcss.append(direcs)
3694
+ direcs2s.append(direcs2)
3695
+
3696
+ upper, lower = [], []
3697
+ random.seed()
3698
+
3699
+
3700
+ #lipU = lipU or lipL
3701
+ lipU_loc = lipU_loc or lipL_loc
3702
+ lipLO = lipLO or lipL
3703
+ lipUO = lipUO or lipLO
3704
+ lipUs = [lipU,lipUO]
3705
+ lipLs = [lipL,lipLO]
3706
+
3707
+ av_liplenU = get_avlip_len(lipU)
3708
+ av_liplenUO = get_avlip_len(lipUO)
3709
+ av_liplenL = get_avlip_len(lipL)
3710
+ av_liplenLO = get_avlip_len(lipLO)
3711
+
3712
+ #removing lipids within -fudge of protein
3713
+ prot_coords = np.array(protein_lip.coord)
3714
+ #write_point(prot_coords*10,"Protein_filled.pdb")
3715
+
3716
+ tailsU = np.linspace(0,av_liplenU*1.5,50)
3717
+ tailsUO = np.linspace(0,av_liplenUO*1.5,50)
3718
+ tailsL = np.linspace(0,av_liplenL*1.5,50)
3719
+ tailsLO = np.linspace(0,av_liplenLO*1.5,50)
3720
+ tailsUs = [tailsU,tailsUO]
3721
+ tailsLs = [tailsL,tailsLO]
3722
+
3723
+ exprot = float(options["-fudge"].value)
3724
+ zdist = float(options["-ps"].value)
3725
+ print("Calculating lipid positions...")
3726
+
3727
+ for gi in range(2):
3728
+ test_pts = DiskGridFib(20,np.sqrt(area_ls[gi])/1.5)
3729
+ total_up_lips = up_grids[gi].shape[0]
3730
+ total_lo_lips = lo_grids[gi].shape[0]
3731
+ if(options["-ps"].value > 1e-5 or gi == 0):
3732
+ upper_tmp, lower_tmp = [], []
3733
+ for i in range(total_up_lips):
3734
+ zdef = 0
3735
+ mtdef = 1.0
3736
+
3737
+ direc = np.array([direcss[gi][i][0],direcss[gi][i][1],direcss[gi][i][2]])
3738
+ coll = False
3739
+ for si in test_pts:
3740
+ if memdata:
3741
+ xtest = (up_grids[gi][i][0]+si[0]-pbcx/2)*10
3742
+ ytest = (up_grids[gi][i][1]+si[1]-pbcy/2)*10
3743
+ xind = int(((xtest-xlin_def[0])/(xlin_def[-1]-xlin_def[0]))*xlin_def.shape[0])
3744
+ yind = int(((ytest-ylin_def[0])/(ylin_def[-1]-ylin_def[0]))*ylin_def.shape[0])
3745
+ if xind < 0 or yind < 0 or xind >= xlin_def.shape[0] or yind >= ylin_def.shape[0]:
3746
+ zdef = 0
3747
+ else:
3748
+ defor = membrane_pos[xind,yind]/10.0
3749
+ zdef = defor[0]
3750
+ mtdef = (10*defor[1]/membrane_pos[0,0,1])
3751
+ poser = np.array([up_grids[gi][i][0],up_grids[gi][i][1],mtdef*up_grids[gi][i][2]+zdist*(gi*2-1)+zdef])
3752
+ coll = False
3753
+ path = [poser+si]
3754
+ for it,dr in enumerate(tailsUs[gi]):
3755
+ #prot_slice = get_box_slice(prot_coords,poser-dr*direc*mtdef,[exprot,exprot,exprot])
3756
+ if tm:
3757
+ prot_sliceb = get_box_slice(prot_coords,path[-1],[exprot,exprot,exprot])
3758
+ else:
3759
+ prot_sliceb = jnp.empty((0,3))
3760
+ if not prot_sliceb.size == 0:
3761
+ path_bead,can_place = place_bead(jnp.array(path[-1]),tailsUs[gi][1],jnp.array(direc),SpGrid,jnp.array(prot_sliceb),exprot)
3762
+ else:
3763
+ path_bead = path[-1]-direc*tailsUs[gi][1]
3764
+ can_place =True
3765
+ path.append(np.array(path_bead))
3766
+ if(not can_place):
3767
+ coll = True
3768
+ break
3769
+ if not coll:
3770
+ for _ in range(10):
3771
+ path_bead = path[-1]-direc*tailsUs[gi][1]
3772
+ path.append(np.array(path_bead))
3773
+ path_top = [poser+si+direc*tailsUs[gi][1]]
3774
+ for _ in range(50):
3775
+ path_top.append(path_top[-1]+direc*tailsUs[gi][1])
3776
+ for i in range(49):
3777
+ path.append(path_top[-i-1])
3778
+ break
3779
+ if(not coll):
3780
+ upper_tmp.append((random.random(),up_grids[gi][i][0],up_grids[gi][i][1],up_grids[gi][i][2],direcss[gi][i][0],direcss[gi][i][1],direcss[gi][i][2],path))
3781
+ upper.append((random.random(),up_grids[gi][i][0],up_grids[gi][i][1],up_grids[gi][i][2],direcss[gi][i][0],direcss[gi][i][1],direcss[gi][i][2],path))
3782
+ for i in range(total_lo_lips):
3783
+ zdef = 0
3784
+ mtdef = 1.0
3785
+ direc = np.array([direcs2s[gi][i][0],direcs2s[gi][i][1],direcs2s[gi][i][2]])
3786
+ coll = False
3787
+ for si in test_pts:
3788
+ if memdata:
3789
+ xtest = (lo_grids[gi][i][0]+si[0]-pbcx/2)*10
3790
+ ytest = (lo_grids[gi][i][1]+si[1]-pbcy/2)*10
3791
+ xind = int(((xtest-xlin_def[0])/(xlin_def[-1]-xlin_def[0]))*xlin_def.shape[0])
3792
+ yind = int(((ytest-ylin_def[0])/(ylin_def[-1]-ylin_def[0]))*ylin_def.shape[0])
3793
+ if xind < 0 or yind < 0 or xind >= xlin_def.shape[0] or yind >= ylin_def.shape[0]:
3794
+ zdef = 0
3795
+ else:
3796
+ defor = membrane_pos[xind,yind]/10.0
3797
+ zdef = defor[0]
3798
+ mtdef = (10*defor[1]/membrane_pos[0,0,1])
3799
+ poser = np.array([lo_grids[gi][i][0],lo_grids[gi][i][1],mtdef*lo_grids[gi][i][2]+zdist*(gi*2-1)+zdef])
3800
+
3801
+ coll = False
3802
+ path = [poser+si]
3803
+ #if tm:
3804
+ for it,dr in enumerate(tailsLs[gi]):
3805
+ #prot_slice = get_box_slice(prot_coords,poser+dr*direc*mtdef,[exprot,exprot,exprot])
3806
+ if tm:
3807
+ prot_sliceb = get_box_slice(prot_coords,path[-1],[exprot,exprot,exprot])
3808
+ else:
3809
+ prot_sliceb = jnp.empty((0,3))
3810
+ if not prot_sliceb.size == 0:
3811
+ path_bead,can_place = place_bead(jnp.array(path[-1]),tailsLs[gi][1],-jnp.array(direc),SpGrid,jnp.array(prot_sliceb),exprot)
3812
+ else:
3813
+ path_bead = path[-1]+direc*tailsLs[gi][1]
3814
+ can_place =True
3815
+ path.append(np.array(path_bead))
3816
+ if(not can_place):
3817
+ coll = True
3818
+ break
3819
+ if not coll:
3820
+ for _ in range(10):
3821
+ path_bead = path[-1]+direc*tailsLs[gi][1]
3822
+ path.append(np.array(path_bead))
3823
+ path_top = [poser+si+direc*tailsUs[gi][1]]
3824
+ for _ in range(50):
3825
+ path_top.append(path_top[-1]+direc*tailsUs[gi][1])
3826
+ for i in range(49):
3827
+ path.append(path_top[-i-1])
3828
+ break
3829
+
3830
+ if(not coll):
3831
+
3832
+ lower_tmp.append((random.random(),lo_grids[gi][i][0],lo_grids[gi][i][1],lo_grids[gi][i][2],direcs2s[gi][i][0],direcs2s[gi][i][1],direcs2s[gi][i][2],path))
3833
+ lower.append((random.random(),lo_grids[gi][i][0],lo_grids[gi][i][1],lo_grids[gi][i][2],direcs2s[gi][i][0],direcs2s[gi][i][1],direcs2s[gi][i][2],path))
3834
+
3835
+
3836
+ # Sort on the random number
3837
+ upper_tmp.sort()
3838
+ lower_tmp.sort()
3839
+
3840
+
3841
+
3842
+
3843
+ # Extract coordinates, taking asymmetry in account
3844
+ asym = options["-asym"].value or 0
3845
+ upper_tmp = [i[1:] for i in upper_tmp[max(0, asym):]]
3846
+ lower_tmp = [i[1:] for i in lower_tmp[max(0,-asym):]]
3847
+ print("; %d lipids in upper leaflet, %d lipids in lower leaflet"%(len(upper_tmp),len(lower_tmp)),file=sys.stderr )
3848
+
3849
+ # Types of lipids, relative numbers, fractions and numbers
3850
+
3851
+ # Upper leaflet (+1)
3852
+ lipU_new, numU = list(zip(*[ parse_mol(i) for i in lipUs[gi] ]))
3853
+ totU = float(sum(numU))
3854
+ num_up = [int(len(upper_tmp)*i/totU) for i in numU]
3855
+
3856
+ lip_up = [l for i,l in list(zip(num_up,lipU_new)) for j in range(i)]
3857
+
3858
+ leaf_up = ( 1,list(zip(lip_up,upper_tmp)))
3859
+
3860
+ # Lower leaflet (-1)
3861
+ lipL_new, numL = list(zip(*[ parse_mol(i) for i in lipLs[gi] ]))
3862
+ totL = float(sum(numL))
3863
+ num_lo = [int(len(lower_tmp)*i/totL) for i in numL]
3864
+ lip_lo = [l for i,l in list(zip(num_lo,lipL_new)) for j in range(i)]
3865
+
3866
+ #lower_tmp = LocBias(lower_tmp,num_lo,lipL_new,10000,lipL_loc,loc_grid[0])
3867
+ leaf_lo = (-1,list(zip(lip_lo,lower_tmp)))
3868
+ if(gi == 0):
3869
+ molecules += list(zip(lipU_new,num_up)) + list(zip(lipL_new,num_lo))
3870
+ else:
3871
+ molecules += list(zip(lipU_new,num_up)) + list(zip(lipL_new,num_lo))
3872
+
3873
+ kick = options["-rand"].value
3874
+
3875
+
3876
+ print("Building membrane(s)...")
3877
+ # Build the membrane
3878
+ for leaflet,leaf_lip in [leaf_up,leaf_lo]:
3879
+ for lipid, pos_dir in leaf_lip:
3880
+ pos = pos_dir[:3]
3881
+ dirs = pos_dir[3:6]
3882
+ path = np.array(pos_dir[-1])-pos
3883
+ #print(path[0])
3884
+ #print(pos)
3885
+ # Increase the residue number by one
3886
+ resi += 1
3887
+ # Set the random rotation for this lipid
3888
+ rangle = 2*random.random()*math.pi
3889
+ rcos = math.cos(rangle)
3890
+ rsin = math.sin(rangle)
3891
+ # Fetch the atom list with x,y,z coordinates
3892
+ atoms = list(zip(lipidsa[lipid][1].split(),lipidsx[lipidsa[lipid][0]],lipidsy[lipidsa[lipid][0]],lipidsz[lipidsa[lipid][0]]))
3893
+ # Only keep atoms appropriate for the lipid
3894
+ at,ax,ay,az = list(zip(*[i for i in atoms if i[0] != "-"]))
3895
+ # The z-coordinates are spaced at 0.3 nm,
3896
+ # starting with the first bead at 0.15 nm
3897
+ #+leaflet*(0.5+(i-min(az)))*options["-bd"].value
3898
+
3899
+ xx = list(zip( ax,ay ))
3900
+ nx = [rcos*i-rsin*j+random.random()*kick for i,j in xx]
3901
+ ny = [rsin*i+rcos*j+random.random()*kick for i,j in xx]
3902
+
3903
+ az = np.array([ leaflet*-2+pos[2]+leaflet*(0.5+(i-min(az)))*options["-bd"].value for i in az ])
3904
+ if leaflet == 1:
3905
+ vgrid = tailsUs[gi]
3906
+ else:
3907
+ vgrid = tailsLs[gi]
3908
+ new_poses = []
3909
+ for ai in range(az.shape[0]):
3910
+ vi = 0
3911
+ indv = -leaflet*((az[ai]-pos[2])/vgrid[-1])*len(vgrid)
3912
+ indv_f = np.floor(indv)
3913
+ indv_c = np.ceil(indv)
3914
+ indv_p = indv_c-indv
3915
+ pf = path[int(indv_f)]
3916
+ pc = path[int(indv_c)]
3917
+
3918
+ sdirec = pf-pc
3919
+ sdirec /= np.linalg.norm(sdirec)
3920
+
3921
+ upp = np.array([0,0,1])
3922
+ sdirec2 = sdirec+1e-4*np.linalg.norm(upp+sdirec)
3923
+ sdirec2 /= np.linalg.norm(sdirec2)
3924
+ angl = np.dot(-sdirec2,upp)
3925
+
3926
+
3927
+ v = np.cross(-sdirec2,upp)
3928
+ vmat = np.array([[0,-v[2],v[1]],[v[2],0,-v[0]],[-v[1],v[0],0]])
3929
+ rot_mat = np.eye(3)+vmat+np.dot(vmat,vmat)*1/(1+angl)
3930
+
3931
+ xdir = np.dot(np.array([1,0,0]),rot_mat)
3932
+ ydir = np.dot(np.array([0,1,0]),rot_mat)
3933
+
3934
+ if np.linalg.norm(xdir)<0.9:
3935
+ print(np.linalg.norm(xdir))
3936
+
3937
+ new_pos = pf*(1-indv_p)+pc*indv_p+pos[:3]+nx[ai]*xdir+ny[ai]*ydir
3938
+ new_poses.append(new_pos)
3939
+
3940
+
3941
+ for i in range(len(at)):
3942
+ atom = "%5d%-5s%5s%5d"%(resi,lipid,at[i],atid)
3943
+ membrane.coord.append((new_poses[i][0],new_poses[i][1],new_poses[i][2]))
3944
+
3945
+ membrane.atoms.append((at[i],lipid,resi,0,0,0))
3946
+ atid += 1
3947
+
3948
+
3949
+
3950
+ # Now move everything to the center of the box before adding solvent
3951
+ mz = pbcz/2
3952
+ z = [ i[2] for i in protein.coord+membrane.coord ]
3953
+ adj = -(max(z)+min(z))/2
3954
+ mz += adj
3955
+ protein += (0,0,mz)
3956
+ membrane += (0,0,mz)
3957
+ print("Done")
3958
+ else:
3959
+ mz=0
3960
+ adj = 0
3961
+
3962
+ if(Num_PGL > 0):
3963
+ PGL += (0,0,adj)
3964
+
3965
+
3966
+
3967
+ ################
3968
+ ## 3. SOLVENT ##
3969
+ ################
3970
+
3971
+ # Charge of the system so far
3972
+
3973
+
3974
+ charge,pcharge,mcharge,pgcharge = get_charge(0,pbcz)
3975
+
3976
+ plen, mlen, slen = 0, 0, 0
3977
+ plen = protein and len(protein) or 0
3978
+
3979
+ print("; NDX Protein %d %d" % (1, protein and plen or 0),file=sys.stderr)
3980
+ print("; Charge of protein: %f" % pcharge,file=sys.stderr)
3981
+
3982
+ mlen = membrane and len(membrane) or 0
3983
+
3984
+ pglen = PGL and len(PGL) or 0
3985
+
3986
+ print("; NDX Membrane %d %d" % (1+plen, membrane and plen+mlen or 0),file=sys.stderr)
3987
+ print("; Charge of membrane: %f" % mcharge,file=sys.stderr)
3988
+
3989
+ print("; NDX PG Layer %d %d" % (1+mlen+plen, PGL and plen+mlen+pglen or 0),file=sys.stderr)
3990
+ print("; Charge of PG Layer: %f" % pgcharge,file=sys.stderr)
3991
+
3992
+ print("; Total charge: %f" % charge,file=sys.stderr)
3993
+
3994
+
3995
+ def _point(y,phi):
3996
+ r = math.sqrt(1-y*y)
3997
+ return math.cos(phi)*r, y, math.sin(phi)*r
3998
+
3999
+
4000
+ def pointsOnSphere(n):
4001
+ return [_point((2.*k+1)/n-1,k*2.3999632297286531) for k in range(n)]
4002
+
4003
+ if solv:
4004
+ print("Adding solvent...")
4005
+
4006
+ # Set up a grid
4007
+ d = 1/(options["-sold"].value*np.sqrt(3)/2)
4008
+ da = 1/options["-sold"].value
4009
+
4010
+ nx,ny,nz = int(1+da*pbcx),int(1+d*pbcy),int(1+d*pbcz)
4011
+
4012
+ dx,dy,dz = pbcx/nx,pbcy/ny,pbcz/nz
4013
+ zdist = options["-ps"].value
4014
+ inner_lengs = [zdist,zdist]
4015
+
4016
+
4017
+ dzdist = int(zdist/dz)+1
4018
+
4019
+ excl,hz = int(nz*options["-excl"].value/pbcz), int(0.5*nz)
4020
+
4021
+ zshift = 0
4022
+ if membrane:
4023
+ if(options["-ps"].value > 1e-5):
4024
+ memz = [i[2] for i in membrane.coord]
4025
+ midz = (max(memz)+min(memz))/2
4026
+ memz_upp = [i[2] for i in membrane.coord if i[2]>midz]
4027
+ midz_upp = (max(memz_upp)+min(memz_upp))/2
4028
+ memz_low = [i[2] for i in membrane.coord if i[2]<=midz]
4029
+ midz_low = (max(memz_low)+min(memz_low))/2
4030
+ midz = (midz_upp+midz_low)/2
4031
+ excl -= 1
4032
+ else:
4033
+ memz = [i[2] for i in membrane.coord]
4034
+ midz = (max(memz)+min(memz))/2
4035
+ hz = int(nz*midz/pbcz) # Grid layer in which the membrane is located
4036
+ zshift = (hz+0.5)*nz - midz # Shift of membrane middle to center of grid layer
4037
+ # Initialize a grid of solvent, spanning the whole cell
4038
+ # Exclude all cells within specified distance from membrane center
4039
+ mem_size = 1.9
4040
+ if(lipL):
4041
+ print("Excluding solvent from membrane(s)...")
4042
+ if(options["-ps"].value > 1e-5):
4043
+ grids = []
4044
+ for gk in range(2):
4045
+
4046
+ if(cdirs[gk] < 0):
4047
+ grid = [[[(pbcz*(i+0.5))/nz <= -leaflet_function((pbcx*k)/nx-pbcx/2+((i+j)%2)*0.5*dx,(pbcy*j)/ny-pbcy/2+(i%2)*0.5*dy,curv_up[gk],rcurv_up[gk],ang_exts[gk],add_pore,inner_lengs[gk]-2)[0]-mem_size+mz+zdist*(2*gk-1) or (pbcz*(i+0.5))/nz >= -leaflet_function((pbcx*k)/nx-pbcx/2+((i+j)%2)*0.5*dx,(pbcy*j)/ny-pbcy/2+(i%2)*0.5*dy,curv_lo[gk],rcurv_lo[gk],ang_exts[gk],add_pore,inner_lengs[gk]+2)[0]+mem_size+mz+zdist*(2*gk-1) for i in range(nz)] for j in range(ny)] for k in range(nx)]
4048
+ else:
4049
+ grid = [[[(pbcz*(i+0.5))/nz >= leaflet_function((pbcx*k)/nx-pbcx/2+((i+j)%2)*0.5*dx,(pbcy*j)/ny-pbcy/2+(i%2)*0.5*dy,curv_up[gk],rcurv_up[gk],ang_exts[gk],add_pore,inner_lengs[gk]-2)[0]+mem_size+mz+zdist*(2*gk-1) or (pbcz*(i+0.5))/nz <= leaflet_function((pbcx*k)/nx-pbcx/2+((i+j)%2)*0.5*dx,(pbcy*j)/ny-pbcy/2+(i%2)*0.5*dy,curv_lo[gk],rcurv_lo[gk],ang_exts[gk],add_pore,inner_lengs[gk]+2)[0]-mem_size+mz+zdist*(2*gk-1) for i in range(nz)] for j in range(ny)] for k in range(nx)]
4050
+ grids.append(grid)
4051
+ grids = np.array(grids)
4052
+ grid = grids[0]*grids[1]
4053
+
4054
+ else:
4055
+ if is_micelle:
4056
+ rad = mi_rad
4057
+ else:
4058
+ if mem_outer_red>0:
4059
+ rad = mem_outer_red
4060
+ else:
4061
+ rad = 1000
4062
+ if(cdirs[0] < 0):
4063
+ grid = [[[((pbcx*k)/nx-pbcx/2)*((pbcx*k)/nx-pbcx/2)+((pbcy*j)/ny-pbcy/2)*((pbcy*j)/ny-pbcy/2) > rad*rad or (pbcz*(i+0.5))/nz <= -leaflet_function((pbcx*k)/nx-pbcx/2+((i+j)%2)*0.5*dx,(pbcy*j)/ny-pbcy/2+(i%2)*0.5*dy,curv_up[0],rcurv_up[0],ang_exts[0],add_pore,inner_lengs[0])[0]-mem_size+mz or (pbcz*(i+0.5))/nz >= -leaflet_function((pbcx*k)/nx-pbcx/2+((i+j)%2)*0.5*dx,(pbcy*j)/ny-pbcy/2+(i%2)*0.5*dy,curv_lo[0],rcurv_lo[0],ang_exts[0],add_pore,inner_lengs[0])[0]+mem_size+mz for i in range(nz)] for j in range(ny)] for k in range(nx)]
4064
+ else:
4065
+ grid = [[[((pbcx*k)/nx-pbcx/2)*((pbcx*k)/nx-pbcx/2)+((pbcy*j)/ny-pbcy/2)*((pbcy*j)/ny-pbcy/2) > rad*rad or (pbcz*(i+0.5))/nz >= leaflet_function((pbcx*k)/nx-pbcx/2+((i+j)%2)*0.5*dx,(pbcy*j)/ny-pbcy/2+(i%2)*0.5*dy,curv_up[0],rcurv_up[0],ang_exts[0],add_pore,inner_lengs[0])[0]+mem_size+mz or (pbcz*(i+0.5))/nz <= leaflet_function((pbcx*k)/nx-pbcx/2+((i+j)%2)*0.5*dx,(pbcy*j)/ny-pbcy/2+(i%2)*0.5*dy,curv_lo[0],rcurv_lo[0],ang_exts[0],add_pore,inner_lengs[0])[0]-mem_size+mz for i in range(nz)] for j in range(ny)] for k in range(nx)]
4066
+ else:
4067
+ grid = [[[True for i in range(nz)] for j in range(ny)] for k in range(nx)]
4068
+
4069
+
4070
+ if len(protein.coord) > 0:
4071
+ print("Filling the inside of protein(s) with solvent...")
4072
+
4073
+ grid = np.array(grid)
4074
+ pc = np.array(protein.coord)
4075
+ maxz = np.max(pc[:,2])
4076
+ minz = np.min(pc[:,2])
4077
+
4078
+ max_iz = int((maxz/pbcz)*nz)
4079
+ min_iz = int((minz/pbcz)*nz)
4080
+ #print(max_iz,min_iz)
4081
+
4082
+ for zl in range(min_iz,max_iz):
4083
+ #print(zl)
4084
+ acc_z = (zl/nz)*pbcz
4085
+ lzrange = acc_z-dz
4086
+ uzrange = acc_z+dz
4087
+ zpslice = pc[np.logical_and(pc[:,2] > lzrange,pc[:,2] < uzrange)]
4088
+ water_layer = np.zeros((nx,ny))
4089
+ for pos in zpslice[:,:2]:
4090
+ px = int((pos[0]/pbcx)*nx)
4091
+ py = int((pos[1]/pbcy)*ny)
4092
+ water_layer[px,py] = 1
4093
+
4094
+ filled_water = flood_fill(water_layer,False)+water_layer
4095
+
4096
+ grid[:,:,zl][filled_water[:,:] == 0] = True
4097
+ print("Removing solvent in cells occupied by other structures...")
4098
+ # Flag all cells occupied by protein or membrane
4099
+ for p,q,r in protein.coord+membrane.coord+PGL.coord:
4100
+ for s,t,u in pointsOnSphere(20):
4101
+ x,y,z = p+0.1*s,q+0.1*t,r+0.1*u
4102
+
4103
+ if z >= pbcz:
4104
+ x -= box[2][0]
4105
+ y -= box[2][1]
4106
+ z -= box[2][2]
4107
+ if z < 0:
4108
+ x += box[2][0]
4109
+ y += box[2][1]
4110
+ z += box[2][2]
4111
+ if y >= pbcy:
4112
+ x -= box[1][0]
4113
+ y -= box[1][1]
4114
+ if y < 0:
4115
+ x += box[1][0]
4116
+ y += box[1][1]
4117
+ if x >= pbcx:
4118
+ x -= box[0][0]
4119
+ if x < 0:
4120
+ x += box[0][0]
4121
+
4122
+
4123
+ zgrid = int(nz*z/rz)
4124
+ y = y-(0.5*dy)*(zgrid%2)
4125
+ ygrid = int(ny*y/ry)
4126
+ x = x - (0.5*dx)*((zgrid+ygrid)%2)
4127
+
4128
+
4129
+ grid[int(nx*x/rx)][ygrid][zgrid] = False
4130
+
4131
+ for i in range(nx):
4132
+ for j in range(ny):
4133
+ for k in range(nz):
4134
+ if(random.random() < anti_freeze):
4135
+ grid[i][j][k] = False
4136
+
4137
+
4138
+ # Set the center for each solvent molecule
4139
+ kick = options["-solr"].value
4140
+ grid = [ [R(),(i+0.5+R()*kick)*dx + (0.5*dx)*((j+k)%2),(j+0.5+R()*kick)*dy+(0.5*dy)*(k%2),(k+0.5+R()*kick)*dz]
4141
+ for i in range(nx) for j in range(ny) for k in range(nz) if grid[i][j][k] ]
4142
+
4143
+
4144
+ print("Calculating number of solvent compartments...")
4145
+ comp_nos = np.zeros(3)
4146
+ if(zdist > 1e-5):
4147
+ for gr in grid:
4148
+ lz = leaflet_function(gr[1]-pbcx/2,gr[2]-pbcy/2,curv_up[0],rcurv_up[0],ang_exts[0],add_pore,inner_lengs[0])[0]+mz-zdist
4149
+ uz = -leaflet_function(gr[1]-pbcx/2,gr[2]-pbcy/2,curv_up[1],rcurv_up[1],ang_exts[1],add_pore,inner_lengs[1])[0]+mz+zdist
4150
+
4151
+ if(gr[3] > lz and gr[3] < uz):
4152
+ gr[0] += 1
4153
+ comp_nos[1] += 1
4154
+ elif gr[3] < lz:
4155
+ comp_nos[0] += 1
4156
+ elif gr[3] > uz:
4157
+ if(not (zpbc or add_pore)):
4158
+ gr[0] += 2
4159
+ comp_nos[2] += 1
4160
+
4161
+ else:
4162
+ for gr in grid:
4163
+ lz = cdirs[0]*leaflet_function(gr[1]-pbcx/2,gr[2]-pbcy/2,curv_up[0],rcurv_up[0],ang_exts[0],add_pore,inner_lengs[0])[0]+mz
4164
+ if(gr[3] > lz):
4165
+ if(not (zpbc or add_pore)):
4166
+ gr[0] += 1
4167
+ comp_nos[2] += 1
4168
+ elif gr[3] < lz:
4169
+ comp_nos[0] += 1
4170
+ if(zpbc or add_pore):
4171
+ comp_nos[0] = comp_nos[0]+comp_nos[2]
4172
+ comp_nos[2] = 0
4173
+
4174
+
4175
+ # Sort on the random number
4176
+ grid.sort()
4177
+
4178
+ # 'grid' contains all positions on which a solvent molecule can be placed.
4179
+ # The number of positions is taken as the basis for determining the salt concentration.
4180
+ # This is fine for simple salt solutions, but may not be optimal for complex mixtures
4181
+ # (like when mixing a 1M solution of this with a 1M solution of that
4182
+
4183
+
4184
+ print("Calculating charges per compartment...")
4185
+
4186
+ # First get names and relative numbers for each solvent
4187
+ solnames, solnums = list(zip(*[ parse_mol(i) for i in solv ]))
4188
+ solnames, solnums = list(solnames), list(solnums)
4189
+ totS = float(sum(solnums))
4190
+
4191
+ # Set the number of ions to add
4192
+ nna, ncl = 0, 0
4193
+ charge_rats = np.zeros(3)
4194
+ if options["-charge_ratio"].value:
4195
+ concs = options["-charge_ratio"].value.split(",")
4196
+ # If the concentration is set negative, set the charge to zero
4197
+ countc = 0
4198
+ for c in concs:
4199
+ charge_rats[countc] = float(c)
4200
+ countc += 1
4201
+
4202
+
4203
+
4204
+
4205
+ non_zero = 0
4206
+ for cn in comp_nos:
4207
+ if(cn > 1e-5):
4208
+ non_zero += 1
4209
+
4210
+
4211
+ concentrations = np.zeros(3)
4212
+ if options["-ion_conc"].value:
4213
+ concs = options["-ion_conc"].value.split(",")
4214
+ # If the concentration is set negative, set the charge to zero
4215
+ countc = 0
4216
+ for c in concs:
4217
+ concentrations[countc] = float(c)
4218
+ countc += 1
4219
+
4220
+ nsol = ("SPC" in solnames and 1 or 4)*len(grid)
4221
+
4222
+ # Correct number of grid cells for placement of solvent
4223
+
4224
+
4225
+ if options["-charge"].value != "0":
4226
+ charge = (options["-charge"].value != "auto") and int(options["-charge"].value) or charge
4227
+ else:
4228
+ charge = 0
4229
+
4230
+ ncharges = np.zeros(3,dtype=int)
4231
+ if options["-charge_ratio"].value:
4232
+ charge_rats /= np.sum(charge_rats[:non_zero])
4233
+ ncharges = np.array(charge*charge_rats,dtype=int)
4234
+ else:
4235
+ if(zdist > 1e-5):
4236
+ ncharges[1],_,_,_ = get_charge(mz-zdist,mz+zdist)
4237
+ ncharges[2],_,_,_ = get_charge(mz+zdist,pbcz)
4238
+ ncharges[0],_,_,_ = get_charge(0,mz-zdist)
4239
+ if(zpbc):
4240
+ ncharges[0] = ncharges[0]+ncharges[2]
4241
+ else:
4242
+ if(zpbc):
4243
+ ncharges[0] = charge
4244
+ else:
4245
+ ncharges[2],_,_,_ = get_charge(mz,pbcz)
4246
+ ncharges[0],_,_,_ = get_charge(0,mz)
4247
+
4248
+
4249
+ #dealing with charge of each compartment
4250
+ diff_c = charge-np.sum(ncharges)
4251
+ ncharges[0] += diff_c
4252
+ new_solnames = []
4253
+ new_num_sol = []
4254
+ rcomp_nos = comp_nos/np.sum(comp_nos)
4255
+
4256
+ if(len(pos_ions[1]) == 0):
4257
+ pos_ions[1] = pos_ions[0]
4258
+ if(len(pos_ions[2]) == 0):
4259
+ pos_ions[2] = pos_ions[0]
4260
+
4261
+ if(len(neg_ions[1]) == 0):
4262
+ neg_ions[1] = neg_ions[0]
4263
+ if(len(neg_ions[2]) == 0):
4264
+ neg_ions[2] = neg_ions[0]
4265
+ ion_names = []
4266
+ for pi in pos_ions:
4267
+ for pii in pi:
4268
+ mole = parse_mol(pii)[0]
4269
+ if(mole not in solnames):
4270
+ solnames.append(mole)
4271
+ ion_names.append(mole)
4272
+ for pi in neg_ions:
4273
+ for pii in pi:
4274
+ mole = parse_mol(pii)[0]
4275
+ if(mole not in solnames):
4276
+ solnames.append(mole)
4277
+ ion_names.append(mole)
4278
+
4279
+ for ci,cn in enumerate(comp_nos):
4280
+ added = 0
4281
+ new_nsol = nsol*rcomp_nos[ci]
4282
+ total_ions = int(1+(concentrations[ci]*new_nsol/(27.7+concentrations[ci])))
4283
+
4284
+ cperi = -ncharges[ci]/total_ions
4285
+
4286
+ negi = neg_ions[ci]
4287
+ posi = pos_ions[ci]
4288
+
4289
+
4290
+ total_negc = 0
4291
+ total_posc = 0
4292
+ total_negi = 0
4293
+ total_posi = 0
4294
+ for ni_c in negi:
4295
+ iname, icount = parse_mol(ni_c)
4296
+ total_negc += ion_charges[iname]*icount
4297
+ total_negi += icount
4298
+
4299
+ for pi_c in posi:
4300
+ iname, icount = parse_mol(pi_c)
4301
+ total_posc += ion_charges[iname]*icount
4302
+ total_posi += icount
4303
+
4304
+
4305
+ if(total_negc-(total_negi/total_posi) == 0):
4306
+ A_pos = (cperi-total_negc/total_negi)/(total_posc-total_negc*(total_posi/total_negi))
4307
+ A_neg = (cperi-total_posc*A_pos)/total_negc
4308
+ elif(total_posc-(total_posi/total_negi) == 0):
4309
+ A_neg = (cperi-total_posc/total_posi)/(total_negc-total_posc*(total_negi/total_posi))
4310
+ A_pos = (cperi-total_negc*A_neg)/total_posc
4311
+ else:
4312
+ A_neg = (cperi-total_posc/total_posi)/(total_negc-total_posc*(total_negi/total_posi))
4313
+ A_pos = (cperi-total_negc/total_negi)/(total_posc-total_negc*(total_posi/total_negi))
4314
+
4315
+ if(A_pos < 0):
4316
+ A_pos = 0
4317
+ A_neg = cperi/total_negc
4318
+ if(A_neg < 0):
4319
+ A_neg = 0
4320
+ A_pos = cperi/total_posc
4321
+
4322
+ A_pos = max(0,A_pos)*total_ions
4323
+ A_neg = max(0,A_neg)*total_ions
4324
+
4325
+ negi_dict = {}
4326
+ posi_dict = {}
4327
+
4328
+ for pi_c in ion_names:
4329
+ negi_dict[pi_c]=0
4330
+ posi_dict[pi_c]=0
4331
+
4332
+ for ni_c in negi:
4333
+ iname, icount = parse_mol(ni_c)
4334
+ negi_dict[iname]=icount*A_neg
4335
+
4336
+ total_pic = 0
4337
+ for pi_c in posi:
4338
+ iname, icount = parse_mol(pi_c)
4339
+ posi_dict[iname]=icount*A_pos
4340
+
4341
+ ion_nums = []
4342
+ for inn in ion_names:
4343
+ ion_nums.append(int(posi_dict[inn]+negi_dict[inn]))
4344
+
4345
+
4346
+
4347
+ total_ion_charge = 0
4348
+ for ind,inn in enumerate(ion_names):
4349
+ total_ion_charge += ion_charges[inn]*ion_nums[ind]
4350
+
4351
+
4352
+ cdiff = ncharges[ci]+total_ion_charge
4353
+
4354
+
4355
+ if(cdiff > 0):
4356
+ for ind,inn in enumerate(ion_names):
4357
+ if(ion_charges[inn] == -1):
4358
+ ion_nums[ind] += cdiff
4359
+ break
4360
+
4361
+ elif(cdiff < 0):
4362
+ for ind,inn in enumerate(ion_names):
4363
+ if(ion_charges[inn] == 1):
4364
+ ion_nums[ind] -= cdiff
4365
+ break
4366
+
4367
+
4368
+ ngrid = cn - np.sum(ion_nums)
4369
+ num_sol = [int(ngrid*i/totS) for i in solnums]
4370
+ for inn in ion_nums:
4371
+ num_sol.append(inn)
4372
+
4373
+
4374
+
4375
+ for n,sn in enumerate(solnames):
4376
+ adj_cn = num_sol
4377
+ if(cn > 1e-5):
4378
+ new_solnames.append(sn)
4379
+ new_num_sol.append(num_sol[n])
4380
+ added += num_sol[n]
4381
+ differ = int(cn-added)
4382
+ if(len(new_num_sol)>0):
4383
+ new_num_sol[-len(solnames)]+=differ
4384
+
4385
+ num_sol = []
4386
+ for i in range(len(solnames)):
4387
+ num_sol.append(np.sum(new_num_sol[i::len(solnames)]))
4388
+ print("THIS SHOULD BE ZERO",len(grid)-sum(num_sol))
4389
+
4390
+
4391
+
4392
+ # Names and grid positions for solvent molecules
4393
+ solvent = list(zip([s for i,s in list(zip(new_num_sol,new_solnames)) for j in range(i)],grid))
4394
+
4395
+ solvent_split = []
4396
+ for sni in range(len(solnames)):
4397
+ solvent_split.append([])
4398
+ for si in solvent:
4399
+ if(si[0] in solnames):
4400
+ solvent_split[solnames.index(si[0])].append(si)
4401
+ solvent = []
4402
+ for si in solvent_split:
4403
+ for ssi in si:
4404
+ solvent.append(ssi)
4405
+
4406
+ # Extend the list of molecules (for the topology)
4407
+ molecules.extend(list(zip(solnames,num_sol)))
4408
+ print("Building solvent and ions...")
4409
+ cc = 0
4410
+ # Build the solvent
4411
+ sol = []
4412
+ for resn,(rndm,x,y,z) in solvent:
4413
+
4414
+ cc += 1
4415
+ resi += 1
4416
+ solmol = solventParticles.get(resn)
4417
+ if solmol and len(solmol) > 1:
4418
+ # Random rotation (quaternion)
4419
+ u, v, w = random.random(), 2*math.pi*random.random(), 2*math.pi*random.random()
4420
+ s, t = math.sqrt(1-u), math.sqrt(u)
4421
+ qw, qx, qy, qz = s*math.sin(v), s*math.cos(v), t*math.sin(w), t*math.cos(w)
4422
+ qq = qw*qw-qx*qx-qy*qy-qz*qz
4423
+ for atnm,(px,py,pz) in solmol:
4424
+ qp = 2*(qx*px + qy*py + qz*pz)
4425
+ rx = x + qp*qx + qq*px + qw*(qy*pz-qz*py)
4426
+ ry = y + qp*qy + qq*py + qw*(qz*px-qx*pz)
4427
+ rz = z + qp*qz + qq*pz + qw*(qx*py-qy*px)
4428
+ sol.append(("%5d%-5s%5s%5d"%(resi%1e5,resn,atnm,atid%1e5),(rx,ry,rz)))
4429
+ atid += 1
4430
+ else:
4431
+ sol.append(("%5d%-5s%5s%5d"%(resi%1e5,resn,solmol and solmol[0][0] or resn,atid%1e5),(x,y,z)))
4432
+ atid += 1
4433
+ print("Done")
4434
+ else:
4435
+ solvent, sol = None, []
4436
+
4437
+ print("Writing files...")
4438
+ ## Write the output ##
4439
+ slen = solvent and len(sol) or 0
4440
+
4441
+ print("; NDX Solvent %d %d" % (1+plen+mlen+pglen, solvent and plen+mlen+slen+pglen or 0),file=sys.stderr)
4442
+ print("; NDX System %d %d" % (1, plen+mlen+slen+pglen),file=sys.stderr)
4443
+ print("; \"I mean, the good stuff is just INSANE\" --Julia Ormond",file=sys.stderr)
4444
+
4445
+ # Open the output stream
4446
+ oStream = options["-o"] and open(options["-o"].value,"w") or sys.stdout
4447
+
4448
+ # print(the title)
4449
+ if membrane.atoms:
4450
+ title = "INSANE! Membrane UpperLeaflet>"+":".join(lipU)+"="+":".join([str(i) for i in numU])
4451
+ title += " LowerLeaflet>"+":".join(lipL)+"="+":".join([str(i) for i in numL])
4452
+
4453
+ if protein:
4454
+ title = "Protein in " + title
4455
+ else:
4456
+ title = "Insanely solvated protein."
4457
+
4458
+ print(title,file=oStream)
4459
+
4460
+ #print(the number of atoms)
4461
+ print("%5d"%(len(protein)+len(membrane)+len(sol)+len(PGL)),file=oStream)
4462
+
4463
+
4464
+ membrane.atoms,membrane.coord = reorder_atoms(membrane.atoms,membrane.coord)
4465
+
4466
+ new_molecules = []
4467
+ mol_types = []
4468
+ for m in molecules:
4469
+ if(m[0] in mol_types):
4470
+ new_molecules[mol_types.index(m[0])][1] += m[1]
4471
+ else:
4472
+ mol_types.append(m[0])
4473
+ new_molecules.append(list(m))
4474
+
4475
+
4476
+ # print(the atoms)
4477
+ id = 1
4478
+ if protein:
4479
+ for i in range(len(protein)):
4480
+ at,rn,ri = protein.atoms[i][:3]
4481
+ x,y,z = protein.coord[i]
4482
+ oStream.write("%5d%-5s%5s%5d%8.3f%8.3f%8.3f\n"%(ri%1e5,rn,at,id%1e5,x,y,z))
4483
+ id += 1
4484
+ if PGL:
4485
+ for i in range(len(PGL)):
4486
+ at,rn,ri = PGL.atoms[i][:3]
4487
+ x,y,z = PGL.coord[i]
4488
+ x = x%pbcx
4489
+ y = y%pbcy
4490
+ oStream.write("%5d%-5s%5s%5d%8.3f%8.3f%8.3f\n"%(ri%1e5,rn,at,id%1e5,x,y,z))
4491
+ id += 1
4492
+ if membrane:
4493
+ for i in range(len(membrane)):
4494
+ at,rn,ri = membrane.atoms[i][:3]
4495
+ x,y,z = membrane.coord[i]
4496
+ oStream.write("%5d%-5s%5s%5d%8.3f%8.3f%8.3f\n"%(ri%1e5,rn,at,id%1e5,x,y,z))
4497
+ id += 1
4498
+
4499
+ if sol:
4500
+ # print(the solvent)
4501
+ print("\n".join([i[0]+"%8.3f%8.3f%8.3f"%i[1] for i in sol]),file=oStream)
4502
+
4503
+
4504
+ # print(the box)
4505
+ print("%10.5f%10.5f%10.5f%10.5f%10.5f%10.5f%10.5f%10.5f%10.5f\n"%grobox,file=oStream)
4506
+ oStream.close()
4507
+ if options["-p"].value:
4508
+ # Write a rudimentary topology file
4509
+ with open(options["-p"].value,"w") as top:
4510
+ #print('#include "martini_v3.itp"\n',file=top)
4511
+ print('; '+' '.join(sys.argv),file=top)
4512
+ print('#include "martini_v3.0.0.itp"',file=top)
4513
+ print('#include "martini_v3.0.0_ions_v1.itp"',file=top)
4514
+ print('#include "martini_v3.0.0_solvents_v1.itp"',file=top)
4515
+ print('#include "martini_v3.0.0_phospholipids_v1.itp"',file=top)
4516
+ if(PGL):
4517
+ print('#include "PGL.itp"',file=top)
4518
+
4519
+ if protein:
4520
+ print('#include "protein-cg.itp"',file=top)
4521
+ print('[ system ]\n; name\n%s\n\n[ molecules ]\n; name number'%title,file=top)
4522
+ if protein:
4523
+ print("%-10s %5d"%("Protein",1),file=top)
4524
+ print("\n".join("%-10s %7d"%tuple(i) for i in new_molecules),file=top)
4525
+
4526
+ else:
4527
+ print("\n".join("%-10s %7d"%tuple(i) for i in new_molecules),file=sys.stderr)
4528
+
4529
+ print("Done!")
4530
+
4531
+
4532
+ if __name__ == "__main__":
4533
+ main()