Multi-formalism
ERS supports multi-formalism simulations, meaning you can combine different "types" of simulators within a single model. This allows you to choose the most appropriate simulation paradigm for each part of your system and have them work together seamlessly.
Simulator types
ERS provides four distinct simulator types, each optimized for different modeling scenarios:
Discrete-event
Discrete-event simulation is an event-driven paradigm where the simulation jumps from one event to the next. Time only advances when events occur, making it highly efficient for systems with sporadic activity.
Characteristics:
- Events are scheduled at specific simulation times.
- Time advances only to when events execute.
- No regular time step updates.
- Ideal for event-driven systems.
Best suited for:
- Manufacturing processes with distinct events (arrivals, departures, breakdowns).
- Queuing systems.
- Logistics and supply chain models.
- Systems where activities happen at specific moments in time.
Example use case: a warehouse receiving shipments at irregular intervals, where you only need to simulate when trucks arrive or depart.
struct TruckArrivalEvent
{
void OnEvent()
{
// Handle truck arrival at time 10
}
}
Ers::ModelContainer modelContainer = Ers::ModelContainer::Create();
Ers::Simulator sim1 = modelContainer.AddSimulator("Warehouse", Ers::SimulatorType::DiscreteEvent);
// Schedule discrete events
sim1.EnterSubModel();
Ers::EventScheduler::ScheduleLocalEvent(0, 10, TruckArrivalEvent{});
sim1.ExitSubModel();
struct TruckArrivalEvent : ILocalEvent<TruckArrivalEvent>
{
public void OnEvent()
{
// Handle truck arrival at time 10
}
}
ModelContainer modelContainer = ModelContainer.Create();
Simulator sim1 = modelContainer.AddSimulator("Warehouse", SimulatorType.DiscreteEvent);
// Schedule discrete events
sim1.EnterSubModel();
EventScheduler.ScheduleLocalEvent(0, 10, new TruckArrivalEvent());
sim1.ExitSubModel();
Agent-based
Agent-based simulation describes individual entities (agents) that follow rules and interact with each other and their environment. The simulation advances in steps of fixed intervals at which agents update their state.
Characteristics:
- Fixed time step progression.
OnUpdateandOnLateUpdatecallbacks are invoked each time step.- Each agent has autonomous behavior.
- Emergent system behavior from individual interactions.
Best suited for:
- Warehouse operations with autonomous robots or vehicles.
- Pedestrian dynamics and crowd simulation.
- Swarm intelligence.
- Systems where individual behavior patterns matter.
Ers::ModelContainer modelContainer = Ers::ModelContainer::Create();
Ers::Simulator sim2 = modelContainer.AddSimulator("RetailStore", Ers::SimulatorType::AgentBased);
sim2.TimeStep = 1; // Advance 1 time unit per step
// Script behaviors with OnUpdate will be called each time step
ModelContainer modelContainer = ModelContainer.Create();
Simulator sim2 = modelContainer.AddSimulator("RetailStore", SimulatorType.AgentBased);
sim2.TimeStep = 1; // Advance 1 time unit per step
// Script behaviors with OnUpdate will be called each time step
Continuous
Continuous simulation is designed for systems that change continuously over time, typically modeled using differential equations or continuous state changes.
While it has a configured TimeStep like agent-based simulations, its execution model is fundamentally different.
Characteristics:
- Based on discrete-event execution (not regular time step updates).
- Has a
TimeStepproperty that defines the observation interval. OnUpdateandOnLateUpdateare called only at specific times (see below).- Designed for continuous state evolution.
- Can integrate continuous dynamics.
Best suited for:
- Physical systems (fluid dynamics, thermal systems).
- Chemical processes.
- Continuous production processes.
- Systems with smooth, continuous state changes.
Example use case: modeling a chemical reactor where temperature, pressure, and concentration change continuously based on reaction kinetics.
Ers::ModelContainer modelContainer = Ers::ModelContainer::Create();
Ers::Simulator sim3 = modelContainer.AddSimulator("ChemicalReactor", Ers::SimulatorType::Continuous);
sim3.TimeStep = 1; // Small time step for accurate integration
// Update functions will integrate continuous changes
ModelContainer modelContainer = ModelContainer.Create();
Simulator sim3 = modelContainer.AddSimulator("ChemicalReactor", SimulatorType.Continuous);
sim3.TimeStep = 1; // Small time step for accurate integration
// Update functions will integrate continuous changes
Emulation
Emulation simulation is designed to run in real-time, synchronizing the simulation clock with wall-clock time. This is useful when the simulation needs to interact with real hardware or external systems.
Characteristics:
- Synchronizes with real-world time.
- Can interface with hardware and external systems.
- Real-time constraints apply.
- Used for hardware-in-the-loop testing.
Best suited for:
- Real-world systems
- Hardware validation
Example use case: testing a factory control system where the simulation interacts with actual PLCs and sensors in real-time.
Ers::ModelContainer modelContainer = Ers::ModelContainer::Create();
Ers::Simulator sim4 = modelContainer.AddSimulator("ControlSystem", Ers::SimulatorType::Emulation);
// Simulation will run in real-time
ModelContainer modelContainer = ModelContainer.Create();
Simulator sim4 = modelContainer.AddSimulator("ControlSystem", SimulatorType.Emulation);
// Simulation will run in real-time
Combining different simulator types
One of ERS's most powerful features is the ability to combine different simulator types in a single model. Simulators can be connected through dependencies and communicate via sync-events.
Example: multi-formalism factory model
Consider a factory model that combines multiple formalisms:
graph LR
A[Discrete-event<br/>Assembly line] --> B[Agent-based<br/>Transport robots]
B --> C[Continuous<br/>Chemical bath]
- Discrete-event: Models the assembly line where parts are assembled and processed at discrete stations.
- Agent-based: Models autonomous transport robots that move parts between stations.
- Continuous: Models a chemical treatment bath where parts undergo continuous processing (heating, coating, etc.).
Ers::ModelContainer model = Ers::ModelContainer::Create();
// Create simulators with different types
Ers::Simulator* assembly = model.AddSimulator("AssemblyLine", Ers::SimulatorType::DiscreteEvent);
Ers::Simulator* robots = model.AddSimulator("TransportRobots", Ers::SimulatorType::AgentBased);
robots->TimeStep = 1;
Ers::Simulator* chemBath = model.AddSimulator("ChemicalBath", Ers::SimulatorType::Continuous);
chemBath->TimeStep = 2;
// Set up dependencies (who can send to whom)
model.AddSimulatorDependency(*assembly, *robots);
model.AddSimulatorDependency(*robots, *chemBath);
// Set promises (minimum delay between sync-events)
assembly->EnterSubModel();
Ers::EventScheduler::SetPromise(robots->GetID(), 0);
assembly->ExitSubModel();
robots->EnterSubModel();
Ers::EventScheduler::SetPromise(chemBath->GetID(), 2);
robots->ExitSubModel();
model.Start();
ModelContainer model = ModelContainer.Create();
// Create simulators with different types
Simulator assembly = model.AddSimulator("AssemblyLine", SimulatorType.DiscreteEvent);
Simulator robots = model.AddSimulator("TransportRobots", SimulatorType.AgentBased);
robots.TimeStep = 1;
Simulator chemBath = model.AddSimulator("ChemicalBath", SimulatorType.Continuous);
chemBath.TimeStep = 2;
// Set up dependencies (who can send to whom)
model.AddSimulatorDependency(assembly, robots);
model.AddSimulatorDependency(robots, chemBath);
// Set promises (minimum delay between sync-events)
assembly.EnterSubModel();
EventScheduler.SetPromise(robots.ID, 0);
assembly.ExitSubModel();
robots.EnterSubModel();
EventScheduler.SetPromise(chemBath.ID, 2);
robots.ExitSubModel();
model.Start();
Time step vs event-driven execution
Understanding how different simulator types handle time is crucial for effective multi-formalism modeling: Important: When a simulator receives a sync-event, it processes that event at the scheduled time regardless of its type.
Event-driven (Discrete-event, Emulation)
- Time advances to the next scheduled event.
OnUpdateandOnLateUpdateare not automatically called.- More efficient for sparse event patterns.
- Events must be explicitly scheduled.
Time step based (Agent-based)
- Time advances in fixed increments (controlled by
TimeStep). OnUpdateandOnLateUpdateare automatically called each step.- Recurring update events are automatically scheduled.
Event-driven (Continuous)
Unlike all other simulator types, continuous simulators only update when necessary.
OnUpdate and OnLateUpdate are called in a continuous simulator when:
- Receiving a sync-event: Updates to match the event time before processing it.
- Falling behind other simulators: Keeps the continuous simulation synchronized with the rest of the model.
- Reaching the end time: Final update to complete the simulation.
This approach is very efficient because continuous processes don't need constant observation - they only need to update when interacting with other parts of the system or when checking the final state.
Time step and model precision
The TimeStep property on agent-based and continuous simulators is based on the model precision and must always be an integer value.
For details on how model precision works, see the model precision section in the model container documentation.
- The actual time represented by a TimeStep =
TimeStep * ModelPrecision.
Example: If ModelPrecision is 1,000,000 (treating 1.0 as 1 second):
TimeStep = 1000000→ 1 second per step.TimeStep = 100000→ 0.1 seconds per step.TimeStep = 1000→ 0.001 seconds (1 millisecond) per step.
Communication between simulators
Simulators communicate through sync-events, which transfer data and entities between different simulators.
Sync-events work the same way regardless of the formalism used by the source and target simulators. The only difference is the internal execution model of each simulator, but the sync-event mechanism itself remains consistent. This means you can freely send sync-events between any combination of discrete-event, agent-based, continuous, and emulation simulators.
For details on sync-events, dependencies, and promises, see:
- Sync-events: How to define and use sync-events.
- Dependencies: How to declare which simulators can communicate.
- Promises: How to set minimum delays for parallel execution.