lchains and rchains should be lists of pairs (p, c, n) where p is a PDB object (bio/pdb.py:PDB), c is a chain
           identifier, and n is the NMR model number (or zero if this is not applicable).
           (character). This allows us to represent combinations of unbound chains.
           is_complex should be set to True if the PDB chains collectively form a complex.

def add_pdb_set(self, pdb_names, lchains, rchains, is_complex, notes = None):
        '''lchains and rchains should be lists of pairs (p, c, n) where p is a PDB object (bio/pdb.py:PDB), c is a chain
           identifier, and n is the NMR model number (or zero if this is not applicable).
           (character). This allows us to represent combinations of unbound chains.
           is_complex should be set to True if the PDB chains collectively form a complex.'''

        # If PDB objects differ and is_complex is set, raise an exception
        # This is not foolproof - we use the PDB object reference which could differ if the same PDB were loaded more than
        # once and passed in. However, that would be bad practice and this check is much cheaper than comparing the PDB content.
        if len(set([pc[0] for pc in lchains + rchains])) > 1 and is_complex:
            raise Exception('The PDB set cannot be marked as a complex as it is defined using multiple PDB objects.')

        # Check for unique occurrences of PDB chains (same caveat applies as above)
        all_chains = [(pc[0], pc[1]) for pc in lchains + rchains]
        if not len(all_chains) == len(set(all_chains)):
            raise Exception('Each PDB chain should be included at most once.')

        # Make sure that the chains exist in the PDB objects
        for pc in lchains + rchains:
            assert(pc[0] in pdb_names)
            assert(pc[1] in pc[0].atom_sequences)

        # Create the metadata
        set_number = len(self.pdb_sets)
        pdb_set = dict(
            set_number = set_number,
            is_complex = is_complex,
            notes = notes,
            chains = dict(L = [], R = []),
            pdb_set_id = None
        )

        # Add the PDB chains
        pdb_set_id = []
        for chain_set_def in ((lchains, 'L'), (rchains, 'R')):
            for pc in sorted(chain_set_def[0]):
                chain_set = pdb_set['chains'][chain_set_def[1]]
                nmr_model = None
                if len(pc) > 2:
                    nmr_model = pc[2]
                chain_set.append(dict(
                    chain_index = len(chain_set),
                    pdb_file_id = pdb_names[pc[0]],
                    chain_id = pc[1],
                    nmr_model = nmr_model,
                ))
                pdb_set_id.append('{0}:{1}:{2}:{3}'.format(chain_set_def[0], pdb_names[pc[0]], pc[1], nmr_model))
        pdb_set['pdb_set_id'] = sorted(pdb_set_id)
        print(pdb_set['pdb_set_id'])

        # Make sure we do not already have this set defined (the Complex should contain a unique list of bags of chains).
        if pdb_set['pdb_set_id'] in [ps['pdb_set_id'] for ps in self.pdb_sets]:
            raise Exception('This PDB set has already been defined (same PDB chains/NMR models).')

        self.pdb_sets.append(pdb_set)