docs: def ref_align(self, found_seqs, sequence: Seq=None,
                    locus: str=None, annotation: Annotation=None,
                    partial_ann: Annotation=None,
                    run: int=0,
                    cutoff: float=.90) -> Annotation:
          """
          ref_align - Method for doing targeted alignments on partial annotations
  
          :param found_seqs: The input sequence record.
          :type found_seqs: Seq
          :param sequence: The input sequence record.
          :type sequence: Seq
          :param locus: The gene locus associated with the sequence.
          :type locus: ``str``
          :param annotation: The incomplete annotation from a previous iteration.
          :type annotation: :ref:`ann`
          :param partial_ann: The partial annotation after looping through all of the blast sequences.
          :type partial_ann: :ref:`ann`
          :rtype: :ref:`ann`
  
          """
          if annotation and isinstance(annotation, Annotation):
              if 0 in annotation.mapping \
                      and not isinstance(annotation.mapping[0], int):
                  ft = annotation.mapping[0]
                  start_order = self.refdata.structures[locus][ft]
              else:
                  start_order = 0
  
              # Check whether it's exons only
              exon_only = True
              if hasattr(annotation, 'annotation') and annotation.annotation:
                  for f in annotation.annotation:
                      if re.search("intron", f) or re.search("UTR", f):
                          exon_only = False
              elif(len(sequence.seq) > 900):
                  exon_only = False
  
              annoated = []
              if hasattr(annotation, 'annotation') and annotation.annotation:
                  annoated = list(annotation.annotation.keys())
  
              # Extract the missing blocks and
              # only align those blocks to the known
              # missing features
              # Start with all blocks missing
              # and then delete block if it is found
              tmp_missing = []
              missing_blocks = annotation.blocks
              for b in sorted(annotation.blocks):
                  # **** Check if block equals full input sequence *** #
                  # - If it does, then just align the ful
  
                  start = b[0]-1 if b[0] != 0 else 0
                  seq_feat = \
                      SeqFeature(
                          FeatureLocation(
                              ExactPosition(start),
                              ExactPosition(b[len(b)-1]),
                              strand=1),
                          type="unmapped")
  
                  feat = seq_feat.extract(annotation.seq)
                  combosrecs, exons, fullrec = self._refseqs(locus,
                                                             start,
                                                             annotation,
                                                             feat,
                                                             b)
  
                  # Print out different sequence types being align
                  if self.verbose and self.verbosity > 3:
                      for combseqr in combosrecs:
                          self.logger.info(self.logname + " " + combseqr.id)
  
                  ic = 0
  
                  # Looping through the generated combos
                  # from the reference sequence. (ex. intron1-exon1)
                  for combseqr in combosrecs:
                      if self.verbose:
                          self.logger.info(self.logname + " aligning ->" + combseqr.id)
                      
                      # Running the alignment
                      an, ins, dels = align_seqs(combseqr, feat, locus,
                                                 start,
                                                 annotation.missing,
                                                 len(annoated),
                                                 cutoff=cutoff,
                                                 verbose=self.align_verbose,
                                                 verbosity=self.align_verbosity)
  
                      # Checking if any features were mapped
                      mapped_feat = list(an.annotation.keys())
                      if len(mapped_feat) >= 1:
  
                          # loop through the annotated features
                          for f in an.annotation:
                              f_order = self.refdata.structures[locus][f]
  
                              # Only map features if they are in the correct order
                              if f in annotation.missing \
                                      and f_order >= start_order:
  
                                  # * HARD CODED LOGIC *
                                  # Only accept the alignments if they are
                                  # somewhat similar to what's been observed already
                                  length, lengthsd = 0, 0
                                  length = float(self.refdata.feature_lengths[locus][f][0])
                                  lengthsd = float(self.refdata.feature_lengths[locus][f][1])
  
                                  incr = 3 if not is_classII(locus) else 4
  
                                  max_length = length + (lengthsd*incr) + ins
                                  min_length = length - (lengthsd*incr) - dels
  
                                  if f == "exon_8" and not is_classII(f):
                                      max_length = 10
  
                                  # Check ordering when it's only exon sequences
                                  if exon_only:
                                      f_order = self.refdata.structures[locus][f]
                                      endp = an.features[f].location.end + 1
  
                                      #Make sure order of alignment make sense
                                      if an.features[f].location.start == 0 \
                                              and f != "five_prime_UTR" \
                                              and not isexon(f):
                                          del an.features[f]
                                          continue
  
                                      if endp in annotation.mapping and not isinstance(annotation.mapping[endp], int):
                                          mf = annotation.mapping[endp]
                                          expected_order = f_order + 1
                                          expected_order2 = f_order + 2
                                          if expected_order != self.refdata.structures[locus][mf] and expected_order2 != self.refdata.structures[locus][mf]:
                                              self.logger.info(self.logname + " out of order1 -> " + mf + " " + f)                                        
                                              del an.features[f]
                                              continue
  
                                      startp = an.features[f].location.start - 1
                                      if startp in annotation.mapping and not isinstance(annotation.mapping[startp], int):
                                          mf = annotation.mapping[startp]
                                          expected_order = f_order - 1
                                          expected_order2 = f_order - 2
                                          if expected_order != self.refdata.structures[locus][mf] and expected_order2 != self.refdata.structures[locus][mf]:
                                              self.logger.info(self.logname + " out of order2 -> " + mf + " " + f)
                                              del an.features[f]
                                              continue
                                  else:
  
                                      ##Make sure order of alignment make sense
                                      if an.features[f].location.start == 0 \
                                              and f != "five_prime_UTR" \
                                              and 'three_prime_UTR' in annotation.annotation:
                                          del an.features[f]
                                          continue
  
                                      f_order = self.refdata.structures[locus][f]
                                      endp = an.features[f].location.end + 1
                                      if endp in annotation.mapping and not isinstance(annotation.mapping[endp], int):
                                          mf = annotation.mapping[endp]
                                          expected_order = f_order + 1
                                          if expected_order != self.refdata.structures[locus][mf]:
                                              self.logger.info(self.logname + " out of order12 -> " + mf + " " + f)
                                              del an.features[f]
                                              continue
  
                                      startp = an.features[f].location.start - 1
                                      if startp in annotation.mapping and not isinstance(annotation.mapping[startp], int):
                                          mf = annotation.mapping[startp]
                                          expected_order = f_order - 1
                                          if expected_order != self.refdata.structures[locus][mf]:
                                              self.logger.info(self.logname + " out of order22 -> " + mf + " " + f)
                                              del an.features[f]
                                              continue
  
                                  if self.verbose and self.verbosity > 0:
                                      sl = str(len(an.annotation[f]))
  
                                      self.logger.info(self.logname + " " + locus
                                                       + " " + f
                                                       + " len = " + sl
                                                       + " | max = "
                                                       + str(max_length)
                                                       + " | min = "
                                                       + str(min_length))
  
                                      if len(an.annotation[f]) <= max_length:
                                          self.logger.info(self.logname
                                                           + " " + locus
                                                           + " " + f
                                                           + " " + sl + " <= "
                                                           + str(max_length))
                                      else:
                                          self.logger.info(self.logname
                                                           + " " + locus
                                                           + " " + f
                                                           + " " + sl + " ! <= !"
                                                           + str(max_length))
  
                                      if len(an.annotation[f]) >= min_length:
                                          self.logger.info(self.logname
                                                           + " " + locus
                                                           + " " + f
                                                           + " " + sl + " >= "
                                                           + str(min_length))
                                      else:
                                          self.logger.info(self.logname + " "
                                                           + locus
                                                           + " " + f
                                                           + " " + sl + " ! >= !"
                                                           + str(min_length))
  
                                  # Update the original annotation
                                  # with the returned annotation
                                  if(len(an.annotation[f]) <= max_length and
                                          len(an.annotation[f]) >= min_length):
                                      if self.verbose and self.verbosity > 0:
                                          self.logger.info(self.logname
                                                           + " Annotated " + f
                                                           + " with clustalo using " +
                                                           combseqr.id)
                                          self.logger.info(self.logname
                                                           + " Coordinates for " + f
                                                           + str(an.features[f].location.start)
                                                           + " - " + str(an.features[f].location.end)
                                                           )
                                      if annotation.annotation:
                                          annotation.annotation.update({f:
                                                                      an.annotation[f]
                                                                    })
                                          annotation.features.update({f:
                                                                      an.features[f]
                                                                    })  
                                      else:
                                          annotation.annotation = {}
                                          annotation.annotation.update({f:
                                                                      an.annotation[f]
                                                                    })
                                          annotation.features.update({f:
                                                                      an.features[f]
                                                                    })
                                      if f in annotation.refmissing:
                                          i = annotation.refmissing.index(f)
                                          del annotation.refmissing[i]
  
                                      if f in annotation.missing:
                                          del annotation.missing[f]
  
                                      #if b in annotation.blocks:
                                      #    del annotation.blocks[annotation.blocks.index(b)]
                                      #     print(annotation.blocks)
                                      # if an.blocks:
                                      #     #print("PARTIAL BLOCK")
                                      #     #print(an.blocks)
                                      #     if b in missing_blocks:
                                      #         del missing_blocks[missing_blocks.index(b)]
  
                                      #     if self.verbose and self.verbosity > 0:
                                      #         self.logger.info(self.logname
                                      #                          + " Part of block mapped")
  
                                      # else:
                                      #     if self.verbose and self.verbosity > 0:
                                      #         self.logger.info(self.logname
                                      #                          + " All blocks mapped")
                                          
                                      #     del annotation.blocks[annotation.blocks.index(b)]
                                      #     if b in missing_blocks:
                                      #         del missing_blocks[missing_blocks.index(b)]
                                  else:
                                      self.logger.info(self.logname + " FAILED HERE!!!!!!!!!")
                                  #elif b not in mbtmp and b in missing_blocks:
                                  #    mbtmp.append(b)
                              else:
                                  self.logger.info(self.logname + " OUT OF ORDER !!!!!!!!!!!!!!!!!!!")
  
                      # Update the coordinates
                      coordinates = dict(map(lambda x: [x, 1], [i for i in range(0, len(sequence.seq)+1)]))
                      for f in annotation.features:
                          s = annotation.features[f].location.start
                          e = annotation.features[f].location.end
                          if s != 0:
                              s += 1
                              e += 1
                          else:
                              e += 1
  
                          for i in range(s, e):
                              annotation.mapping[i] = f
                              if i in coordinates:
                                  del coordinates[i]
  
                      # Get any remaining blocks after updated
                      # annotation
                      blocks = getblocks(coordinates)
                      annotation.blocks = blocks
  
                      # Check to see if that annotation is complete
                      annotation.check_annotation()
                      if annotation.complete_annotation:
                          if self.verbose:
                              self.logger.info(self.logname
                                               + " Completed annotation"
                                               + " with targeted ref_align")
                          return annotation
                      else:
  
                          if an.features:
                              # for f in an.features:
                              #     f_order = self.refdata.structures[locus][f]
                              #     # Only add features if they are after the
                              #     # first feature mapped
                              #     if f_order >= start_order and f not in annotation.features \
                              #             and f in annotation.annotation:
                              #         annotation.features[f] = an.features[f]
  
                              # Rerunning seqsearch with
                              # new annotation from alignment
                              tmpann = self.seqsearch.search_seqs(found_seqs,
                                                                  sequence,
                                                                  locus,
                                                                  partial_ann=annotation,
                                                                  run=run)
  
                              if tmpann.complete_annotation:
                                  for f in tmpann.annotation:
                                      if f not in annotation.annotation:
                                          annotation.annotation[f] = tmpann.annotation[f]
                                  if self.verbose:
                                      self.logger.info(self.logname
                                                       + " Completed annotation"
                                                       + " with targeted ref_align and seqsearch!")
  
                                  return tmpann
                              annotation = tmpann
  
                      ic += 1
  
                  # Has to be missing exons
                  exons_n = 0
                  for f in annotation.missing:
                      if re.search("intron", f) or re.search("UTR", f):
                          exons_n += 1
  
                  # Run exon only alignment
                  if len(exons.seq) >= 4 and exons_n > 0:
                      exonan, ins, dels = align_seqs(exons, feat, locus, start,
                                                     annotation.missing,
                                                     len(annoated),
                                                     cutoff=cutoff,
                                                     verbose=self.align_verbose,
                                                     verbosity=self.align_verbosity)
                      mapped_exons = list(exonan.annotation.keys())
                      if len(mapped_exons) >= 1:
                          if self.verbose:
                              self.logger.info(self.logname
                                               + " Annotated exons with align")
                          for f in exonan.annotation:
                              if self.verbose and self.verbosity > 0:
                                  self.logger.info(self.logname
                                                   + " Annotated "
                                                   + f + " len = "
                                                   + str(len(exonan
                                                             .annotation[f])))
                              annotation.annotation.update({f: exonan.annotation[f]})
                              annotation.features.update({f: exonan.features[f]})
  
                          coordinates = dict(map(lambda x: [x, 1], [i for i in range(0, len(sequence.seq)+1)]))
                          for f in annotation.features:
                              s = annotation.features[f].location.start
                              e = annotation.features[f].location.end
                              if s != 0:
                                  s += 1
                                  e += 1
                              else:
                                  e += 1
                              for i in range(s, e):
                                  annotation.mapping[i] = f
                                  if i in coordinates:
                                      del coordinates[i]
  
                          blocks = getblocks(coordinates)
                          annotation.blocks = blocks
                          annotation.check_annotation()
                          if annotation.complete_annotation:
                              if self.verbose:
                                  self.logger.info(self.logname + " Completed annotation with targeted exons ref_align")
                              return annotation
  
              return annotation
          elif partial_ann:
  
              annoated = []
              if hasattr(partial_ann, 'annotation') and partial_ann.annotation:
                  annoated = list(partial_ann.annotation.keys())
  
              # Do full sequence alignments
              # any only extract out the part
              # that couldn't be explained from above
              if 0 in partial_ann.mapping \
                      and not isinstance(partial_ann.mapping[0], int):
                  ft = partial_ann.mapping[0]
                  start_order = self.refdata.structures[locus][ft]
              else:
                  start_order = 0
  
              # Extract the missing blocks and
              # only align those blocks to the known
              # missing features
              # Start with all blocks missing
              # and then delete block if it is found
              tmp_missing = []
              missing_blocks = partial_ann.blocks
              for b in sorted(partial_ann.blocks):
  
                  # **** Check if block equals full input sequence *** #
                  # - If it does, then just align the ful
                  start = b[0]-1 if b[0] != 0 else 0
                  seq_feat = \
                      SeqFeature(
                          FeatureLocation(
                              ExactPosition(start),
                              ExactPosition(b[len(b)-1]),
                              strand=1),
                          type="unmapped")
  
                  feat = seq_feat.extract(partial_ann.seq)
                  combosrecs, exons, fullrec = self._refseqs(locus,
                                                             start,
                                                             partial_ann,
                                                             feat,
                                                             b)
                  if len(fullrec.seq) >= 4:
  
                      fullref, ins, dels = align_seqs(fullrec, feat,
                                                      locus, start,
                                                      partial_ann.missing,
                                                      len(annoated),
                                                      cutoff=cutoff,
                                                      verbose=self.align_verbose,
                                                      verbosity=self.align_verbosity)
  
                      if hasattr(fullref, 'features') and fullref.features:
                          mapped_full = list(fullref.annotation.keys())
                          if len(mapped_full) >= 1:
  
                              if self.verbose:
                                  self.logger.info(self.logname
                                                   + " Annotated fullrec"
                                                   + " with clustalo")
  
                              # If it wasn't found
                              del missing_blocks[missing_blocks.index(b)]
  
                              for f in fullref.annotation:
                                  if self.verbose and self.verbosity > 0:
                                      self.logger.info(self.logname + " Annotated " + f + " len = " + str(len(fullref.annotation[f])))
                                  partial_ann.annotation.update({f: fullref.annotation[f]})
  
                          if b in missing_blocks:
                              del missing_blocks[missing_blocks.index(b)]
                          else:
                              for bm in tmp_missing:
                                  if bm in missing_blocks:
                                      del missing_blocks[missing_blocks.index(bm)]
  
                          for f in fullref.features:
                              f_order = self.refdata.structures[locus][f]
                              # Only add features if they are after the
                              # first feature mapped
                              if f_order >= start_order and f not in partial_ann.features \
                                      and f in partial_ann.annotation:
                                  partial_ann.features[f] = fullref.features[f]
  
                          coordinates = dict(map(lambda x: [x, 1], [i for i in range(0, len(sequence.seq)+1)]))
                          for f in partial_ann.features:
                              s = partial_ann.features[f].location.start
                              e = partial_ann.features[f].location.end
                              if s != 0:
                                  s += 1
                                  e += 1
                              else:
                                  e += 1
                              for i in range(s, e):
                                  partial_ann.mapping[i] = f
                                  if i in coordinates:
                                      del coordinates[i]
  
                          blocks = getblocks(coordinates)
                          partial_ann.check_annotation()
                          if partial_ann.complete_annotation:
                              if self.verbose:
                                  self.logger.info(self.logname + " Annotated all features with clustalo")
                          
                      return partial_ann
  
              if self.verbose:
                  self.logger.info(self.logname
                                   + " Failed to annotate features")
              return ''