MPI objects

MPI objects come in a non-owning form (*_view), which is cheap to copy and never frees the object, and an owning, move-only form that frees it on destruction. Every function that takes an MPI object also accepts the native handle (e.g. MPI_Comm) and your own wrapper types; see Customization points and MPI objects.

With MPI_ERRORS_RETURN set on a communicator, errors are thrown as mpi_error; the default MPI_ERRORS_ARE_FATAL terminates the program.

Environment

class environment

RAII wrapper that calls MPI_Init_thread on construction and MPI_Finalize on destruction.

Construct one instance at the top of main. The destructor guards against double-finalization. This class is non-copyable and non-movable: it owns global MPI state.

int main(int argc, char** argv) {
    kamping::v2::environment env(argc, argv);                         // single-threaded
    kamping::v2::environment env(argc, argv, ThreadLevel::multiple);  // threaded variant
}

Defined in header <kamping/v2/environment.hpp>

Communicators

class comm_view

Non-owning wrapper around an MPI_Comm.

Satisfies convertible_to_mpi_handle<MPI_Comm>. Does not free the communicator on destruction — use the owning comm for that. Provides read-only accessors and .dup() / .split() via comm_accessors.

Defined in header <kamping/v2/comm.hpp>

comm_view(MPI_Comm c) noexcept

Construct from a raw MPI_Comm. The communicator must outlive this view.

int rank() const
Returns:

The rank of the calling process in this communicator.

int size() const
Returns:

The number of processes in this communicator.

group group() const

Extract the group associated with this communicator.

The returned group is owned by the caller.

Throws:
  • mpi_error – if MPI_Comm_group fails.

comm dup() const

Collective: duplicate this communicator (MPI_Comm_dup).

All processes in the communicator must call this collectively. Delegates to the free function kamping::v2::dup.

Throws:
  • mpi_error – if MPI_Comm_dup fails.

comm split(int color, int key = 0) const

Collective: split this communicator by color and key (MPI_Comm_split).

Processes with the same color form a sub-communicator ordered by key. Pass MPI_UNDEFINED as color to opt out — result is MPI_COMM_NULL. Delegates to the free function kamping::v2::split.

Throws:
  • mpi_error – if MPI_Comm_split fails.

class comm

Owning RAII wrapper for MPI_Comm.

Move-only. Calls MPI_Comm_free on destruction unless the stored handle is MPI_COMM_NULL.

Invariant: only communicators created by the caller (via MPI_Comm_dup, MPI_Comm_split, MPI_Comm_create_from_group, etc.) should be passed to from_native. Never adopt MPI_COMM_WORLD or MPI_COMM_SELF.

Satisfies convertible_to_mpi_handle<MPI_Comm>.

Defined in header <kamping/v2/comm.hpp>

comm() noexcept = default
(1)
comm(comm &&o) noexcept
(2)

(1) Default-construct a null communicator (holds MPI_COMM_NULL).

Useful as an output parameter for the free functions dup() / split():

comm out;
kamping::v2::dup(source, out);

(2) Move constructor — transfers ownership; moved-from holds MPI_COMM_NULL.

comm &operator=(comm &&o) noexcept

Move assignment — frees the current handle then transfers ownership.

~comm() noexcept

Free the communicator (unless moved from or null).

void free()

Explicitly free the communicator.

After this call *this holds MPI_COMM_NULL — the destructor becomes a no-op. Use this instead of relying on the destructor when you need to handle errors from MPI_Comm_free.

The handle is exchanged to MPI_COMM_NULL before the MPI call so the destructor cannot double-free even if this throws.

Throws:
  • mpi_error – if MPI_Comm_free fails.

MPI_Comm release() noexcept

Relinquish ownership; returns the raw MPI_Comm handle.

Leaves *this as MPI_COMM_NULL. The caller is responsible for calling MPI_Comm_free on the returned handle.

operator comm_view() const noexcept

Implicit conversion to a non-owning view.

Allows passing a comm wherever a comm_view is expected without an explicit cast. The view borrows; it does not extend lifetime.

int rank() const
Returns:

The rank of the calling process in this communicator.

int size() const
Returns:

The number of processes in this communicator.

group group() const

Extract the group associated with this communicator.

The returned group is owned by the caller.

Throws:
  • mpi_error – if MPI_Comm_group fails.

comm dup() const

Collective: duplicate this communicator (MPI_Comm_dup).

All processes in the communicator must call this collectively. Delegates to the free function kamping::v2::dup.

Throws:
  • mpi_error – if MPI_Comm_dup fails.

comm split(int color, int key = 0) const

Collective: split this communicator by color and key (MPI_Comm_split).

Processes with the same color form a sub-communicator ordered by key. Pass MPI_UNDEFINED as color to opt out — result is MPI_COMM_NULL. Delegates to the free function kamping::v2::split.

Throws:
  • mpi_error – if MPI_Comm_split fails.

static comm from_native(MPI_Comm c) noexcept

Adopt an already-created MPI_Comm (takes ownership).

Do not pass predefined communicators (MPI_COMM_WORLD, MPI_COMM_SELF).

template<convertible_to_mpi_handle<MPI_Group> Group, convertible_to_mpi_handle<MPI_Info> Info = MPI_Info>
static comm from_group(Group const &g, std::string_view tag = "", Info info = MPI_INFO_NULL)

Collective: create a new communicator from a group.

Calls MPI_Comm_create_from_group. All processes in g must call this collectively with the same tag.

Template parameters:
Parameters:
  • g – Group defining the new communicator’s process set.

  • tag – Application-defined string tag (must match across all callers).

  • info – MPI info hints (defaults to MPI_INFO_NULL).

Throws:
  • mpi_error – if the MPI call fails.

The free functions dup and split do the same as the members, and can also write into an existing comm:

template<convertible_to_mpi_handle<MPI_Comm> Comm = MPI_Comm, convertible_to_mpi_handle_ptr<MPI_Comm> NewComm = MPI_Comm*>
void dup(Comm const &c, NewComm &new_comm)
(1)
template<convertible_to_mpi_handle<MPI_Comm> Comm = MPI_Comm>
comm dup(Comm const &c)
(2)

(1) Collective: duplicate a communicator (MPI_Comm_dup).

(2) Collective: duplicate a communicator, returning an owning comm.

Template parameters:
Parameters:
  • c – Input communicator.

  • new_comm – Output: receives the duplicated communicator handle.

Throws:
  • mpi_error – if MPI_Comm_dup fails.

Defined in header <kamping/v2/comm.hpp>

template<convertible_to_mpi_handle<MPI_Comm> Comm = MPI_Comm, convertible_to_mpi_handle_ptr<MPI_Comm> NewComm = MPI_Comm*>
void split(Comm const &c, int color, int key, NewComm &new_comm)
(1)
template<convertible_to_mpi_handle<MPI_Comm> Comm = MPI_Comm>
comm split(Comm const &c, int color, int key = 0)
(2)

(1) Collective: split a communicator by color and key (MPI_Comm_split).

Processes with the same color form a sub-communicator, ordered by key. Pass MPI_UNDEFINED as color to opt out — the output handle is set to MPI_COMM_NULL for that process.

(2) Collective: split a communicator, returning an owning comm.

Template parameters:
Parameters:
  • c – Input communicator.

  • new_comm – Output: receives the new sub-communicator handle.

Throws:
  • mpi_error – if MPI_Comm_split fails.

Defined in header <kamping/v2/comm.hpp>

Groups

class group_view

Non-owning wrapper around an MPI_Group.

Satisfies convertible_to_mpi_handle<MPI_Group>. Does not free the group on destruction — use the owning group for that.

Defined in header <kamping/v2/group.hpp>

explicit group_view(MPI_Group g) noexcept

Construct from a raw MPI_Group. The group must outlive this view.

int size() const
Returns:

Number of processes in the group.

std::optional<int> rank() const
Returns:

Rank of the calling process in this group, or std::nullopt if the calling process is not a member (MPI_UNDEFINED).

bool contains_self() const
Returns:

true if the calling process is a member of this group.

GroupEquality compare(group_view other) const

Compare two groups.

Returns:

GroupEquality::Identical if same object, Similar if same processes in different order, Unequal otherwise.

class group

Owning RAII wrapper for MPI_Group.

Move-only. Calls MPI_Group_free on destruction unless the stored handle is MPI_GROUP_EMPTY (the predefined empty group, which must not be freed).

Satisfies convertible_to_mpi_handle<MPI_Group>.

Defined in header <kamping/v2/group.hpp>

group() noexcept = default
(1)
group(group &&o) noexcept
(2)

(1) Default-construct (holds MPI_GROUP_EMPTY).

(2) Move constructor — transfers ownership; moved-from holds MPI_GROUP_EMPTY.

group &operator=(group &&o) noexcept

Move assignment — frees the current handle then transfers ownership.

~group() noexcept

Free the group (unless it is MPI_GROUP_EMPTY or moved from).

MPI_Group release() noexcept

Relinquish ownership; returns the raw MPI_Group handle.

Leaves *this as MPI_GROUP_EMPTY. The caller is responsible for calling MPI_Group_free on the returned handle.

operator group_view() const noexcept

Implicit conversion to a non-owning view.

Allows passing a group wherever a group_view is expected without an explicit cast. The view borrows; it does not extend lifetime.

int size() const
Returns:

Number of processes in the group.

std::optional<int> rank() const
Returns:

Rank of the calling process in this group, or std::nullopt if the calling process is not a member (MPI_UNDEFINED).

bool contains_self() const
Returns:

true if the calling process is a member of this group.

GroupEquality compare(group_view other) const

Compare two groups.

Returns:

GroupEquality::Identical if same object, Similar if same processes in different order, Unequal otherwise.

static group empty() noexcept

Return an owning wrapper around MPI_GROUP_EMPTY.

The predefined empty group is never freed — free_if_valid skips it.

static group from_native(MPI_Group g) noexcept

Adopt an already-created MPI_Group handle (takes ownership).

Use when you have called an MPI routine that returns an MPI_Group and you want RAII management. Do not pass MPI_GROUP_EMPTY (it is never freed anyway, but using group::empty() is clearer).

Status

class status

Owning wrapper around MPI_Status.

All fields are undefined until the object is passed to (or filled by) an MPI communication function. Satisfies both convertible_to_mpi_handle<MPI_Status> and convertible_to_mpi_handle_ptr<MPI_Status>.

Defined in header <kamping/v2/status.hpp>

status()
(1)
explicit status(MPI_Status s)
(2)

(1) Default-construct. All fields are undefined until filled by MPI.

(2) Construct from an existing MPI_Status.

MPI_Status &native()
(1)
MPI_Status const &native() const
(2)
Returns:
  • (1) Reference to the underlying MPI_Status (escape hatch).

  • (2) Const reference to the underlying MPI_Status (escape hatch).

operator status_view() noexcept

Implicit conversion to a non-owning view.

Allows passing a status wherever a status_view is expected without an explicit cast. The view borrows; it does not extend lifetime.

operator const_status_view() const noexcept

Implicit conversion to a read-only, non-owning view.

int source() const
Returns:

The source rank.

int tag() const
Returns:

The tag.

std::optional<int> count(MPI_Datatype datatype) const
(1)
template<typename T>
requires kamping::types::is_builtin_type_v<T>
std::optional<int> count() const
(2)
Template parameters:
  • T – A builtin MPI-mappable type.

Parameters:
  • datatype – The MPI datatype.

Returns:
  • (1) The number of top-level elements of the given datatype in the message. In cases where MPI_Get_count would return MPI_UNDEFINED, std::nullopt is returned.

  • (2) The number of top-level elements of type T in the message. In cases where MPI_Get_count would return MPI_UNDEFINED, std::nullopt is returned.

class status_view

Non-owning view over an existing MPI_Status.

Satisfies convertible_to_mpi_handle_ptr<MPI_Status> so it can be passed directly to operations that accept a status out-parameter.

Defined in header <kamping/v2/status.hpp>

explicit status_view(MPI_Status *status)

Construct from a pointer to an existing MPI_Status. Must not be null.

MPI_Status *native() const
Returns:

Pointer to the underlying MPI_Status (escape hatch).

int source() const
Returns:

The source rank.

int tag() const
Returns:

The tag.

std::optional<int> count(MPI_Datatype datatype) const
(1)
template<typename T>
requires kamping::types::is_builtin_type_v<T>
std::optional<int> count() const
(2)
Template parameters:
  • T – A builtin MPI-mappable type.

Parameters:
  • datatype – The MPI datatype.

Returns:
  • (1) The number of top-level elements of the given datatype in the message. In cases where MPI_Get_count would return MPI_UNDEFINED, std::nullopt is returned.

  • (2) The number of top-level elements of type T in the message. In cases where MPI_Get_count would return MPI_UNDEFINED, std::nullopt is returned.

class const_status_view

Read-only, non-owning view over an existing MPI_Status.

Provides the read accessors (source(), tag(), count()) for a status that must not be written, e.g. an element of a const status_vector. Satisfies convertible_to_mpi_handle<MPI_Status> but, being read-only, not convertible_to_mpi_handle_ptr<MPI_Status>.

Defined in header <kamping/v2/status.hpp>

explicit const_status_view(MPI_Status const *status)
(1)
const_status_view(status_view view) noexcept
(2)

(1) Construct from a pointer to an existing MPI_Status. Must not be null.

(2) Implicit conversion from a mutable view.

MPI_Status const *native() const
Returns:

Pointer to the underlying MPI_Status (escape hatch).

int source() const
Returns:

The source rank.

int tag() const
Returns:

The tag.

std::optional<int> count(MPI_Datatype datatype) const
(1)
template<typename T>
requires kamping::types::is_builtin_type_v<T>
std::optional<int> count() const
(2)
Template parameters:
  • T – A builtin MPI-mappable type.

Parameters:
  • datatype – The MPI datatype.

Returns:
  • (1) The number of top-level elements of the given datatype in the message. In cases where MPI_Get_count would return MPI_UNDEFINED, std::nullopt is returned.

  • (2) The number of top-level elements of type T in the message. In cases where MPI_Get_count would return MPI_UNDEFINED, std::nullopt is returned.

class status_vector

Growable array of MPI statuses that mirrors std::vector, but whose element access yields status_views (or const_status_views, through a const vector) instead of raw MPI_Statuses.

The statuses are stored contiguously, so the whole array can be passed as the statuses argument of the multiple-completion functions (waitall, waitsome, …) without copying; it exposes them via mpi_handle_range() rather than data(), since its elements as a range are views, not MPI_Statuses.

request_vector requests; status_vector statuses(requests.size()); waitall(requests, statuses); int source = statuses[0].source();

Unlike request_vector, a status is a plain value with no MPI resource attached, so status_vector is copyable and dropping elements needs no completion. Views are invalidated by reallocation, as with std::vector.

Defined in header <kamping/v2/status.hpp>

explicit status_vector(size_type n)

Constructs n statuses. Their fields are undefined until filled in by MPI.

void reserve(size_type n)

Reserves storage for n statuses. Invalidates all views if it reallocates.

void resize(size_type n)

Resizes to n statuses. Invalidates all views if it reallocates.

status_view operator[](size_type i) noexcept
(1)
const_status_view operator[](size_type i) const noexcept
(2)
Returns:
  • (1) A view of the status at index i. Precondition: i < size().

  • (2) A read-only view of the status at index i. Precondition: i < size().

Info objects

class info_view

Non-owning view over an existing MPI_Info.

Does not free the handle on destruction. Use for MPI_INFO_NULL, handles borrowed from the MPI implementation, or anywhere lifetimes are managed externally.

Satisfies convertible_to_mpi_handle<MPI_Info> so it can be passed directly to any operation that accepts an info argument.

Defined in header <kamping/v2/info.hpp>

explicit info_view(MPI_Info info) noexcept

Wrap info without taking ownership. The handle must outlive this view.

int nkeys() const
Returns:

Number of key–value pairs.

std::string nth_key(int n) const

Return the n-th key (0-indexed), null-truncated at the first \0.

std::optional<std::string> get(std::string_view key) const
(1)
template<typename T>
std::optional<T> get(std::string_view key) const
(2)

(1) Look up key; returns std::nullopt if the key is absent.

(2) Type-safe get. Requires info_value_traits<T> to be specialized.

bool contains(std::string_view key) const
Returns:

true if key is present.

void set(std::string_view key, std::string_view value)
(1)
template<typename T>
requires (!std::convertible_to<T, std::string_view>)
void set(std::string_view key, T const &value)
(2)

(1) Set key to value (creates or overwrites).

(2) Type-safe set. Requires info_value_traits<T> to be specialized.

Note: this overload is excluded when T is already implicitly convertible to std::string_view — the non-template overload above is preferred then.

void erase(std::string_view key)

Remove key.

Throws:
  • mpi_error – if the MPI call fails (including when the key is absent).

entry_iterator begin() const

Iterator to the first key–value pair.

entry_sentinel end() const

Sentinel marking the end of iteration.

auto entries() const

Lazy range of all (key, value) pairs.

Returns a std::ranges::subrange that can be passed directly to range algorithms and supports structured bindings in range-for:

for (auto [key, val] : my_info.entries()) { ... }
auto n = std::ranges::distance(my_info.entries());
info dup() const

Duplicate this info object into a new, independently owned copy.

Throws:
  • mpi_error – if MPI_Info_dup fails.

Returns:

A new info with the same key–value pairs.

class info

Owning RAII wrapper for MPI_Info.

Calls MPI_Info_create on construction and MPI_Info_free on destruction. Move-only: if you need an independent copy, call dup() explicitly.

Satisfies convertible_to_mpi_handle<MPI_Info> so it can be passed directly to any operation that accepts an info argument.

Defined in header <kamping/v2/info.hpp>

info()
(1)
info(info &&other) noexcept
(2)

(1) Create a new empty info object via MPI_Info_create.

(2) Move constructor — transfers ownership; the moved-from object holds MPI_INFO_NULL.

Throws:
  • mpi_error – if the MPI call fails.

info &operator=(info &&other) noexcept

Move assignment — frees the current handle then transfers ownership.

~info() noexcept

Free the info object (unless moved from).

void free()

Explicitly free the info object.

After this call *this holds MPI_INFO_NULL — the destructor becomes a no-op. Use this instead of relying on the destructor when you need to handle errors from MPI_Info_free.

The handle is exchanged to MPI_INFO_NULL before the MPI call so the destructor cannot double-free even if this throws.

Throws:
  • mpi_error – if MPI_Info_free fails.

MPI_Info release() noexcept

Relinquish ownership; returns the raw MPI_Info handle.

Leaves *this as MPI_INFO_NULL. The caller is responsible for calling MPI_Info_free on the returned handle.

operator info_view() const noexcept

Implicit conversion to a non-owning view.

Allows passing an info wherever an info_view is expected without an explicit cast. The view borrows; it does not extend lifetime.

int nkeys() const
Returns:

Number of key–value pairs.

std::string nth_key(int n) const

Return the n-th key (0-indexed), null-truncated at the first \0.

std::optional<std::string> get(std::string_view key) const
(1)
template<typename T>
std::optional<T> get(std::string_view key) const
(2)

(1) Look up key; returns std::nullopt if the key is absent.

(2) Type-safe get. Requires info_value_traits<T> to be specialized.

bool contains(std::string_view key) const
Returns:

true if key is present.

void set(std::string_view key, std::string_view value)
(1)
template<typename T>
requires (!std::convertible_to<T, std::string_view>)
void set(std::string_view key, T const &value)
(2)

(1) Set key to value (creates or overwrites).

(2) Type-safe set. Requires info_value_traits<T> to be specialized.

Note: this overload is excluded when T is already implicitly convertible to std::string_view — the non-template overload above is preferred then.

void erase(std::string_view key)

Remove key.

Throws:
  • mpi_error – if the MPI call fails (including when the key is absent).

entry_iterator begin() const

Iterator to the first key–value pair.

entry_sentinel end() const

Sentinel marking the end of iteration.

auto entries() const

Lazy range of all (key, value) pairs.

Returns a std::ranges::subrange that can be passed directly to range algorithms and supports structured bindings in range-for:

for (auto [key, val] : my_info.entries()) { ... }
auto n = std::ranges::distance(my_info.entries());
info dup() const

Duplicate this info object into a new, independently owned copy.

Throws:
  • mpi_error – if MPI_Info_dup fails.

Returns:

A new info with the same key–value pairs.

static info from_native(MPI_Info h) noexcept

Adopt an already-created MPI_Info handle (takes ownership).

Do not pass predefined info objects (MPI_INFO_NULL, MPI_INFO_ENV).

template<typename T>
struct info_value_traits

Defined in header <mpi/info.hpp>

Sessions

class session_view

Non-owning wrapper around an MPI_Session.

Does not finalize the session on destruction — use the owning session for that.

Defined in header <kamping/v2/session.hpp>

explicit session_view(MPI_Session s) noexcept

Construct from a raw MPI_Session. The session must outlive this view.

std::optional<group> group_from_pset(std::string_view pset_name) const

Create an owned group from a named process set.

Calls MPI_Group_from_session_pset. Returns std::nullopt if the calling process is not a member of the named process set — MPI sets the output group to MPI_GROUP_EMPTY in that case. Returns the owned group otherwise.

This is a local (non-collective) operation.

Parameters:
  • pset_name – Name of the process set (e.g., "mpi://WORLD").

Throws:
  • mpi_error – if the MPI call fails (e.g., unknown pset name).

Returns:

The owned group, or std::nullopt if this process is not a member.

template<convertible_to_mpi_handle<MPI_Info> Info = MPI_Info>
std::optional<comm> comm_from_pset(std::string_view pset_name, std::string_view tag = "", Info info = MPI_INFO_NULL) const

Collective: create a communicator from a named process set.

Convenience shortcut for:

auto g = s.group_from_pset(pset_name);
if (g) auto c = comm::from_group(*g, tag, info);

Returns std::nullopt if the calling process is not a member of the pset. All processes that are members must call this collectively with the same tag. Processes that receive std::nullopt must not call this.

Template parameters:
Parameters:
  • pset_name – Name of the process set (e.g., "mpi://WORLD").

  • tag – Application-defined string tag (must match across all callers).

  • info – MPI info hints (defaults to MPI_INFO_NULL).

Throws:
  • mpi_error – if either MPI call fails.

Returns:

The new communicator, or std::nullopt if this process is not a member.

template<convertible_to_mpi_handle<MPI_Info> Info = MPI_Info>
pset_range<Info> psets(Info info = MPI_INFO_NULL) const

Enumerate all process set names visible to this session.

Returns a lazy input range. MPI_Session_get_num_psets is called once when iteration begins; each increment fetches the next name on demand via MPI_Session_get_nth_pset. No names are loaded until iteration starts.

info is stored by value inside the returned range, so owning wrappers are kept alive for the range’s lifetime.

Template parameters:
Parameters:
  • info – Optional MPI info hints (defaults to MPI_INFO_NULL).

class session

Owning RAII wrapper for MPI_Session (MPI-4 sessions model).

Move-only. Calls MPI_Session_finalize on destruction unless the stored handle is MPI_SESSION_NULL or MPI has already been finalized.

Unlike kamping::v2::environment, a session does not require MPI_Init to have been called — the sessions model allows MPI to be initialized via sessions alone. When used alongside the traditional model, the session should be finalized before MPI_Finalize.

namespace psets = kamping::v2::psets;

kamping::v2::session s;

// Create a comm directly from a pset name (most concise):
auto c = s.comm_from_pset(psets::world);

// Or work through the group explicitly:
auto g = s.group_from_pset(psets::world);  // std::optional<group>
if (g) {
    auto c2 = comm::from_group(*g, "my-tag");
}

Defined in header <kamping/v2/session.hpp>

session()
(1)
session(session &&o) noexcept
(2)

(1) Initialize a session with default info and the return-errors error handler.

(2) Move constructor — transfers ownership; moved-from holds MPI_SESSION_NULL.

Throws:
  • mpi_error – if MPI_Session_init fails.

session &operator=(session &&o) noexcept

Move assignment — finalizes the current session then transfers ownership.

~session() noexcept

Finalize the session unless already done or MPI is already finalized.

void finalize()

Explicitly finalize the session.

After this call *this holds MPI_SESSION_NULL — the destructor becomes a no-op. Use this instead of relying on the destructor when you need to handle errors from MPI_Session_finalize.

The handle is exchanged to MPI_SESSION_NULL before the MPI call so the destructor cannot double-free even if this throws.

Throws:
  • mpi_error – if MPI_Session_finalize fails.

MPI_Session release() noexcept

Relinquish ownership; returns the raw MPI_Session handle.

Leaves *this as MPI_SESSION_NULL. The caller is responsible for calling MPI_Session_finalize on the returned handle.

operator session_view() const noexcept

Implicit conversion to a non-owning view.

std::optional<group> group_from_pset(std::string_view pset_name) const

Create an owned group from a named process set.

Calls MPI_Group_from_session_pset. Returns std::nullopt if the calling process is not a member of the named process set — MPI sets the output group to MPI_GROUP_EMPTY in that case. Returns the owned group otherwise.

This is a local (non-collective) operation.

Parameters:
  • pset_name – Name of the process set (e.g., "mpi://WORLD").

Throws:
  • mpi_error – if the MPI call fails (e.g., unknown pset name).

Returns:

The owned group, or std::nullopt if this process is not a member.

template<convertible_to_mpi_handle<MPI_Info> Info = MPI_Info>
std::optional<comm> comm_from_pset(std::string_view pset_name, std::string_view tag = "", Info info = MPI_INFO_NULL) const

Collective: create a communicator from a named process set.

Convenience shortcut for:

auto g = s.group_from_pset(pset_name);
if (g) auto c = comm::from_group(*g, tag, info);

Returns std::nullopt if the calling process is not a member of the pset. All processes that are members must call this collectively with the same tag. Processes that receive std::nullopt must not call this.

Template parameters:
Parameters:
  • pset_name – Name of the process set (e.g., "mpi://WORLD").

  • tag – Application-defined string tag (must match across all callers).

  • info – MPI info hints (defaults to MPI_INFO_NULL).

Throws:
  • mpi_error – if either MPI call fails.

Returns:

The new communicator, or std::nullopt if this process is not a member.

template<convertible_to_mpi_handle<MPI_Info> Info = MPI_Info>
pset_range<Info> psets(Info info = MPI_INFO_NULL) const

Enumerate all process set names visible to this session.

Returns a lazy input range. MPI_Session_get_num_psets is called once when iteration begins; each increment fetches the next name on demand via MPI_Session_get_nth_pset. No names are loaded until iteration starts.

info is stored by value inside the returned range, so owning wrappers are kept alive for the range’s lifetime.

Template parameters:
Parameters:
  • info – Optional MPI info hints (defaults to MPI_INFO_NULL).

static session from_native(MPI_Session s) noexcept

Adopt an already-initialized MPI_Session handle (takes ownership).

Use when you have called MPI_Session_init directly and want RAII management.

Windows

class win_view

Non-owning wrapper around an MPI_Win.

Satisfies convertible_to_mpi_handle<MPI_Win>. Does not free the window on destruction — use the owning win for that. Provides .group() / .fence() via win_accessors.

Defined in header <kamping/v2/win.hpp>

win_view(MPI_Win w) noexcept

Construct from a raw MPI_Win. The window must outlive this view.

group group() const

Extract the group of processes sharing this window.

The returned group is owned by the caller.

Throws:
  • mpi_error – if MPI_Win_get_group fails.

void fence(int assertion = 0) const

Collective: synchronize an active-target epoch (MPI_Win_fence).

Delegates to the free function kamping::v2::fence.

Throws:
  • mpi_error – if MPI_Win_fence fails.

class win

Owning RAII wrapper for MPI_Win.

Move-only. Calls MPI_Win_free on destruction unless the stored handle is MPI_WIN_NULL. Freeing a window is collective, so all processes of the window’s group must destroy (or free) it at the same point.

Satisfies convertible_to_mpi_handle<MPI_Win> and convertible_to_mpi_handle_ptr<MPI_Win>.

Defined in header <kamping/v2/win.hpp>

win() noexcept = default
(1)
win(win &&o) noexcept
(2)

(1) Default-construct a null window (holds MPI_WIN_NULL).

Useful as an output parameter for the Level 1 win_allocate().

(2) Move constructor — transfers ownership; moved-from holds MPI_WIN_NULL.

win &operator=(win &&o) noexcept

Move assignment — frees the current window then transfers ownership.

~win() noexcept

Free the window (unless moved from or null).

void free()

Explicitly free the window.

After this call *this holds MPI_WIN_NULL — the destructor becomes a no-op. Use this instead of relying on the destructor when you need to handle errors from MPI_Win_free.

The handle is exchanged to MPI_WIN_NULL before the MPI call so the destructor cannot double-free even if this throws.

Throws:
  • mpi_error – if MPI_Win_free fails.

MPI_Win release() noexcept

Relinquish ownership; returns the raw MPI_Win handle.

Leaves *this as MPI_WIN_NULL. The caller is responsible for calling MPI_Win_free on the returned handle.

operator win_view() const noexcept

Implicit conversion to a non-owning view.

The view borrows; it does not extend lifetime.

group group() const

Extract the group of processes sharing this window.

The returned group is owned by the caller.

Throws:
  • mpi_error – if MPI_Win_get_group fails.

void fence(int assertion = 0) const

Collective: synchronize an active-target epoch (MPI_Win_fence).

Delegates to the free function kamping::v2::fence.

Throws:
  • mpi_error – if MPI_Win_fence fails.

static win from_native(MPI_Win w) noexcept

Adopt an already-created MPI_Win (takes ownership).

template<typename T, convertible_to_mpi_handle<MPI_Comm> Comm = MPI_Comm, convertible_to_mpi_handle_ptr<MPI_Win> NewWin = MPI_Win*, convertible_to_mpi_handle<MPI_Info> Info = MPI_Info>
requires std::is_trivially_copyable_v<T>
void win_allocate(std::size_t count, Comm const &c, T *&base, NewWin &new_win, Info const &info = MPI_INFO_NULL)
(1)
template<typename T, convertible_to_mpi_handle<MPI_Comm> Comm = MPI_Comm, convertible_to_mpi_handle<MPI_Info> Info = MPI_Info>
requires std::is_trivially_copyable_v<T>
std::pair<win, std::span<T>> win_allocate(std::size_t count, Comm const &c, Info const &info = MPI_INFO_NULL)
(2)

(1) Collective: allocate a window exposing count elements of T on each process (MPI_Win_allocate).

The displacement unit is sizeof(T), so target displacements count elements of T. The memory is owned by MPI, valid until the window is freed, and uninitialized.

(2) Collective: allocate a window exposing count elements of T on each process, returning an owning win.

See the Level 1 overload for the semantics.

Template parameters:
Parameters:
  • count – Number of elements of T exposed by this process (may differ between processes).

  • c – The communicator whose processes share the window.

  • base – Output: receives the address of this process’s local memory.

  • new_win – Output: receives the window handle.

  • info – Info hints (defaults to MPI_INFO_NULL).

Throws:
  • mpi_error – if MPI_Win_allocate fails.

Returns:

The window and this process’s local, uninitialized part of it.

Defined in header <kamping/v2/win.hpp>

template<convertible_to_mpi_handle<MPI_Win> Win = MPI_Win>
void fence(Win const &w, int assertion = 0)

Collective: synchronize an active-target epoch (MPI_Win_fence).

Template parameters:
Parameters:
  • w – The window.

  • assertion – Bitwise OR of MPI_MODE_* assertions (MPI_MODE_NOPRECEDE, MPI_MODE_NOSUCCEED, …).

Throws:
  • mpi_error – if MPI_Win_fence fails.

Defined in header <kamping/v2/win.hpp>

Caching state on MPI objects

See Caching state on MPI objects.

template<attribute_kind Kind, typename T>
requires std::is_nothrow_destructible_v<T>
class cache

Owning cache of one T per MPI object, attached to the object as an attribute.

The cache owns its values; each object carries a non-owning attribute pointing to its value, which makes lookup O(1). A value is destroyed when

  • its object is freed (MPI_Comm_free, MPI_Win_free, MPI_Type_free), via the attribute’s delete callback,

  • it is removed with erase, or

  • the cache is destroyed, which removes all remaining values in the order they were created.

Each cache has its own keyval, so independent caches on the same object do not interfere, and no global state is involved: the cache works the same with the World and the Sessions model. Where no explicit owner is available (stateless interfaces, e.g. behind a C API), use keyval<Kind, T>, whose values are owned by the objects instead.

Collective use. If creating or destroying a T is collective (e.g. a window on a communicator), then get_or_create, erase and the destructor are collective too: all processes must call them for the same objects in the same order. Destroying the cache in creation order makes its cleanup consistent across processes. The cache must be destroyed before MPI is finalized.

The delete callback runs inside MPI, so T’s destructor must not throw. Duplicated objects (MPI_Comm_dup, MPI_Type_dup) do not inherit cached values.

Template parameters:
  • Kind – The kind of MPI object, one of the tags in attribute.

  • T – The cached value type. Need not be movable: it is constructed in place from the factory’s result.

Defined in header <kamping/v2/cache.hpp>

using handle_type = typename Kind::handle_type

The raw MPI handle type of the cached objects.

cache()
(1)
cache(cache &&other) noexcept = default
(2)

(1) Creates an empty cache with its own keyval.

(2) Takes over other’s values. A moved-from cache may only be destroyed or assigned to.

Throws:
  • mpi_error – if the keyval cannot be created.

cache &operator=(cache &&other) noexcept

Destroys this cache’s values, then takes over other’s.

~cache()

Destroys all remaining values in creation order and frees the keyval (see class documentation).

template<convertible_to_mpi_handle<handle_type> Obj, std::invocable F>
requires std::same_as<std::invoke_result_t<F>, T>
T &get_or_create(Obj const &obj, F &&make)

Returns the value cached for obj, creating it with make() if there is none.

Parameters:
  • obj – The MPI object, as a raw handle or any wrapper convertible to it.

  • make – Called only on a miss; must return a T by value, which is constructed in place.

Throws:
  • mpi_error – if an attribute call fails; nothing is cached in that case.

Returns:

The cached value; stays valid until it is destroyed (see class documentation).

template<convertible_to_mpi_handle<handle_type> Obj>
T *find(Obj const &obj)
(1)
template<convertible_to_mpi_handle<handle_type> Obj>
T const *find(Obj const &obj) const
(2)
Throws:
  • mpi_error – if the attribute lookup fails.

Returns:
  • (1) The value cached for obj, or nullptr if there is none.

  • (2) The value cached for obj, or nullptr if there is none. The cache owns its values, so a const cache gives read-only access to them.

template<convertible_to_mpi_handle<handle_type> Obj>
bool erase(Obj const &obj)

Destroys the value cached for obj, if any.

Throws:
  • mpi_error – if an attribute call fails.

Returns:

true if a value was destroyed.

std::size_t size() const noexcept
Returns:

The number of cached values.

bool empty() const noexcept
Returns:

true if no values are cached.

template<attribute_kind Kind, typename T>
requires std::is_nothrow_destructible_v<T>
class keyval

A typed keyval: caches one T per MPI object, owned by the object’s attribute.

Each value lives as long as its attribute: it is destroyed when its object is freed (MPI_Comm_free, MPI_Win_free, MPI_Type_free) or when it is removed with erase. Destroying the keyval only frees the key: values already attached stay alive until their objects are freed, but can no longer be looked up. Values on objects that are never freed (e.g. MPI_COMM_WORLD) are therefore never destroyed.

This suits stateless interfaces, where nothing but the MPI object is available to hold the cached state (e.g. behind a C API). When an explicit owner is available, prefer cache<Kind, T>, which also destroys its values when it is destroyed.

Collective use. If creating or destroying a T is collective (e.g. a window on a communicator), then get_or_create and erase are collective too, and freeing the object runs the destructor of its value.

Lifetime of the key. A keyval must be destroyed while MPI is usable. For a keyval in static storage, which is destroyed after MPI_Finalize, the destructor skips freeing the key once MPI has been finalized (World model). In the Sessions model this cannot be detected; destroy the keyval before the last session is finalized.

Constness. A keyval is a key, not a container: it does not own the values, so const does not apply to them, and find on a const keyval still returns a mutable value (like a const std::span or std::unique_ptr). cache<Kind, T>, which owns its values, propagates const to them instead.

The delete callback runs inside MPI, so T’s destructor must not throw. Duplicated objects (MPI_Comm_dup, MPI_Type_dup) do not inherit cached values.

Template parameters:
  • Kind – The kind of MPI object, one of the tags in attribute.

  • T – The cached value type. Need not be movable: it is constructed in place from the factory’s result.

Defined in header <kamping/v2/cache.hpp>

using handle_type = typename Kind::handle_type

The raw MPI handle type of the objects carrying values.

keyval()
(1)
keyval(keyval &&other) noexcept
(2)

(1) Creates a new key.

(2) Takes over other’s key; other is left without one.

Throws:
  • mpi_error – if the key cannot be created.

keyval &operator=(keyval &&other) noexcept

Frees this key, then takes over other’s.

~keyval()

Frees the key; attached values stay alive until their objects are freed (see class documentation).

template<convertible_to_mpi_handle<handle_type> Obj, std::invocable F>
requires std::same_as<std::invoke_result_t<F>, T>
T &get_or_create(Obj const &obj, F &&make)

Returns the value attached to obj, creating it with make() if there is none.

Parameters:
  • obj – The MPI object, as a raw handle or any wrapper convertible to it.

  • make – Called only on a miss; must return a T by value, which is constructed in place.

Throws:
  • mpi_error – if an attribute call fails; nothing is attached in that case.

Returns:

The attached value; stays valid until obj is freed or the value is erased.

template<convertible_to_mpi_handle<handle_type> Obj>
T *find(Obj const &obj) const
Throws:
  • mpi_error – if the attribute lookup fails.

Returns:

The value attached to obj, or nullptr if there is none. Mutable even through a const keyval, which does not own the values (see class documentation).

template<convertible_to_mpi_handle<handle_type> Obj>
bool erase(Obj const &obj)

Destroys the value attached to obj, if any.

Throws:
  • mpi_error – if an attribute call fails.

Returns:

true if a value was destroyed.

Errors

struct mpi_error

Exception thrown by the MPI wrappers when an MPI call returns an error code other than MPI_SUCCESS.

Errors are only reported this way if the communicator’s error handler returns them, e.g. MPI_ERRORS_RETURN; with the default MPI_ERRORS_ARE_FATAL MPI aborts before the wrapper sees the error.

Defined in header <kamping/v2/error.hpp>

int error_code() const
Returns:

The MPI error code.

int error_class() const
Returns:

The MPI error class of the error code (MPI_Error_class).

mpi_error as_class_error() const
Returns:

An error whose code is the error class of this error.

std::string error_string() const
Returns:

The description of the error code (MPI_Error_string).

char const *what() const noexcept final
Returns:

The description of the error code, computed on first use.