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