@Override
  public void notifyIterationEnds(IterationEndsEvent event) {

    // Store and write out some aggregated numbers for analysis purposes.

    this.iteration2totalDelay.put(event.getIteration(), this.delayComputation.getTotalDelay());
    this.iteration2totalTollPayments.put(
        event.getIteration(), this.intervalBasedTolling.getTotalTollPayments());
    this.iteration2totalTravelTime.put(
        event.getIteration(), this.delayComputation.getTotalTravelTime());

    double monetizedUserBenefits = 0.;
    for (Person person : this.congestionInfo.getScenario().getPopulation().getPersons().values()) {
      monetizedUserBenefits =
          monetizedUserBenefits
              + person.getSelectedPlan().getScore()
                  / this.congestionInfo
                      .getScenario()
                      .getConfig()
                      .planCalcScore()
                      .getMarginalUtilityOfMoney();
    }
    this.iteration2userBenefits.put(event.getIteration(), monetizedUserBenefits);

    CongestionInfoWriter.writeIterationStats(
        this.iteration2totalDelay,
        this.iteration2totalTollPayments,
        this.iteration2totalTravelTime,
        this.iteration2userBenefits,
        this.congestionInfo.getScenario().getConfig().controler().getOutputDirectory());

    XYLineChart chart1 = new XYLineChart("Total travel time and total delay", "Iteration", "Hours");
    double[] iterations1 = new double[event.getIteration() + 1];
    double[] values1a = new double[event.getIteration() + 1];
    double[] values1b = new double[event.getIteration() + 1];
    for (int i = this.congestionInfo.getScenario().getConfig().controler().getFirstIteration();
        i <= event.getIteration();
        i++) {
      iterations1[i] = i;
      values1a[i] = this.iteration2totalDelay.get(i) / 3600.;
      values1b[i] = this.iteration2totalTravelTime.get(i) / 3600.;
    }
    chart1.addSeries("Total delay", iterations1, values1a);
    chart1.addSeries("Total travel time", iterations1, values1b);
    chart1.saveAsPng(
        this.congestionInfo.getScenario().getConfig().controler().getOutputDirectory()
            + "travelTime_delay.png",
        800,
        600);

    XYLineChart chart2 =
        new XYLineChart(
            "System welfare, user benefits and toll revenues", "Iteration", "Monetary units");
    double[] iterations2 = new double[event.getIteration() + 1];
    double[] values2a = new double[event.getIteration() + 1];
    double[] values2b = new double[event.getIteration() + 1];
    double[] values2c = new double[event.getIteration() + 1];

    for (int i = this.congestionInfo.getScenario().getConfig().controler().getFirstIteration();
        i <= event.getIteration();
        i++) {
      iterations2[i] = i;
      values2a[i] = this.iteration2userBenefits.get(i) + this.iteration2totalTollPayments.get(i);
      values2b[i] = this.iteration2userBenefits.get(i);
      values2c[i] = this.iteration2totalTollPayments.get(i);
    }
    chart2.addSeries("System welfare", iterations2, values2a);
    chart2.addSeries("User benefits", iterations2, values2b);
    chart2.addSeries("Toll revenues", iterations2, values2c);
    chart2.saveAsPng(
        this.congestionInfo.getScenario().getConfig().controler().getOutputDirectory()
            + "systemWelfare_userBenefits_tollRevenues.png",
        800,
        600);
  }
  @Override
  public void notifyAfterMobsim(AfterMobsimEvent event) {

    if (event.getIteration()
                % this.congestionInfo.getDecongestionConfigGroup().getWRITE_OUTPUT_ITERATION()
            == 0.
        || event.getIteration()
                % this.congestionInfo.getDecongestionConfigGroup().getUPDATE_PRICE_INTERVAL()
            == 0.) {
      computeDelays(event);
    }

    if (event.getIteration()
        == this.congestionInfo.getScenario().getConfig().controler().getFirstIteration()) {
      // skip first iteration

    } else if (event.getIteration()
            % this.congestionInfo.getDecongestionConfigGroup().getUPDATE_PRICE_INTERVAL()
        == 0.) {

      int totalNumberOfIterations =
          this.congestionInfo.getScenario().getConfig().controler().getLastIteration()
              - this.congestionInfo.getScenario().getConfig().controler().getFirstIteration();
      int iterationCounter =
          event.getIteration()
              - this.congestionInfo.getScenario().getConfig().controler().getFirstIteration();

      if (iterationCounter
              < this.congestionInfo
                      .getDecongestionConfigGroup()
                      .getFRACTION_OF_ITERATIONS_TO_END_PRICE_ADJUSTMENT()
                  * totalNumberOfIterations
          && iterationCounter
              > this.congestionInfo
                      .getDecongestionConfigGroup()
                      .getFRACTION_OF_ITERATIONS_TO_START_PRICE_ADJUSTMENT()
                  * totalNumberOfIterations) {

        log.info("+++ Iteration " + event.getIteration() + ". Update tolls per link and time bin.");
        tollComputation.updateTolls(event.getIteration());
      }
    }

    if (event.getIteration()
            % this.congestionInfo.getDecongestionConfigGroup().getWRITE_OUTPUT_ITERATION()
        == 0.) {
      CongestionInfoWriter.writeDelays(
          congestionInfo,
          event.getIteration(),
          this.congestionInfo.getScenario().getConfig().controler().getOutputDirectory()
              + "ITERS/it."
              + event.getIteration()
              + "/");
      CongestionInfoWriter.writeTolls(
          congestionInfo,
          event.getIteration(),
          this.congestionInfo.getScenario().getConfig().controler().getOutputDirectory()
              + "ITERS/it."
              + event.getIteration()
              + "/");
    }
  }