/**
   * Initializes the controller and returns the number of ticks for the first simulation run
   *
   * @return
   */
  public synchronized long initialize() {
    error = 1e+10;
    repetition = 0;
    counter = 0;

    Coordinator c = Coordinator.getInstance();

    if (parameterSweep != null) {
      parameterSweep.setInitialValuesAndAdvance();
    }

    currentParameters = VariableSetFactory.createVariableSet("batch@run@current@set");
    currentParameters.synchronizeWithParameters(c.getParameters());
    goodParameters = null;

    if (log != null) {
      log.print("Run,Repetition,Error,");
      log.println(currentParameters.getVariableNames());
    }

    for (Render render : Coordinator.getInstance().getRenders()) {
      render.setSnapshotNamePrefix("" + counter + "-" + repetition + "-");
    }

    // Register the data layer saver
    dataLayerSaver.setFileNamePrefix("" + counter + "-" + repetition + "-");
    c.getDataReceiver().addDataConsumer(dataLayerSaver.getFilter());

    return numberOfTicks;
  }
  /** Sets options for saving data layers */
  public void setDataLayers(String[] names, int interval, int precision, boolean oneFileFlag) {
    dataLayerSaver.removeAllDataLayers();

    dataLayerSaver.setOneFileFlag(oneFileFlag);
    dataLayerSaver.setPrecision(precision);
    dataLayerSaver.getFilter().setInterval(interval);

    for (String name : names) {
      dataLayerSaver.addDataLayer(name);
    }
  }
  /** This function is called when all runs are done */
  void stop() {
    dataLayerSaver.clear();
    Coordinator.getInstance().getDataReceiver().removeDataConsumer(dataLayerSaver.getFilter());

    if (goodParameters != null) {
      if (log != null) {
        log.println();
        log.print(goodCounter);
        log.print(',');
        log.print(goodRepetition);
        log.print(',');
        log.print(error);
        log.print(',');
        log.println(goodParameters.getVariableValues());
        log.flush();
      }
    }

    if (log != null) {
      log.close();
      log = null;
    }
  }
  /**
   * Saves collected data, begins a new simulation step, and return the number of ticks for the new
   * step. If ticks number == 0, then end the batch process.
   *
   * @return
   */
  public synchronized long nextStep(DataSet dataSet) {
    // Save data
    if (saveDataFlag) {
      saveData();
    }

    // Save snapshots
    if (saveFinalSnapshots) {
      for (Render render : Coordinator.getInstance().getRenders()) {
        render.takeSnapshot("" + counter + "-" + repetition + "-");
      }
    }

    // Analyze data
    if (dataAnalyzer != null && dataSet != null) {
      double err = dataAnalyzer.analyze(dataSet, variableName);

      if (log != null) {
        log.print(counter);
        log.print(',');
        log.print(repetition);
        log.print(',');
        log.print(err);
        log.print(',');
        log.println(currentParameters.getVariableValues());
        log.flush();
      }

      if (err < error) {
        error = err;
        goodCounter = counter;
        goodRepetition = repetition;
        goodParameters = currentParameters;
      }
    }

    if (dataSet != null) {
      dataSet.clear();
    }

    dataLayerSaver.clear();

    repetition++;
    if (repetition >= numberOfRepetition) {
      if (parameterSweep != null) {
        if (!parameterSweep.setCurrentValuesAndAdvance()) {
          stop();
          return 0;
        }

        repetition = 0;
        counter++;
      } else {
        stop();
        return 0;
      }
    }

    currentParameters = VariableSetFactory.createVariableSet("batch@run@current@set");
    currentParameters.synchronizeWithParameters(Coordinator.getInstance().getParameters());

    for (Render render : Coordinator.getInstance().getRenders()) {
      render.setSnapshotNamePrefix("" + counter + "-" + repetition + "-");
    }

    dataLayerSaver.setFileNamePrefix("" + counter + "-" + repetition + "-");

    return numberOfTicks;
  }