| Prev | Getting Started – Table of Contents | Next |

Part 2: Creating your First Simulation

Here we will create a very simple SyDEVS simulation.

Let’s start by adding a few new folders to your sydevs-tutorial project.

  1. In sydevs-tutorial/src/nodes, create a folder named getting_started.
  2. In the new getting_started folder, create a folder named waveform. This is where your first SyDEVS node will be located.
  3. In sydevs-tutorial/src/simulations make a folder named first_simulation. The code here will invoke the simulation code in nodes/getting_started/waveform.

The overall directory structure should now be as follows.

sydevs-tutorial/
    bin/
        ...
    external/
        ...
    src/
        nodes/
            getting_started/
                waveform/
        simulations/
            first_simulation/
            setting_up/

The CMakeLists.txt file will have to be updated, so let’s get that out of the way. Add the following instructions to the SyDEVS Nodes section. These instructions prepare a list of the header (.h) files you will later create in the waveform folder.

set(WAVEFORM_DIR ${NODES_DIR}/getting_started/waveform)
file(GLOB WAVEFORM_HDRS "${WAVEFORM_DIR}/*.h")

Also add the following instructions to the SyDEVS Simulations section. These instructions create an executable for Part 2 of the tutorial. Observe that the executable references the waveform header files.

set(FIRST_SIMULATION_DIR ${SIMULATIONS_DIR}/first_simulation)
aux_source_directory(${FIRST_SIMULATION_DIR} FIRST_SIMULATION_SRCS)
add_executable(first_simulation ${FIRST_SIMULATION_SRCS} ${WAVEFORM_HDRS})
target_link_libraries(first_simulation SyDEVS-static)

The bottom of the CMakeLists.txt file should now appear as follows.

# ------------------------------------------------------------------------------
#
#   SyDEVS Nodes
#
# ------------------------------------------------------------------------------
set(NODES_DIR src/nodes)

set(WAVEFORM_DIR ${NODES_DIR}/getting_started/waveform)
file(GLOB WAVEFORM_HDRS "${WAVEFORM_DIR}/*.h")

# ------------------------------------------------------------------------------
#
#   SyDEVS Simulations
#
# ------------------------------------------------------------------------------
set(SIMULATIONS_DIR src/simulations)

set(SETTING_UP_DIR ${SIMULATIONS_DIR}/setting_up)
aux_source_directory(${SETTING_UP_DIR} SETTING_UP_SRCS)
add_executable(setting_up ${SETTING_UP_SRCS})
target_link_libraries(setting_up SyDEVS-static)

set(FIRST_SIMULATION_DIR ${SIMULATIONS_DIR}/first_simulation)
aux_source_directory(${FIRST_SIMULATION_DIR} FIRST_SIMULATION_SRCS)
add_executable(first_simulation ${FIRST_SIMULATION_SRCS} ${WAVEFORM_HDRS})
target_link_libraries(first_simulation SyDEVS-static)

Save the file.

It’s time now to add a SyDEVS node to the project. In the nodes/getting_started/waveform folder, create a text file named square_wave_closed_system.h and save it with the following code.

#pragma once
#ifndef SYDEVS_TUTORIAL_SQUARE_WAVE_CLOSED_SYSTEM_H_
#define SYDEVS_TUTORIAL_SQUARE_WAVE_CLOSED_SYSTEM_H_

#include <sydevs/systems/atomic_node.h>
#include <iostream>

namespace sydevs_tutorial {

using namespace sydevs;
using namespace sydevs::systems;


class square_wave_closed_system : public atomic_node
{
public:
    // Constructor/Destructor:
    square_wave_closed_system(const std::string& node_name, const node_context& external_context);
    virtual ~square_wave_closed_system() = default;

    // Attributes:
    virtual scale time_precision() const { return micro; }

    // Ports:

protected:
    // State Variables:
    duration period_dt;  // duration of one period of the square wave
    float64 duty_cycle;  // fraction (0 to 1) of each period spent in the "on" phase
    int64 phase;         // binary signal phase (0 => off, 1 => on)

    // Event Handlers:
    virtual duration initialization_event();
    virtual duration unplanned_event(duration elapsed_dt);
    virtual duration planned_event(duration elapsed_dt);
    virtual void finalization_event(duration elapsed_dt);
};


inline square_wave_closed_system::square_wave_closed_system(const std::string& node_name, const node_context& external_context)
    : atomic_node(node_name, external_context)
{
}


inline duration square_wave_closed_system::initialization_event()
{
    period_dt = (10_s).fixed_at(time_precision());
    duty_cycle = 0.3;
    phase = 1;
    return 0_s;
}


inline duration square_wave_closed_system::unplanned_event(duration elapsed_dt)
{
    return duration();
}


inline duration square_wave_closed_system::planned_event(duration elapsed_dt)
{
    duration planned_dt;
    if (phase == 0) {
        phase = 1;
        planned_dt = period_dt*duty_cycle;
    }
    else if (phase == 1) {
        phase = 0;
        planned_dt = period_dt*(1.0 - duty_cycle);
    }
    std::cout << "y = " << float64(phase) << std::endl;
    return planned_dt;
}


inline void square_wave_closed_system::finalization_event(duration elapsed_dt)
{
}


}  // namespace

#endif

Let’s make a few observations about this node.

Also in the waveform folder, create a text file named square_wave.h and save it with the code below.

#pragma once
#ifndef SYDEVS_TUTORIAL_SQUARE_WAVE_H_
#define SYDEVS_TUTORIAL_SQUARE_WAVE_H_

#include <nodes/getting_started/waveform/square_wave_closed_system.h>
#include <sydevs/systems/simulation.h>
#include <iostream>

namespace sydevs_tutorial {

using namespace sydevs;
using namespace sydevs::systems;


void simulate_square_wave_closed_system()
{
    try {
        simulation<square_wave_closed_system> sim(1_min, 0, std::cout);
        sim.process_remaining_events();
    }
    catch (const system_node::error& e) {
        std::cout << "SYSTEM NODE ERROR: " << e.what() << std::endl;
    }
    catch (const std::exception& e) {
        std::cout << "OTHER ERROR: " << e.what() << std::endl;
    }
}


}  // namespace

#endif

This file contains a function (simulate_square_wave_closed_system) which constructs a simulation (sim) configured using three arguments. The first argument with value 1_min (1 minute) is the duration of the simulation in simulated time. The second argument with value 0 is an integer that seeds the random number generator common to all SyDEVS nodes. For stochastic simulations, the same seed on the same platform should give the same results. Changing the seed will change all randomly generated numbers. The third argument indicates that output data is sent to std::cout. The simulation is executed by invoking the sim object’s process_remaining_events member function.

Finally, in simulations/first_simulation, save the following code as main.cpp. This main program simply calls the function described above.

#include <nodes/getting_started/waveform/square_wave.h>

int main(int argc, const char* argv[])
{
    sydevs_tutorial::simulate_square_wave_closed_system();
    return 0;
}

Build the project and run the new first_simulation executable. It should produce the following output.

y = 0
y = 1
y = 0
y = 1
y = 0
y = 1
y = 0
y = 1
y = 0
y = 1
y = 0
y = 1

The square wave signal alternatives between off and on.

You’ve now completed Part 2 of the Getting Started tutorial, and have successfully run a simulation developed using SyDEVS. In Part 3, you will modify this example to output more information about the simulation run.

Continue to Part 3