Example #1
0
def set_dist(spin_id1=None, spin_id2=None, ave_dist=None, unit='meter'):
    """Set up the magnetic dipole-dipole interaction.

    @keyword spin_id1:      The spin identifier string of the first spin of the pair.
    @type spin_id1:         str
    @keyword spin_id2:      The spin identifier string of the second spin of the pair.
    @type spin_id2:         str
    @keyword ave_dist:      The r^-3 averaged interatomic distance.
    @type ave_dist:         float
    @keyword unit:          The measurement unit.  This can be either 'meter' or 'Angstrom'.
    @type unit:             str
    """

    # Check the units.
    if unit not in ['meter', 'Angstrom']:
        raise RelaxError("The measurement unit of '%s' must be one of 'meter' or 'Angstrom'." % unit)

    # Unit conversion.
    if unit == 'Angstrom':
        ave_dist = ave_dist * 1e-10

    # Generate the selection objects.
    sel_obj1 = Selection(spin_id1)
    sel_obj2 = Selection(spin_id2)

    # Loop over the interatomic containers.
    data = []
    for interatom in interatomic_loop():
        # Get the spin info.
        mol_name1, res_num1, res_name1, spin1 = return_spin(spin_hash=interatom._spin_hash1, full_info=True)
        mol_name2, res_num2, res_name2, spin2 = return_spin(spin_hash=interatom._spin_hash2, full_info=True)

        # No match, either way.
        if not (sel_obj1.contains_spin(spin_num=spin1.num, spin_name=spin1.name, res_num=res_num1, res_name=res_name1, mol=mol_name1) and sel_obj2.contains_spin(spin_num=spin2.num, spin_name=spin2.name, res_num=res_num2, res_name=res_name2, mol=mol_name2)) and not (sel_obj2.contains_spin(spin_num=spin1.num, spin_name=spin1.name, res_num=res_num1, res_name=res_name1, mol=mol_name1) and sel_obj1.contains_spin(spin_num=spin2.num, spin_name=spin2.name, res_num=res_num2, res_name=res_name2, mol=mol_name2)):
            continue

        # Store the averaged distance.
        interatom.r = ave_dist

        # Store the data for the printout.
        data.append([repr(interatom.spin_id1), repr(interatom.spin_id2), repr(ave_dist)])

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

    # Print out.
    print("The following averaged distances have been set:\n")
    write_data(out=sys.stdout, headings=["Spin_ID_1", "Spin_ID_2", "Ave_distance(meters)"], data=data)
Example #2
0
def set_dist(spin_id1=None, spin_id2=None, ave_dist=None, unit='meter'):
    """Set up the magnetic dipole-dipole interaction.

    @keyword spin_id1:      The spin identifier string of the first spin of the pair.
    @type spin_id1:         str
    @keyword spin_id2:      The spin identifier string of the second spin of the pair.
    @type spin_id2:         str
    @keyword ave_dist:      The r^-3 averaged interatomic distance.
    @type ave_dist:         float
    @keyword unit:          The measurement unit.  This can be either 'meter' or 'Angstrom'.
    @type unit:             str
    """

    # Check the units.
    if unit not in ['meter', 'Angstrom']:
        raise RelaxError("The measurement unit of '%s' must be one of 'meter' or 'Angstrom'." % unit)

    # Unit conversion.
    if unit == 'Angstrom':
        ave_dist = ave_dist * 1e-10

    # Generate the selection objects.
    sel_obj1 = Selection(spin_id1)
    sel_obj2 = Selection(spin_id2)

    # Loop over the interatomic containers.
    data = []
    for interatom in interatomic_loop():
        # Get the spin info.
        mol_name1, res_num1, res_name1, spin1 = return_spin(interatom.spin_id1, full_info=True)
        mol_name2, res_num2, res_name2, spin2 = return_spin(interatom.spin_id2, full_info=True)

        # No match, either way.
        if not (sel_obj1.contains_spin(spin_num=spin1.num, spin_name=spin1.name, res_num=res_num1, res_name=res_name1, mol=mol_name1) and sel_obj2.contains_spin(spin_num=spin2.num, spin_name=spin2.name, res_num=res_num2, res_name=res_name2, mol=mol_name2)) and not (sel_obj2.contains_spin(spin_num=spin1.num, spin_name=spin1.name, res_num=res_num1, res_name=res_name1, mol=mol_name1) and sel_obj1.contains_spin(spin_num=spin2.num, spin_name=spin2.name, res_num=res_num2, res_name=res_name2, mol=mol_name2)):
            continue

        # Store the averaged distance.
        interatom.r = ave_dist

        # Store the data for the printout.
        data.append([repr(interatom.spin_id1), repr(interatom.spin_id2), repr(ave_dist)])

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

    # Print out.
    print("The following averaged distances have been set:\n")
    write_data(out=sys.stdout, headings=["Spin_ID_1", "Spin_ID_2", "Ave_distance(meters)"], data=data)
Example #3
0
def pack_data(ri_id,
              ri_type,
              frq,
              values,
              errors,
              spin_ids=None,
              mol_names=None,
              res_nums=None,
              res_names=None,
              spin_nums=None,
              spin_names=None,
              spin_id=None,
              gen_seq=False,
              verbose=True):
    """Pack the relaxation data into the data pipe and spin containers.

    The values, errors, and spin_ids arguments must be lists of equal length or None.  Each element i corresponds to a unique spin.

    @param ri_id:           The relaxation data ID string.
    @type ri_id:            str
    @param ri_type:         The relaxation data type, ie 'R1', 'R2', or 'NOE'.
    @type ri_type:          str
    @param frq:             The spectrometer proton frequency in Hz.
    @type frq:              float
    @keyword values:        The relaxation data for each spin.
    @type values:           None or list of float or float array
    @keyword errors:        The relaxation data errors for each spin.
    @type errors:           None or list of float or float array
    @keyword spin_ids:      The list of spin ID strings.  If the other spin identifiers are given, i.e. mol_names, res_nums, res_names, spin_nums, and/or spin_names, then this argument is not necessary.
    @type spin_ids:         None or list of str
    @keyword mol_names:     The list of molecule names used for creating the spin IDs (if not given) or for generating the sequence data.
    @type mol_names:        None or list of str
    @keyword res_nums:      The list of residue numbers used for creating the spin IDs (if not given) or for generating the sequence data.
    @type res_nums:         None or list of str
    @keyword res_names:     The list of residue names used for creating the spin IDs (if not given) or for generating the sequence data.
    @type res_names:        None or list of str
    @keyword spin_nums:     The list of spin numbers used for creating the spin IDs (if not given) or for generating the sequence data.
    @type spin_nums:        None or list of str
    @keyword spin_names:    The list of spin names used for creating the spin IDs (if not given) or for generating the sequence data.
    @type spin_names:       None or list of str
    @keyword gen_seq:       A flag which if True will cause the molecule, residue, and spin sequence data to be generated.
    @type gen_seq:          bool
    @keyword verbose:       A flag which if True will cause all relaxation data loaded to be printed out.
    @type verbose:          bool
    """

    # The number of spins.
    N = len(values)

    # Test the data.
    if errors != None and len(errors) != N:
        raise RelaxError(
            "The length of the errors arg (%s) does not match that of the value arg (%s)."
            % (len(errors), N))
    if spin_ids and len(spin_ids) != N:
        raise RelaxError(
            "The length of the spin ID strings arg (%s) does not match that of the value arg (%s)."
            % (len(mol_names), N))
    if mol_names and len(mol_names) != N:
        raise RelaxError(
            "The length of the molecule names arg (%s) does not match that of the value arg (%s)."
            % (len(mol_names), N))
    if res_nums and len(res_nums) != N:
        raise RelaxError(
            "The length of the residue numbers arg (%s) does not match that of the value arg (%s)."
            % (len(res_nums), N))
    if res_names and len(res_names) != N:
        raise RelaxError(
            "The length of the residue names arg (%s) does not match that of the value arg (%s)."
            % (len(res_names), N))
    if spin_nums and len(spin_nums) != N:
        raise RelaxError(
            "The length of the spin numbers arg (%s) does not match that of the value arg (%s)."
            % (len(spin_nums), N))
    if spin_names and len(spin_names) != N:
        raise RelaxError(
            "The length of the spin names arg (%s) does not match that of the value arg (%s)."
            % (len(spin_names), N))

    # Generate some empty lists.
    if not mol_names:
        mol_names = [None] * N
    if not res_nums:
        res_nums = [None] * N
    if not res_names:
        res_names = [None] * N
    if not spin_nums:
        spin_nums = [None] * N
    if not spin_names:
        spin_names = [None] * N
    if errors == None:
        errors = [None] * N

    # Generate the spin IDs.
    if not spin_ids:
        spin_ids = []
        for i in range(N):
            spin_ids.append(
                generate_spin_id_unique(spin_num=spin_nums[i],
                                        spin_name=spin_names[i],
                                        res_num=res_nums[i],
                                        res_name=res_names[i],
                                        mol_name=mol_names[i]))

    # Initialise the global data for the current pipe if necessary.
    if not hasattr(cdp, 'ri_type'):
        cdp.ri_type = {}
    if not hasattr(cdp, 'ri_ids'):
        cdp.ri_ids = []

    # Set the spectrometer frequency.
    set_frequency(id=ri_id, frq=frq)

    # Update the global data.
    cdp.ri_ids.append(ri_id)
    cdp.ri_type[ri_id] = ri_type

    # The selection object.
    select_obj = None
    if spin_id:
        select_obj = Selection(spin_id)

    # Loop over the spin data.
    data = []
    for i in range(N):
        # A selection union.
        select_id = spin_ids[i]
        if spin_id != None:
            select_id = "%s&%s" % (select_id, spin_id)

        # Get the corresponding spin container.
        match_mol_names, match_res_nums, match_res_names, spins = return_spin_from_selection(
            selection=select_id, full_info=True, multi=True)

        # No spin.
        if len(spins) == 0:
            continue

        # Check that multiple spins are not present.
        if len(spins) > 1:
            # Generate the list of spin IDs.
            new_ids = []
            for j in range(len(spins)):
                new_ids.append(
                    generate_spin_id_unique(mol_name=match_mol_names[j],
                                            res_num=match_res_nums[j],
                                            res_name=match_res_names[j],
                                            spin_num=spins[j].num,
                                            spin_name=spins[j].name))

            # Raise the error.
            raise RelaxMultiSpinIDError(spin_ids[i], new_ids)

        # Check that at least one spin is present.
        if len(spins) == 0:
            raise RelaxNoSpinError(spin_ids[i])

        # Loop over the spins.
        for j in range(len(spins)):
            # No match to the selection.
            if select_obj and not select_obj.contains_spin(
                    spin_num=spins[j].num,
                    spin_name=spins[j].name,
                    res_num=res_nums[j],
                    res_name=res_names[j],
                    mol=mol_names[j]):
                continue

            # Initialise the spin data if necessary.
            if not hasattr(spins[j], 'ri_data') or spins[j].ri_data == None:
                spins[j].ri_data = {}
            if not hasattr(spins[j],
                           'ri_data_err') or spins[j].ri_data_err == None:
                spins[j].ri_data_err = {}

            # Update all data structures.
            spins[j].ri_data[ri_id] = values[i]
            spins[j].ri_data_err[ri_id] = errors[i]

            # Append the data for printing out.
            data.append([spin_ids[i], repr(values[i]), repr(errors[i])])

    # Print out.
    if verbose:
        print(
            "\nThe following %s MHz %s relaxation data with the ID '%s' has been loaded into the relax data store:\n"
            % (frq / 1e6, ri_type, ri_id))
        write_data(out=sys.stdout,
                   headings=["Spin_ID", "Value", "Error"],
                   data=data)
Example #4
0
def interatomic_loop(selection1=None, selection2=None, pipe=None, skip_desel=True):
    """Generator function for looping over all the interatomic data containers.

    @keyword selection1:    The optional spin ID selection of the first atom.
    @type selection1:       str
    @keyword selection2:    The optional spin ID selection of the second atom.
    @type selection2:       str
    @keyword pipe:          The data pipe containing the spin.  Defaults to the current data pipe.
    @type pipe:             str
    @keyword skip_desel:    A flag which if True will cause only selected interatomic data containers to be returned.
    @type skip_desel:       bool
    """

    # The data pipe.
    if pipe == None:
        pipe = pipes.cdp_name()

    # Get the data pipe.
    dp = pipes.get_pipe(pipe)

    # Parse the spin ID selection strings.
    select_obj = None
    select_obj1 = None
    select_obj2 = None
    if selection1 and selection2:
        select_obj1 = Selection(selection1)
        select_obj2 = Selection(selection2)
    elif selection1:
        select_obj = Selection(selection1)
    elif selection2:
        select_obj = Selection(selection2)

    # Loop over the containers, yielding them.
    for i in range(len(dp.interatomic)):
        # Skip deselected containers.
        if skip_desel and not dp.interatomic[i].select:
            continue

        # Aliases.
        interatom = dp.interatomic[i]
        mol_index1, res_index1, spin_index1 = dp.mol._spin_hash_lookup[interatom._spin_hash1]
        mol_index2, res_index2, spin_index2 = dp.mol._spin_hash_lookup[interatom._spin_hash2]
        mol1 =  dp.mol[mol_index1]
        res1 =  dp.mol[mol_index1].res[res_index1]
        spin1 = dp.mol[mol_index1].res[res_index1].spin[spin_index1]
        mol2 = dp.mol[mol_index2]
        res2 =  dp.mol[mol_index2].res[res_index2]
        spin2 = dp.mol[mol_index2].res[res_index2].spin[spin_index2]

        # The different selection combinations.
        if select_obj:
            sel1 = select_obj.contains_spin(spin_name=spin1.name, spin_num=spin1.num, res_name=res1.name, res_num=res1.num, mol=mol1.name)
            sel2 = select_obj.contains_spin(spin_name=spin2.name, spin_num=spin2.num, res_name=res2.name, res_num=res2.num, mol=mol2.name)
        if select_obj1:
            sel11 = select_obj1.contains_spin(spin_name=spin1.name, spin_num=spin1.num, res_name=res1.name, res_num=res1.num, mol=mol1.name)
            sel12 = select_obj1.contains_spin(spin_name=spin2.name, spin_num=spin2.num, res_name=res2.name, res_num=res2.num, mol=mol2.name)
        if select_obj2:
            sel21 = select_obj2.contains_spin(spin_name=spin1.name, spin_num=spin1.num, res_name=res1.name, res_num=res1.num, mol=mol1.name)
            sel22 = select_obj2.contains_spin(spin_name=spin2.name, spin_num=spin2.num, res_name=res2.name, res_num=res2.num, mol=mol2.name)

        # Check that the selections are met.
        if select_obj:
            if not sel1 and not sel2:
                continue
        if select_obj1:
            if not (sel11 or sel12):
                continue
        if select_obj2:
            if not (sel21 or sel22):
                continue

        # Return the container.
        yield interatom
Example #5
0
def pack_data(ri_id, ri_type, frq, values, errors, spin_ids=None, mol_names=None, res_nums=None, res_names=None, spin_nums=None, spin_names=None, spin_id=None, gen_seq=False, verbose=True):
    """Pack the relaxation data into the data pipe and spin containers.

    The values, errors, and spin_ids arguments must be lists of equal length or None.  Each element i corresponds to a unique spin.

    @param ri_id:           The relaxation data ID string.
    @type ri_id:            str
    @param ri_type:         The relaxation data type, ie 'R1', 'R2', or 'NOE'.
    @type ri_type:          str
    @param frq:             The spectrometer proton frequency in Hz.
    @type frq:              float
    @keyword values:        The relaxation data for each spin.
    @type values:           None or list of float or float array
    @keyword errors:        The relaxation data errors for each spin.
    @type errors:           None or list of float or float array
    @keyword spin_ids:      The list of spin ID strings.  If the other spin identifiers are given, i.e. mol_names, res_nums, res_names, spin_nums, and/or spin_names, then this argument is not necessary.
    @type spin_ids:         None or list of str
    @keyword mol_names:     The list of molecule names used for creating the spin IDs (if not given) or for generating the sequence data.
    @type mol_names:        None or list of str
    @keyword res_nums:      The list of residue numbers used for creating the spin IDs (if not given) or for generating the sequence data.
    @type res_nums:         None or list of str
    @keyword res_names:     The list of residue names used for creating the spin IDs (if not given) or for generating the sequence data.
    @type res_names:        None or list of str
    @keyword spin_nums:     The list of spin numbers used for creating the spin IDs (if not given) or for generating the sequence data.
    @type spin_nums:        None or list of str
    @keyword spin_names:    The list of spin names used for creating the spin IDs (if not given) or for generating the sequence data.
    @type spin_names:       None or list of str
    @keyword gen_seq:       A flag which if True will cause the molecule, residue, and spin sequence data to be generated.
    @type gen_seq:          bool
    @keyword verbose:       A flag which if True will cause all relaxation data loaded to be printed out.
    @type verbose:          bool
    """

    # The number of spins.
    N = len(values)

    # Test the data.
    if errors != None and len(errors) != N:
        raise RelaxError("The length of the errors arg (%s) does not match that of the value arg (%s)." % (len(errors), N))
    if spin_ids and len(spin_ids) != N:
        raise RelaxError("The length of the spin ID strings arg (%s) does not match that of the value arg (%s)." % (len(mol_names), N))
    if mol_names and len(mol_names) != N:
        raise RelaxError("The length of the molecule names arg (%s) does not match that of the value arg (%s)." % (len(mol_names), N))
    if res_nums and len(res_nums) != N:
        raise RelaxError("The length of the residue numbers arg (%s) does not match that of the value arg (%s)." % (len(res_nums), N))
    if res_names and len(res_names) != N:
        raise RelaxError("The length of the residue names arg (%s) does not match that of the value arg (%s)." % (len(res_names), N))
    if spin_nums and len(spin_nums) != N:
        raise RelaxError("The length of the spin numbers arg (%s) does not match that of the value arg (%s)." % (len(spin_nums), N))
    if spin_names and len(spin_names) != N:
        raise RelaxError("The length of the spin names arg (%s) does not match that of the value arg (%s)." % (len(spin_names), N))

    # Generate some empty lists.
    if not mol_names:
        mol_names = [None] * N
    if not res_nums:
        res_nums = [None] * N
    if not res_names:
        res_names = [None] * N
    if not spin_nums:
        spin_nums = [None] * N
    if not spin_names:
        spin_names = [None] * N
    if errors == None:
        errors = [None] * N

    # Generate the spin IDs.
    if not spin_ids:
        spin_ids = []
        for i in range(N):
            spin_ids.append(generate_spin_id_unique(spin_num=spin_nums[i], spin_name=spin_names[i], res_num=res_nums[i], res_name=res_names[i], mol_name=mol_names[i]))

    # Initialise the global data for the current pipe if necessary.
    if not hasattr(cdp, 'ri_type'):
        cdp.ri_type = {}
    if not hasattr(cdp, 'ri_ids'):
        cdp.ri_ids = []

    # Set the spectrometer frequency.
    set_frequency(id=ri_id, frq=frq)

    # Update the global data.
    cdp.ri_ids.append(ri_id)
    cdp.ri_type[ri_id] = ri_type

    # The selection object.
    select_obj = None
    if spin_id:
        select_obj = Selection(spin_id)

    # Loop over the spin data.
    data = []
    for i in range(N):
        # Get the corresponding spin container.
        match_mol_names, match_res_nums, match_res_names, spins = return_spin_from_selection(spin_ids[i], full_info=True, multi=True)
        if spins in [None, []]:
            raise RelaxNoSpinError(spin_ids[i])

        # Remove non-matching spins.
        if select_obj:
            new_spins = []
            new_mol_names = []
            new_res_nums = []
            new_res_names = []
            new_ids = []
            for j in range(len(spins)):
                if select_obj.contains_spin(spin_num=spins[j].num, spin_name=spins[j].name, res_num=match_res_nums[j], res_name=match_res_names[j], mol=match_mol_names[j]):
                    new_spins.append(spins[j])
                    new_mol_names.append(match_mol_names[j])
                    new_res_nums.append(match_res_nums[j])
                    new_res_names.append(match_res_names[j])
                    new_ids.append(generate_spin_id_unique(mol_name=mol_names[i], res_num=res_nums[i], res_name=res_names[i], spin_num=spins[j].num, spin_name=spins[j].name))
            new_id = new_ids[0]

        # Aliases for normal operation.
        else:
            new_spins = spins
            new_mol_names = match_mol_names
            new_res_nums = match_res_nums
            new_res_names = match_res_names
            new_id = spin_ids[i]
            new_ids = None

        # Check that only a singe spin is present.
        if len(new_spins) > 1:
            if new_ids:
                raise RelaxMultiSpinIDError(spin_ids[i], new_ids)
            else:
                raise RelaxMultiSpinIDError(spin_ids[i], new_ids)
        if len(new_spins) == 0:
            raise RelaxNoSpinError(spin_ids[i])

        # Loop over the spins.
        for j in range(len(new_spins)):
            # No match to the selection.
            if select_obj and not select_obj.contains_spin(spin_num=new_spins[j].num, spin_name=new_spins[j].name, res_num=new_res_nums[j], res_name=new_res_names[j], mol=new_mol_names[j]):
                continue

            # Initialise the spin data if necessary.
            if not hasattr(new_spins[j], 'ri_data') or new_spins[j].ri_data == None:
                new_spins[j].ri_data = {}
            if not hasattr(new_spins[j], 'ri_data_err') or new_spins[j].ri_data_err == None:
                new_spins[j].ri_data_err = {}

            # Update all data structures.
            new_spins[j].ri_data[ri_id] = values[i]
            new_spins[j].ri_data_err[ri_id] = errors[i]

            # Append the data for printing out.
            data.append([new_id, repr(values[i]), repr(errors[i])])

    # Print out.
    if verbose:
        print("\nThe following %s MHz %s relaxation data with the ID '%s' has been loaded into the relax data store:\n" % (frq/1e6, ri_type, ri_id))
        write_data(out=sys.stdout, headings=["Spin_ID", "Value", "Error"], data=data)
Example #6
0
def interatomic_loop(selection1=None, selection2=None, pipe=None, skip_desel=True):
    """Generator function for looping over all the interatomic data containers.

    @keyword selection1:    The optional spin ID selection of the first atom.
    @type selection1:       str
    @keyword selection2:    The optional spin ID selection of the second atom.
    @type selection2:       str
    @keyword pipe:          The data pipe containing the spin.  Defaults to the current data pipe.
    @type pipe:             str
    @keyword skip_desel:    A flag which if True will cause only selected interatomic data containers to be returned.
    @type skip_desel:       bool
    """

    # The data pipe.
    if pipe == None:
        pipe = pipes.cdp_name()

    # Get the data pipe.
    dp = pipes.get_pipe(pipe)

    # Parse the spin ID selection strings.
    select_obj = None
    select_obj1 = None
    select_obj2 = None
    if selection1 and selection2:
        select_obj1 = Selection(selection1)
        select_obj2 = Selection(selection2)
    elif selection1:
        select_obj = Selection(selection1)
    elif selection2:
        select_obj = Selection(selection2)

    # Loop over the containers, yielding them.
    for i in range(len(dp.interatomic)):
        # Skip deselected containers.
        if skip_desel and not dp.interatomic[i].select:
            continue

        # Aliases.
        interatom = dp.interatomic[i]
        mol_index1, res_index1, spin_index1 = cdp.mol._spin_id_lookup[interatom.spin_id1]
        mol_index2, res_index2, spin_index2 = cdp.mol._spin_id_lookup[interatom.spin_id2]
        mol1 =  cdp.mol[mol_index1]
        res1 =  cdp.mol[mol_index1].res[res_index1]
        spin1 = cdp.mol[mol_index1].res[res_index1].spin[spin_index1]
        mol2 = cdp.mol[mol_index2]
        res2 =  cdp.mol[mol_index2].res[res_index2]
        spin2 = cdp.mol[mol_index2].res[res_index2].spin[spin_index2]

        # The different selection combinations.
        if select_obj:
            sel1 = select_obj.contains_spin(spin_name=spin1.name, spin_num=spin1.num, res_name=res1.name, res_num=res1.num, mol=mol1.name)
            sel2 = select_obj.contains_spin(spin_name=spin2.name, spin_num=spin2.num, res_name=res2.name, res_num=res2.num, mol=mol2.name)
        if select_obj1:
            sel11 = select_obj1.contains_spin(spin_name=spin1.name, spin_num=spin1.num, res_name=res1.name, res_num=res1.num, mol=mol1.name)
            sel12 = select_obj1.contains_spin(spin_name=spin2.name, spin_num=spin2.num, res_name=res2.name, res_num=res2.num, mol=mol2.name)
        if select_obj2:
            sel21 = select_obj2.contains_spin(spin_name=spin1.name, spin_num=spin1.num, res_name=res1.name, res_num=res1.num, mol=mol1.name)
            sel22 = select_obj2.contains_spin(spin_name=spin2.name, spin_num=spin2.num, res_name=res2.name, res_num=res2.num, mol=mol2.name)

        # Check that the selections are met.
        if select_obj:
            if not sel1 and not sel2:
                continue
        if select_obj1:
            if not (sel11 or sel12):
                continue
        if select_obj2:
            if not (sel21 or sel22):
                continue

        # Return the container.
        yield interatom