1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """The full frame order analysis."""
24
25
26
27 from numpy import float64, zeros
28 from os import F_OK, access, getcwd, sep
29 import sys
30
31
32 from data_store import Relax_data_store; ds = Relax_data_store()
33 from pipe_control.pipes import get_pipe
34 from lib.text.sectioning import section, subsection, title
35 from lib.geometry.coord_transform import spherical_to_cartesian
36 from prompt.interpreter import Interpreter
37 from lib.errors import RelaxError
38 from lib.io import open_write_file
39 from status import Status; status = Status()
40
41
43 """The frame order auto-analysis protocol."""
44
45 - def __init__(self, data_pipe_full=None, data_pipe_subset=None, pipe_bundle=None, results_dir=None, grid_inc=11, grid_inc_rigid=21, min_algor='simplex', num_int_pts_grid=50, num_int_pts_subset=[20, 100], func_tol_subset=[1e-2, 1e-2], num_int_pts_full=[100, 1000, 200000], func_tol_full=[1e-2, 1e-3, 1e-4], mc_sim_num=500, mc_int_pts=1000, mc_func_tol=1e-3, models=['rigid', 'free rotor', 'rotor', 'iso cone, free rotor', 'iso cone, torsionless', 'iso cone', 'pseudo-ellipse, torsionless', 'pseudo-ellipse']):
46 """Perform the full frame order analysis.
47
48 @param data_pipe_full: The name of the data pipe containing all of the RDC and PCS data.
49 @type data_pipe_full: str
50 @param data_pipe_subset: The name of the data pipe containing all of the RDC data but only a small subset of ~5 PCS points.
51 @type data_pipe_subset: str
52 @keyword pipe_bundle: The data pipe bundle to associate all spawned data pipes with.
53 @type pipe_bundle: str
54 @keyword results_dir: The directory where files are saved in.
55 @type results_dir: str
56 @keyword grid_inc: The number of grid increments to use in the grid search of certain models.
57 @type grid_inc: int
58 @keyword grid_inc_rigid: The number of grid increments to use in the grid search of the initial rigid model.
59 @type grid_inc_rigid: int
60 @keyword min_algor: The minimisation algorithm (in most cases this should not be changed).
61 @type min_algor: str
62 @keyword num_int_pts_grid: The number of Sobol' points for the PCS numerical integration in the grid searches.
63 @type num_int_pts_grid: int
64 @keyword num_int_pts_subset: The list of the number of Sobol' points for the PCS numerical integration to use iteratively in the optimisations after the grid search (for the PCS data subset).
65 @type num_int_pts_subset: list of int
66 @keyword func_tol_subset: The minimisation function tolerance cutoff to terminate optimisation (for the PCS data subset, see the minimise user function).
67 @type func_tol_subset: list of float
68 @keyword num_int_pts_full: The list of the number of Sobol' points for the PCS numerical integration to use iteratively in the optimisations after the grid search (for all PCS and RDC data).
69 @type num_int_pts_full: list of int
70 @keyword func_tol_full: The minimisation function tolerance cutoff to terminate optimisation (for all PCS and RDC data, see the minimise user function).
71 @type func_tol_full: list of float
72 @keyword mc_sim_num: The number of Monte Carlo simulations to be used for error analysis at the end of the analysis.
73 @type mc_sim_num: int
74 @keyword mc_int_num: The number of Sobol' points for the PCS numerical integration during Monte Carlo simulations.
75 @type mc_int_num: int
76 @keyword mc_func_tol: The minimisation function tolerance cutoff to terminate optimisation during Monte Carlo simulations.
77 @type mc_func_tol: float
78 @keyword models: The frame order models to use in the analysis. The 'rigid' model must be included as this is essential for the analysis.
79 @type models: list of str
80 """
81
82
83 status.exec_lock.acquire(pipe_bundle, mode='auto-analysis')
84
85
86 title(file=sys.stdout, text="Frame order auto-analysis", prespace=7)
87
88
89 self.data_pipe_full = data_pipe_full
90 self.data_pipe_subset = data_pipe_subset
91 self.pipe_bundle = pipe_bundle
92 self.grid_inc = grid_inc
93 self.grid_inc_rigid = grid_inc_rigid
94 self.min_algor = min_algor
95 self.num_int_pts_grid = num_int_pts_grid
96 self.num_int_pts_subset = num_int_pts_subset
97 self.func_tol_subset = func_tol_subset
98 self.num_int_pts_full = num_int_pts_full
99 self.func_tol_full = func_tol_full
100 self.mc_sim_num = mc_sim_num
101 self.mc_int_pts = mc_int_pts
102 self.mc_func_tol = mc_func_tol
103 self.models = models
104
105
106 self.pipe_name_dict = {}
107 self.pipe_name_list = []
108
109
110 if results_dir:
111 self.results_dir = results_dir + sep
112 else:
113 self.results_dir = getcwd() + sep
114
115
116 self.check_vars()
117
118
119 self.interpreter = Interpreter(show_script=False, raise_relax_error=True)
120 self.interpreter.populate_self()
121 self.interpreter.on(verbose=False)
122
123
124 try:
125
126 self.nested_models()
127
128
129 if not self.read_results(model='final', pipe_name='final'):
130
131 self.interpreter.model_selection(method='AIC', modsel_pipe='final', pipes=self.pipe_name_list)
132
133
134 self.interpreter.frame_order.num_int_pts(num=self.mc_int_pts)
135
136
137 self.interpreter.monte_carlo.setup(number=self.mc_sim_num)
138 self.interpreter.monte_carlo.create_data()
139 self.interpreter.monte_carlo.initial_values()
140 self.interpreter.minimise(self.min_algor, func_tol=self.mc_func_tol, constraints=False)
141 self.interpreter.eliminate()
142 self.interpreter.monte_carlo.error_analysis()
143
144
145 self.interpreter.results.write(file='results', dir=self.results_dir+'final', force=True)
146
147
148 self.visualisation(model='final')
149
150
151 finally:
152
153 status.exec_lock.release()
154
155
156 self.interpreter.state.save('final_state', dir=self.results_dir, force=True)
157
158
160 """Check that the user has set the variables correctly."""
161
162
163 if not isinstance(self.pipe_bundle, str):
164 raise RelaxError("The pipe bundle name '%s' is invalid." % self.pipe_bundle)
165
166
167 if not isinstance(self.grid_inc, int):
168 raise RelaxError("The grid_inc user variable '%s' is incorrectly set. It should be an integer." % self.grid_inc)
169 if not isinstance(self.grid_inc_rigid, int):
170 raise RelaxError("The grid_inc_rigid user variable '%s' is incorrectly set. It should be an integer." % self.grid_inc)
171 if not isinstance(self.min_algor, str):
172 raise RelaxError("The min_algor user variable '%s' is incorrectly set. It should be a string." % self.min_algor)
173 if not isinstance(self.num_int_pts_grid, int):
174 raise RelaxError("The num_int_pts_grid user variable '%s' is incorrectly set. It should be an integer." % self.mc_sim_num)
175 if not isinstance(self.mc_sim_num, int):
176 raise RelaxError("The mc_sim_num user variable '%s' is incorrectly set. It should be an integer." % self.mc_sim_num)
177 if not isinstance(self.mc_int_pts, int):
178 raise RelaxError("The mc_int_pts user variable '%s' is incorrectly set. It should be an integer." % self.mc_int_pts)
179 if not isinstance(self.mc_func_tol, float):
180 raise RelaxError("The mc_func_tol user variable '%s' is incorrectly set. It should be a floating point number." % self.mc_func_tol)
181
182
183 if len(self.num_int_pts_subset) != len(self.func_tol_subset):
184 raise RelaxError("The num_int_pts_subset and func_tol_subset user variables of '%s' and '%s' respectively must be of the same length." % (self.num_int_pts_subset, self.func_tol_subset))
185 for i in range(len(self.num_int_pts_subset)):
186 if not isinstance(self.num_int_pts_subset[i], int):
187 raise RelaxError("The num_int_pts_subset user variable '%s' must be a list of integers." % self.num_int_pts_subset)
188 if not isinstance(self.func_tol_subset[i], float):
189 raise RelaxError("The func_tol_subset user variable '%s' must be a list of floats." % self.func_tol_subset)
190
191
192 if len(self.num_int_pts_full) != len(self.func_tol_full):
193 raise RelaxError("The num_int_pts_full and func_tol_full user variables of '%s' and '%s' respectively must be of the same length." % (self.num_int_pts_full, self.func_tol_full))
194 for i in range(len(self.num_int_pts_full)):
195 if not isinstance(self.num_int_pts_full[i], int):
196 raise RelaxError("The num_int_pts_full user variable '%s' must be a list of integers." % self.num_int_pts_full)
197 if not isinstance(self.func_tol_full[i], float):
198 raise RelaxError("The func_tol_full user variable '%s' must be a list of floats." % self.func_tol_full)
199
200
202 """Set up a customised grid search increment number for each model.
203
204 @param model: The frame order model.
205 @type model: str
206 @return: The list of increment values.
207 @rtype: list of int and None
208 """
209
210
211 incs = []
212 if hasattr(cdp, 'pivot_fixed') and not cdp.pivot_fixed:
213 incs += [None, None, None]
214 if hasattr(cdp, 'ave_pos_translation') and cdp.ave_pos_translation:
215 incs += [None, None, None]
216
217
218 if model == 'rotor':
219 incs += [None, None, None, self.grid_inc, self.grid_inc, self.grid_inc]
220
221
222 if model == 'free rotor':
223 incs += [self.grid_inc, self.grid_inc, self.grid_inc, self.grid_inc]
224
225
226 if model == 'iso cone, torsionless':
227 incs += [None, None, None, self.grid_inc, self.grid_inc, self.grid_inc]
228
229
230 if model == 'iso cone, free rotor':
231 incs += [None, None, None, None, self.grid_inc]
232
233
234 if model == 'iso cone':
235 incs += [None, None, None, self.grid_inc, self.grid_inc, self.grid_inc, None]
236
237
238 if model == 'pseudo-ellipse, torsionless':
239 incs += [None, None, None, self.grid_inc, self.grid_inc, self.grid_inc, self.grid_inc, None]
240
241
242 if model == 'pseudo-ellipse, free rotor':
243 incs += [None, None, None, self.grid_inc, self.grid_inc, self.grid_inc, self.grid_inc, None]
244
245
246 if model == 'pseudo-ellipse':
247 incs += [None, None, None, self.grid_inc, self.grid_inc, self.grid_inc, self.grid_inc, None, None]
248
249
250 return incs
251
252
254 """Copy the parameters from the simpler nested models for faster optimisation.
255
256 @param model: The frame order model.
257 @type model: str
258 """
259
260
261 if model not in []:
262
263 rigid_pipe = get_pipe(self.pipe_name_dict['rigid'])
264
265
266 if hasattr(rigid_pipe, 'ave_pos_x'):
267 cdp.ave_pos_x = rigid_pipe.ave_pos_x
268 if hasattr(rigid_pipe, 'ave_pos_y'):
269 cdp.ave_pos_y = rigid_pipe.ave_pos_y
270 if hasattr(rigid_pipe, 'ave_pos_z'):
271 cdp.ave_pos_z = rigid_pipe.ave_pos_z
272 if model not in ['free rotor', 'iso cone, free rotor']:
273 cdp.ave_pos_alpha = rigid_pipe.ave_pos_alpha
274 cdp.ave_pos_beta = rigid_pipe.ave_pos_beta
275 cdp.ave_pos_gamma = rigid_pipe.ave_pos_gamma
276
277
278 if model in ['iso cone']:
279
280 rotor_pipe = get_pipe(self.pipe_name_dict['rotor'])
281
282
283 cdp.axis_theta = rotor_pipe.axis_theta
284 cdp.axis_phi = rotor_pipe.axis_phi
285
286
287 if model in ['iso cone, free rotor']:
288
289 free_rotor_pipe = get_pipe(self.pipe_name_dict['free rotor'])
290
291
292 cdp.axis_theta = free_rotor_pipe.axis_theta
293 cdp.axis_phi = free_rotor_pipe.axis_phi
294
295
296 if model in ['iso cone', 'pseudo-ellipse']:
297
298 rotor_pipe = get_pipe(self.pipe_name_dict['rotor'])
299
300
301 cdp.cone_sigma_max = rotor_pipe.cone_sigma_max
302
303
304 if model in ['pseudo-ellipse, torsionless', 'pseudo-ellipse, free rotor', 'pseudo-ellipse']:
305
306 pipe = get_pipe(self.pipe_name_dict['iso cone, torsionless'])
307
308
309 cdp.cone_theta_x = pipe.cone_theta
310 cdp.cone_theta_y = pipe.cone_theta
311
312
314 """Protocol for the nested optimisation of the frame order models."""
315
316
317 self.optimise_rigid()
318
319
320 for model in self.models:
321
322 if model == 'rigid':
323 continue
324
325
326 title = model[0].upper() + model[1:]
327
328
329 section(file=sys.stdout, text="%s frame order model"%title, prespace=5)
330
331
332 self.pipe_name_dict[model] = '%s - %s' % (title, self.pipe_bundle)
333 self.pipe_name_list.append(self.pipe_name_dict[model])
334
335
336 if self.read_results(model=model, pipe_name=self.pipe_name_dict[model]):
337
338 self.interpreter.eliminate()
339
340
341 self.visualisation(model=model)
342
343
344 continue
345
346
347 self.interpreter.pipe.copy(self.data_pipe_subset, self.pipe_name_dict[model], bundle_to=self.pipe_bundle)
348 self.interpreter.pipe.switch(self.pipe_name_dict[model])
349
350
351 self.interpreter.frame_order.select_model(model=model)
352
353
354 self.nested_params(model)
355
356
357 self.interpreter.frame_order.num_int_pts(num=self.num_int_pts_grid)
358 self.interpreter.frame_order.quad_int(flag=False)
359
360
361 incs = self.custom_grid_incs(model)
362 self.interpreter.grid_search(inc=incs, constraints=False)
363
364
365 for i in range(len(self.num_int_pts_subset)):
366 self.interpreter.frame_order.num_int_pts(num=self.num_int_pts_subset[i])
367 self.interpreter.minimise(self.min_algor, func_tol=self.func_tol_subset[i], constraints=False)
368
369
370 self.interpreter.pcs.copy(pipe_from=self.data_pipe_full, pipe_to=self.pipe_name_dict[model])
371
372
373 for i in range(len(self.num_int_pts_full)):
374 self.interpreter.frame_order.num_int_pts(num=self.num_int_pts_full[i])
375 self.interpreter.minimise(self.min_algor, func_tol=self.func_tol_full[i], constraints=False)
376
377
378 self.print_results()
379
380
381 self.interpreter.eliminate()
382
383
384 self.interpreter.results.write(dir=self.results_dir+model, force=True)
385
386
387 self.visualisation(model=model)
388
389
391 """Optimise the rigid frame order model.
392
393 The Sobol' integration is not used here, so the algorithm is different to the other frame order models.
394 """
395
396
397 model = 'rigid'
398 title = model[0].upper() + model[1:]
399
400
401 section(file=sys.stdout, text="%s frame order model"%title, prespace=5)
402
403
404 self.pipe_name_dict[model] = '%s - %s' % (title, self.pipe_bundle)
405 self.pipe_name_list.append(self.pipe_name_dict[model])
406
407
408 if self.read_results(model=model, pipe_name=self.pipe_name_dict[model]):
409
410 self.interpreter.frame_order.pdb_model(dir=self.results_dir+model, force=True)
411
412
413 return
414
415
416 self.interpreter.pipe.copy(self.data_pipe_full, self.pipe_name_dict[model], bundle_to=self.pipe_bundle)
417 self.interpreter.pipe.switch(self.pipe_name_dict[model])
418
419
420 self.interpreter.frame_order.select_model(model=model)
421
422
423 if cdp.ave_pos_translation:
424
425 print("\n\nTranslation active - splitting the grid search and iterating.")
426
427
428 for i in range(2):
429
430 self.interpreter.grid_search(inc=[None, None, None, self.grid_inc_rigid, self.grid_inc_rigid, self.grid_inc_rigid], constraints=False)
431
432
433 self.interpreter.grid_search(inc=[self.grid_inc_rigid, self.grid_inc_rigid, self.grid_inc_rigid, None, None, None], constraints=False)
434
435
436 else:
437 self.interpreter.grid_search(inc=self.grid_inc_rigid, constraints=False)
438
439
440 self.interpreter.minimise(self.min_algor, constraints=False)
441
442
443 self.print_results()
444
445
446 self.interpreter.results.write(dir=self.results_dir+model, force=True)
447
448
449 self.interpreter.frame_order.pdb_model(dir=self.results_dir+model, force=True)
450
451
453 """Print out the optimisation results for the current data pipe."""
454
455
456 sys.stdout.write("\nFinal optimisation results:\n")
457
458
459 format_float = " %-20s %20.15f\n"
460 format_vect = " %-20s %20s\n"
461
462
463 if hasattr(cdp, 'ave_pos_x') or hasattr(cdp, 'ave_pos_alpha') or hasattr(cdp, 'ave_pos_beta') or hasattr(cdp, 'ave_pos_gamma'):
464 sys.stdout.write("\nAverage moving domain position:\n")
465 if hasattr(cdp, 'ave_pos_x'):
466 sys.stdout.write(format_float % ('x:', cdp.ave_pos_x))
467 if hasattr(cdp, 'ave_pos_y'):
468 sys.stdout.write(format_float % ('y:', cdp.ave_pos_y))
469 if hasattr(cdp, 'ave_pos_z'):
470 sys.stdout.write(format_float % ('z:', cdp.ave_pos_z))
471 if hasattr(cdp, 'ave_pos_alpha'):
472 sys.stdout.write(format_float % ('alpha:', cdp.ave_pos_alpha))
473 if hasattr(cdp, 'ave_pos_beta'):
474 sys.stdout.write(format_float % ('beta:', cdp.ave_pos_beta))
475 if hasattr(cdp, 'ave_pos_gamma'):
476 sys.stdout.write(format_float % ('gamma:', cdp.ave_pos_gamma))
477
478
479 if hasattr(cdp, 'eigen_alpha') or hasattr(cdp, 'eigen_beta') or hasattr(cdp, 'eigen_gamma') or hasattr(cdp, 'axis_theta') or hasattr(cdp, 'axis_phi'):
480 sys.stdout.write("\nFrame order eigenframe:\n")
481 if hasattr(cdp, 'eigen_alpha'):
482 sys.stdout.write(format_float % ('eigen alpha:', cdp.eigen_alpha))
483 if hasattr(cdp, 'eigen_beta'):
484 sys.stdout.write(format_float % ('eigen beta:', cdp.eigen_beta))
485 if hasattr(cdp, 'eigen_gamma'):
486 sys.stdout.write(format_float % ('eigen gamma:', cdp.eigen_gamma))
487
488
489 if hasattr(cdp, 'axis_theta'):
490
491 sys.stdout.write(format_float % ('axis theta:', cdp.axis_theta))
492 sys.stdout.write(format_float % ('axis phi:', cdp.axis_phi))
493
494
495 axis = zeros(3, float64)
496 spherical_to_cartesian([1.0, cdp.axis_theta, cdp.axis_phi], axis)
497 sys.stdout.write(format_vect % ('axis:', axis))
498
499
500 if hasattr(cdp, 'cone_theta_x') or hasattr(cdp, 'cone_theta_y') or hasattr(cdp, 'cone_theta') or hasattr(cdp, 'cone_s1') or hasattr(cdp, 'cone_sigma_max'):
501 sys.stdout.write("\nFrame ordering:\n")
502 if hasattr(cdp, 'cone_theta_x'):
503 sys.stdout.write(format_float % ('cone theta_x:', cdp.cone_theta_x))
504 if hasattr(cdp, 'cone_theta_y'):
505 sys.stdout.write(format_float % ('cone theta_y:', cdp.cone_theta_y))
506 if hasattr(cdp, 'cone_theta'):
507 sys.stdout.write(format_float % ('cone theta:', cdp.cone_theta))
508 if hasattr(cdp, 'cone_s1'):
509 sys.stdout.write(format_float % ('cone s1:', cdp.cone_s1))
510 if hasattr(cdp, 'cone_sigma_max'):
511 sys.stdout.write(format_float % ('sigma_max:', cdp.cone_sigma_max))
512
513
514 if hasattr(cdp, 'chi2'):
515 sys.stdout.write("\nMinimisation statistics:\n")
516 if hasattr(cdp, 'chi2'):
517 sys.stdout.write(format_float % ('chi2:', cdp.chi2))
518
519
520 sys.stdout.write("\n")
521
522
524 """Attempt to read old results files.
525
526 @keyword model: The frame order model.
527 @type model: str
528 @keyword pipe_name: The name of the data pipe to use for this model.
529 @type pipe_name: str
530 @return: True if the file exists and has been read, False otherwise.
531 @rtype: bool
532 """
533
534
535 path = self.results_dir + model + sep + 'results.bz2'
536
537
538 if not access(path, F_OK):
539 return False
540
541
542 self.interpreter.pipe.create(pipe_name=pipe_name, pipe_type='frame order')
543
544
545 self.interpreter.results.read(path)
546
547
548 self.print_results()
549
550
551 return True
552
553
555 """Create visual representations of the frame order results for the given model.
556
557 This includes a PDB representation of the motions (the 'cone.pdb' file located in each model directory) together with a relax script for displaying the average domain positions together with the cone/motion representation in PyMOL (the 'pymol_display.py' file, also created in the model directory).
558
559 @keyword model: The frame order model to visualise. This should match the model of the current data pipe, unless the special value of 'final' is used to indicate the visualisation of the final results.
560 @type model: str
561 """
562
563
564 if model != 'final' and model != cdp.model:
565 raise RelaxError("The model '%s' does not match the model '%s' of the current data pipe." % (model, cdp.model))
566
567
568 self.interpreter.frame_order.pdb_model(dir=self.results_dir+model, force=True)
569
570
571 subsection(file=sys.stdout, text="Creating a PyMOL visualisation script.")
572 script = open_write_file(file_name='pymol_display.py', dir=self.results_dir+model, force=True)
573
574
575 script.write("# relax script for displaying the frame order results of this '%s' model in PyMOL.\n\n" % model)
576
577
578 script.write("# PyMOL visualisation.\n")
579 script.write("pymol.view()\n")
580 script.write("pymol.command('show spheres')\n")
581 script.write("pymol.frame_order(file='frame_order.pdb', dist_file='frame_order_distribution.pdb')\n")
582
583
584 script.close()
585