Microscopic Traffic Simulator
Simulation.cs
Go to the documentation of this file.
2 using System;
3 using System.Collections.Generic;
4 using System.Diagnostics;
5 using System.Threading;
6 
7 namespace Microscopic_Traffic_Simulator___Model.SimulationControl
8 {
12  public class Simulation : IDisposable
13  {
17  private Random random;
18 
22  private Timer timer;
23 
28  private int validToken = 0;
29 
35  private object eventsLock = new object();
36 
40  private DateTime dateTimeOfLastAction;
41 
45  private TimeSpan currentModelTime;
49  public TimeSpan CurrentModelTime { get { return currentModelTime; } }
50 
54  private TimeSpan modelTimeToPause = TimeSpan.MaxValue;
58  public TimeSpan ModelTimeToPause
59  {
60  get { return modelTimeToPause; }
61  set { modelTimeToPause = value; }
62  }
63 
67  public event EventHandler ModelTimeChanged;
68 
72  public event EventHandler SimulationPaused;
73 
77  public event EventHandler SingleSimulationActionPerformed;
78 
82  public event EventHandler<SimulationSpeedChangeEventArgs> SimulationSpeedChanged;
83 
87  public event EventHandler IsMaxSimulationSpeedChange;
88 
92  private SimulationState simulationState = SimulationState.NotRunning;
96  public SimulationState SimulationState { get { return simulationState; } }
97 
101  private int usedSeed;
105  public int UsedSeed { get { return usedSeed; } }
106 
110  private const double MinimumSimulationSpeed = 0.001;
114  private const double MaximumSimulationSpeed = 10000.0;
118  private double simulationSpeed = 1.0;
122  public double SimulationSpeed
123  {
124  get { return simulationSpeed; }
125  set
126  {
127  if (value < MinimumSimulationSpeed || value > MaximumSimulationSpeed)
128  {
129  return;
130  }
131  double oldSimulationSpeed = simulationSpeed;
132  lock (eventsLock)
133  {
134  if (simulationState == SimulationState.Running)
135  {
136  PauseTimer();
137  }
138  simulationSpeed = value;
139  if (simulationState == SimulationState.Running)
140  {
141  StartOrResumeTimer();
142  }
143  }
144  if (oldSimulationSpeed != simulationSpeed)
145  OnSimulationSpeedChange(oldSimulationSpeed, simulationSpeed);
146  }
147  }
148 
152  private bool isMaxSimulationSpeed;
156  public bool IsMaxSimulationSpeed
157  {
158  get { return isMaxSimulationSpeed; }
159  set
160  {
161  if (isMaxSimulationSpeed != value)
162  {
163  isMaxSimulationSpeed = value;
164  if (isMaxSimulationSpeed)
165  {
166  if (simulationState == SimulationState.Running)
167  {
168  lock (eventsLock)
169  {
170  validToken++;
171  }
172  //needed to test the simulation state again because scheduled pause might be performed
173  //just before the locked section right above. Then do not resume timer.
174  if (simulationState == SimulationState.Running)
175  {
176  StartOrResumeTimer();
177  }
178  }
179  }
180  OnIsMaxSimulationSpeedChange();
181  }
182  }
183  }
184 
188  private bool IsModelTimeToPauseReached
189  {
190  get
191  {
192  if (simulationActions.Count == 0)
193  return false;
194  else
195  return simulationActions.Top.Key.Time >= modelTimeToPause;
196  }
197  }
198 
204 
208  private List<ISimulationEventsGenerator> simulationActionGenerators =
209  new List<ISimulationEventsGenerator>();
210 
216  internal Simulation(List<ISimulationEventsGenerator> simulationEventGenerators)
217  {
218  this.simulationActionGenerators = simulationEventGenerators;
219  }
220 
225  private void PushNewActionToCalendarForCurrentActionGenerator(
226  ISimulationEventsGenerator simulationEventsGenerator)
227  {
228  TimeSpan timeToNextAction = simulationEventsGenerator.GetTimeToNextAction(random);
229  if (timeToNextAction != TimeSpan.MaxValue)
230  {
231  simulationActions.Push(new SimulationEventGeneratorKey(currentModelTime + timeToNextAction,
232  simulationEventsGenerator.Priority), simulationEventsGenerator);
233  }
234  }
235 
242  private void InitializeSimulationRun(int? seed)
243  {
244  Debug.Assert(simulationActions.Count == 0);
245  Debug.Assert(currentModelTime == TimeSpan.Zero);
246  Debug.Assert(simulationState == SimulationState.NotRunning);
247  foreach (ISimulationEventsGenerator i in simulationActionGenerators)
248  PushNewActionToCalendarForCurrentActionGenerator(i);
249  if (seed == null)
250  usedSeed = (int)(DateTime.Now.Ticks & 0x0000FFFF);
251  else
252  usedSeed = seed.Value;
253  random = new Random(usedSeed);
254  }
255 
260  internal void Run(int? seed = null)
261  {
262  Debug.Assert(simulationState == SimulationState.NotRunning ||
263  simulationState == SimulationState.Paused);
264  if (simulationState == SimulationState.NotRunning)
265  {
266  InitializeSimulationRun(seed);
267  }
268  simulationState = SimulationState.Running;
269  ResetModelTimeToPauseIfReached();
270  StartOrResumeTimer();
271  }
272 
278  internal void StepForward(int? seed = null)
279  {
280  Debug.Assert(simulationState == SimulationState.NotRunning ||
281  simulationState == SimulationState.Paused);
282  if (simulationState == SimulationState.NotRunning)
283  {
284  InitializeSimulationRun(seed);
285  simulationState = SimulationState.Paused;
286  }
287  ResetModelTimeToPauseIfReached();
288  RunStep();
289  }
290 
294  internal void Pause()
295  {
296  lock (eventsLock)
297  {
298  if (simulationState == SimulationState.Paused ||
299  simulationState == SimulationState.NotRunning)
300  {
301  Debug.Assert(true,
302  "Possible simultaneous call of Pause command and scheduled pause or bug in code.");
303  return;
304  }
305  simulationState = SimulationState.Paused;
306  PauseTimer();
307  }
308  }
309 
313  internal void Stop()
314  {
315  lock (eventsLock)
316  {
317  if (simulationState == SimulationState.NotRunning)
318  {
319  Debug.Assert(true,
320  "Possible simultaneous call of Stop command and scheduled pause or bug in code.");
321  return;
322  }
323  simulationState = SimulationState.NotRunning;
324  StopTimer();
325  simulationActions.Clear();
326  ResetModelTimeToPause();
327  }
328  }
329 
335  private void StartOrResumeTimer()
336  {
337  TimeSpan timeToBeSetInTimer = TimeSpan.Zero;
338  if (!isMaxSimulationSpeed && simulationActions.Count > 0)
339  {
340  dateTimeOfLastAction = DateTime.Now;
341  timeToBeSetInTimer = (simulationActions.Top.Key.Time - currentModelTime).Divide(simulationSpeed);
342  if (timeToBeSetInTimer < TimeSpan.Zero)
343  timeToBeSetInTimer = TimeSpan.Zero;
344  }
345  timer = new Timer(Tick, validToken, timeToBeSetInTimer, Timeout.InfiniteTimeSpan);
346  }
347 
353  private ISimulationEventsGenerator GetGeneratorToPerformAnActionAndStoreNewOne()
354  {
355  if (simulationActions.Count == 0)
356  return null;
357  var currentEvent = simulationActions.Pop();
358  currentModelTime = currentEvent.Key.Time;
359  PushNewActionToCalendarForCurrentActionGenerator(currentEvent.Value);
360  return currentEvent.Value;
361  }
362 
366  private void RunStep()
367  {
368  new Thread(() =>
369  {
370  lock (eventsLock) //prevent from potential simultaneous executing of Run or Stop command.
371  {
372  var currentActionGenerator = GetGeneratorToPerformAnActionAndStoreNewOne();
373  if (currentActionGenerator == null)
374  return;
375  currentActionGenerator.PerformAction(random);
376  currentModelTime = simulationActions.Top.Key.Time;
377  OnModelTimeChanged();
378  OnSingleSimulationActionPerformed();
379  }
380  }).Start();
381  }
382 
389  private void Tick(object state)
390  {
391  lock (eventsLock)
392  {
393  if ((int)state != validToken || simulationActions.Count == 0)
394  {
395  return;
396  }
397  if (IsModelTimeToPauseReached || simulationActions.Top.Value.IsPauseScheduled)
398  {
399  Pause();
400  OnSimulationPaused();
401  return;
402  }
403  var currentActionGenerator = GetGeneratorToPerformAnActionAndStoreNewOne();
404  StartOrResumeTimer();
405  OnModelTimeChanged();
406  currentActionGenerator.PerformAction(random);
407  }
408  }
409 
414  private void ResetModelTimeToPauseIfReached()
415  {
416  if (IsModelTimeToPauseReached)
417  {
418  ResetModelTimeToPause();
419  }
420  }
421 
425  private void ResetModelTimeToPause()
426  {
427  modelTimeToPause = TimeSpan.MaxValue;
428  }
429 
433  private void UpdateTimes()
434  {
435  if ((isMaxSimulationSpeed || IsModelTimeToPauseReached) && simulationActions.Count > 0)
436  currentModelTime = simulationActions.Top.Key.Time;
437  else
438  currentModelTime += (DateTime.Now - dateTimeOfLastAction).Multiply(simulationSpeed);
439  }
440 
444  private void PauseTimer()
445  {
446  UpdateTimes();
447  OnModelTimeChanged();
448  validToken++;
449  }
450 
454  private void StopTimer()
455  {
456  currentModelTime = TimeSpan.Zero;
457  OnModelTimeChanged();
458  validToken++;
459  }
460 
464  private void OnModelTimeChanged()
465  {
466  if (ModelTimeChanged != null)
467  ModelTimeChanged(this, EventArgs.Empty);
468  }
469 
474  private void OnSimulationPaused()
475  {
476  if (SimulationPaused != null)
477  SimulationPaused(this, EventArgs.Empty);
478  }
479 
483  private void OnSingleSimulationActionPerformed()
484  {
485  if (SingleSimulationActionPerformed != null)
486  SingleSimulationActionPerformed(this, EventArgs.Empty);
487  }
488 
494  private void OnSimulationSpeedChange(double oldSimulationSpeed, double newSimulationSpeed)
495  {
496  if (SimulationSpeedChanged != null)
497  {
498  SimulationSpeedChanged(this, new SimulationSpeedChangeEventArgs()
499  {
500  OldSimulationSpeed = oldSimulationSpeed,
501  NewSimulationSpeed = newSimulationSpeed
502  });
503  }
504  }
505 
509  private void OnIsMaxSimulationSpeedChange()
510  {
511  if (IsMaxSimulationSpeedChange != null)
512  IsMaxSimulationSpeedChange(this, EventArgs.Empty);
513  }
514 
519  protected virtual void Dispose(bool disposing)
520  {
521  if (disposing)
522  {
523  if (timer != null)
524  {
525  timer.Dispose();
526  timer = null;
527  }
528  }
529  }
530 
534  public void Dispose()
535  {
536  Dispose(true);
537  GC.SuppressFinalize(this);
538  }
539  }
540 }
EventHandler ModelTimeChanged
An event informing about changing of model time.
Definition: Simulation.cs:67
EventHandler< SimulationSpeedChangeEventArgs > SimulationSpeedChanged
Event of simulation speed change.
Definition: Simulation.cs:82
TimeSpan GetTimeToNextAction(Random random)
Method for getting time to next action from the implementing class
EventHandler IsMaxSimulationSpeedChange
Event of activation or deactivation of maximum simulation speed.
Definition: Simulation.cs:87
EventHandler SimulationPaused
An event informing about applying of pause by the simulation control.
Definition: Simulation.cs:72
int Priority
Priority determining the rank of the events which have the same time.
Heap data structure where values of items are ordered by their keys.
Definition: Heap.cs:11
void Dispose()
Disposes cellular topology resources.
Definition: Simulation.cs:534
EventHandler SingleSimulationActionPerformed
An event informing about finishing of simulation action.
Definition: Simulation.cs:77
Class controlling performing simulation actions by simulation calendar.
Definition: Simulation.cs:12
Every class which performs some repeating action should implement this interface
virtual void Dispose(bool disposing)
Dispose disposable fields.
Definition: Simulation.cs:519