4.5.6 pde.solvers.explicit_mpi module
Defines an explicit solver using multiprocessing via MPI.
TODO: Implement this not as a separate solver but as a separate numba_mpi backend
- class ExplicitMPISolver(pde, decomposition='auto', *, backend='auto', adaptive=False, tolerance=0.0001)[source]
Bases:
EulerSolverExplicit Euler solver using MPI.
Warning
This solver can only be used if MPI is properly installed. In particular, python scripts then need to be started using
mpirunormpiexec. Please refer to the documentation of your MPI distribution for details.The main idea of the solver is to take the full initial state in the main node (ID 0) and split the grid into roughly equal subgrids. The main node then distributes these subfields to all other nodes and each node creates the right hand side of the PDE for itself (and independently). Each node then advances the PDE independently, ensuring proper coupling to neighboring nodes via special boundary conditions, which exchange field values between sub grids. This is implemented by the
get_boundary_conditions()method of the sub grids, which takes the boundary conditions for the full grid and creates conditions suitable for the specific sub grid on the given node. The trackers (and thus all input and output) are only handled on the main node.Warning
The function providing the right hand side of the PDE needs to support MPI. This is automatically the case for local evaluations (which only use the field value at the current position), for the differential operators provided by
pde, and integration of fields. Similarly, post_step_hook can only be used to do local modifications since the field data supplied to the function is local to each MPI node.Example
A minimal example using the MPI solver is
from pde import DiffusionPDE, pde.fields.scalar.ScalarField, UnitGrid grid = UnitGrid([64, 64]) state = pde.fields.scalar.ScalarField.random_uniform(grid, 0.2, 0.3) eq = DiffusionPDE(diffusivity=0.1) result = eq.solve(state, t_range=10, dt=0.1, solver="explicit_mpi") if result is not None: # restrict the output to the main node result.plot()
Saving this script as multiprocessing.py, a parallel simulation is started by
mpiexec -n 2 python3 multiprocessing.py
Here, the number 2 determines the number of cores that will be used. Note that macOS might require an additional hint on how to connect the processes even when they are run on the same machine (e.g., your workstation). It might help to run
mpiexec -n 2 -host localhost python3 multiprocessing.pyin this case- Parameters:
pde (
PDEBase) – The partial differential equation that should be solveddecomposition (str, int, or list of ints) – Number of subdivision in each direction. Should be a list of length grid.num_axes specifying the number of nodes for this axis. If one value is -1, its value will be determined from the number of available nodes. A single integer is interpreted as the number of subdivisions along one axis. The default value auto tries to determine an optimal decomposition by minimizing communication between nodes.
backend (str) – The backend used for numerical operations
adaptive (bool) – Whether to use adaptive time stepping
tolerance (float) – Error tolerance for adaptive time stepping
- make_stepper(state, dt=None)[source]
Create the executable stepping function produced by this solver.
- Parameters:
- Returns:
Function that can be called to advance the state from time t_start to time t_end. The function call signature is (state: numpy.ndarray, t_start: float, t_end: float)
- Return type:
- name = 'explicit_mpi'