Author: bugman Date: Fri Jul 11 10:46:21 2014 New Revision: 24522 URL: http://svn.gna.org/viewcvs/relax?rev=24522&view=rev Log: Parallelised the frame order grid search to run on clusters or multi-core systems via OpenMPI. This involved the creation of the Frame_order_grid_command class which is the multi-processor Slave_command for performing the grid search. This was created by duplicating the Frame_order_minimise_command class and then differentiating both classes. For the subdivision of the grid search, the new minfx grid.grid_split_array() function is used in the frame order grid() API method. The grid() method no longer calls the minimise() method but instead obtains the processor box itself and adds the subdivided grid slaves to the processor. The relax grid_search user function takes care of the rest. Modified: branches/frame_order_cleanup/specific_analyses/frame_order/api.py branches/frame_order_cleanup/specific_analyses/frame_order/optimisation.py Modified: branches/frame_order_cleanup/specific_analyses/frame_order/api.py URL: http://svn.gna.org/viewcvs/relax/branches/frame_order_cleanup/specific_analyses/frame_order/api.py?rev=24522&r1=24521&r2=24522&view=diff ============================================================================== --- branches/frame_order_cleanup/specific_analyses/frame_order/api.py (original) +++ branches/frame_order_cleanup/specific_analyses/frame_order/api.py Fri Jul 11 10:46:21 2014 @@ -25,6 +25,7 @@ # Python module imports. from copy import deepcopy from math import pi +from minfx.grid import grid_split_array from numpy import array, dot, float64, zeros from warnings import warn @@ -40,7 +41,7 @@ from specific_analyses.api_common import API_common from specific_analyses.frame_order.checks import check_pivot from specific_analyses.frame_order.data import domain_moving -from specific_analyses.frame_order.optimisation import Frame_order_memo, Frame_order_minimise_command, grid_row, store_bc_data, target_fn_setup +from specific_analyses.frame_order.optimisation import Frame_order_grid_command, Frame_order_memo, Frame_order_minimise_command, grid_row, store_bc_data, target_fn_setup from specific_analyses.frame_order.parameter_object import Frame_order_params from specific_analyses.frame_order.parameters import assemble_param_vector, assemble_scaling_matrix, linear_constraints, param_num, update_model from specific_analyses.frame_order.variables import MODEL_ISO_CONE_FREE_ROTOR @@ -507,23 +508,31 @@ warn(RelaxWarning("The '%s' model parameters are not constrained, turning the linear constraint algorithm off." % cdp.model)) constraints = False - # Eliminate all points outside of constraints (useful for the pseudo-ellipse models). - if constraints: - # Construct a new point array. - new_pts = [] - for i in range(total_pts): - # Calculate A.x - b. - ci = dot(A, pts[i]) - b - - # Only add the point if all constraints are satisfied. - if min(ci) >= 0.0: - new_pts.append(pts[i]) - - # Convert to a numpy array. - pts = array(new_pts) - - # Minimisation. - self.minimise(min_algor='grid', min_options=pts, constraints=constraints, verbosity=verbosity, sim_index=sim_index) + + # Printout. + print("Parallelised grid search.") + + # Get the Processor box singleton (it contains the Processor instance) and alias the Processor. + processor_box = Processor_box() + processor = processor_box.processor + + # Loop over each grid subdivision, with all points violating constraints being eliminated. + verbosity_init = True + for subdivision in grid_split_array(divisions=processor.processor_size(), points=pts, A=A, b=b): + # Set up the memo for storage on the master. + memo = Frame_order_memo(sim_index=sim_index, scaling=True, scaling_matrix=scaling_matrix) + + # Set up the command object to send to the slave and execute. + command = Frame_order_grid_command(points=subdivision, scaling_matrix=scaling_matrix, sim_index=sim_index, verbosity=verbosity, verbosity_init=verbosity_init) + + # Add the slave command and memo to the processor queue. + processor.add_to_queue(command, memo) + + # Turn off the verbosity_init flag so that the target_fn_setup() call in Frame_order_grid_command only prints out the information once for the first subdivision. + verbosity_init = False + + # Execute the queued elements. + processor.run_queue() def map_bounds(self, param, spin_id=None): @@ -593,7 +602,7 @@ algor = min_algor if min_algor == 'Log barrier': algor = min_options[0] - allowed = ['grid', 'simplex'] + allowed = ['simplex'] if algor not in allowed: raise RelaxError("Only the 'simplex' minimisation algorithm is supported for the relaxation dispersion analysis as function gradients are not implemented.") Modified: branches/frame_order_cleanup/specific_analyses/frame_order/optimisation.py URL: http://svn.gna.org/viewcvs/relax/branches/frame_order_cleanup/specific_analyses/frame_order/optimisation.py?rev=24522&r1=24521&r2=24522&view=diff ============================================================================== --- branches/frame_order_cleanup/specific_analyses/frame_order/optimisation.py (original) +++ branches/frame_order_cleanup/specific_analyses/frame_order/optimisation.py Fri Jul 11 10:46:21 2014 @@ -804,6 +804,53 @@ +class Frame_order_grid_command(Slave_command): + """Command class for relaxation dispersion optimisation on the slave processor.""" + + def __init__(self, points=None, scaling_matrix=None, sim_index=None,verbosity=None, verbosity_init=False): + """Initialise the base class, storing all the master data to be sent to the slave processor. + + This method is run on the master processor whereas the run() method is run on the slave processor. + + @keyword points: The points of the grid search subdivision to search over. + @type points: numpy rank-2 array + @keyword scaling_matrix: The diagonal, square scaling matrix. + @type scaling_matrix: numpy diagonal matrix + @keyword sim_index: The index of the simulation to optimise. This should be None if normal optimisation is desired. + @type sim_index: None or int + @keyword verbosity: The verbosity level. This is used by the result command returned to the master for printouts. + @type verbosity: int + @keyword verbosity_init: The verbosity flag for the target_fn_setup() call so that it only prints out the information once for the first subdivision. + @type verbosity_init: bool + """ + + # Store some arguments. + self.points = points + self.verbosity = verbosity + self.scaling_matrix = scaling_matrix + + # Alias some data to be sent to the slave. + self.model = cdp.model + self.num_int_pts = cdp.num_int_pts + + # Set up and store the data structures for the target function. + self.param_vector, self.full_tensors, self.full_in_ref_frame, self.rdcs, self.rdc_err, self.rdc_weight, self.rdc_vect, self.rdc_const, self.pcs, self.pcs_err, self.pcs_weight, self.atomic_pos, self.temp, self.frq, self.paramag_centre, self.com, self.ave_pos_pivot, self.pivot, self.pivot_opt = target_fn_setup(sim_index=sim_index, verbosity=verbosity_init) + + + def run(self, processor, completed): + """Set up and perform the optimisation.""" + + # Set up the optimisation target function class. + target_fn = Frame_order(model=self.model, init_params=self.param_vector, full_tensors=self.full_tensors, full_in_ref_frame=self.full_in_ref_frame, rdcs=self.rdcs, rdc_errors=self.rdc_err, rdc_weights=self.rdc_weight, rdc_vect=self.rdc_vect, dip_const=self.rdc_const, pcs=self.pcs, pcs_errors=self.pcs_err, pcs_weights=self.pcs_weight, atomic_pos=self.atomic_pos, temp=self.temp, frq=self.frq, paramag_centre=self.paramag_centre, scaling_matrix=self.scaling_matrix, com=self.com, ave_pos_pivot=self.ave_pos_pivot, pivot=self.pivot, pivot_opt=self.pivot_opt, num_int_pts=self.num_int_pts) + + # Grid search. + results = grid_point_array(func=target_fn.func, args=(), points=self.points, verbosity=self.verbosity) + + # Create the result command object on the slave to send back to the master. + processor.return_object(Frame_order_result_command(processor=processor, memo_id=self.memo_id, results=results, A_5D_bc=target_fn.A_5D_bc, pcs_theta=target_fn.pcs_theta, rdc_theta=target_fn.rdc_theta, completed=completed)) + + + class Frame_order_memo(Memo): """The frame order memo class.""" @@ -904,13 +951,8 @@ # Set up the optimisation target function class. target_fn = Frame_order(model=self.model, init_params=self.param_vector, full_tensors=self.full_tensors, full_in_ref_frame=self.full_in_ref_frame, rdcs=self.rdcs, rdc_errors=self.rdc_err, rdc_weights=self.rdc_weight, rdc_vect=self.rdc_vect, dip_const=self.rdc_const, pcs=self.pcs, pcs_errors=self.pcs_err, pcs_weights=self.pcs_weight, atomic_pos=self.atomic_pos, temp=self.temp, frq=self.frq, paramag_centre=self.paramag_centre, scaling_matrix=self.scaling_matrix, com=self.com, ave_pos_pivot=self.ave_pos_pivot, pivot=self.pivot, pivot_opt=self.pivot_opt, num_int_pts=self.num_int_pts) - # Grid search. - if search('^[Gg]rid', self.min_algor): - results = grid_point_array(func=target_fn.func, args=(), points=self.min_options, verbosity=self.verbosity) - # Minimisation. - else: - results = generic_minimise(func=target_fn.func, args=(), x0=self.param_vector, min_algor=self.min_algor, min_options=self.min_options, func_tol=self.func_tol, grad_tol=self.grad_tol, maxiter=self.max_iterations, A=self.A, b=self.b, full_output=True, print_flag=self.verbosity) + results = generic_minimise(func=target_fn.func, args=(), x0=self.param_vector, min_algor=self.min_algor, min_options=self.min_options, func_tol=self.func_tol, grad_tol=self.grad_tol, maxiter=self.max_iterations, A=self.A, b=self.b, full_output=True, print_flag=self.verbosity) # Create the result command object on the slave to send back to the master. processor.return_object(Frame_order_result_command(processor=processor, memo_id=self.memo_id, results=results, A_5D_bc=target_fn.A_5D_bc, pcs_theta=target_fn.pcs_theta, rdc_theta=target_fn.rdc_theta, completed=completed))