docs: def run(self, *pipelines, **kwargs):
          """
          Connects all pipelines to that study's repository and runs them
          in the same NiPype workflow
  
          Parameters
          ----------
          pipeline(s) : Pipeline, ...
              The pipeline to connect to repository
          required_outputs : list[set[str]]
              A set of required outputs for each pipeline. If None then all
              outputs are assumed to be required
          subject_ids : list[str]
              The subset of subject IDs to process. If None all available will be
              processed. Note this is not a duplication of the study
              and visit IDs passed to the Study __init__, as they define the
              scope of the analysis and these simply limit the scope of the
              current run (e.g. to break the analysis into smaller chunks and
              run separately). Therefore, if the analysis joins over subjects,
              then all subjects will be processed and this parameter will be
              ignored.
          visit_ids : list[str]
              The same as 'subject_ids' but for visit IDs
          session_ids : list[str,str]
              The same as 'subject_ids' and 'visit_ids', except specifies a set
              of specific combinations in tuples of (subject ID, visit ID).
          force : bool | 'all'
              A flag to force the reprocessing of all sessions in the filter
              array, regardless of whether the parameters|pipeline used
              to generate them matches the current ones. NB: if True only the
              final pipeline will be reprocessed (prerequisite pipelines won't
              run unless they don't match provenance). To process all
              prerequisite pipelines 'all' should be passed to force.
  
          Returns
          -------
          report : ReportNode
              The final report node, which can be connected to subsequent
              pipelines
          """
          if not pipelines:
              raise ArcanaUsageError("No pipelines provided to {}.run"
                                     .format(self))
          # Get filter kwargs  (NB: in Python 3 they could be in the kwarg list)
          subject_ids = kwargs.pop('subject_ids', None)
          visit_ids = kwargs.pop('visit_ids', None)
          session_ids = kwargs.pop('session_ids', None)
          clean_work_dir = kwargs.pop('clean_work_dir',
                                      self._clean_work_dir_between_runs)
          required_outputs = kwargs.pop('required_outputs', repeat(None))
          # Create name by combining pipelines
          name = '_'.join(p.name for p in pipelines)
          # Clean work dir if required
          if clean_work_dir:
              workflow_work_dir = op.join(self.work_dir, name)
              if op.exists(workflow_work_dir):
                  shutil.rmtree(workflow_work_dir)
          # Trim the end of very large names to avoid problems with
          # workflow names exceeding system limits.
          name = name[:WORKFLOW_MAX_NAME_LEN]
          workflow = pe.Workflow(name=name, base_dir=self.work_dir)
  
          # Generate filter array to optionally restrict the run to certain
          # subject and visit IDs.
          tree = self.study.tree
          # Create maps from the subject|visit IDs to an index used to represent
          # them in the filter array
          subject_inds = {s.id: i for i, s in enumerate(tree.subjects)}
          visit_inds = {v.id: i for i, v in enumerate(tree.visits)}
          if not subject_ids and not visit_ids and not session_ids:
              # No filters applied so create a full filter array
              filter_array = np.ones((len(subject_inds), len(visit_inds)),
                                     dtype=bool)
          else:
              # Filters applied so create an empty filter array and populate
              # from filter lists
              filter_array = np.zeros((len(subject_inds), len(visit_inds)),
                                      dtype=bool)
              if subject_ids is not None:
                  for subj_id in subject_ids:
                      filter_array[subject_inds[subj_id], :] = True
              if visit_ids is not None:
                  for visit_id in visit_ids:
                      filter_array[:, visit_inds[visit_id]] = True
              if session_ids is not None:
                  for subj_id, visit_id in session_ids:
                      filter_array[subject_inds[subj_id],
                                   visit_inds[visit_id]] = True
              if not filter_array.any():
                  raise ArcanaUsageError(
                      "Provided filters:\n" +
                      ("  subject_ids: {}\n".format(', '.join(subject_ids))
                       if subject_ids is not None else '') +
                      ("  visit_ids: {}\n".format(', '.join(visit_ids))
                       if visit_ids is not None else '') +
                      ("  session_ids: {}\n".format(', '.join(session_ids))
                       if session_ids is not None else '') +
                      "Did not match any sessions in the project:\n" +
                      "  subject_ids: {}\n".format(', '.join(subject_inds)) +
                      "  visit_ids: {}\n".format(', '.join(visit_inds)))
  
          # Stack of pipelines to process in reverse order of required execution
          stack = OrderedDict()
  
          def push_on_stack(pipeline, filt_array, req_outputs):
              if req_outputs is None:
                  req_outputs = pipeline.output_names
              if pipeline.name in stack:
                  # Pop pipeline from stack in order to add it to the end of the
                  # stack and ensure it is run before all downstream pipelines
                  prev_pipeline, prev_req_outputs, prev_filt_array = stack.pop(
                      pipeline.name)
                  if pipeline is not prev_pipeline and pipeline != prev_pipeline:
                      raise ArcanaDesignError(
                          "Attempting to run two different pipelines with the "
                          "same name, {} and {}".format(pipeline, prev_pipeline))
                  # Combined required outputs and filter array with previous
                  # references to the pipeline
                  req_outputs = copy(req_outputs)
                  req_outputs.update(prev_req_outputs)
                  filt_array = filt_array | prev_filt_array
              # If the pipeline to process contains summary outputs (i.e. 'per-
              # subject|visit|study' frequency), then we need to "dialate" the
              # filter array to include IDs across the scope of the study, e.g.
              # all subjects for per-vist, or all visits for per-subject.
              output_freqs = set(pipeline.output_frequencies)
              dialated_filt_array = self._dialate_array(filt_array,
                                                        pipeline.joins)
              added = dialated_filt_array ^ filt_array
              if added.any():
                  filt_array = dialated_filt_array
                  # Invert the index dictionaries to get index-to-ID maps
                  inv_subject_inds = {v: k for k, v in subject_inds.items()}
                  inv_visit_inds = {v: k for k, v in visit_inds.items()}
                  logger.warning(
                      "Dialated filter array used to process '{}' pipeline to "
                      "include {} subject/visit IDs due to its '{}' summary "
                      "outputs ".format(
                          pipeline.name,
                          ', '.join('({},{})'.format(inv_subject_inds[s],
                                                     inv_visit_inds[v])
                                    for s, v in zip(*np.nonzero(added))),
                          "' and '".join(output_freqs)))
  
              stack[pipeline.name] = pipeline, req_outputs, filt_array
              # Recursively add all prerequisites to stack
              for prq_getter, prq_req_outputs in pipeline.prerequisites.items():
                  try:
                      prereq = pipeline.study.pipeline(
                          prq_getter, prq_req_outputs)
                      push_on_stack(prereq, filt_array, prq_req_outputs)
                  except (ArcanaMissingDataException,
                          ArcanaOutputNotProducedException) as e:
                      e.msg += ("{}, which are required as inputs to the '{}' "
                                "pipeline to produce '{}'".format(
                                    pipeline.name, "', '".join(req_outputs)))
                      raise e
  
          # Add all primary pipelines to the stack along with their prereqs
          for pipeline, req_outputs in zip(pipelines, required_outputs):
              push_on_stack(pipeline, filter_array, req_outputs)
  
          # Iterate through stack of required pipelines from upstream to
          # downstream
          for pipeline, req_outputs, flt_array in reversed(list(stack.values())):
              try:
                  self._connect_pipeline(
                      pipeline, req_outputs, workflow, subject_inds, visit_inds,
                      flt_array, **kwargs)
              except ArcanaNoRunRequiredException:
                  logger.info("Not running '{}' pipeline as its outputs "
                              "are already present in the repository"
                              .format(pipeline.name))
          # Save complete graph for debugging purposes
  #         workflow.write_graph(graph2use='flat', format='svg')
  #         print('Graph saved in {} directory'.format(os.getcwd()))
          # Actually run the generated workflow
          result = workflow.run(plugin=self._plugin)
          # Reset the cached tree of filesets in the repository as it will
          # change after the pipeline has run.
          self.study.clear_caches()
          return result