Documentation Index
Fetch the complete documentation index at: https://mintlify.com/DedalusProject/dedalus/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The distributor module provides the Distributor class for managing parallel distribution and transformation of fields across MPI processes. It handles domain decomposition, layout management, and coordinate transforms.
Distributor
Distributor Class
Distributor(coordsystems, comm=None, mesh=None, dtype=None)
Manages parallelized distribution and transformation of fields.
Parameters
- coordsystems (CoordinateSystem or tuple): Coordinate system(s) for the domain
- comm (MPI.Comm, optional): MPI communicator (default: MPI.COMM_WORLD)
- mesh (tuple of ints, optional): Process mesh dimensions (default: 1D mesh)
- dtype (dtype, optional): Default data type
Attributes
- dim (int): Number of dimensions
- coords (tuple): Coordinate objects
- mesh (ndarray): Process mesh shape
- comm (MPI.Comm): MPI communicator
- comm_cart (MPI.Comm): Cartesian communicator
- layouts (list): Available data layouts
- coeff_layout (Layout): Coefficient space layout
- grid_layout (Layout): Grid space layout
Example: Basic Setup
import dedalus.public as d3
import numpy as np
from mpi4py import MPI
# 1D domain
coord = d3.Coordinate('x')
dist = d3.Distributor(coord)
# 2D domain
coords = d3.CartesianCoordinates('x', 'y')
dist = d3.Distributor(coords)
# 3D domain with custom mesh
coords = d3.CartesianCoordinates('x', 'y', 'z')
mesh = [2, 2] # 2D process mesh for 3D domain
dist = d3.Distributor(coords, mesh=mesh)
# Check distribution
print(f"Process {dist.comm.rank}/{dist.comm.size}")
print(f"Mesh: {dist.mesh}")
print(f"Coordinates: {dist.comm_cart.coords}")
Example: Multiple Coordinate Systems
import dedalus.public as d3
# Combine different coordinate systems
cart = d3.CartesianCoordinates('x', 'y')
z_coord = d3.Coordinate('z')
dist = d3.Distributor((cart, z_coord))
print(f"Total dimension: {dist.dim}") # 3
Methods
Field Creation
Field(bases=None, …) - Create a field
u = dist.Field(bases=(xbasis, ybasis), name='u')
ScalarField(…) - Create scalar field
T = dist.ScalarField(bases=(xbasis, ybasis), name='T')
VectorField(coordsys, …) - Create vector field
u = dist.VectorField(coords, bases=(xbasis, ybasis), name='u')
TensorField(coordsys_out, coordsys_in, …) - Create tensor field
τ = dist.TensorField(coords, bases=(xbasis, ybasis), name='tau')
IdentityTensor(coordsys_in, coordsys_out) - Create identity tensor
I = dist.IdentityTensor(coords)
Grid Access
local_grid(basis, scale) - Get local grid for basis
x = dist.local_grid(xbasis, scale=1)
*local_grids(bases, scales) - Get local grids for multiple bases
x, y = dist.local_grids(xbasis, ybasis)
Mode Access
local_modes(basis) - Get local mode indices
k = dist.local_modes(xbasis)
Layout Management
get_layout_object(layout) - Get layout from identifier
coeff_layout = dist.get_layout_object('c')
grid_layout = dist.get_layout_object('g')
Utility Methods
get_axis(coord) - Get axis index for coordinate
axis = dist.get_axis(coords['x'])
get_basis_axis(basis) - Get first axis for basis
axis = dist.get_basis_axis(xbasis)
first_axis(basis) - First axis of basis
last_axis(basis) - Last axis of basis
remedy_scales(scales) - Normalize scale specification
scales = dist.remedy_scales(2) # (2, 2, 2) for 3D
scales = dist.remedy_scales((1, 2, 1)) # (1, 2, 1)
Layouts
Layout Objects
Layouts represent different transform/distribution states of field data.
Attributes
- local (ndarray of bool): Which axes are local (not distributed)
- grid_space (ndarray of bool): Which axes are in grid space
- index (int): Layout index in transform sequence
Methods
global_shape(domain, scales) - Global data shape
local_shape(domain, scales) - Local data shape
local_elements(domain, scales) - Local element indices
Dedalus uses multiple layouts to transform between coefficient and grid space:
import dedalus.public as d3
coords = d3.CartesianCoordinates('x', 'y', 'z')
mesh = [2, 2]
dist = d3.Distributor(coords, mesh=mesh)
# Print layout sequence
for i, layout in enumerate(dist.layouts):
print(f"Layout {i}:")
print(f" Local: {layout.local}")
print(f" Grid: {layout.grid_space}")
# Coefficient layout (first)
print(f"\nCoeff layout index: {dist.coeff_layout.index}")
# Grid layout (last)
print(f"Grid layout index: {dist.grid_layout.index}")
Example output for 3D domain on 2×2 mesh:
Layout 0 (coefficient):
Local: [False, False, True]
Grid: [False, False, False]
Layout 1 (transpose):
Local: [False, True, False]
Grid: [False, False, False]
Layout 2 (transform z):
Local: [False, True, False]
Grid: [False, False, True]
Layout 3 (transpose):
Local: [True, False, False]
Grid: [False, False, True]
Layout 4 (transform y):
Local: [True, False, False]
Grid: [False, True, True]
Layout 5 (transform x):
Local: [True, False, False]
Grid: [True, True, True]
Parallelization
Process Mesh
The process mesh determines how data is distributed:
import dedalus.public as d3
from mpi4py import MPI
coords = d3.CartesianCoordinates('x', 'y', 'z')
# 1D mesh (default): all processes along first dimension
mesh = None # or [N] for N processes
dist = d3.Distributor(coords, mesh=mesh)
# 2D mesh: distribute first two dimensions
mesh = [2, 4] # 8 total processes
dist = d3.Distributor(coords, mesh=mesh)
# Check process position
rank = dist.comm.rank
coords = dist.comm_cart.coords
print(f"Rank {rank} at mesh coordinates {coords}")
Domain Decomposition
Data is distributed in different ways depending on layout:
Coefficient space: First R dimensions distributed
Grid space: Dimensions 1 to R distributed
Example for 3D domain on 2×2 mesh:
import dedalus.public as d3
import numpy as np
coords = d3.CartesianCoordinates('x', 'y', 'z')
mesh = [2, 2]
dist = d3.Distributor(coords, mesh=mesh)
xbasis = d3.RealFourier(coords['x'], size=64, bounds=(0, 2*np.pi))
ybasis = d3.RealFourier(coords['y'], size=64, bounds=(0, 2*np.pi))
zbasis = d3.RealFourier(coords['z'], size=64, bounds=(0, 2*np.pi))
u = dist.Field(bases=(xbasis, ybasis, zbasis))
# Coefficient space: x, y distributed; z local
u.change_layout('c')
print(f"Coeff shape: {u.data.shape}") # (~32, ~32, 64)
# Grid space: x local; y, z distributed
u.change_layout('g')
print(f"Grid shape: {u.data.shape}") # (64, ~32, ~32)
Advanced Usage
Custom Communicators
import dedalus.public as d3
from mpi4py import MPI
# Create custom communicator
comm = MPI.COMM_WORLD.Split(color=rank//2, key=rank)
# Use in distributor
coords = d3.CartesianCoordinates('x', 'y')
dist = d3.Distributor(coords, comm=comm)
Multiple Distributors
import dedalus.public as d3
# Different distributors for different domains
coords_xy = d3.CartesianCoordinates('x', 'y')
dist_2d = d3.Distributor(coords_xy, mesh=[2, 2])
coords_xyz = d3.CartesianCoordinates('x', 'y', 'z')
dist_3d = d3.Distributor(coords_xyz, mesh=[2, 2])
See Also