0
# Solvers
1
2
Solver classes provide time integration algorithms for evolving PDE systems with adaptive time stepping, stability control, and parallel computing support through MPI.
3
4
## Capabilities
5
6
### Controller
7
8
High-level solver controller that manages time integration with automatic solver selection and progress tracking.
9
10
```python { .api }
11
class Controller:
12
def __init__(self, sol_class, *, t_range, tracker=None):
13
"""
14
Initialize solver controller.
15
16
Parameters:
17
- sol_class: SolverBase class or instance, time integration solver
18
- t_range: float or array-like, time integration range
19
- tracker: TrackerBase or list, progress tracking
20
"""
21
22
def run(self, initial_state, dt=None, **kwargs):
23
"""
24
Run the simulation.
25
26
Parameters:
27
- initial_state: FieldBase, initial field configuration
28
- dt: float, time step (auto-determined if None)
29
- kwargs: additional solver parameters
30
31
Returns:
32
FieldBase: Final field state
33
"""
34
35
@property
36
def solver(self):
37
"""SolverBase: The underlying solver instance"""
38
39
@property
40
def tracker(self):
41
"""TrackerCollection: Collection of trackers"""
42
```
43
44
### ExplicitSolver
45
46
Explicit time stepping methods with adaptive time step control.
47
48
```python { .api }
49
class ExplicitSolver:
50
def __init__(self, pde, scheme="euler", *, backend="auto", adaptive=False, tolerance=1e-4):
51
"""
52
Initialize explicit solver.
53
54
Parameters:
55
- pde: PDEBase, the PDE to solve
56
- scheme: str, integration scheme ("euler", "runge-kutta", "rk", "rk45")
57
- backend: str, computation backend ("auto", "numpy", "numba")
58
- adaptive: bool, enable adaptive time stepping
59
- tolerance: float, error tolerance for adaptive stepping
60
"""
61
62
def make_stepper(self, state, dt):
63
"""
64
Create compiled stepper function.
65
66
Parameters:
67
- state: FieldBase, example state for compilation
68
- dt: float, time step
69
70
Returns:
71
Callable: Compiled stepper function
72
"""
73
74
@property
75
def pde(self):
76
"""PDEBase: The PDE being solved"""
77
78
@property
79
def info(self):
80
"""dict: Solver information and statistics"""
81
```
82
83
### ImplicitSolver
84
85
Implicit time stepping methods for stiff PDEs requiring large time steps.
86
87
```python { .api }
88
class ImplicitSolver:
89
def __init__(self, pde, *, scheme="backward_euler"):
90
"""
91
Initialize implicit solver.
92
93
Parameters:
94
- pde: PDEBase, the PDE to solve
95
- scheme: str, integration scheme ("backward_euler")
96
"""
97
98
def solve_newton(self, state, dt, *, newton_options=None):
99
"""
100
Solve nonlinear system using Newton's method.
101
102
Parameters:
103
- state: FieldBase, current state
104
- dt: float, time step
105
- newton_options: dict, Newton solver options
106
107
Returns:
108
FieldBase: Updated state
109
"""
110
```
111
112
### CrankNicolsonSolver
113
114
Crank-Nicolson scheme providing second-order accuracy in time.
115
116
```python { .api }
117
class CrankNicolsonSolver:
118
def __init__(self, pde):
119
"""
120
Initialize Crank-Nicolson solver for linear PDEs.
121
122
Parameters:
123
- pde: PDEBase, the PDE to solve (must be linear)
124
"""
125
126
def make_stepper(self, state, dt):
127
"""
128
Create stepper for Crank-Nicolson scheme.
129
130
Parameters:
131
- state: FieldBase, example state
132
- dt: float, time step
133
134
Returns:
135
Callable: Stepper function
136
"""
137
```
138
139
### AdamsBashforthSolver
140
141
Adams-Bashforth multi-step method with higher-order accuracy.
142
143
```python { .api }
144
class AdamsBashforthSolver:
145
def __init__(self, pde, *, order=2):
146
"""
147
Initialize Adams-Bashforth solver.
148
149
Parameters:
150
- pde: PDEBase, the PDE to solve
151
- order: int, order of the method (1-4)
152
"""
153
154
@property
155
def order(self):
156
"""int: Order of the Adams-Bashforth method"""
157
158
def make_stepper(self, state, dt):
159
"""
160
Create multi-step stepper function.
161
162
Parameters:
163
- state: FieldBase, example state
164
- dt: float, time step
165
166
Returns:
167
Callable: Multi-step stepper function
168
"""
169
```
170
171
### ScipySolver
172
173
Interface to SciPy's ODE integration methods with automatic stiffness detection.
174
175
```python { .api }
176
class ScipySolver:
177
def __init__(self, pde, *, method="RK45"):
178
"""
179
Initialize SciPy solver wrapper.
180
181
Parameters:
182
- pde: PDEBase, the PDE to solve
183
- method: str, SciPy integration method
184
("RK45", "RK23", "DOP853", "Radau", "BDF", "LSODA")
185
"""
186
187
@property
188
def method(self):
189
"""str: SciPy integration method being used"""
190
191
def solve(self, initial_state, t_span, **kwargs):
192
"""
193
Solve using SciPy integration.
194
195
Parameters:
196
- initial_state: FieldBase, initial condition
197
- t_span: tuple, (t_start, t_end)
198
- kwargs: additional SciPy solver options
199
200
Returns:
201
FieldBase: Final state
202
"""
203
```
204
205
### ExplicitMPISolver
206
207
MPI-parallel explicit solver for distributed computing (requires MPI installation).
208
209
```python { .api }
210
class ExplicitMPISolver:
211
def __init__(self, pde, *, scheme="euler"):
212
"""
213
Initialize MPI parallel explicit solver.
214
215
Parameters:
216
- pde: PDEBase, the PDE to solve
217
- scheme: str, integration scheme
218
219
Note:
220
Only available if MPI dependencies are installed
221
"""
222
223
@property
224
def is_mpi_root(self):
225
"""bool: True if this is the root MPI process"""
226
227
def make_stepper(self, state, dt):
228
"""
229
Create MPI-parallel stepper.
230
231
Parameters:
232
- state: FieldBase, example state
233
- dt: float, time step
234
235
Returns:
236
Callable: MPI-parallel stepper function
237
"""
238
```
239
240
### Solver Registry
241
242
Functions for managing and discovering available solvers.
243
244
```python { .api }
245
def registered_solvers():
246
"""
247
Get list of all registered solver names.
248
249
Returns:
250
list of str: Names of available solvers
251
"""
252
```
253
254
### SolverBase
255
256
Base class providing common solver functionality.
257
258
```python { .api }
259
class SolverBase:
260
@classmethod
261
def from_name(cls, name, pde, **kwargs):
262
"""
263
Create solver instance by name.
264
265
Parameters:
266
- name: str, solver name
267
- pde: PDEBase, PDE to solve
268
- kwargs: additional solver parameters
269
270
Returns:
271
SolverBase: Solver instance
272
"""
273
274
@classmethod
275
def registered_solvers(cls):
276
"""
277
Get list of registered solver names.
278
279
Returns:
280
list of str: Available solver names
281
"""
282
283
def make_stepper(self, state, dt=None):
284
"""
285
Create time stepping function (abstract method).
286
287
Parameters:
288
- state: FieldBase, example state for compilation
289
- dt: float, time step
290
291
Returns:
292
Callable: Compiled stepper function
293
"""
294
@property
295
def supports_adaptive_stepping(self):
296
"""bool: Whether solver supports adaptive time steps"""
297
298
def diagnose_performance(self, steps=100, *, state=None):
299
"""
300
Analyze solver performance characteristics.
301
302
Parameters:
303
- steps: int, number of test steps
304
- state: FieldBase, test state (created if None)
305
306
Returns:
307
dict: Performance diagnostics
308
"""
309
310
def check_state_compatibility(self, state):
311
"""
312
Check if state is compatible with solver.
313
314
Parameters:
315
- state: FieldBase, state to check
316
317
Raises:
318
ValueError: If incompatible
319
"""
320
```
321
322
## Usage Examples
323
324
### Basic Solver Usage
325
326
```python
327
import pde
328
329
# Set up problem
330
grid = pde.UnitGrid([64, 64], periodic=False)
331
state = pde.ScalarField.random_uniform(grid, 0.2, 0.3)
332
eq = pde.DiffusionPDE(diffusivity=0.1)
333
334
# Use explicit solver
335
solver = pde.ExplicitSolver(eq, adaptive=True)
336
result = eq.solve(state, t_range=10.0, solver=solver)
337
338
print(f"Solver info: {solver.info}")
339
```
340
341
### Comparing Solver Performance
342
343
```python
344
import pde
345
import time
346
347
# Set up test problem
348
grid = pde.UnitGrid([32, 32], periodic=True)
349
state = pde.ScalarField.random_uniform(grid)
350
eq = pde.AllenCahnPDE()
351
352
solvers = {
353
"explicit": pde.ExplicitSolver(eq),
354
"implicit": pde.ImplicitSolver(eq),
355
"crank_nicolson": pde.CrankNicolsonSolver(eq),
356
"scipy_rk45": pde.ScipySolver(eq, method="RK45")
357
}
358
359
# Time each solver
360
for name, solver in solvers.items():
361
start_time = time.time()
362
result = eq.solve(state.copy(), t_range=1.0, solver=solver)
363
elapsed = time.time() - start_time
364
print(f"{name}: {elapsed:.3f}s")
365
```
366
367
### Advanced Solver Configuration
368
369
```python
370
import pde
371
372
# Set up stiff PDE requiring implicit methods
373
grid = pde.CartesianGrid([[0, 10]], [128])
374
eq = pde.DiffusionPDE(diffusivity=100) # High diffusivity = stiff
375
376
# Configure implicit solver with Newton options
377
newton_opts = {
378
"maxiter": 10,
379
"atol": 1e-8,
380
"rtol": 1e-6
381
}
382
383
solver = pde.ImplicitSolver(eq)
384
state = pde.ScalarField.random_uniform(grid)
385
386
# Use controller for automatic management
387
controller = pde.Controller(
388
solver,
389
t_range=1.0,
390
tracker=pde.ProgressTracker()
391
)
392
393
result = controller.run(state, dt=0.1)
394
print(f"Simulation completed successfully")
395
```
396
397
### Adaptive Time Stepping
398
399
```python
400
import pde
401
402
# Problem with varying time scales
403
grid = pde.UnitGrid([64])
404
eq = pde.KuramotoSivashinskyPDE()
405
state = eq.get_initial_condition(grid)
406
407
# Enable adaptive stepping
408
solver = pde.ExplicitSolver(eq, adaptive=True)
409
410
# Set up detailed tracking
411
tracker = [
412
pde.DataTracker(interrupts=0.1),
413
pde.RuntimeTracker(interrupts=1.0)
414
]
415
416
result = eq.solve(
417
state,
418
t_range=100.0,
419
solver=solver,
420
tracker=tracker,
421
dt=0.01, # Initial time step
422
adaptive={"atol": 1e-4, "rtol": 1e-3} # Tolerance for adaptation
423
)
424
425
print(f"Adaptive stepping completed")
426
```
427
428
## Solver Registry
429
430
Function for discovering available solver types.
431
432
```python { .api }
433
def registered_solvers():
434
"""
435
Get list of all registered solver names.
436
437
Returns:
438
list of str: Names of available solver classes
439
"""
440
```