docs: def cached_tree(self, subject_ids=None, visit_ids=None, fill=False):
          """
          Access the repository tree and caches it for subsequent
          accesses
  
          Parameters
          ----------
          subject_ids : list(str)
              List of subject IDs with which to filter the tree with. If
              None all are returned
          visit_ids : list(str)
              List of visit IDs with which to filter the tree with. If
              None all are returned
          fill : bool
              Create empty sessions for any that are missing in the
              subject_id x visit_id block. Typically only used if all
              the inputs to the study are coming from different repositories
              to the one that the derived products are stored in
  
          Returns
          -------
          tree : arcana.repository.Tree
              A hierarchical tree of subject, vist, session information and that
              of the filesets and fields they contain
          """
          if subject_ids is not None:
              subject_ids = frozenset(subject_ids)
          if visit_ids is not None:
              visit_ids = frozenset(visit_ids)
          try:
              tree = self._cache[subject_ids][visit_ids]
          except KeyError:
              if fill:
                  fill_subjects = subject_ids
                  fill_visits = visit_ids
              else:
                  fill_subjects = fill_visits = None
              tree = self.tree(
                  subject_ids=subject_ids, visit_ids=visit_ids,
                  fill_visits=fill_visits, fill_subjects=fill_subjects)
              # Save the tree within the cache under the given subject/
              # visit ID filters and the IDs that were actually returned
              self._cache[subject_ids][visit_ids] = self._cache[
                  frozenset(tree.subject_ids)][frozenset(tree.visit_ids)] = tree
          return tree