/// <summary> /// To call before starting a new occurence of the same simulation. /// </summary> public virtual void PrepareForNextOccurrence() { this.remainingDuration = this.Duration.XValue; this.lastProcessTime = this.simulationTimeArrives; //if (this.simulationCrewMembersAssigned == null) this.simulationCrewMembersAssigned = new List<CrewMember>(); //else this.crewMembersAssigned.Clear(); //TODO: Find out if we want to clear the list at this point }
/// <summary> /// Generates the concrete value based on its statistical distribution and a random number, /// and assign it to <see cref="XValue"/>. /// </summary> /// <param name="rand">A random number generator.</param> /// <returns>The concrete value generated, ≥ 0</returns> public SimulationTime NextValue(Random rand) { switch (this.probabilityDistribution) { case ProbabilityDistribution.Exponential: this.xValue = -Math.Log(1.0 - rand.NextDouble()) * mode; //mode == mean == 1/lambda (where lamda is the rate parameter) return(this.xValue); case ProbabilityDistribution.Triangular: //TODO:Optimise (e.g. helper variables) //Try to implement with integers? var u = rand.NextDouble(); var minS = this.min.TotalSeconds; var modeS = this.mode.TotalSeconds; var maxS = this.max.TotalSeconds; if (u <= ((modeS - minS) / (maxS - minS))) { this.xValue = new SimulationTime(TimeUnit.Seconds, minS + Math.Sqrt((u * (maxS - minS) * (modeS - minS)))); } else { this.xValue = new SimulationTime(TimeUnit.Seconds, maxS - Math.Sqrt(((1.0 - u) * (maxS - minS) * (maxS - modeS)))); } this.xValue.Unit = this.Unit; return(this.xValue); case ProbabilityDistribution.Constant: //Nothing to do default: return(this.xValue); } }
/// <summary> /// Reset to the default parameters of the parent Task, except for readonly attributes (e.g. this.id) and lists. /// </summary> public void Reset() { if (this.refTask == null) { this.name = "!Invalid"; this.TaskType = (int)default(StandardTaskType); this.taskInterruptionPolicy = TaskInterruptionPolicies.Undefined; this.phaseInterruptionPolicy = PhaseInterruptionPolicies.Undefined; this.scenarioInterruptionPolicy = ScenarioInterruptionPolicies.Undefined; return; } this.InternalId = refTask.InternalId; this.name = this.refTask.name; this.TaskType = this.refTask.taskType; //this.systemTask = this.refTask.systemTask; this.autoExpandToAllCrewmen = this.refTask.autoExpandToAllCrewmen; this.RelativeDate = this.refTask.relativeDate; this.DateOffset = this.refTask.DateOffset; this.StartDate = this.refTask.StartDate; this.relativeTime = this.refTask.relativeTime; this.DailyHourStart = this.refTask.DailyHourStart; this.DailyHourEnd = this.refTask.DailyHourEnd; this.onHolidays = this.refTask.onHolidays; this.Duration = this.refTask.Duration; this.taskInterruptionPolicy = this.refTask.taskInterruptionPolicy; this.phaseInterruptionPolicy = this.refTask.phaseInterruptionPolicy; this.scenarioInterruptionPolicy = this.refTask.scenarioInterruptionPolicy; this.interruptionErrorPolicy = this.refTask.interruptionErrorPolicy; this.priority = this.refTask.priority; this.numberOfCrewmenNeeded = this.refTask.numberOfCrewmenNeeded; this.Rotation = this.refTask.Rotation; this.description = this.refTask.description; this.duplicatesPolicy = this.refTask.duplicatesPolicy; }
/// <summary> /// Check the different time constraints to tell when the task will next be allowed to be resumed. /// </summary> /// <param name="eventTime">A simulation time</param> /// <param name="allowCurrentTime">Gives the possibility to use the given simulation time</param> /// <returns>A simulation time in the relative future when the task is allowed to run</returns> public SimulationTime NextPossibleResume(SimulationTime eventTime, bool allowCurrentTime = true) { var workStart = eventTime.NextDayTime(this.DailyHourStart, allowCurrentTime); var workEnd = eventTime.NextDayTime(this.DailyHourEnd, allowCurrentTime); if ((workStart < workEnd) || (eventTime >= workEnd)) { eventTime = workStart; //TimeWindow, next day } else if (!allowCurrentTime) { eventTime = eventTime.NextUp(); } if ((!this.onHolidays) && eventTime.IsSunday) { eventTime = eventTime.NextWeekTime(SimulationTime.OneDay, allowCurrentTime: false); //Next monday workStart = eventTime.NextDayTime(this.DailyHourStart); workEnd = eventTime.NextDayTime(this.DailyHourEnd); if ((workStart < workEnd) || (eventTime >= workEnd)) { eventTime = workStart; //TimeWindow, next day } } return(eventTime); }
/// <summary> /// Call <see cref="DismissTask"/> for all tasks currently assigned to the crewman. /// </summary> /// <param name="time">Current simulation time</param> /// <param name="phase">Current phase</param> public void DismissAllTasks(SimulationTime time, Phase phase) { while (this.tasksAssigned.Count > 0) { DismissTask(time, phase, this.tasksAssigned[0]); } }
/// <summary> /// Assign the crewman to a running task. /// This starts by calling <see cref="RefreshStatus"/>, and increase <see cref="CurrentLoad"/>. /// </summary> /// <param name="time">Current simulation time</param> /// <param name="phase">Current phase</param> /// <param name="task">New task</param> public virtual void AssignTask(SimulationTime time, Phase phase, SimulationTask task) { RefreshStatus(time); this.tasksAssigned.Add(task); if (task.IsWork) { currentLoad++; } }
/// <summary> /// To call when the time since last update needs to be discarded. /// Used for instance when a task has to start a bit before than current time and be shortened accordingly. /// </summary> /// <param name="currentTime">Current simulation time.</param> public virtual void DiscardUntilNow(SimulationTime currentTime) { var duration = currentTime - this.lastProcessTime; if (duration.Positive) { this.remainingDuration -= duration; } this.lastProcessTime = currentTime; }
/// <summary> /// Remove a running or completed task from the crewman. /// This starts by calling <see cref="RefreshStatus"/>, and decrease <see cref="CurrentLoad"/>. /// </summary> /// <param name="time">Current simulation time</param> /// <param name="phase">Current phase</param> /// <param name="task">Task dismissed</param> public virtual void DismissTask(SimulationTime time, Phase phase, SimulationTask task) { RefreshStatus(time); this.tasksAssigned.Remove(task); if (task.IsWork) { this.currentLoad--; Debug.Assert(currentLoad >= 0, "Current load must be positive!"); if (this.currentLoad < 0) { this.currentLoad = 0; } } }
/// <summary> /// To call when the task has been active until now, in order to update the statistics of the task (e.g. remaining duration). /// Does not call <see cref="Crewman.RefreshStatus"/> by default. /// </summary> /// <param name="currentTime">Current simulation time.</param> /// <param name="phase">Phase during which the process occurs.</param> /// <returns>A positive duration if the task was processed, <see cref="SimulationTime.Zero"/> otherwise.</returns> public virtual SimulationTime ProcessUntilNow(SimulationTime currentTime, Phase phase) { var previousProcessTime = this.lastProcessTime; this.lastProcessTime = currentTime; if (this.simulationCrewmenAssigned.Count >= this.numberOfCrewmenNeeded) { var duration = currentTime - previousProcessTime; if (duration.Positive) { this.remainingDuration -= duration; Debug.Assert((this.taskType == (int)StandardTaskType.InternalWait) || Allowed(phase), "A task must not run in phases where it is not allowed!"); Debug.Assert(duration <= currentTime - phase.simulationTimeBegin, "A task cannot last longer than its phase!"); return(duration); } } return(SimulationTime.Zero); }
/// <summary> /// Refresh all status parameters of the crewman such as cumulated work time. /// This is called automatically by <see cref="AssignTask"/>, <see cref="DismissTask"/>, /// at at the end of each phase transition by <see cref="Simulator"/>. /// Furthermore, this should be called by implementations of <see cref="SimManning.Domain.DomainDispatcher"/> /// before deciding which crewmen should take a job. /// </summary> /// <remarks>Implementations of domains should override this function to include their domain-specific parameters</remarks> /// <param name="time">Current simulation time</param> /// <returns>true if a refresh was needed, false otherwise</returns> public virtual bool RefreshStatus(SimulationTime time) { //In the base class, we only have cumulatedWorkTime Debug.Assert(this.lastRefreshTime <= time, "Simulation cannot go back in time!"); if (time == this.lastRefreshTime) { return(false); } //Debug.WriteLine("?\t{0}\tRefreshStatus\t{1}", time, this); if (this.currentLoad > 0) { //The crewman is currently working var offset = time - this.lastRefreshTime; if (offset.Positive) { this.cumulatedWorkTime += offset; } } this.lastRefreshTime = time; return(true); }
public void Validate() { if ((this.Unit == TimeUnit.Undefined) || (this.mode < SimulationTime.Zero)) { this.mode = SimulationTime.Zero; } if (this.min > this.mode) { this.min = this.mode; } else if (this.min < SimulationTime.Zero) { this.min = SimulationTime.Zero; } if ((this.max != SimulationTime.Zero) && (this.max < this.mode)) { this.max = this.mode; } }
public TimeDistribution(TimeUnit timeUnit, SimulationTime min, SimulationTime mode, SimulationTime max) { this.min = min; this.mode = mode; this.max = max; if (this.mode <= SimulationTime.Zero) { this.probabilityDistribution = ProbabilityDistribution.Constant; this.min = this.max = this.mode = SimulationTime.Zero; } else if (this.max <= SimulationTime.Zero) { this.probabilityDistribution = ProbabilityDistribution.Exponential; this.min = this.max = SimulationTime.Zero; } else { if (this.min > this.mode) { this.min = this.mode; } else if (this.min < SimulationTime.Zero) { this.min = SimulationTime.Zero; } if (this.max < this.mode) { this.max = this.mode; } if ((this.min < this.mode) || (this.mode < this.max)) { this.probabilityDistribution = ProbabilityDistribution.Triangular; } else { this.probabilityDistribution = ProbabilityDistribution.Constant; } } this.xValue = this.mode; this.Unit = timeUnit; }
public TimeDistribution(TimeUnit timeUnit, SimulationTime constantValue) : this(timeUnit, constantValue, constantValue, constantValue) { }
public TimeDistribution(SimulationTime min, SimulationTime mode, SimulationTime max) : this(mode.Unit, min, mode, max) { }
/// <summary> /// Tells if the task is allowed to run at this time of the day. /// </summary> /// <param name="eventTime">A date/time; only the time of the day will be used.</param> /// <returns>true if the task is allowed to run at this time of the day, false otherwise.</returns> public bool IsAllowedTime(SimulationTime eventTime) { return(eventTime.InDayTimeInterval(this.DailyHourStart, this.DailyHourEnd) && (this.onHolidays || (!eventTime.IsSunday) || (!eventTime.NextDown().IsSunday))); //Case of Sunday at 00:00 }
/// <summary> /// To be called before each replication to reset some parameters. /// Automatically called by <see cref="SimulationDataSet.PrepareForNextReplication"/> /// </summary> protected internal virtual void PrepareForNextReplication() { this.lastRefreshTime = SimulationTime.MinValue; this.cumulatedWorkTime = SimulationTime.Zero; this.tasksAssigned.Clear(); }
public TimeDistribution(SimulationTime constantValue) : this(constantValue.Unit, constantValue, constantValue, constantValue) { }
public void Validate() { #pragma warning disable 618 //Disable warning for obsolete "DoNotInterrupt" if (this.phaseInterruptionPolicy == PhaseInterruptionPolicies.DoNotInterrupt) #pragma warning restore 618 { //Back compatibility this.taskInterruptionPolicy = TaskInterruptionPolicies.ContinueOrResumeWithError; this.phaseInterruptionPolicy = PhaseInterruptionPolicies.ContinueOrDropWithError; } if (this.taskType.IsSubCodeOf(StandardTaskType.ExternalCondition) || this.taskType.IsSubCodeOf(StandardTaskType.CriticalEvents)) { this.taskInterruptionPolicy = TaskInterruptionPolicies.DropWithError; this.phaseInterruptionPolicy = PhaseInterruptionPolicies.ResumeOrDropWithError; this.scenarioInterruptionPolicy = ScenarioInterruptionPolicies.DropWithoutError; //this.relativeTime = Task.RelativeTimeType.TimeWindow; //this.dailyHourStart = TimeSpan.Zero; //this.dailyHourEnd = TimeSpan.Zero; //this.onHolidays = true; this.autoExpandToAllCrewmen = false; this.numberOfCrewmenNeeded = 0; this.Rotation = SimulationTime.Zero; this.duplicatesPolicy = TaskDuplicatesPolicy.MergeDuplicates; this.masterTasks.Clear(); this.parallelTasks.Clear(); this.priority = 700; } else { this.slaveTasks.Clear(); //Only external conditions can have slaves if (this.relativeDate == RelativeDateType.TriggeredByAnEvent) { this.StartDate = TimeDistribution.Zero; this.Duration = new TimeDistribution(SimulationTime.ArbitraryLargeDuration); this.duplicatesPolicy = TaskDuplicatesPolicy.MergeDuplicates; this.parallelTasks.Clear(); this.phaseTypes.Clear(); } else { this.masterTasks.Clear(); } if (this.phaseInterruptionPolicy == PhaseInterruptionPolicies.WholePhase) { this.DailyHourStart = SimulationTime.Zero; this.DailyHourEnd = SimulationTime.Zero; this.RelativeDate = RelativeDateType.RelativeStartFromStartOfPhase; this.StartDate = TimeDistribution.Zero; this.Duration = new TimeDistribution(SimulationTime.ArbitraryLargeDuration); this.parallelTasks.Clear(); } else if ((this.phaseInterruptionPolicy == PhaseInterruptionPolicies.Obligatory) && (this.relativeDate != RelativeDateType.RelativeStartFromStartOfPhase) && (this.relativeDate != RelativeDateType.RelativeStartFromEndOfPhase) && (this.relativeDate != RelativeDateType.RelativeStopFromEndOfPhase)) { this.phaseInterruptionPolicy = PhaseInterruptionPolicies.DropWithError; } switch (this.relativeDate) { case RelativeDateType.RelativeStopFromEndOfPhase: case RelativeDateType.RelativeStartFromStartOfPhase: case RelativeDateType.RelativeStartFromEndOfPhase: case RelativeDateType.RelativeStartFromPreviousStart: this.DateOffset = default(TimeDistribution); break; } if (((this.relativeDate == RelativeDateType.AbsoluteStartMonthDay) || (this.relativeDate == RelativeDateType.AbsoluteStartWeekDay))) { this.StartDate.Unit = TimeUnit.Days; } if (this.autoExpandToAllCrewmen) { this.numberOfCrewmenNeeded = 1; this.Rotation = SimulationTime.Zero; } } this.Duration.Validate(); this.StartDate.Validate(); }
/// <summary> /// To call when the task has been waiting until now, in order to update the statistics of the task. /// </summary> /// <param name="currentTime">Current simulation time.</param> public virtual void SleepUntilNow(SimulationTime currentTime) { this.lastProcessTime = currentTime; }