0
# Trackers
1
2
Tracker classes monitor simulation progress, collect data, create visualizations, and implement custom analysis during PDE time evolution with flexible interrupt scheduling.
3
4
## Capabilities
5
6
### Data Collection Trackers
7
8
Collect and store field data during simulations for analysis and visualization.
9
10
```python { .api }
11
class DataTracker:
12
def __init__(self, interrupts=1, *, filename=None):
13
"""
14
Track field data throughout simulation.
15
16
Parameters:
17
- interrupts: interrupt schedule for data collection
18
- filename: str, optional file for data storage
19
"""
20
21
@property
22
def data(self):
23
"""MemoryStorage: Collected field data"""
24
25
def get_time_series(self, *, field_index=0):
26
"""
27
Extract time series data for analysis.
28
29
Parameters:
30
- field_index: int, field index for FieldCollection
31
32
Returns:
33
dict: Time series data with 't' and 'data' arrays
34
"""
35
36
class CallbackTracker:
37
def __init__(self, func, interrupts=1):
38
"""
39
Call custom function during simulation.
40
41
Parameters:
42
- func: callable, function to call with (state, time)
43
- interrupts: interrupt schedule
44
"""
45
46
def handle(self, field, t):
47
"""
48
Handle data by calling user function.
49
50
Parameters:
51
- field: FieldBase, current field state
52
- t: float, current time
53
"""
54
```
55
56
### Visualization Trackers
57
58
Create plots and visualizations during simulation execution.
59
60
```python { .api }
61
class PlotTracker:
62
def __init__(self, interrupts=1, *, filename=None, **kwargs):
63
"""
64
Create static plots during simulation.
65
66
Parameters:
67
- interrupts: interrupt schedule for plotting
68
- filename: str, filename pattern (supports time formatting)
69
- kwargs: additional plotting parameters
70
"""
71
72
def finalize(self):
73
"""Finalize and save any pending plots"""
74
75
class LivePlotTracker:
76
def __init__(self, interrupts=1, *, show=True, **kwargs):
77
"""
78
Create live updating plots during simulation.
79
80
Parameters:
81
- interrupts: interrupt schedule for plot updates
82
- show: bool, whether to display plots
83
- kwargs: additional plotting parameters
84
"""
85
86
class InteractivePlotTracker:
87
def __init__(self, interrupts=1, *, **kwargs):
88
"""
89
Interactive plotting with napari integration.
90
91
Parameters:
92
- interrupts: interrupt schedule
93
- kwargs: napari viewer parameters
94
95
Note:
96
Requires napari installation
97
"""
98
```
99
100
### Progress and Status Trackers
101
102
Monitor simulation progress and provide status updates.
103
104
```python { .api }
105
class ProgressTracker:
106
def __init__(self, interrupts="0:10"):
107
"""
108
Display simulation progress bar.
109
110
Parameters:
111
- interrupts: interrupt schedule (default: every 10 real-time seconds)
112
"""
113
114
class PrintTracker:
115
def __init__(self, interrupts=1):
116
"""
117
Print field information during simulation.
118
119
Parameters:
120
- interrupts: interrupt schedule for printing
121
"""
122
123
class RuntimeTracker:
124
def __init__(self, interrupts=1):
125
"""
126
Track simulation runtime and performance.
127
128
Parameters:
129
- interrupts: interrupt schedule for timing updates
130
"""
131
132
@property
133
def runtime(self):
134
"""float: Total runtime in seconds"""
135
136
def get_performance_data(self):
137
"""
138
Get detailed performance statistics.
139
140
Returns:
141
dict: Performance metrics
142
"""
143
```
144
145
### Analysis Trackers
146
147
Analyze field properties and detect special conditions during simulation.
148
149
```python { .api }
150
class SteadyStateTracker:
151
def __init__(self, atol=1e-8, rtol=1e-5, interrupts=1):
152
"""
153
Detect when simulation reaches steady state.
154
155
Parameters:
156
- atol: float, absolute tolerance for steady state
157
- rtol: float, relative tolerance for steady state
158
- interrupts: interrupt schedule for checking
159
"""
160
161
@property
162
def is_steady_state(self):
163
"""bool: Whether steady state has been reached"""
164
165
class ConsistencyTracker:
166
def __init__(self, interrupts=1):
167
"""
168
Check field consistency and detect numerical issues.
169
170
Parameters:
171
- interrupts: interrupt schedule for consistency checks
172
"""
173
174
def check_finite(self, field):
175
"""
176
Check if field contains only finite values.
177
178
Parameters:
179
- field: FieldBase, field to check
180
181
Returns:
182
bool: True if all values are finite
183
"""
184
185
class MaterialConservationTracker:
186
def __init__(self, interrupts=1):
187
"""
188
Monitor conservation of integrated quantities.
189
190
Parameters:
191
- interrupts: interrupt schedule for conservation checks
192
"""
193
194
@property
195
def conserved_quantity(self):
196
"""float: Current value of conserved quantity"""
197
```
198
199
### Interrupt Scheduling
200
201
Classes for defining when trackers should be called during simulation.
202
203
```python { .api }
204
class ConstantInterrupts:
205
def __init__(self, dt):
206
"""
207
Constant time intervals.
208
209
Parameters:
210
- dt: float, time interval between interrupts
211
"""
212
213
class FixedInterrupts:
214
def __init__(self, times):
215
"""
216
Fixed time points.
217
218
Parameters:
219
- times: array-like, specific times for interrupts
220
"""
221
222
class LogarithmicInterrupts:
223
def __init__(self, t_start, t_end, *, factor=2):
224
"""
225
Logarithmically spaced intervals.
226
227
Parameters:
228
- t_start: float, first interrupt time
229
- t_end: float, final time
230
- factor: float, spacing factor between interrupts
231
"""
232
233
class RealtimeInterrupts:
234
def __init__(self, duration):
235
"""
236
Real-time based intervals.
237
238
Parameters:
239
- duration: float, real-time seconds between interrupts
240
"""
241
242
def parse_interrupt(interrupts):
243
"""
244
Parse interrupt specification from various formats.
245
246
Parameters:
247
- interrupts: int, float, str, or InterruptData, interrupt specification
248
249
Returns:
250
InterruptData: Parsed interrupt schedule
251
"""
252
```
253
254
### Tracker Management
255
256
Functions and classes for organizing multiple trackers.
257
258
```python { .api }
259
def get_named_trackers():
260
"""
261
Get dictionary of available named trackers.
262
263
Returns:
264
dict: Mapping of names to tracker classes
265
"""
266
267
class TrackerCollection:
268
def __init__(self, trackers=None):
269
"""
270
Collection of multiple trackers.
271
272
Parameters:
273
- trackers: list of TrackerBase, trackers to collect
274
"""
275
276
def append(self, tracker):
277
"""
278
Add tracker to collection.
279
280
Parameters:
281
- tracker: TrackerBase, tracker to add
282
"""
283
284
def handle(self, field, t):
285
"""
286
Handle data with all trackers in collection.
287
288
Parameters:
289
- field: FieldBase, current field state
290
- t: float, current time
291
"""
292
```
293
294
## Usage Examples
295
296
### Basic Data Collection
297
298
```python
299
import pde
300
301
# Set up simulation
302
grid = pde.UnitGrid([64], periodic=True)
303
state = pde.ScalarField.random_uniform(grid)
304
eq = pde.DiffusionPDE(diffusivity=0.1)
305
306
# Track data every 0.5 time units
307
tracker = pde.DataTracker(interrupts=0.5)
308
309
# Run simulation
310
result = eq.solve(state, t_range=10.0, tracker=tracker)
311
312
# Analyze collected data
313
times = tracker.data.times
314
print(f"Collected {len(times)} time points")
315
print(f"Time range: {times[0]:.2f} to {times[-1]:.2f}")
316
```
317
318
### Visualization During Simulation
319
320
```python
321
import pde
322
323
grid = pde.CartesianGrid([[0, 10], [0, 10]], [64, 64])
324
state = pde.ScalarField.random_uniform(grid)
325
eq = pde.AllenCahnPDE()
326
327
# Create movie during simulation
328
movie_tracker = pde.PlotTracker(
329
interrupts=0.1,
330
filename="evolution_{time:06.2f}.png"
331
)
332
333
# Live plot updates
334
live_tracker = pde.LivePlotTracker(interrupts=0.5)
335
336
# Combine trackers
337
trackers = [movie_tracker, live_tracker]
338
339
result = eq.solve(state, t_range=5.0, tracker=trackers)
340
print("Simulation complete - check generated images")
341
```
342
343
### Progress Monitoring
344
345
```python
346
import pde
347
348
# Long-running simulation setup
349
grid = pde.UnitGrid([128, 128], periodic=True)
350
eq = pde.SwiftHohenbergPDE()
351
state = eq.get_initial_condition(grid)
352
353
# Multiple progress trackers
354
trackers = [
355
pde.ProgressTracker(), # Progress bar
356
pde.RuntimeTracker(interrupts=1.0), # Performance monitoring
357
pde.PrintTracker(interrupts=5.0) # Periodic status prints
358
]
359
360
result = eq.solve(state, t_range=100.0, tracker=trackers)
361
```
362
363
### Steady State Detection
364
365
```python
366
import pde
367
368
grid = pde.UnitGrid([64], periodic=False)
369
eq = pde.DiffusionPDE(diffusivity=1.0)
370
state = pde.ScalarField.random_uniform(grid, 0.4, 0.6)
371
372
# Detect when simulation reaches steady state
373
steady_tracker = pde.SteadyStateTracker(
374
atol=1e-6,
375
rtol=1e-4,
376
interrupts=0.1
377
)
378
379
try:
380
result = eq.solve(state, t_range=float('inf'), tracker=steady_tracker)
381
print(f"Reached steady state at t={steady_tracker.time:.3f}")
382
except StopIteration:
383
print("Steady state detected - simulation stopped")
384
```
385
386
### Custom Analysis Tracker
387
388
```python
389
import pde
390
import numpy as np
391
392
class EnergyTracker(pde.TrackerBase):
393
"""Custom tracker for monitoring system energy"""
394
395
def __init__(self, interrupts=1):
396
super().__init__(interrupts=interrupts)
397
self.energies = []
398
self.times = []
399
400
def handle(self, field, t):
401
# Calculate energy as field variance
402
energy = np.var(field.data)
403
self.energies.append(energy)
404
self.times.append(t)
405
406
# Stop if energy becomes too high
407
if energy > 10.0:
408
raise StopIteration("Energy exceeded threshold")
409
410
# Use custom tracker
411
grid = pde.UnitGrid([32], periodic=True)
412
eq = pde.KuramotoSivashinskyPDE()
413
state = eq.get_initial_condition(grid)
414
415
energy_tracker = EnergyTracker(interrupts=0.1)
416
result = eq.solve(state, t_range=50.0, tracker=energy_tracker)
417
418
print(f"Final energy: {energy_tracker.energies[-1]:.3f}")
419
```
420
421
### Real-time Interrupt Scheduling
422
423
```python
424
import pde
425
426
grid = pde.UnitGrid([64, 64], periodic=True)
427
eq = pde.AllenCahnPDE()
428
state = eq.get_initial_condition(grid)
429
430
# Different interrupt schedules
431
trackers = [
432
pde.DataTracker("0:30"), # Every 30 real-time seconds
433
pde.PlotTracker("1.0"), # Every 1.0 simulation time units
434
pde.ProgressTracker("0:5") # Every 5 real-time seconds
435
]
436
437
result = eq.solve(state, t_range=20.0, tracker=trackers)
438
```
439
440
## Additional Interrupt Classes
441
442
Additional interrupt scheduling options for specialized use cases.
443
444
```python { .api }
445
class GeometricInterrupts:
446
def __init__(self, initial_dt, factor, *, max_dt=None):
447
"""
448
Geometric sequence of interrupt times.
449
450
Parameters:
451
- initial_dt: float, initial time interval
452
- factor: float, multiplication factor for each step
453
- max_dt: float, optional maximum time interval
454
"""
455
```
456
457
## Tracker Registry Functions
458
459
Functions for discovering and managing available tracker types.
460
461
```python { .api }
462
def get_named_trackers():
463
"""
464
Get dictionary of all named tracker classes.
465
466
Returns:
467
dict: Mapping of names to tracker classes
468
"""
469
470
def parse_interrupt(interrupts, t_start=0, t_end=None):
471
"""
472
Parse interrupt specification into interrupt object.
473
474
Parameters:
475
- interrupts: interrupt specification (float, str, or object)
476
- t_start: float, start time for simulation
477
- t_end: float, end time for simulation
478
479
Returns:
480
InterruptBase: Parsed interrupt object
481
"""
482
```