docs: def set_representative_structure(self, seq_outdir=None, struct_outdir=None, pdb_file_type=None,
                                       engine='needle', always_use_homology=False, rez_cutoff=0.0,
                                       seq_ident_cutoff=0.5, allow_missing_on_termini=0.2,
                                       allow_mutants=True, allow_deletions=False,
                                       allow_insertions=False, allow_unresolved=True,
                                       clean=True, keep_chemicals=None, skip_large_structures=False,
                                       force_rerun=False):
          """Set a representative structure from a structure in the structures attribute.
  
          Each gene can have a combination of the following, which will be analyzed to set a representative structure.
              * Homology model(s)
              * Ranked PDBs
              * BLASTed PDBs
  
          If the ``always_use_homology`` flag is true, homology models are always set as representative when they exist.
          If there are multiple homology models, we rank by the percent sequence coverage.
  
          Args:
              seq_outdir (str): Path to output directory of sequence alignment files, must be set if Protein directory
                  was not created initially
              struct_outdir (str): Path to output directory of structure files, must be set if Protein directory
                  was not created initially
              pdb_file_type (str): ``pdb``, ``mmCif``, ``xml``, ``mmtf`` - file type for files downloaded from the PDB
              engine (str): ``biopython`` or ``needle`` - which pairwise alignment program to use.
                  ``needle`` is the standard EMBOSS tool to run pairwise alignments.
                  ``biopython`` is Biopython's implementation of needle. Results can differ!
              always_use_homology (bool): If homology models should always be set as the representative structure
              rez_cutoff (float): Resolution cutoff, in Angstroms (only if experimental structure)
              seq_ident_cutoff (float): Percent sequence identity cutoff, in decimal form
              allow_missing_on_termini (float): Percentage of the total length of the reference sequence which will be ignored
                  when checking for modifications. Example: if 0.1, and reference sequence is 100 AA, then only residues
                  5 to 95 will be checked for modifications.
              allow_mutants (bool): If mutations should be allowed or checked for
              allow_deletions (bool): If deletions should be allowed or checked for
              allow_insertions (bool): If insertions should be allowed or checked for
              allow_unresolved (bool): If unresolved residues should be allowed or checked for
              clean (bool): If structure should be cleaned
              keep_chemicals (str, list): Keep specified chemical names if structure is to be cleaned
              skip_large_structures (bool): Default False -- currently, large structures can't be saved as a PDB file even
                  if you just want to save a single chain, so Biopython will throw an error when trying to do so. As an
                  alternative, if a large structure is selected as representative, the pipeline will currently point to it
                  and not clean it. If you don't want this to happen, set this to true.
              force_rerun (bool): If sequence to structure alignment should be rerun
  
          Returns:
              StructProp: Representative structure from the list of structures. This is a not a map to the original
              structure, it is copied and optionally cleaned from the original one.
  
          Todo:
              - Remedy large structure representative setting
  
          """
          log.debug('{}: setting representative structure'.format(self.id))
  
          if len(self.structures) == 0:
              log.debug('{}: no structures available'.format(self.id))
              return None
  
          if not self.representative_sequence:
              log.error('{}: no representative sequence to compare structures to'.format(self.id))
              return None
  
          if self.representative_structure and not force_rerun:
              log.debug('{}: representative structure already set'.format(self.id))
              return self.representative_structure
  
          if self.representative_structure and force_rerun:
              log.debug('{}: representative structure previously set, unsetting'.format(self.id))
              self.representative_structure = None
  
          if not pdb_file_type:
              pdb_file_type = self.pdb_file_type
  
          if not seq_outdir:
              seq_outdir = self.sequence_dir
              if not seq_outdir:
                  raise ValueError('Sequence output directory must be specified')
  
          if not struct_outdir:
              struct_outdir = self.structure_dir
              if not struct_outdir:
                  raise ValueError('Structure output directory must be specified')
  
          has_homology = False
          has_pdb = False
          use_homology = False
          use_pdb = False
  
          if self.num_structures_homology > 0:
              has_homology = True
          if self.num_structures_experimental > 0:
              has_pdb = True
  
          # If we mark to always use homology, use it if it exists
          if always_use_homology:
              if has_homology:
                  use_homology = True
              elif has_pdb:
                  use_pdb = True
          # If we don't always want to use homology, use PDB if it exists
          else:
              if has_homology and has_pdb:
                  use_pdb = True
                  use_homology = True
              elif has_homology and not has_pdb:
                  use_homology = True
              elif has_pdb and not has_homology:
                  use_pdb = True
  
          if use_pdb:
              # Put PDBs through QC/QA
              all_pdbs = self.get_experimental_structures()
              log.debug('{}: checking quality of {} experimental structures'.format(self.id, len(all_pdbs)))
  
              for pdb in all_pdbs:
                  # Download the structure and parse it
                  # This will add all chains to the mapped_chains attribute if there are none
                  try:
                      pdb.download_structure_file(outdir=struct_outdir, file_type=pdb_file_type, force_rerun=force_rerun, load_header_metadata=True)
                  except (requests.exceptions.HTTPError, URLError):
                      log.error('{}: structure file could not be downloaded in {} format'.format(pdb, pdb_file_type))
                      continue
                      # TODO: add try/except to download cif file as fallback like below?
  
                  if rez_cutoff and pdb.resolution:
                      if pdb.resolution > rez_cutoff:
                          log.debug('{}: structure does not meet experimental resolution cutoff'.format(pdb, pdb_file_type))
                          continue
                  # TODO: clean up these try/except things
                  try:
                      self.align_seqprop_to_structprop(seqprop=self.representative_sequence,
                                                       structprop=pdb,
                                                       outdir=seq_outdir,
                                                       engine=engine,
                                                       parse=True,
                                                       force_rerun=force_rerun)
                  except (PDBConstructionException, ExtraData, KeyError) as e:
                      log.error('Protein {}, PDB {}: unable to parse structure file as {}. Falling back to mmCIF format.'.format(self.id, pdb, pdb_file_type))
                      print(e)
                      # Fall back to using mmCIF file if structure cannot be parsed
                      try:
                          pdb.download_structure_file(outdir=struct_outdir, file_type='mmCif',
                                                      force_rerun=force_rerun, load_header_metadata=True)
                      except (requests.exceptions.HTTPError, URLError):
                          log.error('Protein {}, PDB {}: structure file could not be downloaded'.format(self.id, pdb))
                          continue
                      try:
                          self.align_seqprop_to_structprop(seqprop=self.representative_sequence,
                                                           structprop=pdb,
                                                           outdir=seq_outdir,
                                                           engine=engine,
                                                           parse=True,
                                                           force_rerun=force_rerun)
                      except (PDBConstructionException, KeyError) as e:
                          log.error('Protein {}, PDB {}: unable to parse structure file as {}.'.format(self.id, pdb, 'mmCif'))
                          print(e)
                          continue
  
                  best_chain = self.find_representative_chain(seqprop=self.representative_sequence,
                                                              structprop=pdb,
                                                              seq_ident_cutoff=seq_ident_cutoff,
                                                              allow_missing_on_termini=allow_missing_on_termini,
                                                              allow_mutants=allow_mutants, allow_deletions=allow_deletions,
                                                              allow_insertions=allow_insertions, allow_unresolved=allow_unresolved)
  
                  if best_chain:
                      try:
                          self._representative_structure_setter(structprop=pdb,
                                                                clean=clean,
                                                                out_suffix='-{}_clean'.format(best_chain),
                                                                keep_chain=best_chain,
                                                                keep_chemicals=keep_chemicals,
                                                                outdir=struct_outdir,
                                                                force_rerun=force_rerun)
                      except TypeError:
                          if skip_large_structures == True:
                              log.warning("{}: unable to save large PDB {}-{} in PDB file format, trying next "
                                          "structure.".format(self.id, pdb.id, best_chain))
                              continue
                          else:
                              log.warning("{}: unable to save large PDB {}-{} in PDB file format, setting original "
                                          "structure as representative. Set skip_large_structures=True if you don't "
                                          "want this to happen".format(self.id, pdb.id, best_chain))
                              self.representative_structure = pdb
                      except Exception as e:
                          # Try force rerunning first if there exists a corrupt clean PDB file
                          try:
                              log.debug('{}: unknown error with {}, trying force_rerun first'.format(self.id, pdb.id))
                              self._representative_structure_setter(structprop=pdb,
                                                                    clean=clean,
                                                                    out_suffix='-{}_clean'.format(best_chain),
                                                                    keep_chain=best_chain,
                                                                    keep_chemicals=keep_chemicals,
                                                                    outdir=struct_outdir,
                                                                    force_rerun=True)
                          except Exception as e:
                              # TODO: inspect causes of these errors - most common is Biopython PDBParser error
                              logging.exception("{}: unknown error with PDB ID {}".format(self.id, pdb.id))
                              print(e)
                              continue
                      log.debug('{}-{}: set as representative structure'.format(pdb.id, best_chain))
                      pdb.reset_chain_seq_records()
                      return self.representative_structure
                  else:
                      pdb.reset_chain_seq_records()
              else:
                  log.debug('{}: no experimental structures meet cutoffs'.format(self.id))
  
          # If we are to use homology, save its information in the representative structure field
          if use_homology:
              log.debug('{}: checking quality of homology models'.format(self.id))
              all_models = self.get_homology_models()
  
              # TODO: homology models are not ordered in any other way other than how they are loaded,
              # rethink this for multiple homology models
              for homology in all_models:
                  if not homology.structure_file:
                      log.debug('{}: no homology structure file'.format(self.id))
                      continue
  
                  self.align_seqprop_to_structprop(seqprop=self.representative_sequence,
                                                   structprop=homology,
                                                   outdir=seq_outdir,
                                                   engine=engine,
                                                   parse=True,
                                                   force_rerun=force_rerun)
                  best_chain = self.find_representative_chain(seqprop=self.representative_sequence,
                                                              structprop=homology,
                                                              seq_ident_cutoff=seq_ident_cutoff,
                                                              allow_missing_on_termini=allow_missing_on_termini,
                                                              allow_mutants=allow_mutants,
                                                              allow_deletions=allow_deletions,
                                                              allow_insertions=allow_insertions,
                                                              allow_unresolved=allow_unresolved)
  
                  if best_chain:
                      # If chain ID is empty (some homology models are like that), use ID "X"
                      if not best_chain.strip():
                          best_chain = 'X'
                      try:
                          self._representative_structure_setter(structprop=homology,
                                                                # new_id='{}-{}'.format(homology.id, best_chain), # 170906 Deprecated use of new_id
                                                                clean=True,
                                                                out_suffix='-{}_clean'.format(best_chain),
                                                                keep_chain=best_chain,
                                                                outdir=struct_outdir,
                                                                force_rerun=force_rerun)
                      except:
                          # TODO: inspect causes of these errors - most common is Biopython PDBParser error
                          logging.exception("Unknown error with homology model {}".format(homology.id))
                          continue
                      log.debug('{}-{}: set as representative structure'.format(homology.id, best_chain))
                      homology.reset_chain_seq_records()
                      return self.representative_structure
                  else:
                      homology.reset_chain_seq_records()
  
          log.warning('{}: no structures meet quality checks'.format(self.id))
          return None