public void update() {
    double t = 0.0;
    double errRatio;
    if (step > samplingStep) step = samplingStep;
    int nSteps = 0;
    for (; ; ) {
      if ((samplingStep - t < step) && (samplingStep - t > 0.0)) step = samplingStep - t;

      rkckStep(step);
      errRatio = Numerics.max(yerr) / tolerance;

      //
      // Update the substance levels and go to the next step if
      // 1. The target tolerance is reached.
      // 2. The maximum # of iteractions is exceeded.
      // 3. The minimum time step is reached.
      //
      if (errRatio <= 1.0) {
        t += step;
        updateSystem(step);
        //
        // grow the step a little bit. but not more than a factor of
        // five
        //
        step *= Math.min(SAFETY * Math.pow(errRatio, PGROW), 5.0);
      } else if (nSteps > maxIterations) {
        System.out.println(" WARNING: # of iterations exceeds " + maxIterations);
        t += step;
        updateSystem(step);
      } else if (step < minStep) {
        System.out.println(" WARNING: Minimum integrateion step size (" + minStep + ") reached");
        t += step;
        updateSystem(step);
      } else {
        // step size too large.
        // Need to reset the values of all the substances
        //
        for (int i = 0; i < numberOfSubstances; i++) s[i].setValue(y1[i]);
        //
        // reset the Timer back to where it started.
        //
        timer.step(0 - step);

        //
        // shrink the step size
        // and recompute. But shrink by a factor smaller than 10.
        //
        step *= Math.max(SAFETY * Math.pow(errRatio, PSHRINK), 0.1);
      }
      if (t >= samplingStep) break;
    }

    //
    // Store the data if the sampling step is reached.
    //
    timer.storeTimePoint();
    for (int i = 0; i < numberOfSubstances; i++) {
      s[i].storeValue();
      s[i].storeRate();
    }
  }