Exemple #1
0
    def minimise(self,
                 min_algor=None,
                 min_options=None,
                 func_tol=None,
                 grad_tol=None,
                 max_iterations=None,
                 constraints=False,
                 scaling_matrix=None,
                 verbosity=0,
                 sim_index=None,
                 lower=None,
                 upper=None,
                 inc=None):
        """Minimisation function.

        @param min_algor:           The minimisation algorithm to use.
        @type min_algor:            str
        @param min_options:         An array of options to be used by the minimisation algorithm.
        @type min_options:          array of str
        @param func_tol:            The function tolerance which, when reached, terminates optimisation.  Setting this to None turns of the check.
        @type func_tol:             None or float
        @param grad_tol:            The gradient tolerance which, when reached, terminates optimisation.  Setting this to None turns of the check.
        @type grad_tol:             None or float
        @param max_iterations:      The maximum number of iterations for the algorithm.
        @type max_iterations:       int
        @param constraints:         If True, constraints are used during optimisation.
        @type constraints:          bool
        @keyword scaling_matrix:    The per-model list of diagonal and square scaling matrices.
        @type scaling_matrix:       list of numpy rank-2, float64 array or list of None
        @param verbosity:           A flag specifying the amount of information to print.  The higher the value, the greater the verbosity.
        @type verbosity:            int
        @param 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 lower:             The per-model lower bounds of the grid search which must be equal to the number of parameters in the model.  This optional argument is only used when doing a grid search.
        @type lower:                list of lists of numbers
        @keyword upper:             The per-model upper bounds of the grid search which must be equal to the number of parameters in the model.  This optional argument is only used when doing a grid search.
        @type upper:                list of lists of numbers
        @keyword inc:               The per-model increments for each dimension of the space for the grid search.  The number of elements in the array must equal to the number of parameters in the model.  This argument is only used when doing a grid search.
        @type inc:                  list of lists of int
        """

        # Check the optimisation algorithm.
        algor = min_algor
        if min_algor == 'Log barrier':
            algor = min_options[0]
        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."
            )

        # Set up the data structures for the target function.
        param_vector, full_tensors, full_in_ref_frame, rdcs, rdc_err, rdc_weight, rdc_vect, rdc_const, pcs, pcs_err, pcs_weight, atomic_pos, temp, frq, paramag_centre, com, ave_pos_pivot, pivot, pivot_opt = target_fn_data_setup(
            sim_index=sim_index, verbosity=verbosity, unset_fail=True)

        # The numeric integration information.
        if not hasattr(cdp, 'quad_int'):
            cdp.quad_int = False
        sobol_max_points, sobol_oversample = None, None
        if hasattr(cdp, 'sobol_max_points'):
            sobol_max_points = cdp.sobol_max_points
            sobol_oversample = cdp.sobol_oversample

        # Get the Processor box singleton (it contains the Processor instance) and alias the Processor.
        processor_box = Processor_box()
        processor = processor_box.processor

        # Set up the memo for storage on the master.
        memo = Frame_order_memo(sim_index=sim_index,
                                scaling_matrix=scaling_matrix[0])

        # Set up the command object to send to the slave and execute.
        command = Frame_order_minimise_command(
            min_algor=min_algor,
            min_options=min_options,
            func_tol=func_tol,
            grad_tol=grad_tol,
            max_iterations=max_iterations,
            scaling_matrix=scaling_matrix[0],
            constraints=constraints,
            sim_index=sim_index,
            model=cdp.model,
            param_vector=param_vector,
            full_tensors=full_tensors,
            full_in_ref_frame=full_in_ref_frame,
            rdcs=rdcs,
            rdc_err=rdc_err,
            rdc_weight=rdc_weight,
            rdc_vect=rdc_vect,
            rdc_const=rdc_const,
            pcs=pcs,
            pcs_err=pcs_err,
            pcs_weight=pcs_weight,
            atomic_pos=atomic_pos,
            temp=temp,
            frq=frq,
            paramag_centre=paramag_centre,
            com=com,
            ave_pos_pivot=ave_pos_pivot,
            pivot=pivot,
            pivot_opt=pivot_opt,
            sobol_max_points=sobol_max_points,
            sobol_oversample=sobol_oversample,
            verbosity=verbosity,
            quad_int=cdp.quad_int)

        # Add the slave command and memo to the processor queue.
        processor.add_to_queue(command, memo)
Exemple #2
0
    def grid_search(self,
                    lower=None,
                    upper=None,
                    inc=None,
                    scaling_matrix=None,
                    constraints=False,
                    verbosity=0,
                    sim_index=None):
        """Perform a grid search.

        @keyword lower:             The per-model lower bounds of the grid search which must be equal to the number of parameters in the model.
        @type lower:                list of lists of numbers
        @keyword upper:             The per-model upper bounds of the grid search which must be equal to the number of parameters in the model.
        @type upper:                list of lists of numbers
        @keyword inc:               The per-model increments for each dimension of the space for the grid search. The number of elements in the array must equal to the number of parameters in the model.
        @type inc:                  list of lists of int
        @keyword scaling_matrix:    The per-model list of diagonal and square scaling matrices.
        @type scaling_matrix:       list of numpy rank-2, float64 array or list of None
        @keyword constraints:       If True, constraints are applied during the grid search (eliminating parts of the grid).  If False, no constraints are used.
        @type constraints:          bool
        @keyword verbosity:         A flag specifying the amount of information to print.  The higher the value, the greater the verbosity.
        @type verbosity:            int
        @keyword sim_index:         The Monte Carlo simulation index.
        @type sim_index:            None or int
        """

        # Test if the Frame Order model has been set up.
        if not hasattr(cdp, 'model'):
            raise RelaxNoModelError('Frame Order')

        # Test if the pivot has been set.
        check_pivot()

        # The number of parameters.
        n = param_num()

        # Alias the single model grid bounds and increments.
        lower = lower[0]
        upper = upper[0]
        inc = inc[0]

        # Initialise the grid increments structures.
        grid = []
        """This structure is a list of lists.  The first dimension corresponds to the model
        parameter.  The second dimension are the grid node positions."""

        # Generate the grid.
        for i in range(n):
            # Fixed parameter.
            if inc[i] == None:
                grid.append(None)
                continue

            # Reset.
            dist_type = None
            end_point = True

            # Arccos grid from 0 to pi.
            if cdp.params[i] in ['ave_pos_beta', 'eigen_beta', 'axis_theta']:
                # Change the default increment numbers.
                if not isinstance(inc, list):
                    inc[i] = int(inc[i] / 2) + 1

                # The distribution type and end point.
                dist_type = 'acos'
                end_point = False

            # Append the grid row.
            row = grid_row(inc[i],
                           lower[i],
                           upper[i],
                           dist_type=dist_type,
                           end_point=end_point)
            grid.append(row)

            # Remove an inc if the end point has been removed.
            if not end_point:
                inc[i] -= 1

        # Total number of points.
        total_pts = 1
        for i in range(n):
            # Fixed parameter.
            if grid[i] == None:
                continue

            total_pts = total_pts * len(grid[i])

        # Check the number.
        max_pts = 50e6
        if total_pts > max_pts:
            raise RelaxError(
                "The total number of grid points '%s' exceeds the maximum of '%s'."
                % (total_pts, int(max_pts)))

        # Build the points array.
        pts = zeros((total_pts, n), float64)
        indices = zeros(n, int)
        for i in range(total_pts):
            # Loop over the dimensions.
            for j in range(n):
                # Fixed parameter.
                if grid[j] == None:
                    # Get the current parameter value.
                    pts[i, j] = getattr(
                        cdp, cdp.params[j]) / scaling_matrix[0][j, j]

                # Add the point coordinate.
                else:
                    pts[i, j] = grid[j][indices[j]] / scaling_matrix[0][j, j]

            # Increment the step positions.
            for j in range(n):
                if inc[j] != None and indices[j] < inc[j] - 1:
                    indices[j] += 1
                    break  # Exit so that the other step numbers are not incremented.
                else:
                    indices[j] = 0

        # Linear constraints.
        A, b = None, None
        if constraints:
            # Obtain the constraints.
            A, b = linear_constraints(scaling_matrix=scaling_matrix[0])

            # Constraint flag set but no constraints present.
            if A is None:
                if verbosity:
                    warn(
                        RelaxWarning(
                            "The '%s' model parameters are not constrained, turning the linear constraint algorithm off."
                            % cdp.model))
                constraints = False

        # The numeric integration information.
        if not hasattr(cdp, 'quad_int'):
            cdp.quad_int = False
        sobol_max_points, sobol_oversample = None, None
        if hasattr(cdp, 'sobol_max_points'):
            sobol_max_points = cdp.sobol_max_points
            sobol_oversample = cdp.sobol_oversample

        # Set up the data structures for the target function.
        param_vector, full_tensors, full_in_ref_frame, rdcs, rdc_err, rdc_weight, rdc_vect, rdc_const, pcs, pcs_err, pcs_weight, atomic_pos, temp, frq, paramag_centre, com, ave_pos_pivot, pivot, pivot_opt = target_fn_data_setup(
            sim_index=sim_index, verbosity=verbosity)

        # Get the Processor box singleton (it contains the Processor instance) and alias the Processor.
        processor_box = Processor_box()
        processor = processor_box.processor

        # Set up for multi-processor execution.
        if processor.processor_size() > 1:
            # Printout.
            print("Parallelised grid search.")
            print(
                "Randomising the grid points to equalise the time required for each grid subdivision.\n"
            )

            # Randomise the points.
            shuffle(pts)

        # Loop over each grid subdivision, with all points violating constraints being eliminated.
        for subdivision in grid_split_array(
                divisions=processor.processor_size(),
                points=pts,
                A=A,
                b=b,
                verbosity=verbosity):
            # Set up the memo for storage on the master.
            memo = Frame_order_memo(sim_index=sim_index,
                                    scaling_matrix=scaling_matrix[0])

            # Set up the command object to send to the slave and execute.
            command = Frame_order_grid_command(
                points=subdivision,
                scaling_matrix=scaling_matrix[0],
                sim_index=sim_index,
                model=cdp.model,
                param_vector=param_vector,
                full_tensors=full_tensors,
                full_in_ref_frame=full_in_ref_frame,
                rdcs=rdcs,
                rdc_err=rdc_err,
                rdc_weight=rdc_weight,
                rdc_vect=rdc_vect,
                rdc_const=rdc_const,
                pcs=pcs,
                pcs_err=pcs_err,
                pcs_weight=pcs_weight,
                atomic_pos=atomic_pos,
                temp=temp,
                frq=frq,
                paramag_centre=paramag_centre,
                com=com,
                ave_pos_pivot=ave_pos_pivot,
                pivot=pivot,
                pivot_opt=pivot_opt,
                sobol_max_points=sobol_max_points,
                sobol_oversample=sobol_oversample,
                verbosity=verbosity,
                quad_int=cdp.quad_int)

            # Add the slave command and memo to the processor queue.
            processor.add_to_queue(command, memo)

        # Execute the queued elements.
        processor.run_queue()
Exemple #3
0
    def calculate(self,
                  spin_id=None,
                  scaling_matrix=None,
                  verbosity=1,
                  sim_index=None):
        """Calculate the chi-squared value for the current parameter values.

        @keyword spin_id:           The spin identification string (unused).
        @type spin_id:              None
        @keyword scaling_matrix:    The per-model list of diagonal and square scaling matrices.
        @type scaling_matrix:       list of numpy rank-2, float64 array or list of None
        @keyword verbosity:         The amount of information to print.  The higher the value, the greater the verbosity.
        @type verbosity:            int
        @keyword sim_index:         The optional MC simulation index (unused).
        @type sim_index:            None or int
        """

        # Set up the data structures for the target function.
        param_vector, full_tensors, full_in_ref_frame, rdcs, rdc_err, rdc_weight, rdc_vect, rdc_const, pcs, pcs_err, pcs_weight, atomic_pos, temp, frq, paramag_centre, com, ave_pos_pivot, pivot, pivot_opt = target_fn_data_setup(
            sim_index=sim_index, verbosity=verbosity, unset_fail=True)

        # The numeric integration information.
        if not hasattr(cdp, 'quad_int'):
            cdp.quad_int = False
        sobol_max_points, sobol_oversample = None, None
        if hasattr(cdp, 'sobol_max_points'):
            sobol_max_points = cdp.sobol_max_points
            sobol_oversample = cdp.sobol_oversample

        # Set up the optimisation target function class.
        target_fn = frame_order.Frame_order(
            model=cdp.model,
            init_params=param_vector,
            full_tensors=full_tensors,
            full_in_ref_frame=full_in_ref_frame,
            rdcs=rdcs,
            rdc_errors=rdc_err,
            rdc_weights=rdc_weight,
            rdc_vect=rdc_vect,
            dip_const=rdc_const,
            pcs=pcs,
            pcs_errors=pcs_err,
            pcs_weights=pcs_weight,
            atomic_pos=atomic_pos,
            temp=temp,
            frq=frq,
            paramag_centre=paramag_centre,
            com=com,
            ave_pos_pivot=ave_pos_pivot,
            pivot=pivot,
            pivot_opt=pivot_opt,
            sobol_max_points=sobol_max_points,
            sobol_oversample=sobol_oversample,
            quad_int=cdp.quad_int)

        # Make a single function call.  This will cause back calculation and the data will be stored in the class instance.
        chi2 = target_fn.func(param_vector)

        # Set the chi2.
        cdp.chi2 = chi2

        # Store the back-calculated data.
        store_bc_data(A_5D_bc=target_fn.A_5D_bc,
                      pcs_theta=target_fn.pcs_theta,
                      rdc_theta=target_fn.rdc_theta)

        # Feedback on the number of integration points used.
        if not cdp.quad_int:
            count_sobol_points(target_fn=target_fn, verbosity=verbosity)

        # Printout.
        if verbosity:
            print("Chi2:  %s" % chi2)
Exemple #4
0
    def minimise(self, min_algor=None, min_options=None, func_tol=None, grad_tol=None, max_iterations=None, constraints=False, scaling_matrix=None, verbosity=0, sim_index=None, lower=None, upper=None, inc=None):
        """Minimisation function.

        @param min_algor:           The minimisation algorithm to use.
        @type min_algor:            str
        @param min_options:         An array of options to be used by the minimisation algorithm.
        @type min_options:          array of str
        @param func_tol:            The function tolerance which, when reached, terminates optimisation.  Setting this to None turns of the check.
        @type func_tol:             None or float
        @param grad_tol:            The gradient tolerance which, when reached, terminates optimisation.  Setting this to None turns of the check.
        @type grad_tol:             None or float
        @param max_iterations:      The maximum number of iterations for the algorithm.
        @type max_iterations:       int
        @param constraints:         If True, constraints are used during optimisation.
        @type constraints:          bool
        @keyword scaling_matrix:    The per-model list of diagonal and square scaling matrices.
        @type scaling_matrix:       list of numpy rank-2, float64 array or list of None
        @param verbosity:           A flag specifying the amount of information to print.  The higher the value, the greater the verbosity.
        @type verbosity:            int
        @param 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 lower:             The per-model lower bounds of the grid search which must be equal to the number of parameters in the model.  This optional argument is only used when doing a grid search.
        @type lower:                list of lists of numbers
        @keyword upper:             The per-model upper bounds of the grid search which must be equal to the number of parameters in the model.  This optional argument is only used when doing a grid search.
        @type upper:                list of lists of numbers
        @keyword inc:               The per-model increments for each dimension of the space for the grid search.  The number of elements in the array must equal to the number of parameters in the model.  This argument is only used when doing a grid search.
        @type inc:                  list of lists of int
        """

        # Check the optimisation algorithm.
        algor = min_algor
        if min_algor == 'Log barrier':
            algor = min_options[0]
        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.")

        # Set up the data structures for the target function.
        param_vector, full_tensors, full_in_ref_frame, rdcs, rdc_err, rdc_weight, rdc_vect, rdc_const, pcs, pcs_err, pcs_weight, atomic_pos, temp, frq, paramag_centre, com, ave_pos_pivot, pivot, pivot_opt = target_fn_data_setup(sim_index=sim_index, verbosity=verbosity, unset_fail=True)

        # The numeric integration information.
        if not hasattr(cdp, 'quad_int'):
            cdp.quad_int = False
        sobol_max_points, sobol_oversample = None, None
        if hasattr(cdp, 'sobol_max_points'):
            sobol_max_points = cdp.sobol_max_points
            sobol_oversample = cdp.sobol_oversample

        # Get the Processor box singleton (it contains the Processor instance) and alias the Processor.
        processor_box = Processor_box() 
        processor = processor_box.processor

        # Set up the memo for storage on the master.
        memo = Frame_order_memo(sim_index=sim_index, scaling_matrix=scaling_matrix[0])

        # Set up the command object to send to the slave and execute.
        command = Frame_order_minimise_command(min_algor=min_algor, min_options=min_options, func_tol=func_tol, grad_tol=grad_tol, max_iterations=max_iterations, scaling_matrix=scaling_matrix[0], constraints=constraints, sim_index=sim_index, model=cdp.model, param_vector=param_vector, full_tensors=full_tensors, full_in_ref_frame=full_in_ref_frame, rdcs=rdcs, rdc_err=rdc_err, rdc_weight=rdc_weight, rdc_vect=rdc_vect, rdc_const=rdc_const, pcs=pcs, pcs_err=pcs_err, pcs_weight=pcs_weight, atomic_pos=atomic_pos, temp=temp, frq=frq, paramag_centre=paramag_centre, com=com, ave_pos_pivot=ave_pos_pivot, pivot=pivot, pivot_opt=pivot_opt, sobol_max_points=sobol_max_points, sobol_oversample=sobol_oversample, verbosity=verbosity, quad_int=cdp.quad_int)

        # Add the slave command and memo to the processor queue.
        processor.add_to_queue(command, memo)
Exemple #5
0
    def grid_search(self, lower=None, upper=None, inc=None, scaling_matrix=None, constraints=False, verbosity=0, sim_index=None):
        """Perform a grid search.

        @keyword lower:             The per-model lower bounds of the grid search which must be equal to the number of parameters in the model.
        @type lower:                list of lists of numbers
        @keyword upper:             The per-model upper bounds of the grid search which must be equal to the number of parameters in the model.
        @type upper:                list of lists of numbers
        @keyword inc:               The per-model increments for each dimension of the space for the grid search. The number of elements in the array must equal to the number of parameters in the model.
        @type inc:                  list of lists of int
        @keyword scaling_matrix:    The per-model list of diagonal and square scaling matrices.
        @type scaling_matrix:       list of numpy rank-2, float64 array or list of None
        @keyword constraints:       If True, constraints are applied during the grid search (eliminating parts of the grid).  If False, no constraints are used.
        @type constraints:          bool
        @keyword verbosity:         A flag specifying the amount of information to print.  The higher the value, the greater the verbosity.
        @type verbosity:            int
        @keyword sim_index:         The Monte Carlo simulation index.
        @type sim_index:            None or int
        """

        # Test if the Frame Order model has been set up.
        if not hasattr(cdp, 'model'):
            raise RelaxNoModelError('Frame Order')

        # Test if the pivot has been set.
        check_pivot()

        # The number of parameters.
        n = param_num()

        # Alias the single model grid bounds and increments.
        lower = lower[0]
        upper = upper[0]
        inc = inc[0]

        # Initialise the grid increments structures.
        grid = []
        """This structure is a list of lists.  The first dimension corresponds to the model
        parameter.  The second dimension are the grid node positions."""

        # Generate the grid.
        for i in range(n):
            # Fixed parameter.
            if inc[i] == None:
                grid.append(None)
                continue

            # Reset.
            dist_type = None
            end_point = True

            # Arccos grid from 0 to pi.
            if cdp.params[i] in ['ave_pos_beta', 'eigen_beta', 'axis_theta']:
                # Change the default increment numbers.
                if not isinstance(inc, list):
                    inc[i] = int(inc[i] / 2) + 1

                # The distribution type and end point.
                dist_type = 'acos'
                end_point = False

            # Append the grid row.
            row = grid_row(inc[i], lower[i], upper[i], dist_type=dist_type, end_point=end_point)
            grid.append(row)

            # Remove an inc if the end point has been removed.
            if not end_point:
                inc[i] -= 1

        # Total number of points.
        total_pts = 1
        for i in range(n):
            # Fixed parameter.
            if grid[i] == None:
                continue

            total_pts = total_pts * len(grid[i])

        # Check the number.
        max_pts = 50e6
        if total_pts > max_pts:
            raise RelaxError("The total number of grid points '%s' exceeds the maximum of '%s'." % (total_pts, int(max_pts)))

        # Build the points array.
        pts = zeros((total_pts, n), float64)
        indices = zeros(n, int)
        for i in range(total_pts):
            # Loop over the dimensions.
            for j in range(n):
                # Fixed parameter.
                if grid[j] == None:
                    # Get the current parameter value.
                    pts[i, j] = getattr(cdp, cdp.params[j]) / scaling_matrix[0][j, j]

                # Add the point coordinate.
                else:
                    pts[i, j] = grid[j][indices[j]] / scaling_matrix[0][j, j]

            # Increment the step positions.
            for j in range(n):
                if inc[j] != None and indices[j] < inc[j]-1:
                    indices[j] += 1
                    break    # Exit so that the other step numbers are not incremented.
                else:
                    indices[j] = 0

        # Linear constraints.
        A, b = None, None
        if constraints:
            # Obtain the constraints.
            A, b = linear_constraints(scaling_matrix=scaling_matrix[0])

            # Constraint flag set but no constraints present.
            if A is None:
                if verbosity:
                    warn(RelaxWarning("The '%s' model parameters are not constrained, turning the linear constraint algorithm off." % cdp.model))
                constraints = False

        # The numeric integration information.
        if not hasattr(cdp, 'quad_int'):
            cdp.quad_int = False
        sobol_max_points, sobol_oversample = None, None
        if hasattr(cdp, 'sobol_max_points'):
            sobol_max_points = cdp.sobol_max_points
            sobol_oversample = cdp.sobol_oversample

        # Set up the data structures for the target function.
        param_vector, full_tensors, full_in_ref_frame, rdcs, rdc_err, rdc_weight, rdc_vect, rdc_const, pcs, pcs_err, pcs_weight, atomic_pos, temp, frq, paramag_centre, com, ave_pos_pivot, pivot, pivot_opt = target_fn_data_setup(sim_index=sim_index, verbosity=verbosity)

        # Get the Processor box singleton (it contains the Processor instance) and alias the Processor.
        processor_box = Processor_box() 
        processor = processor_box.processor

        # Set up for multi-processor execution.
        if processor.processor_size() > 1:
            # Printout.
            print("Parallelised grid search.")
            print("Randomising the grid points to equalise the time required for each grid subdivision.\n")

            # Randomise the points.
            shuffle(pts)

        # Loop over each grid subdivision, with all points violating constraints being eliminated.
        for subdivision in grid_split_array(divisions=processor.processor_size(), points=pts, A=A, b=b, verbosity=verbosity):
            # Set up the memo for storage on the master.
            memo = Frame_order_memo(sim_index=sim_index, scaling_matrix=scaling_matrix[0])

            # Set up the command object to send to the slave and execute.
            command = Frame_order_grid_command(points=subdivision, scaling_matrix=scaling_matrix[0], sim_index=sim_index, model=cdp.model, param_vector=param_vector, full_tensors=full_tensors, full_in_ref_frame=full_in_ref_frame, rdcs=rdcs, rdc_err=rdc_err, rdc_weight=rdc_weight, rdc_vect=rdc_vect, rdc_const=rdc_const, pcs=pcs, pcs_err=pcs_err, pcs_weight=pcs_weight, atomic_pos=atomic_pos, temp=temp, frq=frq, paramag_centre=paramag_centre, com=com, ave_pos_pivot=ave_pos_pivot, pivot=pivot, pivot_opt=pivot_opt, sobol_max_points=sobol_max_points, sobol_oversample=sobol_oversample, verbosity=verbosity, quad_int=cdp.quad_int)

            # Add the slave command and memo to the processor queue.
            processor.add_to_queue(command, memo)

        # Execute the queued elements.
        processor.run_queue()
Exemple #6
0
    def calculate(self, spin_id=None, scaling_matrix=None, verbosity=1, sim_index=None):
        """Calculate the chi-squared value for the current parameter values.

        @keyword spin_id:           The spin identification string (unused).
        @type spin_id:              None
        @keyword scaling_matrix:    The per-model list of diagonal and square scaling matrices.
        @type scaling_matrix:       list of numpy rank-2, float64 array or list of None
        @keyword verbosity:         The amount of information to print.  The higher the value, the greater the verbosity.
        @type verbosity:            int
        @keyword sim_index:         The optional MC simulation index (unused).
        @type sim_index:            None or int
        """

        # Set up the data structures for the target function.
        param_vector, full_tensors, full_in_ref_frame, rdcs, rdc_err, rdc_weight, rdc_vect, rdc_const, pcs, pcs_err, pcs_weight, atomic_pos, temp, frq, paramag_centre, com, ave_pos_pivot, pivot, pivot_opt = target_fn_data_setup(sim_index=sim_index, verbosity=verbosity, unset_fail=True)

        # The numeric integration information.
        if not hasattr(cdp, 'quad_int'):
            cdp.quad_int = False
        sobol_max_points, sobol_oversample = None, None
        if hasattr(cdp, 'sobol_max_points'):
            sobol_max_points = cdp.sobol_max_points
            sobol_oversample = cdp.sobol_oversample

        # Set up the optimisation target function class.
        target_fn = frame_order.Frame_order(model=cdp.model, init_params=param_vector, full_tensors=full_tensors, full_in_ref_frame=full_in_ref_frame, rdcs=rdcs, rdc_errors=rdc_err, rdc_weights=rdc_weight, rdc_vect=rdc_vect, dip_const=rdc_const, pcs=pcs, pcs_errors=pcs_err, pcs_weights=pcs_weight, atomic_pos=atomic_pos, temp=temp, frq=frq, paramag_centre=paramag_centre, com=com, ave_pos_pivot=ave_pos_pivot, pivot=pivot, pivot_opt=pivot_opt, sobol_max_points=sobol_max_points, sobol_oversample=sobol_oversample, quad_int=cdp.quad_int)

        # Make a single function call.  This will cause back calculation and the data will be stored in the class instance.
        chi2 = target_fn.func(param_vector)

        # Set the chi2.
        cdp.chi2 = chi2

        # Store the back-calculated data.
        store_bc_data(A_5D_bc=target_fn.A_5D_bc, pcs_theta=target_fn.pcs_theta, rdc_theta=target_fn.rdc_theta)

        # Feedback on the number of integration points used.
        if not cdp.quad_int:
            count_sobol_points(target_fn=target_fn, verbosity=verbosity)

        # Printout.
        if verbosity:
            print("Chi2:  %s" % chi2)