0
# Grids
1
2
Grid classes define spatial domains with coordinate systems and discretization for solving PDEs. py-pde supports regular orthogonal grids in various coordinate systems including Cartesian, polar, spherical, and cylindrical.
3
4
## Capabilities
5
6
### UnitGrid
7
8
Simple unit grid in Cartesian coordinates, suitable for quick prototyping and testing.
9
10
```python { .api }
11
class UnitGrid:
12
def __init__(self, shape, periodic=True):
13
"""
14
Initialize unit grid with domain [0, 1]^dim.
15
16
Parameters:
17
- shape: int or sequence of ints, number of grid points per axis
18
- periodic: bool or sequence of bools, periodicity per axis
19
"""
20
21
@classmethod
22
def from_state(cls, state):
23
"""
24
Create grid from serialized state.
25
26
Parameters:
27
- state: dict, serialized grid state
28
29
Returns:
30
UnitGrid reconstructed from state
31
"""
32
33
@property
34
def dim(self):
35
"""int: Number of spatial dimensions"""
36
37
@property
38
def shape(self):
39
"""tuple: Number of grid points per axis"""
40
41
@property
42
def periodic(self):
43
"""list of bool: Periodicity per axis"""
44
45
@property
46
def volume(self):
47
"""float: Total volume of the grid"""
48
49
def get_line_data(self, data, *, extract="auto"):
50
"""
51
Extract line data for 1D plotting.
52
53
Parameters:
54
- data: array-like, field data on grid
55
- extract: extraction method
56
57
Returns:
58
dict with 'x' and 'data' arrays
59
"""
60
61
def to_cartesian(self):
62
"""
63
Convert to equivalent CartesianGrid.
64
65
Returns:
66
CartesianGrid with same discretization
67
"""
68
69
def slice(self, indices):
70
"""
71
Create subgrid by slicing.
72
73
Parameters:
74
- indices: slice indices for each axis
75
76
Returns:
77
UnitGrid containing the slice
78
"""
79
```
80
81
### CartesianGrid
82
83
Cartesian grid with customizable domain bounds and discretization.
84
85
```python { .api }
86
class CartesianGrid:
87
def __init__(self, bounds, shape, periodic=False):
88
"""
89
Initialize Cartesian grid.
90
91
Parameters:
92
- bounds: sequence of [min, max] pairs for each axis
93
- shape: int or sequence of ints, number of grid points per axis
94
- periodic: bool or sequence of bools, periodicity per axis
95
"""
96
97
@classmethod
98
def from_state(cls, state):
99
"""
100
Create grid from serialized state.
101
102
Parameters:
103
- state: dict, serialized grid state
104
105
Returns:
106
CartesianGrid reconstructed from state
107
"""
108
109
@classmethod
110
def from_bounds(cls, bounds, shape, periodic=False):
111
"""
112
Create grid from bounds specification.
113
114
Parameters:
115
- bounds: sequence of [min, max] pairs for each axis
116
- shape: int or sequence of ints, number of grid points per axis
117
- periodic: bool or sequence of bools, periodicity per axis
118
119
Returns:
120
CartesianGrid with specified bounds
121
"""
122
123
@property
124
def bounds(self):
125
"""list: Domain bounds [[xmin, xmax], [ymin, ymax], ...]"""
126
127
@property
128
def discretization(self):
129
"""np.ndarray: Grid spacing per axis"""
130
131
@property
132
def axes_bounds(self):
133
"""list: Bounds for each axis"""
134
135
def get_image_data(self, data, **kwargs):
136
"""
137
Prepare data for image visualization.
138
139
Parameters:
140
- data: array-like, field data on grid
141
- kwargs: additional visualization parameters
142
143
Returns:
144
dict with image data and extent information
145
"""
146
147
def cell_to_point(self, cells, *, cartesian=True):
148
"""
149
Convert cell indices to coordinate points.
150
151
Parameters:
152
- cells: array-like, cell indices
153
- cartesian: bool, return Cartesian coordinates
154
155
Returns:
156
np.ndarray: Coordinate points
157
"""
158
159
def point_to_cell(self, points):
160
"""
161
Convert coordinate points to cell indices.
162
163
Parameters:
164
- points: array-like, coordinate points
165
166
Returns:
167
np.ndarray: Cell indices
168
"""
169
170
@property
171
def cell_volume_data(self):
172
"""np.ndarray: Volume of each grid cell"""
173
174
def iter_mirror_points(self, point, num_axes=None):
175
"""
176
Iterate over mirror points considering periodicity.
177
178
Parameters:
179
- point: array-like, reference point
180
- num_axes: int, number of axes to consider
181
182
Yields:
183
np.ndarray: Mirror points
184
"""
185
186
def get_random_point(self, boundary_distance=0, coords='grid', rng=None):
187
"""
188
Generate random point within grid domain.
189
190
Parameters:
191
- boundary_distance: float, minimum distance from boundaries
192
- coords: str, coordinate system ('grid' or 'cartesian')
193
- rng: random number generator
194
195
Returns:
196
np.ndarray: Random point coordinates
197
"""
198
199
def difference_vector(self, p1, p2, coords='grid'):
200
"""
201
Calculate difference vector between two points.
202
203
Parameters:
204
- p1: array-like, first point
205
- p2: array-like, second point
206
- coords: str, coordinate system
207
208
Returns:
209
np.ndarray: Difference vector
210
"""
211
212
def get_vector_data(self, data, **kwargs):
213
"""
214
Prepare vector data for visualization.
215
216
Parameters:
217
- data: array-like, vector field data
218
- kwargs: additional visualization parameters
219
220
Returns:
221
dict: Vector visualization data
222
"""
223
224
def plot(self, ax, **kwargs):
225
"""
226
Plot the grid structure.
227
228
Parameters:
229
- ax: matplotlib axes object
230
- kwargs: plotting parameters
231
"""
232
233
def slice(self, indices):
234
"""
235
Create subgrid by slicing.
236
237
Parameters:
238
- indices: slice indices for each axis
239
240
Returns:
241
CartesianGrid containing the slice
242
"""
243
```
244
245
### PolarSymGrid
246
247
Polar grid with angular symmetry for 2D problems with radial symmetry.
248
249
```python { .api }
250
class PolarSymGrid:
251
def __init__(self, radius, shape, periodic=True):
252
"""
253
Initialize polar symmetric grid.
254
255
Parameters:
256
- radius: float or [r_min, r_max], radial domain
257
- shape: int, number of radial grid points
258
- periodic: bool, periodicity in angular direction
259
"""
260
261
@property
262
def radius(self):
263
"""float: Maximum radius of the grid"""
264
265
@property
266
def axes_bounds(self):
267
"""list: Radial bounds [r_min, r_max]"""
268
269
def transform(self, coordinates, *, with_jacobian=False):
270
"""
271
Transform between coordinate systems.
272
273
Parameters:
274
- coordinates: array-like, coordinates to transform
275
- with_jacobian: bool, whether to return Jacobian
276
277
Returns:
278
np.ndarray or tuple: Transformed coordinates (and Jacobian)
279
"""
280
281
@classmethod
282
def from_state(cls, state):
283
"""
284
Create grid from serialized state.
285
286
Parameters:
287
- state: dict, serialized grid state
288
289
Returns:
290
PolarSymGrid reconstructed from state
291
"""
292
```
293
294
### SphericalSymGrid
295
296
Spherical grid with full spherical symmetry for 3D radially symmetric problems.
297
298
```python { .api }
299
class SphericalSymGrid:
300
def __init__(self, radius, shape):
301
"""
302
Initialize spherical symmetric grid.
303
304
Parameters:
305
- radius: float or [r_min, r_max], radial domain
306
- shape: int, number of radial grid points
307
"""
308
309
@property
310
def coordinate_constraints(self):
311
"""list: Constraints on coordinate values"""
312
313
def get_cartesian_grid(self):
314
"""
315
Get equivalent Cartesian grid for visualization.
316
317
Returns:
318
CartesianGrid: Corresponding Cartesian grid
319
"""
320
321
@classmethod
322
def from_state(cls, state):
323
"""
324
Create grid from serialized state.
325
326
Parameters:
327
- state: dict, serialized grid state
328
329
Returns:
330
SphericalSymGrid reconstructed from state
331
"""
332
```
333
334
### CylindricalSymGrid
335
336
Cylindrical grid with symmetry in angular direction for problems with cylindrical geometry.
337
338
```python { .api }
339
class CylindricalSymGrid:
340
def __init__(self, radius, bounds, shape, periodic_z=True):
341
"""
342
Initialize cylindrical symmetric grid.
343
344
Parameters:
345
- radius: float or [r_min, r_max], radial domain
346
- bounds: [z_min, z_max], axial domain bounds
347
- shape: [r_points, z_points], grid points per axis
348
- periodic_z: bool, periodicity in z-direction
349
"""
350
351
@property
352
def typical_discretization(self):
353
"""np.ndarray: Typical grid spacing"""
354
355
def make_operator_list(self, operator_type):
356
"""
357
Create list of differential operators.
358
359
Parameters:
360
- operator_type: str, type of operator
361
362
Returns:
363
list: Differential operators for this grid
364
"""
365
366
@classmethod
367
def from_state(cls, state):
368
"""
369
Create grid from serialized state.
370
371
Parameters:
372
- state: dict, serialized grid state
373
374
Returns:
375
CylindricalSymGrid reconstructed from state
376
"""
377
```
378
379
### Grid Base Functionality
380
381
Common functionality shared by all grid types.
382
383
```python { .api }
384
class GridBase:
385
@property
386
def coordinate_constraints(self):
387
"""list: Constraints on coordinate values"""
388
389
@property
390
def cell_volume_data(self):
391
"""np.ndarray: Volume of each grid cell"""
392
393
def iter_mirror_points(self, point, with_self=True):
394
"""
395
Iterate over mirror points considering periodicity.
396
397
Parameters:
398
- point: array-like, reference point
399
- with_self: bool, include the original point
400
401
Yields:
402
np.ndarray: Mirror points
403
"""
404
405
def normalize_point(self, point, *, reflect=True):
406
"""
407
Normalize point to grid domain.
408
409
Parameters:
410
- point: array-like, point to normalize
411
- reflect: bool, apply reflection at boundaries
412
413
Returns:
414
np.ndarray: Normalized point
415
"""
416
417
def contains_point(self, point):
418
"""
419
Check if point is inside grid domain.
420
421
Parameters:
422
- point: array-like, point to check
423
424
Returns:
425
bool: True if point is inside domain
426
"""
427
428
@property
429
def state(self):
430
"""dict: Serializable state of the grid"""
431
432
@property
433
def size(self):
434
"""int: Total number of grid points"""
435
436
@property
437
def ndim(self):
438
"""int: Number of spatial dimensions"""
439
440
def copy(self):
441
"""
442
Create a copy of the grid.
443
444
Returns:
445
GridBase: Copy of the grid
446
"""
447
448
def get_boundary_conditions(self, bc, rank=0):
449
"""
450
Process boundary condition specification.
451
452
Parameters:
453
- bc: boundary condition specification
454
- rank: int, tensor rank of the field
455
456
Returns:
457
Processed boundary conditions
458
"""
459
460
def make_operator(self, operator, bc, *, backend='auto'):
461
"""
462
Create differential operator for this grid.
463
464
Parameters:
465
- operator: str, operator name ('laplace', 'gradient', etc.)
466
- bc: boundary conditions
467
- backend: str, computational backend
468
469
Returns:
470
Callable differential operator
471
"""
472
```
473
474
## Usage Examples
475
476
### Creating Different Grid Types
477
478
```python
479
import pde
480
481
# Simple unit grid for prototyping
482
unit_grid = pde.UnitGrid([64, 64], periodic=[True, False])
483
484
# Cartesian grid with custom bounds
485
cart_grid = pde.CartesianGrid([[-5, 5], [0, 10]], [32, 64])
486
487
# Polar grid for radially symmetric problems
488
polar_grid = pde.PolarSymGrid(radius=5.0, shape=64)
489
490
# Cylindrical grid
491
cyl_grid = pde.CylindricalSymGrid(
492
radius=[0, 3], bounds=[-10, 10], shape=[32, 64]
493
)
494
495
print(f"Unit grid volume: {unit_grid.volume}")
496
print(f"Cartesian grid discretization: {cart_grid.discretization}")
497
print(f"Polar grid radius: {polar_grid.radius}")
498
```
499
500
### Grid Coordinate Operations
501
502
```python
503
import pde
504
import numpy as np
505
506
# Create 2D Cartesian grid
507
grid = pde.CartesianGrid([[-2, 2], [-1, 1]], [32, 16])
508
509
# Convert between cell indices and coordinates
510
cell_indices = np.array([[15, 8], [20, 12]])
511
coordinates = grid.cell_to_point(cell_indices)
512
back_to_cells = grid.point_to_cell(coordinates)
513
514
print(f"Cell indices: {cell_indices}")
515
print(f"Coordinates: {coordinates}")
516
print(f"Back to cells: {back_to_cells}")
517
518
# Check if points are inside domain
519
test_points = np.array([[0, 0], [3, 0], [-1.5, 0.8]])
520
inside = [grid.contains_point(p) for p in test_points]
521
print(f"Points inside domain: {inside}")
522
```