How to Use MPI for Distributed Parallel Computing in Nelson: A Complete Guide

Nelson provides a native MPI module that wraps the standard MPI C API, allowing you to write distributed parallel scripts using high-level functions like MPI_Init, MPI_Comm_rank, and MPI_Send directly from Nelson code.

Nelson, the open-source numerical computing environment, includes a built-in MPI module for distributed parallel computing that exposes standard Message Passing Interface (MPI) functions directly to Nelson scripts. Located in the nelson-lang/nelson repository, this module provides a C++ backend that wraps system MPI libraries (OpenMPI, MPICH, or MS-MPI) while presenting a familiar, high-level API for launching multi-process numerical workloads across clusters or multi-core workstations.

MPI Module Architecture

The Nelson MPI implementation consists of a thin C++ backend that interfaces with system MPI libraries and a set of Nelson-level wrapper functions.

C++ Backend Components

The core MPI functionality resides in modules/mpi/src/cpp/MPI_helpers.cpp, with declarations in modules/mpi/src/include/MPI_helpers.hpp. These files implement the low-level initialization, error handling, and data packing routines that bridge Nelson's data types with MPI C calls.

MPI communicator objects are represented by MPI_CommHandleObject, defined in modules/mpi/src/include/MPI_CommHandleObject.hpp. This class wraps the native MPI_Comm handle and manages its lifecycle within the Nelson environment.

Nelson-Level API

The functions you call from Nelson scripts—such as MPI_Init, MPI_Finalize, MPI_Comm_rank, and MPI_Comm_size—are thin wrappers that forward calls to the C++ helpers. These reside in the modules/mpi directory, with the launcher script mpiexec.m handling process spawning.

Installation and Build Configuration

MPI support is optional in Nelson and controlled via CMake configuration flags.

Prerequisites

Install a system MPI library before building Nelson:

  • Ubuntu/Debian: sudo apt install libopenmpi-dev
  • macOS: brew install open-mpi
  • Windows: Install MS-MPI redistributable

The repository includes dependency installation scripts in tools/install_dependencies/ (e.g., install-ubuntu-24.04.sh) that automate MPI library installation.

Building with MPI

Enable MPI support by ensuring the WITHOUT_MPI_MODULE CMake flag is OFF (the default for binary releases):

cmake -DCMAKE_BUILD_TYPE=Release -DWITHOUT_MPI_MODULE=FALSE <repo_root>
make -j$(nproc)

Verify the installation by querying the linked MPI library version:

getMpiLibraryVersion()

Basic MPI Usage in Nelson

All Nelson MPI programs follow a standard pattern: initialize the runtime, obtain communicator information, perform work, and finalize.

Hello World Example

The minimal Nelson MPI script demonstrates rank identification and size queries. This example is available in modules/mpi/examples/MPI_helloworld.m:

% MPI_helloworld.m
if ~MPI_Initialized()
    MPI_Init();
end

comm = MPI_Comm_object();      % Returns MPI_COMM_WORLD
rank = MPI_Comm_rank(comm);    % My process ID
size = MPI_Comm_size(comm);    % Total number of processes

fprintf('Hello from rank %d of %d\n', rank, size);

if MPI_Initialized()
    MPI_Finalize();
end
exit

Launching MPI Jobs

Use the mpiexec helper function to launch scripts across multiple processes:

mpiexec('MPI_helloworld.m', 4)

This builds and executes the shell command:

mpiexec -n 4 nelson-cli -q -e "run('MPI_helloworld.m');exit()"

Point-to-Point and Collective Operations

Nelson wraps standard MPI communication patterns for data exchange between processes.

Send and Receive

Use MPI_Send and MPI_Recv for point-to-point communication. The following pattern from modules/mpi/examples/MPI_parallel_sum.m shows a master-worker reduction:

% Worker process sends partial result
if rank ~= 0
    MPI_Send(partial_sum, 0, 1000+rank, comm);
else
    % Master receives from all workers
    total = partial_sum;
    for src = 1:size-1
        total = total + MPI_Recv(src, 1000+src, comm);
    end
end

Collective Operations

For better performance, use collective operations that wrap MPI_Bcast, MPI_Reduce, MPI_Allreduce, and MPI_Barrier:

  • Broadcast: MPI_Bcast(data, root, comm) sends data from the root rank to all others.
  • Reduction: MPI_Reduce(sendbuf, op, root, comm) combines values from all ranks to the root.
  • All-Reduce: MPI_Allreduce(sendbuf, op, comm) combines values and distributes the result to all ranks.
  • Barrier: MPI_Barrier(comm) synchronizes all processes at a synchronization point.

Advanced MPI Features

Custom Communicators

Create sub-groups of processes using MPI_Comm_split. This is useful for hybrid parallelism or dividing a global communicator into row/column groups:

% Split MPI_COMM_WORLD into even and odd ranks
world = MPI_Comm_object('MPI_COMM_WORLD');
rank = MPI_Comm_rank(world);
color = mod(rank, 2);  % 0 for even, 1 for odd
newComm = MPI_Comm_split(world, color, rank);

newRank = MPI_Comm_rank(newComm);
fprintf('World rank %d → new rank %d in group %d\n', ...
        rank, newRank, color);

MPI_Comm_free(newComm);

Error Handling

The C++ backend in MPI_helpers.cpp installs a custom MPIErrorHandler that converts MPI errors into Nelson exceptions. When an MPI call fails, the wrapper throws a standard Nelson Error with diagnostic information rather than terminating the process, allowing you to handle failures using Nelson's standard try-catch mechanisms.

Summary

  • Nelson's MPI module provides native distributed parallel computing by wrapping standard MPI C APIs in modules/mpi/src/cpp/MPI_helpers.cpp and exposing them as high-level Nelson functions.
  • Build configuration requires a system MPI library (OpenMPI, MPICH, or MS-MPI) and CMake flag -DWITHOUT_MPI_MODULE=FALSE (default enabled).
  • Core workflow involves MPI_Init(), MPI_Comm_object() for communicators, MPI_Comm_rank()/MPI_Comm_size() for process info, communication calls like MPI_Send()/MPI_Recv() or collectives, and MPI_Finalize().
  • Execution uses mpiexec('script.m', n) which invokes mpiexec -n n nelson-cli to launch distributed jobs.
  • Advanced features include custom communicators via MPI_Comm_split() and automatic error handling through the C++ backend.

Frequently Asked Questions

How do I check if MPI is available in my Nelson installation?

Call getMpiLibraryVersion() in the Nelson console. If MPI is compiled and linked, this function returns a string describing the underlying MPI implementation (e.g., "Open MPI 4.1.4"). If the module is disabled, the function will be undefined.

Can I use Nelson MPI on Windows?

Yes. Nelson supports MS-MPI on Windows. Install the MS-MPI redistributable and ensure Nelson is built with -DWITHOUT_MPI_MODULE=FALSE. The mpiexec.m launcher and all MPI functions work identically across Linux, macOS, and Windows platforms.

What is the difference between MPI_Comm_object and MPI_Comm_split?

MPI_Comm_object() returns a handle to a predefined communicator—typically MPI_COMM_WORLD containing all launched processes. MPI_Comm_split() creates a new communicator by partitioning an existing one into sub-groups based on a color value, allowing you to organize processes into rows, columns, or functional groups for more complex parallel algorithms.

How does Nelson handle MPI errors?

The C++ backend in MPI_helpers.cpp installs a custom MPIErrorHandler that intercepts MPI errors and converts them into Nelson exceptions. When an MPI call fails, Nelson throws a standard Error with a descriptive message rather than terminating the process or returning an error code, allowing you to handle failures using Nelson's standard try-catch mechanisms.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →