API Documentation for C++

This page provides full documentation for the C++ API of MUSCLE3.

Namespace libmuscle

Data

class Data : public libmuscle::DataConstRef

A data object.

This represents a data object, which is what MUSCLE3 sends and receives.

Data objects refer to a simple value of a basic type, or refer to a dictionary or list. They model a reference, so if you copy a Data object to a new Data object, you’ll have two Data objects referring to the same data item. If you assign to a Data object, you modify the referred-to item, which will be visible also via any existing copies of the Data object.

With respect to memory management, this is like a shared_ptr, in that it will automatically manage any referenced memory, and only remove any actual items once all Data objects referring to them have been destructed.

Note that this publicly derives from DataConstRef, so see that class for the constructors and read-only member functions; they work on Data as well.

See the C++ tutorial for examples of how to use this.

Subclassed by libmuscle::ClosePort

Public Functions

Data(Data const&) = default

Copy-construct a Data object.

Explicit default avoids a compiler warning on some compilers.

Data(Data&&) = default

Move-construct a Data object.

Explicit default avoids a compiler warning on some compilers.

Data &operator=(Data const &rhs)

Copy-assign the given value to this Data object.

If the argument is a basic type, then the value will be copied. If it is a list or a dict, then this Data object will refer to the same list or dict as the argument.

Parameters:

rhs – The object to copy from.

Data operator[](std::string const &key)

Access a dictionary value by key.

Returns a Data object referring to the value for the given key. Assign to that object to modify a value, as in

mydict["stress"] = 12.4;

If no key with the given name exists, a new entry is added to the dictionary with the given key and a nil value, and a reference to it is then returned. This way new key/value pairs can be added to a dictionary.

Parameters:

key – The key to search for.

Throws:

std::runtime_error – if the object is not a dictionary.

Returns:

A writable reference to the requested value.

Data value(std::size_t i) const

Access a value in a dictionary by index.

Use only if is_a_dict() returns true.

Indices match those of key(), so value(i) will give you the value corresponding to key(i).

See also

size()

Parameters:

i – The index of the value to retrieve.

Throws:
  • std::runtime_error – if the object is not a map.

  • std::domain_error – if the index is out of bounds.

Data operator[](std::size_t index)

Access a list entry by index.

Returns a Data object referring to the value at the given index. Assign to that object to modify a value, as in

mylist[3] = 12.4;
mylist[4] = "MUSCLE3";
Parameters:

index – The index to refer to.

Throws:
  • std::runtime_error – if the object is not a list.

  • std::out_of_range – if the index is beyond the end of the list.

Returns:

A writable reference to the requested value.

char *as_byte_array()

Access a byte array.

Use is_a_byte_array() to check whether this object represents a byte array. Use size() to get the size in bytes.

The returned buffer will remain valid and accessible at least until this Data goes out of scope.

Throws:

std::runtime_error – if this is not a byte array.

Returns:

A pointer to a the first byte of a consecutive buffer.

DataConstRef()

Create a Data object representing nil.

Nil is a special “no data” value, like nullptr or None in Python.

DataConstRef(bool value)

Create a DataConstRef object representing a boolean value.

Parameters:

value – The value to represent.

DataConstRef(char const *const value)

Create a DataConstRef object representing a string value.

Parameters:

value – The value to represent, a null-terminated C string.

DataConstRef(std::string const &value)

Create a DataConstRef object representing a string value.

Parameters:

value – The value to represent.

DataConstRef(int value)

Create a DataConstRef object representing an integer value.

Parameters:

value – The value to represent.

DataConstRef(long int value)

Create a DataConstRef object representing an integer value.

Parameters:

value – The value to represent.

DataConstRef(long long int value)

Create a DataConstRef object representing an integer value.

Parameters:

value – The value to represent.

DataConstRef(unsigned int value)

Create a DataConstRef object representing an unsigned integer value.

Parameters:

value – The value to represent.

DataConstRef(unsigned long int value)

Create a DataConstRef object representing an unsigned integer value.

Parameters:

value – The value to represent.

DataConstRef(unsigned long long int value)

Create a DataConstRef object representing an unsigned integer value.

Parameters:

value – The value to represent.

DataConstRef(float value)

Create a DataConstRef object representing a 32-bit floating point value.

Parameters:

value – The value to represent.

DataConstRef(double value)

Create a DataConstRef object representing a 64-bit floating point value.

Parameters:

value – The value to represent.

DataConstRef(::ymmsl::SettingValue const &value)

Create a DataConstRef object from a SettingValue’s value.

Note that this will decode to whichever type is stored in the SettingValue, not to a SettingValue object.

Parameters:

value – The value to represent.

DataConstRef(::ymmsl::Settings const &settings)

Create a DataConstRef object representing a Settings object.

Parameters:

value – The value to represent.

DataConstRef(DataConstRef const&) = default

Copy-construct a DataConstRef object.

DataConstRef(DataConstRef&&) = default

Move-construct a DataConstRef object.

Public Static Functions

template<typename Element>
static Data grid(Element const *const data, std::vector<std::size_t> const &shape, std::vector<std::string> const &indexes = {}, StorageOrder storage_order = StorageOrder::last_adjacent)

Create a Data object containing a grid object.

This creates a DataConstRef that represents a grid or array of a given element type.

Supported types are std::int32_t, std::int64_t, float, double and bool. Note that unless you have exotic hardware, int, long and long long will be aliased as either int32_t or int64_t, and will therefore work as well. Unsigned integer types are not supported.

Besides a type, arrays have a shape. This is a list of sizes, one for each dimension of the array.

They also have a storage order, which specifies in which order the elements are arranged in memory. StorageOrder::first_adjacent means that array items who only differ by one in their first index are adjacent in memory, while StorageOrder::last_adjacent means that array items which only differ by one in their last index are adjacent in memory. Last adjacent is the standard in C and C++, and is also known as column-major, while first adjacent is the standard in Fortran, and is also known as row-major.

The data argument should be a pointer to a contiguous array of elements of the given type.

Finally, the optional index_names argument may be used to specify the names of the indices. For a Cartesian grid, these may be x and y, while for for example a polar grid you may have rho and phi. These names are optional, but help to make it easier to interpret the data, and so adding them is very much recommended.

Template Parameters:

Element – The type of the elements.

Parameters:
  • data – Pointer to the array data.

  • shape – The shape of the array.

  • indexes – Names of the array’s indexes.

  • storage_order – The storage order of the array data.

static Data dict()

Create a Data containing an empty dictionary.

Returns:

A Data containing an empty dictionary.

template<typename ...Args>
static Data dict(Args const&... args)

Create a Data containing a dictionary with the given keys and values.

An even number of arguments must be given. The even arguments must be strings, and are the keys, while the odd arguments are the values. These are Data objects, so you can pass those, or a value of any type representable by Data.

Example:

auto mydict = Data::dict(
    "id", "element1",
    "stress", 12.3,
    "strain", 1.23);
Returns:

A Data containing a dictionary with the given keys and values.

static Data list()

Create a Data containing an empty list.

Returns:

A Data containing an empty list.

static Data nils(std::size_t size)

Create a Data containing a list of the given size.

The items in the list will be initialised to the nil value.

Parameters:

size – The size of the new list.

Returns:

A Data containing a list of nil values of length size.

template<typename ...Args>
static Data list(Args const&... args)

Create a Data containing a list of the given items.

Each argument must be either a Data object, or an object of a type representable by a Data object.

static Data byte_array(uint32_t size)

Create a byte array of a given size.

The buffer will be owned by this Data object. Use as_byte_array() to get a pointer to put data into it.

static Data byte_array(char const *buffer, uint32_t size)

Create a Data referencing a byte array.

The buffer passed will not be copied! This creates a Data object that refers to your buffer, and you need to make sure that that buffer exists for as long as the Data object (and/or any copies of it) is used.

Parameters:
  • buffer – A pointer to the beginning of the buffer.

  • size – The size of the buffer.

DataConstRef

class DataConstRef

A const reference to some kind of data.

This defines a read-only API for variable data objects, which is what MUSCLE3 sends and receives.

As a user, you should be creating Data objects, not DataConstRef objects. Data objects have the same interface as DataConstRef objects, but have additional member functions for modification.

This class models a const reference. You can create it and access the referenced data, but you cannot assign to this because that would change the referenced data, and this is a const reference.

With respect to memory management, this is like a shared_ptr, in that it will automatically manage referenced memory, even if you copy the object.

Subclassed by libmuscle::Data

Public Functions

DataConstRef()

Create a Data object representing nil.

Nil is a special “no data” value, like nullptr or None in Python.

DataConstRef(bool value)

Create a DataConstRef object representing a boolean value.

Parameters:

value – The value to represent.

DataConstRef(char const *const value)

Create a DataConstRef object representing a string value.

Parameters:

value – The value to represent, a null-terminated C string.

DataConstRef(std::string const &value)

Create a DataConstRef object representing a string value.

Parameters:

value – The value to represent.

DataConstRef(int value)

Create a DataConstRef object representing an integer value.

Parameters:

value – The value to represent.

DataConstRef(long int value)

Create a DataConstRef object representing an integer value.

Parameters:

value – The value to represent.

DataConstRef(long long int value)

Create a DataConstRef object representing an integer value.

Parameters:

value – The value to represent.

DataConstRef(unsigned int value)

Create a DataConstRef object representing an unsigned integer value.

Parameters:

value – The value to represent.

DataConstRef(unsigned long int value)

Create a DataConstRef object representing an unsigned integer value.

Parameters:

value – The value to represent.

DataConstRef(unsigned long long int value)

Create a DataConstRef object representing an unsigned integer value.

Parameters:

value – The value to represent.

DataConstRef(float value)

Create a DataConstRef object representing a 32-bit floating point value.

Parameters:

value – The value to represent.

DataConstRef(double value)

Create a DataConstRef object representing a 64-bit floating point value.

Parameters:

value – The value to represent.

DataConstRef(::ymmsl::SettingValue const &value)

Create a DataConstRef object from a SettingValue’s value.

Note that this will decode to whichever type is stored in the SettingValue, not to a SettingValue object.

Parameters:

value – The value to represent.

DataConstRef(::ymmsl::Settings const &settings)

Create a DataConstRef object representing a Settings object.

Parameters:

value – The value to represent.

DataConstRef(DataConstRef const&) = default

Copy-construct a DataConstRef object.

DataConstRef(DataConstRef&&) = default

Move-construct a DataConstRef object.

DataConstRef &operator=(DataConstRef const&) = delete

Assignment is forbidden, this models a const reference.

DataConstRef &operator=(DataConstRef&&) = delete

Assignment is forbidden, this models a const reference.

void reseat(DataConstRef const &target)

Reseat the reference.

This makes this DataConstRef object refer to the object referred to by the argument.

Parameters:

target – The object to refer to.

template<typename T>
bool is_a() const

Determine the type of the referenced data.

This works for the following types:

  • bool

  • std::string

  • char (checks for integer, not for string!)

  • short int

  • int

  • long int

  • long long int

  • unsigned char

  • unsigned short int

  • unsigned int

  • unsigned long int

  • unsigned long long int

  • float

  • double

  • ymmsl::SettingValue

  • ymmsl::Settings

For checking nil, list and dict, see is_nil(), is_a_list() and is_a_dict().

Template Parameters:

T – The type to check.

bool is_nil() const

Return whether this references a nil value.

Returns:

True iff this references a nil value.

bool is_a_dict() const

Return whether this references a dict value.

If so, operator[key] can be used to obtain values.

Returns:

True iff this references a dict.

bool is_a_list() const

Return whether this references a list value.

If so, operator[index] can be used to obtain values.

Returns:

True iff this references a list.

template<typename Element>
bool is_a_grid_of() const

Return whether this references a grid of the given element type.

Supported element types are std::int32_t, std::int64_t, float, double, and bool. Unless you’re on some exotic machine, int, long, and long long are aliases for int32_t or int64_t, and so will also work. Unsigned types are not supported.

Template Parameters:

Element – The type of the elements of the array.

bool is_a_byte_array() const

Return whether this references a byte array.

If so, as_byte_array() can be used to obtain values, and size() to get the number of bytes in the array.

Returns:

True iff this references a byte array.

std::size_t size() const

Returns the size of a list, dict, grid or byte array.

Returns:

The number of items in a referenced list or dict value, the number of elements in a grid, or the number of bytes in a byte array.

template<typename T>
T as() const

Access a referenced scalar value.

Use is_a* first to check whether the type is what you expect. If the type mismatches, an exception will be thrown.

The following types can be used:

  • bool

  • std::string

  • char (accesses as integer, not as string!)

  • short int

  • int

  • long int

  • long long int

  • unsigned char

  • unsigned short int

  • unsigned int

  • unsigned long int

  • unsigned long long int

  • float

  • double

  • ymmsl::SettingValue

  • ymmsl::Settings

Template Parameters:

T – The type to access, as above.

Throws:

std::runtime_error – if the type does not match.

Returns:

The referenced value, as the given type.

const char *as_byte_array() const

Access a byte array.

Use is_a_byte_array() to check whether this object represents a byte array. Use size() to get the size.

The returned buffer will remain valid and accessible at least until this DataConstRef goes out of scope.

Throws:

std::runtime_error – if this is not a byte array.

Returns:

A pointer to a the first byte of a consecutive buffer.

DataConstRef operator[](std::string const &key) const

Access an item in a dictionary by key.

Use only if is_a_dict() returns true.

Parameters:

key – The key whose value to retrieve.

Throws:
  • std::runtime_error – if the object is not a map.

  • std::domain_error – if the key does not exist.

std::string key(std::size_t i) const

Access a key in a dictionary by index.

Use only if is_a_dict() returns true.

Indices match those of value(), so value(i) will give you the value corresponding to key(i).

See also

size()

Parameters:

i – The index of the key to retrieve.

Throws:
  • std::runtime_error – if the object is not a map.

  • std::domain_error – if the index is out of bounds.

DataConstRef value(std::size_t i) const

Access a value in a dictionary by index.

Use only if is_a_dict() returns true.

Indices match those of key(), so value(i) will give you the value corresponding to key(i).

See also

size()

Parameters:

i – The index of the value to retrieve.

Throws:
  • std::runtime_error – if the object is not a map.

  • std::domain_error – if the index is out of bounds.

DataConstRef operator[](std::size_t index) const

Access an item in a list.

Use only if is_a_list() returns true.

Indexes are zero-based, use size() to find the valid range.

Parameters:

index – The index at which to retrieve a value.

Throws:
  • std::runtime_error – if the object is not a list.

  • std::domain_error – if the index is out of range.

std::vector<std::size_t> shape() const

Get the shape of a grid.

Use only if is_a_grid_of() returns true.

The shape of an array is a list of sizes of the array, one for each of its dimensions.

Throws:

std::runtime_error – if the object is not a grid.

Returns:

The shape of the contained grid.

StorageOrder storage_order() const

Get the storage order of the grid.

Use only if is_a_grid_of() returns true.

The storage order is either StorageOrder::first_adjacent or StorageOrder::last_adjacent. StorageOrder::first_adjacent means that array items who only differ by one in their first index are adjacent in memory, while StorageOrder::last_adjacent means that array items which only differ by one in their last index are adjacent in memory. Last adjacent is the standard in C and C++, and is also known as column-major, while first adjacent is the standard in Fortran, and is also known as row-major.

Throws:

std::runtime_error – if the object is not a grid.

Returns:

The storage order of the grid.

bool has_indexes() const

Return whether a grid has index names.

Use only if is_a_grid_of() returns true.

This function determines whether the grid has named indexes. If so, you can access them through indexes().

Throws:

std::runtime_Error – if the object is not a grid.

Returns:

True iff the grid has named indexes.

std::vector<std::string> indexes() const

Get the index names of the grid.

Use only if is_a_grid_of() returns true and has_indexes() returns true.

The optional index names returned by this function specify which index refers to what. For a 2D Cartesian grid, these may be 'x' and 'y' for example, or for a polar grid, 'phi' and 'rho'. They’re intended to help annotate and use the data, and may be absent if the sender of a message did not include them.

Throws:

std::runtime_error – if the object is not a grid.

Returns:

The indexes.

template<typename Element>
const Element *elements() const

Get the elements (data values) of a grid.

Use only if is_a_grid_of<Element>() returns true.

This returns a pointer to the specified type which points to a block of memory containing the grid’s element values. They are contiguous in memory in the order specified by storage_order().

The returned pointer is valid at least as long as this object exists.

Template Parameters:

Element – The type of the data stored in the grid.

Throws:

std::runtime_error – if the object is not a grid of this type.

Returns:

A pointer to the data, as specified above.

Public Static Functions

template<typename Element>
static DataConstRef grid(Element const *const data, std::vector<std::size_t> const &shape, std::vector<std::string> const &indexes = {}, StorageOrder storage_order = StorageOrder::last_adjacent)

Create a DataConstRef object containing a grid object.

This creates a DataConstRef that represents a grid or array of a given element type.

Supported types are std::int32_t, std::int64_t, float, double and bool. Note that unless you have exotic hardware, int, long and long long will be aliased as either int32_t or int64_t, and will therefore work as well. Unsigned integer types are not supported.

Besides a type, arrays have a shape. This is a list of sizes, one for each dimension of the array.

They also have a storage order, which specifies in which order the elements are arranged in memory. StorageOrder::first_adjacent means that array items who only differ by one in their first index are adjacent in memory, while StorageOrder::last_adjacent means that array items which only differ by one in their last index are adjacent in memory. Last adjacent is the standard in C and C++, and is also known as column-major, while first adjacent is the standard in Fortran, and is also known as row-major.

The data argument should be a pointer to a contiguous array of elements of the given type.

Finally, the optional index_names argument may be used to specify the names of the indices. For a Cartesian grid, these may be x and y, while for for example a polar grid you may have rho and phi. These names are optional, but help to make it easier to interpret the data, and so adding them is very much recommended.

Template Parameters:

Element – The type of the elements.

Parameters:
  • data – Pointer to the array data.

  • shape – The shape of the array.

  • indexes – Names of the array’s indexes.

  • storage_order – The storage order of the array data.

static DataConstRef dict()

Create a DataConstRef containing an empty dictionary.

Returns:

A DataConstRef containing an empty dictionary.

template<typename ...Args>
static DataConstRef dict(Args const&... args)

Create a DataConstRef of a dictionary with the given keys and values.

An even number of arguments must be given. The even arguments must be strings, and are the keys, while the odd arguments are the values. These are DataConstRef objects, so you can pass those, or a value of any type representable by DataConstRef.

Example:

auto mydict = Data::dict(
    "id", "element1",
    "stress", 12.3,
    "strain", 1.23);
Returns:

A DataConstRef containing a dictionary with the given keys and values.

static DataConstRef list()

Create a DataConstRef containing an empty list.

Returns:

A DataConstRef containing an empty list.

static DataConstRef nils(std::size_t size)

Create a DataConstRef containing a list of the given size.

The items in the list will be initialised to the nil value.

Parameters:

size – The size of the new list.

Returns:

A DataConstRef containing a list of nil values of length size.

template<typename ...Args>
static DataConstRef list(Args const&... args)

Create a DataConstRef containing a list of the given items.

Each argument must be either a DataConstRef object, or an object of a type representable by a DataConstRef object.

Instance

class Instance

Represents a component instance in a MUSCLE3 simulation.

This class provides a low-level send/receive API for the instance to use.

Public Functions

Instance(int argc, char const *const argv[], MPI_Comm const &communicator = MPI_COMM_WORLD, int root = 0)

Create an Instance.

For MPI-based components, creating an Instance is a collective operation, so it must be done in all processes simultaneously, with the same communicator and the same root.

Parameters:
  • argc – The number of command-line arguments.

  • argv – Command line arguments.

  • communicator – MPI communicator containing all processes in this instance (MPI only).

  • root – The designated root process (MPI only).

Instance(int argc, char const *const argv[], PortsDescription const &ports, MPI_Comm const &communicator = MPI_COMM_WORLD, int root = 0)

Create an instance.

A PortsDescription can be written like this:

PortsDescription ports({ {Operator::F_INIT, {“port1”, “port2”}}, {Operator::O_F, {“port3[]”}} });

For MPI-based components, creating an Instance is a collective operation, so it must be done in all processes simultaneously, with the same communicator and the same root.

Parameters:
  • argc – The number of command-line arguments.

  • argv – Command line arguments.

  • ports – A description of the ports that this instance has.

  • communicator – MPI communicator containing all processes in this instance (MPI only).

  • root – The designated root process (MPI only).

Instance(int argc, char const *const argv[], InstanceFlags flags, MPI_Comm const &communicator = MPI_COMM_WORLD, int root = 0)

Create an Instance.

For MPI-based components, creating an Instance is a collective operation, so it must be done in all processes simultaneously, with the same communicator and the same root.

Parameters:
  • argc – The number of command-line arguments.

  • argv – Command line arguments.

  • flags – InstanceFlags for this instance.

  • communicator – MPI communicator containing all processes in this instance (MPI only).

  • root – The designated root process (MPI only).

Instance(int argc, char const *const argv[], PortsDescription const &ports, InstanceFlags flags, MPI_Comm const &communicator = MPI_COMM_WORLD, int root = 0)

Create an instance.

A PortsDescription can be written like this:

PortsDescription ports({ {Operator::F_INIT, {“port1”, “port2”}}, {Operator::O_F, {“port3[]”}} });

For MPI-based components, creating an Instance is a collective operation, so it must be done in all processes simultaneously, with the same communicator and the same root.

Parameters:
  • argc – The number of command-line arguments.

  • argv – Command line arguments.

  • ports – A description of the ports that this instance has.

  • flags – InstanceFlags for this instance.

  • communicator – MPI communicator containing all processes in this instance (MPI only).

  • root – The designated root process (MPI only).

bool reuse_instance()

Decide whether to run this instance again.

In a multiscale simulation, instances get reused all the time. For example, in a macro-micro simulation, the micromodel does a complete run for every timestep of the macromodel. Rather than starting up a new instance of the micromodel, which could be expensive, we reuse a single instance many times.

This may bring other advantages, such as faster convergence when starting from the previous final state, and in some cases may be necessary if micromodel state needs to be preserved from one macro timestep to the next.

So in MUSCLE, submodels run in a reuse loop, which runs them over and over again until their work is done and they should be shut down. Whether to do another F_INIT, O_I, S, O_F cycle is decided by this method.

This method must be called at the beginning of the reuse loop, i.e. before the F_INIT operator, and its return value should decide whether to enter that loop again.

MPI-based components must execute the reuse loop in each process in parallel, and call this function at the top of the reuse loop in each process.

void error_shutdown(std::string const &message)

Logs an error and shuts down the Instance.

If you detect that something is wrong (invalid input, invalid settings, simulation diverged, or anything else really), you should call this method before calling exit() or raising an exception that you don’t expect to catch.

If you do so, the Instance will tell the rest of the simulation that it encountered an error and will shut down. That makes it easier to debug the situation (the message will be logged), and it reduces the chance that other parts of the simulation will sit around waiting forever for a message that this instance was supposed to send.

MPI-based components may either call this function in all processes, or only in the root process (as passed to the constructor).

Parameters:

message – An error message describing the problem.

std::vector<std::string> list_settings() const

List settings by name.

This function returns a list of names of the available settings.

Returns:

A list of setting names.

::ymmsl::SettingValue get_setting(std::string const &name) const

Returns the value of a model setting.

MPI-based components may call this function at any time within the reuse loop, in any or all processes, simultaneously or not.

Parameters:

name – The name of the setting, without any instance prefix.

Throws:

std::out_of_range – if no setting with the given name exists.

Returns:

The value of the setting as a generic SettingValue.

template<typename ValueType>
ValueType get_setting_as(std::string const &name) const

Returns the value of a model setting.

MPI-based components may call this function at any time within the reuse loop, in any or all processes, simultaneously or not.

Template Parameters:

ValueType – The (expected) type of the setting. Needs to match exactly or an exception will be thrown, this will not convert e.g. an integer into a string.

Parameters:

name – The name of the setting, without any instance prefix.

Throws:
  • std::out_of_range – if no setting with the given name exists.

  • std::bad_cast – if the value is not of the specified type.

Returns:

The value of the setting as a ValueType

std::unordered_map<::ymmsl::Operator, std::vector<std::string>> list_ports() const

Returns a description of the ports that this CE has.

This keeps Doxygen from getting confused.

Note that the result has almost the same format as the port declarations you pass when making an Instance. The only difference is that the port names never have [] at the end, even if the port is a vector port.

MPI-based components may call this function only in the root process.

Returns:

A map, indexed by operator, containing lists of port names. Operators with no associated ports are not included.

bool is_connected(std::string const &port) const

Returns whether the given port is connected.

MPI-based components may call this function only in the root process.

Parameters:

port – The name of the port to inspect.

Returns:

true if there is a conduit attached to this port, false if not.

bool is_vector_port(std::string const &port) const

Returns whether a port is a vector or scalar port.

If a port has been declared to be a vector port (i.e. the name passed when creating this Instance had ‘[]’ at the end), then you can pass a ‘slot’ argument when sending or receiving. It’s like the port is a vector of slots on which you can send or receive messages.

MPI-based components may call this function only in the root process.

This function returns True if the given port is a vector port, and False if it is a scalar port.

Parameters:

port – The port to check this property of.

bool is_resizable(std::string const &port) const

Returns whether the given port is resizable.

Scalar ports are never resizable. Whether a vector port is resizable depends on what it is connected to.

MPI-based components may call this function only in the root process.

Parameters:

port – Name of the port to inspect.

Returns:

: true if the port can be resized, false if not.

int get_port_length(std::string const &port) const

Returns the current length of the port.

MPI-based components may call this function only in the root process.

Parameters:

port – The name of the port to measure.

Throws:

std::runtime_error – if this is a scalar port.

void set_port_length(std::string const &port, int length)

Resizes the port to the given length.

You should check whether the port is resizable using is_resizable() first; whether it is depends on how this component is wired up, so you should check.

MPI-based components may call this function only in the root process.

Parameters:
  • port – Name of the port to resize.

  • length – The new length.

Throws:

std::runtime_error – if the port is not resizable.

void send(std::string const &port_name, Message const &message)

Send a message to the outside world.

Sending is non-blocking, a copy of the message will be made and stored until the receiver is ready to receive it.

MPI-based components may call this function either in all processes, or only in the root process. In both cases, the message given by the root process will be sent, the others ignored.

Parameters:
  • port_name – The port on which this message is to be sent.

  • message – The message to be sent.

void send(std::string const &port_name, Message const &message, int slot)

Send a message to the outside world.

Sending is non-blocking, a copy of the message will be made and stored until the receiver is ready to receive it.

MPI-based components may call this function either in all processes, or only in the root process. In both cases, the message given by the root process will be sent, the others ignored. You may want to do a gather operation first to collect all the information that is to be sent in the root process.

Parameters:
  • port_name – The port on which this message is to be sent.

  • message – The message to be sent.

  • slot – The slot to send the message on.

Message receive(std::string const &port_name)

Receive a message from the outside world.

Receiving is a blocking operation. This function will contact the sender, wait for a message to be available, and receive and return it.

If the port you are receiving on is not connected, an exception will be thrown.

MPI-based components must call this function in all processes simultaneously. The received message will be returned in the root process, all other processes will receive a dummy message. It is therefore up to the model code to scatter or broadcast the received message to the non-root processes, if necessary.

Parameters:

port_name – The endpoint on which a message is to be received.

Throws:

std::runtime_error – if the given port is not connected.

Returns:

The received message. The settings attribute of the received message will not be set.

Message receive(std::string const &port_name, Message const &default_msg)

Receive a message from the outside world.

Receiving is a blocking operation. This function will contact the sender, wait for a message to be available, and receive and return it.

If the port you are receiving on is not connected, the default value you specified will be returned exactly as you passed it.

MPI-based components must call this function in all processes simultaneously. The received message will be returned in the root process, all other processes will receive a dummy message. It is therefore up to the model code to scatter or broadcast the received message to the non-root processes, if necessary.

Parameters:
  • port_name – The endpoint on which a message is to be received.

  • default_msg – A default value to return if this port is not connected.

Throws:

std::runtime_error – if the given port is not connected and no default value was given.

Returns:

The received message. The settings attribute of the received message will not be set.

Message receive(std::string const &port_name, int slot)

Receive a message from the outside world.

Receiving is a blocking operation. This function will contact the sender, wait for a message to be available, and receive and return it.

If the port you are receiving on is not connected, an exception will be thrown.

MPI-based components must call this function in all processes simultaneously. The received message will be returned in the root process, all other processes will receive a dummy message. It is therefore up to the model code to scatter or broadcast the received message to the non-root processes, if necessary.

Parameters:
  • port_name – The endpoint on which a message is to be received.

  • slot – The slot to receive the message, on, if any.

Throws:

std::runtime_error – if the given port is not connected and no default value was given.

Returns:

The received message. The settings attribute of the received message will not be set.

Message receive(std::string const &port_name, int slot, Message const &default_msg)

Receive a message from the outside world.

Receiving is a blocking operation. This function will contact the sender, wait for a message to be available, and receive and return it.

If the port you are receiving on is not connected, the default value you specified will be returned exactly as you passed it. If you didn’t specify a default value (e.g. because there is no reasonable default, you really need the outside input) and the port is not connected, you’ll get a std::runtime_error thrown.

MPI-based components must call this function in all processes simultaneously. The received message will be returned in the root process, all other processes will receive a dummy message. It is therefore up to the model code to scatter or broadcast the received message to the non-root processes, if necessary.

Parameters:
  • port_name – The endpoint on which a message is to be received.

  • slot – The slot to receive the message, on, if any.

  • default_msg – A default value to return if this port is not connected.

Throws:

std::runtime_error – if the given port is not connected and no default value was given.

Returns:

The received message. The settings attribute of the received message will not be set.

Message receive_with_settings(std::string const &port_name)

Receive a message with attached settings overlay.

This function should not be used in submodels. It is intended for use by special components that are ensemble-aware and have to pass on overlay settings explicitly.

Receiving is a blocking operation. This function will contact the sender, wait for a message to be available, and receive and return it.

If the port you are receiving on is not connected, an exception will be thrown.

MPI-based components must call this function in all processes simultaneously. The received message will be returned in the root process, all other processes will receive a dummy message. It is therefore up to the model code to scatter or broadcast the received message to the non-root processes, if necessary.

Parameters:

port_name – The port on which a message is to be received.

Throws:

std::runtime_error – if the given port is not connected.

Returns:

The received message. The settings attribute of the received message will contain the received settings.

Message receive_with_settings(std::string const &port_name, int slot)

Receive a message with attached settings overlay.

This function should not be used in submodels. It is intended for use by special components that are ensemble-aware and have to pass on overlay settings explicitly.

Receiving is a blocking operation. This function will contact the sender, wait for a message to be available, and receive and return it.

If the port you are receiving on is not connected, an exception will be thrown.

MPI-based components must call this function in all processes simultaneously. The received message will be returned in the root process, all other processes will receive a dummy message. It is therefore up to the model code to scatter or broadcast the received message to the non-root processes, if necessary.

Parameters:
  • port_name – The endpoint on which a message is to be received.

  • slot – The slot to receive the message, on, if any.

Throws:

std::runtime_error – if the given port is not connected.

Returns:

The received message. The settings attribute of the received message will contain the received settings.

Message receive_with_settings(std::string const &port_name, Message const &default_msg)

Receive a message with attached settings overlay.

This function should not be used in submodels. It is intended for use by special components that are ensemble-aware and have to pass on overlay settings explicitly.

Receiving is a blocking operation. This function will contact the sender, wait for a message to be available, and receive and return it.

If the port you are receiving on is not connected, the default value you specified will be returned exactly as you passed it. If you didn’t specify a default value (e.g. because there is no reasonable default, you really need the outside input) and the port is not connected, you’ll get a std::runtime_error thrown.

MPI-based components must call this function in all processes simultaneously. The received message will be returned in the root process, all other processes will receive a dummy message. It is therefore up to the model code to scatter or broadcast the received message to the non-root processes, if necessary.

Parameters:
  • port_name – The endpoint on which a message is to be received.

  • default_msg – A default value to return if this port is not connected.

Throws:

std::runtime_error – if the given port is not connected and no default value was given.

Returns:

The received message. The settings attribute of the received message will contain the received settings.

Message receive_with_settings(std::string const &port_name, int slot, Message const &default_msg)

Receive a message with attached settings overlay.

This function should not be used in submodels. It is intended for use by special components that are ensemble-aware and have to pass on overlay settings explicitly.

Receiving is a blocking operation. This function will contact the sender, wait for a message to be available, and receive and return it.

If the port you are receiving on is not connected, the default value you specified will be returned exactly as you passed it. If you didn’t specify a default value (e.g. because there is no reasonable default, you really need the outside input) and the port is not connected, you’ll get a std::runtime_error thrown.

MPI-based components must call this function in all processes simultaneously. The received message will be returned in the root process, all other processes will receive a dummy message. It is therefore up to the model code to scatter or broadcast the received message to the non-root processes, if necessary.

Parameters:
  • port_name – The endpoint on which a message is to be received.

  • slot – The slot to receive the message, on, if any.

  • default_msg – A default value to return if this port is not connected.

Throws:

std::runtime_error – if the given port is not connected and no default value was given.

Returns:

The received message. The settings attribute of the received message will contain the received settings.

bool resuming()

Check if this instance is resuming from a snapshot.

Must be used by submodels that implement the checkpointing API. You’ll get a RuntimeError if you don’t call this method in an iteration of the reuse loop.

This method returns True for the first iteration of the reuse loop after resuming from a previously taken snapshot. When resuming from a snapshot, the submodel must load its state from the snapshot returned by Instance::load_snapshot.

MPI-based components must call this function in all processes simultaneously.

Returns:

true iff the submodel must resume from a snapshot.

bool should_init()

Check if this instance should initialize.

Must be used by submodels that implement the checkpointing API.

When resuming from a previous snapshot, instances need not always execute the F_INIT phase of the submodel execution loop. Use this method before attempting to receive data on F_INIT ports.

MPI-based components must call this function in all processes simultaneously.

Returns:

true if the submodel must execute the F_INIT step.

Returns:

false otherwise.

Message load_snapshot()

Load a snapshot.

Must only be called when Instance::resuming returns True.

MPI-based components may only call this from the root process. An error is raised when attempting to call this method in any other process. It is therefore up to the model code to scatter or broadcast the snapshot state to the non-root processes, if necessary.

Returns:

Message containing the state as saved in a previous run through Instance::save_snapshot or Instance::save_final_snapshot.

bool should_save_snapshot(double timestamp)

Check if a snapshot should be saved after the S Operator of the submodel.

This method checks if a snapshot should be saved right now, based on the provided timestamp and elapsed wallclock time.

If this method returns true, then the submodel must also save a snapshot through Instance::save_snapshot. A std::runtime_error will be generated if this is not done.

See also Instance::should_save_final_snapshot for the variant that must be called at the end of the reuse loop.

MPI-based components must call this function in all processes simultaneously.

Parameters:

timestamp – current timestamp of the submodel.

Returns:

true iff a snapshot should be taken by the submodel according to the checkpoint rules provided in the ymmsl configuration.

void save_snapshot(Message message)

Save a snapshot after the S Operator of the submodel.

Before saving a snapshot, you should check using Instance::should_save_snapshot if a snapshot should be saved according to the checkpoint rules specified in the ymmsl configuration. You should use the same timestamp in the provided Message object as used to query Instance::should_save_snapshot.

MPI-based components may only call this from the root process. An error is raised when attempting to call this method in any other process. It is therefore up to the model code to gather the necessary state from the non-root processes before saving the snapshot.

Parameters:

messageMessage object that is saved as snapshot. The message timestamp attribute should be the same as passed to Instance::should_save_snapshot. The data attribute can be used to store the internal state of the submodel.

bool should_save_final_snapshot()

Check if a snapshot should be saved at the end of the reuse loop.

This method checks if a snapshot should be saved at the end of the reuse loop. All your communication on O_F ports must be finished before calling this method, otherwise your simulation may deadlock.

When this method returns true, the submodel must also save a snapshot through Instance::save_final_snapshot. A std::runtime_error will be generated if this is not done.

See also Instance::should_save_snapshot for the variant that may be called inside of a time-integration loop of the submodel.

MPI-based components must call this function in all processes simultaneously.

Note

This method will block until it can determine whether a final snapshot should be taken, because it must determine if this instance is reused.

Returns:

true iff a final snapshot should be taken by the submodel according to the checkpoint rules provided in the ymmsl configuration.

void save_final_snapshot(Message message)

Save a snapshot at the end of the reuse loop.

Before saving a snapshot, you should check using Instance::should_save_final_snapshot if a snapshot should be saved according to the checkpoint rules specified in the ymmsl configuration.

See also Instance::save_snapshot for the variant that may be called after each S Operator of the submodel.

MPI-based components may only call this from the root process. An error is raised when attempting to call this method in any other process. It is therefore up to the model code to gather the necessary state from the non-root processes before saving the snapshot.

Parameters:

messageMessage object that is saved as snapshot. The data attribute can be used to store the internal state of the submodel.

InstanceFlags

enum class libmuscle::InstanceFlags : int

Enumeration of properties that an instance may have.

You may combine multiple flags using the bitwise OR operator |. For example:

auto flags = InstanceFlags::DONT_APPLY_OVERLAY | InstanceFlags::USES_CHECKPOINT_API;
Instance instance(argc, argv, flags);

Values:

enumerator NONE
enumerator DONT_APPLY_OVERLAY

Do not apply the received settings overlay during prereceive of F_INIT messages.

If you’re going to use Instance.receive_with_settings on your F_INIT ports, you need to set this flag when creating an Instance.

If you don’t know what that means, do not specify this flag and everything will be fine. If it turns out that you did need to specify the flag, MUSCLE3 will tell you about it in an error message and you can add it still.

enumerator USES_CHECKPOINT_API

Indicate that this instance supports checkpointing.

You may not use any checkpointing API calls when this flag is not supplied.

enumerator KEEPS_NO_STATE_FOR_NEXT_USE

Indicate this instance does not carry state between iterations of the reuse loop.

Specifying this flag is equivalent to ymmsl.KeepsStateForNextUse.NO.

By default, (if neither KEEPS_NO_STATE_FOR_NEXT_USE nor STATE_NOT_REQUIRED_FOR_NEXT_USE are provided), the instance is assumed to keep state between reuses, and to require that state (equivalent to ymmsl.KeepsStateForNextUse.NECESSARY).

enumerator STATE_NOT_REQUIRED_FOR_NEXT_USE

Indicate this instance carries state between iterations of the reuse loop, however this state is not required for restarting.

Specifying this flag is equivalent to ymmsl.KeepsStateForNextUse.HELPFUL.

By default, (if neither KEEPS_NO_STATE_FOR_NEXT_USE nor STATE_NOT_REQUIRED_FOR_NEXT_USE are provided), the instance is assumed to keep state between reuses, and to require that state (equivalent to ymmsl.KeepsStateForNextUse.NECESSARY).

Message

class Message

A message to be sent or received.

This class describes a message to be sent or that has been received.

Public Functions

explicit Message(double timestamp)

Create an empty Message.

Parameters:

timestamp – Simulation time for which this data is valid.

Message(double timestamp, DataConstRef const &data)

Create a Message.

Parameters:
  • timestamp – Simulation time for which this data is valid.

  • data – An object to send or that was received.

Message(double timestamp, double next_timestamp, DataConstRef const &data)

Create a Message.

Parameters:
  • timestamp – Simulation time for which this data is valid.

  • next_timestamp – Simulation time for the next message to be transmitted through this port.

  • data – An object to send or that was received.

Message(double timestamp, DataConstRef const &data, ymmsl::Settings const &settings)

Create a Message.

Parameters:
  • timestamp – Simulation time for which this data is valid.

  • data – An object to send or that was received.

  • settings – Overlay settings to send or that were received.

Message(double timestamp, double next_timestamp, DataConstRef const &data, ymmsl::Settings const &settings)

Create a Message.

Parameters:
  • timestamp – Simulation time for which this data is valid.

  • next_timestamp – Simulation time for the next message to be transmitted through this port.

  • data – An object to send or that was received.

  • settings – Overlay settings to send or that were received.

Message(Message const &message)

Copy constructor.

Message(Message &&message)

Move constructor.

Message &operator=(Message const &message)

Copy assignment.

Message &operator=(Message &&message)

Move assignment.

double timestamp() const

Returns the timestamp of the message.

void set_timestamp(double timestamp)

Sets the timestamp of the message.

Parameters:

timestamp – The new value.

bool has_next_timestamp() const

Returns whether the message has a next timestamp.

double next_timestamp() const

Returns the next timestamp of the message.

Only call if has_next_timestamp() returns true.

Throws:

std::logic_error – if the next timestamp is not set.

void set_next_timestamp(double next_timestamp)

Sets the next timestamp of the message.

Parameters:

next_timestamp – The new value.

void unset_next_timestamp()

Unsets the next timestamp of the message.

const DataConstRef &data() const

Returns the data of the message.

void set_data(DataConstRef const &data)

Sets data to the given value.

Parameters:

data – The new data to set.

bool has_settings() const

Returns whether the message carries settings.

const ::ymmsl::Settings &settings() const

Returns the settings carried by the message.

Only call if has_settings() returns true.

void set_settings(::ymmsl::Settings const &settings)

Sets settings to the given value.

This overwrites the entire Settings object, not a single value.

Parameters:

settings – The new settings to use.

void unset_settings()

Unsets the settings of the message.

PortsDescription

using libmuscle::PortsDescription = std::unordered_map<ymmsl::Operator, std::vector<std::string>>

A description of which ports a component has.

You can create one like this:

PortsDescription ports({
    {Operator::F_INIT, {"port1", "port2"}},
    {Operator::O_F, {"port3[]"}}
    });

and access elements as

ports[Operator::F_INIT][0] == "port1";

or for a const reference to a PortsDescription

ports.at(Operator::F_INIT)[1] == "port2";

Namespace ymmsl

allows_sending

bool ymmsl::allows_sending(Operator op)

Whether the given operator allows sending messages.

Parameters:

op – The operator to check.

Returns:

true If and only if the operator allows sending

allows_receiving

bool ymmsl::allows_receiving(Operator op)

Whether the given operator allows receiving messages.

Parameters:

op – The operator to check.

Returns:

true If and only if the operator allows receiving

Conduit

class Conduit

A conduit transports data between simulation components.

A conduit has two endpoints, which are references to a Port on a Component. These references must be of one of the following forms:

  • submodel.port

  • namespace.submodel.port (or several namespace prefixes)

@attribute sender The sending port that this conduit is connected to. @attribute receiver The receiving port that this conduit is connected to.

Public Functions

Conduit(std::string const &sender, std::string const &receiver)

Create a Conduit.

Parameters:
  • sender – The sending port that this conduit is connected to, including the component name and the port name.

  • receiver – The receiving port that this conduit is connected to, including the component name and the port name.

explicit operator std::string() const

Convert to string.

bool operator==(Conduit const &rhs) const

Compare two conduits for equality.

Parameters:

rhs – The other conduit to compare with.

Returns:

true iff the two conduits are identical.

Reference sending_component() const

Returns a reference to the sending component.

Identifier sending_port() const

Returns the identity of the sending port.

std::vector<int> sending_slot() const

Returns the slot on the sending port.

If no slot was given, an empty list is returned.

Note that conduits connected to specific slots are currently not supported by MUSCLE3.

Returns:

A list of slot indexes.

Reference receiving_component() const

Returns a reference to the receiving component.

Identifier receiving_port() const

Returns the identity of the receiving port.

std::vector<int> receiving_slot() const

Returns the slot on the receiving port.

If no slot was given, an empty list is returned.

Note that conduits connected to specific slots are currently not supported by MUSCLE3.

Returns:

A list of slot indexes.

Identifier

class Identifier

A custom string type that represents an identifier.

An identifier may consist of upper- and lowercase characters, digits, and underscores.

Public Functions

Identifier(std::string const &contents)

Create an Identifier.

This creates a new identifier object, using the given string.

Parameters:

contents – The contents of the identifier.

Throws:

std::invalid_argument – if contents is not a valid identifier.

Identifier(char const *const contents)

Create an Identifier.

This creates a new identifier object, using the given C-style string.

Parameters:

contents – The contents of the identifier.

Throws:

std::invalid_argument – if contents is not a valid identifier.

operator std::string() const

Implicit conversion to std::string.

This is a custom string class, so that’s appropriate.

Returns:

The string representation of this Identifier.

bool operator==(Identifier const &rhs) const

Compare for equality.

Parameters:

rhs – The Identifier to compare against.

Returns:

True iff both Identifiers are equal.

bool operator==(std::string const &rhs) const

Compare for equality against a string.

Parameters:

rhs – The string to compare against.

Returns:

True iff the Identifier matches the string.

bool operator==(char const *const rhs) const

Compare for equality against a C-style string.

Parameters:

rhs – The string to compare against.

Returns:

True iff the Identifier matches the string.

bool operator!=(Identifier const &rhs) const

Compare for inequality.

Parameters:

rhs – The Identifier to compare against.

Returns:

True iff both Identifiers are different.

bool operator!=(std::string const &rhs) const

Compare for inequality against a string.

Parameters:

rhs – The string to compare against.

Returns:

True iff the Identifier is different from the string.

bool operator!=(char const *const rhs) const

Compare for inequality against a C-style string.

Parameters:

rhs – The string to compare against.

Returns:

True iff the Identifier is different from the string.

std::ostream &ymmsl::operator<<(std::ostream &os, Identifier const &i)

Operator

enum class ymmsl::Operator

An operator of a component.

This is a combination of the Submodel Execution Loop operators, and operators for other components such as mappers.

Values:

enumerator NONE
enumerator F_INIT
enumerator O_I
enumerator S
enumerator O_F

Port

struct Port

A port on a component.

Ports are used by components to send or receive messages on. They are connected by conduits to enable communication between components.

Subclassed by libmuscle::Port

Public Functions

Port(Identifier const &name, Operator oper)

The MMSL operator in which this port is used.

Create a Port.

Parameters:
  • name – The name of the port.

  • oper – The MMSL operator in which this port is used.

Public Members

Operator oper

The name of the port.

Reference

class Reference

A reference to an object in the MMSL execution model.

References in string form are written as either:

In object form, they consist of a list of Identifiers and ints. The first list item is always an Identifier. For the rest of the list, an Identifier represents a period operator with that argument, while an int represents the indexing operator with that argument.

Reference objects act like a list of Identifiers and ints, you can get their length using length(), iterate through the parts using cbegin() and cend(), and get individual items using []. Note that the sublist has to be a valid Reference, so it cannot start with an int.

References can be compared for equality to each other or to a plain string, and they can be used as dictionary keys. Reference objects are immutable (or they’re supposed to be anyway), so do not try to change any of the elements. Instead, make a new Reference. Especially References that are used as dictionary keys must not be modified, this will get your dictionary in a very confused state.

Public Types

typedef std::vector<ReferencePart>::const_iterator const_iterator

Random access iterator type for a Reference.

Public Functions

Reference(std::string const &content)

Create a Reference from a string.

Creates a Reference from a string, which will be parsed.

Parameters:

content – A string to parse.

Throws:

std::invalid_argument – if the argument does not define a valid Reference.

Reference(char const *content)

Create a Reference from a C string.

Creates a Reference from a C string, which will be parsed.

Parameters:

content – A string to parse.

Throws:

std::invalid_argument – if the argument does not define a valid Reference.

template<class ForwardIt>
Reference(ForwardIt begin, ForwardIt end)

Create a Reference from a ReferencePart range.

*begin and *end must be of type ReferencePart.

Parameters:
  • begin – An iterator to the start of the range.

  • end – An iterator to the end of the range.

explicit operator std::string() const

Conversion to std::string.

Returns:

The string representation of this Identifier.

std::size_t length() const

Returns the number of parts in the Reference.

bool operator==(Reference const &rhs) const

Compares for equality.

Will compare part-by-part.

Parameters:

rhs – The Reference to compare with.

Returns:

True iff the two References are equal.

bool operator==(std::string const &rhs) const

Compares for equality.

Compares string representations.

Parameters:

rhs – The string to compare with.

Returns:

True iff this Reference matches the given string.

bool operator==(char const *rhs) const

Compares for equality.

Compares string representations.

Parameters:

rhs – The string to compare with.

Returns:

True iff this Reference matches the given string.

bool operator!=(Reference const &rhs) const

Compares for inequality.

Will compare part-by-part.

Parameters:

rhs – The Reference to compare with.

Returns:

True iff the two References are different.

bool operator!=(std::string const &rhs) const

Compares for inequality.

Compares string representations.

Parameters:

rhs – The string to compare with.

Returns:

True iff this Reference does not match the given string.

bool operator!=(char const *rhs) const

Compares for inequality.

Compares string representations.

Parameters:

rhs – The string to compare with.

Returns:

True iff this Reference does not match the given string.

const_iterator cbegin() const

Returns a const_iterator to the beginning of the Reference.

const_iterator cend() const

Returns a const_iterator to one-past-the-end of the Reference.

const_iterator begin() const

Returns a const_iterator to the beginning of the Reference.

const_iterator end() const

Returns a const_iterator to one-past-the-end of the Reference.

const ReferencePart &operator[](int i) const

Returns the ReferencePart at the given index.

Parameters:

i – The index to dereference.

Returns:

The ReferencePart at that index.

const Reference &operator+=(ReferencePart const &rhs)

Append a part to this Reference.

Parameters:

rhs – The part to append.

Returns:

A reference to this (updated) object.

const Reference &operator+=(std::vector<int> const &rhs)

Append a list of indexes to this Reference.

Parameters:

rhs – The indexes to append.

Returns:

A reference to this (updated) object.

Reference operator+(Reference const &rhs) const

Concatenate two References.

Parameters:

rhs – The Reference to append to this one to produce the new Reference.

Reference operator+(ReferencePart const &rhs) const

Append a ReferencePart to this Reference to create a new one.

Parameters:

rhs – The ReferencePart to append to this one to produce the new Reference.

Reference operator+(std::vector<int> const &rhs) const

Append a list of indexes to this Reference.

Parameters:

rhs – The indexes to append.

std::ostream &ymmsl::operator<<(std::ostream &os, Reference const &r)
class ReferencePart

An item in a Reference.

Public Functions

ReferencePart(Identifier const &i)

Create a ReferencePart containing an Identifier.

This is implicit, so that you can give an Identifier wherever a ReferencePart is required.

Parameters:

i – The Identifier to store.

ReferencePart(int index)

Create a ReferencePart containing an index.

This is implicit, so that you can give an int wherever a ReferencePart is required.

Parameters:

index – The index to store.

bool is_identifier() const

Returns whether this Part holds an Identifier.

Returns:

True iff this holds an Identifier.

bool is_index() const

Returns whether this Part holds an index.

Returns:

True iff this holds an index.

const Identifier &identifier() const

Returns the Identifier value.

Throws:

std::runtime_error – if this object does not hold an Identifier.

Returns:

The identifier value.

int index() const

Returns the index value.

Throws:

std::runtime_error – if this object does not hold an index.

Returns:

The index value.

bool operator==(ReferencePart const &rhs) const

Compares for equality.

Parameters:

rhs – The ReferencePart to compare with.

Returns:

True if both type and value match.

bool operator!=(ReferencePart const &rhs) const

Compares for inequality.

Parameters:

rhs – The ReferencePart to compare with.

Returns:

True if type or value mismatch.

Settings

class Settings

Settings for doing an experiment.

An experiment is done by running a model with particular settings, e.g. the submodel scales, model parameters, and any other settings.

Public Functions

Settings() = default

Create an empty Settings object.

Settings(std::initializer_list<MapType_::value_type> const &init)

Create a Settings object with the given settings.

Parameters:

init – An initializer list with pairs of {Reference, SettingValue}

bool operator==(Settings const &rhs) const

Compare Settings objects for equality.

Returns:

True iff the Settings are equal.

bool operator!=(Settings const &rhs) const

Compare Settings objects for inequality.

Returns:

True iff the Settings are not equal.

std::size_t size() const

Return the number of settings in this object.

bool empty() const

Return true iff this object has no settings.

bool contains(Reference const &setting) const

Return true iff a setting with this name exists here.

Parameters:

setting – Name of the setting to check for.

Returns:

true iff it exists.

const SettingValue &at(Reference const &setting) const

Get the value of a given setting.

Parameters:

setting – The name of the setting to read.

Throws:

std::out_of_range – if there is no setting with that name.

Returns:

The value of that setting.

SettingValue &operator[](Reference const &setting)

Set the value of a given setting.

Adds the setting first if it does not exist.

Parameters:

setting – The name of the setting to read.

Returns:

A reference to the setting’s value that can be modified.

std::size_t erase(std::string const &setting)

Removes setting with the given key.

Parameters:

setting – Key of the setting to remove.

Returns:

The number of settings removed (0u or 1u).

void clear()

Removes all settings.

const_iterator begin() const

Return an iterator to the first setting.

The iterator dereferences to a std::pair<Reference, SettingValue>.

const_iterator end() const

Return an iterator past the last setting.

std::ostream &ymmsl::operator<<(std::ostream &os, ymmsl::Settings const &settings)

Outputs a human-readable representation of the Settings to a stream.

This makes it so you can use e.g. std::cout << settings.

SettingValue

class SettingValue

Holds the value of a setting.

This is a discriminated union that can contain a std::string, an int64_t, a double, a bool, a std::vector<double> or a std::vector<std::vector<double>>.

Values of these types will be automatically converted wherever a SettingValue is required.

Public Functions

SettingValue()

Create an empty (and invalid) SettingValue.

SettingValue(std::string const &value)

Create a SettingValue containing a string.

Parameters:

value – The string value to hold.

SettingValue(char const *value)

Create a SettingValue containing a string.

Parameters:

value – The string value to hold.

SettingValue(int value)

Create a SettingValue containing an int64_t.

Parameters:

value – The value to hold.

SettingValue(long int value)

Create a SettingValue containing an int64_t.

Parameters:

value – The value to hold.

SettingValue(long long int value)

Create a SettingValue containing an int64_t.

Parameters:

value – The value to hold.

SettingValue(double value)

Create a SettingValue containing a double.

Parameters:

value – The value to hold.

SettingValue(bool value)

Create a SettingValue containing a bool.

Parameters:

value – The value to hold.

SettingValue(std::initializer_list<double> value)

Create a SettingValue containing a std::vector<double>.

This covers SettingValue({1.0, 2.0, 3.0});

Parameters:

value – The value to hold.

SettingValue(std::vector<double> const &value)

Create a SettingValue containing a std::vector<double>.

Parameters:

value – The value to hold.

SettingValue(std::initializer_list<std::vector<double>> const &value)

Create a SettingValue containing a std::vector<std::vector<double>>.

This covers SettingValue({{1.0, 2.0}, {3.0, 4.0}});

Parameters:

value – The value to hold.

SettingValue(std::vector<std::vector<double>> const &value)

Create a SettingValue containing a std::vector<std::vector<double>>.

Parameters:

value – The value to hold.

SettingValue(SettingValue const &other)

Copy-constructs a SettingValue.

SettingValue(SettingValue &&other)

Move-constructs a SettingValue.

SettingValue &operator=(SettingValue const &other)

Copy-assigns a SettingValue.

SettingValue &operator=(SettingValue &&other)

Move-assigns a SettingValue.

~SettingValue()

Destructs a SettingValue.

bool operator==(SettingValue const &rhs) const

Compare against another SettingValue.

Returns true iff both type and value are the same.

Parameters:

rhs – The value to compare with.

bool operator!=(SettingValue const &rhs) const

Compare against another SettingValue.

Returns true iff both type and value are the same.

Parameters:

rhs – The value to compare with.

template<typename T>
bool is_a() const

Return whether this SettingValue holds a value of the given type.

Note that for int32_t, this function will return true only if the value is integer and fits in an int32_t. For double, it will return true if the value is integer, even if converting it to a double would reduce precision.

Since int and long are usually equivalent to int32_t or int64_t, you can use those values too.

Parameters:

T – A valid type, being one of std::string, int32_t, int64_t, double, bool, std::vector<double>, or std::vector<std::vector<double>>.

template<typename T>
T as() const

Return the value as the given type.

Only call if is_a<T>() returns true.

Parameters:

T – A valid type, being one of std::string, int32_t, int64_t, double, bool, std::vector<double>, or std::vector<std::vector<double>>.

Throws:

std::bad_cast – if the type of this value does not match the template parameter.

std::ostream &ymmsl::operator<<(std::ostream &os, ymmsl::SettingValue const &val)

Outputs a human-readable representation of the SettingValue to a stream.

This makes it so you can use e.g. std::cout << setting_value.