Skip to content

9. Running Simulations

Román Cárdenas edited this page Feb 1, 2023 · 6 revisions

Simulating DEVS (and Cell-DEVS) models is Cadmium is pretty straightforward. We will illustrate it with the GPT model. However, the process is equivalent for any DEVS model built in Cadmium 2.

Sequential Simulation

This is the simplest approach to simulate a DEVS model.

#include <cadmium/core/logger/csv.hpp>  // To import a CSV logger (to store simulation results in CSV file)
#include <cadmium/core/simulation/root_coordinator.hpp>  // To import the root coordinator
#include <limits>
#include "gpt.hpp"

int main() {
    // model-related configuration parameters
    int jobPeriod = 3;
    int processingTime = 1;
    double obsTime = 102.;

    // We create the model and forward it to the root coordinator
    // NOTE THAT WE NEED A POINTER TO THE MODEL!
    auto model = std::make_shared<GPT>("gpt", jobPeriod, processingTime, obsTime);
    auto rootCoordinator = cadmium::RootCoordinator(model);
    
    // We can add a logger to the root coordinator
    // In this example, we use a CSV logger that uses ; to separate columns.
    // Simulation results will be stored in the log_gpt.csv file.
    auto logger = std::make_shared<cadmium::CSVLogger>("log_gpt.csv", ";");
    rootCoordinator.setLogger(logger);
    
    // To start the simulation we 1) start, 2) simulate 3) stop.
    rootCoordinator.start();
    // in simulate method, we can select a maximum simulation time (in this case, infinity)
    rootCoordinator.simulate(std::numeric_limits<double>::infinity());
    rootCoordinator.stop();

    return 0;
}

Logging Simulation Results

In most of the cases, we don't just want to simulate our model, but also store the simulation results somewhere. To do so, we must attach a logger to the top coordinator. In the next example, we will attach a CSV logger to our simulation. Simulation results will be stored in the log_gpt.csv file:

#include <cadmium/core/logger/csv.hpp>  // To import a CSV logger (to store simulation results in CSV file)
#include <cadmium/core/simulation/root_coordinator.hpp>
#include <limits>
#include "gpt.hpp"

int main() {
    int jobPeriod = 3;
    int processingTime = 1;
    double obsTime = 102.;
    auto model = std::make_shared<GPT>("gpt", jobPeriod, processingTime, obsTime);
    auto rootCoordinator = cadmium::RootCoordinator(model);
    
    // We can add a logger to the root coordinator
    // In this example, we use a CSV logger that uses ; to separate columns.
    // Simulation results will be stored in the log_gpt.csv file.
    auto logger = std::make_shared<cadmium::CSVLogger>("log_gpt.csv", ";");
    rootCoordinator.setLogger(logger);
    
    rootCoordinator.start();
    rootCoordinator.simulate(std::numeric_limits<double>::infinity());
    rootCoordinator.stop();

    return 0;
}

Once the simulation is done, we can open the log_gpt.csv file. We will find something like this:

time;model_id;model_name;port_name;data
0;1;transducer;;{0,0,0}
0;2;processor;;inf
0;3;generator;;0
0;1;transducer;;{0,1,0}
0;2;processor;;1
0;3;generator;outGenerated;{0,0,-1}

Columns are separated by semicolons (this is configurable). The time column represents the simulation time. On the other hand, model_id and model_name clearly identifies which model generated the log trace. The meaning of the next two fields depends on the trace. The port_name column contains an optional field. If the column is empty, then the value in the data column represents the model's state. On the other hand, if the port_name column is not empty, then data represents an output message, and port_name univoquely identifies which port generated this message.

Parallel Simulation

If you have all the dependencies for running parallel simulation, you can give it a shot as follows:

#include <cadmium/core/logger/csv.hpp>
#include <cadmium/core/simulation/parallel_root_coordinator.hpp> //<! Use parallel coordinator instead!
#include <limits>
#include "gpt.hpp"

using namespace cadmium::example::gpt;

int main() {
    // We created the model exactly in the same fashion
    int jobPeriod = 3;
    int processingTime = 1;
    double obsTime = 102.;
    auto model = std::make_shared<GPT>("gpt", jobPeriod, processingTime, obsTime);
    
    // However, now we create a parallel root coordinator
    auto rootCoordinator = cadmium::ParallelRootCoordinator(model);

    // We can add a new logger as with the sequential coordinator
    auto logger = std::make_shared<cadmium::CSVLogger>("log_gpt.csv", ";");
    rootCoordinator.setLogger(logger);

    // We run the simulation using the same methods!
    rootCoordinator.start();
    rootCoordinator.simulate(std::numeric_limits<double>::infinity());
    rootCoordinator.stop();
    return 0;
}