docs: def disaggregation(
          sources, site, imt, iml, gsim_by_trt, truncation_level,
          n_epsilons, mag_bin_width, dist_bin_width, coord_bin_width,
          source_filter=filters.nofilter, filter_distance='rjb'):
      """
      Compute "Disaggregation" matrix representing conditional probability of an
      intensity mesaure type ``imt`` exceeding, at least once, an intensity
      measure level ``iml`` at a geographical location ``site``, given rupture
      scenarios classified in terms of:
  
      - rupture magnitude
      - Joyner-Boore distance from rupture surface to site
      - longitude and latitude of the surface projection of a rupture's point
        closest to ``site``
      - epsilon: number of standard deviations by which an intensity measure
        level deviates from the median value predicted by a GSIM, given the
        rupture parameters
      - rupture tectonic region type
  
      In other words, the disaggregation matrix allows to compute the probability
      of each scenario with the specified properties (e.g., magnitude, or the
      magnitude and distance) to cause one or more exceedences of a given hazard
      level.
  
      For more detailed information about the disaggregation, see for instance
      "Disaggregation of Seismic Hazard", Paolo Bazzurro, C. Allin Cornell,
      Bulletin of the Seismological Society of America, Vol. 89, pp. 501-520,
      April 1999.
  
      :param sources:
          Seismic source model, as for
          :mod:`PSHA <openquake.hazardlib.calc.hazard_curve>` calculator it
          should be an iterator of seismic sources.
      :param site:
          :class:`~openquake.hazardlib.site.Site` of interest to calculate
          disaggregation matrix for.
      :param imt:
          Instance of :mod:`intensity measure type <openquake.hazardlib.imt>`
          class.
      :param iml:
          Intensity measure level. A float value in units of ``imt``.
      :param gsim_by_trt:
          Tectonic region type to GSIM objects mapping.
      :param truncation_level:
          Float, number of standard deviations for truncation of the intensity
          distribution.
      :param n_epsilons:
          Integer number of epsilon histogram bins in the result matrix.
      :param mag_bin_width:
          Magnitude discretization step, width of one magnitude histogram bin.
      :param dist_bin_width:
          Distance histogram discretization step, in km.
      :param coord_bin_width:
          Longitude and latitude histograms discretization step,
          in decimal degrees.
      :param source_filter:
          Optional source-site filter function. See
          :mod:`openquake.hazardlib.calc.filters`.
  
      :returns:
          A tuple of two items. First is itself a tuple of bin edges information
          for (in specified order) magnitude, distance, longitude, latitude,
          epsilon and tectonic region types.
  
          Second item is 6d-array representing the full disaggregation matrix.
          Dimensions are in the same order as bin edges in the first item
          of the result tuple. The matrix can be used directly by pmf-extractor
          functions.
      """
      trts = sorted(set(src.tectonic_region_type for src in sources))
      trt_num = dict((trt, i) for i, trt in enumerate(trts))
      rlzs_by_gsim = {gsim_by_trt[trt]: [0] for trt in trts}
      iml4 = make_iml4(1, {str(imt): iml})
      by_trt = groupby(sources, operator.attrgetter('tectonic_region_type'))
      bdata = {}
      sitecol = SiteCollection([site])
      for trt, srcs in by_trt.items():
          ruptures = []
          for src in srcs:
              ruptures.extend(src.iter_ruptures())
          cmaker = ContextMaker(
              trt, rlzs_by_gsim, source_filter.integration_distance,
              {'filter_distance': filter_distance})
          bdata[trt] = collect_bin_data(
              ruptures, sitecol, cmaker, iml4, truncation_level, n_epsilons)
      if sum(len(bd.mags) for bd in bdata.values()) == 0:
          warnings.warn(
              'No ruptures have contributed to the hazard at site %s'
              % site, RuntimeWarning)
          return None, None
  
      min_mag = min(bd.mags.min() for bd in bdata.values())
      max_mag = max(bd.mags.max() for bd in bdata.values())
      mag_bins = mag_bin_width * numpy.arange(
          int(numpy.floor(min_mag / mag_bin_width)),
          int(numpy.ceil(max_mag / mag_bin_width) + 1))
  
      min_dist = min(bd.dists.min() for bd in bdata.values())
      max_dist = max(bd.dists.max() for bd in bdata.values())
      dist_bins = dist_bin_width * numpy.arange(
          int(numpy.floor(min_dist / dist_bin_width)),
          int(numpy.ceil(max_dist / dist_bin_width) + 1))
  
      bb = (min(bd.lons.min() for bd in bdata.values()),
            min(bd.lats.min() for bd in bdata.values()),
            max(bd.lons.max() for bd in bdata.values()),
            max(bd.lats.max() for bd in bdata.values()))
      lon_bins, lat_bins = lon_lat_bins(bb, coord_bin_width)
  
      eps_bins = numpy.linspace(-truncation_level, truncation_level,
                                n_epsilons + 1)
  
      bin_edges = (mag_bins, dist_bins, [lon_bins], [lat_bins], eps_bins)
      matrix = numpy.zeros((len(mag_bins) - 1, len(dist_bins) - 1,
                            len(lon_bins) - 1, len(lat_bins) - 1,
                            len(eps_bins) - 1, len(trts)))
      for trt in bdata:
          dic = build_disagg_matrix(bdata[trt], bin_edges, sid=0)
          if dic:  # (poe, imt, rlzi) -> matrix
              [mat] = dic.values()
              matrix[..., trt_num[trt]] = mat
      return bin_edges + (trts,), matrix