Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/verify_guided_examples.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright 2026 Matteo Fusi and Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
name: "Build Guided Examples"
on:
push:
branches: [ "main" ]
paths:
- 'docs/guided_examples/**'
pull_request:
branches: [ "main" ]
paths:
- 'docs/guided_examples/**'
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
jobs:
Build-Guided-Examples:
strategy:
matrix:
os: [ ubuntu-latest ]
name: Build and test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- uses: cachix/install-nix-action@v31
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
- name: Build Examples
run: cd docs/guided_examples && nix develop --command ./build_all_examples.sh
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/.idea
/cmake-build-*
/docs/tutorial/build*
/docs/guided_examples/*/build*
/docs/guided_examples/flake.lock
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ cd Simo
Clone Simo and initialize the submodules:

Build dependencies:
- Clang (recommended)
- CMake >= 3.31.0
- Boost ([Boost.Test](https://www.boost.org/libs/test), [Boost.TypeIndex](https://www.boost.org/libs/type_index))
- [Glaze](https://github.com/stephenberry/glaze)
Expand All @@ -42,7 +43,7 @@ The GitHub actions run entering the virtual environment of `nix develop`.

## First Steps

Look inside [docs/tutorial](./docs/tutorial) .
Look inside [docs/guided_examples](./docs/guided_examples) .

## Features

Expand Down
11 changes: 3 additions & 8 deletions docs/guided_examples/1_FirstModule_and_SimoSim/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,16 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Look for Simo package
find_package(Simo REQUIRED)
get_filename_component(SIMO_PACKAGE_PREFIX "${Simo_DIR}/../../.." ABSOLUTE)


# Create you collection of modules
add_library(TutorialCollection SHARED
add_library(FirstModuleCollection SHARED
FirstModule.cc
)
# Hide symbols by default
set_target_properties(TutorialCollection PROPERTIES
set_target_properties(FirstModuleCollection PROPERTIES
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN 1
)

# Use Simo::Simo_includes_only to only use the include files and avoid direct linking to Simo
target_link_libraries(TutorialCollection PRIVATE Simo::Simo_includes_only)
target_include_directories(TutorialCollection PRIVATE
"${SIMO_PACKAGE_PREFIX}/include"
)
target_link_libraries(FirstModuleCollection PRIVATE Simo::Simo_includes_only)
92 changes: 80 additions & 12 deletions docs/guided_examples/1_FirstModule_and_SimoSim/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ The documents highlights some location in the source of [FirstModule.cc](./First
to better understand how to write your own `Module` class and how to use it
in `SimoSim`, a general purpose executable to run simulations.

It is assumed that this example is executed inside the nix development environment
provided by [`../flake.nix`](../flake.nix).

### You first module
## You first module

Modules are the basic block of the simulation. They have the ability to
schedule events in the simulation loop. To create a new module, it is
enough to inherit from `Simo::Module` class.


#### Module initialization
### Module initialization
All the classed are declared in the
include `Simo/Simo.h` and they are contained in the `Simo` namespace.

Expand Down Expand Up @@ -56,21 +58,87 @@ Other interesting content in the `initialize` method:
- a new statistic is created with `create_statistic` method.
- logging is set up to save the log at `tutorial_module.log`

#### Module event
### Module event

`event_log` runs first at time zero, and it re-schedules itself every `period` time units
using the simulation context. Look for `Simo/core/Context.h` for the difference between
`schedule_at` and `schedule_in` of .
using the simulation context. Look at `Simo/core/Context.h` for the difference between
`schedule_at` and `schedule_in` .
Source of the method:


```cpp
void log_event() {
// schedule_in schedule and event at current_time + period
++(*num_events);
log(Log::LogLevel::INFO, [this]() {
return std::format("{}, Hello from TestModule!", num_events->value());
});
sim_ctx().schedule_in(period, [this]() { log_event(); });
// schedule_in schedule and event at current_time + period
++(*num_events);
log(Log::LogLevel::INFO, [this]() {
return std::format("{}, Hello from TestModule!", num_events->value());
});
sim_ctx().schedule_in(period, [this]() { log_event(); });
}
```

This function above increase the statistic, and it logs the event in the logger.

### Parameters for the module

`Parameters` class defines a set of parameters. Parameters are organized in a
trie-like structure. The easiest way to define parameters for a new module is to
extend the `Parameters` class, and add parameter definitions in the constructor.

```cpp
class FirstModuleParameters : public Parameters {
public:
// Parameters describe inputs of a Module.
// Parameters with a default value are added with `trie.add<>`
// and without a default with `trie.add_unset<>`
FirstModuleParameters() {
// validator method is used to verify if a parameter is valid
trie.add_unset<Time>("period").validator(
[](const auto& t) { return t > Time::one; });
trie.add<std::string>("log_level", "WARNING");
}
};

```

## Expose modules and parameters for SimoSim

`SimoSim` is an executable able to detect shared libraries at runtime that contains
modules. A shared library needs to expose a function named `simo_get_collection`.
With this function, `SimoSim` can load a collection of factories. A Factory tells
`SimoSim` how to instantiate a module and the associated parameters.


## Build the test module as a shared library

Use the usual CMake commands to build the shared library that contains the `FirstModule`. Note
it is not required to link against the shared library of Simo in this case: only
the header files are sufficient. The build process will create a shared library
named `libFirstModuleCollection.<extension>`.

## Run your first module with `SimoSim`

Assuming:
- The shared library has been built in `<COLLECTION_PATH>`
- The path to the example is `<EXAMPLE_PATH>`
Run `SimoSim` with the following command:

```bash
SimoSim --config <EXAMPLE_PATH>/system_config.yaml --search-path <COLLECTION_PATH>
```

This command will run the simulation as specified in `system_config.yaml`. Please
look at this file and look at the structure. Note:
- The `collector` module. This one allows to dump statistics
- The `parameters` section allows to specify the parameters for a module instance
- `connections` is empty. Connections are going to be explained in another example.
- `simulation` section tells how long the simulation should run.


## Next Steps

Try to create your own module and pack it into a collection.

A more complete example is the `PingPongCollection` at
`tests/collection/PingPongCollection.cc`.

The second example will show how to deal with module ports.
82 changes: 0 additions & 82 deletions docs/guided_examples/1_FirstModule_and_SimoSim/flake.lock

This file was deleted.

3 changes: 3 additions & 0 deletions docs/guided_examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Guided Examples

This directory contains a set of simple examples to learn how to use Simo.
28 changes: 28 additions & 0 deletions docs/guided_examples/build_all_examples.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#! /usr/bin/env bash
#
# Copyright 2026 Matteo Fusi and Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
BUILD_TYPE="Debug"

while IFS= read -r -d '' dir
do
pushd "$dir" > /dev/null || exit
echo "Building example in $dir"
cmake -B ./build "-DCMAKE_BUILD_TYPE=$BUILD_TYPE"
cmake --build ./build --config "$BUILD_TYPE" -j
popd > /dev/null || exit
done < <(find "$SCRIPT_DIR" -mindepth 1 -maxdepth 1 -type d -print0)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
flake-utils.url = "github:numtide/flake-utils";

simo.url = "../../..";
simo.url = "../..";
simo.inputs.nixpkgs.follows = "nixpkgs";
simo.inputs.flake-utils.follows = "flake-utils";
};
Expand All @@ -26,7 +26,6 @@
llvm
glaze
doxygen

simo.packages.${system}.default
];
};
Expand Down
3 changes: 2 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
simo = pkgs.stdenv.mkDerivation {
simo = pkgs.clangStdenv.mkDerivation {
pname = "simo";
version = "0.0.1";
src = ./.;
Expand All @@ -47,6 +47,7 @@

doCheck = true;
checkPhase = ''
ls *.so
ctest --output-on-failure
'';
};
Expand Down
4 changes: 2 additions & 2 deletions include/Simo/core/Time.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ struct TimeValue {
Time::Unit unit;
};

template <auto Format>
template <unsigned int Format>
struct from<Format, Time> {
template <auto Opts>
static void op(Time& value, is_context auto&& ctx, auto&& it, auto&& end) {
Expand All @@ -161,7 +161,7 @@ struct from<Format, Time> {
}
};

template <auto Format>
template <unsigned int Format>
struct to<Format, Time> {
template <auto Opts>
static void op(const Time& value, is_context auto&& ctx, auto&& b,
Expand Down
4 changes: 2 additions & 2 deletions include/Simo/port/Port.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class SIMO_PUBLIC Port {

/// Utility to the get type of class. Need the type at compile time
template <typename Self>
TypeId get_type_id(this Self& _) {
TypeId get_type_id(this Self& /*unused*/) {
return boost::typeindex::type_id<Self>();
}

Expand Down Expand Up @@ -86,7 +86,7 @@ class SIMO_PUBLIC OutPort : public Port {
state_ = PORT_STATE::FILLED;
return SEND_OUTCOME::REPLACED;
}
SIMO_ASSERT(false);
std::abort();
}

void clear() { state_ = PORT_STATE::EMPTY; }
Expand Down
Loading