0
# PDEs
1
2
PDE classes provide mathematical descriptions of partial differential equations with automatic operator compilation and built-in support for common equations in physics and dynamical systems.
3
4
## Capabilities
5
6
### Generic PDE
7
8
General PDE class for defining custom differential equations using mathematical expressions.
9
10
```python { .api }
11
class PDE:
12
def __init__(self, rhs, *, noise=None, is_sde_value=None):
13
"""
14
Initialize generic PDE.
15
16
Parameters:
17
- rhs: callable or dict, right-hand side of PDE
18
- noise: float or FieldBase, noise strength for stochastic PDEs
19
- is_sde_value: bool, whether noise affects the value directly
20
"""
21
22
def solve(self, initial_state, t_range, *, dt=None, solver="auto",
23
tracker=None, bc=None, **kwargs):
24
"""
25
Solve the PDE with given initial conditions.
26
27
Parameters:
28
- initial_state: FieldBase, initial field configuration
29
- t_range: float or array-like, time range for integration
30
- dt: float, time step (auto-determined if None)
31
- solver: str or SolverBase, time integration method
32
- tracker: TrackerBase or list, simulation tracking
33
- bc: boundary conditions
34
- kwargs: additional solver parameters
35
36
Returns:
37
FieldBase: Final field state
38
"""
39
40
def evolution_rate(self, state, t=0):
41
"""
42
Calculate time derivative of state.
43
44
Parameters:
45
- state: FieldBase, current field state
46
- t: float, current time
47
48
Returns:
49
FieldBase: Time derivative
50
"""
51
52
@property
53
def expressions(self):
54
"""dict: Mathematical expressions defining the PDE"""
55
56
def make_post_step_hook(self, state):
57
"""
58
Create hook function called after each time step.
59
60
Parameters:
61
- state: FieldBase, current field state
62
63
Returns:
64
tuple: (hook_function, hook_data)
65
"""
66
```
67
68
### DiffusionPDE
69
70
Standard diffusion equation with optional convection and reaction terms.
71
72
```python { .api }
73
class DiffusionPDE:
74
def __init__(self, diffusivity=1, *, bc=None, noise=0, rng=None):
75
"""
76
Initialize diffusion PDE: ∂c/∂t = D∇²c + η
77
78
Parameters:
79
- diffusivity: float, diffusion coefficient
80
- bc: boundary conditions
81
- noise: float, noise strength (default: 0)
82
- rng: numpy random generator for noise (optional)
83
"""
84
85
@property
86
def diffusivity(self):
87
"""Diffusion coefficient"""
88
89
def get_initial_condition(self, grid, **kwargs):
90
"""
91
Get suitable initial condition for the grid.
92
93
Parameters:
94
- grid: GridBase, spatial grid
95
- kwargs: additional parameters
96
97
Returns:
98
ScalarField: Initial condition
99
"""
100
```
101
102
### AllenCahnPDE
103
104
Allen-Cahn equation for phase separation dynamics.
105
106
```python { .api }
107
class AllenCahnPDE:
108
def __init__(self, a=1, b=1, *, noise=None, bc=None):
109
"""
110
Initialize Allen-Cahn PDE: ∂φ/∂t = a∇²φ + bφ - bφ³ + η
111
112
Parameters:
113
- a: float, interface energy parameter
114
- b: float, bulk energy parameter
115
- noise: float or FieldBase, noise strength
116
- bc: boundary conditions
117
"""
118
119
def get_initial_condition(self, grid, **kwargs):
120
"""
121
Get random initial condition with appropriate statistics.
122
123
Parameters:
124
- grid: GridBase, spatial grid
125
- kwargs: parameters like 'amplitude' for noise level
126
127
Returns:
128
ScalarField: Random initial condition
129
"""
130
```
131
132
### CahnHilliardPDE
133
134
Cahn-Hilliard equation for conserved phase separation.
135
136
```python { .api }
137
class CahnHilliardPDE:
138
def __init__(self, a=1, b=1, *, noise=None, bc=None):
139
"""
140
Initialize Cahn-Hilliard PDE: ∂φ/∂t = ∇²[aφ - bφ³ - ∇²φ] + η
141
142
Parameters:
143
- a: float, linear coefficient
144
- b: float, nonlinear coefficient
145
- noise: float or FieldBase, noise strength
146
- bc: boundary conditions
147
"""
148
```
149
150
### WavePDE
151
152
Wave equation for oscillatory dynamics.
153
154
```python { .api }
155
class WavePDE:
156
def __init__(self, speed=1, *, noise=None, bc=None):
157
"""
158
Initialize wave PDE: ∂²u/∂t² = c²∇²u + η
159
160
Parameters:
161
- speed: float, wave propagation speed
162
- noise: float or FieldBase, noise strength
163
- bc: boundary conditions
164
"""
165
166
def get_initial_condition(self, u, v=None):
167
"""
168
Create suitable initial condition with position and velocity.
169
170
Parameters:
171
- u: ScalarField, initial position field
172
- v: ScalarField, optional initial velocity field (zeros if None)
173
174
Returns:
175
FieldCollection: Initial [position, velocity] fields
176
"""
177
```
178
179
### KuramotoSivashinskyPDE
180
181
Kuramoto-Sivashinsky equation exhibiting spatiotemporal chaos.
182
183
```python { .api }
184
class KuramotoSivashinskyPDE:
185
def __init__(self, *, noise=None, bc=None):
186
"""
187
Initialize Kuramoto-Sivashinsky PDE: ∂u/∂t = -∇²u - ∇⁴u - ½|∇u|² + η
188
189
Parameters:
190
- noise: float or FieldBase, noise strength
191
- bc: boundary conditions (typically periodic)
192
"""
193
```
194
195
### SwiftHohenbergPDE
196
197
Swift-Hohenberg equation for pattern formation.
198
199
```python { .api }
200
class SwiftHohenbergPDE:
201
def __init__(self, a=1, b=1, *, noise=None, bc=None):
202
"""
203
Initialize Swift-Hohenberg PDE: ∂u/∂t = au - (1+∇²)²u - bu³ + η
204
205
Parameters:
206
- a: float, linear instability parameter
207
- b: float, nonlinear saturation parameter
208
- noise: float or FieldBase, noise strength
209
- bc: boundary conditions
210
"""
211
```
212
213
### KPZInterfacePDE
214
215
Kardar-Parisi-Zhang equation for interface growth.
216
217
```python { .api }
218
class KPZInterfacePDE:
219
def __init__(self, diffusivity=1, lambda_=1, *, noise=1, bc=None):
220
"""
221
Initialize KPZ interface PDE: ∂h/∂t = D∇²h + λ|∇h|² + η
222
223
Parameters:
224
- diffusivity: float, surface tension coefficient
225
- lambda_: float, nonlinear growth coefficient
226
- noise: float, noise strength
227
- bc: boundary conditions
228
"""
229
```
230
231
### Elliptic Equation Solvers
232
233
Direct solvers for elliptic PDEs like Laplace and Poisson equations.
234
235
```python { .api }
236
def solve_laplace_equation(grid, bc, *, solver="auto"):
237
"""
238
Solve Laplace equation ∇²u = 0.
239
240
Parameters:
241
- grid: GridBase, spatial grid
242
- bc: boundary conditions
243
- solver: str, solution method ("scipy" or "numba")
244
245
Returns:
246
ScalarField: Solution field
247
"""
248
249
def solve_poisson_equation(grid, rhs, bc, *, solver="auto"):
250
"""
251
Solve Poisson equation ∇²u = f.
252
253
Parameters:
254
- grid: GridBase, spatial grid
255
- rhs: ScalarField or callable, right-hand side
256
- bc: boundary conditions
257
- solver: str, solution method
258
259
Returns:
260
ScalarField: Solution field
261
"""
262
```
263
264
### PDEBase
265
266
Base class providing common PDE functionality.
267
268
```python { .api }
269
class PDEBase:
270
@property
271
def complex_valued(self):
272
"""bool: Whether PDE involves complex values"""
273
274
@property
275
def is_sde(self):
276
"""bool: Whether this is a stochastic differential equation"""
277
278
def make_post_step_hook(self, state):
279
"""
280
Create hook function called after each time step.
281
282
Parameters:
283
- state: FieldBase, current field state
284
285
Returns:
286
tuple: (hook_function, hook_data)
287
"""
288
289
def evolution_rate(self, state, t=0):
290
"""
291
Calculate time derivative of state (abstract method).
292
293
Parameters:
294
- state: FieldBase, current field state
295
- t: float, current time
296
297
Returns:
298
FieldBase: Time derivative
299
"""
300
301
def check_rhs_consistency(self, state, t=0):
302
"""
303
Check consistency of right-hand side calculation.
304
305
Parameters:
306
- state: FieldBase, current field state
307
- t: float, current time
308
309
Returns:
310
bool: True if consistent
311
"""
312
313
def make_pde_rhs(self, state, backend='auto'):
314
"""
315
Create compiled right-hand side function.
316
317
Parameters:
318
- state: FieldBase, field state for compilation
319
- backend: str, computational backend
320
321
Returns:
322
Callable: Compiled RHS function
323
"""
324
325
def noise_realization(self, state, t=0, label=None):
326
"""
327
Generate noise realization for stochastic PDEs.
328
329
Parameters:
330
- state: FieldBase, current field state
331
- t: float, current time
332
- label: str, optional label for noise field
333
334
Returns:
335
FieldBase: Noise field
336
"""
337
338
def make_sde_rhs(self, state, backend='auto'):
339
"""
340
Create compiled SDE right-hand side function.
341
342
Parameters:
343
- state: FieldBase, field state for compilation
344
- backend: str, computational backend
345
346
Returns:
347
Callable: Compiled SDE RHS function
348
"""
349
350
def get_state_serializer(self, **kwargs):
351
"""
352
Get serializer for PDE state data.
353
354
Parameters:
355
- kwargs: serialization options
356
357
Returns:
358
Callable: State serialization function
359
"""
360
361
def check_initial_condition_compatibility(self, initial_state):
362
"""
363
Check compatibility of initial condition.
364
365
Parameters:
366
- initial_state: FieldBase, initial field state
367
368
Raises:
369
ValueError: If incompatible
370
"""
371
```
372
373
## Usage Examples
374
375
### Solving Standard PDEs
376
377
```python
378
import pde
379
import numpy as np
380
381
# Create grid and initial condition
382
grid = pde.UnitGrid([64, 64], periodic=False)
383
state = pde.ScalarField.random_uniform(grid, 0.2, 0.3)
384
385
# Solve diffusion equation
386
eq = pde.DiffusionPDE(diffusivity=0.1)
387
result = eq.solve(state, t_range=10.0, dt=0.01)
388
389
print(f"Initial average: {state.average:.3f}")
390
print(f"Final average: {result.average:.3f}")
391
```
392
393
### Custom PDE with Expression
394
395
```python
396
import pde
397
398
# Define custom reaction-diffusion PDE
399
def my_pde_rhs(state, t):
400
c = state
401
return 0.1 * c.laplace("auto_periodic_neumann") + c - c**3
402
403
# Create PDE
404
grid = pde.UnitGrid([32], periodic=True)
405
initial = pde.ScalarField.random_uniform(grid, -0.1, 0.1)
406
407
eq = pde.PDE(my_pde_rhs)
408
result = eq.solve(initial, t_range=50)
409
```
410
411
### Wave Equation Simulation
412
413
```python
414
import pde
415
import matplotlib.pyplot as plt
416
417
# Set up 1D wave equation
418
grid = pde.UnitGrid([128], periodic=False)
419
eq = pde.WavePDE(speed=1.0)
420
421
# Gaussian initial condition
422
initial = eq.get_initial_condition(grid)
423
initial[0] = pde.ScalarField.from_expression(grid, "exp(-(x-0.3)**2/0.01)")
424
425
# Solve with progress tracking
426
tracker = pde.PlotTracker(interrupts=0.1, filename="wave_evolution.mp4")
427
result = eq.solve(initial, t_range=2.0, tracker=tracker)
428
429
print("Wave simulation complete - check wave_evolution.mp4")
430
```
431
432
### Elliptic PDE Solutions
433
434
```python
435
import pde
436
437
# Solve Poisson equation with source term
438
grid = pde.CartesianGrid([[-1, 1], [-1, 1]], [64, 64])
439
440
# Source term: Gaussian
441
source = pde.ScalarField.from_expression(grid, "exp(-(x**2 + y**2)/0.1)")
442
443
# Dirichlet boundary conditions
444
bc = {"value": 0}
445
446
# Solve Poisson equation
447
solution = pde.solve_poisson_equation(grid, source, bc)
448
449
print(f"Source integral: {source.integral():.3f}")
450
print(f"Solution range: [{solution.data.min():.3f}, {solution.data.max():.3f}]")
451
```