Skip to content

Pattern formation

Pattern formation: amplitude equations and rolls.

BrusselatorElement(label, visual=None, *, u=1.0, v=3.0, a=1.0, b=3.0, Du=1.0, Dv=8.0)

Bases: BrusselatorReactionElement

Site of the Brusselator, the reactor of the Brusselator with the diffusion coefficients of its intermediates.

The four reactions of brusselator run at every site, and its diffusions read Du and Dv.

Parameters:

Name Type Description Default
label str

The label of the site or the field.

required
visual VisualSpec | None

How the element is drawn, or None for default_visual_.

None
u float

The initial concentration of u.

1.0
v float

The initial concentration of v.

3.0
a float

The feed of u.

1.0
b float

The conversion of u into v.

3.0
Du Annotated[object, ParameterSpec()]

The diffusion of u.

1.0
Dv Annotated[object, ParameterSpec()]

The diffusion of v.

8.0

Examples:

>>> from skcomplex.models.chemistry.pattern_formation import BrusselatorElement
>>> BrusselatorElement('cell').Dv
8.0
Source code in src/skcomplex/models/chemistry/pattern_formation/_brusselator.py
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
def __init__(
    self,
    label: str,
    visual: VisualSpec | None = None,
    *,
    u: float = 1.0,
    v: float = 3.0,
    a: float = 1.0,
    b: float = 3.0,
    Du: Annotated[object, ParameterSpec()] = 1.0,
    Dv: Annotated[object, ParameterSpec()] = 8.0,
) -> None:
    super().__init__(label, visual=visual, u=u, v=v, a=a, b=b)
    self.Du = Du
    self.Dv = Dv

GrayScottElement(label, visual=None, *, u=1.0, v=0.0, Du=0.16, Dv=0.08, F=0.035, k=0.065)

Bases: Element

Site of the Gray-Scott model, the substrate u and the activator v.

The reactions of gray_scott at every site, the cubic autocatalysis of the activator on the substrate, the feed F of the substrate, and the removal F + k of the activator, read F and k, and its diffusions read Du and Dv.

Parameters:

Name Type Description Default
label str

The label of the site or the field.

required
visual VisualSpec | None

How the element is drawn, or None for default_visual_.

None
u Annotated[object, StateSpec()]

The initial substrate.

1.0
v Annotated[object, StateSpec()]

The initial activator.

0.0
Du Annotated[object, ParameterSpec()]

The diffusion of the substrate.

0.16
Dv Annotated[object, ParameterSpec()]

The diffusion of the activator.

0.08
F Annotated[object, ParameterSpec()]

The feed rate.

0.035
k Annotated[object, ParameterSpec()]

The kill rate.

0.065

Examples:

>>> from skcomplex.models.chemistry.pattern_formation import GrayScottElement
>>> GrayScottElement('cell').k
0.065
Source code in src/skcomplex/models/chemistry/pattern_formation/_gray_scott.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
def __init__(
    self,
    label: str,
    visual: VisualSpec | None = None,
    *,
    u: Annotated[object, StateSpec()] = 1.0,
    v: Annotated[object, StateSpec()] = 0.0,
    Du: Annotated[object, ParameterSpec()] = 0.16,
    Dv: Annotated[object, ParameterSpec()] = 0.08,
    F: Annotated[object, ParameterSpec()] = 0.035,
    k: Annotated[object, ParameterSpec()] = 0.065,
) -> None:
    super().__init__(label, visual=visual)
    self.u = u
    self.v = v
    self.Du = Du
    self.Dv = Dv
    self.F = F
    self.k = k

SchnakenbergElement(label, visual=None, *, u=1.0, v=0.9, a=0.1, b=0.9, Du=1.0, Dv=40.0)

Bases: Element

Site of the Schnakenberg model, the activator u and the inhibitor v.

The reactions of schnakenberg at every site, the productions a of u and b of v, the decay of u, and the autocatalysis 2U + V -> 3U, read a and b, and its diffusions read Du and Dv.

Parameters:

Name Type Description Default
label str

The label of the site or the field.

required
visual VisualSpec | None

How the element is drawn, or None for default_visual_.

None
u Annotated[object, StateSpec()]

The initial activator.

1.0
v Annotated[object, StateSpec()]

The initial inhibitor.

0.9
a Annotated[object, ParameterSpec()]

The production of u.

0.1
b Annotated[object, ParameterSpec()]

The production of v.

0.9
Du Annotated[object, ParameterSpec()]

The diffusion of the activator.

1.0
Dv Annotated[object, ParameterSpec()]

The diffusion of the inhibitor.

40.0

Examples:

>>> from skcomplex.models.chemistry.pattern_formation import SchnakenbergElement
>>> SchnakenbergElement('cell').Dv
40.0
Source code in src/skcomplex/models/chemistry/pattern_formation/_schnakenberg.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
def __init__(
    self,
    label: str,
    visual: VisualSpec | None = None,
    *,
    u: Annotated[object, StateSpec()] = 1.0,
    v: Annotated[object, StateSpec()] = 0.9,
    a: Annotated[object, ParameterSpec()] = 0.1,
    b: Annotated[object, ParameterSpec()] = 0.9,
    Du: Annotated[object, ParameterSpec()] = 1.0,
    Dv: Annotated[object, ParameterSpec()] = 40.0,
) -> None:
    super().__init__(label, visual=visual)
    self.u = u
    self.v = v
    self.a = a
    self.b = b
    self.Du = Du
    self.Dv = Dv

brusselator(shape=(64, 64), *, a=1.0, b=3.0, Du=1.0, Dv=8.0, random_state=0)

Return the Brusselator reaction-diffusion model from small noise around its steady state (a, b / a).

Parameters:

Name Type Description Default
shape Sequence[int]

The number of rows and columns of the periodic lattice.

(64, 64)
a float

The feed of u.

1.0
b float

The conversion of u into v.

3.0
Du float

The diffusion of u.

1.0
Dv float

The diffusion of v.

8.0
random_state int | Generator | None

The seed or generator of the noise.

0

Returns:

Name Type Description
system System

The model, with the concentrations cells.u and cells.v.

Examples:

>>> from skcomplex.models.chemistry.pattern_formation import brusselator
>>> brusselator((8, 8), b=2.5).elements[0].values['b']
2.5
Source code in src/skcomplex/models/chemistry/pattern_formation/_reaction_diffusion.py
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
@register_model(
    field='chemistry/pattern_formation',
    tags=('field', 'reaction-diffusion', 'Turing', 'oscillation', 'pde'),
    references=('Prigogine and Lefever 1968', 'Gros 2015'),
    defaults={'until': 100.0, 'dt': 1.0, 'solver': RK4Solver(dt=0.01)},
)
def brusselator(
    shape: Sequence[int] = (64, 64),
    *,
    a: float = 1.0,
    b: float = 3.0,
    Du: float = 1.0,
    Dv: float = 8.0,
    random_state: int | np.random.Generator | None = 0,
) -> System:
    """Return the Brusselator reaction-diffusion model from small noise around its steady state `(a, b / a)`.

    Args:
        shape:
            The number of rows and columns of the periodic lattice.

        a:
            The feed of `u`.

        b:
            The conversion of `u` into `v`.

        Du:
            The diffusion of `u`.

        Dv:
            The diffusion of `v`.

        random_state:
            The seed or generator of the noise.

    Returns:
        system:
            The model, with the concentrations `cells.u` and `cells.v`.

    Examples:
        >>> from skcomplex.models.chemistry.pattern_formation import brusselator
        >>> brusselator((8, 8), b=2.5).elements[0].values['b']
        2.5
    """
    shape = tuple(shape)
    values = {
        'u': a + _noise(shape, 0.01, random_state),
        'v': np.full(shape, b / a),
        'a': a,
        'b': b,
        'Du': Du,
        'Dv': Dv,
    }
    return System(
        elements=[FieldElement('cells', element=BrusselatorElement, space=LatticeSpace(shape), values=values)],
        interactions=[*_get_brusselator_reactions(), *_get_diffusions()],
    )

gray_scott(shape=(128, 128), *, Du=0.16, Dv=0.08, F=0.035, k=0.065, random_state=0)

Return the Gray-Scott reaction-diffusion model, seeded in its middle, which grows spots that replicate.

Parameters:

Name Type Description Default
shape Sequence[int]

The number of rows and columns of the periodic lattice.

(128, 128)
Du float

The diffusion of the substrate u.

0.16
Dv float

The diffusion of the activator v.

0.08
F float

The feed rate.

0.035
k float

The kill rate.

0.065
random_state int | Generator | None

The seed or generator of the noise on the seed.

0

Returns:

Name Type Description
system System

The model, with the substrate cells.u and the activator cells.v.

Examples:

>>> from skcomplex.models.chemistry.pattern_formation import gray_scott
>>> gray_scott((32, 32), F=0.04).elements[0].values['F']
0.04
Source code in src/skcomplex/models/chemistry/pattern_formation/_reaction_diffusion.py
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
@register_model(
    field='chemistry/pattern_formation',
    tags=('field', 'reaction-diffusion', 'self-replication', 'pde'),
    references=('Gray and Scott 1984', 'Pearson 1993'),
    defaults={'until': 2000.0, 'dt': 20.0, 'solver': RK4Solver(dt=1.0)},
)
def gray_scott(
    shape: Sequence[int] = (128, 128),
    *,
    Du: float = 0.16,
    Dv: float = 0.08,
    F: float = 0.035,
    k: float = 0.065,
    random_state: int | np.random.Generator | None = 0,
) -> System:
    """Return the Gray-Scott reaction-diffusion model, seeded in its middle, which grows spots that replicate.

    Args:
        shape:
            The number of rows and columns of the periodic lattice.

        Du:
            The diffusion of the substrate `u`.

        Dv:
            The diffusion of the activator `v`.

        F:
            The feed rate.

        k:
            The kill rate.

        random_state:
            The seed or generator of the noise on the seed.

    Returns:
        system:
            The model, with the substrate `cells.u` and the activator `cells.v`.

    Examples:
        >>> from skcomplex.models.chemistry.pattern_formation import gray_scott
        >>> gray_scott((32, 32), F=0.04).elements[0].values['F']
        0.04
    """
    shape = tuple(shape)
    u, v = np.ones(shape), np.zeros(shape)
    middle = tuple(slice(size // 2 - size // 10, size // 2 + size // 10) for size in shape)
    u[middle], v[middle] = 0.5, 0.25
    noise = _noise(shape, 0.01, random_state)
    values = {'u': u + noise, 'v': v + np.abs(noise), 'Du': Du, 'Dv': Dv, 'F': F, 'k': k}
    return System(
        elements=[FieldElement('cells', element=GrayScottElement, space=LatticeSpace(shape), values=values)],
        interactions=[*_get_gray_scott_reactions(), *_get_diffusions()],
    )

schnakenberg(shape=(64, 64), *, a=0.1, b=0.9, Du=1.0, Dv=40.0, spacing=1.0, random_state=0)

Return the Schnakenberg reaction-diffusion model, which forms Turing patterns from noise when Dv >> Du.

The steady state u = a + b, v = b / (a + b)^2 is stable without diffusion and unstable to perturbations of a band of wavelengths with it.

Parameters:

Name Type Description Default
shape Sequence[int]

The number of sites along every dimension of the periodic lattice.

(64, 64)
a float

The production of u.

0.1
b float

The production of v.

0.9
Du float

The diffusion of the activator u.

1.0
Dv float

The diffusion of the inhibitor v.

40.0
spacing float

The distance between sites.

1.0
random_state int | Generator | None

The seed or generator of the noise.

0

Returns:

Name Type Description
system System

The model, with the concentrations cells.u and cells.v.

Examples:

>>> from skcomplex.models.chemistry.pattern_formation import schnakenberg
>>> schnakenberg((8, 8)).elements[0].values['Dv']
40.0
Source code in src/skcomplex/models/chemistry/pattern_formation/_reaction_diffusion.py
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
@register_model(
    field='chemistry/pattern_formation',
    tags=('field', 'reaction-diffusion', 'Turing', 'pde'),
    references=('Schnakenberg 1979', 'Turing 1952', 'Murray 2003'),
    defaults={'until': 200.0, 'dt': 5.0, 'solver': RK4Solver(dt=0.005)},
)
def schnakenberg(
    shape: Sequence[int] = (64, 64),
    *,
    a: float = 0.1,
    b: float = 0.9,
    Du: float = 1.0,
    Dv: float = 40.0,
    spacing: float = 1.0,
    random_state: int | np.random.Generator | None = 0,
) -> System:
    """Return the Schnakenberg reaction-diffusion model, which forms Turing patterns from noise when `Dv >> Du`.

    The steady state `u = a + b`, `v = b / (a + b)^2` is stable without diffusion and unstable to perturbations of a
    band of wavelengths with it.

    Args:
        shape:
            The number of sites along every dimension of the periodic lattice.

        a:
            The production of `u`.

        b:
            The production of `v`.

        Du:
            The diffusion of the activator `u`.

        Dv:
            The diffusion of the inhibitor `v`.

        spacing:
            The distance between sites.

        random_state:
            The seed or generator of the noise.

    Returns:
        system:
            The model, with the concentrations `cells.u` and `cells.v`.

    Examples:
        >>> from skcomplex.models.chemistry.pattern_formation import schnakenberg
        >>> schnakenberg((8, 8)).elements[0].values['Dv']
        40.0
    """
    shape = tuple(shape)
    steady_u, steady_v = a + b, b / (a + b) ** 2
    values = {
        'u': steady_u * (1 + _noise(shape, 0.01, random_state)),
        'v': np.full(shape, steady_v),
        'a': a,
        'b': b,
        'Du': Du,
        'Dv': Dv,
    }
    return System(
        elements=[
            FieldElement(
                'cells',
                element=SchnakenbergElement,
                space=LatticeSpace(shape, spacing=spacing),
                values=values,
            ),
        ],
        interactions=[*_get_schnakenberg_reactions(), *_get_diffusions()],
    )