JCCKit logo

2.3 Example: Brusselator

The Brusselator applet (see the Examples page) shows the time evolution of a simulated dynamical system (a so-called reaction-diffusion system) in an animated way. At equidistant time steps (defining the frame rate of the animation) two curves are plotted. There is a start button as well as a stop button for starting/stopping the animation. With the buttons labeled "reset" and "add noise" the user can change the initial state of the system.

The design of this applet is based on the Model View Controller (MVC) architectual pattern:

Model:
The class Brusselator holds the state of the system. It has getters and setters for manipulating the system state and the model parameters. The method next() calculates the state for the next time step. Registrated ActionListeners will be notified if the state has been changed.
View:
Actual there are two views: TimeView showing the current simulation time in the upper-left corner and BrusselatorPlot showing the current state of the Brusselator using JCCKit.
Controller:
The controller class is BrusselatorController. It is responsible for the actions caused by button events.
The BrusselatorApplet puts everything together.

First, we take a closer look at the code of BrusselatorPlot (usage of JCCKit is highlighted):

public class BrusselatorPlot extends GraphicsPlotCanvas {
  private Brusselator _brusselator;

  public BrusselatorPlot(ConfigParameters config, Brusselator brusselator) {
    super(config);
    _brusselator = brusselator;
    brusselator.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent event) {
            replot();
          }
        });
    replot();
  }

  private void replot() { ... }
}
We see that BrusselatorPlot is a subclass of GraphicsPlotCanvas. GraphicsPlotCanvas is a convenient class for presenting a plot in a Java AWT Canvas. But it should be configured by an instance of ConfigParameters. Below we will see that the configuration parameters are provided by the applet parameters. Thus all the details of the coordinate system, fonts, colors etc. can be specified by applet parameters during developing the HTML page where the applet is embedded.

The model (i.e. Brusselator) is stored in the field _brusselator. It will be needed in the method replot() to obtain the data to be plotted. Also an anonymous ActionListener is added to the model: When the model state changes replot() will be invoked.

Here is the code of replot():

private void replot() {
  DataPlot plot = new DataPlot();
  DataCurve uCurve = new DataCurve("u");
  DataCurve vCurve = new DataCurve("v");
  double dx = _brusselator.getDx();
  for (int i = 0, n = _brusselator.getNumberOfPoints(); i < n; i++) {
    uCurve.addElement(new DataPoint(dx * i, _brusselator.getU(i)));
    vCurve.addElement(new DataPoint(dx * i, _brusselator.getV(i)));
  }
  plot.addElement(uCurve);
  plot.addElement(vCurve);
  connect(plot);
}
A DataPlot with two DataCurves is created. In the for loop the DataCurves are filled with the data from the model. Finally the DataPlot instance is connected with this GraphicsPlotCanvas instance.

By the way, it is not a good idea to use the method replaceElementAt() for the curves or even the data points. This is suitable in the first example where only one curve or data point changes at a time. But here a large number of data points will be changed in each time step of the animation. Each invocation of replaceElementAt leads to an automatic update of the view which includes a new calculation of the abstract graphical reperesentation of a curve. This sums up to a very time-consuming task which drastically slows done animation.

What the replot() actually does is a mapping from the original data model Brusselator (which is and should be independent from JCCKit) to the data model of JCCKit.

To see how the configuration parameters are obtained and how the plot is embedded into the applet we take a look at the code of BrusselatorApplet:

public class BrusselatorApplet extends Applet {
  private ConfigParameters _config = new ConfigParameters(new AppletBasedConfigData(this));

  public void init() {
    setBackground(_config.getColor("background", getBackground()));
    Brusselator brusselator = createBrusselator();
    BrusselatorPlot plot = new BrusselatorPlot(_config, brusselator);

    setLayout(new BorderLayout());
    Panel p = new Panel();
    p.setLayout(new FlowLayout(FlowLayout.LEFT));
    p.add(new TimeView(brusselator));
    add(p, BorderLayout.NORTH);
    add(plot.getGraphicsCanvas(), BorderLayout.CENTER);
    add(new BrusselatorController(brusselator).getControlPanel(), 
        BorderLayout.SOUTH);
  }

  private Brusselator createBrusselator() { ... }
}
The first line of code after the class declaration shows how to create an instance of ConfigParameters based on applet parameters. Another way is explained in the first example. The configuration parameters are used in the line where the instance of BrusselatorPlot is created. Note, that BrusselatorPlot as a subclass of GraphicsPlotCanvas is not a subclass of Java AWT Component. The corresponding AWT component has be obtained by the method getGraphicsCanvas.

Here is the applet element with the configuration parameters (more about their meaning can be found in the chapters 3 and 4):

<applet code="BrusselatorApplet" archive="brusselator.jar, jcckit.jar" width=700 height=400>
<param name="background" value="0xffffff">
<param name="paper" value="0 0 1 0.35">

<param name="dt" value="0.1">
<param name="dx" value="1">
<param name="noiseFactor" value="0.1">
<param name="L" value="200">
<param name="d" value="16">
<param name="alpha" value="1.8">
<param name="beta" value="1">

<param name="defaultAxisLabelAttributes/className" value="jcckit.graphic.BasicGraphicAttributes">
<param name="defaultAxisLabelAttributes/fontType" value="bold">
<param name="defaultAxisLabelAttributes/fontSize" value="0.035">
<param name="defaultTicLabelAttributes/className" value="jcckit.graphic.BasicGraphicAttributes">
<param name="defaultTicLabelAttributes/fontType" value="bold">
<param name="defaultTicLabelAttributes/fontSize" value="0.015">

<param name="plot/coordinateSystem/origin" value="0.075 0.02">
<param name="plot/coordinateSystem/xAxis/axisLength" value="0.9">
<param name="plot/coordinateSystem/xAxis/maximum" value="200">
<param name="plot/coordinateSystem/xAxis/axisLabelAttributes/" value="defaultAxisLabelAttributes/">
<param name="plot/coordinateSystem/xAxis/ticLabelFormat" value="%0f">
<param name="plot/coordinateSystem/xAxis/ticLabelAttributes/" value="defaultTicLabelAttributes/">
<param name="plot/coordinateSystem/xAxis/axisLabelPosition" value="0 -0.02">
<param name="plot/coordinateSystem/yAxis/axisLength" value="0.37">
<param name="plot/coordinateSystem/yAxis/axisLabel" value="u, v">
<param name="plot/coordinateSystem/yAxis/axisLabelAttributes/" value="defaultAxisLabelAttributes/">
<param name="plot/coordinateSystem/yAxis/automaticTicCalculation" value="false">
<param name="plot/coordinateSystem/yAxis/numberOfTics" value="7">
<param name="plot/coordinateSystem/yAxis/ticLabelAttributes/" value="defaultTicLabelAttributes/">
<param name="plot/coordinateSystem/yAxis/maximum" value="3">
<param name="plot/coordinateSystem/yAxis/axisLabelPosition" value="-0.035 0">
<param name="plot/curveFactory/definitions" value="def null">
<param name="plot/curveFactory/def/symbolFactory/className" value="jcckit.plot.SquareSymbolFactory">
<param name="plot/curveFactory/def/symbolFactory/size" value="0.004">
<param name="plot/curveFactory/def/symbolFactory/attributes/className" 
       value="jcckit.graphic.ShapeAttributes">
<param name="plot/legend/boxHeight" value="0.08">
<param name="plot/legend/boxWidth" value="0.09">
<param name="plot/legend/upperRightCorner" value="0.97 0.385">
<param name="plot/legend/" value="">
<param name="plot/legend/" value="">
</applet>