Simulator
Simulators are responsible for the events of the simulation: they perform the simulation by executing the events that are scheduled. Each simulator is paired with a submodel, and different simulators run in parallel. Events that are scheduled within a simulator are called local events and can only operate on the submodel attached to the simulator. If a simulator needs to influence another simulator, it has to use a sync-event to schedule an event on the other simulator.
Dependencies
In order for ERS to be able to schedule sync-events between simulators, it needs to know which simulators can send to which other simulators. To do this, simulators have dependencies which specify from which sender simulators sync-events can be sent to which target simulators.
Ers::ModelContainer modelContainer = Ers::ModelContainer::Create();
Ers::Simulator sim1 = modelContainer.AddSimulator("Simulator 1", Ers::SimulatorType::DiscreteEvent);
Ers::Simulator sim2 = modelContainer.AddSimulator("Simulator 2", Ers::SimulatorType::DiscreteEvent);
// Allow Simulator 1 to schedule sync-events onto Simulator 2
modelContainer.AddSimulatorDependency(sim1, sim2);
ModelContainer modelContainer = ModelContainer.Create();
Simulator sim1 = modelContainer.AddSimulator("Simulator 1", SimulatorType.DiscreteEvent);
Simulator sim2 = modelContainer.AddSimulator("Simulator 2", SimulatorType.DiscreteEvent);
// Allow Simulator 1 to schedule sync-events onto Simulator 2
modelContainer.AddSimulatorDependency(sim1, sim2);
Each dependency is another constraint for ERS to work with, limiting how it can run the model efficiently. However, the benefits of being able to run the simulation in parallel should outweigh the overhead of more complicated scheduling. Therefore, dependencies should only be used when necessary. Depending on the scale and complexity of the simulation, a single simulator and submodel are still very fast and may be enough for the entire simulation.
Bi-directional
When two simulators have a direct dependency set to each other in both directions, they have a "bi-directional dependency."
Ers::ModelContainer modelContainer = Ers::ModelContainer::Create();
Ers::Simulator sim1 = modelContainer.AddSimulator("Simulator 1", Ers::SimulatorType::DiscreteEvent);
Ers::Simulator sim2 = modelContainer.AddSimulator("Simulator 2", Ers::SimulatorType::DiscreteEvent);
// Set a bi-directional dependency between Simulator 1 and 2
modelContainer.AddSimulatorDependency(sim1, sim2);
modelContainer.AddSimulatorDependency(sim2, sim1);
ModelContainer modelContainer = ModelContainer.Create();
Simulator sim1 = modelContainer.AddSimulator("Simulator 1", SimulatorType.DiscreteEvent);
Simulator sim2 = modelContainer.AddSimulator("Simulator 2", SimulatorType.DiscreteEvent);
// Set a bi-directional dependency between Simulator 1 and 2
modelContainer.AddSimulatorDependency(sim1, sim2);
modelContainer.AddSimulatorDependency(sim2, sim1);
Promises
Promises define the minimum time between scheduling an event and executing it on the target simulator. They are a contract between two simulators saying that the sender will not schedule a sync-event before the given promise time. This allows the target simulator to run ahead of the sender simulator, enabling more efficient parallelization. Because of this, the delay of a sync-event can not be lower than the promise it has to adhere to, otherwise it will break causality. For example, if simulator A has a promise of ten set to simulator B, simulator A's sync-event to B needs to have a delay of at least ten.
// Set the promises between simulators
sim1.EnterSubModel();
Ers::EventScheduler::SetPromise(sim2.GetID(), 10);
sim1.ExitSubModel();
// Set the promises between simulators
sim1.EnterSubModel();
EventScheduler.SetPromise(sim2.ID, 10);
sim1.ExitSubModel();
Run together
When two simulators have a bi-directional dependency and their promises are set to zero, they are "running together." In this case they are updating together and are in perfect sync with each other. But events that take place at the same time in each simulator will still be executed in parallel and the execution order stays deterministic.