BRUSSELATOR
Overview
The BRUSSELATOR function numerically solves the Brusselator system of ordinary differential equations, which models autocatalytic chemical reactions. The Brusselator is a classic example in nonlinear dynamics and chemical kinetics, describing the interaction of two species, X and Y, with parameters and controlling the reaction rates. The system is defined by:
where and are the concentrations of the two species, and , are positive constants. The function uses SciPy’s ODE solver (scipy.integrate.solve_ivp ) to integrate the system over a specified time interval. Only the basic two-variable model is exposed; spatial extensions and complex networks are not supported. The integration method can be selected from several common solvers, but only the most used options are exposed. This example function is provided as-is without any representation of accuracy.
Usage
To use the function in Excel:
=BRUSSELATOR(x_initial, y_initial, a, b, t_start, t_end, [timesteps], [solve_ivp_method])x_initial(float, required): Initial value of X.y_initial(float, required): Initial value of Y.a(float, required): Parameter a (reaction rate).b(float, required): Parameter b (reaction rate).t_start(float, required): Start time for integration.t_end(float, required): End time for integration.timesteps(int, optional, default=10): Number of timesteps to solve for.solve_ivp_method(string (enum), optional, default=‘RK45’): Integration method. Valid options:RK45,RK23,DOP853,Radau,BDF,LSODA.
The function returns a 2D array (table) with columns: t, X, Y, representing time and the concentrations of X and Y at each step. If the input is invalid or integration fails, a string error message is returned.
Examples
Example 1: Basic Case
Inputs:
| x_initial | y_initial | a | b | t_start | t_end | timesteps | method |
|---|---|---|---|---|---|---|---|
| 1.0 | 1.0 | 1.0 | 2.0 | 0.0 | 1.0 | 10 | RK45 |
Excel formula:
=BRUSSELATOR(1.0, 1.0, 1.0, 2.0, 0.0, 1.0, 10)Expected output:
| t | X | Y |
|---|---|---|
| 0.000 | 1.000 | 1.000 |
| 0.111 | 0.894 | 1.114 |
| 0.222 | 0.815 | 1.234 |
| 0.333 | 0.756 | 1.356 |
| 0.444 | 0.713 | 1.476 |
| 0.556 | 0.682 | 1.591 |
| 0.667 | 0.659 | 1.699 |
| 0.778 | 0.641 | 1.800 |
| 0.889 | 0.626 | 1.892 |
| 1.000 | 0.614 | 1.977 |
Example 2: RK23 Method
Inputs:
| x_initial | y_initial | a | b | t_start | t_end | timesteps | method |
|---|---|---|---|---|---|---|---|
| 1.0 | 1.0 | 1.0 | 2.0 | 0.0 | 1.0 | 10 | RK23 |
Excel formula:
=BRUSSELATOR(1.0, 1.0, 1.0, 2.0, 0.0, 1.0, 10, "RK23")Expected output:
| t | X | Y |
|---|---|---|
| 0.000 | 1.000 | 1.000 |
| 0.111 | 0.889 | 1.135 |
| 0.222 | 0.798 | 1.279 |
| 0.333 | 0.726 | 1.428 |
| 0.444 | 0.671 | 1.578 |
| 0.556 | 0.631 | 1.724 |
| 0.667 | 0.604 | 1.861 |
| 0.778 | 0.587 | 1.985 |
| 0.889 | 0.577 | 2.093 |
| 1.000 | 0.572 | 2.184 |
Example 3: Different Parameters
Inputs:
| x_initial | y_initial | a | b | t_start | t_end | timesteps | method |
|---|---|---|---|---|---|---|---|
| 2.0 | 1.0 | 2.0 | 3.0 | 0.0 | 1.0 | 10 | RK45 |
Excel formula:
=BRUSSELATOR(2.0, 1.0, 2.0, 3.0, 0.0, 1.0, 10)Expected output:
| t | X | Y |
|---|---|---|
| 0.000 | 2.000 | 1.000 |
| 0.111 | 1.805 | 1.232 |
| 0.222 | 1.642 | 1.487 |
| 0.333 | 1.516 | 1.754 |
| 0.444 | 1.427 | 2.022 |
| 0.556 | 1.374 | 2.281 |
| 0.667 | 1.353 | 2.522 |
| 0.778 | 1.359 | 2.738 |
| 0.889 | 1.387 | 2.924 |
| 1.000 | 1.431 | 3.076 |
Example 4: Longer Time Interval
Inputs:
| x_initial | y_initial | a | b | t_start | t_end | timesteps | method |
|---|---|---|---|---|---|---|---|
| 1.0 | 2.0 | 1.0 | 2.0 | 0.0 | 2.0 | 10 | RK45 |
Excel formula:
=BRUSSELATOR(1.0, 2.0, 1.0, 2.0, 0.0, 2.0, 10)Expected output:
| t | X | Y |
|---|---|---|
| 0.000 | 1.000 | 2.000 |
| 0.000 | 1.000 | 2.000 |
| 0.000 | 1.000 | 2.000 |
| 0.000 | 1.000 | 2.000 |
| 0.001 | 1.000 | 2.000 |
| 0.011 | 1.000 | 2.000 |
| 0.111 | 1.000 | 2.000 |
| 1.111 | 1.000 | 2.000 |
| 2.000 | 1.000 | 2.000 |
Python Code
from scipy.integrate import solve_ivp as scipy_solve_ivp
import numpy as np
def brusselator(x_initial, y_initial, a, b, t_start, t_end, timesteps=10, solve_ivp_method='RK45'):
"""
Numerically solves the Brusselator system of ordinary differential equations for
autocatalytic chemical reactions. This function is a thin wrapper that uses
SciPy's ODE solver (scipy.integrate.solve_ivp) to integrate the system.
Args:
x_initial: Initial x value.
y_initial: Initial y value.
a: Parameter a.
b: Parameter b.
t_start: Start time of integration.
t_end: End time of integration.
timesteps: Number of timesteps to solve for. Default is 10.
solve_ivp_method: Integration method ('RK45', 'RK23', 'DOP853', 'Radau', 'BDF', 'LSODA'). Default is 'RK45'.
Returns:
2D list with header row: t, X, Y. Each row contains time and variable values, or an error message (str) if input is invalid.
Wraps: scipy.integrate.solve_ivp
Documentation: https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.solve_ivp.html
This example function is provided as-is without any representation of accuracy.
"""
# Validate input types
try:
x0 = float(x_initial)
y0 = float(y_initial)
a = float(a)
b = float(b)
t0 = float(t_start)
t1 = float(t_end)
ntp = int(timesteps)
except Exception:
return "Invalid input: All initial values, parameters, and timesteps must be numbers."
if t1 <= t0:
return "Invalid input: t_end must be greater than t_start."
if ntp <= 0:
return "Invalid input: timesteps must be a positive integer."
if solve_ivp_method not in ['RK45', 'RK23', 'DOP853', 'Radau', 'BDF', 'LSODA']:
return "Invalid input: solve_ivp_method must be one of 'RK45', 'RK23', 'DOP853', 'Radau', 'BDF', 'LSODA'."
# Create time array for evaluation
t_eval = np.linspace(t0, t1, ntp)
# Brusselator ODE system
def brusselator_ode(t, y):
x, yv = y
dxdt = a - (b + 1) * x + x * x * yv
dydt = b * x - x * x * yv
return [dxdt, dydt]
# Integrate
try:
sol = scipy_solve_ivp(
brusselator_ode,
[t0, t1],
[x0, y0],
method=solve_ivp_method,
dense_output=False,
t_eval=t_eval
)
except Exception as e:
return f"Integration error: {e}"
if not sol.success:
return f"Integration failed: {sol.message}"
# Format output: header row then data rows
result = [["t", "X", "Y"]]
for i in range(len(sol.t)):
t_val = float(sol.t[i])
x_val = float(sol.y[0][i])
y_val = float(sol.y[1][i])
# Disallow nan/inf
if any([
not isinstance(t_val, float) or not isinstance(x_val, float) or not isinstance(y_val, float),
t_val != t_val or x_val != x_val or y_val != y_val, # NaN check
abs(t_val) == float('inf') or abs(x_val) == float('inf') or abs(y_val) == float('inf')
]):
return "Invalid output: nan or inf detected."
result.append([t_val, x_val, y_val])
return result