Returns a list of all PDB files which contain protein sequences similar to the protein sequences of pdb_id.
           Only protein chains are considered in the matching so e.g. some results may have DNA or RNA chains or ligands
           while some may not.

def by_pdb(self, pdb_id, take_top_percentile = 30.0, cut_off = None, matrix = None, sequence_identity_cut_off = None, silent = None):
        '''Returns a list of all PDB files which contain protein sequences similar to the protein sequences of pdb_id.
           Only protein chains are considered in the matching so e.g. some results may have DNA or RNA chains or ligands
           while some may not.
        '''

        self.log('BLASTing {0}'.format(pdb_id), silent, colortext.pcyan)

        # Preamble
        matrix = matrix or self.matrix
        cut_off = cut_off or self.cut_off
        sequence_identity_cut_off = sequence_identity_cut_off or self.sequence_identity_cut_off

        # Parse PDB file
        p = self.bio_cache.get_pdb_object(pdb_id)

        chain_ids = sorted(p.seqres_sequences.keys())
        assert(chain_ids)

        # Run BLAST over all chains
        hits = set(self.blast_by_pdb_chain(pdb_id, chain_ids[0], cut_off = cut_off, matrix = matrix, sequence_identity_cut_off = sequence_identity_cut_off, take_top_percentile = take_top_percentile, silent = silent))
        for chain_id in chain_ids[1:]:
            chain_hits = self.blast_by_pdb_chain(pdb_id, chain_id, cut_off = cut_off, matrix = matrix, sequence_identity_cut_off = sequence_identity_cut_off, take_top_percentile = take_top_percentile)
            if chain_hits != None:
                # None suggests that the chain was not a protein chain whereas an empty list suggest a protein chain with no hits
                hits = hits.intersection(set(chain_hits))
        return sorted(hits)