Example #1
0
def _convert_to_string(data=None, justification=None, custom_format=None):
    """Convert all elements of the given data structures to strings in place.

    @keyword data:          The headings or content to convert.
    @type data:             list of lists
    @keyword justification: The structure to store the cell justification in.
    @type justification:    list of lists
    @keyword custom_format: This list allows a custom format to be specified for each column.  The number of elements must match the number of columns.  If an element is None, then the default will be used.  Otherwise the elements must be valid string formatting constructs.
    @type custom_format:    None or list of None and str
    """

    # Loop over the rows.
    for i in range(len(data)):
        # Loop over the columns.
        for j in range(len(data[i])):
            # Skip multi-columns.
            if data[i][j] == MULTI_COL:
                continue

            # Default left justification.
            justification[i][j] = 'l'

            # Right justify numbers.
            if not isinstance(data[i][j], bool) and (isinstance(
                    data[i][j], int) or is_float(data[i][j])):
                justification[i][j] = 'r'

            # None types.
            if data[i][j] == None:
                data[i][j] = ''

            # Custom format (defaulting to standard string conversion if all fails).
            elif custom_format and custom_format[j]:
                try:
                    data[i][j] = custom_format[j] % data[i][j]
                except TypeError:
                    data[i][j] = "%s" % data[i][j]

            # Bool types.
            elif isinstance(data[i][j], bool):
                data[i][j] = "%s" % data[i][j]

            # Int types.
            elif isinstance(data[i][j], int):
                data[i][j] = "%i" % data[i][j]

            # Float types.
            elif is_float(data[i][j]):
                data[i][j] = "%g" % data[i][j]

            # All other non-string types.
            elif not isinstance(data[i][j], str):
                data[i][j] = "%s" % data[i][j]
Example #2
0
def _convert_to_string(data=None, justification=None, custom_format=None):
    """Convert all elements of the given data structures to strings in place.

    @keyword data:          The headings or content to convert.
    @type data:             list of lists
    @keyword justification: The structure to store the cell justification in.
    @type justification:    list of lists
    @keyword custom_format: This list allows a custom format to be specified for each column.  The number of elements must match the number of columns.  If an element is None, then the default will be used.  Otherwise the elements must be valid string formatting constructs.
    @type custom_format:    None or list of None and str
    """

    # Loop over the rows.
    for i in range(len(data)):
        # Loop over the columns.
        for j in range(len(data[i])):
            # Skip multi-columns.
            if data[i][j] == MULTI_COL:
                continue

            # Default left justification.
            justification[i][j] = 'l'

            # Right justify numbers.
            if not isinstance(data[i][j], bool) and (isinstance(data[i][j], int) or is_float(data[i][j])):
                justification[i][j] = 'r'

            # None types.
            if data[i][j] == None:
                data[i][j] = ''

            # Custom format (defaulting to standard string conversion if all fails).
            elif custom_format and custom_format[j]:
                try:
                    data[i][j] = custom_format[j] % data[i][j]
                except TypeError:
                    data[i][j] = "%s" % data[i][j]

            # Bool types.
            elif isinstance(data[i][j], bool):
                data[i][j] = "%s" % data[i][j]

            # Int types.
            elif isinstance(data[i][j], int):
                data[i][j] = "%i" % data[i][j]

            # Float types.
            elif is_float(data[i][j]):
                data[i][j] = "%g" % data[i][j]

            # All other non-string types.
            elif not isinstance(data[i][j], str):
                data[i][j] = "%s" % data[i][j]
Example #3
0
    def _multi_system(self):
        """Convert the angle, pivot and axis data structures for handling multiple motional modes."""

        # The tilt angle.
        if is_float(self.TILT_ANGLE):
            self.TILT_ANGLE = [self.TILT_ANGLE]

        # The increment value.
        if is_float(self.INC):
            self.INC = [self.INC]

        # The pivot.
        if is_float(self.PIVOT[0]):
            self.PIVOT = [self.PIVOT]

        # The axis.
        if is_float(self.axes[0]):
            self.axes = [self.axes]
Example #4
0
    def _multi_system(self):
        """Convert the angle, pivot and axis data structures for handling multiple motional modes."""

        # The tilt angle.
        if is_float(self.TILT_ANGLE):
            self.TILT_ANGLE = [self.TILT_ANGLE]

        # The increment value.
        if is_float(self.INC):
            self.INC = [self.INC]

        # The pivot.
        if is_float(self.PIVOT[0]):
            self.PIVOT = [self.PIVOT]

        # The axis.
        if is_float(self.axes[0]):
            self.axes = [self.axes]
Example #5
0
def num_data_points():
    """Determine the number of data points used in the model.

    @return:    The number, n, of data points in the model.
    @rtype:     int
    """

    # Determine the data type.
    data_types = base_data_types()

    # Init.
    n = 0

    # Spin loop.
    for spin in spin_loop(skip_desel=True):
        # PCS data (skipping array elements set to None).
        if 'pcs' in data_types:
            if hasattr(spin, 'pcs'):
                for id in spin.pcs:
                    if is_float(spin.pcs[id]):
                        n += 1

    # Interatomic data loop.
    for interatom in interatomic_loop(skip_desel=True):
        # RDC data (skipping array elements set to None).
        if 'rdc' in data_types:
            if hasattr(interatom, 'rdc'):
                for id in interatom.rdc:
                    if is_float(interatom.rdc[id]):
                        n += 1

    # Alignment tensors.
    if 'tensor' in data_types:
        n += 5*len(cdp.align_tensors)

    # Return the value.
    return n
Example #6
0
def num_data_points():
    """Determine the number of data points used in the model.

    @return:    The number, n, of data points in the model.
    @rtype:     int
    """

    # Determine the data type.
    data_types = base_data_types()

    # Init.
    n = 0

    # Spin loop.
    for spin in spin_loop(skip_desel=True):
        # PCS data (skipping array elements set to None).
        if 'pcs' in data_types:
            if hasattr(spin, 'pcs'):
                for id in spin.pcs:
                    if is_float(spin.pcs[id]):
                        n += 1

    # Interatomic data loop.
    for interatom in interatomic_loop(skip_desel=True):
        # RDC data (skipping array elements set to None).
        if 'rdc' in data_types:
            if hasattr(interatom, 'rdc'):
                for id in interatom.rdc:
                    if is_float(interatom.rdc[id]):
                        n += 1

    # Alignment tensors.
    if 'tensor' in data_types:
        n += 5*len(cdp.align_tensors)

    # Return the value.
    return n
Example #7
0
    def setup_page(self, page=None, **kargs):
        """Allow a specified user function page to be remotely set up.

        @keyword page:  The page to setup.  This is the page index key.
        @type page:     str
        """

        # Get the page.
        page = self.get_page(self.page_indices[page])

        # Loop over the keyword arguments and set them.
        for arg in kargs:
            # The value.
            value = kargs[arg]
            if isinstance(value, str):
                value = str_to_gui(value)
            elif is_float(value):
                value = float_to_gui(value)

            # Set the argument.
            page.SetValue(arg, value)
Example #8
0
    def setup_page(self, page=None, **kargs):
        """Allow a specified user function page to be remotely set up.

        @keyword page:  The page to setup.  This is the page index key.
        @type page:     str
        """

        # Get the page.
        page = self.get_page(self.page_indices[page])

        # Loop over the keyword arguments and set them.
        for arg in kargs:
            # The value.
            value = kargs[arg]
            if isinstance(value, str):
                value = str_to_gui(value)
            elif is_float(value):
                value = float_to_gui(value)

            # Set the argument.
            page.SetValue(arg, value)
Example #9
0
def floatToBinaryString(obj):
    """Pack a python float into a binary string.

    This function assumes that the python type float it represents a 64bit double of 8 bytes. This
    function reverses the resulting string if the current architecture is big endian.

    @param obj:         A python float to pack.
    @type obj:          float
    @return:            A string of 8 bytes.
    @rtype:             str
    @raise TypeError:   If the input object isn't a python float.
    """

    if not is_float(obj):
        raise TypeError('the object recieved wasn\'t a float, type was: %s' % type(obj))

    # pack float into binary string
    packed =pack('d', obj)

    #change byte order to little endian by reversing string
    if sys.byteorder == 'big':
        packed = packed[::-1]

    return packed
Example #10
0
def floatToBinaryString(obj):
    """Pack a python float into a binary string.

    This function assumes that the python type float it represents a 64bit double of 8 bytes. This
    function reverses the resulting string if the current architecture is big endian.

    @param obj:         A python float to pack.
    @type obj:          float
    @return:            A string of 8 bytes.
    @rtype:             str
    @raise TypeError:   If the input object isn't a python float.
    """

    if not is_float(obj):
        raise TypeError('the object recieved wasn\'t a float, type was: %s' % type(obj))

    # pack float into binary string
    packed =pack('d', obj)

    #change byte order to little endian by reversing string
    if sys.byteorder == 'big':
        packed = packed[::-1]

    return packed
Example #11
0
def write_spin_data(file, dir=None, sep=None, spin_ids=None, mol_names=None, res_nums=None, res_names=None, spin_nums=None, spin_names=None, force=False, data=None, data_name=None, error=None, error_name=None, float_format="%20.15g"):
    """Generator function for reading the spin specific data from file.

    Description
    ===========

    This function writes a columnar formatted file where each line corresponds to a spin system.  Spin identification is either through a spin ID string or through columns containing the molecule name, residue name and number, and/or spin name and number.


    @param file:            The name of the file to write the data to (or alternatively an already opened file object).
    @type file:             str or file object
    @keyword dir:           The directory to place the file into (defaults to the current directory if None and the file argument is not a file object).
    @type dir:              str or None
    @keyword sep:           The column separator which, if None, defaults to whitespace.
    @type sep:              str or None
    @keyword spin_ids:      The list of spin ID strings.
    @type spin_ids:         None or list of str
    @keyword mol_names:     The list of molecule names.
    @type mol_names:        None or list of str
    @keyword res_nums:      The list of residue numbers.
    @type res_nums:         None or list of int
    @keyword res_names:     The list of residue names.
    @type res_names:        None or list of str
    @keyword spin_nums:     The list of spin numbers.
    @type spin_nums:        None or list of int
    @keyword spin_names:    The list of spin names.
    @type spin_names:       None or list of str
    @keyword force:         A flag which if True will cause an existing file to be overwritten.
    @type force:            bool
    @keyword data:          A list of the data to write out.  The first dimension corresponds to the spins.  A second dimension can also be given if multiple data sets across multiple columns are desired.
    @type data:             list or list of lists
    @keyword data_name:     A name corresponding to the data argument.  If the data argument is a list of lists, then this must also be a list with the same length as the second dimension of the data arg.
    @type data_name:        str or list of str
    @keyword error:         A list of the errors to write out.  The first dimension corresponds to the spins.  A second dimension can also be given if multiple data sets across multiple columns are desired.  These will be inter-dispersed between the data columns, if the data is given.  If the data arg is not None, then this must have the same dimensions as that object.
    @type error:            list or list of lists
    @keyword error_name:    A name corresponding to the error argument.  If the error argument is a list of lists, then this must also be a list with the same length at the second dimension of the error arg.
    @type error_name:       str or list of str
    @keyword float_format:  A float formatting string to use for the data and error whenever a float is found.
    @type float_format:     str
    """

    # Data argument tests.
    if data:
        # Data is a list of lists.
        if isinstance(data[0], list):
            # Data and data_name don't match.
            if not isinstance(data_name, list):
                raise RelaxError("The data_name arg '%s' must be a list as the data argument is a list of lists." % data_name)

            # Error doesn't match.
            if error and (len(data) != len(error) or len(data[0]) != len(error[0])):
                raise RelaxError("The data arg:\n%s\n\ndoes not have the same dimensions as the error arg:\n%s." % (data, error))

        # Data is a simple list.
        else:
            # Data and data_name don't match.
            if not isinstance(data_name, str):
                raise RelaxError("The data_name arg '%s' must be a string as the data argument is a simple list." % data_name)

            # Error doesn't match.
            if error and len(data) != len(error):
                raise RelaxError("The data arg:\n%s\n\ndoes not have the same dimensions as the error arg:\n%s." % (data, error))

    # Error argument tests.
    if error:
        # Error is a list of lists.
        if isinstance(error[0], list):
            # Error and error_name don't match.
            if not isinstance(error_name, list):
                raise RelaxError("The error_name arg '%s' must be a list as the error argument is a list of lists." % error_name)

        # Error is a simple list.
        else:
            # Error and error_name don't match.
            if not isinstance(error_name, str):
                raise RelaxError("The error_name arg '%s' must be a string as the error argument is a simple list." % error_name)

    # Number of spins check.
    args = [spin_ids, mol_names, res_nums, res_names, spin_nums, spin_names]
    arg_names = ['spin_ids', 'mol_names', 'res_nums', 'res_names', 'spin_nums', 'spin_names']
    N = None
    first_arg = None
    first_arg_name = None
    for i in range(len(args)):
        if isinstance(args[i], list):
            # First list match.
            if N == None:
                N = len(args[i])
                first_arg = args[i]
                first_arg_name = arg_names[i]

            # Length check.
            if len(args[i]) != N:
                raise RelaxError("The %s and %s arguments do not have the same number of spins ('%s' vs. '%s' respectively)." % (first_arg_name, arg_names[i], len(first_arg), len(args[i])))

    # Nothing?!?
    if N == None:
        raise RelaxError("No spin ID data is present.")

    # Data and error length check.
    if data and len(data) != N:
        raise RelaxError("The %s and data arguments do not have the same number of spins ('%s' vs. '%s' respectively)." % (first_arg_name, len(first_arg), len(data)))
    if error and len(error) != N:
        raise RelaxError("The %s and error arguments do not have the same number of spins ('%s' vs. '%s' respectively)." % (first_arg_name, len(first_arg), len(error)))

    # The spin arguments.
    args = [spin_ids, mol_names, res_nums, res_names, spin_nums, spin_names]
    arg_names = ['spin_id', 'mol_name', 'res_num', 'res_name', 'spin_num', 'spin_name']


    # Init.
    headings = []
    file_data = []

    # Headers - the spin ID info.
    for i in range(len(args)):
        if args[i]:
            headings.append(arg_names[i])

    # Headers - the data.
    if data:
        # List of lists.
        if isinstance(data[0], list):
            # Loop over the list.
            for i in range(len(data[0])):
                # The data.
                headings.append(data_name[i])

                # The error.
                if error:
                    headings.append(error_name[i])

        # Simple list.
        else:
            # The data.
            headings.append(data_name)

            # The error.
            if error:
                headings.append(error_name)

    # Headers - only errors.
    elif error:
        # List of lists.
        if isinstance(error[0], list):
            for i in range(len(error[0])):
                headings.append(error_name[i])

        # Simple list.
        else:
            headings.append(error_name)

    # No headings.
    if headings == []:
        headings = None

    # Spin specific data.
    for spin_index in range(N):
        # Append a new data row.
        file_data.append([])

        # The spin ID info.
        for i in range(len(args)):
            if args[i]:
                value = args[i][spin_index]
                if not isinstance(value, str):
                    value = repr(value)
                file_data[-1].append(value)

        # The data.
        if data:
            # List of lists.
            if isinstance(data[0], list):
                # Loop over the list.
                for i in range(len(data[0])):
                    # The data.
                    if is_float(data[spin_index][i]):
                        file_data[-1].append(float_format % data[spin_index][i])
                    else:
                        file_data[-1].append(repr(data[spin_index][i]))

                    # The error.
                    if error:
                        if is_float(error[spin_index][i]):
                            file_data[-1].append(float_format % error[spin_index][i])
                        else:
                            file_data[-1].append(repr(error[spin_index][i]))

            # Simple list.
            else:
                # The data.
                if is_float(data[spin_index]):
                    file_data[-1].append(float_format % data[spin_index])
                else:
                    file_data[-1].append(repr(data[spin_index]))

                # The error.
                if error:
                    if is_float(error[spin_index]):
                        file_data[-1].append(float_format % error[spin_index])
                    else:
                        file_data[-1].append(repr(error[spin_index]))

        # Only errors.
        elif error:
            # List of lists.
            if isinstance(error[0], list):
                for i in range(len(error[0])):
                    file_data[-1].append(repr(error[spin_index][i]))

            # Simple list.
            else:
                file_data[-1].append(repr(error[spin_index]))

    # No data to write, so do nothing!
    if file_data == [] or file_data == [[]]:
        return

    # Open the file for writing.
    file = open_write_file(file_name=file, dir=dir, force=force)

    # Write out the file data.
    write_data(out=file, headings=headings, data=file_data, sep=sep)
Example #12
0
def read(file=None, dir=None, file_data=None, spin_id1_col=None, spin_id2_col=None, data_col=None, error_col=None, sign_col=None, sep=None):
    """Read the J coupling data from file.

    @keyword file:          The name of the file to open.
    @type file:             str
    @keyword dir:           The directory containing the file (defaults to the current directory if None).
    @type dir:              str or None
    @keyword file_data:     An alternative to opening a file, if the data already exists in the correct format.  The format is a list of lists where the first index corresponds to the row and the second the column.
    @type file_data:        list of lists
    @keyword spin_id1_col:  The column containing the spin ID strings of the first spin.
    @type spin_id1_col:     int
    @keyword spin_id2_col:  The column containing the spin ID strings of the second spin.
    @type spin_id2_col:     int
    @keyword data_col:      The column containing the J coupling data in Hz.
    @type data_col:         int or None
    @keyword error_col:     The column containing the J coupling errors.
    @type error_col:        int or None
    @keyword sign_col:      The optional column containing the sign of the J coupling.
    @type sign_col:         int or None
    @keyword sep:           The column separator which, if None, defaults to whitespace.
    @type sep:              str or None
    """

    # Check the pipe setup.
    check_pipe_setup(sequence=True)

    # Either the data or error column must be supplied.
    if data_col == None and error_col == None:
        raise RelaxError("One of either the data or error column must be supplied.")

    # Extract the data from the file, and remove comments and blank lines.
    file_data = extract_data(file, dir, sep=sep)
    file_data = strip(file_data, comments=True)

    # Loop over the J coupling data.
    data = []
    for line in file_data:
        # Invalid columns.
        if spin_id1_col > len(line):
            warn(RelaxWarning("The data %s is invalid, no first spin ID column can be found." % line))
            continue
        if spin_id2_col > len(line):
            warn(RelaxWarning("The data %s is invalid, no second spin ID column can be found." % line))
            continue
        if data_col and data_col > len(line):
            warn(RelaxWarning("The data %s is invalid, no data column can be found." % line))
            continue
        if error_col and error_col > len(line):
            warn(RelaxWarning("The data %s is invalid, no error column can be found." % line))
            continue
        if sign_col and sign_col > len(line):
            warn(RelaxWarning("The data %s is invalid, no sign column can be found." % line))
            continue

        # Unpack.
        spin_id1 = line[spin_id1_col-1]
        spin_id2 = line[spin_id2_col-1]
        value = None
        if data_col:
            value = line[data_col-1]
        error = None
        if error_col:
            error = line[error_col-1]
        sign = None
        if sign_col:
            sign = line[sign_col-1]

        # Convert the spin IDs.
        if spin_id1[0] in ["\"", "\'"]:
            spin_id1 = eval(spin_id1)
        if spin_id2[0] in ["\"", "\'"]:
            spin_id2 = eval(spin_id2)

        # Convert and check the value.
        if value == 'None':
            value = None
        if value != None:
            try:
                value = float(value)
            except ValueError:
                warn(RelaxWarning("The J coupling value of the line %s is invalid." % line))
                continue

        # The sign data.
        if sign == 'None':
            sign = None
        if sign != None:
            try:
                sign = float(sign)
            except ValueError:
                warn(RelaxWarning("The J coupling sign of the line %s is invalid." % line))
                continue
            if sign not in [1.0, -1.0]:
                warn(RelaxWarning("The J coupling sign of the line %s is invalid." % line))
                continue

        # Convert and check the error.
        if error == 'None':
            error = None
        if error != None:
            try:
                error = float(error)
            except ValueError:
                warn(RelaxWarning("The error value of the line %s is invalid." % line))
                continue

        # Get the spins.
        spin1 = return_spin(spin_id=spin_id1)
        spin2 = return_spin(spin_id=spin_id2)

        # Check the spin IDs.
        if not spin1:
            warn(RelaxWarning("The spin ID '%s' cannot be found in the current data pipe, skipping the data %s." % (spin_id1, line)))
            continue
        if not spin2:
            warn(RelaxWarning("The spin ID '%s' cannot be found in the current data pipe, skipping the data %s." % (spin_id2, line)))
            continue

        # Test the error value (cannot be 0.0).
        if error == 0.0:
            raise RelaxError("An invalid error value of zero has been encountered.")

        # Get the interatomic data container.
        interatom = return_interatom(spin_hash1=spin1._hash, spin_hash2=spin2._hash)

        # Create the container if needed.
        if interatom == None:
            interatom = create_interatom(spin_id1=spin_id1, spin_id2=spin_id2)

        # Add the data.
        if data_col:
            # Sign conversion.
            if sign != None:
                value = value * sign

            # Add the value.
            interatom.j_coupling = value

        # Add the error.
        if error_col:
            interatom.j_coupling_err = error

        # Append the data for printout.
        data.append([spin_id1, spin_id2])
        if is_float(value):
            data[-1].append("%20.15f" % value)
        else:
            data[-1].append("%20s" % value)
        if is_float(error):
            data[-1].append("%20.15f" % error)
        else:
            data[-1].append("%20s" % error)

    # No data, so fail hard!
    if not len(data):
        raise RelaxError("No J coupling data could be extracted.")

    # Print out.
    print("The following J coupling have been loaded into the relax data store:\n")
    write_data(out=sys.stdout, headings=["Spin_ID1", "Spin_ID2", "Value", "Error"], data=data)
Example #13
0
def permute_axes(permutation='A'):
    """Permute the axes of the motional eigenframe to switch between local minima.

    @keyword permutation:   The permutation to use.  This can be either 'A' or 'B' to select between the 3 permutations, excluding the current combination.
    @type permutation:      str
    """

    # Check that the model is valid.
    allowed = MODEL_LIST_ISO_CONE + MODEL_LIST_PSEUDO_ELLIPSE
    if cdp.model not in allowed:
        raise RelaxError("The permutation of the motional eigenframe is only valid for the frame order models %s." % allowed)

    # Check that the model parameters are setup.
    if cdp.model in MODEL_LIST_ISO_CONE:
        if not hasattr(cdp, 'cone_theta') or not is_float(cdp.cone_theta):
            raise RelaxError("The parameter values are not set up.")
    else:
        if not hasattr(cdp, 'cone_theta_y') or not is_float(cdp.cone_theta_y):
            raise RelaxError("The parameter values are not set up.")

    # The iso cones only have one permutation.
    if cdp.model in MODEL_LIST_ISO_CONE and permutation == 'B':
        raise RelaxError("The isotropic cones only have one permutation.")

    # The angles.
    cone_sigma_max = 0.0
    if cdp.model in MODEL_LIST_RESTRICTED_TORSION:
        cone_sigma_max = cdp.cone_sigma_max
    elif cdp.model in MODEL_LIST_FREE_ROTORS:
        cone_sigma_max = pi
    if cdp.model in MODEL_LIST_ISO_CONE:
        angles = array([cdp.cone_theta, cdp.cone_theta, cone_sigma_max], float64)
    else:
        angles = array([cdp.cone_theta_x, cdp.cone_theta_y, cone_sigma_max], float64)
    x, y, z = angles

    # The axis system.
    axes = generate_axis_system()

    # Start printout for the isotropic cones.
    if cdp.model in MODEL_LIST_ISO_CONE:
        print("\nOriginal parameters:")
        print("%-20s %20.10f" % ("cone_theta", cdp.cone_theta))
        print("%-20s %20.10f" % ("cone_sigma_max", cone_sigma_max))
        print("%-20s %20.10f" % ("axis_theta", cdp.axis_theta))
        print("%-20s %20.10f" % ("axis_phi", cdp.axis_phi))
        print("%-20s\n%s" % ("cone axis", axes[:, 2]))
        print("%-20s\n%s" % ("full axis system", axes))
        print("\nPermutation '%s':" % permutation)

    # Start printout for the pseudo-ellipses.
    else:
        print("\nOriginal parameters:")
        print("%-20s %20.10f" % ("cone_theta_x", cdp.cone_theta_x))
        print("%-20s %20.10f" % ("cone_theta_y", cdp.cone_theta_y))
        print("%-20s %20.10f" % ("cone_sigma_max", cone_sigma_max))
        print("%-20s %20.10f" % ("eigen_alpha", cdp.eigen_alpha))
        print("%-20s %20.10f" % ("eigen_beta", cdp.eigen_beta))
        print("%-20s %20.10f" % ("eigen_gamma", cdp.eigen_gamma))
        print("%-20s\n%s" % ("eigenframe", axes))
        print("\nPermutation '%s':" % permutation)

    # The axis inversion structure.
    inv = ones(3, float64)

    # The starting condition x <= y <= z.
    if x <= y and y <= z:
        # Printout.
        print("%-20s %-20s" % ("Starting condition", "x <= y <= z"))

        # The cone angle and axes permutations.
        if permutation == 'A':
            perm_angles = [0, 2, 1]
            perm_axes   = [2, 1, 0]
            inv[perm_axes[2]] = -1.0
        else:
            perm_angles = [1, 2, 0]
            perm_axes   = [2, 0, 1]

    # The starting condition x <= z <= y.
    elif x <= z and z <= y:
        # Printout.
        print("%-20s %-20s" % ("Starting condition", "x <= z <= y"))

        # The cone angle and axes permutations.
        if permutation == 'A':
            perm_angles = [0, 2, 1]
            perm_axes   = [2, 1, 0]
            inv[perm_axes[2]] = -1.0
        else:
            perm_angles = [2, 1, 0]
            perm_axes   = [0, 2, 1]
            inv[perm_axes[2]] = -1.0

    # The starting condition z <= x <= y.
    elif z <= x  and x <= y:
        # Printout.
        print("%-20s %-20s" % ("Starting condition", "z <= x <= y"))

        # The cone angle and axes permutations.
        if permutation == 'A':
            perm_angles = [2, 0, 1]
            perm_axes   = [1, 2, 0]
        else:
            perm_angles = [2, 1, 0]
            perm_axes   = [0, 2, 1]
            inv[perm_axes[2]] = -1.0

    # Cannot be here.
    else:
        raise RelaxFault

    # Printout.
    print("%-20s %-20s" % ("Cone angle permutation", perm_angles))
    print("%-20s %-20s" % ("Axes permutation", perm_axes))

    # Permute the angles.
    if cdp.model in MODEL_LIST_ISO_CONE:
        cdp.cone_theta = (angles[perm_angles[0]] + angles[perm_angles[1]]) / 2.0
    else:
        cdp.cone_theta_x = angles[perm_angles[0]]
        cdp.cone_theta_y = angles[perm_angles[1]]
    if cdp.model in MODEL_LIST_RESTRICTED_TORSION:
        cdp.cone_sigma_max = angles[perm_angles[2]]
    elif cdp.model in MODEL_LIST_FREE_ROTORS:
        cdp.cone_sigma_max = pi

    # Permute the axes (iso cone).
    if cdp.model in MODEL_LIST_ISO_CONE:
        # Convert the y-axis to spherical coordinates (the x-axis would be ok too, or any vector in the x-y plane due to symmetry of the original permutation).
        axis_new = axes[:, 1]
        r, cdp.axis_theta, cdp.axis_phi = cartesian_to_spherical(axis_new)

    # Permute the axes (pseudo-ellipses).
    else:
        axes_new = transpose(array([inv[0]*axes[:, perm_axes[0]], inv[1]*axes[:, perm_axes[1]], inv[2]*axes[:, perm_axes[2]]], float64))

        # Convert the permuted frame to Euler angles and store them.
        cdp.eigen_alpha, cdp.eigen_beta, cdp.eigen_gamma = R_to_euler_zyz(axes_new)

    # End printout.
    if cdp.model in MODEL_LIST_ISO_CONE:
        print("\nPermuted parameters:")
        print("%-20s %20.10f" % ("cone_theta", cdp.cone_theta))
        if cdp.model == MODEL_ISO_CONE:
            print("%-20s %20.10f" % ("cone_sigma_max", cdp.cone_sigma_max))
        print("%-20s %20.10f" % ("axis_theta", cdp.axis_theta))
        print("%-20s %20.10f" % ("axis_phi", cdp.axis_phi))
        print("%-20s\n%s" % ("cone axis", axis_new))
    else:
        print("\nPermuted parameters:")
        print("%-20s %20.10f" % ("cone_theta_x", cdp.cone_theta_x))
        print("%-20s %20.10f" % ("cone_theta_y", cdp.cone_theta_y))
        if cdp.model == MODEL_PSEUDO_ELLIPSE:
            print("%-20s %20.10f" % ("cone_sigma_max", cdp.cone_sigma_max))
        print("%-20s %20.10f" % ("eigen_alpha", cdp.eigen_alpha))
        print("%-20s %20.10f" % ("eigen_beta", cdp.eigen_beta))
        print("%-20s %20.10f" % ("eigen_gamma", cdp.eigen_gamma))
        print("%-20s\n%s" % ("eigenframe", axes_new))
Example #14
0
def grid_search_setup(spins=None, spin_ids=None, param_vector=None, lower=None, upper=None, inc=None, scaling_matrix=None):
    """The grid search setup function.

    @keyword spins:             The list of spin data containers for the block.
    @type spins:                list of SpinContainer instances
    @keyword spin_ids:          The corresponding spin ID strings.
    @type spin_ids:             list of str
    @keyword param_vector:      The parameter vector.
    @type param_vector:         numpy array
    @keyword lower:             The 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:                array of numbers
    @keyword upper:             The 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:                array of numbers
    @keyword 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.  This argument is only used when doing a grid search.
    @type inc:                  array of int
    @keyword scaling_matrix:    The scaling matrix.
    @type scaling_matrix:       numpy diagonal matrix
    @return:                    A tuple of the grid size and the minimisation options.  For the minimisation options, the first dimension corresponds to the model parameter.  The second dimension is a list of the number of increments, the lower bound, and upper bound.
    @rtype:                     (int, list of lists [int, float, float])
    """

    # The length of the parameter array.
    n = len(param_vector)

    # Make sure that the length of the parameter array is > 0.
    if n == 0:
        raise RelaxError("Cannot run a grid search on a model with zero parameters.")

    # Lower bounds.
    if lower != None and len(lower) != n:
        raise RelaxLenError('lower bounds', n)

    # Upper bounds.
    if upper != None and len(upper) != n:
        raise RelaxLenError('upper bounds', n)

    # Increment.
    if isinstance(inc, list) and len(inc) != n:
        raise RelaxLenError('increment', n)
    elif isinstance(inc, int):
        inc = [inc]*n

    # Set up the default bounds.
    if not lower:
        # Init.
        lower = []
        upper = []

        # The R2eff model.
        if cdp.model_type == 'R2eff':
            # Loop over each experiment type, spectrometer frequency, offset and dispersion point.
            for exp_type, frq, offset, point in loop_exp_frq_offset_point():
                # Loop over the parameters.
                for param_name, param_index, si, r20_key in loop_parameters(spins=spins):
                    # R2eff relaxation rate (from 1 to 40 s^-1).
                    if param_name == 'r2eff':
                        lower.append(1.0)
                        upper.append(40.0)

                    # Intensity.
                    elif param_name == 'i0':
                        lower.append(0.0001)
                        upper.append(max(spins[si].intensities.values()))

        # All other models.
        else:
            # Loop over the parameters.
            for param_name, param_index, si, r20_key in loop_parameters(spins=spins):
                # Cluster specific parameter.
                if si == None:
                    si = 0

                # R2 relaxation rates (from 1 to 40 s^-1).
                if param_name in ['r2', 'r2a', 'r2b']:
                    lower.append(1.0)
                    upper.append(40.0)

                # The pA.pB.dw**2 and pA.dw**2 parameters.
                elif param_name in ['phi_ex', 'phi_ex_B', 'phi_ex_C', 'padw2']:
                    lower.append(0.0)
                    upper.append(10.0)

                # Chemical shift difference between states A and B (heteronucleus).
                elif param_name in ['dw', 'dw_AB', 'dw_AC', 'dw_BC']:
                    if spins[si].model in MODEL_LIST_MMQ:
                        lower.append(-10.0)
                    else:
                        lower.append(0.0)
                    upper.append(10.0)

                # Chemical shift difference between states A and B (proton).
                elif param_name in ['dwH', 'dwH_AB', 'dwH_AC', 'dwH_BC']:
                    if spins[si].model in MODEL_LIST_MMQ:
                        lower.append(-3.0)
                    else:
                        lower.append(0.0)
                    upper.append(3.0)

                # The population of state A.
                elif param_name == 'pA':
                    if spins[si].model == MODEL_M61B:
                        lower.append(0.85)
                    else:
                        lower.append(0.5)
                    upper.append(1.0)

                # The population of state B (for 3-site exchange).
                elif param_name == 'pB':
                    lower.append(0.0)
                    upper.append(0.5)

                # Exchange rates.
                elif param_name in ['kex', 'kex_AB', 'kex_AC', 'kex_BC', 'k_AB', 'kB', 'kC']:
                    lower.append(1.0)
                    upper.append(100000.0)

                # Time of exchange.
                elif param_name in ['tex']:
                    lower.append(1/100000.0)
                    upper.append(1.0)

    # Pre-set parameters.
    for param_name, param_index, si, r20_key in loop_parameters(spins=spins):
        # Cluster specific parameter.
        if si == None:
            si = 0

        # Get the parameter.
        if hasattr(spins[si], param_name):
            val = getattr(spins[si], param_name)

            # Value already set.
            if is_float(val) and val != 0.0:
                # Printout.
                print("The spin '%s' parameter '%s' is pre-set to %s, skipping it in the grid search." % (spin_ids[si], param_name, val))

                # Turn of the grid search for this parameter.
                inc[param_index] = 1
                lower[param_index] = val
                upper[param_index] = val

    # The full grid size.
    grid_size = 1
    for i in range(n):
        grid_size *= inc[i]

    # Diagonal scaling of minimisation options.
    lower_new = []
    upper_new = []
    for i in range(n):
        lower_new.append(lower[i] / scaling_matrix[i, i])
        upper_new.append(upper[i] / scaling_matrix[i, i])

    # Return the data structures.
    return grid_size, inc, lower_new, upper_new
Example #15
0
def read(file=None, dir=None, file_data=None, spin_id1_col=None, spin_id2_col=None, data_col=None, error_col=None, sign_col=None, sep=None):
    """Read the J coupling data from file.

    @keyword file:          The name of the file to open.
    @type file:             str
    @keyword dir:           The directory containing the file (defaults to the current directory if None).
    @type dir:              str or None
    @keyword file_data:     An alternative to opening a file, if the data already exists in the correct format.  The format is a list of lists where the first index corresponds to the row and the second the column.
    @type file_data:        list of lists
    @keyword spin_id1_col:  The column containing the spin ID strings of the first spin.
    @type spin_id1_col:     int
    @keyword spin_id2_col:  The column containing the spin ID strings of the second spin.
    @type spin_id2_col:     int
    @keyword data_col:      The column containing the J coupling data in Hz.
    @type data_col:         int or None
    @keyword error_col:     The column containing the J coupling errors.
    @type error_col:        int or None
    @keyword sign_col:      The optional column containing the sign of the J coupling.
    @type sign_col:         int or None
    @keyword sep:           The column separator which, if None, defaults to whitespace.
    @type sep:              str or None
    """

    # Check the pipe setup.
    check_pipe_setup(sequence=True)

    # Either the data or error column must be supplied.
    if data_col == None and error_col == None:
        raise RelaxError("One of either the data or error column must be supplied.")

    # Extract the data from the file, and remove comments and blank lines.
    file_data = extract_data(file, dir, sep=sep)
    file_data = strip(file_data, comments=True)

    # Loop over the J coupling data.
    data = []
    for line in file_data:
        # Invalid columns.
        if spin_id1_col > len(line):
            warn(RelaxWarning("The data %s is invalid, no first spin ID column can be found." % line))
            continue
        if spin_id2_col > len(line):
            warn(RelaxWarning("The data %s is invalid, no second spin ID column can be found." % line))
            continue
        if data_col and data_col > len(line):
            warn(RelaxWarning("The data %s is invalid, no data column can be found." % line))
            continue
        if error_col and error_col > len(line):
            warn(RelaxWarning("The data %s is invalid, no error column can be found." % line))
            continue
        if sign_col and sign_col > len(line):
            warn(RelaxWarning("The data %s is invalid, no sign column can be found." % line))
            continue

        # Unpack.
        spin_id1 = line[spin_id1_col-1]
        spin_id2 = line[spin_id2_col-1]
        value = None
        if data_col:
            value = line[data_col-1]
        error = None
        if error_col:
            error = line[error_col-1]
        sign = None
        if sign_col:
            sign = line[sign_col-1]

        # Convert the spin IDs.
        if spin_id1[0] in ["\"", "\'"]:
            spin_id1 = eval(spin_id1)
        if spin_id2[0] in ["\"", "\'"]:
            spin_id2 = eval(spin_id2)

        # Convert and check the value.
        if value == 'None':
            value = None
        if value != None:
            try:
                value = float(value)
            except ValueError:
                warn(RelaxWarning("The J coupling value of the line %s is invalid." % line))
                continue

        # The sign data.
        if sign == 'None':
            sign = None
        if sign != None:
            try:
                sign = float(sign)
            except ValueError:
                warn(RelaxWarning("The J coupling sign of the line %s is invalid." % line))
                continue
            if sign not in [1.0, -1.0]:
                warn(RelaxWarning("The J coupling sign of the line %s is invalid." % line))
                continue

        # Convert and check the error.
        if error == 'None':
            error = None
        if error != None:
            try:
                error = float(error)
            except ValueError:
                warn(RelaxWarning("The error value of the line %s is invalid." % line))
                continue

        # Get the spins.
        spin1 = return_spin(spin_id1)
        spin2 = return_spin(spin_id2)

        # Check the spin IDs.
        if not spin1:
            warn(RelaxWarning("The spin ID '%s' cannot be found in the current data pipe, skipping the data %s." % (spin_id1, line)))
            continue
        if not spin2:
            warn(RelaxWarning("The spin ID '%s' cannot be found in the current data pipe, skipping the data %s." % (spin_id2, line)))
            continue

        # Test the error value (cannot be 0.0).
        if error == 0.0:
            raise RelaxError("An invalid error value of zero has been encountered.")

        # Get the interatomic data container.
        interatom = return_interatom(spin_id1, spin_id2)

        # Create the container if needed.
        if interatom == None:
            interatom = create_interatom(spin_id1=spin_id1, spin_id2=spin_id2)

        # Add the data.
        if data_col:
            # Sign conversion.
            if sign != None:
                value = value * sign

            # Add the value.
            interatom.j_coupling = value

        # Add the error.
        if error_col:
            interatom.j_coupling_err = error

        # Append the data for printout.
        data.append([spin_id1, spin_id2])
        if is_float(value):
            data[-1].append("%20.15f" % value)
        else:
            data[-1].append("%20s" % value)
        if is_float(error):
            data[-1].append("%20.15f" % error)
        else:
            data[-1].append("%20s" % error)

    # No data, so fail hard!
    if not len(data):
        raise RelaxError("No J coupling data could be extracted.")

    # Print out.
    print("The following J coupling have been loaded into the relax data store:\n")
    write_data(out=sys.stdout, headings=["Spin_ID1", "Spin_ID2", "Value", "Error"], data=data)
Example #16
0
def copy(pipe_from=None, pipe_to=None, align_id=None, back_calc=True):
    """Copy the PCS data from one data pipe to another.

    @keyword pipe_from: The data pipe to copy the PCS data from.  This defaults to the current data pipe.
    @type pipe_from:    str
    @keyword pipe_to:   The data pipe to copy the PCS data to.  This defaults to the current data pipe.
    @type pipe_to:      str
    @keyword align_id:  The alignment ID string.
    @type align_id:     str
    @keyword back_calc: A flag which if True will cause any back-calculated RDCs present to also be copied with the real values and errors.
    @type back_calc:    bool
    """

    # Defaults.
    if pipe_from == None and pipe_to == None:
        raise RelaxError("The pipe_from and pipe_to arguments cannot both be set to None.")
    elif pipe_from == None:
        pipe_from = pipes.cdp_name()
    elif pipe_to == None:
        pipe_to = pipes.cdp_name()

    # Check the pipe setup.
    check_pipe_setup(pipe=pipe_from, pcs_id=align_id, sequence=True, pcs=True)
    check_pipe_setup(pipe=pipe_to, sequence=True)

    # Get the data pipes.
    dp_from = pipes.get_pipe(pipe_from)
    dp_to = pipes.get_pipe(pipe_to)

    # The IDs.
    if align_id == None:
        align_ids = dp_from.align_ids
    else:
        align_ids = [align_id]

    # Init target pipe global structures.
    if not hasattr(dp_to, 'align_ids'):
        dp_to.align_ids = []
    if not hasattr(dp_to, 'pcs_ids'):
        dp_to.pcs_ids = []

    # Loop over the align IDs.
    for align_id in align_ids:
        # Printout.
        print("\nCoping PCSs for the alignment ID '%s'." % align_id)

        # Copy the global data.
        if align_id not in dp_to.align_ids and align_id not in dp_to.align_ids:
            dp_to.align_ids.append(align_id)
        if align_id in dp_from.pcs_ids and align_id not in dp_to.pcs_ids:
            dp_to.pcs_ids.append(align_id)

        # Spin loop.
        data = []
        for spin_from, spin_id in spin_loop(return_id=True, skip_desel=True, pipe=pipe_from):
            # Find the matching spin container in the target data pipe.
            spin_to = return_spin(spin_id, pipe=pipe_to)

            # No matching spin container.
            if spin_to == None:
                warn(RelaxWarning("The spin container for the spin '%s' cannot be found in the target data pipe." % spin_id))
                continue

            # No data or errors.
            if (not hasattr(spin_from, 'pcs') or not align_id in spin_from.pcs) and (not hasattr(spin_from, 'pcs_err') or not align_id in spin_from.pcs_err):
                continue

            # Initialise the spin data if necessary.
            if hasattr(spin_from, 'pcs') and not hasattr(spin_to, 'pcs'):
                spin_to.pcs = {}
            if back_calc and hasattr(spin_from, 'pcs_bc') and not hasattr(spin_to, 'pcs_bc'):
                spin_to.pcs_bc = {}
            if hasattr(spin_from, 'pcs_err') and not hasattr(spin_to, 'pcs_err'):
                spin_to.pcs_err = {}

            # Copy the value and error from pipe_from.
            value = None
            error = None
            value_bc = None
            if hasattr(spin_from, 'pcs'):
                value = spin_from.pcs[align_id]
                spin_to.pcs[align_id] = value
            if back_calc and hasattr(spin_from, 'pcs_bc'):
                value_bc = spin_from.pcs_bc[align_id]
                spin_to.pcs_bc[align_id] = value_bc
            if hasattr(spin_from, 'pcs_err'):
                error = spin_from.pcs_err[align_id]
                spin_to.pcs_err[align_id] = error

            # Append the data for printout.
            data.append([spin_id])
            if is_float(value):
                data[-1].append("%20.15f" % value)
            else:
                data[-1].append("%20s" % value)
            if back_calc:
                if is_float(value_bc):
                    data[-1].append("%20.15f" % value_bc)
                else:
                    data[-1].append("%20s" % value_bc)
            if is_float(error):
                data[-1].append("%20.15f" % error)
            else:
                data[-1].append("%20s" % error)

        # Printout.
        print("The following PCSs have been copied:\n")
        if back_calc:
            write_data(out=sys.stdout, headings=["Spin_ID", "Value", "Back-calculated", "Error"], data=data)
        else:
            write_data(out=sys.stdout, headings=["Spin_ID", "Value", "Error"], data=data)
Example #17
0
def permute_axes(permutation='A'):
    """Permute the axes of the motional eigenframe to switch between local minima.

    @keyword permutation:   The permutation to use.  This can be either 'A' or 'B' to select between the 3 permutations, excluding the current combination.
    @type permutation:      str
    """

    # Check that the model is valid.
    allowed = MODEL_LIST_ISO_CONE + MODEL_LIST_PSEUDO_ELLIPSE
    if cdp.model not in allowed:
        raise RelaxError(
            "The permutation of the motional eigenframe is only valid for the frame order models %s."
            % allowed)

    # Check that the model parameters are setup.
    if cdp.model in MODEL_LIST_ISO_CONE:
        if not hasattr(cdp, 'cone_theta') or not is_float(cdp.cone_theta):
            raise RelaxError("The parameter values are not set up.")
    else:
        if not hasattr(cdp, 'cone_theta_y') or not is_float(cdp.cone_theta_y):
            raise RelaxError("The parameter values are not set up.")

    # The iso cones only have one permutation.
    if cdp.model in MODEL_LIST_ISO_CONE and permutation == 'B':
        raise RelaxError("The isotropic cones only have one permutation.")

    # The angles.
    cone_sigma_max = 0.0
    if cdp.model in MODEL_LIST_RESTRICTED_TORSION:
        cone_sigma_max = cdp.cone_sigma_max
    elif cdp.model in MODEL_LIST_FREE_ROTORS:
        cone_sigma_max = pi
    if cdp.model in MODEL_LIST_ISO_CONE:
        angles = array([cdp.cone_theta, cdp.cone_theta, cone_sigma_max],
                       float64)
    else:
        angles = array([cdp.cone_theta_x, cdp.cone_theta_y, cone_sigma_max],
                       float64)
    x, y, z = angles

    # The axis system.
    axes = generate_axis_system()

    # Start printout for the isotropic cones.
    if cdp.model in MODEL_LIST_ISO_CONE:
        print("\nOriginal parameters:")
        print("%-20s %20.10f" % ("cone_theta", cdp.cone_theta))
        print("%-20s %20.10f" % ("cone_sigma_max", cone_sigma_max))
        print("%-20s %20.10f" % ("axis_theta", cdp.axis_theta))
        print("%-20s %20.10f" % ("axis_phi", cdp.axis_phi))
        print("%-20s\n%s" % ("cone axis", axes[:, 2]))
        print("%-20s\n%s" % ("full axis system", axes))
        print("\nPermutation '%s':" % permutation)

    # Start printout for the pseudo-ellipses.
    else:
        print("\nOriginal parameters:")
        print("%-20s %20.10f" % ("cone_theta_x", cdp.cone_theta_x))
        print("%-20s %20.10f" % ("cone_theta_y", cdp.cone_theta_y))
        print("%-20s %20.10f" % ("cone_sigma_max", cone_sigma_max))
        print("%-20s %20.10f" % ("eigen_alpha", cdp.eigen_alpha))
        print("%-20s %20.10f" % ("eigen_beta", cdp.eigen_beta))
        print("%-20s %20.10f" % ("eigen_gamma", cdp.eigen_gamma))
        print("%-20s\n%s" % ("eigenframe", axes))
        print("\nPermutation '%s':" % permutation)

    # The axis inversion structure.
    inv = ones(3, float64)

    # The starting condition x <= y <= z.
    if x <= y and y <= z:
        # Printout.
        print("%-20s %-20s" % ("Starting condition", "x <= y <= z"))

        # The cone angle and axes permutations.
        if permutation == 'A':
            perm_angles = [0, 2, 1]
            perm_axes = [2, 1, 0]
            inv[perm_axes[2]] = -1.0
        else:
            perm_angles = [1, 2, 0]
            perm_axes = [2, 0, 1]

    # The starting condition x <= z <= y.
    elif x <= z and z <= y:
        # Printout.
        print("%-20s %-20s" % ("Starting condition", "x <= z <= y"))

        # The cone angle and axes permutations.
        if permutation == 'A':
            perm_angles = [0, 2, 1]
            perm_axes = [2, 1, 0]
            inv[perm_axes[2]] = -1.0
        else:
            perm_angles = [2, 1, 0]
            perm_axes = [0, 2, 1]
            inv[perm_axes[2]] = -1.0

    # The starting condition z <= x <= y.
    elif z <= x and x <= y:
        # Printout.
        print("%-20s %-20s" % ("Starting condition", "z <= x <= y"))

        # The cone angle and axes permutations.
        if permutation == 'A':
            perm_angles = [2, 0, 1]
            perm_axes = [1, 2, 0]
        else:
            perm_angles = [2, 1, 0]
            perm_axes = [0, 2, 1]
            inv[perm_axes[2]] = -1.0

    # Cannot be here.
    else:
        raise RelaxFault

    # Printout.
    print("%-20s %-20s" % ("Cone angle permutation", perm_angles))
    print("%-20s %-20s" % ("Axes permutation", perm_axes))

    # Permute the angles.
    if cdp.model in MODEL_LIST_ISO_CONE:
        cdp.cone_theta = (angles[perm_angles[0]] +
                          angles[perm_angles[1]]) / 2.0
    else:
        cdp.cone_theta_x = angles[perm_angles[0]]
        cdp.cone_theta_y = angles[perm_angles[1]]
    if cdp.model in MODEL_LIST_RESTRICTED_TORSION:
        cdp.cone_sigma_max = angles[perm_angles[2]]
    elif cdp.model in MODEL_LIST_FREE_ROTORS:
        cdp.cone_sigma_max = pi

    # Permute the axes (iso cone).
    if cdp.model in MODEL_LIST_ISO_CONE:
        # Convert the y-axis to spherical coordinates (the x-axis would be ok too, or any vector in the x-y plane due to symmetry of the original permutation).
        axis_new = axes[:, 1]
        r, cdp.axis_theta, cdp.axis_phi = cartesian_to_spherical(axis_new)

    # Permute the axes (pseudo-ellipses).
    else:
        axes_new = transpose(
            array([
                inv[0] * axes[:, perm_axes[0]], inv[1] * axes[:, perm_axes[1]],
                inv[2] * axes[:, perm_axes[2]]
            ], float64))

        # Convert the permuted frame to Euler angles and store them.
        cdp.eigen_alpha, cdp.eigen_beta, cdp.eigen_gamma = R_to_euler_zyz(
            axes_new)

    # End printout.
    if cdp.model in MODEL_LIST_ISO_CONE:
        print("\nPermuted parameters:")
        print("%-20s %20.10f" % ("cone_theta", cdp.cone_theta))
        if cdp.model == MODEL_ISO_CONE:
            print("%-20s %20.10f" % ("cone_sigma_max", cdp.cone_sigma_max))
        print("%-20s %20.10f" % ("axis_theta", cdp.axis_theta))
        print("%-20s %20.10f" % ("axis_phi", cdp.axis_phi))
        print("%-20s\n%s" % ("cone axis", axis_new))
    else:
        print("\nPermuted parameters:")
        print("%-20s %20.10f" % ("cone_theta_x", cdp.cone_theta_x))
        print("%-20s %20.10f" % ("cone_theta_y", cdp.cone_theta_y))
        if cdp.model == MODEL_PSEUDO_ELLIPSE:
            print("%-20s %20.10f" % ("cone_sigma_max", cdp.cone_sigma_max))
        print("%-20s %20.10f" % ("eigen_alpha", cdp.eigen_alpha))
        print("%-20s %20.10f" % ("eigen_beta", cdp.eigen_beta))
        print("%-20s %20.10f" % ("eigen_gamma", cdp.eigen_gamma))
        print("%-20s\n%s" % ("eigenframe", axes_new))
Example #18
0
def return_rdc_data(sim_index=None):
    """Set up the data structures for optimisation using RDCs as base data sets.

    @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
    @return:            The assembled data structures for using RDCs as the base data for optimisation.  These include:
                            - rdc, the RDC values.
                            - rdc_err, the RDC errors.
                            - rdc_weight, the RDC weights.
                            - vectors, the interatomic vectors (pseudo-atom dependent).
                            - rdc_const, the dipolar constants (pseudo-atom dependent).
                            - absolute, the absolute value flags (as 1's and 0's).
                            - T_flags, the flags for T = J+D type data (as 1's and 0's).
                            - j_couplings, the J coupling values if the RDC data type is set to T = J+D.
                            - pseudo_flags, the list of flags indicating if the interatomic data contains a pseudo-atom (as 1's and 0's).
    @rtype:             tuple of (numpy rank-2 float64 array, numpy rank-2 float64 array, numpy rank-2 float64 array, list of numpy rank-3 float64 arrays, list of lists of floats, numpy rank-2 int32 array, numpy rank-2 int32 array, numpy rank-2 float64 array, numpy rank-1 int32 array)
    """

    # Sort out pseudo-atoms first.  This only needs to be called once.
    setup_pseudoatom_rdc()

    # Initialise.
    rdc = []
    rdc_err = []
    rdc_weight = []
    unit_vect = []
    rdc_const = []
    absolute = []
    T_flags = []
    j_couplings = []
    pseudo_flags = []

    # The unit vectors, RDC constants, and J couplings.
    for interatom in interatomic_loop():
        # Get the spins.
        spin1 = return_spin(interatom.spin_id1)
        spin2 = return_spin(interatom.spin_id2)

        # RDC checks.
        if not check_rdcs(interatom):
            continue

        # Gyromagnetic ratios.
        g1 = return_gyromagnetic_ratio(spin1.isotope)
        g2 = return_gyromagnetic_ratio(spin2.isotope)

        # Pseudo atoms.
        if is_pseudoatom(spin1) and is_pseudoatom(spin2):
            raise RelaxError("Support for both spins being in a dipole pair being pseudo-atoms is not implemented yet.")
        if is_pseudoatom(spin1) or is_pseudoatom(spin2):
            # Set the flag.
            pseudo_flags.append(1)

            # Alias the pseudo and normal atoms.
            if is_pseudoatom(spin1):
                pseudospin = spin1
                base_spin = spin2
                pseudospin_id = interatom.spin_id1
                base_spin_id = interatom.spin_id2
            else:
                pseudospin = spin2
                base_spin = spin1
                pseudospin_id = interatom.spin_id2
                base_spin_id = interatom.spin_id1

            # Loop over the atoms of the pseudo-atom, storing the data.
            pseudo_unit_vect = []
            pseudo_rdc_const = []
            for spin, spin_id in pseudoatom_loop(pseudospin, return_id=True):
                # Get the corresponding interatomic data container.
                pseudo_interatom = return_interatom(spin_id1=spin_id, spin_id2=base_spin_id)

                # Check.
                if pseudo_interatom == None:
                    raise RelaxError("The interatomic data container between the spins '%s' and '%s' for the pseudo-atom '%s' is not defined." % (base_spin_id, spin_id, pseudospin_id))

                # Add the vectors.
                if is_float(interatom.vector[0]):
                    pseudo_unit_vect.append([pseudo_interatom.vector])
                else:
                    pseudo_unit_vect.append(pseudo_interatom.vector)

                # Calculate the RDC dipolar constant (in Hertz, and the 3 comes from the alignment tensor), and append it to the list.
                pseudo_rdc_const.append(3.0/(2.0*pi) * dipolar_constant(g1, g2, pseudo_interatom.r))

            # Reorder the unit vectors so that the structure and pseudo-atom dimensions are swapped.
            pseudo_unit_vect = transpose(array(pseudo_unit_vect, float64), (1, 0, 2))

            # Block append the pseudo-data.
            unit_vect.append(pseudo_unit_vect)
            rdc_const.append(pseudo_rdc_const)

        # Normal atom.
        else:
            # Set the flag.
            pseudo_flags.append(0)

            # Add the vectors.
            if is_float(interatom.vector[0]):
                unit_vect.append([interatom.vector])
            else:
                unit_vect.append(interatom.vector)

            # Calculate the RDC dipolar constant (in Hertz, and the 3 comes from the alignment tensor), and append it to the list.
            rdc_const.append(3.0/(2.0*pi) * dipolar_constant(g1, g2, interatom.r))

        # Store the measured J coupling.
        if opt_uses_j_couplings():
            j_couplings.append(interatom.j_coupling)

    # Fix the unit vector data structure.
    num = None
    for rdc_index in range(len(unit_vect)):
        # Convert to numpy structures.
        unit_vect[rdc_index] = array(unit_vect[rdc_index], float64)

        # Number of vectors.
        if num == None:
            if unit_vect[rdc_index] != None:
                num = len(unit_vect[rdc_index])
            continue

        # Check.
        if unit_vect[rdc_index] != None and len(unit_vect[rdc_index]) != num:
            raise RelaxError("The number of interatomic vectors for all no match:\n%s" % unit_vect[rdc_index])

    # Missing unit vectors.
    if num == None:
        raise RelaxError("No interatomic vectors could be found.")

    # Update None entries.
    for i in range(len(unit_vect)):
        if unit_vect[i] == None:
            unit_vect[i] = [[None, None, None]]*num

    # The RDC data.
    for i in range(len(cdp.align_ids)):
        # Alias the ID.
        align_id = cdp.align_ids[i]

        # Skip non-optimised data.
        if not opt_uses_align_data(align_id):
            continue

        # Append empty arrays to the RDC structures.
        rdc.append([])
        rdc_err.append([])
        rdc_weight.append([])
        absolute.append([])
        T_flags.append([])

        # Interatom loop.
        for interatom in interatomic_loop():
            # Get the spins.
            spin1 = return_spin(interatom.spin_id1)
            spin2 = return_spin(interatom.spin_id2)

            # RDC checks.
            if not check_rdcs(interatom):
                continue

            # T-type data.
            if align_id in interatom.rdc_data_types and interatom.rdc_data_types[align_id] == 'T':
                T_flags[-1].append(True)
            else:
                T_flags[-1].append(False)

            # Check for J couplings if the RDC data type is T = J+D.
            if T_flags[-1][-1] and not hasattr(interatom, 'j_coupling'):
                continue

            # Defaults of None.
            value = None
            error = None

            # Normal set up.
            if align_id in interatom.rdc.keys():
                # The RDC.
                if sim_index != None:
                    value = interatom.rdc_sim[align_id][sim_index]
                else:
                    value = interatom.rdc[align_id]

                # The error.
                if hasattr(interatom, 'rdc_err') and align_id in interatom.rdc_err.keys():
                    # T values.
                    if T_flags[-1][-1]:
                        error = sqrt(interatom.rdc_err[align_id]**2 + interatom.j_coupling_err**2)

                    # D values.
                    else:
                        error = interatom.rdc_err[align_id]

            # Append the RDCs to the list.
            rdc[-1].append(value)

            # Append the RDC errors.
            rdc_err[-1].append(error)

            # Append the weight.
            if hasattr(interatom, 'rdc_weight') and align_id in interatom.rdc_weight.keys():
                rdc_weight[-1].append(interatom.rdc_weight[align_id])
            else:
                rdc_weight[-1].append(1.0)

            # Append the absolute value flag.
            if hasattr(interatom, 'absolute_rdc') and align_id in interatom.absolute_rdc.keys():
                absolute[-1].append(interatom.absolute_rdc[align_id])
            else:
                absolute[-1].append(False)

    # Convert to numpy objects.
    rdc = array(rdc, float64)
    rdc_err = array(rdc_err, float64)
    rdc_weight = array(rdc_weight, float64)
    absolute = array(absolute, int32)
    T_flags = array(T_flags, int32)
    if not opt_uses_j_couplings():
        j_couplings = None
    pseudo_flags = array(pseudo_flags, int32)

    # Return the data structures.
    return rdc, rdc_err, rdc_weight, unit_vect, rdc_const, absolute, T_flags, j_couplings, pseudo_flags
Example #19
0
def read(align_id=None, file=None, dir=None, file_data=None, data_type='D', spin_id1_col=None, spin_id2_col=None, data_col=None, error_col=None, sep=None, neg_g_corr=False, absolute=False):
    """Read the RDC data from file.

    @keyword align_id:      The alignment tensor ID string.
    @type align_id:         str
    @keyword file:          The name of the file to open.
    @type file:             str
    @keyword dir:           The directory containing the file (defaults to the current directory if None).
    @type dir:              str or None
    @keyword file_data:     An alternative to opening a file, if the data already exists in the correct format.  The format is a list of lists where the first index corresponds to the row and the second the column.
    @type file_data:        list of lists
    @keyword data_type:     A string which is set to 'D' means that the splitting in the aligned sample was assumed to be J + D, or if set to '2D' then the splitting was taken as J + 2D.  If set to 'T', then the data will be marked as being J+D values.
    @keyword spin_id1_col:  The column containing the spin ID strings of the first spin.
    @type spin_id1_col:     int
    @keyword spin_id2_col:  The column containing the spin ID strings of the second spin.
    @type spin_id2_col:     int
    @keyword data_col:      The column containing the RDC data in Hz.
    @type data_col:         int or None
    @keyword error_col:     The column containing the RDC errors.
    @type error_col:        int or None
    @keyword sep:           The column separator which, if None, defaults to whitespace.
    @type sep:              str or None
    @keyword neg_g_corr:    A flag which is used to correct for the negative gyromagnetic ratio of 15N.  If True, a sign inversion will be applied to all RDC values to be loaded.
    @type neg_g_corr:       bool
    @keyword absolute:      A flag which if True indicates that the RDCs to load are signless.  All RDCs will then be converted to positive values.
    @type absolute:         bool
    """

    # Check the pipe setup.
    check_pipe_setup(sequence=True)

    # Either the data or error column must be supplied.
    if data_col == None and error_col == None:
        raise RelaxError("One of either the data or error column must be supplied.")

    # Check the data types.
    rdc_types = ['D', '2D', 'T']
    if data_type not in rdc_types:
        raise RelaxError("The RDC data type '%s' must be one of %s." % (data_type, rdc_types))

    # Spin specific data.
    #####################

    # Extract the data from the file, and remove comments and blank lines.
    file_data = extract_data(file, dir, sep=sep)
    file_data = strip(file_data, comments=True)

    # Loop over the RDC data.
    data = []
    for line in file_data:
        # Invalid columns.
        if spin_id1_col > len(line):
            warn(RelaxWarning("The data %s is invalid, no first spin ID column can be found." % line))
            continue
        if spin_id2_col > len(line):
            warn(RelaxWarning("The data %s is invalid, no second spin ID column can be found." % line))
            continue
        if data_col and data_col > len(line):
            warn(RelaxWarning("The data %s is invalid, no data column can be found." % line))
            continue
        if error_col and error_col > len(line):
            warn(RelaxWarning("The data %s is invalid, no error column can be found." % line))
            continue

        # Unpack.
        spin_id1 = line[spin_id1_col-1]
        spin_id2 = line[spin_id2_col-1]
        value = None
        if data_col:
            value = line[data_col-1]
        error = None
        if error_col:
            error = line[error_col-1]

        # Convert the spin IDs.
        if spin_id1[0] in ["\"", "\'"]:
            spin_id1 = eval(spin_id1)
        if spin_id2[0] in ["\"", "\'"]:
            spin_id2 = eval(spin_id2)

        # Convert and check the value.
        if value == 'None':
            value = None
        if value != None:
            try:
                value = float(value)
            except ValueError:
                warn(RelaxWarning("The RDC value of the line %s is invalid." % line))
                continue

        # Convert and check the error.
        if error == 'None':
            error = None
        if error != None:
            try:
                error = float(error)
            except ValueError:
                warn(RelaxWarning("The error value of the line %s is invalid." % line))
                continue

        # Get the spins.
        spin1 = return_spin(spin_id1)
        spin2 = return_spin(spin_id2)

        # Check the spin IDs.
        if not spin1:
            warn(RelaxWarning("The spin ID '%s' cannot be found in the current data pipe, skipping the data %s." % (spin_id1, line)))
            continue
        if not spin2:
            warn(RelaxWarning("The spin ID '%s' cannot be found in the current data pipe, skipping the data %s." % (spin_id2, line)))
            continue

        # Get the interatomic data container.
        interatom = return_interatom(spin_id1, spin_id2)

        # Create the container if needed.
        if interatom == None:
            interatom = create_interatom(spin_id1=spin_id1, spin_id2=spin_id2)

        # Test the error value (a value of 0.0 will cause the interatomic container to be deselected).
        if error == 0.0:
            interatom.select = False
            warn(RelaxWarning("An error value of zero has been encountered, deselecting the interatomic container between spin '%s' and '%s'." % (spin_id1, spin_id2)))
            continue

        # Store the data type as global data (need for the conversion of RDC data).
        if not hasattr(interatom, 'rdc_data_types'):
            interatom.rdc_data_types = {}
        if not align_id in interatom.rdc_data_types:
            interatom.rdc_data_types[align_id] = data_type

        # Convert and add the data.
        if data_col:
            # Data conversion.
            value = convert(value, data_type, align_id, to_intern=True)

            # Correction for the negative gyromagnetic ratio of 15N.
            if neg_g_corr and value != None:
                value = -value

            # Absolute values.
            if absolute:
                # Force the value to be positive.
                value = abs(value)

            # Initialise.
            if not hasattr(interatom, 'rdc'):
                interatom.rdc = {}

            # Add the value.
            interatom.rdc[align_id] = value

            # Store the absolute value flag.
            if not hasattr(interatom, 'absolute_rdc'):
                interatom.absolute_rdc = {}
            interatom.absolute_rdc[align_id] = absolute

        # Convert and add the error.
        if error_col:
            # Data conversion.
            error = convert(error, data_type, align_id, to_intern=True)

            # Initialise.
            if not hasattr(interatom, 'rdc_err'):
                interatom.rdc_err = {}

            # Append the error.
            interatom.rdc_err[align_id] = error

        # Append the data for printout.
        data.append([spin_id1, spin_id2])
        if is_float(value):
            data[-1].append("%20.15f" % value)
        else:
            data[-1].append("%20s" % value)
        if is_float(error):
            data[-1].append("%20.15f" % error)
        else:
            data[-1].append("%20s" % error)

    # No data, so fail hard!
    if not len(data):
        raise RelaxError("No RDC data could be extracted.")

    # Print out.
    print("The following RDCs have been loaded into the relax data store:\n")
    write_data(out=sys.stdout, headings=["Spin_ID1", "Spin_ID2", "Value", "Error"], data=data)

    # Initialise some global structures.
    if not hasattr(cdp, 'align_ids'):
        cdp.align_ids = []
    if not hasattr(cdp, 'rdc_ids'):
        cdp.rdc_ids = []

    # Add the RDC id string.
    if align_id not in cdp.align_ids:
        cdp.align_ids.append(align_id)
    if align_id not in cdp.rdc_ids:
        cdp.rdc_ids.append(align_id)
Example #20
0
def back_calc(align_id=None):
    """Back calculate the RDC from the alignment tensor and unit bond vectors.

    @keyword align_id:      The alignment tensor ID string.
    @type align_id:         str
    """

    # Check the pipe setup.
    check_pipe_setup(rdc_id=align_id, sequence=True, N=True, tensors=True)

    # Convert the align IDs to an array, or take all IDs.
    if align_id:
        align_ids = [align_id]
    else:
        align_ids = cdp.align_ids

    # Add the ID to the RDC IDs, if needed.
    for align_id in align_ids:
        # Init.
        if not hasattr(cdp, 'rdc_ids'):
            cdp.rdc_ids = []

        # Add the ID.
        if align_id not in cdp.rdc_ids:
            cdp.rdc_ids.append(align_id)

    # The weights.
    weights = ones(cdp.N, float64) / cdp.N

    # Unit vector data structure init.
    unit_vect = zeros((cdp.N, 3), float64)

    # Loop over the interatomic data.
    count = 0
    for interatom in interatomic_loop():
        # Skip containers with no interatomic vectors.
        if not hasattr(interatom, 'vector'):
            continue

        # Get the spins.
        spin1 = return_spin(interatom.spin_id1)
        spin2 = return_spin(interatom.spin_id2)

        # Checks.
        if not hasattr(spin1, 'isotope'):
            raise RelaxSpinTypeError(interatom.spin_id1)
        if not hasattr(spin2, 'isotope'):
            raise RelaxSpinTypeError(interatom.spin_id2)

        # Single vector.
        if is_float(interatom.vector[0]):
            vectors = [interatom.vector]
        else:
            vectors = interatom.vector

        # Gyromagnetic ratios.
        g1 = return_gyromagnetic_ratio(spin1.isotope)
        g2 = return_gyromagnetic_ratio(spin2.isotope)

        # Calculate the RDC dipolar constant (in Hertz, and the 3 comes from the alignment tensor), and append it to the list.
        dj = 3.0/(2.0*pi) * dipolar_constant(g1, g2, interatom.r)

        # Unit vectors.
        for c in range(cdp.N):
            unit_vect[c] = vectors[c] / norm(vectors[c])

        # Initialise if necessary.
        if not hasattr(interatom, 'rdc_bc'):
            interatom.rdc_bc = {}

        # Calculate the RDCs.
        for id in align_ids:
            # The signed value.
            interatom.rdc_bc[id] = ave_rdc_tensor(dj, unit_vect, cdp.N, cdp.align_tensors[get_tensor_index(align_id=id)].A, weights=weights)

            # T values.
            if hasattr(interatom, 'rdc_data_types') and align_id in interatom.rdc_data_types and interatom.rdc_data_types[align_id] == 'T':
                if not hasattr(interatom, 'j_coupling'):
                    raise RelaxNoJError

                interatom.rdc_bc[id] += interatom.j_coupling

            # The absolute value.
            if hasattr(interatom, 'absolute_rdc') and id in interatom.absolute_rdc.keys() and interatom.absolute_rdc[id]:
                interatom.rdc_bc[id] = abs(interatom.rdc_bc[id])

        # Increment the counter.
        count += 1

    # No RDCs calculated.
    if not count:
        warn(RelaxWarning("No RDCs have been back calculated, probably due to missing bond vector information."))
Example #21
0
def write_spin_data(file, dir=None, sep=None, spin_ids=None, mol_names=None, res_nums=None, res_names=None, spin_nums=None, spin_names=None, force=False, data=None, data_name=None, error=None, error_name=None, float_format="%20.15g"):
    """Generator function for reading the spin specific data from file.

    Description
    ===========

    This function writes a columnar formatted file where each line corresponds to a spin system.  Spin identification is either through a spin ID string or through columns containing the molecule name, residue name and number, and/or spin name and number.


    @param file:            The name of the file to write the data to (or alternatively an already opened file object).
    @type file:             str or file object
    @keyword dir:           The directory to place the file into (defaults to the current directory if None and the file argument is not a file object).
    @type dir:              str or None
    @keyword sep:           The column separator which, if None, defaults to whitespace.
    @type sep:              str or None
    @keyword spin_ids:      The list of spin ID strings.
    @type spin_ids:         None or list of str
    @keyword mol_names:     The list of molecule names.
    @type mol_names:        None or list of str
    @keyword res_nums:      The list of residue numbers.
    @type res_nums:         None or list of int
    @keyword res_names:     The list of residue names.
    @type res_names:        None or list of str
    @keyword spin_nums:     The list of spin numbers.
    @type spin_nums:        None or list of int
    @keyword spin_names:    The list of spin names.
    @type spin_names:       None or list of str
    @keyword force:         A flag which if True will cause an existing file to be overwritten.
    @type force:            bool
    @keyword data:          A list of the data to write out.  The first dimension corresponds to the spins.  A second dimension can also be given if multiple data sets across multiple columns are desired.
    @type data:             list or list of lists
    @keyword data_name:     A name corresponding to the data argument.  If the data argument is a list of lists, then this must also be a list with the same length as the second dimension of the data arg.
    @type data_name:        str or list of str
    @keyword error:         A list of the errors to write out.  The first dimension corresponds to the spins.  A second dimension can also be given if multiple data sets across multiple columns are desired.  These will be inter-dispersed between the data columns, if the data is given.  If the data arg is not None, then this must have the same dimensions as that object.
    @type error:            list or list of lists
    @keyword error_name:    A name corresponding to the error argument.  If the error argument is a list of lists, then this must also be a list with the same length at the second dimension of the error arg.
    @type error_name:       str or list of str
    @keyword float_format:  A float formatting string to use for the data and error whenever a float is found.
    @type float_format:     str
    """

    # Data argument tests.
    if data:
        # Data is a list of lists.
        if isinstance(data[0], list):
            # Data and data_name don't match.
            if not isinstance(data_name, list):
                raise RelaxError("The data_name arg '%s' must be a list as the data argument is a list of lists." % data_name)

            # Error doesn't match.
            if error and (len(data) != len(error) or len(data[0]) != len(error[0])):
                raise RelaxError("The data arg:\n%s\n\ndoes not have the same dimensions as the error arg:\n%s." % (data, error))

        # Data is a simple list.
        else:
            # Data and data_name don't match.
            if not isinstance(data_name, str):
                raise RelaxError("The data_name arg '%s' must be a string as the data argument is a simple list." % data_name)

            # Error doesn't match.
            if error and len(data) != len(error):
                raise RelaxError("The data arg:\n%s\n\ndoes not have the same dimensions as the error arg:\n%s." % (data, error))

    # Error argument tests.
    if error:
        # Error is a list of lists.
        if isinstance(error[0], list):
            # Error and error_name don't match.
            if not isinstance(error_name, list):
                raise RelaxError("The error_name arg '%s' must be a list as the error argument is a list of lists." % error_name)

        # Error is a simple list.
        else:
            # Error and error_name don't match.
            if not isinstance(error_name, str):
                raise RelaxError("The error_name arg '%s' must be a string as the error argument is a simple list." % error_name)

    # Number of spins check.
    args = [spin_ids, mol_names, res_nums, res_names, spin_nums, spin_names]
    arg_names = ['spin_ids', 'mol_names', 'res_nums', 'res_names', 'spin_nums', 'spin_names']
    N = None
    first_arg = None
    first_arg_name = None
    for i in range(len(args)):
        if isinstance(args[i], list):
            # First list match.
            if N == None:
                N = len(args[i])
                first_arg = args[i]
                first_arg_name = arg_names[i]

            # Length check.
            if len(args[i]) != N:
                raise RelaxError("The %s and %s arguments do not have the same number of spins ('%s' vs. '%s' respectively)." % (first_arg_name, arg_names[i], len(first_arg), len(args[i])))

    # Nothing?!?
    if N == None:
        raise RelaxError("No spin ID data is present.")

    # Data and error length check.
    if data and len(data) != N:
        raise RelaxError("The %s and data arguments do not have the same number of spins ('%s' vs. '%s' respectively)." % (first_arg_name, len(first_arg), len(data)))
    if error and len(error) != N:
        raise RelaxError("The %s and error arguments do not have the same number of spins ('%s' vs. '%s' respectively)." % (first_arg_name, len(first_arg), len(error)))

    # The spin arguments.
    args = [spin_ids, mol_names, res_nums, res_names, spin_nums, spin_names]
    arg_names = ['spin_id', 'mol_name', 'res_num', 'res_name', 'spin_num', 'spin_name']


    # Init.
    headings = []
    file_data = []

    # Headers - the spin ID info.
    for i in range(len(args)):
        if args[i]:
            headings.append(arg_names[i])

    # Headers - the data.
    if data:
        # List of lists.
        if isinstance(data[0], list):
            # Loop over the list.
            for i in range(len(data[0])):
                # The data.
                headings.append(data_name[i])

                # The error.
                if error:
                    headings.append(error_name[i])

        # Simple list.
        else:
            # The data.
            headings.append(data_name)

            # The error.
            if error:
                headings.append(error_name)

    # Headers - only errors.
    elif error:
        # List of lists.
        if isinstance(error[0], list):
            for i in range(len(error[0])):
                headings.append(error_name[i])

        # Simple list.
        else:
            headings.append(error_name)

    # No headings.
    if headings == []:
        headings = None

    # Spin specific data.
    for spin_index in range(N):
        # Append a new data row.
        file_data.append([])

        # The spin ID info.
        for i in range(len(args)):
            if args[i]:
                value = args[i][spin_index]
                if not isinstance(value, str):
                    value = repr(value)
                file_data[-1].append(value)

        # The data.
        if data:
            # List of lists.
            if isinstance(data[0], list):
                # Loop over the list.
                for i in range(len(data[0])):
                    # The data.
                    if is_float(data[spin_index][i]):
                        file_data[-1].append(float_format % data[spin_index][i])
                    else:
                        file_data[-1].append(repr(data[spin_index][i]))

                    # The error.
                    if error:
                        if is_float(error[spin_index][i]):
                            file_data[-1].append(float_format % error[spin_index][i])
                        else:
                            file_data[-1].append(repr(error[spin_index][i]))

            # Simple list.
            else:
                # The data.
                if is_float(data[spin_index]):
                    file_data[-1].append(float_format % data[spin_index])
                else:
                    file_data[-1].append(repr(data[spin_index]))

                # The error.
                if error:
                    if is_float(error[spin_index]):
                        file_data[-1].append(float_format % error[spin_index])
                    else:
                        file_data[-1].append(repr(error[spin_index]))

        # Only errors.
        elif error:
            # List of lists.
            if isinstance(error[0], list):
                for i in range(len(error[0])):
                    file_data[-1].append(repr(error[spin_index][i]))

            # Simple list.
            else:
                file_data[-1].append(repr(error[spin_index]))

    # No data to write, so do nothing!
    if file_data == [] or file_data == [[]]:
        return

    # Open the file for writing.
    file = open_write_file(file_name=file, dir=dir, force=force)

    # Write out the file data.
    write_data(out=file, headings=headings, data=file_data, sep=sep)