/**
   * Constructor takes a lane's collection of Tiles and calculates the median phasing/prephasing for
   * the first and second (if available) reads
   */
  public LanePhasingMetricsCollector(final Collection<Tile> laneTiles) {
    final Map<TileTemplateRead, Float> medianPhasingMapLocal =
        new TreeMap<TileTemplateRead, Float>();
    final Map<TileTemplateRead, Float> medianPrePhasingMapLocal =
        new TreeMap<TileTemplateRead, Float>();

    final CollectionUtil.MultiMap<TileTemplateRead, Float> phasingValues =
        new CollectionUtil.MultiMap<TileTemplateRead, Float>();
    final CollectionUtil.MultiMap<TileTemplateRead, Float> prePhasingValues =
        new CollectionUtil.MultiMap<TileTemplateRead, Float>();

    // Collect the phasing/prephasing values from all of the tiles, sorted by template read #
    for (final Tile tile : laneTiles) {
      for (final TileTemplateRead tileTemplateRead : tile.getPhasingMap().keySet()) {
        phasingValues.append(tileTemplateRead, tile.getPhasingMap().get(tileTemplateRead));
        prePhasingValues.append(tileTemplateRead, tile.getPrePhasingMap().get(tileTemplateRead));
      }
    }

    // Calculate the medians for the collected data
    for (final TileTemplateRead tileTemplateRead : phasingValues.keySet()) {
      medianPhasingMapLocal.put(
          tileTemplateRead, medianPercentage(phasingValues.get(tileTemplateRead)));
      medianPrePhasingMapLocal.put(
          tileTemplateRead, medianPercentage(prePhasingValues.get(tileTemplateRead)));
    }

    this.medianPhasingMap = Collections.unmodifiableMap(medianPhasingMapLocal);
    this.medianPrePhasingMap = Collections.unmodifiableMap(medianPrePhasingMapLocal);
  }
 private static double calculateLaneDensityFromTiles(final Collection<Tile> tiles) {
   double area = 0;
   double clusters = 0;
   for (final Tile tile : tiles) {
     area += (tile.getClusterCount() / tile.getClusterDensity());
     clusters += tile.getClusterCount();
   }
   return clusters / area;
 }