Exemplo n.º 1
0
def param_num():
    """Determine the number of parameters in the model.

    @return:    The number of model parameters.
    @rtype:     int
    """

    # Determine the data type.
    data_types = base_data_types()

    # Init.
    num = 0

    # Alignment tensor params.
    if ('rdc' in data_types
            or 'pcs' in data_types) and not align_tensor.all_tensors_fixed():
        # Loop over the alignments.
        for i in range(len(cdp.align_tensors)):
            # Skip non-optimised tensors.
            if not opt_uses_tensor(cdp.align_tensors[i]):
                continue

            # Add 5 tensor parameters.
            num += 5

    # Populations.
    if cdp.model in ['2-domain', 'population']:
        num = num + (cdp.N - 1)

    # Euler angles.
    if cdp.model == '2-domain':
        num = num + 3 * cdp.N

    # The paramagnetic centre.
    if hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed:
        num = num + 3

    # Return the param number.
    return num
Exemplo n.º 2
0
def param_num():
    """Determine the number of parameters in the model.

    @return:    The number of model parameters.
    @rtype:     int
    """

    # Determine the data type.
    data_types = base_data_types()

    # Init.
    num = 0

    # Alignment tensor params.
    if ('rdc' in data_types or 'pcs' in data_types) and not align_tensor.all_tensors_fixed():
        # Loop over the alignments.
        for i in range(len(cdp.align_tensors)):
            # Skip non-optimised tensors.
            if not opt_uses_tensor(cdp.align_tensors[i]):
                continue

            # Add 5 tensor parameters.
            num += 5

    # Populations.
    if cdp.model in ['2-domain', 'population']:
        num = num + (cdp.N - 1)

    # Euler angles.
    if cdp.model == '2-domain':
        num = num + 3*cdp.N

    # The paramagnetic centre.
    if hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed:
        num = num + 3

     # Return the param number.
    return num
Exemplo n.º 3
0
def linear_constraints(data_types=None, scaling_matrix=None):
    """Function for setting up the linear constraint matrices A and b.

    Standard notation
    =================

    The N-state model constraints are::

        0 <= pc <= 1,

    where p is the probability and c corresponds to state c.


    Matrix notation
    ===============

    In the notation A.x >= b, where A is an matrix of coefficients, x is an array of parameter
    values, and b is a vector of scalars, these inequality constraints are::

        | 1  0  0 |                   |    0    |
        |         |                   |         |
        |-1  0  0 |                   |   -1    |
        |         |                   |         |
        | 0  1  0 |                   |    0    |
        |         |     |  p0  |      |         |
        | 0 -1  0 |     |      |      |   -1    |
        |         |  .  |  p1  |  >=  |         |
        | 0  0  1 |     |      |      |    0    |
        |         |     |  p2  |      |         |
        | 0  0 -1 |                   |   -1    |
        |         |                   |         |
        |-1 -1 -1 |                   |   -1    |
        |         |                   |         |
        | 1  1  1 |                   |    0    |

    This example is for a 4-state model, the last probability pn is not included as this
    parameter does not exist (because the sum of pc is equal to 1).  The Euler angle parameters
    have been excluded here but will be included in the returned A and b objects.  These
    parameters simply add columns of zero to the A matrix and have no effect on b.  The last two
    rows correspond to the inequality::

        0 <= pN <= 1.

    As::
                N-1
                \
        pN = 1 - >  pc,
                /__
                c=1

    then::

        -p1 - p2 - ... - p(N-1) >= -1,

         p1 + p2 + ... + p(N-1) >= 0.


    @keyword data_types:        The base data types used in the optimisation.  This list can
                                contain the elements 'rdc', 'pcs' or 'tensor'.
    @type data_types:           list of str
    @keyword scaling_matrix:    The diagonal scaling matrix.
    @type scaling_matrix:       numpy rank-2 square matrix
    @return:                    The matrices A and b.
    @rtype:                     tuple of len 2 of a numpy rank-2, size NxM matrix and numpy
                                rank-1, size N array
    """

    # Starting point of the populations.
    pop_start = 0
    if ('rdc' in data_types
            or 'pcs' in data_types) and not align_tensor.all_tensors_fixed():
        # Loop over the alignments.
        for i in range(len(cdp.align_tensors)):
            # Skip non-optimised tensors.
            if not opt_uses_tensor(cdp.align_tensors[i]):
                continue

            # Add 5 parameters.
            pop_start += 5

    # Initialisation (0..j..m).
    A = []
    b = []
    zero_array = zeros(param_num(), float64)
    i = pop_start
    j = 0

    # Probability parameters.
    if cdp.model in ['2-domain', 'population']:
        # Loop over the prob parameters (N - 1, because the sum of pc is 1).
        for k in range(cdp.N - 1):
            # 0 <= pc <= 1.
            A.append(zero_array * 0.0)
            A.append(zero_array * 0.0)
            A[j][i] = 1.0
            A[j + 1][i] = -1.0
            b.append(0.0)
            b.append(-1.0 / scaling_matrix[i, i])
            j = j + 2

            # Increment i.
            i = i + 1

        # Add the inequalities for pN.
        A.append(zero_array * 0.0)
        A.append(zero_array * 0.0)
        for i in range(pop_start, pop_start + cdp.N - 1):
            A[-2][i] = -1.0
            A[-1][i] = 1.0
        b.append(-1.0 / scaling_matrix[i, i])
        b.append(0.0)

    # Convert to numpy data structures.
    A = array(A, float64)
    b = array(b, float64)

    # Return the constraint objects.
    return A, b
Exemplo n.º 4
0
def disassemble_param_vector(param_vector=None,
                             data_types=None,
                             sim_index=None):
    """Disassemble the parameter vector and place the values into the relevant variables.

    For the 2-domain N-state model, the parameters are stored in the probability and Euler angle data structures.  For the population N-state model, only the probabilities are stored.  If RDCs are present and alignment tensors are optimised, then these are stored as well.

    @keyword data_types:    The base data types used in the optimisation.  This list can contain the elements 'rdc', 'pcs' or 'tensor'.
    @type data_types:       list of str
    @keyword param_vector:  The parameter vector returned from optimisation.
    @type param_vector:     numpy array
    @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
    """

    # Test if the model is selected.
    if not hasattr(cdp, 'model') or not isinstance(cdp.model, str):
        raise RelaxNoModelError

    # Unpack and strip off the alignment tensor parameters.
    if ('rdc' in data_types
            or 'pcs' in data_types) and not align_tensor.all_tensors_fixed():
        # Loop over the alignments, adding the alignment tensor parameters to the tensor data container.
        tensor_num = 0
        for i in range(len(cdp.align_tensors)):
            # Skip non-optimised tensors.
            if not opt_uses_tensor(cdp.align_tensors[i]):
                continue

            # Normal tensors.
            if sim_index == None:
                cdp.align_tensors[i].set(param='Axx',
                                         value=param_vector[5 * tensor_num])
                cdp.align_tensors[i].set(param='Ayy',
                                         value=param_vector[5 * tensor_num +
                                                            1])
                cdp.align_tensors[i].set(param='Axy',
                                         value=param_vector[5 * tensor_num +
                                                            2])
                cdp.align_tensors[i].set(param='Axz',
                                         value=param_vector[5 * tensor_num +
                                                            3])
                cdp.align_tensors[i].set(param='Ayz',
                                         value=param_vector[5 * tensor_num +
                                                            4])

            # Monte Carlo simulated tensors.
            else:
                cdp.align_tensors[i].set(param='Axx',
                                         value=param_vector[5 * tensor_num],
                                         category='sim',
                                         sim_index=sim_index)
                cdp.align_tensors[i].set(param='Ayy',
                                         value=param_vector[5 * tensor_num +
                                                            1],
                                         category='sim',
                                         sim_index=sim_index)
                cdp.align_tensors[i].set(param='Axy',
                                         value=param_vector[5 * tensor_num +
                                                            2],
                                         category='sim',
                                         sim_index=sim_index)
                cdp.align_tensors[i].set(param='Axz',
                                         value=param_vector[5 * tensor_num +
                                                            3],
                                         category='sim',
                                         sim_index=sim_index)
                cdp.align_tensors[i].set(param='Ayz',
                                         value=param_vector[5 * tensor_num +
                                                            4],
                                         category='sim',
                                         sim_index=sim_index)

            # Increase the tensor number.
            tensor_num += 1

        # Create a new parameter vector without the tensors.
        param_vector = param_vector[5 * tensor_num:]

    # Alias the Monte Carlo simulation data structures.
    if sim_index != None:
        # Populations.
        if cdp.model in ['2-domain', 'population']:
            probs = cdp.probs_sim[sim_index]

        # Euler angles.
        if cdp.model == '2-domain':
            alpha = cdp.alpha_sim[sim_index]
            beta = cdp.beta_sim[sim_index]
            gamma = cdp.gamma_sim[sim_index]

    # Alias the normal data structures.
    else:
        # Populations.
        if cdp.model in ['2-domain', 'population']:
            probs = cdp.probs

        # Euler angles.
        if cdp.model == '2-domain':
            alpha = cdp.alpha
            beta = cdp.beta
            gamma = cdp.gamma

    # Set the probabilities for states 0 to N-1 in the aliased structures.
    if cdp.model in ['2-domain', 'population']:
        for i in range(cdp.N - 1):
            probs[i] = param_vector[i]

        # The probability for state N.
        probs[-1] = 1 - sum(probs[0:-1])

    # Set the Euler angles in the aliased structures.
    if cdp.model == '2-domain':
        for i in range(cdp.N):
            alpha[i] = param_vector[cdp.N - 1 + 3 * i]
            beta[i] = param_vector[cdp.N - 1 + 3 * i + 1]
            gamma[i] = param_vector[cdp.N - 1 + 3 * i + 2]

    # The paramagnetic centre.
    if hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed:
        # Create the structure if needed.
        if not hasattr(cdp, 'paramagnetic_centre'):
            cdp.paramagnetic_centre = zeros(3, float64)

        # The position.
        if sim_index == None:
            cdp.paramagnetic_centre[0] = param_vector[-3]
            cdp.paramagnetic_centre[1] = param_vector[-2]
            cdp.paramagnetic_centre[2] = param_vector[-1]

        # Monte Carlo simulated positions.
        else:
            if cdp.paramagnetic_centre_sim[sim_index] is None:
                cdp.paramagnetic_centre_sim[sim_index] = [None, None, None]
            cdp.paramagnetic_centre_sim[sim_index][0] = param_vector[-3]
            cdp.paramagnetic_centre_sim[sim_index][1] = param_vector[-2]
            cdp.paramagnetic_centre_sim[sim_index][2] = param_vector[-1]
Exemplo n.º 5
0
def linear_constraints(data_types=None, scaling_matrix=None):
    """Function for setting up the linear constraint matrices A and b.

    Standard notation
    =================

    The N-state model constraints are::

        0 <= pc <= 1,

    where p is the probability and c corresponds to state c.


    Matrix notation
    ===============

    In the notation A.x >= b, where A is an matrix of coefficients, x is an array of parameter
    values, and b is a vector of scalars, these inequality constraints are::

        | 1  0  0 |                   |    0    |
        |         |                   |         |
        |-1  0  0 |                   |   -1    |
        |         |                   |         |
        | 0  1  0 |                   |    0    |
        |         |     |  p0  |      |         |
        | 0 -1  0 |     |      |      |   -1    |
        |         |  .  |  p1  |  >=  |         |
        | 0  0  1 |     |      |      |    0    |
        |         |     |  p2  |      |         |
        | 0  0 -1 |                   |   -1    |
        |         |                   |         |
        |-1 -1 -1 |                   |   -1    |
        |         |                   |         |
        | 1  1  1 |                   |    0    |

    This example is for a 4-state model, the last probability pn is not included as this
    parameter does not exist (because the sum of pc is equal to 1).  The Euler angle parameters
    have been excluded here but will be included in the returned A and b objects.  These
    parameters simply add columns of zero to the A matrix and have no effect on b.  The last two
    rows correspond to the inequality::

        0 <= pN <= 1.

    As::
                N-1
                \
        pN = 1 - >  pc,
                /__
                c=1

    then::

        -p1 - p2 - ... - p(N-1) >= -1,

         p1 + p2 + ... + p(N-1) >= 0.


    @keyword data_types:        The base data types used in the optimisation.  This list can
                                contain the elements 'rdc', 'pcs' or 'tensor'.
    @type data_types:           list of str
    @keyword scaling_matrix:    The diagonal scaling matrix.
    @type scaling_matrix:       numpy rank-2 square matrix
    @return:                    The matrices A and b.
    @rtype:                     tuple of len 2 of a numpy rank-2, size NxM matrix and numpy
                                rank-1, size N array
    """

    # Starting point of the populations.
    pop_start = 0
    if ('rdc' in data_types or 'pcs' in data_types) and not align_tensor.all_tensors_fixed():
        # Loop over the alignments.
        for i in range(len(cdp.align_tensors)):
            # Skip non-optimised tensors.
            if not opt_uses_tensor(cdp.align_tensors[i]):
                continue

            # Add 5 parameters.
            pop_start += 5

    # Initialisation (0..j..m).
    A = []
    b = []
    zero_array = zeros(param_num(), float64)
    i = pop_start
    j = 0

    # Probability parameters.
    if cdp.model in ['2-domain', 'population']:
        # Loop over the prob parameters (N - 1, because the sum of pc is 1).
        for k in range(cdp.N - 1):
            # 0 <= pc <= 1.
            A.append(zero_array * 0.0)
            A.append(zero_array * 0.0)
            A[j][i] = 1.0
            A[j+1][i] = -1.0
            b.append(0.0)
            b.append(-1.0 / scaling_matrix[i, i])
            j = j + 2

            # Increment i.
            i = i + 1

        # Add the inequalities for pN.
        A.append(zero_array * 0.0)
        A.append(zero_array * 0.0)
        for i in range(pop_start, pop_start+cdp.N-1):
            A[-2][i] = -1.0
            A[-1][i] = 1.0
        b.append(-1.0 / scaling_matrix[i, i])
        b.append(0.0)

    # Convert to numpy data structures.
    A = array(A, float64)
    b = array(b, float64)

    # Return the constraint objects.
    return A, b
Exemplo n.º 6
0
def disassemble_param_vector(param_vector=None, data_types=None, sim_index=None):
    """Disassemble the parameter vector and place the values into the relevant variables.

    For the 2-domain N-state model, the parameters are stored in the probability and Euler angle data structures.  For the population N-state model, only the probabilities are stored.  If RDCs are present and alignment tensors are optimised, then these are stored as well.

    @keyword data_types:    The base data types used in the optimisation.  This list can contain the elements 'rdc', 'pcs' or 'tensor'.
    @type data_types:       list of str
    @keyword param_vector:  The parameter vector returned from optimisation.
    @type param_vector:     numpy array
    @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
    """

    # Test if the model is selected.
    if not hasattr(cdp, 'model') or not isinstance(cdp.model, str):
        raise RelaxNoModelError

    # Unpack and strip off the alignment tensor parameters.
    if ('rdc' in data_types or 'pcs' in data_types) and not align_tensor.all_tensors_fixed():
        # Loop over the alignments, adding the alignment tensor parameters to the tensor data container.
        tensor_num = 0
        for i in range(len(cdp.align_tensors)):
            # Skip non-optimised tensors.
            if not opt_uses_tensor(cdp.align_tensors[i]):
                continue

            # Normal tensors.
            if sim_index == None:
                cdp.align_tensors[i].set(param='Axx', value=param_vector[5*tensor_num])
                cdp.align_tensors[i].set(param='Ayy', value=param_vector[5*tensor_num+1])
                cdp.align_tensors[i].set(param='Axy', value=param_vector[5*tensor_num+2])
                cdp.align_tensors[i].set(param='Axz', value=param_vector[5*tensor_num+3])
                cdp.align_tensors[i].set(param='Ayz', value=param_vector[5*tensor_num+4])

            # Monte Carlo simulated tensors.
            else:
                cdp.align_tensors[i].set(param='Axx', value=param_vector[5*tensor_num], category='sim', sim_index=sim_index)
                cdp.align_tensors[i].set(param='Ayy', value=param_vector[5*tensor_num+1], category='sim', sim_index=sim_index)
                cdp.align_tensors[i].set(param='Axy', value=param_vector[5*tensor_num+2], category='sim', sim_index=sim_index)
                cdp.align_tensors[i].set(param='Axz', value=param_vector[5*tensor_num+3], category='sim', sim_index=sim_index)
                cdp.align_tensors[i].set(param='Ayz', value=param_vector[5*tensor_num+4], category='sim', sim_index=sim_index)

            # Increase the tensor number.
            tensor_num += 1

        # Create a new parameter vector without the tensors.
        param_vector = param_vector[5*tensor_num:]

    # Alias the Monte Carlo simulation data structures.
    if sim_index != None:
        # Populations.
        if cdp.model in ['2-domain', 'population']:
            probs = cdp.probs_sim[sim_index]

        # Euler angles.
        if cdp.model == '2-domain':
            alpha = cdp.alpha_sim[sim_index]
            beta = cdp.beta_sim[sim_index]
            gamma = cdp.gamma_sim[sim_index]

    # Alias the normal data structures.
    else:
        # Populations.
        if cdp.model in ['2-domain', 'population']:
            probs = cdp.probs

        # Euler angles.
        if cdp.model == '2-domain':
            alpha = cdp.alpha
            beta = cdp.beta
            gamma = cdp.gamma

    # Set the probabilities for states 0 to N-1 in the aliased structures.
    if cdp.model in ['2-domain', 'population']:
        for i in range(cdp.N-1):
            probs[i] = param_vector[i]

        # The probability for state N.
        probs[-1] = 1 - sum(probs[0:-1])

    # Set the Euler angles in the aliased structures.
    if cdp.model == '2-domain':
        for i in range(cdp.N):
            alpha[i] = param_vector[cdp.N-1 + 3*i]
            beta[i] = param_vector[cdp.N-1 + 3*i + 1]
            gamma[i] = param_vector[cdp.N-1 + 3*i + 2]

    # The paramagnetic centre.
    if hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed:
        # Create the structure if needed.
        if not hasattr(cdp, 'paramagnetic_centre'):
            cdp.paramagnetic_centre = zeros(3, float64)

        # The position.
        if sim_index == None:
            cdp.paramagnetic_centre[0] = param_vector[-3]
            cdp.paramagnetic_centre[1] = param_vector[-2]
            cdp.paramagnetic_centre[2] = param_vector[-1]

        # Monte Carlo simulated positions.
        else:
            if cdp.paramagnetic_centre_sim[sim_index] == None:
                cdp.paramagnetic_centre_sim[sim_index] = [None, None, None]
            cdp.paramagnetic_centre_sim[sim_index][0] = param_vector[-3]
            cdp.paramagnetic_centre_sim[sim_index][1] = param_vector[-2]
            cdp.paramagnetic_centre_sim[sim_index][2] = param_vector[-1]
Exemplo n.º 7
0
    def grid_search(self, lower=None, upper=None, inc=None, scaling_matrix=None, constraints=False, verbosity=0, sim_index=None):
        """The grid search function.

        @param lower:           The lower bounds of the grid search which must be equal to the number of parameters in the model.
        @type lower:            list of lists of floats
        @param upper:           The upper bounds of the grid search which must be equal to the number of parameters in the model.
        @type upper:            list of lists of floats
        @param inc:             The 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
        @param constraints:     If True, constraints are applied during the grid search (elinating parts of the grid).  If False, no constraints are used.
        @type constraints:      bool
        @param verbosity:       A flag specifying the amount of information to print.  The higher the value, the greater the verbosity.
        @type verbosity:        int
        """

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

        # The number of parameters.
        n = param_num()

        # Determine the data type.
        data_types = base_data_types()

        # The number of tensors to optimise.
        tensor_num = align_tensor.num_tensors(skip_fixed=True)

        # Custom sub-grid search for when only tensors are optimised (as each tensor is independent, the number of points collapses from inc**(5*N) to N*inc**5).
        if cdp.model == 'fixed' and tensor_num > 1 and ('rdc' in data_types or 'pcs' in data_types) and not align_tensor.all_tensors_fixed() and hasattr(cdp, 'paramag_centre_fixed') and cdp.paramag_centre_fixed:
            # Print out.
            print("Optimising each alignment tensor separately.")

            # Store the alignment tensor fixed flags.
            fixed_flags = []
            for i in range(len(cdp.align_ids)):
                # Get the tensor object.
                tensor = align_tensor.return_tensor(index=i, skip_fixed=False)

                # Store the flag.
                fixed_flags.append(tensor.fixed)

                # Fix the tensor.
                tensor.set('fixed', True)

            # Loop over each sub-grid.
            for i in range(len(cdp.align_ids)):
                # Skip the tensor if originally fixed.
                if fixed_flags[i]:
                    continue

                # Get the tensor object.
                tensor = align_tensor.return_tensor(index=i, skip_fixed=False)

                # Unfix the current tensor.
                tensor.set('fixed', False)

                # Grid search parameter subsets.
                lower_sub = lower[0][i*5:i*5+5]
                upper_sub = upper[0][i*5:i*5+5]
                inc_sub = inc[0][i*5:i*5+5]

                # Minimisation of the sub-grid.
                self.minimise(min_algor='grid', lower=[lower_sub], upper=[upper_sub], inc=[inc_sub], scaling_matrix=[None], constraints=constraints, verbosity=verbosity, sim_index=sim_index)

                # Fix the tensor again.
                tensor.set('fixed', True)

            # Reset the state of the tensors.
            for i in range(len(cdp.align_ids)):
                # Get the tensor object.
                tensor = align_tensor.return_tensor(index=i, skip_fixed=False)

                # Fix the tensor.
                tensor.set('fixed', fixed_flags[i])

        # All other minimisation.
        else:
            self.minimise(min_algor='grid', lower=lower, upper=upper, inc=inc, scaling_matrix=scaling_matrix, constraints=constraints, verbosity=verbosity, sim_index=sim_index)
Exemplo n.º 8
0
Arquivo: api.py Projeto: tlinnet/relax
    def grid_search(self,
                    lower=None,
                    upper=None,
                    inc=None,
                    scaling_matrix=None,
                    constraints=False,
                    verbosity=0,
                    sim_index=None):
        """The grid search function.

        @param lower:           The lower bounds of the grid search which must be equal to the number of parameters in the model.
        @type lower:            list of lists of floats
        @param upper:           The upper bounds of the grid search which must be equal to the number of parameters in the model.
        @type upper:            list of lists of floats
        @param inc:             The 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
        @param constraints:     If True, constraints are applied during the grid search (elinating parts of the grid).  If False, no constraints are used.
        @type constraints:      bool
        @param verbosity:       A flag specifying the amount of information to print.  The higher the value, the greater the verbosity.
        @type verbosity:        int
        """

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

        # The number of parameters.
        n = param_num()

        # Determine the data type.
        data_types = base_data_types()

        # The number of tensors to optimise.
        tensor_num = align_tensor.num_tensors(skip_fixed=True)

        # Custom sub-grid search for when only tensors are optimised (as each tensor is independent, the number of points collapses from inc**(5*N) to N*inc**5).
        if cdp.model == 'fixed' and tensor_num > 1 and (
                'rdc' in data_types or 'pcs' in data_types
        ) and not align_tensor.all_tensors_fixed() and hasattr(
                cdp, 'paramag_centre_fixed') and cdp.paramag_centre_fixed:
            # Print out.
            print("Optimising each alignment tensor separately.")

            # Store the alignment tensor fixed flags.
            fixed_flags = []
            for i in range(len(cdp.align_ids)):
                # Get the tensor object.
                tensor = align_tensor.return_tensor(index=i, skip_fixed=False)

                # Store the flag.
                fixed_flags.append(tensor.fixed)

                # Fix the tensor.
                tensor.set('fixed', True)

            # Loop over each sub-grid.
            for i in range(len(cdp.align_ids)):
                # Skip the tensor if originally fixed.
                if fixed_flags[i]:
                    continue

                # Get the tensor object.
                tensor = align_tensor.return_tensor(index=i, skip_fixed=False)

                # Unfix the current tensor.
                tensor.set('fixed', False)

                # Grid search parameter subsets.
                lower_sub = lower[0][i * 5:i * 5 + 5]
                upper_sub = upper[0][i * 5:i * 5 + 5]
                inc_sub = inc[0][i * 5:i * 5 + 5]

                # Minimisation of the sub-grid.
                self.minimise(min_algor='grid',
                              lower=[lower_sub],
                              upper=[upper_sub],
                              inc=[inc_sub],
                              scaling_matrix=[None],
                              constraints=constraints,
                              verbosity=verbosity,
                              sim_index=sim_index)

                # Fix the tensor again.
                tensor.set('fixed', True)

            # Reset the state of the tensors.
            for i in range(len(cdp.align_ids)):
                # Get the tensor object.
                tensor = align_tensor.return_tensor(index=i, skip_fixed=False)

                # Fix the tensor.
                tensor.set('fixed', fixed_flags[i])

        # All other minimisation.
        else:
            self.minimise(min_algor='grid',
                          lower=lower,
                          upper=upper,
                          inc=inc,
                          scaling_matrix=scaling_matrix,
                          constraints=constraints,
                          verbosity=verbosity,
                          sim_index=sim_index)