# Writing Documentation#

## User Manual#

The user manual (including the page you are currently reading) is generated with Sphinx using the reStructuredText syntax. Here, you will find some examples that help you write your own documentation entry (take a look at the “page source” to see the code behind the text).

### Examples#

Tables of contents are implemented like this:

Notes, warnings, and hints can be included thusly:

Note

This is a note.

Warning

This is a warning.

Hint

This is a hint.

#### Math and Formulae#

Mathematical expressions can be included like so:

Let $$x \rightarrow \infty$$, then

$\lim_{x \rightarrow \infty} \frac{1}{x} = 0$

#### Code snippets and blocks#

Code snippets like std::algorithm or cell_manager are indicated like this. Code blocks can be included like this:

def id(x):
return x


#### Python Documentation Bits#

The typical use case of Sphinx is rendering a documentation of Python modules.

class utopya.multiverse.Multiverse(*, model_name: Optional[str] = None, info_bundle: = None, run_cfg_path: Optional[str] = None, user_cfg_path: Optional[str] = None, _shared_worker_manager: Optional[utopya.workermanager.WorkerManager] = None, **update_meta_cfg)[source]

Bases: object

The Multiverse is where a single simulation run is orchestrated from.

It spawns multiple universes, each of which represents a single simulation of the selected model with the parameters specified by the meta configuration.

The WorkerManager takes care to perform these simulations in parallel, the DataManager allows loading the created data, and the PlotManager handles plotting of that data.

Initialize the Multiverse.

Parameters
• model_name (str, optional) – The name of the model to run

• info_bundle (ModelInfoBundle, optional) – The model information bundle that includes information about the binary path etc. If not given, will attempt to read it from the model registry.

• run_cfg_path (str, optional) – The path to the run configuration.

• user_cfg_path (str, optional) – If given, this is used to update the base configuration. If None, will look for it in the default path, see Multiverse.USER_CFG_SEARCH_PATH.

• _shared_worker_manager (WorkerManager, optional) –

If given, this already existing WorkerManager instance (and its reporter) will be used instead of initializing new instances.

Warning

This argument is only exposed for internal purposes. It should not be used for production code and behavior of this argument may change at any time.

• **update_meta_cfg – Can be used to update the meta configuration generated from the previous configuration levels

BASE_META_CFG_PATH = '/builds/utopia-project/docs/utopia/python/utopya/utopya/cfg/base_cfg.yml'
USER_CFG_SEARCH_PATH = '/root/.config/utopia/user_cfg.yml'
RUN_DIR_TIME_FSTR = '%y%m%d-%H%M%S'
UTOPYA_BASE_PLOTS_PATH = '/builds/utopia-project/docs/utopia/python/utopya/utopya/plot_funcs/base_plots.yml'
__init__(*, model_name: Optional[str] = None, info_bundle: = None, run_cfg_path: Optional[str] = None, user_cfg_path: Optional[str] = None, _shared_worker_manager: Optional[utopya.workermanager.WorkerManager] = None, **update_meta_cfg)[source]

Initialize the Multiverse.

Parameters
• model_name (str, optional) – The name of the model to run

• info_bundle (ModelInfoBundle, optional) – The model information bundle that includes information about the binary path etc. If not given, will attempt to read it from the model registry.

• run_cfg_path (str, optional) – The path to the run configuration.

• user_cfg_path (str, optional) – If given, this is used to update the base configuration. If None, will look for it in the default path, see Multiverse.USER_CFG_SEARCH_PATH.

• _shared_worker_manager (WorkerManager, optional) –

If given, this already existing WorkerManager instance (and its reporter) will be used instead of initializing new instances.

Warning

This argument is only exposed for internal purposes. It should not be used for production code and behavior of this argument may change at any time.

• **update_meta_cfg – Can be used to update the meta configuration generated from the previous configuration levels

property info_bundle: utopya.model_registry.info_bundle.ModelInfoBundle

The model info bundle for this Multiverse

property model_name: str

The model name associated with this Multiverse

property model_binpath: str

The path to this model’s binary

property meta_cfg: dict

The meta configuration.

property dirs: dict

Information on managed directories.

property cluster_mode: bool

Whether the Multiverse should run in cluster mode

property cluster_params: dict

Returns a copy of the cluster mode configuration parameters

property resolved_cluster_params: dict

Returns a copy of the cluster configuration with all parameters resolved. This makes some additional keys available on the top level.

property dm: utopya.datamanager.DataManager

The Multiverse’s DataManager.

property wm: utopya.workermanager.WorkerManager

The Multiverse’s WorkerManager.

property pm: utopya.plotting.PlotManager

The Multiverse’s PlotManager.

run(*, sweep: Optional[bool] = None)[source]

Starts a Utopia simulation run.

Specifically, this method adds simulation tasks to the associated WorkerManager, locks its task list, and then invokes the start_working() method which performs all the simulation tasks.

If cluster mode is enabled, this will split up the parameter space into (ideally) equally sized parts and only run one of these parts, depending on the cluster node this Multiverse is being invoked on.

Note

As this method locks the task list of the WorkerManager, no further tasks can be added henceforth. This means, that each Multiverse instance can only perform a single simulation run.

Parameters

sweep (bool, optional) – Whether to perform a sweep or not. If None, the value will be read from the perform_sweep key of the meta-configuration.

run_single()[source]

Runs a single simulation using the parameter space’s default value.

See run() for more information.

run_sweep()[source]

Runs a parameter sweep.

See run() for more information.

renew_plot_manager(**update_kwargs)[source]

Tries to set up a new PlotManager. If this succeeds, the old one is discarded and the new one is associated with this Multiverse.

Parameters

**update_kwargs – Passed on to PlotManager.__init__

__annotations__ = {}
__dict__ = mappingproxy({'__module__': 'utopya.multiverse', '__doc__': 'The Multiverse is where a single simulation run is orchestrated from.\n\n    It spawns multiple universes, each of which represents a single simulation\n    of the selected model with the parameters specified by the meta\n    configuration.\n\n    The WorkerManager takes care to perform these simulations in parallel, the\n    DataManager allows loading the created data, and the PlotManager handles\n    plotting of that data.\n    ', 'BASE_META_CFG_PATH': '/builds/utopia-project/docs/utopia/python/utopya/utopya/cfg/base_cfg.yml', 'USER_CFG_SEARCH_PATH': '/root/.config/utopia/user_cfg.yml', 'RUN_DIR_TIME_FSTR': '%y%m%d-%H%M%S', 'UTOPYA_BASE_PLOTS_PATH': '/builds/utopia-project/docs/utopia/python/utopya/utopya/plot_funcs/base_plots.yml', '__init__': <function Multiverse.__init__>, 'info_bundle': <property object>, 'model_name': <property object>, 'model_binpath': <property object>, 'meta_cfg': <property object>, 'dirs': <property object>, 'cluster_mode': <property object>, 'cluster_params': <property object>, 'resolved_cluster_params': <property object>, 'dm': <property object>, 'wm': <property object>, 'pm': <property object>, 'run': <function Multiverse.run>, 'run_single': <function Multiverse.run_single>, 'run_sweep': <function Multiverse.run_sweep>, 'renew_plot_manager': <function Multiverse.renew_plot_manager>, '_create_meta_cfg': <function Multiverse._create_meta_cfg>, '_create_run_dir': <function Multiverse._create_run_dir>, '_setup_pm': <function Multiverse._setup_pm>, '_perform_backup': <function Multiverse._perform_backup>, '_perform_pspace_backup': <function Multiverse._perform_pspace_backup>, '_prepare_executable': <function Multiverse._prepare_executable>, '_resolve_cluster_params': <function Multiverse._resolve_cluster_params>, '_add_sim_task': <function Multiverse._add_sim_task>, '_add_sim_tasks': <function Multiverse._add_sim_tasks>, '_validate_meta_cfg': <function Multiverse._validate_meta_cfg>, '__dict__': <attribute '__dict__' of 'Multiverse' objects>, '__weakref__': <attribute '__weakref__' of 'Multiverse' objects>, '__annotations__': {}})
__module__ = 'utopya.multiverse'
__weakref__

list of weak references to the object (if defined)

#### Doxygen Documentation Bits#

Wondering what the class template Cell looks like? Well, here you go:

template<typename Traits>
class Cell : public Utopia::Entity<Cell<Traits>, Traits>#

A cell is a slightly specialized state container.

It can be extended with the use of tags and can be associated with so-called “custom links”. These specializations are carried into the cell by means of the CellTraits struct. A cell is embedded into the CellManager, where the discretization allows assigning a position in space to the cell. The cell itself does not need to know anything about that …

Template Parameters

Traits – Valid Utopia::EntityTraits, describing the type of cell

Public Types

using Self = Cell<Traits>#

The type of this cell.

using State = typename Traits::State#

The type of the state.

Public Functions

inline Cell(const IndexType id, const State initial_state)#

Construct a cell.

#### The Logging Module#

This is a documentation of the entire Logging module:

group Logging

Utility functions for all logging output based on the spdlog backend.

All output of the simulation backend is intended to be controlled via loggers. Loggers are implemented using spdlog (see https://github.com/gabime/spdlog). Regular output via the standard pipes std::cout and std::cerr is strongly discouraged.

Utopia generates three types of loggers: One logger for Data I/O functions, one for Core (backend) functions, and one for each model instance. The Utopia::Model base class holds a logger instance which should be used for information on the current model. To write log messages from within Data I/O or Core backend functions, the respective logger first has to be retrieved. This is achieved by using spdlog::get (https://github.com/gabime/spdlog/wiki/2.-Creating-loggers#accessing-loggers-using-spdlogget). The names for the two loggers are exported within the Utopia namespace. All log levels are handled through the input configuration files.

The Utopia::PseudoParent automatically creates the utility loggers. For executables without Models (like tests), the loggers have to be created explicitly by manually calling Utopia::setup_loggers.

Functions

inline std::shared_ptr<spdlog::logger> init_logger(const std::string name, const spdlog::level::level_enum level, const bool throw_on_exist = true)#

Initialize a logger with a certain name and log level.

If the logger already exists, issue a warning and only set the log level. Optionally, this function can throw an exception.

Parameters
• name – Name of the logger. This is also the registered logger name.

• level – Level of the logger. See spdlog::level::level_enum

• throw_on_exist – Throw an exception if the logger exists

inline void setup_loggers(const spdlog::level::level_enum level_core = spdlog::level::warn, const spdlog::level::level_enum level_data_io = spdlog::level::warn, const spdlog::level::level_enum level_data_mngr = spdlog::level::warn, const std::string &log_pattern = "")#

Set up and register the global loggers and set the global log pattern.

Utopia employs the following global loggers:

• core: for the Core module

• data_io: for the Data I/O module in general

• data_mngr: for the DataIO::DataManager

They can be retrieved with the spdlog::get(name) function, where ‘name’ can be one of the ‘log_’ strings stored in the Utopia namespace.

This function only (re)sets the log levels if the loggers already exist.

Parameters
• level_core – Log level of the core logger

• level_data_io – Log level of the data_io logger

• level_data_mngr – Log level of the data_mngr logger

• log_pattern – The global log pattern. If empty, a pre-defined log pattern will be set instead of the spdlog default.

Variables

const std::string log_core = "core"#
const std::string log_data_io = "data_io"#
const std::string log_data_mngr = "data_mngr"#

## C++ Documentation#

The C++ documentation is created with Doxygen. If you want to contribute to Utopia, you will need to write documentation, too. For this, we provide coding guidelines, as well as the additional information below.

### How to write the Doxygen documentation#

Doxygen is a neat and widely used tool to document C++ source code. The documentation is based on docstrings that are attached to the actual source code they should document using the comment syntax of the respective programming language.

Whenever you write a new function, class, and even when you only add a new class member or method, write at least a \brief description, such that this object can later be referred to via the documentation. Notice that you can also add docstrings to a certain object anywhere in the source code, if need be.

### Using Doxygen Modules#

Documentations for large code bases quickly become confusing. By default, Doxygen groups documentation pages by class names and namespaces. However, a certain set of classes typically closely interact within one, or even across several, namespaces. For documenting these groupings and interactions, Doxygen implements Modules.

Somewhere in the source code, one may define a module using \defgroup <label> <title>, or \addtogroup <label> together with a set of brackets { ... }. Single objects can be added to an existing group with \ingroup <label>. Modules themselves can be nested, i.e., a module can be grouped into another module.

For documenting modules, we use modules.dox files inside the respective source directory. Doxygen always uses the C++ syntax, therefore all documentation inside these files must have the syntax of a C++ comment.

## Python Documentation#

When developing utopya or any other part of the Utopia frontend, you will also have to write documentation of the Python code. For this, please consult and follow the coding guidelines.