Example #1
0
  /**
   * initialize before simulation begins. Rewind/forward any population model values to the start
   * time of the sequencer
   *
   * @param time
   */
  public void initialize(STEMTime time) {
    EList<Decorator> redoList = new BasicEList<Decorator>();

    boolean redo = false;
    for (Decorator d : this.getDecorators()) {
      if (d instanceof IntegrationDecorator) {
        EList<DynamicLabel> labels = d.getLabelsToUpdate();
        for (DynamicLabel l : labels) {
          if (l instanceof IntegrationLabel) {
            IntegrationLabel il = (IntegrationLabel) l;
            il.reset(time);
            if (((SimpleDataExchangeLabelValue) il.getDeltaValue()).getArrivals().size() > 0
                || ((SimpleDataExchangeLabelValue) il.getDeltaValue()).getDepartures().size() > 0)
              redo = true;
          }
        }
      }
      if (!redo) redoList.add(d);
    }
    // Fix decorators with unapplied deltas
    if (redo) {
      for (Decorator d : redoList) {
        if (d instanceof IntegrationDecorator) {
          EList<DynamicLabel> labels = d.getLabelsToUpdate();
          for (DynamicLabel l : labels) {
            if (l instanceof IntegrationLabel) {
              IntegrationLabel il = (IntegrationLabel) l;
              il.reset(time);
            }
          }
        }
      }
    }
    this.setInitialized(true);
  }
Example #2
0
  /**
   * _step Do the step for a single thread
   *
   * @param time
   * @param timeDelta
   * @param cycle
   * @param threadnum
   */
  protected void _step(STEMTime time, long timeDelta, int cycle, short threadnum) {
    //		this.setProgress(0.0);
    // We only deal with standard disease model decorators

    ArrayList<Decorator> iDecorators = new ArrayList<Decorator>();

    for (Decorator d : getDecorators()) {
      if (d instanceof IntegrationDecorator) iDecorators.add(d);
    }

    // First we get the step size, either the default step size
    // (initially 1.0) or the last step size used.

    double h = this.getStepSize();
    // x is to keep track of how far we have advanced in the solution. It is essentially
    // a double cycle representation

    double x = this.getCurrentX();

    // Substantial performance can be gained here. Basically if the current cycle
    // is greater than the cycle requested by the simulation, we are done. This
    // means that the error tolerance between last step and this step is small
    // enough so we don't need to update the labels. The error tolerance is
    // specified in the disease model

    // *** OBSERVE: Since we limit h to max 1 below, this code is never invoked. It's kept
    // *** around in case we want to allow time to be calculated far out in the future if
    // *** the error is small enough

    if (x >= cycle) {
      // Just copy the next value the same as the current value for all labels
      for (Decorator sdm : iDecorators) {
        EList<DynamicLabel> myLabels = sdm.getLabelsToUpdate(threadnum, num_threads);
        int numLabels = myLabels.size();
        double n = 0.0;
        int setProgressEveryNthNode = num_threads * numLabels / (MAX_PROGRESS_REPORTS);
        if (setProgressEveryNthNode == 0) setProgressEveryNthNode = 1;
        for (final Iterator<DynamicLabel> currentStateLabelIter = myLabels.iterator();
            currentStateLabelIter.hasNext(); ) {
          final IntegrationLabel diseaseLabel = (IntegrationLabel) currentStateLabelIter.next();

          // The estimated disease value contains the value calculated at position x

          IntegrationLabelValue nextValueAtX =
              (IntegrationLabelValue) EcoreUtil.copy(diseaseLabel.getProbeValue());
          IntegrationLabelValue currentValueAtCycle =
              (IntegrationLabelValue) diseaseLabel.getCurrentValue();
          IntegrationLabelValue nextState = (IntegrationLabelValue) diseaseLabel.getNextValue();
          adjustValuesToCycle(currentValueAtCycle, nextValueAtX, x, cycle);
          // NextValueAtX has been modified here to the correct value for this cycle.
          nextState.set(nextValueAtX);
          // The next value is valid now.
          diseaseLabel.setNextValueValid(true);
          double progress = n / numLabels;
          jobs[threadnum].setProgress(progress);
          if (n % setProgressEveryNthNode == 0) {
            // Get the progress for all threads
            for (int i = 0; i < num_threads; ++i)
              if (i != threadnum && jobs[i] != null) progress += jobs[i].getProgress();
            progress /= num_threads;
            sdm.setProgress(progress);
          }
          n += 1.0;
        }
      } // For each decorator
      // So that validation code above is happy
      jobs[threadnum].h = h;
      jobs[threadnum].t = x;

      return;
    }

    // When x (or time) is this we're done
    double end = Math.floor(this.getCurrentX()) + 1.0;

    // Make sure we actually have labels to update
    boolean workToDo = false;
    for (Decorator sdm : iDecorators)
      if (sdm.getLabelsToUpdate(threadnum, num_threads).size() > 0) {
        workToDo = true;
        break;
      }

    if (!workToDo) {
      // Nothing to do, just advance x and set h
      jobs[threadnum].h = h;
      jobs[threadnum].t = x;
      // Be nice and walk in step with others until done
      while (x < end) {
        try {
          // Set to a large number to make sure it's larger than any step size reported
          // by another thread
          do {
            jobs[threadnum].h = Double.MAX_VALUE;
            stepSizeBarrier.await();
          } while (this.maximumError > 1.0);
          updateDoneBarrier.await();
        } catch (InterruptedException ie) {
          // Should never happen
          Activator.logError(ie.getMessage(), ie);
        } catch (BrokenBarrierException bbe) {
          // Should never happen
          Activator.logError(bbe.getMessage(), bbe);
        }
        // Set to the smallest value reported by another thread
        h = this.smallestH;
        x += h;
        jobs[threadnum].h = h;
        jobs[threadnum].t = x;
      }
      return;
    }
    // We use the Runge Kutta Kash Carp method to advance to the next
    // step in the simulation. Two estimates of the disease deltas
    // are calculated and compared to each other. If they differ
    // by more than a maximum error (determined by a parameter for
    // the disease model), we reduce the step size until an acceptable
    // error is reached.

    // These are used during Runge Kutta calculations:
    Map<IntegrationLabel, IntegrationLabelValue> k1map =
        new HashMap<IntegrationLabel, IntegrationLabelValue>();
    Map<IntegrationLabel, IntegrationLabelValue> k2map =
        new HashMap<IntegrationLabel, IntegrationLabelValue>();
    Map<IntegrationLabel, IntegrationLabelValue> k3map =
        new HashMap<IntegrationLabel, IntegrationLabelValue>();
    Map<IntegrationLabel, IntegrationLabelValue> k4map =
        new HashMap<IntegrationLabel, IntegrationLabelValue>();
    Map<IntegrationLabel, IntegrationLabelValue> k5map =
        new HashMap<IntegrationLabel, IntegrationLabelValue>();
    Map<IntegrationLabel, IntegrationLabelValue> k6map =
        new HashMap<IntegrationLabel, IntegrationLabelValue>();

    // Used below as temporary place holder, one for each decorator
    IntegrationLabelValue _k1[], _k2[], _k3[], _k4[], _k5[], _k6[];
    int numDecorators = iDecorators.size();
    _k1 = new IntegrationLabelValue[numDecorators];
    _k2 = new IntegrationLabelValue[numDecorators];
    _k3 = new IntegrationLabelValue[numDecorators];
    _k4 = new IntegrationLabelValue[numDecorators];
    _k5 = new IntegrationLabelValue[numDecorators];
    _k6 = new IntegrationLabelValue[numDecorators];

    // The final estimates for label values are stored here
    Map<IntegrationLabel, IntegrationLabelValue> finalEstimate =
        new HashMap<IntegrationLabel, IntegrationLabelValue>();

    // Delta is used to scale the step (h)
    double delta = 0.0;

    int n = 0;
    for (Decorator sdm : iDecorators) {
      Iterator<DynamicLabel> iter = sdm.getLabelsToUpdate(threadnum, num_threads).iterator();
      IntegrationLabel firstLabel = (IntegrationLabel) iter.next();
      // Initialize temporary place holders just by creating dups of the first label available
      _k1[n] = (IntegrationLabelValue) EcoreUtil.copy(firstLabel.getCurrentValue());
      _k2[n] = (IntegrationLabelValue) EcoreUtil.copy(firstLabel.getCurrentValue());
      _k3[n] = (IntegrationLabelValue) EcoreUtil.copy(firstLabel.getCurrentValue());
      _k4[n] = (IntegrationLabelValue) EcoreUtil.copy(firstLabel.getCurrentValue());
      _k5[n] = (IntegrationLabelValue) EcoreUtil.copy(firstLabel.getCurrentValue());
      _k6[n++] = (IntegrationLabelValue) EcoreUtil.copy(firstLabel.getCurrentValue());
    }

    // Keep track if whether anyone want to stop
    // or pause updating labels
    boolean interrupt = false, pause = false;

    // We keep these around to determine when to call setProgress(...) on the decorators.
    // If we call too frequently we can too many callbacks which affects performance.
    double nextProgressReportStep = num_threads * (end - x) / MAX_PROGRESS_REPORTS;
    double nextProgressReport = x + nextProgressReportStep;

    //		HashMap<StandardDiseaseModelLabel, StandardDiseaseModelLabelValue> validate = new
    //			HashMap<StandardDiseaseModelLabel, StandardDiseaseModelLabelValue>();

    // This is the main loop we keep iterating over until we are done with the step
    while (x < end) {
      k1map.clear();
      k2map.clear();
      k3map.clear();
      k4map.clear();
      k5map.clear();
      k6map.clear();
      finalEstimate.clear();

      // Validation code kept here if needed in the future

      /*

        HashMap<StandardDiseaseModelLabel, StandardDiseaseModelLabelValue> validate = new HashMap<StandardDiseaseModelLabel, StandardDiseaseModelLabelValue>();


      if(!redo)
      	for(StandardDiseaseModelImpl sdm:diseaseModelDecorators) {
      		for (final Iterator<DynamicLabel> currentStateLabelIter = sdm.getLabelsToUpdate(threadnum, num_threads)
      			.iterator(); currentStateLabelIter.hasNext();) {
      			final StandardDiseaseModelLabel diseaseLabel = (StandardDiseaseModelLabel) currentStateLabelIter
      			.next();
      			final StandardDiseaseModelLabelValue val = (StandardDiseaseModelLabelValue)diseaseLabel.getCurrentDiseaseModelTempLabelValue();
      			validate.put(diseaseLabel, val);
      		}
      	}
      else {
      	for(StandardDiseaseModelImpl sdm:diseaseModelDecorators)
      		for (final Iterator<DynamicLabel> currentStateLabelIter = sdm.getLabelsToUpdate(threadnum, num_threads)
      				.iterator(); currentStateLabelIter.hasNext();) {
      				final StandardDiseaseModelLabel diseaseLabel = (StandardDiseaseModelLabel) currentStateLabelIter
      				.next();
      				final SIRLabelValue val = (SIRLabelValue)diseaseLabel.getCurrentDiseaseModelTempLabelValue();
      				validate.put(diseaseLabel, val);
      				final SIRLabelValue oldVal = (SIRLabelValue)validate.get(diseaseLabel);

      				if(val.getI() != oldVal.getI() ||
      						val.getS() != oldVal.getS() ||
      						val.getR() != oldVal.getR() ||
      						//val.getE() != oldVal.getE() ||
      						val.getBirths() != oldVal.getBirths() ||
      						val.getDeaths() != oldVal.getDeaths() ||
      						val.getDiseaseDeaths() != oldVal.getDiseaseDeaths()
      						)
      					Activator.logError("Error, old and new value not the same  label: "+diseaseLabel, new Exception());
      		}
      }
      */

      // ToDo: We should check if a maximum number of iterations have been
      // exceeded here and throw an error.

      // First, get the delta values at the current state
      for (Decorator sdm : iDecorators)
        ((IntegrationDecorator) sdm)
            .calculateDelta(time, timeDelta, sdm.getLabelsToUpdate(threadnum, num_threads));
      for (Decorator sdm : iDecorators)
        ((IntegrationDecorator) sdm)
            .applyExternalDeltas(time, timeDelta, sdm.getLabelsToUpdate(threadnum, num_threads));

      // Set the scaling factor for disease parameters for each decorator and location
      for (Decorator sdm : iDecorators) {
        for (final Iterator<DynamicLabel> currentStateLabelIter =
                sdm.getLabelsToUpdate(threadnum, num_threads).iterator();
            currentStateLabelIter.hasNext(); ) {
          final IntegrationLabel diseaseLabel = (IntegrationLabel) currentStateLabelIter.next();

          IntegrationLabelValue scale = (IntegrationLabelValue) diseaseLabel.getErrorScale();
          scale.set((IntegrationLabelValue) diseaseLabel.getTempValue());

          IntegrationLabelValue dt =
              (IntegrationLabelValue) EcoreUtil.copy(diseaseLabel.getDeltaValue());
          dt.scale(h);
          dt.abs();
          dt.add(TINY);
          scale.abs();
          scale.add(dt);
        }
      }

      // Step 1 in Runge Kutta Fehlberg.
      // Get the delta values out of each node label and
      // build a first estimate of the next value'
      for (Decorator sdm : iDecorators) {
        for (final Iterator<DynamicLabel> currentStateLabelIter =
                sdm.getLabelsToUpdate(threadnum, num_threads).iterator();
            currentStateLabelIter.hasNext(); ) {
          final IntegrationLabel diseaseLabel = (IntegrationLabel) currentStateLabelIter.next();

          IntegrationLabelValue deltaLabel = (IntegrationLabelValue) diseaseLabel.getDeltaValue();
          k1map.put(diseaseLabel, (IntegrationLabelValue) EcoreUtil.copy(deltaLabel));

          deltaLabel.scale(h);
          deltaLabel.scale(b21);
          ((IntegrationLabelValue) diseaseLabel.getProbeValue())
              .set(deltaLabel.add((IntegrationLabelValue) diseaseLabel.getTempValue()));
        }
      }

      // Now get the next delta values
      for (Decorator sdm : iDecorators)
        ((IntegrationDecorator) sdm)
            .calculateDelta(time, timeDelta, sdm.getLabelsToUpdate(threadnum, num_threads));
      for (Decorator sdm : iDecorators)
        ((IntegrationDecorator) sdm)
            .applyExternalDeltas(time, timeDelta, sdm.getLabelsToUpdate(threadnum, num_threads));

      // Step 2 in Runge Kutta Fehlberg.
      // Get the delta values out of each node label and
      // build a second estimate of the next value
      n = 0;
      for (Decorator sdm : iDecorators) {
        for (final Iterator<DynamicLabel> currentStateLabelIter =
                sdm.getLabelsToUpdate(threadnum, num_threads).iterator();
            currentStateLabelIter.hasNext(); ) {
          final IntegrationLabel diseaseLabel = (IntegrationLabel) currentStateLabelIter.next();

          IntegrationLabelValue deltaLabel = (IntegrationLabelValue) diseaseLabel.getDeltaValue();
          k2map.put(diseaseLabel, (IntegrationLabelValue) EcoreUtil.copy(deltaLabel));
          _k1[n].set(k1map.get(diseaseLabel));
          _k2[n].set(deltaLabel);

          IntegrationLabelValue estDelta = _k1[n].scale(b31);
          _k2[n].scale(b32);
          estDelta.add(_k2[n]);

          estDelta.scale(h);

          ((IntegrationLabelValue) diseaseLabel.getProbeValue())
              .set(estDelta.add((IntegrationLabelValue) diseaseLabel.getTempValue()));
        }
        ++n;
      }

      // Now get the next delta values
      for (Decorator sdm : iDecorators)
        ((IntegrationDecorator) sdm)
            .calculateDelta(time, timeDelta, sdm.getLabelsToUpdate(threadnum, num_threads));
      for (Decorator sdm : iDecorators)
        ((IntegrationDecorator) sdm)
            .applyExternalDeltas(time, timeDelta, sdm.getLabelsToUpdate(threadnum, num_threads));

      // Step 3 in Runge Kutta Fehlberg.
      // Get the delta values out of each node label and
      // build a third estimate of the next value
      n = 0;
      for (Decorator sdm : iDecorators) {
        for (final Iterator<DynamicLabel> currentStateLabelIter =
                sdm.getLabelsToUpdate(threadnum, num_threads).iterator();
            currentStateLabelIter.hasNext(); ) {
          final IntegrationLabel diseaseLabel = (IntegrationLabel) currentStateLabelIter.next();

          IntegrationLabelValue deltaLabel = (IntegrationLabelValue) diseaseLabel.getDeltaValue();
          k3map.put(diseaseLabel, (IntegrationLabelValue) EcoreUtil.copy(deltaLabel));

          _k1[n].set(k1map.get(diseaseLabel));
          _k2[n].set(k2map.get(diseaseLabel));
          _k3[n].set(deltaLabel);

          _k1[n].scale(b41);
          _k2[n].scale(b42);
          _k3[n].scale(b43);
          IntegrationLabelValue estDelta = _k1[n];
          estDelta.add(_k2[n]);
          estDelta.add(_k3[n]);

          estDelta.scale(h);

          ((IntegrationLabelValue) diseaseLabel.getProbeValue())
              .set(estDelta.add((IntegrationLabelValue) diseaseLabel.getTempValue()));
        }
        ++n;
      }

      // Now get the next delta values
      for (Decorator sdm : iDecorators)
        ((IntegrationDecorator) sdm)
            .calculateDelta(time, timeDelta, sdm.getLabelsToUpdate(threadnum, num_threads));
      for (Decorator sdm : iDecorators)
        ((IntegrationDecorator) sdm)
            .applyExternalDeltas(time, timeDelta, sdm.getLabelsToUpdate(threadnum, num_threads));

      // Step 4 in Runge Kutta Fehlberg.
      // Get the delta values out of each node label and
      // build a fourth estimate of the next value
      n = 0;
      for (Decorator sdm : iDecorators) {
        for (final Iterator<DynamicLabel> currentStateLabelIter =
                sdm.getLabelsToUpdate(threadnum, num_threads).iterator();
            currentStateLabelIter.hasNext(); ) {
          final IntegrationLabel diseaseLabel = (IntegrationLabel) currentStateLabelIter.next();

          IntegrationLabelValue deltaLabel = (IntegrationLabelValue) diseaseLabel.getDeltaValue();
          k4map.put(diseaseLabel, (IntegrationLabelValue) EcoreUtil.copy(deltaLabel));

          _k1[n].set(k1map.get(diseaseLabel));
          _k2[n].set(k2map.get(diseaseLabel));
          _k3[n].set(k3map.get(diseaseLabel));
          _k4[n].set(deltaLabel);

          _k1[n].scale(b51);
          _k2[n].scale(b52);
          _k3[n].scale(b53);
          _k4[n].scale(b54);

          IntegrationLabelValue estDelta = _k1[n];
          estDelta.add(_k2[n]);
          estDelta.add(_k3[n]);
          estDelta.add(_k4[n]);

          estDelta.scale(h);
          ((IntegrationLabelValue) diseaseLabel.getProbeValue())
              .set(estDelta.add((IntegrationLabelValue) diseaseLabel.getTempValue()));
        }
        ++n;
      }

      // Now get the next delta values
      for (Decorator sdm : iDecorators)
        ((IntegrationDecorator) sdm)
            .calculateDelta(time, timeDelta, sdm.getLabelsToUpdate(threadnum, num_threads));
      for (Decorator sdm : iDecorators)
        ((IntegrationDecorator) sdm)
            .applyExternalDeltas(time, timeDelta, sdm.getLabelsToUpdate(threadnum, num_threads));

      // Step 5 in Runge Kutta Fehlberg.
      // Get the delta values out of each node label and
      // build a fifth estimate of the next value
      n = 0;
      for (Decorator sdm : iDecorators) {
        for (final Iterator<DynamicLabel> currentStateLabelIter =
                sdm.getLabelsToUpdate(threadnum, num_threads).iterator();
            currentStateLabelIter.hasNext(); ) {

          final IntegrationLabel diseaseLabel = (IntegrationLabel) currentStateLabelIter.next();

          IntegrationLabelValue deltaLabel = (IntegrationLabelValue) diseaseLabel.getDeltaValue();
          k5map.put(diseaseLabel, (IntegrationLabelValue) EcoreUtil.copy(deltaLabel));

          _k1[n].set(k1map.get(diseaseLabel));
          _k2[n].set(k2map.get(diseaseLabel));
          _k3[n].set(k3map.get(diseaseLabel));
          _k4[n].set(k4map.get(diseaseLabel));
          _k5[n].set(deltaLabel);

          _k1[n].scale(b61);
          _k2[n].scale(b62);
          _k3[n].scale(b63);
          _k4[n].scale(b64);
          _k5[n].scale(b65);

          IntegrationLabelValue estDelta = _k1[n];
          estDelta.add(_k2[n]);
          estDelta.add(_k3[n]);
          estDelta.add(_k4[n]);
          estDelta.add(_k5[n]);

          estDelta.scale(h);

          ((IntegrationLabelValue) diseaseLabel.getProbeValue())
              .set(estDelta.add((IntegrationLabelValue) diseaseLabel.getTempValue()));
        }
        ++n;
      }

      // Now get the next delta values
      for (Decorator sdm : iDecorators)
        ((IntegrationDecorator) sdm)
            .calculateDelta(time, timeDelta, sdm.getLabelsToUpdate(threadnum, num_threads));
      for (Decorator sdm : iDecorators)
        ((IntegrationDecorator) sdm)
            .applyExternalDeltas(time, timeDelta, sdm.getLabelsToUpdate(threadnum, num_threads));

      // Step 6 in Runge Kutta Fehlberg.
      // Calculate k6
      n = 0;
      for (Decorator sdm : iDecorators) {
        for (final Iterator<DynamicLabel> currentStateLabelIter =
                sdm.getLabelsToUpdate(threadnum, num_threads).iterator();
            currentStateLabelIter.hasNext(); ) {

          final IntegrationLabel diseaseLabel = (IntegrationLabel) currentStateLabelIter.next();

          IntegrationLabelValue deltaLabel = (IntegrationLabelValue) diseaseLabel.getDeltaValue();
          k6map.put(diseaseLabel, (IntegrationLabelValue) EcoreUtil.copy(deltaLabel));
        }
        ++n;
      }

      // Step 7 in Runge Kutta Fehlberg
      // Calculate the two estimates from k1, .. k6 values
      // and determine the maximum difference (error) between them.

      boolean success = true; // Were we able to update all labels without a large enough error?
      double maxerror = 0.0;
      n = 0;
      for (Decorator sdm : iDecorators) {
        for (final Iterator<DynamicLabel> currentStateLabelIter =
                sdm.getLabelsToUpdate(threadnum, num_threads).iterator();
            currentStateLabelIter.hasNext(); ) {

          final IntegrationLabel diseaseLabel = (IntegrationLabel) currentStateLabelIter.next();

          IntegrationLabelValue currentValue = (IntegrationLabelValue) diseaseLabel.getTempValue();

          _k1[n].set(k1map.get(diseaseLabel));
          _k3[n].set(k3map.get(diseaseLabel));
          _k4[n].set(k4map.get(diseaseLabel));
          _k5[n].set(k5map.get(diseaseLabel));
          _k6[n].set(k6map.get(diseaseLabel));

          _k1[n].scale(c1);
          _k3[n].scale(c3);
          _k4[n].scale(c4);
          _k6[n].scale(c6);

          // New Y
          IntegrationLabelValue yout =
              (IntegrationLabelValue) EcoreUtil.copy(_k1[n].add(_k3[n]).add(_k4[n]).add(_k6[n]));

          yout.scale(h);
          yout.add(currentValue);

          // Get the error
          _k1[n].set(k1map.get(diseaseLabel));
          _k3[n].set(k3map.get(diseaseLabel));
          _k4[n].set(k4map.get(diseaseLabel));
          _k5[n].set(k5map.get(diseaseLabel));
          _k6[n].set(k6map.get(diseaseLabel));

          _k1[n].scale(dc1);
          _k3[n].scale(dc3);
          _k4[n].scale(dc4);
          _k5[n].scale(dc5);
          _k6[n].scale(dc6);

          IntegrationLabelValue yerror =
              (IntegrationLabelValue)
                  EcoreUtil.copy(_k1[n].add(_k3[n]).add(_k4[n]).add(_k5[n]).add(_k6[n]));
          yerror.scale(h);

          yerror.divide((IntegrationLabelValue) diseaseLabel.getErrorScale());
          double error = yerror.max();
          error /= relativeTolerance;

          if (error > maxerror) {
            maxerror = error;
          }

          if (error <= 1.0)
            finalEstimate.put(diseaseLabel, (IntegrationLabelValue) EcoreUtil.copy(yout));
        }
        ++n;
      }

      jobs[threadnum].h = h;
      jobs[threadnum].maxerror = maxerror;
      try {
        stepSizeBarrier.await();
      } catch (InterruptedException ie) {
        // Should never happen
        Activator.logError(ie.getMessage(), ie);
      } catch (BrokenBarrierException bbe) {
        // Should never happen
        Activator.logError(bbe.getMessage(), bbe);
      }

      // At least one of the threads had to large of an error, fail
      if (this.maximumError > 1.0) success = false;

      // Are we done?
      if (success) {
        // Check to make sure
        if (this.smallestH > h)
          Activator.logError(
              "Error, h was less than the smallest, perhaps barrier process failed to execute? h:"
                  + h
                  + " vs "
                  + this.smallestH,
              new Exception());

        // Yes, hurrah, advance x using the step size h
        x += h;
        if (this.maximumError > ERRCON) h = SAFETY * h * Math.pow(this.maximumError, PGROW);
        else h = 5.0 * h;

        // Limit to max 1
        if (h > 1.0) h = 1.0;

        // Make sure we don't overshoot
        if (x < end && x + h > end) h = (end - x);

        // Update the current value to the new position
        for (Decorator sdm : iDecorators) {
          for (final Iterator<DynamicLabel> currentStateLabelIter =
                  sdm.getLabelsToUpdate(threadnum, num_threads).iterator();
              currentStateLabelIter.hasNext(); ) {
            final IntegrationLabel diseaseLabel = (IntegrationLabel) currentStateLabelIter.next();
            ((IntegrationLabelValue) diseaseLabel.getTempValue())
                .set(finalEstimate.get(diseaseLabel));
            ((IntegrationLabelValue) diseaseLabel.getProbeValue())
                .set(finalEstimate.get(diseaseLabel));
          }
        }

        // Wait until all other threads have updated the current value
        try {
          updateDoneBarrier.await();
        } catch (InterruptedException ie) {
          // Should never happen
          Activator.logError(ie.getMessage(), ie);
        } catch (BrokenBarrierException bbe) {
          // Should never happen
          Activator.logError(bbe.getMessage(), bbe);
        }

        double progress = (end - x < 0.0) ? 1.0 : 1.0 - (end - x);
        jobs[threadnum].setProgress(progress);
        if (x > nextProgressReport) {
          // Get the progress for all threads
          for (int i = 0; i < num_threads; ++i)
            if (i != threadnum && jobs[i] != null) progress += jobs[i].getProgress();
          progress /= num_threads;
          for (Decorator sdm : iDecorators) sdm.setProgress(progress);
          nextProgressReport += nextProgressReportStep;
        }

      } else {
        // At least one thread failed, change the step size

        // Problem, error too big, we need to reduce the step size
        delta = SAFETY * h * Math.pow(this.maximumError, PSHRNK);
        if (h > 0.0) h = (delta > 0.1 * h) ? delta : 0.1 * h;
        else h = (delta > 0.1 * h) ? 0.1 * h : delta;

        // We didn't succeed.

        // Reset the estimated value back to the original, the step size
        // has been reduced so we well try again.
        // Set the estimated value back to the current original value
        for (Decorator sdm : iDecorators) {
          for (final Iterator<DynamicLabel> currentStateLabelIter =
                  sdm.getLabelsToUpdate(threadnum, num_threads).iterator();
              currentStateLabelIter.hasNext(); ) {
            final IntegrationLabel diseaseLabel = (IntegrationLabel) currentStateLabelIter.next();
            ((IntegrationLabelValue) diseaseLabel.getProbeValue())
                .set((IntegrationLabelValue) diseaseLabel.getTempValue());
          }
        }
      }
    } // While x < end

    jobs[threadnum].t = x;
    jobs[threadnum].h = h;

    // Remember the step size and position in the solver
    this.setStepSize(h);
    this.setCurrentX(x);

    // We're done
    for (Decorator sdm : iDecorators) {
      for (final Iterator<DynamicLabel> currentStateLabelIter =
              sdm.getLabelsToUpdate(threadnum, num_threads).iterator();
          currentStateLabelIter.hasNext(); ) {
        final IntegrationLabel diseaseLabel = (IntegrationLabel) currentStateLabelIter.next();

        // This is the next state for the label
        IntegrationLabelValue nextState = (IntegrationLabelValue) diseaseLabel.getNextValue();
        // This is the original current state at the previous cycle
        IntegrationLabelValue originalState =
            (IntegrationLabelValue) diseaseLabel.getCurrentValue();
        // This is the final value calculated at position x.
        IntegrationLabelValue newValue = finalEstimate.get(diseaseLabel);
        // x could be larger than the requested cycle, so we do a linear interpolation
        // to fit it exactly to the requested cycle
        // *** Not needed since we always end exactly at the requested cycle
        // adjustValuesToCycle(originalState, newValue, x, cycle);

        // New value has been modified here to fit the requested cycle
        nextState.set(newValue);
        // Do any model specific work for instance add noise
        ((IntegrationDecorator) sdm).doModelSpecificAdjustments((LabelValue) nextState);
        // The next value is valid now.
        diseaseLabel.setNextValueValid(true);
      }
    }
  }
Example #3
0
  /**
   *
   * <!-- begin-user-doc -->
   * <!-- end-user-doc -->
   *
   * @generated NOT
   */
  @Override
  public boolean step(STEMTime time, long timeDelta, int cycle) {

    // Validate all decorators that return deltas to make sure
    // they are of deterministic nature. The Runge Kutta integratio
    // can only handle determininistic variants

    for (Decorator decorator : this.getDecorators())
      if (decorator instanceof IntegrationDecorator) {
        IntegrationDecorator idec = (IntegrationDecorator) decorator;
        if (!idec.isDeterministic()) {
          Activator.logError(
              "Error, decorator: "
                  + idec
                  + " is not deterministic. The Runge Kutta Integrator can only handle deterministic models.",
              new Exception());
          return false;
        }
      }

    Activator act = org.eclipse.stem.ui.Activator.getDefault();
    if (act != null) {
      final Preferences preferences = act.getPluginPreferences();
      num_threads =
          (short)
              preferences.getInt(
                  org.eclipse.stem.ui.preferences.PreferenceConstants.SIMULATION_THREADS);
    } else num_threads = 2; // Just so we can run inside junit test

    final int c = cycle;

    // Initialize latches
    stepSizeBarrier =
        new CyclicBarrier(
            num_threads,
            new Runnable() {
              public void run() {
                // All threads successfully advanced time by some step h.
                // Find the smallest
                smallestH = Double.MAX_VALUE;
                maximumError = -Double.MAX_VALUE;
                for (int i = 0; i < num_threads; ++i) {
                  if (jobs[i].h <= smallestH) {
                    if (maximumError < jobs[i].maxerror) maximumError = jobs[i].maxerror;
                    smallestH = jobs[i].h;
                  }
                }
              }
            });

    updateDoneBarrier = new CyclicBarrier(num_threads);

    // Find triggers and make sure they are invoked
    for (Decorator decorator : this.getDecorators()) {
      if (decorator instanceof Trigger) {
        decorator.updateLabels(time, timeDelta, cycle);
      }
    }

    // First initialize the probe and temp label values from the current
    // label values.

    for (Decorator decorator : this.getDecorators()) {
      EList<DynamicLabel> allLabels = decorator.getLabelsToUpdate();
      for (final Iterator<DynamicLabel> currentStateLabelIter = allLabels.iterator();
          currentStateLabelIter.hasNext(); ) {
        if (decorator instanceof IntegrationDecorator) {
          // It's a standard disease model with a standard disease model label
          final IntegrationLabel iLabel = (IntegrationLabel) currentStateLabelIter.next();
          ((IntegrationLabelValue) iLabel.getProbeValue())
              .set((IntegrationLabelValue) iLabel.getCurrentValue());
          ((IntegrationLabelValue) iLabel.getTempValue())
              .set((IntegrationLabelValue) iLabel.getCurrentValue());
          ((IntegrationLabelValue) iLabel.getTempValue()).prepareCycle();
          ((IntegrationLabelValue) iLabel.getProbeValue()).prepareCycle();
        } else currentStateLabelIter.next();
      }
    }

    if (jobs == null || jobs.length != num_threads) {
      // Initialize the jobs if not done yet or of the number of threads changes
      jobs = new RkJob[num_threads];

      for (short i = 0; i < num_threads; ++i) {
        final short threadnum = i;
        jobs[i] = new RkJob("Worker " + i, threadnum, this);
      } // For each job
    } // If not initialized

    // Initialize
    int thread = 0;
    for (RkJob j : jobs) {
      j.cycle = c;
      j.time = time;
      j.timeDelta = timeDelta;
    }
    // Schedule. Jobs can be rescheduled after finished
    for (RkJob j : jobs) j.schedule();

    // Wait until all jobs completed
    for (RkJob j : jobs) {
      try {
        j.join();
      } catch (InterruptedException ie) {
        Activator.logError(ie.getMessage(), ie);
      }
    }

    // Set the common time and step size here and validate everything is right
    double minStep = Double.MAX_VALUE;
    double currentT = jobs[0].t;
    for (RkJob j : jobs) {
      // The jobs have calculated new step sizes after they finished. Pick the
      // smallest one for the next cycle
      if (j.h < minStep) minStep = j.h;
      if (j.t != currentT)
        Activator.logError(
            "Error, one thread was in misstep with other threads, its time was "
                + j.t
                + " versus "
                + currentT,
            new Exception());
    }
    return true;
  }