docs: def autofocus_stack(fieldstack, nm, res, ival, roi=None,
                      metric="average gradient", padding=True,
                      same_dist=False, ret_ds=False, ret_grads=False,
                      num_cpus=_cpu_count, copy=True):
      """Numerical autofocusing of a stack using the Helmholtz equation.
  
  
      Parameters
      ----------
      fieldstack : 2d or 3d ndarray
          Electric field is BG-Corrected, i.e. Field = EX/BEx
      nm : float
          Refractive index of medium.
      res : float
          Size of wavelength in pixels.
      ival : tuple of floats
          Approximate interval to search for optimal focus in px.
      metric : str
          see `autofocus_field`.
      padding : bool
          Perform padding with linear ramp from edge to average
          to reduce ringing artifacts.
  
          .. versionchanged:: 0.1.4
             improved padding value and padding location
      ret_dopt : bool
          Return optimized distance and gradient plotting data.
      same_dist : bool
          Refocus entire sinogram with one distance.
      red_ds : bool
          Return the autofocusing distances in pixels. Defaults to False.
          If sam_dist is True, still returns autofocusing distances
          of first pass. The used refocusing distance is the
          average.
      red_grads : bool
          Return the computed gradients as a list.
      copy : bool
          If False, overwrites input array.
  
  
      Returns
      -------
      The focused field (and the refocussing distance + data if d is None)
      """
      dopt = list()
      grad = list()
  
      M = fieldstack.shape[0]
  
      # setup arguments
      stackargs = list()
      for s in range(M):
          stackargs.append([fieldstack[s].copy(copy), nm, res, ival,
                            roi, metric, padding, True, True, 1])
      # perform first pass
      p = mp.Pool(num_cpus)
      result = p.map_async(_autofocus_wrapper, stackargs).get()
      p.close()
      p.terminate()
      p.join()
      # result = []
      # for arg in stackargs:
      #    result += _autofocus_wrapper(arg)
  
      newstack = np.zeros(fieldstack.shape, dtype=fieldstack.dtype)
  
      for s in range(M):
          field, ds, gs = result[s]
          dopt.append(ds)
          grad.append(gs)
          newstack[s] = field
  
      # perform second pass if `same_dist` is True
      if same_dist:
          # find average dopt
          davg = np.average(dopt)
          newstack = refocus_stack(fieldstack, davg, nm, res,
                                   num_cpus=num_cpus, copy=copy,
                                   padding=padding)
  
      ret_list = [newstack]
      if ret_ds:
          ret_list += [dopt]
      if ret_grads:
          ret_list += [grad]
  
      if len(ret_list) == 1:
          return ret_list[0]
      else:
          return tuple(ret_list)