/// <summary>
        /// Raises the InterationCompleted event.
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnInterationCompleted(IterationCompletedEventArgs e)
        {
            Trace.Assert(e != null);

            if (IterationCompleted != null)
            {
                IterationCompleted(this, e);
            }
        }
        ////////////////////////////////////////////////////////////////////////////////
        #region Public Methods

        /// <summary>
        /// Computes one frame of the reaction.
        /// </summary>
        /// <returns>An array containing the reaction products for the next frame. </returns>
        public unsafe double[, ,] ComputeReaction()
        {
            Debug.Assert(CheckInvariant(), "ComputeReaction: CheckInvariant failed");

            double Xa;
            double Xb;
            double Xc;
            double c;
            double d;
            double f;
            double g0;
            double feedbackFromC;
            double feedbackFromB;

            iteration++;

            // If boundary conditions have changed since the previous frame, update them.
            if (this._boundaryConditionsPrev != this._boundaryConditions)
            {
                this.SetBoundaryConditions(this._boundaryConditions);

                this._boundaryConditionsPrev = this._boundaryConditions;
            }

            // Copy boundary values to the out buffer.
            for (int i = 0; i < vesselWidth; i++)
            {
                reactionOut[indexA, i, 0] = reaction[indexA, i, 0];
                reactionOut[indexB, i, 0] = reaction[indexB, i, 0];
                reactionOut[indexC, i, 0] = reaction[indexC, i, 0];

                reactionOut[indexA, i, vesselHeight - 1] = reaction[indexA, i, vesselHeight - 1];
                reactionOut[indexB, i, vesselHeight - 1] = reaction[indexB, i, vesselHeight - 1];
                reactionOut[indexC, i, vesselHeight - 1] = reaction[indexC, i, vesselHeight - 1];
            }

            for (int j = 0; j < vesselHeight; j++)
            {
                reactionOut[indexA, 0, j] = reaction[indexA, 0, j];
                reactionOut[indexB, 0, j] = reaction[indexB, 0, j];
                reactionOut[indexC, 0, j] = reaction[indexC, 0, j];

                reactionOut[indexA, vesselWidth - 1, j] = reaction[indexA, vesselWidth - 1, j];
                reactionOut[indexB, vesselWidth - 1, j] = reaction[indexB, vesselWidth - 1, j];
                reactionOut[indexC, vesselWidth - 1, j] = reaction[indexC, vesselWidth - 1, j];
            }

            // Traverse the grid and compute concentrations for
            // all three reactants. This implements the Gontar model.
            for (int i = 1; i < vesselWidth - 1; i++)
            {
                for (int j = 1; j < vesselHeight - 1; j++)
                {
                    try
                    {
                        // Compute concentrations at cell (i,j).
                        feedbackFromC = Math.Exp(-W1 / weight(indexC, i, j));
                        feedbackFromB = Math.Exp(-W2 * weight(indexB, i, j));
                        g0            = (K1 * K2 * feedbackFromC * feedbackFromB) / (1.0 + K1 * feedbackFromC);

                        // Compute concentrations at cell (i,j).
                        //c = -W1 / weight(2, i, j);
                        //f = -W2 * weight(1, i, j);
                        //e_to_c = Math.Exp(c);
                        //e_to_f = Math.Exp(f);
                        //d = 1.0 + K1 * e_to_c;
                        //g0 = (K1 * K2 * e_to_c * e_to_f) / d;

                        Xc = b * (g0 / (g0 + 1));
                        if (Xc <= minConcentration)
                        {
                            Xc = minConcentration;
                        }

                        Xb = (K1 * feedbackFromC / (1 + K1 * feedbackFromC)) * (b - Xc);
                        if (Xb <= minConcentration)
                        {
                            Xb = minConcentration;
                        }

                        Xa = b - Xb - Xc;
                        if (Xa <= minConcentration)
                        {
                            Xa = minConcentration;
                        }


                        if (Xa > b)
                        {
                            Xa = b;
                        }

                        if (Xb > b)
                        {
                            Xb = b;
                        }

                        if (Xc > b)
                        {
                            Xc = b;
                        }

                        reactionOut[indexA, i, j] = Xa;
                        reactionOut[indexB, i, j] = Xb;
                        reactionOut[indexC, i, j] = Xc;
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("caught exception: ", ex.ToString());
                    }
                }
            }

            int ubi = reaction.GetUpperBound(1) + 1;
            int ubj = reaction.GetUpperBound(2) + 1;

            // Copy the out buffer to the in buffer.
            fixed(double *pOutBuff = reactionOut, pInBuff = reaction)
            {
                uint buffSize = (uint)(3 * ubi * ubj * sizeof(double));

                uint count = buffSize;

                double *ps = pOutBuff;
                double *pd = pInBuff;

                lock (reactionOut.SyncRoot)
                {
                    try
                    {
                        CopyMemory((void *)pd, (void *)ps, count);
                    }
                    catch (Exception ex)
                    {
                        Trace.WriteLine(ex.Message);
                    }
                }
            }

            // Raise the IterationCompleted event.
            IterationCompletedEventArgs e = new IterationCompletedEventArgs(this.iteration);

            OnInterationCompleted(e);

            return(reactionOut);
        }