1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 from math import cos, pi, sin
24 from numpy import array, dot, eye, float64, zeros
25
26
27 from lib.geometry.rotations import two_vect_to_R
28 from pipe_control.structure.geometric import angles_uniform, get_proton_name
29
30
31 -def cone_edge(mol=None, cone=None, res_name='CON', res_num=None, chain_id='', apex=None, axis=None, R=None, scale=None, inc=None, distribution='uniform', debug=False):
32 """Add a residue to the atomic data representing a cone of the given angle.
33
34 A series of vectors totalling the number of increments and starting at the origin are equally spaced around the cone axis. The atoms representing neighbouring vectors will be directly bonded together. This will generate an object representing the outer edge of a cone.
35
36
37 @keyword mol: The molecule container.
38 @type mol: MolContainer instance
39 @keyword cone: The cone object. This should provide the limit_check() method with determines the limits of the distribution accepting two arguments, the polar angle phi and the azimuthal angle theta, and return True if the point is in the limits or False if outside. It should also provide the phi_max() method for returning the phi value for the given theta.
40 @type cone: class instance
41 @keyword res_name: The residue name.
42 @type res_name: str
43 @keyword res_num: The residue number.
44 @type res_num: int
45 @keyword chain_id: The chain identifier.
46 @type chain_id: str
47 @keyword apex: The apex of the cone.
48 @type apex: numpy array, len 3
49 @keyword axis: The central axis of the cone. If supplied, then this arg will be used to construct the rotation matrix.
50 @type axis: numpy array, len 3
51 @keyword R: A 3x3 rotation matrix. If the axis arg supplied, then this matrix will be ignored.
52 @type R: 3x3 numpy array
53 @keyword scale: The scaling factor to stretch all points by.
54 @type scale: float
55 @keyword inc: The number of increments or number of vectors used to generate the outer edge of the cone.
56 @type inc: int
57 @keyword distribution: The type of point distribution to use. This can be 'uniform' or 'regular'.
58 @type distribution: str
59 """
60
61
62 atom_num = mol.atom_num[-1]+1
63
64
65 mol.atom_add(pdb_record='HETATM', atom_num=atom_num, atom_name='APX', res_name=res_name, res_num=res_num, pos=apex, segment_id=None, element='H')
66 origin_atom = atom_num
67
68
69 if distribution == 'uniform':
70 phi, theta = angles_uniform(inc)
71 else:
72 phi, theta = angles_regular(inc)
73
74
75 if R == None:
76 R = eye(3)
77
78
79 if axis != None:
80 two_vect_to_R(array([0, 0, 1], float64), axis, R)
81
82
83 phi_max = zeros(len(theta), float64)
84 edge_index = zeros(len(theta), int)
85 for i in range(len(theta)):
86
87 phi_max[i] = cone.phi_max(theta[i])
88
89
90 for j in range(len(phi)):
91 if phi[j] <= phi_max[i]:
92 edge_index[i] = j
93 break
94
95
96 edge_index_rev = len(phi) - 1 - edge_index
97
98
99 atom_num = atom_num + 1
100 for i in range(len(theta)):
101
102 x = cos(theta[i]) * sin(phi_max[i])
103 y = sin(theta[i])* sin(phi_max[i])
104 z = cos(phi_max[i])
105 vector = array([x, y, z], float64)
106
107
108 vector = dot(R, vector)
109
110
111 atom_id = 'T' + repr(i)
112
113
114 pos = apex+vector*scale
115
116
117 if debug:
118 print("i: %s; theta: %s" % (i, theta[i]))
119 print("%sAdding atom %s." % (" "*4, get_proton_name(atom_num)))
120
121
122 mol.atom_add(pdb_record='HETATM', atom_num=atom_num, atom_name=get_proton_name(atom_num), res_name=res_name, res_num=res_num, pos=pos, segment_id=None, element='H')
123
124
125 mol.atom_connect(index1=origin_atom-1, index2=atom_num-1)
126
127
128 atom_num = atom_num + 1
129
130
131 for j in range(len(phi)):
132
133 k = len(phi) - 1 - j
134
135
136 if debug:
137 print("%sj: %s; phi: %-20s; k: %s; phi: %-20s; phi_max: %-20s" % (" "*4, j, phi[j], k, phi[k], phi_max[i]))
138
139
140 skip = True
141
142
143 fwd_index = i+1
144 if i == len(theta)-1:
145 fwd_index = 0
146 if j >= edge_index[i] and j < edge_index[fwd_index] and not abs(phi_max[fwd_index] - phi[j]) < 1e-6:
147
148 if debug:
149 print("%sForward edge." % (" "*8))
150
151
152 skip = False
153
154
155 phi_val = phi[j]
156 if fwd_index == 0:
157 theta_max = theta[fwd_index] + 2*pi
158 else:
159 theta_max = theta[fwd_index]
160 theta_max = cone.theta_max(phi_val, theta_min=theta[i], theta_max=theta_max-1e-7)
161
162
163 rev_index = i-1
164 if i == 0:
165 rev_index = len(theta)-1
166 if i < len(theta)-1 and j > edge_index_rev[i] and j <= edge_index_rev[i+1] and not abs(phi_max[fwd_index] - phi[k]) < 1e-6:
167
168 if debug:
169 print("%sBack edge." % (" "*8))
170
171
172 skip = False
173
174
175 phi_val = phi[k]
176 theta_max = cone.theta_max(phi_val, theta_min=theta[i-1], theta_max=theta[i])
177
178
179 if skip:
180 continue
181
182
183 if debug:
184 print("%sAdding atom %s." % (" "*8, get_proton_name(atom_num)))
185
186
187 x = cos(theta_max) * sin(phi_val)
188 y = sin(theta_max) * sin(phi_val)
189 z = cos(phi_val)
190 pos = array([x, y, z], float64) * scale
191
192
193 pos = apex + dot(R, pos)
194
195
196 mol.atom_add(pdb_record='HETATM', atom_num=atom_num, atom_name=get_proton_name(atom_num), res_name=res_name, chain_id=chain_id, res_num=res_num, pos=pos, segment_id=None, element='H')
197
198
199 atom_num = atom_num + 1
200
201
202 if debug:
203 print("\nBuilding the edge.")
204
205
206 for i in range(origin_atom, atom_num-2):
207
208 if debug:
209 print("%sCone edge, connecting %s to %s" % (" "*4, get_proton_name(i), get_proton_name(i+1)))
210
211
212 mol.atom_connect(index1=i, index2=i+1)
213
214
215 mol.atom_connect(index1=atom_num-2, index2=origin_atom)
216
217
218 -def cone(mol=None, cone=None, start_res=1, apex=None, axis=None, R=None, inc=None, scale=30.0, distribution='regular', axis_flag=True):
219 """Create a structural representation of the given cone object.
220
221 @keyword mol: The molecule container.
222 @type mol: MolContainer instance
223 @keyword cone: The cone object. This should provide the limit_check() method with determines the limits of the distribution accepting two arguments, the polar angle phi and the azimuthal angle theta, and return True if the point is in the limits or False if outside. It should also provide the theta_max() method for returning the theta value for the given phi, the phi_max() method for returning the phi value for the given theta.
224 @type cone: class instance
225 @keyword start_res: The starting residue number.
226 @type start_res: str
227 @keyword apex: The apex of the cone.
228 @type apex: rank-1, 3D numpy array
229 @keyword axis: The central axis of the cone. If not supplied, the z-axis will be used.
230 @type axis: rank-1, 3D numpy array
231 @keyword R: The rotation matrix.
232 @type R: rank-2, 3D numpy array
233 @keyword inc: The increment number used to determine the number of latitude and longitude lines.
234 @type inc: int
235 @keyword scale: The scaling factor to stretch the unit cone by.
236 @type scale: float
237 @keyword distribution: The type of point distribution to use. This can be 'uniform' or 'regular'.
238 @type distribution: str
239 @keyword axis_flag: A flag which if True will create the cone's axis.
240 @type axis_flag: bool
241 """
242
243
244 if not axis:
245 axis = array([0, 0, 1], float64)
246
247
248 if R == None:
249 R = eye(3)
250
251
252 start_atom = 1
253 if hasattr(mol, 'atom_num'):
254 start_atom = mol.atom_num[-1]+1
255
256
257 if axis_flag:
258
259 mol.atom_add(pdb_record='HETATM', atom_num=start_atom, atom_name='R', res_name='APX', res_num=start_res, pos=apex, element='C')
260
261
262 print("\nGenerating the axis vectors.")
263 res_num = generate_vector_residues(mol=mol, vector=dot(R, axis), atom_name='Axis', res_name_vect='AXE', res_num=start_res+1, origin=apex, scale=scale)
264
265
266 print("\nGenerating the cone outer edge.")
267 edge_start_atom = mol.atom_num[-1]+1
268 cone_edge(mol=mol, cone=cone, res_name='EDG', res_num=start_res+2, apex=apex, R=R, scale=scale, inc=inc, distribution=distribution)
269
270
271 print("\nGenerating the cone cap.")
272 cone_start_atom = mol.atom_num[-1]+1
273 generate_vector_dist(mol=mol, res_name='CON', res_num=start_res+3, centre=apex, R=R, limit_check=cone.limit_check, scale=scale, inc=inc, distribution=distribution)
274 stitch_cone_to_edge(mol=mol, cone=cone, dome_start=cone_start_atom, edge_start=edge_start_atom+1, scale=scale, inc=inc, distribution=distribution)
275
276
277 -def stitch_cone_to_edge(mol=None, cone=None, chain_id='', dome_start=None, edge_start=None, scale=1.0, inc=None, distribution='uniform', debug=False):
278 """Function for stitching the cone dome to its edge, in the PDB representations.
279
280 @keyword mol: The molecule container.
281 @type mol: MolContainer instance
282 @keyword cone: The cone object. This should provide the limit_check() method with determines the limits of the distribution accepting two arguments, the polar angle phi and the azimuthal angle theta, and return True if the point is in the limits or False if outside. It should also provide the theta_max() method for returning the theta value for the given phi.
283 @type cone: class instance
284 @keyword chain_id: The chain identifier.
285 @type chain_id: str
286 @keyword dome_start: The starting atom number of the cone dome residue.
287 @type dome_start: int
288 @keyword edge_start: The starting atom number of the cone edge residue.
289 @type edge_start: int
290 @keyword scale: The scaling factor to stretch all points by.
291 @type scale: float
292 @keyword inc: The number of increments or number of vectors used to generate the outer edge of the cone.
293 @type inc: int
294 @keyword distribution: The type of point distribution to use. This can be 'uniform' or 'regular'.
295 @type distribution: str
296 """
297
298
299 if distribution == 'uniform':
300 phi, theta = angles_uniform(inc)
301 else:
302 phi, theta = angles_regular(inc)
303
304
305 phi_max = zeros(len(theta), float64)
306 edge_index = zeros(len(theta), int)
307 for i in range(len(theta)):
308
309 phi_max[i] = cone.phi_max(theta[i])
310
311
312 for j in range(len(phi)):
313 if phi[j] <= phi_max[i]:
314 edge_index[i] = j
315 break
316
317
318 edge_index_rev = len(phi) - 1 - edge_index
319
320
321 if debug:
322 print("\nDome start: %s" % dome_start)
323 print("Edge start: %s" % edge_start)
324 print("Edge indices: %s" % edge_index)
325 print("Edge indices rev: %s" % edge_index_rev)
326
327
328 dome_atom = dome_start
329 edge_atom = edge_start
330 for i in range(len(theta)):
331
332 if debug:
333 print("i: %s; theta: %s" % (i, theta[i]))
334 print("%sDome atom: %s" % (" "*4, get_proton_name(dome_atom)))
335 print("%sStitching longitudinal line to edge - %s to %s." % (" "*4, get_proton_name(edge_atom), get_proton_name(dome_atom)))
336
337
338 mol.atom_connect(index1=dome_atom-1, index2=edge_atom-1)
339
340
341 edge_atom = edge_atom + 1
342
343
344 for j in range(len(phi)):
345
346 k = len(phi) - 1 - j
347
348
349 if debug:
350 print("%sj: %s; phi: %-20s; k: %s; phi: %-20s; phi_max: %-20s" % (" "*4, j, phi[j], k, phi[k], phi_max[i]))
351
352
353 skip = True
354
355
356 fwd_index = i+1
357 if i == len(theta)-1:
358 fwd_index = 0
359 if j >= edge_index[i] and j < edge_index[fwd_index] and not abs(phi_max[fwd_index] - phi[j]) < 1e-6:
360
361 if debug:
362 print("%sForward edge." % (" "*8))
363
364
365 skip = False
366 forward = True
367
368
369 rev_index = i-1
370 if i == 0:
371 rev_index = len(theta)-1
372 if i < len(theta)-1 and j > edge_index_rev[i] and j <= edge_index_rev[i+1] and not abs(phi_max[fwd_index] - phi[k]) < 1e-6:
373
374 if debug:
375 print("%sBack edge." % (" "*8))
376
377
378 skip = False
379 forward = False
380
381
382 if skip:
383 continue
384
385
386 if forward:
387 atom = dome_atom + j - edge_index[i]
388 else:
389 atom = dome_atom + (edge_index_rev[i]+1) + k - edge_index[fwd_index]
390
391
392 if debug:
393 print("%sStitching latitude line to edge - %s to %s." % (" "*8, get_proton_name(edge_atom), get_proton_name(atom)))
394
395
396 mol.atom_connect(index1=atom-1, index2=edge_atom-1)
397
398
399 edge_atom = edge_atom + 1
400
401
402 dome_atom = dome_atom + (len(phi) - edge_index[i])
403