} // end of Event #endregion //-------------------------------------------------------------------------------------------------- // State Change //-------------------------------------------------------------------------------------------------- #region Trigger /// <summary> /// Acutal state change of arrival. If patient arrives from waiting list path is set, otherwise /// next action is taken. /// </summary> /// <param name="time">Time the patient arrives</param> /// <param name="simEngine">SimEngine responsible for simulation execution</param> protected override void StateChange(DateTime time, ISimulationEngine simEngine) { //-------------------------------------------------------------------------------------------------- // In case Patient is returning from special service facility the path // has already been set and needs update to next action //-------------------------------------------------------------------------------------------------- if (Patient.OutpatientTreatmentPath != null) { Patient.OutpatientTreatmentPath.UpdateNextAction(); } else { Patient.OutpatientTreatmentPath = InputData.CreateOutpatientTreatmentPath(Patient, Admission, ScheduledTime, false); ParentControlUnit.AddEntity(Patient); } // end if if (Patient.OutpatientTreatmentPath.TakeNextAction(simEngine, this, time, ParentControlUnit)) { if (Patient.OccupiedFacility == null || Patient.OccupiedFacility.ParentDepartmentControl != ParentControlUnit) { SequentialEvents.Add(Patient.StartWaitingActivity(((ControlUnitOutpatient)ParentControlUnit).WaitingAreaPatientForNextActionType(Patient.OutpatientTreatmentPath.GetCurrentActionType()))); } else { ActivityWaitInFacility waitInFacility = new ActivityWaitInFacility(ParentControlUnit, Patient, Patient.OccupiedFacility); SequentialEvents.Add(waitInFacility.StartEvent); } // end if } // end if } // end of Trigger
} // end of Event #endregion //-------------------------------------------------------------------------------------------------- // Statechange //-------------------------------------------------------------------------------------------------- #region Trigger /// <summary> /// Overriden state change of the event. If the patient's path indicates a inpatient or outpatient /// admission the corresponding request is sent up the control tree. /// </summary> /// <param name="time">Time the patient leaves</param> /// <param name="simEngine">SimEngine responsible for simulation execution</param> protected override void StateChange(DateTime time, ISimulationEngine simEngine) { ParentControlUnit.RemoveEntity(Patient); Patient.CorrespondingDoctor = null; if (Patient.OutpatientTreatmentPath.InpatientAdmission != null) { RequestMoveInpatient reqMoveInpatient = new RequestMoveInpatient(Patient.ToArray(), time, Patient, ParentControlUnit, Patient.OutpatientTreatmentPath.InpatientAdmission); ParentControlUnit.DelegateOutBox.Add(reqMoveInpatient); } // end if if (Patient.OutpatientTreatmentPath.OutpatientAdmission != null) { RequestMoveOutpatient reqMoveOutPatient = new RequestMoveOutpatient(Patient.ToArray(), time, Patient, ParentControlUnit, Patient.OutpatientTreatmentPath.OutpatientAdmission); ParentControlUnit.DelegateOutBox.Add(reqMoveOutPatient); } // end if Patient.OutpatientTreatmentPath = null; } // end of Trigger
} // end of Initialize #endregion //-------------------------------------------------------------------------------------------------- // Rule Handling //-------------------------------------------------------------------------------------------------- #region PerformCustomRules /// <summary> /// Dispatches slot requests by booking in the booking model, further, now show probabilities /// and arrival deviations of patients are calculated. Corresponding events for arrival are scheduled. /// </summary> /// <param name="startTime">Time rules are executed</param> /// <param name="simEngine">SimEngine responsible for simulation execution</param> /// <returns>False</returns> protected override bool PerformCustomRules(DateTime time, ISimulationEngine simEngine) { if (RAEL.Count == 0) { return(false); } if (!WaitingListSchedule.ReadyForDispatch) { return(false); } while (RAEL.Count > 0) { RequestOutpatientWaitingListPatientToAssignSlot reqToDisptatch = (RequestOutpatientWaitingListPatientToAssignSlot)RAEL.First(); DateTime earliestTime = time; earliestTime = reqToDisptatch.EarliestTime; Slot slot = WaitingListSchedule.GetEarliestSlotTime(time, earliestTime, reqToDisptatch.Patient, reqToDisptatch.AdmissionType); WaitingListSchedule.BookSlot(slot, reqToDisptatch.AdmissionType); reqToDisptatch.Patient.StopCurrentActivities(time, simEngine); ParentControlUnit.RemoveRequest(reqToDisptatch); RemoveRequest(reqToDisptatch); if (InputData.NoShowForAppointment(reqToDisptatch.Patient, reqToDisptatch.AdmissionType, slot, time)) { continue; } DateTime arrivalTime = slot.StartTime + InputData.PatientArrivalDeviationFromSlotTime(reqToDisptatch.Patient, reqToDisptatch.AdmissionType); arrivalTime = new DateTime(Math.Max(time.Ticks, arrivalTime.Ticks)); EventOutpatientArrival arrival = new EventOutpatientArrival(ParentControlUnit, reqToDisptatch.Patient, slot.StartTime, InputData, reqToDisptatch.AdmissionType); simEngine.AddScheduledEvent(arrival, arrivalTime); Event patientWait = reqToDisptatch.Patient.StartWaitingActivity(null); patientWait.Trigger(time, simEngine); } // end while WaitingListSchedule.ReadyForDispatch = false; return(false); } // end of PerformCustomRules
} // end of AdmissionType #endregion //-------------------------------------------------------------------------------------------------- // Events //-------------------------------------------------------------------------------------------------- #region TriggerStartEvent /// <summary> /// State changes of the activities start event. Request for slot assigning is filed /// </summary> /// <param name="time"> Time of activity start</param> /// <param name="simEngine"> SimEngine the handles the activity triggering</param> override public void StateChangeStartEvent(DateTime time, ISimulationEngine simEngine) { RequestOutpatientWaitingListPatientToAssignSlot requestAssign = new RequestOutpatientWaitingListPatientToAssignSlot(Patient, time, AdmissionType, EarliestTime, LatestTime); ParentControlUnit.AddRequest(requestAssign); } // end of TriggerStartEvent
} // end of Event #endregion //-------------------------------------------------------------------------------------------------- // State Change //-------------------------------------------------------------------------------------------------- #region StateChange /// <summary> /// Overriden state change of the event. Request for service is made, next client arrival is scheduled /// </summary> /// <param name="time">Time the client arrives</param> /// <param name="simEngine">SimEngine responsible for simulation execution</param> protected override void StateChange(DateTime time, ISimulationEngine simEngine) { // next arrival is scheduled EntityClient nextClient = new EntityClient(); EventClientArrival nextClientArrival = new EventClientArrival(ParentControlUnit, nextClient); double arrivalTimeMinutes = ((SimulationModelQueuing)ParentControlUnit.ParentSimulationModel).ArrivalTime; simEngine.AddScheduledEvent(nextClientArrival, time + TimeSpan.FromMinutes(Distributions.Instance.Exponential(arrivalTimeMinutes))); ParentControlUnit.AddRequest(new RequestQueing("WaitInQueue", Client, time)); } // end of Trigger
} // end of SetChildControlUnits #endregion #region FindSmallestJointControl /// <summary> /// Helping function that returns the lowest joint control unit in the control tree that contains /// both control units in its sub-tree. /// </summary> /// <param name="otherControl"> the other control unit that the smallest joint control is used for</param> /// <returns>Control unit that is lowest in the control tree and has both control units in its subtree, /// returns null if no joint control has been found</returns> public ControlUnit FindSmallestJointControl(ControlUnit otherControl) { if (ChildControlUnits.Contains(otherControl)) { return(this); } else { if (ParentControlUnit == null) { return(null); } return(ParentControlUnit.FindSmallestJointControl(otherControl)); } // end if } // end of FindSmallestJointControl
} // end of Event #endregion //-------------------------------------------------------------------------------------------------- // State Change //-------------------------------------------------------------------------------------------------- #region Trigger /// <summary> /// State change of event. Sends patient to the special service model /// </summary> /// <param name="time">Time event is triggered</param> /// <param name="simEngine">SimEngine responsible for simulation execution</param> protected override void StateChange(DateTime time, ISimulationEngine simEngine) { ControlUnitManagement jointControl = (ControlUnitManagement)ParentControlUnit.FindSmallestJointControl(Availability.ServiceControl); if (Patient != null) { ActivityMove movePatientToSpecialTreatment = new ActivityMove(jointControl, Patient, ParentControlUnit, Availability.ServiceControl, ReturnDelegate, jointControl.InputData.DurationMove(Patient, ParentControlUnit, Availability.ServiceControl)); SequentialEvents.Add(movePatientToSpecialTreatment.StartEvent); } // end if } // end of Trigger
} // end of EventType #endregion #region Trigger /// <summary> /// Trigger method of the event. /// </summary> /// <param name="time">Time when event is triggered</param> /// <param name="simEngine">SimEngine that executes the model</param> public void Trigger(DateTime time, ISimulationEngine simEngine) { foreach (Entity entity in AffectedEntities) { // if the parent control unit of the entity is already set it is checked if the // parent control unit differs from the control the event is hosted. // If it is different it is changed to the parent control of the event and the entity is // added to this control unit if (entity.ParentControlUnit != null) { if (entity.ParentControlUnit != ParentControlUnit) { entity.ParentControlUnit.RemoveEntity(entity); ParentControlUnit.AddEntity(entity); } } // if the entities parent control is not set it is added to the parent control of the event else { ParentControlUnit.AddEntity(entity); } } // endforeach // custom state change of the event, cann be overwritten by the user StateChange(time, simEngine); // the event is logged at the used simulation engine simEngine.LogEvent(this); // sequential events are triggered, they might be defined by custom state change method. foreach (Event seqEvent in SequentialEvents) { seqEvent.Trigger(time, simEngine); } // end foreach // The behavior occured flag of the parent control is set to true ParentControlUnit.BehaviorOccured = true; // sequential eventy are cleared SequentialEvents.Clear(); } // end of Trigger
} // end of Event #endregion //-------------------------------------------------------------------------------------------------- // State Change //-------------------------------------------------------------------------------------------------- #region StateChange /// <summary> /// Overriden state change of the event. If the patient is arrving externaly then the next arrival is /// scheduled. Else the path is updated and the next/first action is taken from the path. /// </summary> /// <param name="time">Time the patient arrives</param> /// <param name="simEngine">SimEngine responsible for simulation execution</param> protected override void StateChange(DateTime time, ISimulationEngine simEngine) { // if patient has a path it is updated if (Patient.EmergencyTreatmentPath != null) { Patient.EmergencyTreatmentPath.UpdateNextAction(); } else { // if patient has no path he is arriving externaly // path is created Patient.EmergencyTreatmentPath = ((ControlUnitEmergency)ParentControlUnit).InputData.CreateEmergencyPath(Patient); // patient is added to control unit ParentControlUnit.AddEntity(Patient); // arrival of next patient is created and scheduled EntityPatient nextPatient = ((ControlUnitEmergency)ParentControlUnit).InputData.GetNextPatient(); EventEmergencyPatientArrival nextPatientArrival = new EventEmergencyPatientArrival(ParentControlUnit, nextPatient, InputData); simEngine.AddScheduledEvent(nextPatientArrival, time + ((ControlUnitEmergency)ParentControlUnit).InputData.PatientArrivalTime(time)); } // end if // next action on path is taken if (Patient.EmergencyTreatmentPath.TakeNextAction(simEngine, this, time, ParentControlUnit)) { // possible waiting or waiting in facility is triggered if (Patient.OccupiedFacility == null || Patient.OccupiedFacility.ParentDepartmentControl != ParentControlUnit) { SequentialEvents.Add(Patient.StartWaitingActivity(((ControlUnitEmergency)ParentControlUnit).WaitingAreaPatientForNextActionType(Patient.EmergencyTreatmentPath.GetCurrentActionType()))); } else { ActivityWaitInFacility waitInFacility = new ActivityWaitInFacility(ParentControlUnit, Patient, Patient.OccupiedFacility); SequentialEvents.Add(waitInFacility.StartEvent); } // end if } // end if } // end of Trigger
} // end of InputData #endregion //-------------------------------------------------------------------------------------------------- // Methods //-------------------------------------------------------------------------------------------------- #region StateChange /// <summary> /// Overriden state change. Initializes a new arrival and patient paths and first action. /// </summary> /// <param name="time">Time the patient arrives</param> /// <param name="simEngine">SimEngine responsible for simulation execution</param> protected override void StateChange(DateTime time, ISimulationEngine simEngine) { Patient.OutpatientTreatmentPath = InputData.CreateOutpatientTreatmentPath(Patient, null, time, true); ParentControlUnit.AddEntity(Patient); DateTime nextTime;; EntityPatient nextPatient = InputData.GetNextWalkInPatient(out nextTime, ParentControlUnit, time); EventOutpatientWalkInPatientArrival nextPatientArrival = new EventOutpatientWalkInPatientArrival(ParentControlUnit, InputData, nextPatient); simEngine.AddScheduledEvent(nextPatientArrival, nextTime); if (Patient.EmergencyTreatmentPath.TakeNextAction(simEngine, this, time, ParentControlUnit)) { SequentialEvents.Add(Patient.StartWaitingActivity()); } // end if } // end of StateChange
} // end of EventStaffChange #endregion //-------------------------------------------------------------------------------------------------- // State Change //-------------------------------------------------------------------------------------------------- #region Trigger /// <summary> /// STaff is removed from control unit /// </summary> /// <param name="time">Time staff is leaving</param> /// <param name="simEngine">SimEngine responsible for simulation execution</param> protected override void StateChange(DateTime time, ISimulationEngine simEngine) { ParentControlUnit.RemoveEntity(StaffLeaving); } // end of Trigger
} // end of TriggerStartEvent #endregion #region TriggerEndEvent /// <summary> /// State changes of the activities end event. Most state changes are standardized and configurable via input. /// </summary> /// <param name="time"> time of activity start</param> /// <param name="simEngine"> SimEngine the handles the activity triggering</param> override public void StateChangeEndEvent(DateTime time, ISimulationEngine simEngine) { //-------------------------------------------------------------------------------------------------- // Some activities define the end of corresponding doctor, nurses for future reference //-------------------------------------------------------------------------------------------------- #region CorrespondingStaff if (ActionType.DefinesCorrespondingDocEnd) { Patient.CorrespondingDoctor = null; ResourceSet.MainDoctor.RemovePatient(Patient); } // end if if (ActionType.DefinesCorrespondingNurseEnd) { Patient.CorrespondingNurse = null; ResourceSet.MainNurse.RemovePatient(Patient); } // end if #endregion //-------------------------------------------------------------------------------------------------- // Occupation //-------------------------------------------------------------------------------------------------- #region Occupation if (ResourceSet.TreatmentFacility is EntityMultiplePatientTreatmentFacility) { ((EntityMultiplePatientTreatmentFacility)ResourceSet.TreatmentFacility).HoldedEntities.Remove(Patient); } else { ResourceSet.TreatmentFacility.Occupied = false; //-------------------------------------------------------------------------------------------------- // in case patient blocking is released required actions are taken //-------------------------------------------------------------------------------------------------- if (ActionType.DefinesFacilitiyOccupationEnd) { // facility is released ResourceSet.TreatmentFacility.PatientBlocking = null; // facility is removed from patient Patient.OccupiedFacility = null; } // end if } // end if #endregion //-------------------------------------------------------------------------------------------------- // If treatment has doctor(s), busyFactors are assigned //-------------------------------------------------------------------------------------------------- #region AssignBusyFactorsDoctors if (ResourceSet.MainDoctor != null) { ResourceSet.MainDoctor.BusyFactor -= ActionType.BusyFactorDoctor; ResourceSet.MainDoctor.BlockedForDispatching = false; } // end if if (ResourceSet.AssistingDoctors != null) { if (ResourceSet.AssistingDoctors.Length != ActionType.BusyFactorAssistingDoctors.Length) { throw new InvalidOperationException(); } for (int i = 0; i < ResourceSet.AssistingDoctors.Length; i++) { ResourceSet.AssistingDoctors[i].BusyFactor -= ActionType.BusyFactorAssistingDoctors[i]; ResourceSet.AssistingDoctors[i].BlockedForDispatching = false; } // end for } // end if #endregion //-------------------------------------------------------------------------------------------------- // If treatment has nurse(s), busyFactors are assigned //-------------------------------------------------------------------------------------------------- #region AssignBusyFactorsNurses if (ResourceSet.MainNurse != null) { ResourceSet.MainNurse.BusyFactor -= ActionType.BusyFactorNurse; } if (ResourceSet.AssistingNurses != null) { if (ResourceSet.AssistingNurses.Length != ActionType.BusyFactorAssistingNurses.Length) { throw new InvalidOperationException(); } for (int i = 0; i < ResourceSet.AssistingNurses.Length; i++) { ResourceSet.AssistingNurses[i].BusyFactor -= ActionType.BusyFactorAssistingNurses[i]; } // end for } // end if #endregion T nextActionType = PatientPath.GetCurrentActionType(); //-------------------------------------------------------------------------------------------------- // Preemption //-------------------------------------------------------------------------------------------------- #region Preempted if (!HoldingRequired) { if (Duration.Ticks > 0) { DegreeOfCompletion += (double)(time - StartTime).Ticks / Duration.Ticks; } else { DegreeOfCompletion = 1; } if (Math.Abs(DegreeOfCompletion - 1) > Helpers <double> .GetNumbericalPrecission()) { RequestHealthCareAction <T> req = new RequestHealthCareAction <T>(Patient, DegreeOfCompletion, ActionType, time, ResourceSet); ParentControlUnit.AddRequest(req); simEngine.RemoveScheduledEvent(EndEvent); EndEvent.SequentialEvents.Add(Patient.StartWaitingActivity(ParentDepartmentControl.WaitingAreaPatientForNextActionType(nextActionType))); return; } // end if } // end if #endregion #region NextActions //-------------------------------------------------------------------------------------------------- // In case of an holding treatment the next action was already taken //-------------------------------------------------------------------------------------------------- if (!HoldingRequired) { if (PatientPath.TakeNextAction(simEngine, EndEvent, time, ParentControlUnit)) { // either waiting or waiting in the treatment facility is launched if (Patient.OccupiedFacility == null || Patient.OccupiedFacility.ParentDepartmentControl != ParentDepartmentControl) { EndEvent.SequentialEvents.Add(Patient.StartWaitingActivity(ParentDepartmentControl.WaitingAreaPatientForNextActionType(nextActionType))); } else { ActivityWaitInFacility waitInFacility = new ActivityWaitInFacility(ParentControlUnit, Patient, Patient.OccupiedFacility); EndEvent.SequentialEvents.Add(waitInFacility.StartEvent); } // end if } // end if //-------------------------------------------------------------------------------------------------- // Possible waiting activities are started //-------------------------------------------------------------------------------------------------- #region StartWaitingActivities if (ResourceSet.MainDoctor != null && ResourceSet.MainDoctor.GetCurrentActivities().Count == 1) { EndEvent.SequentialEvents.Add(ResourceSet.MainDoctor.StartWaitingActivity(ParentDepartmentControl.WaitingRoomForStaff(ResourceSet.MainDoctor))); } if (ResourceSet.AssistingDoctors != null) { foreach (EntityDoctor doc in ResourceSet.AssistingDoctors) { if (doc.GetCurrentActivities().Count == 1) { EndEvent.SequentialEvents.Add(doc.StartWaitingActivity(ParentDepartmentControl.WaitingRoomForStaff(doc))); } } // end foreach } // end if if (ResourceSet.MainNurse != null && ResourceSet.MainNurse.GetCurrentActivities().Count == 1) { EndEvent.SequentialEvents.Add(ResourceSet.MainNurse.StartWaitingActivity(ParentDepartmentControl.WaitingRoomForStaff(ResourceSet.MainDoctor))); } if (ResourceSet.AssistingNurses != null) { foreach (EntityNurse nurse in ResourceSet.AssistingNurses) { if (nurse.GetCurrentActivities().Count == 1) { EndEvent.SequentialEvents.Add(nurse.StartWaitingActivity(ParentDepartmentControl.WaitingRoomForStaff(nurse))); } } // end foreach } // end if #endregion } #endregion #region ReleaseHolding if (ActionType.IsHold) { foreach (EntityStaff staff in AffectedEntities.Where(p => p is EntityStaff)) { staff.OnHold = false; } // end foreach return; } // end if #endregion } // end of TriggerEndEvent