protected virtual void TriggerRelease(Event @event = null) { while (ReleaseQueue.Count > 0) { var release = ReleaseQueue.Peek(); if (release.Request.IsAlive) { if (!RequestQueue.Remove(release.Request)) { throw new InvalidOperationException("Failed to cancel a request."); } BreakOffTime?.Add(Environment.ToDouble(Environment.Now - release.Request.Time)); release.Succeed(); ReleaseQueue.Dequeue(); } else { DoRelease(release); if (release.IsTriggered) { ReleaseQueue.Dequeue(); TriggerWhenAny(); TriggerWhenFull(); TriggerWhenChange(); } else { break; } } } Utilization?.UpdateTo(InUse / (double)Capacity); WIP?.UpdateTo(InUse + RequestQueue.Count); QueueLength?.UpdateTo(RequestQueue.Count); }
protected virtual void TriggerGet(Event @event = null) { var current = GetQueue.First; while (current != null) { var get = current.Value; DoGet(get); if (get.IsTriggered) { var next = current.Next; GetQueue.Remove(current); current = next; TriggerWhenEmpty(); TriggerWhenChange(); } else { current = current.Next; } if (Items.Count == 0) { break; } } Utilization?.UpdateTo(Count / (double)Capacity); WIP?.UpdateTo(Count + PutQueue.Count + GetQueue.Count); GetQueueLength?.UpdateTo(GetQueue.Count); }
protected virtual void TriggerRequest(Event @event = null) { var current = RequestQueue.First; while (current != null) { var request = current.Value; DoRequest(request); if (request.IsTriggered) { var next = current.Next; RequestQueue.Remove(current); current = next; TriggerWhenEmpty(); TriggerWhenChange(); } else { current = current.Next; } if (Resources.Count == 0) { break; } } Utilization?.UpdateTo(InUse / (double)Capacity); WIP?.UpdateTo(InUse + RequestQueue.Count); QueueLength?.UpdateTo(RequestQueue.Count); }
private IEnumerable <Event> Main() { while (true) { Priority = _pendingPrio; Mode = _pendingMode; switch (Mode) { case CraneAgentMode.Idle: State = CraneAgentState.Waiting; Utilization?.UpdateTo(0); _interruptible = true; yield return(new Event(_world.Environment)); _world.Environment.ActiveProcess.HandleFault(); continue; case CraneAgentMode.Dodge: State = CraneAgentState.Moving; Utilization?.UpdateTo(1); _interruptible = true; var moveProcess = _world.Environment.Process(MoveCrane(_dodgePosition, _dodgePosition)); yield return(moveProcess); if (_world.Environment.ActiveProcess.HandleFault()) { moveProcess.Interrupt(); _interruptible = false; yield return(moveProcess); continue; } _pendingMode = CraneAgentMode.Work; _pendingPrio = null; break; case CraneAgentMode.Work: var workingProcess = _world.Environment.Process(Working()); _interruptible = true; yield return(workingProcess); if (_world.Environment.ActiveProcess.HandleFault()) { workingProcess.Interrupt(); _interruptible = false; yield return(workingProcess); continue; } break; default: throw new InvalidOperationException($"Error in CraneAgent, unknown mode: {_pendingMode}."); } } }
protected virtual void TriggerGet(Event @event = null) { while (GetQueue.Count > 0) { var get = GetQueue.Peek(); DoGet(get); if (get.IsTriggered) { GetQueue.Dequeue(); TriggerWhenEmpty(); TriggerWhenChange(); } else { break; } } Utilization?.UpdateTo(Count / (double)Capacity); WIP?.UpdateTo(Count + PutQueue.Count + GetQueue.Count); GetQueueLength?.UpdateTo(GetQueue.Count); }
protected virtual void TriggerRequest(Event @event = null) { while (RequestQueue.Count > 0) { var request = RequestQueue.First.Value; DoRequest(request); if (request.IsTriggered) { RequestQueue.RemoveFirst(); TriggerWhenEmpty(); TriggerWhenChange(); } else { break; } } Utilization?.UpdateTo(InUse / (double)Capacity); WIP?.UpdateTo(InUse + RequestQueue.Count); QueueLength?.UpdateTo(RequestQueue.Count); }
protected virtual void TriggerPickup(Event @event = null) { while (PickupQueue.Count > 0) { var get = PickupQueue.First.Value; DoPickup(get); if (get.IsTriggered) { PickupQueue.RemoveFirst(); TriggerWhenEmpty(); TriggerWhenChange(); } else { break; } } Utilization?.UpdateTo(Location.Height / (double)Location.MaxHeight); WIP?.UpdateTo(Location.Height + DropoffQueue.Count + PickupQueue.Count); PickupQueueLength?.UpdateTo(PickupQueue.Count); }
protected virtual void TriggerPut(Event @event = null) { while (PutQueue.Count > 0) { var put = PutQueue.Peek(); DoPut(put); if (put.IsTriggered) { PutQueue.Dequeue(); TriggerWhenNew(); TriggerWhenAny(); TriggerWhenFull(); TriggerWhenChange(); } else { break; } } Utilization?.UpdateTo(Count / (double)Capacity); WIP?.UpdateTo(Count + PutQueue.Count + GetQueue.Count); PutQueueLength?.UpdateTo(PutQueue.Count); }
protected virtual void TriggerDropoff(Event @event = null) { while (DropoffQueue.Count > 0) { var put = DropoffQueue.First.Value; DoDropoff(put); if (put.IsTriggered) { DropoffQueue.RemoveFirst(); TriggerWhenNew(); TriggerWhenAny(); TriggerWhenFull(); TriggerWhenChange(); } else { break; } } Utilization?.UpdateTo(Location.Height / (double)Location.MaxHeight); WIP?.UpdateTo(Location.Height + DropoffQueue.Count + PickupQueue.Count); DropoffQueueLength?.UpdateTo(DropoffQueue.Count); }
private IEnumerable <Event> MoveCrane(double targetPosition, double goalPos2) { UpdatePosition(); GoalPosition1 = targetPosition; GoalPosition2 = goalPos2; var speed = GirderSpeed.GetValue(); while (Math.Abs(targetPosition - _crane.GirderPosition) > 0.01) { var collider = targetPosition != _crane.GirderPosition ? GetPotentialCollider() : null; _targetGirderPosition = _crane.GirderPosition; if (collider == null) { _targetGirderPosition = _world.ZoneControl.GetClosestToTarget(this, targetPosition); // CASE 1: No collision expected, move to target var sftDist = _crane.Width / 2; if (_crane.GirderPosition < _targetGirderPosition) { sftDist = -sftDist; } var stackHeight = _world.HeightBetween(_crane.GirderPosition + sftDist, targetPosition - sftDist); if (_crane.HoistLevel < stackHeight + 1) { yield return(_world.Environment.Process(MoveHoist(stackHeight + 1))); } _girderSpeed = _targetGirderPosition < _crane.GirderPosition ? -speed : speed; var timeout = _world.Environment.Timeout(TimeSpan.FromSeconds(Math.Abs(_targetGirderPosition - _crane.GirderPosition) / Math.Abs(_girderSpeed))); timeout.AddCallback(_ => { UpdatePosition(); _girderSpeed = 0; _crane.GirderPosition = _targetGirderPosition; }); yield return(timeout & _world.ReactionTime()); _world.ZoneControl.MoveUpdate(); } else { // CASE 2: Avoid potential collision if (collider.State == CraneAgentState.Waiting) { // CASE 2a: collider is idleing, tell it to dodge var dodgePoint = targetPosition < _crane.GirderPosition ? Math.Min(targetPosition, GoalPosition2) - Width / 2 - collider.Width / 2 : Math.Max(targetPosition, GoalPosition2) + Width / 2 + collider.Width / 2; if (collider.Mode == CraneAgentMode.Idle) { Utilization?.UpdateTo(0); yield return(_world.ReactionTime()); Utilization?.UpdateTo(1); } else { collider.Dodge(dodgePoint, Priority); _targetGirderPosition = _world.ZoneControl.GetClosestToTarget(this, targetPosition < _crane.GirderPosition ? collider.GetGirderPosition() + collider.Width / 2 + Width / 2 : collider.GetGirderPosition() - collider.Width / 2 - Width / 2); var sftDist = _crane.Width / 2; if (_crane.GirderPosition < _targetGirderPosition) { sftDist = -sftDist; } var stackHeight = _world.HeightBetween(_crane.GirderPosition + sftDist, targetPosition - sftDist); if (_crane.HoistLevel < stackHeight + 1) { yield return(_world.Environment.Process(MoveHoist(stackHeight + 1))); } _girderSpeed = _targetGirderPosition < _crane.GirderPosition ? -speed : speed; var timeout = _world.Environment.Timeout(TimeSpan.FromSeconds(Math.Abs(_targetGirderPosition - _crane.GirderPosition) / Math.Abs(_girderSpeed))); timeout.AddCallback(_ => { UpdatePosition(); _girderSpeed = 0; _crane.GirderPosition = _targetGirderPosition; }); yield return(timeout & _world.ReactionTime()); _world.ZoneControl.MoveUpdate(); } } else { // Case 2b: The collider is moving or servicing // Calculate the point at which a collision would occur, either the other's current position or its target position var collisionPoint = targetPosition < _crane.GirderPosition ? Math.Max(collider.GetGirderPosition(), collider.TargetPosition) + collider.Width / 2 + Width / 2 : Math.Min(collider.GetGirderPosition(), collider.TargetPosition) - collider.Width / 2 - Width / 2; var dodgePoint = targetPosition < _crane.GirderPosition ? Math.Max(Math.Max(Math.Max(collider.GetGirderPosition(), collider.GoalPosition1), collider.GoalPosition2), collider.TargetPosition) + collider.Width / 2 + Width / 2 : Math.Min(Math.Min(Math.Min(collider.GetGirderPosition(), collider.GoalPosition1), collider.GoalPosition2), collider.TargetPosition) - collider.Width / 2 - Width / 2; if (Priority > collider.Priority) { var tgt = _crane.GirderPosition < collider.GetGirderPosition() ? Math.Min(dodgePoint, targetPosition) - 1e-7: Math.Max(dodgePoint, targetPosition) + 1e-7; if (Math.Abs(tgt - _crane.GirderPosition) > 1e-5) { var oldPrio = Priority; // to propagate priority onto dodgers e.g. 4 -> 4.5 -> 4.75 -> 4.875 // this is necessary so that a dodger is able to cause further cranes to dodge Priority = (collider.Priority + Math.Ceiling((collider.Priority ?? 0) + 1e-7)) / 2.0; if (Math.Abs(_crane.GirderPosition - tgt) < 1e-5) { Utilization?.UpdateTo(0); yield return(_world.ReactionTime()); Utilization?.UpdateTo(1); } else { yield return(_world.AtLeastReactionTime(MoveCrane(tgt, tgt))); } GoalPosition1 = targetPosition; GoalPosition2 = goalPos2; Priority = oldPrio; } else { Utilization?.UpdateTo(0); yield return(_world.ReactionTime()); Utilization?.UpdateTo(1); } } else { _targetGirderPosition = _world.ZoneControl.GetClosestToTarget(this, _crane.GirderPosition < collider.GetGirderPosition() ? Math.Min(targetPosition, collisionPoint) : Math.Max(targetPosition, collisionPoint)); var sftDist = _crane.Width / 2; if (_crane.GirderPosition < _targetGirderPosition) { sftDist = -sftDist; } var stackHeight = _world.HeightBetween(_crane.GirderPosition + sftDist, targetPosition - sftDist); if (_crane.HoistLevel < stackHeight + 1) { yield return(_world.Environment.Process(MoveHoist(stackHeight + 1))); } _girderSpeed = _targetGirderPosition < _crane.GirderPosition ? -speed : speed; var timeout = _world.Environment.Timeout(TimeSpan.FromSeconds(Math.Abs(_targetGirderPosition - _crane.GirderPosition) / Math.Abs(_girderSpeed))); timeout.AddCallback(_ => { UpdatePosition(); _girderSpeed = 0; _crane.GirderPosition = _targetGirderPosition; }); yield return(timeout & _world.ReactionTime()); _world.ZoneControl.MoveUpdate(); } } } UpdatePosition(); } StopCrane(); }
private IEnumerable <Event> Working() { State = CraneAgentState.Waiting; Utilization?.UpdateTo(0); Priority = null; var next = _world.CraneScheduleStore.Get(this); _interruptible = true; yield return(next); if (_world.Environment.ActiveProcess.HandleFault()) { _world.CraneScheduleStore.CancelWaiting(next); yield break; } var move = next.Move; if (move.Amount < 0) { _world.Environment.Log($"Crane {Id}: Moving {move.Amount} number of blocks is not possible -> ignore."); yield break; } if (move.Type == MoveType.PickupAndDropoff && move.Amount > _crane.Capacity) { _world.Environment.Log($"Cannot {move.Type} {move.Amount} block(s). Crane carries {_crane.Load.Size} of {_crane.Capacity} blocks."); yield break; } if (move.Type == MoveType.PickupAndDropoff && move.Amount == 0 && _crane.Load.Size == 0) { _world.Environment.Log($"Crane {Id} should dropoff its current load at {move.PickupLocation}, but does not carry any blocks -> ignore."); yield break; } if (move.ReleaseTime > _world.Now) { // TODO: Throw, ignore, log, wait, ... !? yield return(_world.Environment.Timeout(move.ReleaseTime - _world.Now)); if (_world.Environment.ActiveProcess.HandleFault()) { yield break; } } Priority = move.Id; State = CraneAgentState.Moving; Utilization?.UpdateTo(1); GoalPosition1 = move.PickupGirderPosition; if (move.Amount > 0) { GoalPosition2 = move.DropoffGirderPosition; } else { GoalPosition2 = GoalPosition1; } Process doMove; yield return(doMove = _world.Environment.Process(MoveCrane(move.PickupGirderPosition, move.DropoffGirderPosition))); if (_world.Environment.ActiveProcess.HandleFault()) { doMove.Interrupt(); yield break; } if (move.Type == MoveType.MoveToPickup) { move.Finished.Succeed(); yield break; } var pickupLoc = _world.LocationResources.Single(x => x.Id == move.PickupLocation); if (pickupLoc.Height + _crane.Load.Size < move.Amount) // any load will first be dropped when picking up blocks { _world.Environment.Log($"Cannot pickup {move.Amount} blocks from {move.PickupLocation}, only {pickupLoc.Height} blocks there."); move.Finished.Fail(); yield break; } State = CraneAgentState.Picking; _interruptible = false; yield return(_world.Environment.Process(MoveHoist(pickupLoc.Height))); yield return(_world.Environment.Process(DoPickupDropoff(pickupLoc, move.Amount))); yield return(_world.Environment.Process(MoveHoist(_world.Height - _crane.Capacity))); if (move.Amount > 0) { State = CraneAgentState.Moving; yield return(doMove = _world.Environment.Process(MoveCrane(move.DropoffGirderPosition, move.DropoffGirderPosition))); var dropoffLoc = _world.LocationResources.Single(x => x.Id == move.DropoffLocation); if (dropoffLoc.FreeHeight < move.Amount) { _world.Environment.Log($"Cannot drop off {move.Amount} blocks at {move.DropoffLocation}, only {dropoffLoc.FreeHeight} free space."); move.Finished.Fail(); _interruptible = true; yield break; } State = CraneAgentState.Dropping; yield return(_world.Environment.Process(MoveHoist(dropoffLoc.Height))); yield return(_world.Environment.Process(DoPickupDropoff(dropoffLoc, 0))); } move.Finished.Succeed(); if (move.RaiseHoistAfterService) { yield return(_world.Environment.Process(MoveHoist(_world.Height - _crane.Capacity))); } _interruptible = true; }