public void SkipStep(bool setLights = true) { if (!isMasterNode()) { return; } TrafficLightSimulationManager tlsMan = TrafficLightSimulationManager.Instance(); var newCurrentStep = (CurrentStep + 1) % NumSteps(); foreach (ushort slaveNodeId in NodeGroup) { TrafficLightSimulation slaveSim = tlsMan.GetNodeSimulation(slaveNodeId); if (slaveSim == null || !slaveSim.IsTimedLight()) { continue; } slaveSim.TimedLight.Steps[CurrentStep].SetStepDone(); slaveSim.TimedLight.CurrentStep = newCurrentStep; slaveSim.TimedLight.Steps[newCurrentStep].Start(); if (setLights) { slaveSim.TimedLight.Steps[newCurrentStep].SetLights(); } } }
internal TimedTrafficLights MasterLights() { TrafficLightSimulation masterSim = TrafficLightSimulationManager.Instance().GetNodeSimulation(masterNodeId); if (masterSim == null || !masterSim.IsTimedLight()) { return(null); } return(masterSim.TimedLight); }
internal void RemoveNodeFromGroup(ushort otherNodeId) { NodeGroup.Remove(otherNodeId); if (NodeGroup.Count <= 0) { TrafficLightSimulation.RemoveNodeFromSimulation(NodeId, true); return; } masterNodeId = NodeGroup[0]; }
public void OnUpdate(NodeGeometry nodeGeometry) { #if DEBUG Log._Debug($"TrafficLightSimulation: OnUpdate @ node {NodeId} ({nodeGeometry.NodeId})"); #endif if (!Flags.mayHaveTrafficLight(NodeId)) { Log.Warning($"Housekeeping: Node {NodeId} has traffic light simulation but must not have a traffic light!"); TrafficLightSimulation.RemoveNodeFromSimulation(NodeId, false, true); } if (!IsManualLight() && !IsTimedLight()) { return; } if (!nodeGeometry.IsValid()) { // node has become invalid. Remove manual/timed traffic light and destroy custom lights RemoveNodeFromSimulation(NodeId, false, false); return; } for (var s = 0; s < 8; s++) { var segmentId = Singleton <NetManager> .instance.m_nodes.m_buffer[NodeId].GetSegment(s); if (segmentId == 0) { continue; } #if DEBUG Log._Debug($"TrafficLightSimulation: OnUpdate @ node {NodeId}: Adding live traffic lights to segment {segmentId}"); #endif // add custom lights if (!TrafficLight.CustomTrafficLights.IsSegmentLight(NodeId, segmentId)) { TrafficLight.CustomTrafficLights.AddSegmentLights(NodeId, segmentId); } // housekeep timed light TrafficLight.CustomTrafficLights.GetSegmentLights(NodeId, segmentId).housekeeping(true); } // ensure there is a physical traffic light Flags.setNodeTrafficLight(NodeId, true); TimedLight?.handleNewSegments(); TimedLight?.housekeeping(); }
/// <summary> /// Destroys the traffic light and removes it /// </summary> /// <param name="nodeId"></param> /// <param name="destroyGroup"></param> public static void RemoveNodeFromSimulation(ushort nodeId, bool destroyGroup, bool removeTrafficLight) { if (!TrafficLightSimulations.ContainsKey(nodeId)) { return; } TrafficLightSimulation sim = TrafficLightSimulation.TrafficLightSimulations[nodeId]; if (sim.TimedLight != null) { // remove/destroy other timed traffic lights in group List <ushort> oldNodeGroup = new List <ushort>(sim.TimedLight.NodeGroup); foreach (var timedNodeId in oldNodeGroup) { var otherNodeSim = GetNodeSimulation(timedNodeId); if (otherNodeSim == null) { continue; } if (destroyGroup || timedNodeId == nodeId) { //Log._Debug($"Slave: Removing simulation @ node {timedNodeId}"); otherNodeSim.DestroyTimedTrafficLight(); otherNodeSim.DestroyManualTrafficLight(); otherNodeSim.nodeGeoUnsubscriber.Dispose(); TrafficLightSimulations.Remove(timedNodeId); if (removeTrafficLight) { Flags.setNodeTrafficLight(timedNodeId, false); } } else { otherNodeSim.TimedLight.RemoveNodeFromGroup(nodeId); } } } //Flags.setNodeTrafficLight(nodeId, false); sim.DestroyTimedTrafficLight(); sim.DestroyManualTrafficLight(); sim.nodeGeoUnsubscriber?.Dispose(); TrafficLightSimulations.Remove(nodeId); if (removeTrafficLight) { Flags.setNodeTrafficLight(nodeId, false); } }
public void SetLights() { // set lights foreach (ushort slaveNodeId in NodeGroup) { TrafficLightSimulation slaveSim = TrafficLightSimulation.GetNodeSimulation(slaveNodeId); if (slaveSim == null || !slaveSim.IsTimedLight()) { //TrafficLightSimulation.RemoveNodeFromSimulation(slaveNodeId, false); // we iterate over NodeGroup!! continue; } slaveSim.TimedLight.Steps[CurrentStep].SetLights(); } }
public static TrafficLightSimulation GetNodeSimulation(ushort nodeId) { #if TRACE Singleton <CodeProfiler> .instance.Start("TrafficLightSimulation.GetNodeSimulation"); #endif TrafficLightSimulation ret = null; if (TrafficLightSimulations.ContainsKey(nodeId)) { ret = TrafficLightSimulations[nodeId]; } #if TRACE Singleton <CodeProfiler> .instance.Stop("TrafficLightSimulation.GetNodeSimulation"); #endif return(ret); }
internal void Join(TimedTrafficLights otherTimedLight) { TrafficLightSimulationManager tlsMan = TrafficLightSimulationManager.Instance(); if (NumSteps() < otherTimedLight.NumSteps()) { // increase the number of steps at our timed lights for (int i = NumSteps(); i < otherTimedLight.NumSteps(); ++i) { TimedTrafficLightsStep otherStep = otherTimedLight.GetStep(i); foreach (ushort slaveNodeId in NodeGroup) { TrafficLightSimulation ourSim = tlsMan.GetNodeSimulation(slaveNodeId); if (ourSim == null || !ourSim.IsTimedLight()) { continue; } TimedTrafficLights ourTimedLight = ourSim.TimedLight; ourTimedLight.AddStep(otherStep.minTime, otherStep.maxTime, otherStep.waitFlowBalance, true); } } } else { // increase the number of steps at their timed lights for (int i = otherTimedLight.NumSteps(); i < NumSteps(); ++i) { TimedTrafficLightsStep ourStep = GetStep(i); foreach (ushort slaveNodeId in otherTimedLight.NodeGroup) { TrafficLightSimulation theirSim = tlsMan.GetNodeSimulation(slaveNodeId); if (theirSim == null || !theirSim.IsTimedLight()) { continue; } TimedTrafficLights theirTimedLight = theirSim.TimedLight; theirTimedLight.AddStep(ourStep.minTime, ourStep.maxTime, ourStep.waitFlowBalance, true); } } } // join groups and re-defined master node, determine mean min/max times & mean wait-flow-balances HashSet <ushort> newNodeGroupSet = new HashSet <ushort>(); newNodeGroupSet.UnionWith(NodeGroup); newNodeGroupSet.UnionWith(otherTimedLight.NodeGroup); List <ushort> newNodeGroup = new List <ushort>(newNodeGroupSet); ushort newMasterNodeId = newNodeGroup[0]; int[] minTimes = new int[NumSteps()]; int[] maxTimes = new int[NumSteps()]; float[] waitFlowBalances = new float[NumSteps()]; foreach (ushort timedNodeId in newNodeGroup) { TrafficLightSimulation timedSim = tlsMan.GetNodeSimulation(timedNodeId); if (timedSim == null || !timedSim.IsTimedLight()) { continue; } TimedTrafficLights timedLight = timedSim.TimedLight; for (int i = 0; i < NumSteps(); ++i) { minTimes[i] += timedLight.GetStep(i).minTime; maxTimes[i] += timedLight.GetStep(i).maxTime; waitFlowBalances[i] += timedLight.GetStep(i).waitFlowBalance; } timedLight.NodeGroup = newNodeGroup; timedLight.masterNodeId = newMasterNodeId; } // build means if (NumSteps() > 0) { for (int i = 0; i < NumSteps(); ++i) { minTimes[i] = Math.Max(1, minTimes[i] / newNodeGroup.Count); maxTimes[i] = Math.Max(1, maxTimes[i] / newNodeGroup.Count); waitFlowBalances[i] = Math.Max(0.001f, waitFlowBalances[i] / (float)newNodeGroup.Count); } } // apply means & reset foreach (ushort timedNodeId in newNodeGroup) { TrafficLightSimulation timedSim = tlsMan.GetNodeSimulation(timedNodeId); if (timedSim == null || !timedSim.IsTimedLight()) { continue; } TimedTrafficLights timedLight = timedSim.TimedLight; timedLight.Stop(); timedLight.testMode = false; timedLight.lastSimulationStep = 0; for (int i = 0; i < NumSteps(); ++i) { timedLight.GetStep(i).minTime = minTimes[i]; timedLight.GetStep(i).maxTime = maxTimes[i]; timedLight.GetStep(i).waitFlowBalance = waitFlowBalances[i]; } } }
/// <summary> /// Calculates the current metrics for flowing and waiting vehicles /// </summary> /// <param name="wait"></param> /// <param name="flow"></param> /// <returns>true if the values could be calculated, false otherwise</returns> public bool calcWaitFlow(out float wait, out float flow) { #if DEBUG bool debug = timedNode.NodeId == 17857; #else bool debug = false; #endif uint numFlows = 0; uint numWaits = 0; uint curMeanFlow = 0; uint curMeanWait = 0; // we are the master node. calculate traffic data foreach (ushort timedNodeId in groupNodeIds) { TrafficLightSimulation sim = TrafficLightSimulation.GetNodeSimulation(timedNodeId); if (sim == null || !sim.IsTimedLight()) { continue; } TimedTrafficLights slaveTimedNode = sim.TimedLight; if (slaveTimedNode.NumSteps() <= timedNode.CurrentStep) { for (int i = 0; i < slaveTimedNode.NumSteps(); ++i) { slaveTimedNode.GetStep(i).invalid = true; } continue; } TimedTrafficLightsStep slaveStep = slaveTimedNode.Steps[timedNode.CurrentStep]; //List<int> segmentIdsToDelete = new List<int>(); // minimum time reached. check traffic! foreach (KeyValuePair <ushort, CustomSegmentLights> e in slaveStep.segmentLights) { var fromSegmentId = e.Key; var segLights = e.Value; // one of the traffic lights at this segment is green: count minimum traffic flowing through SegmentEnd fromSeg = TrafficPriority.GetPrioritySegment(timedNodeId, fromSegmentId); if (fromSeg == null) { //Log.Warning("stepDone(): prioSeg is null"); //segmentIdsToDelete.Add(fromSegmentId); continue; // skip invalid segment } bool startPhase = getCurrentFrame() <= startFrame + minTime + 2; // during start phase all vehicles on "green" segments are counted as flowing ExtVehicleType validVehicleTypes = VehicleRestrictionsManager.GetAllowedVehicleTypes(fromSegmentId, timedNode.NodeId); foreach (ExtVehicleType vehicleType in segLights.VehicleTypes) { if (vehicleType != ExtVehicleType.None && (validVehicleTypes & vehicleType) == ExtVehicleType.None) { continue; } CustomSegmentLight segLight = segLights.GetCustomLight(vehicleType); if (segLight == null) { Log.Warning($"Timed traffic light step: Failed to get custom light for vehicleType {vehicleType} @ seg. {fromSegmentId}, node {timedNode.NodeId}!"); continue; } Dictionary <ushort, uint>[] carsToSegmentMetrics = new Dictionary <ushort, uint> [startPhase ? 1: 2]; try { carsToSegmentMetrics[0] = fromSeg.GetVehicleMetricGoingToSegment(null, vehicleType, segLights.SeparateVehicleTypes, debug); } catch (Exception ex) { Log.Warning("calcWaitFlow: " + ex.ToString()); } if (!startPhase) { try { carsToSegmentMetrics[1] = fromSeg.GetVehicleMetricGoingToSegment(0.1f, vehicleType, segLights.SeparateVehicleTypes, debug); } catch (Exception ex) { Log.Warning("calcWaitFlow: " + ex.ToString()); } } if (carsToSegmentMetrics[0] == null) { continue; } // build directions from toSegment to fromSegment Dictionary <ushort, Direction> directions = new Dictionary <ushort, Direction>(); foreach (KeyValuePair <ushort, uint> f in carsToSegmentMetrics[0]) { var toSegmentId = f.Key; SegmentGeometry geometry = CustomRoadAI.GetSegmentGeometry(fromSegmentId); Direction dir = geometry.GetDirection(toSegmentId, timedNodeId); directions[toSegmentId] = dir; } // calculate waiting/flowing traffic for (int i = 0; i < carsToSegmentMetrics.Length; ++i) { if (carsToSegmentMetrics[i] == null) { continue; } foreach (KeyValuePair <ushort, uint> f in carsToSegmentMetrics[i]) { ushort toSegmentId = f.Key; uint totalNormCarLength = f.Value; bool addToFlow = false; switch (directions[toSegmentId]) { case Direction.Left: if (segLight.isLeftGreen()) { addToFlow = true; } break; case Direction.Right: if (segLight.isRightGreen()) { addToFlow = true; } break; case Direction.Forward: default: if (segLight.isForwardGreen()) { addToFlow = true; } break; } if (addToFlow) { if (i > 0 || startPhase) { ++numFlows; curMeanFlow += totalNormCarLength; } } else if (i == 0) { ++numWaits; curMeanWait += totalNormCarLength; } } } } } // delete invalid segments from step /*foreach (int segmentId in segmentIdsToDelete) { * slaveStep.segmentLightStates.Remove(segmentId); * }*/ if (slaveStep.segmentLights.Count <= 0) { invalid = true; flow = 0f; wait = 0f; return(false); } } if (numFlows > 0) { curMeanFlow /= numFlows; } if (numWaits > 0) { curMeanWait /= numWaits; } float fCurMeanFlow = curMeanFlow; fCurMeanFlow /= 100f * waitFlowBalance; // a value smaller than 1 rewards steady traffic currents wait = (float)curMeanWait / 100f; flow = fCurMeanFlow; return(true); }
public bool StepDone(bool updateValues) { if (timedNode.IsInTestMode()) { return(false); } if (stepDone) { return(true); } if (getCurrentFrame() >= startFrame + maxTime) { // maximum time reached. switch! #if DEBUG //Log.Message("step finished @ " + nodeId); #endif stepDone = true; endTransitionStart = getCurrentFrame(); return(stepDone); } if (getCurrentFrame() >= startFrame + minTime) { if (timedNode.masterNodeId != timedNode.NodeId) { TrafficLightSimulation masterSim = TrafficLightSimulation.GetNodeSimulation(timedNode.masterNodeId); if (masterSim == null || !masterSim.IsTimedLight()) { invalid = true; stepDone = true; endTransitionStart = getCurrentFrame(); return(true); } TimedTrafficLights masterTimedNode = masterSim.TimedLight; bool done = masterTimedNode.Steps[masterTimedNode.CurrentStep].StepDone(updateValues); #if DEBUG //Log.Message("step finished (1) @ " + nodeId); #endif stepDone = done; if (stepDone) { endTransitionStart = getCurrentFrame(); } return(stepDone); } else { // we are the master node float wait, flow; uint curFrame = getCurrentFrame(); if (lastFlowWaitCalc < curFrame) { if (!calcWaitFlow(out wait, out flow)) { stepDone = true; endTransitionStart = getCurrentFrame(); return(stepDone); } else { lastFlowWaitCalc = curFrame; } } else { flow = minFlow; wait = maxWait; } float newFlow = minFlow; float newWait = maxWait; if (Single.IsNaN(newFlow)) { newFlow = flow; } else { newFlow = 0.1f * newFlow + 0.9f * flow; // some smoothing } if (Single.IsNaN(newWait)) { newWait = 0; } else { newWait = 0.1f * newWait + 0.9f * wait; // some smoothing } // if more cars are waiting than flowing, we change the step bool done = newWait > 0 && newFlow < newWait; if (updateValues) { minFlow = newFlow; maxWait = newWait; } #if DEBUG //Log.Message("step finished (2) @ " + nodeId); #endif if (updateValues) { stepDone = done; } if (stepDone) { endTransitionStart = getCurrentFrame(); } return(stepDone); } } return(false); }
private static void GetCustomTrafficLightState(ushort vehicleId, ref Vehicle vehicleData, ushort nodeId, ushort fromSegmentId, ushort toSegmentId, out RoadBaseAI.TrafficLightState vehicleLightState, out RoadBaseAI.TrafficLightState pedestrianLightState, TrafficLightSimulation nodeSim = null) { if (nodeSim == null) { nodeSim = TrafficLightSimulation.GetNodeSimulation(nodeId); if (nodeSim == null) { Log.Error($"GetCustomTrafficLightState: node traffic light simulation not found at node {nodeId}! Vehicle {vehicleId} comes from segment {fromSegmentId} and goes to node {nodeId}"); throw new ApplicationException($"GetCustomTrafficLightState: node traffic light simulation not found at node {nodeId}! Vehicle {vehicleId} comes from segment {fromSegmentId} and goes to node {nodeId}"); } } // get vehicle position /*VehiclePosition vehiclePos = TrafficPriority.GetVehiclePosition(vehicleId); if (!vehiclePos.Valid || vehiclePos.FromSegment != fromSegmentId || vehiclePos.ToNode != nodeId) { Log._Debug($"GetTrafficLightState: Recalculating position for vehicle {vehicleId}! FromSegment={vehiclePos.FromSegment} Valid={vehiclePos.Valid}"); try { HandleVehicle(vehicleId, ref Singleton<VehicleManager>.instance.m_vehicles.m_buffer[vehicleId], false, false); } catch (Exception e) { Log.Error("VehicleAI GetTrafficLightState Error: " + e.ToString()); } } if (!vehiclePos.Valid || vehiclePos.FromSegment != fromSegmentId || vehiclePos.ToNode != nodeId) { Log.Warning($"GetTrafficLightState: Vehicle {vehicleId} is not moving at segment {fromSegmentId} to node {nodeId}! FromSegment={vehiclePos.FromSegment} ToNode={vehiclePos.ToNode} Valid={vehiclePos.Valid}"); vehicleLightState = RoadBaseAI.TrafficLightState.Red; pedestrianLightState = RoadBaseAI.TrafficLightState.Red; return; }*/ // get vehicle type ExtVehicleType? vehicleType = CustomVehicleAI.DetermineVehicleTypeFromVehicle(vehicleId, ref vehicleData); if (vehicleData.Info.m_vehicleType == VehicleInfo.VehicleType.Tram && vehicleType != ExtVehicleType.Tram) Log.Warning($"vehicleType={vehicleType} ({(int)vehicleType}) for Tram"); //Log._Debug($"GetCustomTrafficLightState: Vehicle {vehicleId} is a {vehicleType}"); if (vehicleType == null) { Log.Warning($"GetTrafficLightState: Could not determine vehicle type of vehicle {vehicleId}!"); vehicleLightState = RoadBaseAI.TrafficLightState.Red; pedestrianLightState = RoadBaseAI.TrafficLightState.Red; return; } // get responsible traffic light CustomSegmentLights lights = CustomTrafficLights.GetSegmentLights(nodeId, fromSegmentId); CustomSegmentLight light = lights == null ? null : lights.GetCustomLight((ExtVehicleType)vehicleType); if (lights == null || light == null) { Log.Warning($"GetTrafficLightState: No custom light for vehicleType {vehicleType} @ node {nodeId}, segment {fromSegmentId} found. lights null? {lights == null} light null? {light == null}"); vehicleLightState = RoadBaseAI.TrafficLightState.Red; pedestrianLightState = RoadBaseAI.TrafficLightState.Red; return; } SegmentGeometry geometry = CustomRoadAI.GetSegmentGeometry(fromSegmentId); // get traffic light state from responsible traffic light if (geometry.IsLeftSegment(toSegmentId, nodeId)) { vehicleLightState = light.GetLightLeft(); } else if (geometry.IsRightSegment(toSegmentId, nodeId)) { vehicleLightState = light.GetLightRight(); } else { vehicleLightState = light.GetLightMain(); } // get traffic lights state for pedestrians pedestrianLightState = (lights.PedestrianLightState != null) ? (RoadBaseAI.TrafficLightState)lights.PedestrianLightState : RoadBaseAI.TrafficLightState.Red; }
public void SimulationStep() { var currentFrame = Singleton <SimulationManager> .instance.m_currentFrameIndex >> 5; #if DEBUGTTL Log._Debug($"TTL SimStep: currentFrame={currentFrame} lastSimulationStep={lastSimulationStep}"); #endif if (lastSimulationStep >= currentFrame) { #if DEBUGTTL Log._Debug($"TTL SimStep: *STOP* lastSimulationStep >= currentFrame"); #endif return; } lastSimulationStep = currentFrame; if (!isMasterNode() || !IsStarted()) { #if DEBUGTTL Log._Debug($"TTL SimStep: *STOP* isMasterNode={isMasterNode()} IsStarted={IsStarted()}"); #endif return; } if (!housekeeping(false)) { #if DEBUGTTL Log.Warning($"TTL SimStep: *STOP* Housekeeping detected that this timed traffic light has become invalid: {NodeId}."); #endif Stop(); return; } if (!Steps[CurrentStep].isValid()) { #if DEBUGTTL Log._Debug($"TTL SimStep: *STOP* current step ({CurrentStep}) is not valid."); #endif TrafficLightSimulation.RemoveNodeFromSimulation(NodeId, false); return; } #if DEBUGTTL Log._Debug($"TTL SimStep: Setting lights (1)"); #endif SetLights(); if (!Steps[CurrentStep].StepDone(true)) { #if DEBUGTTL Log._Debug($"TTL SimStep: *STOP* current step ({CurrentStep}) is not done."); #endif return; } // step is done #if DEBUGTTL Log._Debug($"TTL SimStep: Setting lights (2)"); #endif SetLights(); if (!Steps[CurrentStep].isEndTransitionDone()) { #if DEBUGTTL Log._Debug($"TTL SimStep: *STOP* current step ({CurrentStep}): end transition is not done."); #endif return; } // ending transition (yellow) finished #if DEBUGTTL Log._Debug($"TTL SimStep: ending transition done. NodeGroup={string.Join(", ", NodeGroup.Select(x => x.ToString()).ToArray())}, nodeId={NodeId}, NumSteps={NumSteps()}"); #endif // change step var newCurrentStep = (CurrentStep + 1) % NumSteps(); foreach (ushort slaveNodeId in NodeGroup) { TrafficLightSimulation slaveSim = TrafficLightSimulation.GetNodeSimulation(slaveNodeId); if (slaveSim == null || !slaveSim.IsTimedLight()) { continue; } slaveSim.TimedLight.CurrentStep = newCurrentStep; slaveSim.TimedLight.Steps[newCurrentStep].Start(); slaveSim.TimedLight.Steps[newCurrentStep].SetLights(); } }
internal bool housekeeping(bool housekeepCustomLights) { bool mayStart = true; List <ushort> nodeIdsToDelete = new List <ushort>(); int i = 0; foreach (ushort otherNodeId in NodeGroup) { if ((Singleton <NetManager> .instance.m_nodes.m_buffer[otherNodeId].m_flags & NetNode.Flags.Created) == NetNode.Flags.None) { Log.Warning($"Timed housekeeping: Remove node {otherNodeId}"); nodeIdsToDelete.Add(otherNodeId); if (otherNodeId == NodeId) { Log.Warning($"Timed housekeeping: Other is this. mayStart = false"); mayStart = false; } } ++i; } foreach (ushort nodeIdToDelete in nodeIdsToDelete) { NodeGroup.Remove(nodeIdToDelete); TrafficLightSimulation.RemoveNodeFromSimulation(nodeIdToDelete, false); } // check that live lights exist (TODO refactor?) foreach (ushort timedNodeId in NodeGroup) { for (int s = 0; s < 8; s++) { var segmentId = Singleton <NetManager> .instance.m_nodes.m_buffer[timedNodeId].GetSegment(s); if (segmentId == 0) { continue; } CustomTrafficLights.AddLiveSegmentLights(timedNodeId, segmentId); } } if (NodeGroup.Count <= 0) { Log.Warning($"Timed housekeeping: No lights left. mayStart = false"); mayStart = false; return(mayStart); } //Log.Warning($"Timed housekeeping: Setting master node to {NodeGroup[0]}"); masterNodeId = NodeGroup[0]; if (housekeepCustomLights) { foreach (TimedTrafficLightsStep step in Steps) { foreach (KeyValuePair <ushort, CustomSegmentLights> e in step.segmentLights) { e.Value.housekeeping(true); } } } return(mayStart); }
public void SimulationStep() { #if TRACE Singleton <CodeProfiler> .instance.Start("TimedTrafficLights.SimulationStep"); #endif if (!isMasterNode() || !IsStarted()) { #if DEBUGTTL Log._Debug($"TTL SimStep: *STOP* NodeId={NodeId} isMasterNode={isMasterNode()} IsStarted={IsStarted()}"); #endif #if TRACE Singleton <CodeProfiler> .instance.Stop("TimedTrafficLights.SimulationStep"); #endif return; } var currentFrame = Singleton <SimulationManager> .instance.m_currentFrameIndex >> 5; #if DEBUGTTL Log._Debug($"TTL SimStep: nodeId={NodeId} currentFrame={currentFrame} lastSimulationStep={lastSimulationStep}"); #endif if (lastSimulationStep >= currentFrame) { #if DEBUGTTL Log._Debug($"TTL SimStep: *STOP* lastSimulationStep >= currentFrame"); #endif #if TRACE Singleton <CodeProfiler> .instance.Stop("TimedTrafficLights.SimulationStep"); #endif return; } lastSimulationStep = currentFrame; /*if (!housekeeping()) { #if DEBUGTTL * Log.Warning($"TTL SimStep: *STOP* NodeId={NodeId} Housekeeping detected that this timed traffic light has become invalid: {NodeId}."); #endif * Stop(); * return; * }*/ if (!Steps[CurrentStep].isValid()) { #if DEBUGTTL Log._Debug($"TTL SimStep: *STOP* NodeId={NodeId} current step ({CurrentStep}) is not valid."); #endif TrafficLightSimulation.RemoveNodeFromSimulation(NodeId, false, false); #if TRACE Singleton <CodeProfiler> .instance.Stop("TimedTrafficLights.SimulationStep"); #endif return; } #if DEBUGTTL Log._Debug($"TTL SimStep: NodeId={NodeId} Setting lights (1)"); #endif SetLights(); if (!Steps[CurrentStep].StepDone(true)) { #if DEBUGTTL Log._Debug($"TTL SimStep: *STOP* NodeId={NodeId} current step ({CurrentStep}) is not done."); #endif #if TRACE Singleton <CodeProfiler> .instance.Stop("TimedTrafficLights.SimulationStep"); #endif return; } // step is done #if DEBUGTTL Log._Debug($"TTL SimStep: NodeId={NodeId} Setting lights (2)"); #endif SetLights(); // check if this is needed if (!Steps[CurrentStep].isEndTransitionDone()) { #if DEBUGTTL Log._Debug($"TTL SimStep: *STOP* NodeId={NodeId} current step ({CurrentStep}): end transition is not done."); #endif #if TRACE Singleton <CodeProfiler> .instance.Stop("TimedTrafficLights.SimulationStep"); #endif return; } // ending transition (yellow) finished #if DEBUGTTL Log._Debug($"TTL SimStep: NodeId={NodeId} ending transition done. NodeGroup={string.Join(", ", NodeGroup.Select(x => x.ToString()).ToArray())}, nodeId={NodeId}, NumSteps={NumSteps()}"); #endif // change step int oldCurrentStep = CurrentStep; while (true) { SkipStep(false); if (CurrentStep == oldCurrentStep) { break; } if (Steps[CurrentStep].minTime > 0) { break; } float flow, wait; bool couldCalculateFlowWaitStats = Steps[CurrentStep].calcWaitFlow(out wait, out flow); if (!couldCalculateFlowWaitStats) { break; } if (flow >= wait) { break; } } Steps[CurrentStep].SetLights(); #if TRACE Singleton <CodeProfiler> .instance.Stop("TimedTrafficLights.SimulationStep"); #endif }
/// <summary> /// Calculates the current metrics for flowing and waiting vehicles /// </summary> /// <param name="wait"></param> /// <param name="flow"></param> /// <returns>true if the values could be calculated, false otherwise</returns> public bool calcWaitFlow(bool onlyMoving, int stepRefIndex, out float wait, out float flow) { uint numFlows = 0; uint numWaits = 0; uint curMeanFlow = 0; uint curMeanWait = 0; // TODO checking agains getCurrentFrame() is only valid if this is the current step if (onlyMoving && getCurrentFrame() <= startFrame + minTime + 1) // during start phase all vehicles on "green" segments are counted as flowing { onlyMoving = false; } TrafficLightSimulationManager tlsMan = TrafficLightSimulationManager.Instance; TrafficPriorityManager prioMan = TrafficPriorityManager.Instance; foreach (ushort timedNodeId in timedNode.NodeGroup) { TrafficLightSimulation sim = tlsMan.GetNodeSimulation(timedNodeId); if (sim == null || !sim.IsTimedLight()) { continue; } TimedTrafficLights slaveTimedNode = sim.TimedLight; TimedTrafficLightsStep slaveStep = slaveTimedNode.Steps[stepRefIndex]; //List<int> segmentIdsToDelete = new List<int>(); // minimum time reached. check traffic! foreach (KeyValuePair <ushort, CustomSegmentLights> e in slaveStep.segmentLights) { var sourceSegmentId = e.Key; var segLights = e.Value; #if DEBUGMETRIC bool debug = sourceSegmentId == 20857 && GlobalConfig.Instance.DebugSwitches[1]; #elif DEBUG bool debug = GlobalConfig.Instance.DebugSwitches[7] && GlobalConfig.Instance.TTLDebugNodeId == timedNodeId; #else bool debug = false; #endif Dictionary <ushort, ArrowDirection> directions = null; if (slaveStep.timedNode.Directions.ContainsKey(sourceSegmentId)) { directions = slaveStep.timedNode.Directions[sourceSegmentId]; } else { #if DEBUG if (debug) { Log._Debug($"calcWaitFlow: No arrow directions defined for segment {sourceSegmentId} @ {timedNodeId}"); } #endif continue; } // one of the traffic lights at this segment is green: count minimum traffic flowing through SegmentEnd sourceSegmentEnd = prioMan.GetPrioritySegment(timedNodeId, sourceSegmentId); if (sourceSegmentEnd == null) { Log.Warning($"TimedTrafficLightsStep.calcWaitFlow: No priority segment @ seg. {sourceSegmentId} found!"); continue; // skip invalid segment } ExtVehicleType validVehicleTypes = VehicleRestrictionsManager.Instance.GetAllowedVehicleTypes(sourceSegmentId, timedNode.NodeId); foreach (KeyValuePair <byte, ExtVehicleType> e2 in segLights.VehicleTypeByLaneIndex) { byte laneIndex = e2.Key; ExtVehicleType vehicleType = e2.Value; if (vehicleType != ExtVehicleType.None && (validVehicleTypes & vehicleType) == ExtVehicleType.None) { continue; } CustomSegmentLight segLight = segLights.GetCustomLight(laneIndex); if (segLight == null) { Log.Warning($"Timed traffic light step: Failed to get custom light for vehicleType {vehicleType} @ seg. {sourceSegmentId}, node {timedNode.NodeId}!"); continue; } #if DEBUG if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Checking lane {laneIndex} @ seg. {sourceSegmentId}. Vehicle types: {vehicleType}"); } #endif Dictionary <ushort, uint> carsFlowingToSegmentMetric = null; Dictionary <ushort, uint> allCarsToSegmentMetric = null; bool evalFlowingVehicles = segLight.IsAnyGreen(); // flowing vehicle need only to be evaluated if a light is green if (evalFlowingVehicles && onlyMoving) { carsFlowingToSegmentMetric = sourceSegmentEnd.GetVehicleMetricGoingToSegment(false, laneIndex, debug); } allCarsToSegmentMetric = sourceSegmentEnd.GetVehicleMetricGoingToSegment(true, laneIndex, debug); // calculate waiting/flowing traffic foreach (KeyValuePair <ushort, uint> f in allCarsToSegmentMetric) { ushort targetSegmentId = f.Key; uint totalNumCars = f.Value; if (!directions.ContainsKey(targetSegmentId)) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Direction undefined for target segment {targetSegmentId} @ {timedNodeId}"); continue; } if (evalFlowingVehicles) { uint totalNumFlowingCars = onlyMoving ? carsFlowingToSegmentMetric[f.Key] : totalNumCars; #if DEBUG if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Total num of flowing cars on seg. {sourceSegmentId}, lane {laneIndex} going to seg. {targetSegmentId}: {totalNumFlowingCars}"); } #endif bool addToFlow = false; switch (directions[targetSegmentId]) { case ArrowDirection.Turn: addToFlow = TrafficPriorityManager.IsLeftHandDrive() ? segLight.IsRightGreen() : segLight.IsLeftGreen(); break; case ArrowDirection.Left: addToFlow = segLight.IsLeftGreen(); break; case ArrowDirection.Right: addToFlow = segLight.IsRightGreen(); break; case ArrowDirection.Forward: default: addToFlow = segLight.IsMainGreen(); break; } if (addToFlow) { curMeanFlow += totalNumFlowingCars; ++numFlows; } else { curMeanWait += totalNumCars; ++numWaits; } } else { curMeanWait += totalNumCars; ++numWaits; } #if DEBUG if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Vehicles on lane {laneIndex} on seg. {sourceSegmentId} going to seg. {targetSegmentId} curMeanFlow={curMeanFlow}, curMeanWait={curMeanWait}, numFlows={numFlows}, numWaits={numWaits}"); } #endif } } } } /*if (numFlows > 0) * curMeanFlow /= numFlows; * if (numWaits > 0) * curMeanWait /= numWaits;*/ float fCurMeanFlow = numFlows > 0 ? (float)curMeanFlow / (float)numFlows : 0; float fCurMeanWait = numWaits > 0 ? (float)curMeanWait / (float)numWaits : 0; fCurMeanFlow /= waitFlowBalance; // a value smaller than 1 rewards steady traffic currents wait = (float)fCurMeanWait; flow = fCurMeanFlow; return(true); }
/// <summary> /// Calculates the current metrics for flowing and waiting vehicles /// </summary> /// <param name="wait"></param> /// <param name="flow"></param> /// <returns>true if the values could be calculated, false otherwise</returns> public bool calcWaitFlow(out float wait, out float flow) { #if TRACE Singleton <CodeProfiler> .instance.Start("TimedTrafficLightsStep.calcWaitFlow"); #endif #if DEBUGMETRIC bool debug = timedNode.NodeId == 3201; #else bool debug = false; #endif #if DEBUGMETRIC if (debug) { Log.Warning($"TimedTrafficLightsStep.calcWaitFlow: ***START*** @ node {timedNode.NodeId}"); } #endif uint numFlows = 0; uint numWaits = 0; uint curMeanFlow = 0; uint curMeanWait = 0; // we are the master node. calculate traffic data foreach (ushort timedNodeId in timedNode.NodeGroup) { TrafficLightSimulation sim = TrafficLightSimulation.GetNodeSimulation(timedNodeId); if (sim == null || !sim.IsTimedLight()) { continue; } TimedTrafficLights slaveTimedNode = sim.TimedLight; if (slaveTimedNode.NumSteps() <= timedNode.CurrentStep) { for (int i = 0; i < slaveTimedNode.NumSteps(); ++i) { slaveTimedNode.GetStep(i).invalid = true; } continue; } TimedTrafficLightsStep slaveStep = slaveTimedNode.Steps[timedNode.CurrentStep]; //List<int> segmentIdsToDelete = new List<int>(); // minimum time reached. check traffic! foreach (KeyValuePair <ushort, CustomSegmentLights> e in slaveStep.segmentLights) { var fromSegmentId = e.Key; var segLights = e.Value; // one of the traffic lights at this segment is green: count minimum traffic flowing through SegmentEnd fromSeg = TrafficPriority.GetPrioritySegment(timedNodeId, fromSegmentId); if (fromSeg == null) { #if DEBUGMETRIC if (debug) { Log.Warning($"TimedTrafficLightsStep.calcWaitFlow: No priority segment @ seg. {fromSegmentId} found!"); } #endif //Log.Warning("stepDone(): prioSeg is null"); //segmentIdsToDelete.Add(fromSegmentId); continue; // skip invalid segment } //bool startPhase = getCurrentFrame() <= startFrame + minTime + 2; // during start phase all vehicles on "green" segments are counted as flowing ExtVehicleType validVehicleTypes = VehicleRestrictionsManager.GetAllowedVehicleTypes(fromSegmentId, timedNode.NodeId); foreach (KeyValuePair <byte, ExtVehicleType> e2 in segLights.VehicleTypeByLaneIndex) { byte laneIndex = e2.Key; ExtVehicleType vehicleType = e2.Value; if (vehicleType != ExtVehicleType.None && (validVehicleTypes & vehicleType) == ExtVehicleType.None) { continue; } CustomSegmentLight segLight = segLights.GetCustomLight(laneIndex); if (segLight == null) { Log.Warning($"Timed traffic light step: Failed to get custom light for vehicleType {vehicleType} @ seg. {fromSegmentId}, node {timedNode.NodeId}!"); continue; } #if DEBUGMETRIC if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Checking lane {laneIndex} @ seg. {fromSegmentId}. Vehicle types: {vehicleType}"); } #endif Dictionary <ushort, uint> carsFlowingToSegmentMetric = null; Dictionary <ushort, uint> allCarsToSegmentMetric = null; try { carsFlowingToSegmentMetric = fromSeg.GetVehicleMetricGoingToSegment(false, laneIndex, debug); } catch (Exception ex) { Log.Warning("calcWaitFlow (1): " + ex.ToString()); } try { allCarsToSegmentMetric = fromSeg.GetVehicleMetricGoingToSegment(true, laneIndex, debug); } catch (Exception ex) { Log.Warning("calcWaitFlow (2): " + ex.ToString()); } if (carsFlowingToSegmentMetric == null) { continue; } // build directions from toSegment to fromSegment Dictionary <ushort, Direction> directions = new Dictionary <ushort, Direction>(); foreach (KeyValuePair <ushort, uint> f in allCarsToSegmentMetric) { var toSegmentId = f.Key; SegmentGeometry geometry = SegmentGeometry.Get(fromSegmentId); Direction dir = geometry.GetDirection(toSegmentId, timedNodeId == geometry.StartNodeId()); directions[toSegmentId] = dir; #if DEBUGMETRIC if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Calculated direction for seg. {fromSegmentId} -> seg. {toSegmentId}: {dir}"); } #endif } // calculate waiting/flowing traffic foreach (KeyValuePair <ushort, uint> f in allCarsToSegmentMetric) { ushort toSegmentId = f.Key; uint totalNormCarLength = f.Value; uint totalFlowingNormCarLength = carsFlowingToSegmentMetric[f.Key]; #if DEBUGMETRIC if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Total norm. car length of vehicles on lane {laneIndex} going to seg. {toSegmentId}: {totalNormCarLength}"); } #endif bool addToFlow = false; switch (directions[toSegmentId]) { case Direction.Turn: addToFlow = TrafficPriority.IsLeftHandDrive() ? segLight.isRightGreen() : segLight.isLeftGreen(); break; case Direction.Left: addToFlow = segLight.isLeftGreen(); break; case Direction.Right: addToFlow = segLight.isRightGreen(); break; case Direction.Forward: default: addToFlow = segLight.isForwardGreen(); break; } if (addToFlow) { ++numFlows; curMeanFlow += totalFlowingNormCarLength; } else { ++numWaits; curMeanWait += totalNormCarLength; } #if DEBUGMETRIC if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Vehicles on lane {laneIndex} on seg. {fromSegmentId} going to seg. {toSegmentId} flowing? {addToFlow} curMeanFlow={curMeanFlow}, curMeanWait={curMeanWait}"); } #endif } } } // delete invalid segments from step /*foreach (int segmentId in segmentIdsToDelete) { * slaveStep.segmentLightStates.Remove(segmentId); * }*/ if (slaveStep.segmentLights.Count <= 0) { invalid = true; flow = 0f; wait = 0f; #if TRACE Singleton <CodeProfiler> .instance.Stop("TimedTrafficLightsStep.calcWaitFlow"); #endif return(false); } } #if DEBUGMETRIC if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: ### Calculation completed. numFlows={numFlows}, numWaits={numWaits}, curMeanFlow={curMeanFlow}, curMeanWait={curMeanWait}"); } wait = curMeanWait; flow = curMeanFlow; #else if (numFlows > 0) { curMeanFlow /= numFlows; } if (numWaits > 0) { curMeanWait /= numWaits; } float fCurMeanFlow = curMeanFlow; fCurMeanFlow /= waitFlowBalance; // a value smaller than 1 rewards steady traffic currents wait = (float)curMeanWait; flow = fCurMeanFlow; #endif #if TRACE Singleton <CodeProfiler> .instance.Stop("TimedTrafficLightsStep.calcWaitFlow"); #endif return(true); }
public void SimulationStep() { // TODO [version 1.9] this method is currently called on each node, but should be called on the master node only if (!IsMasterNode() || !IsStarted()) { #if DEBUGTTL Log._Debug($"TTL SimStep: *STOP* NodeId={NodeId} isMasterNode={isMasterNode()} IsStarted={IsStarted()}"); #endif return; } // we are the master node /*if (!housekeeping()) { #if DEBUGTTL * Log.Warning($"TTL SimStep: *STOP* NodeId={NodeId} Housekeeping detected that this timed traffic light has become invalid: {NodeId}."); #endif * Stop(); * return; * }*/ #if DEBUGTTL Log._Debug($"TTL SimStep: NodeId={NodeId} Setting lights (1)"); #endif SetLights(); if (!Steps[CurrentStep].StepDone(true)) { #if DEBUGTTL Log._Debug($"TTL SimStep: *STOP* NodeId={NodeId} current step ({CurrentStep}) is not done."); #endif return; } // step is done #if DEBUGTTL Log._Debug($"TTL SimStep: NodeId={NodeId} Setting lights (2)"); #endif #if DEBUG bool debug = GlobalConfig.Instance.DebugSwitches[7] && GlobalConfig.Instance.TTLDebugNodeId == NodeId; #endif TrafficLightSimulationManager tlsMan = TrafficLightSimulationManager.Instance; if (Steps[CurrentStep].NextStepRefIndex < 0) { #if DEBUG if (debug) { Log._Debug($"Step {CurrentStep} is done at timed light {NodeId}. Determining next step."); } #endif // next step has not yet identified yet. check for minTime=0 steps int nextStepIndex = (CurrentStep + 1) % NumSteps(); if (Steps[nextStepIndex].minTime == 0) { // next step has minTime=0. calculate flow/wait ratios and compare. int prevStepIndex = CurrentStep; float maxWaitFlowDiff = Steps[CurrentStep].minFlow - Steps[CurrentStep].maxWait; if (float.IsNaN(maxWaitFlowDiff)) { maxWaitFlowDiff = float.MinValue; } int bestNextStepIndex = prevStepIndex; #if DEBUG if (debug) { Log._Debug($"Next step {nextStepIndex} has minTime = 0 at timed light {NodeId}. Old step {CurrentStep} has waitFlowDiff={maxWaitFlowDiff} (flow={Steps[CurrentStep].minFlow}, wait={Steps[CurrentStep].maxWait})."); } #endif while (nextStepIndex != prevStepIndex) { float wait; float flow; Steps[nextStepIndex].calcWaitFlow(false, nextStepIndex, out wait, out flow); float flowWaitDiff = flow - wait; if (flowWaitDiff > maxWaitFlowDiff) { maxWaitFlowDiff = flowWaitDiff; bestNextStepIndex = nextStepIndex; } #if DEBUG if (debug) { Log._Debug($"Checking upcoming step {nextStepIndex} @ node {NodeId}: flow={flow} wait={wait} minTime={Steps[nextStepIndex].minTime}. bestWaitFlowDiff={bestNextStepIndex}, bestNextStepIndex={bestNextStepIndex}"); } #endif if (Steps[nextStepIndex].minTime != 0) { break; } nextStepIndex = (nextStepIndex + 1) % NumSteps(); } if (bestNextStepIndex == CurrentStep) { #if DEBUG if (debug) { Log._Debug($"Best next step {bestNextStepIndex} (wait/flow diff = {maxWaitFlowDiff}) equals CurrentStep @ node {NodeId}."); } #endif // restart the current step foreach (ushort slaveNodeId in NodeGroup) { TrafficLightSimulation slaveSim = tlsMan.GetNodeSimulation(slaveNodeId); if (slaveSim == null || !slaveSim.IsTimedLight()) { continue; } slaveSim.TimedLight.Steps[CurrentStep].Start(CurrentStep); slaveSim.TimedLight.Steps[CurrentStep].UpdateLiveLights(); } return; } else { #if DEBUG if (debug) { Log._Debug($"Best next step {bestNextStepIndex} (wait/flow diff = {maxWaitFlowDiff}) does not equal CurrentStep @ node {NodeId}."); } #endif // set next step reference index for assuring a correct end transition foreach (ushort slaveNodeId in NodeGroup) { TrafficLightSimulation slaveSim = tlsMan.GetNodeSimulation(slaveNodeId); if (slaveSim == null || !slaveSim.IsTimedLight()) { continue; } TimedTrafficLights timedLights = slaveSim.TimedLight; timedLights.Steps[CurrentStep].NextStepRefIndex = bestNextStepIndex; } } } else { Steps[CurrentStep].NextStepRefIndex = nextStepIndex; } } SetLights(); // check if this is needed if (!Steps[CurrentStep].IsEndTransitionDone()) { #if DEBUGTTL Log._Debug($"TTL SimStep: *STOP* NodeId={NodeId} current step ({CurrentStep}): end transition is not done."); #endif return; } // ending transition (yellow) finished #if DEBUGTTL Log._Debug($"TTL SimStep: NodeId={NodeId} ending transition done. NodeGroup={string.Join(", ", NodeGroup.Select(x => x.ToString()).ToArray())}, nodeId={NodeId}, NumSteps={NumSteps()}"); #endif // change step int newStepIndex = Steps[CurrentStep].NextStepRefIndex; int oldStepIndex = CurrentStep; foreach (ushort slaveNodeId in NodeGroup) { TrafficLightSimulation slaveSim = tlsMan.GetNodeSimulation(slaveNodeId); if (slaveSim == null || !slaveSim.IsTimedLight()) { continue; } TimedTrafficLights timedLights = slaveSim.TimedLight; timedLights.CurrentStep = newStepIndex; #if DEBUGTTL Log._Debug($"TTL SimStep: NodeId={slaveNodeId} setting lgihts of next step: {CurrentStep}"); #endif timedLights.Steps[oldStepIndex].NextStepRefIndex = -1; timedLights.Steps[newStepIndex].Start(oldStepIndex); timedLights.Steps[newStepIndex].UpdateLiveLights(); } }