@Override
  public void trigger(double time) {
    Measure m = new Measure();
    m.time = time;
    int cnt = 0;
    double dsCnt = 0;
    double usCnt = 0;
    double dsRho = 0;
    double usRho = 0;
    for (int lane = 0; lane < this.lanes; lane++) {
      CAMoveableEntity[] p = this.l.getParticles(lane);
      for (int i = this.from; i <= this.to; i++) {
        if (p[i] != null) {
          cnt++;
          m.in.add(p[i].getId());
          AgentInfo ai = this.ais.get(p[i].getId());
          // updateTimeRho(i, ai.dir, ai, time, p);
          if (p[i].getDir() == 1) {

            dsCnt++;
            // dsRho += ai.timeRho.get(time);
          } else {
            usCnt++;
            // usRho += ai.timeRho.get(time);
          }
        }
      }
    }
    double rho = cnt / this.a;

    m.rho = rho;
    m.dsRho = dsCnt / this.a;
    m.usRho = usCnt / this.a;
    // m.dsRho = dsRho / dsCnt;
    // m.usRho = usRho / usCnt;

    for (int lane = 0; lane < this.lanes; lane++) {
      CAMoveableEntity[] p = this.l.getParticles(lane);
      for (int i = 0; i < this.l.getNumOfCells(); i++) {
        CAMoveableEntity part = p[i];
        if (part != null) {
          Id id = part.getId();
          AgentInfo ai = this.ais.get(id);
          if (ai == null && (i == 0 || i == this.l.getNumOfCells() - 1)) {
            ai = new AgentInfo(part.getDir());
            // ai.lastPos = i;
            this.ais.put(id, ai);
          }
          if (ai.lastPos != i) {
            ai.timePos.put(time, i);
            ai.lastPos = i;
            if (i == 0) {
              if (part.getDir() == 1) {
                this.dsIn++;
              } else {
                this.usOut++;
              }
            } else if (i == this.l.getNumOfCells() - 1) {
              if (part.getDir() == 1) {
                this.dsOut++;
              } else {
                this.usIn++;
              }
            }
          }
        }
      }
    }
    if (m.rho > 0) {
      this.ms.add(m);
    }
  }
  @Override
  public void report(BufferedWriter bw) throws IOException {
    int in = this.dsIn + this.usIn - this.dsOut - this.usOut;
    System.out.println(
        in
            + " "
            + " dsIn:"
            + this.dsIn
            + " dsOut:"
            + this.dsOut
            + " usIn:"
            + this.usIn
            + " usOut:"
            + this.usOut);

    List<Tuple<Integer, Integer>> ranges = new ArrayList<>();
    Variance vd = new Variance();
    Variance vs = new Variance();
    Variance vf = new Variance();
    int cnt = 0;
    double tm = 15;
    int from = 0;
    int to = 0;
    for (Measure m : this.ms) {
      cpdSpd(m);
      bw.append(
          m.time + " " + m.dsRho + " " + m.dsSpd + " " + m.usRho + " " + m.usSpd + " " + m.rho + " "
              + " " + m.spd + "\n");

      if (true) continue;
      if (m.time < 15 || m.time > 100) {
        to++;
        from++;
        continue;
      }
      cpdSpd(m);
      vd.addVar(m.rho);
      vs.addVar(m.spd);
      vf.addVar(m.rho * m.spd);
      cnt++;
      if (cnt < 5) {
        to++;
        continue;
      }
      double md = vd.getMean();
      double std = Math.sqrt(vd.getVar());

      double ms = vs.getMean();
      double sts = Math.sqrt(vs.getVar());

      double mf = vf.getMean();
      double stf = Math.sqrt(vf.getVar());

      double bal = m.dsRho / m.usRho;
      bal = bal > 1 ? 1 / bal : bal;
      // bal = 1;
      double timespan = m.time - tm;
      if (md > 1 && std > 0.1 * md || sts > 0.1 * ms || bal < 0.5 || timespan > 20) {
        if (timespan > 5) {
          Tuple<Integer, Integer> t = new Tuple<>(from, to);
          ranges.add(t);
        }
        tm = m.time;
        from = to;
        cnt = 0;
        vd = new Variance();
        vs = new Variance();
      }
      to++;
    }

    int rng = ranges.size();
    int cntt = 0;
    for (Tuple<Integer, Integer> r : ranges) {
      cntt++;
      // if (cntt < rng / 2 + rng / 4 || cntt > rng / 2 + rng / 4 + rng /
      // 8) {
      // continue;
      // }
      from = r.getFirst();
      to = r.getSecond();
      Measure m = new Measure();

      double range = to - from;
      double ccnt = 0;
      double lastTime = 0;
      for (int idx = from; idx < to; idx++) {
        Measure mm = this.ms.get(idx);
        if (lastTime + 1 > mm.time) {
          continue;
        }
        ccnt++;
        m.rho += mm.rho;
        m.spd += mm.spd;
        m.time += mm.time;
        m.dsRho += mm.dsRho;
        m.usRho += mm.usRho;
        m.dsSpd += mm.dsSpd;
        m.usSpd += mm.usSpd;
        bw.append(
            mm.time + " " + mm.dsRho + " " + mm.dsSpd + " " + mm.usRho + " " + mm.usSpd + " "
                + mm.rho + " " + " " + mm.spd + "\n");
        lastTime = mm.time;
      }
      m.rho /= ccnt;
      m.spd /= ccnt;
      m.dsRho /= ccnt;
      m.dsSpd /= ccnt;
      m.usRho /= ccnt;
      m.usSpd /= ccnt;
      m.time /= ccnt;
      // bw.append(m.time + " " + m.dsRho + " " + m.dsSpd + " " + m.usRho
      // + " " + m.usSpd + " " + m.rho + " " + " " + m.spd + "\n");

    }
    // bw.append(m.time + " " + m.rho + " " + m.spd + "\n");

  }