###############
Getting Started
###############
Build and Test
==============
To build and install the library, you must have these tools:
- `CMake `_ 3.24 or newer
- A C++ compiler that supports C++23, because the library uses ``std::expected``
.. note::
On Linux, clang cannot compile ``std::expected`` with libstdc++. Use GCC, or use clang with libc++.
CMake downloads the other dependencies (yaml-cpp, and googletest for the tests).
.. code-block:: console
$ git clone https://github.com/NCAR/MechanismConfiguration.git
$ cd MechanismConfiguration
$ mkdir build
$ cd build
$ cmake ..
$ make install -j 8
$ make test
To change the installation directory, set ``CMAKE_INSTALL_PREFIX``.
Use the library in a CMake project
----------------------------------
After you install the library, find it with ``find_package`` and link to the ``musica::mechanism_configuration`` target:
.. code-block:: cmake
find_package(mechanism_configuration REQUIRED)
target_link_libraries(my_target PRIVATE musica::mechanism_configuration)
Docker Container
----------------
Build and run the image::
$ docker build -t mechanism_configuration -f docker/Dockerfile .
$ docker run --rm -it mechanism_configuration
Run an Example
==============
All work goes through the ``mechanism_configuration::Mechanism`` struct. You can get a ``Mechanism`` in two ways:
- **Parse** a configuration file. The parser reads the version from the file and uses the correct parser for it.
- **Build** a ``Mechanism`` in code, then **validate** it.
``Validate()`` runs the same semantic checks as the parser. For example, it checks that each species in a reaction exists.
.. code-block:: cpp
#include
#include
using namespace mechanism_configuration;
void print_errors(const Errors& errors)
{
for (const auto& [code, message] : errors)
std::cerr << " [" << ErrorCodeToString(code) << "] " << message << '\n';
}
int main()
{
int status = 0;
// 1) Parse from a file (YAML or JSON; v0 or v1). Returns std::expected
// with both structural and semantic errors reported.
if (auto parsed = Parse("examples/v1/full_configuration.yaml"))
{
const Mechanism& mechanism = *parsed;
std::cout << "Parsed '" << mechanism.name << "': " << mechanism.species.size()
<< " species, " << mechanism.reactions.arrhenius.size() << " Arrhenius reactions\n";
}
else
{
std::cerr << "Failed to parse file:\n";
print_errors(parsed.error());
status = 1;
}
// 2) Build a Mechanism in code and validate it (species exist, reactants are in their
// phase, no duplicate names, ...).
Mechanism mechanism;
mechanism.name = "example";
mechanism.species = { { .name = "A" }, { .name = "B" } };
mechanism.phases = { { .name = "gas", .species = { { .name = "A" }, { .name = "B" } } } };
types::Arrhenius reaction;
reaction.name = "A -> B";
reaction.gas_phase = "gas";
reaction.reactants = { { .name = "A" } }; // reactants must be registered in the phase
reaction.products = { { .name = "B" } }; // products may reference any phase
mechanism.reactions.arrhenius = { reaction };
if (Errors errors = Validate(mechanism); errors.empty())
std::cout << "In-code mechanism is valid\n";
else
{
std::cerr << "In-code mechanism is invalid:\n";
print_errors(errors);
status = 1;
}
return status;
}
To learn how to write a configuration file, see the :doc:`user_guide/index`.
For all of the types and functions, see the :doc:`api/index`.