Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MESegment.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @date Tue, May 2005
17 : ///
18 : // A single mesoscopic segment (cell)
19 : /****************************************************************************/
20 : #include <config.h>
21 :
22 : #include <algorithm>
23 : #include <limits>
24 : #include <utils/common/StdDefs.h>
25 : #include <microsim/MSGlobals.h>
26 : #include <microsim/MSEdge.h>
27 : #include <microsim/MSJunction.h>
28 : #include <microsim/MSNet.h>
29 : #include <microsim/MSLane.h>
30 : #include <microsim/MSLink.h>
31 : #include <microsim/MSMoveReminder.h>
32 : #include <microsim/traffic_lights/MSTrafficLightLogic.h>
33 : #include <microsim/traffic_lights/MSDriveWay.h>
34 : #include <microsim/traffic_lights/MSRailSignalControl.h>
35 : #include <microsim/output/MSXMLRawOut.h>
36 : #include <microsim/output/MSDetectorFileOutput.h>
37 : #include <microsim/MSVehicleControl.h>
38 : #include <microsim/devices/MSDevice.h>
39 : #include <utils/common/FileHelpers.h>
40 : #include <utils/common/MsgHandler.h>
41 : #include <utils/iodevices/OutputDevice.h>
42 : #include <utils/common/RandHelper.h>
43 : #include "MEVehicle.h"
44 : #include "MELoop.h"
45 : #include "MESegment.h"
46 :
47 : #define DEFAULT_VEH_LENGTH_WITH_GAP (SUMOVTypeParameter::getDefault().length + SUMOVTypeParameter::getDefault().minGap)
48 : // avoid division by zero when driving very slowly
49 : #define MESO_MIN_SPEED (0.05)
50 :
51 : //#define DEBUG_OPENED
52 : //#define DEBUG_JAMTHRESHOLD
53 : //#define DEBUG_COND (getID() == "blocker")
54 : //#define DEBUG_COND (true)
55 : #define DEBUG_COND (myEdge.isSelected())
56 : #define DEBUG_COND2(obj) ((obj != 0 && (obj)->isSelected()))
57 :
58 :
59 : // ===========================================================================
60 : // static member definition
61 : // ===========================================================================
62 : MSEdge MESegment::myDummyParent("MESegmentDummyParent", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", "", -1, 0);
63 : MESegment MESegment::myVaporizationTarget("vaporizationTarget");
64 : const double MESegment::DO_NOT_PATCH_JAM_THRESHOLD(std::numeric_limits<double>::max());
65 : const std::string MESegment::OVERRIDE_TLS_PENALTIES("meso.tls.control");
66 :
67 :
68 : // ===========================================================================
69 : // MESegment::Queue method definitions
70 : // ===========================================================================
71 : MEVehicle*
72 26678510 : MESegment::Queue::remove(MEVehicle* v) {
73 26678510 : myOccupancy -= v->getVehicleType().getLengthWithGap();
74 : assert(std::find(myVehicles.begin(), myVehicles.end(), v) != myVehicles.end());
75 26678510 : if (v == myVehicles.back()) {
76 : myVehicles.pop_back();
77 26672231 : if (myVehicles.empty()) {
78 8446821 : myOccupancy = 0.;
79 : } else {
80 18225410 : return myVehicles.back();
81 : }
82 : } else {
83 6279 : myVehicles.erase(std::find(myVehicles.begin(), myVehicles.end(), v));
84 : }
85 : return nullptr;
86 : }
87 :
88 : void
89 132203 : MESegment::Queue::addDetector(MSMoveReminder* data) {
90 132203 : myDetectorData.push_back(data);
91 137953 : for (MEVehicle* const v : myVehicles) {
92 5750 : v->addReminder(data);
93 : }
94 132203 : }
95 :
96 : void
97 26720154 : MESegment::Queue::addReminders(MEVehicle* veh) const {
98 36354252 : for (MSMoveReminder* rem : myDetectorData) {
99 9634098 : veh->addReminder(rem);
100 : }
101 26720154 : }
102 :
103 : // ===========================================================================
104 : // MESegment method definitions
105 : // ===========================================================================
106 726670 : MESegment::MESegment(const std::string& id,
107 : const MSEdge& parent, MESegment* next,
108 : const double length, const double speed,
109 : const int idx,
110 : const bool multiQueue,
111 726670 : const MesoEdgeType& edgeType):
112 726670 : Named(id), myEdge(parent), myNextSegment(next),
113 726670 : myLength(length), myIndex(idx),
114 726670 : myTau_length(TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, speed)),
115 726670 : myNumVehicles(0),
116 726670 : myLastHeadway(TIME2STEPS(-1)),
117 726670 : myMeanSpeed(speed),
118 1453013 : myLastMeanSpeedUpdate(SUMOTime_MIN) {
119 :
120 : const std::vector<MSLane*>& lanes = parent.getLanes();
121 : int usableLanes = 0;
122 1578603 : for (MSLane* const l : lanes) {
123 851933 : const SVCPermissions allow = MSEdge::getMesoPermissions(l->getPermissions());
124 851933 : if (multiQueue) {
125 111240 : myQueues.push_back(Queue(allow));
126 : }
127 851933 : if (allow != 0) {
128 798274 : usableLanes++;
129 : }
130 : }
131 726670 : if (usableLanes == 0) {
132 : // cars won't drive here. Give sensible tau values capacity for the ignored classes
133 : usableLanes = 1;
134 : }
135 726670 : if (multiQueue) {
136 23691 : if (next == nullptr) {
137 110079 : for (const MSEdge* const edge : parent.getSuccessors()) {
138 86733 : if (edge->isTazConnector()) {
139 284 : continue;
140 : }
141 86449 : const std::vector<MSLane*>* const allowed = parent.allowedLanes(*edge);
142 : assert(allowed != nullptr);
143 : assert(allowed->size() > 0);
144 180879 : for (MSLane* const l : *allowed) {
145 94430 : std::vector<MSLane*>::const_iterator it = std::find(lanes.begin(), lanes.end(), l);
146 94430 : myFollowerMap[edge] |= (1 << distance(lanes.begin(), it));
147 : }
148 : }
149 : }
150 23691 : myQueueCapacity = length;
151 : } else {
152 1405958 : myQueues.push_back(Queue(parent.getPermissions()));
153 : }
154 :
155 726670 : initSegment(edgeType, parent, length * usableLanes);
156 726670 : }
157 :
158 : void
159 726670 : MESegment::initSegment(const MesoEdgeType& edgeType, const MSEdge& parent, const double capacity) {
160 :
161 726670 : myCapacity = capacity;
162 726670 : if (myQueues.size() == 1) {
163 703453 : const double laneScale = capacity / myLength;
164 703453 : myQueueCapacity = capacity;
165 703453 : myTau_length = TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, myMeanSpeed) / laneScale;
166 : // Eissfeldt p. 90 and 151 ff.
167 703453 : myTau_ff = (SUMOTime)((double)edgeType.tauff / laneScale);
168 703453 : myTau_fj = (SUMOTime)((double)edgeType.taufj / laneScale);
169 703453 : myTau_jf = (SUMOTime)((double)edgeType.taujf / laneScale);
170 703453 : myTau_jj = (SUMOTime)((double)edgeType.taujj / laneScale);
171 : } else {
172 23217 : myTau_ff = edgeType.tauff;
173 23217 : myTau_fj = edgeType.taufj;
174 23217 : myTau_jf = edgeType.taujf;
175 23217 : myTau_jj = edgeType.taujj;
176 : }
177 :
178 726670 : myJunctionControl = myNextSegment == nullptr && (edgeType.junctionControl || MELoop::isEnteringRoundabout(parent));
179 725894 : myTLSPenalty = ((edgeType.tlsPenalty > 0 || edgeType.tlsFlowPenalty > 0) &&
180 : // only apply to the last segment of a tls-controlled edge
181 727030 : myNextSegment == nullptr && (
182 298 : parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT ||
183 298 : parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION ||
184 : parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED));
185 :
186 : // only apply to the last segment of an uncontrolled edge that has at least 1 minor link
187 1453660 : myCheckMinorPenalty = (edgeType.minorPenalty > 0 &&
188 320 : myNextSegment == nullptr &&
189 : parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT &&
190 : parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION &&
191 726848 : parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
192 178 : parent.hasMinorLink());
193 726670 : myMinorPenalty = edgeType.minorPenalty;
194 726670 : myOvertaking = edgeType.overtaking && myCapacity > myLength;
195 :
196 : //std::cout << getID() << " myMinorPenalty=" << myMinorPenalty << " myTLSPenalty=" << myTLSPenalty << " myJunctionControl=" << myJunctionControl << " myOvertaking=" << myOvertaking << "\n";
197 :
198 726670 : recomputeJamThreshold(edgeType.jamThreshold);
199 726670 : }
200 :
201 45570 : MESegment::MESegment(const std::string& id):
202 : Named(id),
203 45570 : myEdge(myDummyParent), // arbitrary edge needed to supply the needed reference
204 45570 : myNextSegment(nullptr), myLength(0), myIndex(0),
205 45570 : myTau_ff(0), myTau_fj(0), myTau_jf(0), myTau_jj(0),
206 45570 : myTLSPenalty(false),
207 45570 : myCheckMinorPenalty(false),
208 45570 : myMinorPenalty(0),
209 45570 : myJunctionControl(false),
210 45570 : myOvertaking(false),
211 45570 : myTau_length(1) {
212 45570 : }
213 :
214 :
215 : void
216 2467 : MESegment::updatePermissions() {
217 2467 : if (myQueues.size() > 1) {
218 64 : for (MSLane* lane : myEdge.getLanes()) {
219 48 : myQueues[lane->getIndex()].setPermissions(lane->getPermissions());
220 : }
221 : } else {
222 2451 : myQueues.back().setPermissions(myEdge.getPermissions());
223 : }
224 2467 : }
225 :
226 :
227 : void
228 727714 : MESegment::recomputeJamThreshold(double jamThresh) {
229 727714 : if (jamThresh == DO_NOT_PATCH_JAM_THRESHOLD) {
230 : return;
231 : }
232 727714 : if (jamThresh < 0) {
233 : // compute based on speed
234 727702 : myJamThreshold = jamThresholdForSpeed(myEdge.getSpeedLimit(), jamThresh);
235 : } else {
236 : // compute based on specified percentage
237 12 : myJamThreshold = jamThresh * myCapacity;
238 : }
239 : }
240 :
241 :
242 : double
243 4954321 : MESegment::jamThresholdForSpeed(double speed, double jamThresh) const {
244 : // vehicles driving freely at maximum speed should not jam
245 : // we compute how many vehicles could possible enter the segment until the first vehicle leaves
246 : // and multiply by the space these vehicles would occupy
247 : // the jamThresh parameter is scale the resulting value
248 4954321 : if (speed == 0) {
249 : return std::numeric_limits<double>::max(); // never jam. Irrelevant at speed 0 anyway
250 : }
251 : #ifdef DEBUG_JAMTHRESHOLD
252 : if (true || DEBUG_COND) {
253 : std::cout << "jamThresholdForSpeed seg=" << getID() << " speed=" << speed << " jamThresh=" << jamThresh << " ffVehs=" << std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGTH_WITH_GAP)))) << " thresh=" << std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGTH_WITH_GAP)))) * DEFAULT_VEH_LENGTH_WITH_GAP
254 : << "\n";
255 : }
256 : #endif
257 4954102 : return std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGTH_WITH_GAP, 1.)))) * DEFAULT_VEH_LENGTH_WITH_GAP;
258 : }
259 :
260 :
261 : void
262 128871 : MESegment::addDetector(MSMoveReminder* data, int queueIndex) {
263 128871 : if (queueIndex == -1) {
264 254480 : for (Queue& q : myQueues) {
265 128906 : q.addDetector(data);
266 : }
267 : } else {
268 : assert(queueIndex < (int)myQueues.size());
269 3297 : myQueues[queueIndex].addDetector(data);
270 : }
271 128871 : }
272 :
273 :
274 : /*
275 : void
276 : MESegment::removeDetector(MSMoveReminder* data) {
277 : std::vector<MSMoveReminder*>::iterator it = std::find(myDetectorData.begin(), myDetectorData.end(), data);
278 : if (it != myDetectorData.end()) {
279 : myDetectorData.erase(it);
280 : }
281 : for (const Queue& q : myQueues) {
282 : for (MEVehicle* const v : q.getVehicles()) {
283 : v->removeReminder(data);
284 : }
285 : }
286 : }
287 : */
288 :
289 :
290 : void
291 6424230 : MESegment::prepareDetectorForWriting(MSMoveReminder& data, int queueIndex) {
292 6424230 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
293 6424230 : if (queueIndex == -1) {
294 12873040 : for (const Queue& q : myQueues) {
295 : SUMOTime earliestExitTime = currentTime;
296 7749258 : for (std::vector<MEVehicle*>::const_reverse_iterator i = q.getVehicles().rbegin(); i != q.getVehicles().rend(); ++i) {
297 1299848 : const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
298 1299848 : (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
299 1299848 : earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
300 : }
301 : }
302 : } else {
303 : SUMOTime earliestExitTime = currentTime;
304 612 : for (std::vector<MEVehicle*>::const_reverse_iterator i = myQueues[queueIndex].getVehicles().rbegin(); i != myQueues[queueIndex].getVehicles().rend(); ++i) {
305 12 : const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
306 12 : (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
307 12 : earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
308 : }
309 : }
310 6424230 : }
311 :
312 :
313 : SUMOTime
314 141798034 : MESegment::hasSpaceFor(const MEVehicle* const veh, const SUMOTime entryTime, int& qIdx, const bool init) const {
315 : SUMOTime earliestEntry = SUMOTime_MAX;
316 141798034 : qIdx = 0;
317 141798034 : if (myNumVehicles == 0 && myQueues.size() == 1) {
318 : // we have always space for at least one vehicle
319 27668666 : if (myQueues.front().allows(veh->getVClass())) {
320 : return entryTime;
321 : } else {
322 : return earliestEntry;
323 : }
324 : }
325 114129368 : const SUMOVehicleClass svc = veh->getVClass();
326 : int minSize = std::numeric_limits<int>::max();
327 114839909 : const MSEdge* const succ = myNextSegment == nullptr ? veh->succEdge(veh->getEdge() == &myEdge ? 1 : 2) : nullptr;
328 300907373 : for (int i = 0; i < (int)myQueues.size(); i++) {
329 186778005 : const Queue& q = myQueues[i];
330 186778005 : const double newOccupancy = q.size() == 0 ? 0. : q.getOccupancy() + veh->getVehicleType().getLengthWithGap();
331 186778005 : if (newOccupancy <= myQueueCapacity) { // we must ensure that occupancy remains below capacity
332 60546231 : if (succ == nullptr || myFollowerMap.count(succ) == 0 || ((myFollowerMap.find(succ)->second & (1 << i)) != 0)) {
333 41748349 : if (q.allows(svc) && q.size() < minSize) {
334 26536870 : if (init) {
335 : // regular insertions and initial insertions must respect different constraints:
336 8208785 : if (veh->getInsertionChecks() == (int)InsertionCheck::NONE || hasSpaceForInsertion(q, i, newOccupancy, entryTime)) {
337 4974412 : qIdx = i;
338 : minSize = q.size();
339 : }
340 18328085 : } else if (entryTime >= q.getEntryBlockTime()) {
341 18059895 : qIdx = i;
342 : minSize = q.size();
343 : } else {
344 : earliestEntry = MIN2(earliestEntry, q.getEntryBlockTime());
345 : }
346 : }
347 : }
348 : }
349 : }
350 114129368 : if (minSize == std::numeric_limits<int>::max()) {
351 : return earliestEntry;
352 : }
353 : return entryTime;
354 : }
355 :
356 :
357 : bool
358 8208741 : MESegment::hasSpaceForInsertion(const Queue& q, int /*qIdx*/, double newOccupancy, SUMOTime /*entryTime*/) const {
359 : // - regular insertions must respect entryBlockTime
360 : // - initial insertions should not cause additional jamming
361 : // - inserted vehicle should be able to continue at the current speed
362 8208741 : if (q.getOccupancy() <= myJamThreshold && !hasBlockedLeader() && !myTLSPenalty) {
363 3982122 : return newOccupancy <= myJamThreshold;
364 : } else {
365 4226619 : return newOccupancy <= jamThresholdForSpeed(getMeanSpeed(false), -1);
366 : }
367 : }
368 :
369 :
370 : bool
371 11090777 : MESegment::initialise(MEVehicle* veh, SUMOTime time) {
372 11090777 : int qIdx = 0;
373 11090777 : if (hasSpaceFor(veh, time, qIdx, true) == time) {
374 9177598 : const bool isRail = veh->isRail();
375 : // see MSLane::isInsertionSuccess
376 8348207 : if (isRail && veh->getInsertionChecks() != (int)InsertionCheck::NONE
377 8348188 : && veh->getParameter().departProcedure != DepartDefinition::SPLIT
378 8348188 : && MSRailSignalControl::isSignalized(veh->getVClass())
379 17525777 : && isRailwayOrShared(myEdge.getPermissions())) {
380 8348173 : const MSDriveWay* dw = MSDriveWay::getDepartureDriveway(veh);
381 : MSEdgeVector occupied;
382 8348173 : if (dw->foeDriveWayOccupied(false, veh, occupied)) {
383 8345975 : myEdge.getLanes()[0]->setParameter("insertionBlocked:" + veh->getID(), dw->getID());
384 : return false;
385 : }
386 8348173 : }
387 831623 : receive(veh, qIdx, time, true);
388 831623 : if (isRail) {
389 4464 : myEdge.getLanes()[0]->unsetParameter("insertionConstraint:" + veh->getID());
390 : //unsetParameter("insertionOrder:" + veh->getID());
391 : //unsetParameter("insertionBlocked:" + veh->getID());
392 : //// rail_signal (not traffic_light) requires approach information for
393 : //// switching correctly at the start of the next simulation step
394 : //if (firstRailSignal != nullptr && firstRailSignal->getJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
395 : // veh->registerInsertionApproach(firstRailSignal, firstRailSignalDist);
396 : //}
397 : }
398 : // we can check only after insertion because insertion may change the route via devices
399 : std::string msg;
400 1662498 : if (MSGlobals::gCheckRoutes && !veh->hasValidRoute(msg)) {
401 6 : throw ProcessError(TLF("Vehicle '%' has no valid route. %", veh->getID(), msg));
402 : }
403 : return true;
404 : }
405 : return false;
406 : }
407 :
408 :
409 : double
410 29689648 : MESegment::getMeanSpeed(bool useCached) const {
411 29689648 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
412 29689648 : if (currentTime != myLastMeanSpeedUpdate || !useCached) {
413 29587310 : myLastMeanSpeedUpdate = currentTime;
414 : double v = 0;
415 : int count = 0;
416 61339349 : for (const Queue& q : myQueues) {
417 31752039 : const SUMOTime tau = q.getOccupancy() < myJamThreshold ? myTau_ff : myTau_jf;
418 31752039 : SUMOTime earliestExitTime = currentTime;
419 31752039 : count += q.size();
420 186424901 : for (std::vector<MEVehicle*>::const_reverse_iterator veh = q.getVehicles().rbegin(); veh != q.getVehicles().rend(); ++veh) {
421 154672862 : v += (*veh)->getConservativeSpeed(earliestExitTime); // earliestExitTime is updated!
422 154672862 : earliestExitTime += tauWithVehLength(tau, (*veh)->getVehicleType().getLengthWithGap(), (*veh)->getVehicleType().getCarFollowModel().getHeadwayTime());
423 : }
424 : }
425 29587310 : if (count == 0) {
426 30 : myMeanSpeed = myEdge.getSpeedLimit();
427 : } else {
428 29587280 : myMeanSpeed = v / (double) count;
429 : }
430 : }
431 29689648 : return myMeanSpeed;
432 : }
433 :
434 :
435 : void
436 5226 : MESegment::resetCachedSpeeds() {
437 5226 : myLastMeanSpeedUpdate = SUMOTime_MIN;
438 5226 : }
439 :
440 : void
441 11953 : MESegment::writeVehicles(OutputDevice& of) const {
442 24082 : for (const Queue& q : myQueues) {
443 14162 : for (const MEVehicle* const veh : q.getVehicles()) {
444 2033 : MSXMLRawOut::writeVehicle(of, *veh);
445 : }
446 : }
447 11953 : }
448 :
449 :
450 : MEVehicle*
451 26678510 : MESegment::removeCar(MEVehicle* v, SUMOTime leaveTime, const MSMoveReminder::Notification reason) {
452 26678510 : Queue& q = myQueues[v->getQueIndex()];
453 : // One could be tempted to do v->setSegment(next); here but position on lane will be invalid if next == 0
454 26678510 : v->updateDetectors(leaveTime, v->getEventTime(), true, reason);
455 26678510 : myNumVehicles--;
456 26678510 : myEdge.lock();
457 26678510 : MEVehicle* nextLeader = q.remove(v);
458 26678510 : myEdge.invalidateMesoCache();
459 26678510 : myEdge.unlock();
460 26678510 : return nextLeader;
461 : }
462 :
463 :
464 : SUMOTime
465 13655 : MESegment::getNextInsertionTime(SUMOTime earliestEntry) const {
466 : // since we do not know which queue will be used we give a conservative estimate
467 : SUMOTime earliestLeave = earliestEntry;
468 : SUMOTime latestEntry = -1;
469 27575 : for (const Queue& q : myQueues) {
470 : earliestLeave = MAX2(earliestLeave, q.getBlockTime());
471 : latestEntry = MAX2(latestEntry, q.getEntryBlockTime());
472 : }
473 13655 : if (myEdge.getSpeedLimit() == 0) {
474 12 : return MAX2(earliestEntry, latestEntry); // FIXME: This line is just an adhoc-fix to avoid division by zero (Leo)
475 : } else {
476 13643 : return MAX3(earliestEntry, earliestLeave - TIME2STEPS(myLength / myEdge.getSpeedLimit()), latestEntry);
477 : }
478 : }
479 :
480 :
481 : MSLink*
482 127359115 : MESegment::getLink(const MEVehicle* veh, bool penalty) const {
483 127359115 : if (myJunctionControl || penalty) {
484 29815382 : const MSEdge* const nextEdge = veh->succEdge(1);
485 29815382 : if (nextEdge == nullptr || veh->getQueIndex() == PARKING_QUEUE) {
486 : return nullptr;
487 : }
488 : // try to find any link leading to our next edge, start with the lane pointed to by the que index
489 28494260 : const MSLane* const bestLane = myEdge.getLanes()[veh->getQueIndex()];
490 32786366 : for (MSLink* const link : bestLane->getLinkCont()) {
491 32373383 : if (&link->getLane()->getEdge() == nextEdge) {
492 : return link;
493 : }
494 : }
495 : // this is for the non-multique case, maybe we should use caching here !!!
496 937268 : for (const MSLane* const lane : myEdge.getLanes()) {
497 920613 : if (lane != bestLane) {
498 640140 : for (MSLink* const link : lane->getLinkCont()) {
499 527074 : if (&link->getLane()->getEdge() == nextEdge) {
500 : return link;
501 : }
502 : }
503 : }
504 : }
505 : }
506 : return nullptr;
507 : }
508 :
509 :
510 : bool
511 35175592 : MESegment::isOpen(const MEVehicle* veh) const {
512 : #ifdef DEBUG_OPENED
513 : if (DEBUG_COND || DEBUG_COND2(veh)) {
514 : gDebugFlag1 = true;
515 : std::cout << SIMTIME << " opened seg=" << getID() << " veh=" << Named::getIDSecure(veh)
516 : << " tlsPenalty=" << myTLSPenalty;
517 : const MSLink* link = getLink(veh);
518 : if (link == 0) {
519 : std::cout << " link=0";
520 : } else {
521 : std::cout << " prio=" << link->havePriority()
522 : << " override=" << limitedControlOverride(link)
523 : << " isOpen=" << link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
524 : veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
525 : veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime(),
526 : 0, nullptr, false, veh)
527 : << " et=" << veh->getEventTime()
528 : << " v=" << veh->getSpeed()
529 : << " vLeave=" << veh->estimateLeaveSpeed(link)
530 : << " impatience=" << veh->getImpatience()
531 : << " tWait=" << veh->getWaitingTime();
532 : }
533 : std::cout << "\n";
534 : gDebugFlag1 = false;
535 : }
536 : #endif
537 35175592 : if (myTLSPenalty) {
538 : // XXX should limited control take precedence over tls penalty?
539 : return true;
540 : }
541 35123444 : const MSLink* link = getLink(veh);
542 : return (link == nullptr
543 11331258 : || link->havePriority()
544 9592541 : || limitedControlOverride(link)
545 44715221 : || link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
546 9591777 : veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
547 9591777 : veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime(),
548 : 0, nullptr, false, veh));
549 : }
550 :
551 :
552 : bool
553 9595731 : MESegment::limitedControlOverride(const MSLink* link) const {
554 : assert(link != nullptr);
555 9595731 : if (!MSGlobals::gMesoLimitedJunctionControl) {
556 : return false;
557 : }
558 : // if the target segment of this link is not saturated junction control is disabled
559 : const MSEdge& targetEdge = link->getLane()->getEdge();
560 8400 : const MESegment* target = MSGlobals::gMesoNet->getSegmentForEdge(targetEdge);
561 8400 : return (target->getBruttoOccupancy() * 2 < target->myJamThreshold) && !targetEdge.isRoundabout();
562 : }
563 :
564 :
565 : SUMOTime
566 25885152 : MESegment::computeHeadway(Queue& /*q*/, const Queue& qNext, const MESegment* const next, const MEVehicle* veh) const {
567 25885152 : const bool nextFree = qNext.getOccupancy() <= next->myJamThreshold;
568 : const SUMOTime tau = (!veh->wasJammed()
569 25885152 : ? (nextFree ? myTau_ff : myTau_fj)
570 726695 : : (nextFree ? myTau_jf : getTauJJ((double)qNext.size(), next->myQueueCapacity, next->myJamThreshold)));
571 : assert(tau >= 0);
572 25885152 : SUMOTime headway = tauWithVehLength(tau, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime());
573 25885152 : if (myTLSPenalty) {
574 52148 : const MSLink* const tllink = getLink(veh, true);
575 52148 : if (tllink != nullptr && tllink->isTLSControlled()) {
576 : assert(tllink->getGreenFraction() > 0);
577 49540 : headway = (SUMOTime)((double)headway / tllink->getGreenFraction());
578 : }
579 : }
580 25885152 : return headway;
581 : }
582 :
583 :
584 : void
585 26678510 : MESegment::send(MEVehicle* veh, MESegment* const next, const int nextQIdx, SUMOTime time, const MSMoveReminder::Notification reason) {
586 26678510 : Queue& q = myQueues[veh->getQueIndex()];
587 : assert(isInvalid(next) || time >= q.getBlockTime());
588 26678510 : MSLink* const link = getLink(veh);
589 26678510 : if (link != nullptr) {
590 2051487 : link->removeApproaching(veh);
591 : }
592 26678510 : if (veh->isStopped()) {
593 8464 : veh->processStop();
594 : }
595 26678510 : MEVehicle* lc = removeCar(veh, time, reason); // new leaderCar
596 : q.setBlockTime(time);
597 26678510 : if (myEdge.isNormal() && myCapacity >= 22.5 ) {
598 20395610 : veh->markJammed(q.getOccupancy() > myJamThreshold);
599 : }
600 : if (!isInvalid(next)) {
601 25885152 : myLastHeadway = computeHeadway(q, next->myQueues[nextQIdx], next, veh);
602 25885152 : q.setBlockTime(time + myLastHeadway);
603 : }
604 26678510 : if (lc != nullptr) {
605 : lc->setEventTime(MAX2(lc->getEventTime(), q.getBlockTime()));
606 18225410 : MSGlobals::gMesoNet->addLeaderCar(lc, getLink(lc));
607 : }
608 26678510 : }
609 :
610 :
611 : SUMOTime
612 191353 : MESegment::getTauJJ(double nextQueueSize, double nextQueueCapacity, double nextJamThreshold) const {
613 : // compute coefficients for the jam-jam headway function
614 : // this function models the effect that "empty space" needs to move
615 : // backwards through the downstream segment before the upstream segment may
616 : // send annother vehicle.
617 : // this allows jams to clear and move upstream.
618 : // the headway function f(x) depends on the number of vehicles in the
619 : // downstream segment x
620 : // f is a linear function that passes through the following fixed points:
621 : // f(n_jam_threshold) = tau_jf_withLength (for continuity)
622 : // f(headwayCapacity) = myTau_jj * headwayCapacity
623 :
624 191353 : const SUMOTime tau_jf_withLength = tauWithVehLength(myTau_jf, DEFAULT_VEH_LENGTH_WITH_GAP, 1.);
625 : // number of vehicles that fit into the NEXT queue (could be larger than expected with DEFAULT_VEH_LENGTH_WITH_GAP!)
626 191353 : const double headwayCapacity = MAX2(nextQueueSize, nextQueueCapacity / DEFAULT_VEH_LENGTH_WITH_GAP);
627 : // number of vehicles above which the NEXT queue is jammed
628 191353 : const double n_jam_threshold = headwayCapacity * nextJamThreshold / nextQueueCapacity;
629 :
630 : // slope a and axis offset b for the jam-jam headway function
631 : // solving f(x) = a * x + b
632 191353 : const double a = (STEPS2TIME(myTau_jj) * headwayCapacity - STEPS2TIME(tau_jf_withLength)) / (headwayCapacity - n_jam_threshold);
633 191353 : const double b = headwayCapacity * (STEPS2TIME(myTau_jj) - a);
634 :
635 : // it is only well defined for nextQueueSize >= n_jam_threshold (which may not be the case for longer vehicles), so we take the MAX
636 191353 : return TIME2STEPS(a * MAX2(nextQueueSize, n_jam_threshold) + b);
637 : }
638 :
639 :
640 : bool
641 1206806 : MESegment::overtake() {
642 1206830 : return myOvertaking && RandHelper::rand() > (getBruttoOccupancy() / myCapacity);
643 : }
644 :
645 :
646 : void
647 26725962 : MESegment::addReminders(MEVehicle* veh) const {
648 26725962 : if (veh->getQueIndex() != PARKING_QUEUE) {
649 26720154 : myQueues[veh->getQueIndex()].addReminders(veh);
650 : }
651 26725962 : }
652 :
653 :
654 : void
655 26722978 : MESegment::receive(MEVehicle* veh, const int qIdx, SUMOTime time, const bool isDepart, const bool isTeleport, const bool newEdge) {
656 26722978 : const double speed = isDepart ? -1 : MAX2(veh->getSpeed(), MESO_MIN_SPEED); // on the previous segment
657 26722978 : veh->setSegment(this); // for arrival checking
658 : veh->setLastEntryTime(time);
659 : veh->setBlockTime(SUMOTime_MAX);
660 26722978 : if (!isDepart && (
661 : // arrival on entering a new edge
662 5043389 : (newEdge && myEdge.isNormal() && veh->moveRoutePointer())
663 : // arrival on entering a new segment
664 25891196 : || veh->hasArrived())) {
665 : // route has ended
666 15352 : veh->setEventTime(time + TIME2STEPS(myLength / speed)); // for correct arrival speed
667 15352 : addReminders(veh);
668 15352 : veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
669 30600 : veh->updateDetectors(time, veh->getEventTime(), true,
670 15352 : veh->getEdge()->isVaporizing() ? MSMoveReminder::NOTIFICATION_VAPORIZED_VAPORIZER : MSMoveReminder::NOTIFICATION_ARRIVED);
671 15352 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
672 15352 : return;
673 : }
674 : assert(veh->getEdge() == &getEdge() || getEdge().isInternal());
675 : // route continues
676 26707626 : Queue& q = myQueues[qIdx];
677 26707626 : const double maxSpeedOnEdge = veh->getEdge()->getLanes()[qIdx]->getVehicleMaxSpeed(veh);
678 : const double uspeed = MAX2(maxSpeedOnEdge, MESO_MIN_SPEED);
679 : std::vector<MEVehicle*>& cars = q.getModifiableVehicles();
680 : MEVehicle* newLeader = nullptr; // first vehicle in the current queue
681 26707626 : const SUMOTime stopTime = veh->checkStop(time);
682 26707626 : SUMOTime tleave = MAX2(stopTime + TIME2STEPS(myLength / uspeed) + getLinkPenalty(veh), q.getBlockTime());
683 26707626 : if (veh->isStopped()) {
684 14917 : myEdge.addWaiting(veh);
685 : }
686 26707626 : if (veh->isParking()) {
687 : // parking stops should take at least 1ms
688 5808 : veh->setEventTime(MAX2(stopTime, veh->getEventTime() + 1));
689 5808 : veh->setSegment(this, PARKING_QUEUE);
690 5808 : myEdge.getLanes()[0]->addParking(veh); // TODO for GUI only
691 : } else {
692 26701818 : myEdge.lock();
693 26701818 : if (cars.empty()) {
694 8453571 : cars.push_back(veh);
695 : newLeader = veh;
696 : } else {
697 18248247 : SUMOTime leaderOut = cars[0]->getEventTime();
698 18248247 : if (!isDepart && leaderOut > tleave && overtake()) {
699 20 : if (cars.size() == 1) {
700 4 : MSGlobals::gMesoNet->removeLeaderCar(cars[0]);
701 : newLeader = veh;
702 : }
703 20 : cars.insert(cars.begin() + 1, veh);
704 : } else {
705 18248227 : tleave = MAX2(leaderOut + tauWithVehLength(myTau_ff, cars[0]->getVehicleType().getLengthWithGap(), cars[0]->getVehicleType().getCarFollowModel().getHeadwayTime()), tleave);
706 18248227 : cars.insert(cars.begin(), veh);
707 : }
708 : }
709 26701818 : myEdge.invalidateMesoCache();
710 26701818 : myEdge.unlock();
711 26701818 : myNumVehicles++;
712 26701818 : if (!isDepart && !isTeleport) {
713 : // departs and teleports could take place anywhere on the edge so they should not block regular flow
714 : // the -1 facilitates interleaving of multiple streams
715 25869720 : q.setEntryBlockTime(time + tauWithVehLength(myTau_ff, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime()) - 1);
716 : }
717 26701818 : q.setOccupancy(MIN2(myQueueCapacity, q.getOccupancy() + veh->getVehicleType().getLengthWithGap()));
718 : veh->setEventTime(tleave);
719 : veh->setUnqueuedEventTime(tleave);
720 26701818 : veh->setSegment(this, qIdx);
721 : }
722 26707626 : addReminders(veh);
723 26707626 : if (isDepart) {
724 831623 : veh->onDepart();
725 831623 : veh->activateReminders(MSMoveReminder::NOTIFICATION_DEPARTED);
726 25876003 : } else if (newEdge) {
727 5043230 : veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
728 : } else {
729 20832773 : veh->activateReminders(MSMoveReminder::NOTIFICATION_SEGMENT);
730 : }
731 26707626 : if (veh->isParking()) {
732 5828 : MSGlobals::gMesoNet->addLeaderCar(veh, nullptr);
733 : } else {
734 26701798 : if (newLeader != nullptr) {
735 8453557 : MSGlobals::gMesoNet->addLeaderCar(newLeader, getLink(newLeader));
736 : }
737 : }
738 : }
739 :
740 :
741 : bool
742 8752 : MESegment::vaporizeAnyCar(SUMOTime currentTime, const MSDetectorFileOutput* filter) {
743 9304 : for (const Queue& q : myQueues) {
744 8778 : if (q.size() > 0) {
745 8226 : for (MEVehicle* const veh : q.getVehicles()) {
746 8226 : if (filter->vehicleApplies(*veh)) {
747 8226 : MSGlobals::gMesoNet->removeLeaderCar(veh);
748 8226 : MSGlobals::gMesoNet->changeSegment(veh, currentTime + 1, &myVaporizationTarget, MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR);
749 : return true;
750 : }
751 : }
752 : }
753 : }
754 : return false;
755 : }
756 :
757 :
758 : void
759 352 : MESegment::setSpeedForQueue(double newSpeed, SUMOTime currentTime, SUMOTime blockTime, const std::vector<MEVehicle*>& vehs) {
760 352 : MEVehicle* v = vehs.back();
761 : SUMOTime oldEarliestExitTime = currentTime;
762 : const SUMOTime oldExit = MAX2(oldEarliestExitTime, v->getEventTime());
763 352 : v->updateDetectors(currentTime, oldExit, false);
764 352 : oldEarliestExitTime = oldExit + tauWithVehLength(myTau_ff, v->getVehicleType().getLengthWithGap(), v->getVehicleType().getCarFollowModel().getHeadwayTime());
765 352 : SUMOTime newEvent = MAX2(newArrival(v, newSpeed, currentTime), blockTime);
766 352 : if (v->getEventTime() != newEvent) {
767 330 : MSGlobals::gMesoNet->removeLeaderCar(v);
768 : v->setEventTime(newEvent);
769 330 : MSGlobals::gMesoNet->addLeaderCar(v, getLink(v));
770 : }
771 1075 : for (std::vector<MEVehicle*>::const_reverse_iterator i = vehs.rbegin() + 1; i != vehs.rend(); ++i) {
772 723 : const SUMOTime oldExitTime = MAX2(oldEarliestExitTime, (*i)->getEventTime());
773 723 : (*i)->updateDetectors(currentTime, oldExitTime, false);
774 723 : const SUMOTime minTau = tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
775 723 : oldEarliestExitTime = oldExitTime + minTau;
776 723 : newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + minTau);
777 723 : (*i)->setEventTime(newEvent);
778 : }
779 352 : }
780 :
781 :
782 : SUMOTime
783 1075 : MESegment::newArrival(const MEVehicle* const v, double newSpeed, SUMOTime currentTime) {
784 : // since speed is only an upper bound, pos may be too optimistic
785 1075 : const double pos = MIN2(myLength, STEPS2TIME(currentTime - v->getLastEntryTime()) * v->getSpeed());
786 : // traveltime may not be 0
787 1075 : double tt = (myLength - pos) / MAX2(newSpeed, MESO_MIN_SPEED);
788 1075 : return currentTime + MAX2(TIME2STEPS(tt), SUMOTime(1));
789 : }
790 :
791 :
792 : void
793 1044 : MESegment::setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh, int qIdx) {
794 1044 : recomputeJamThreshold(jamThresh);
795 : //myTau_length = MAX2(MESO_MIN_SPEED, newSpeed) * myEdge.getLanes().size() / TIME2STEPS(1);
796 : int i = 0;
797 2182 : for (const Queue& q : myQueues) {
798 1138 : if (q.size() != 0) {
799 386 : if (qIdx == -1 || qIdx == i) {
800 352 : setSpeedForQueue(newSpeed, currentTime, q.getBlockTime(), q.getVehicles());
801 : }
802 : }
803 1138 : i++;
804 : }
805 1044 : }
806 :
807 :
808 : SUMOTime
809 2081142 : MESegment::getEventTime() const {
810 : SUMOTime result = SUMOTime_MAX;
811 4429759 : for (const Queue& q : myQueues) {
812 2348617 : if (q.size() != 0 && q.getVehicles().back()->getEventTime() < result) {
813 : result = q.getVehicles().back()->getEventTime();
814 : }
815 : }
816 2081142 : if (result < SUMOTime_MAX) {
817 969153 : return result;
818 : }
819 : return -1;
820 : }
821 :
822 :
823 : void
824 11928 : MESegment::saveState(OutputDevice& out) const {
825 : bool write = false;
826 23063 : for (const Queue& q : myQueues) {
827 12407 : if (q.getBlockTime() != -1 || !q.getVehicles().empty()) {
828 : write = true;
829 : break;
830 : }
831 : }
832 11928 : if (write) {
833 1272 : out.openTag(SUMO_TAG_SEGMENT).writeAttr(SUMO_ATTR_ID, getID());
834 2602 : for (const Queue& q : myQueues) {
835 1330 : out.openTag(SUMO_TAG_VIEWSETTINGS_VEHICLES);
836 1330 : out.writeAttr(SUMO_ATTR_TIME, toString<SUMOTime>(q.getBlockTime()));
837 1330 : out.writeAttr(SUMO_ATTR_BLOCKTIME, toString<SUMOTime>(q.getEntryBlockTime()));
838 1330 : out.writeAttr(SUMO_ATTR_VALUE, q.getVehicles());
839 2660 : out.closeTag();
840 : }
841 2544 : out.closeTag();
842 : }
843 11928 : }
844 :
845 :
846 : void
847 398 : MESegment::clearState() {
848 836 : for (Queue& q : myQueues) {
849 : q.getModifiableVehicles().clear();
850 : }
851 398 : }
852 :
853 : void
854 1161 : MESegment::loadState(const std::vector<SUMOVehicle*>& vehs, const SUMOTime blockTime, const SUMOTime entryBlockTime, const int queIdx) {
855 1161 : Queue& q = myQueues[queIdx];
856 1655 : for (SUMOVehicle* veh : vehs) {
857 494 : MEVehicle* v = static_cast<MEVehicle*>(veh);
858 : assert(v->getSegment() == this || myEdge.isInternal());
859 494 : if (myEdge.isInternal()) {
860 13 : v->setSegment(this, v->getQueIndex());
861 : }
862 494 : q.getModifiableVehicles().push_back(v);
863 494 : myNumVehicles++;
864 494 : q.setOccupancy(q.getOccupancy() + v->getVehicleType().getLengthWithGap());
865 494 : addReminders(v);
866 : }
867 1161 : if (q.size() != 0) {
868 : // add the last vehicle of this queue
869 : // !!! one question - what about the previously added vehicle? Is it stored twice?
870 255 : MEVehicle* veh = q.getVehicles().back();
871 255 : MSGlobals::gMesoNet->addLeaderCar(veh, getLink(veh));
872 : }
873 : q.setBlockTime(blockTime);
874 : q.setEntryBlockTime(entryBlockTime);
875 1161 : q.setOccupancy(MIN2(q.getOccupancy(), myQueueCapacity));
876 1161 : }
877 :
878 :
879 : std::vector<const MEVehicle*>
880 122 : MESegment::getVehicles() const {
881 : std::vector<const MEVehicle*> result;
882 316 : for (const Queue& q : myQueues) {
883 194 : result.insert(result.end(), q.getVehicles().begin(), q.getVehicles().end());
884 : }
885 122 : return result;
886 0 : }
887 :
888 :
889 : bool
890 4014415 : MESegment::hasBlockedLeader() const {
891 8081126 : for (const Queue& q : myQueues) {
892 4098730 : if (q.size() > 0 && q.getVehicles().back()->getWaitingTime() > 0) {
893 : return true;
894 : }
895 : }
896 : return false;
897 : }
898 :
899 :
900 : double
901 0 : MESegment::getFlow() const {
902 0 : return 3600 * getCarNumber() * getMeanSpeed() / myLength;
903 : }
904 :
905 :
906 : SUMOTime
907 26707626 : MESegment::getLinkPenalty(const MEVehicle* veh) const {
908 26707626 : const MSLink* link = getLink(veh, myTLSPenalty || myCheckMinorPenalty);
909 26707626 : if (link != nullptr) {
910 : SUMOTime result = 0;
911 2106251 : if (link->isTLSControlled() && myTLSPenalty) {
912 : result += link->getMesoTLSPenalty();
913 : }
914 : // minor tls links may get an additional penalty
915 414409 : if (!link->havePriority() &&
916 : // do not apply penalty on top of tLSPenalty
917 2106251 : !myTLSPenalty &&
918 : // do not apply penalty if limited control is active
919 378527 : (!MSGlobals::gMesoLimitedJunctionControl || limitedControlOverride(link))) {
920 376057 : result += myMinorPenalty;
921 : }
922 2106251 : return result;
923 : } else {
924 : return 0;
925 : }
926 : }
927 :
928 :
929 : double
930 9 : MESegment::getWaitingSeconds() const {
931 : double result = 0;
932 22 : for (const Queue& q : myQueues) {
933 : // @note: only the leader currently accumulates waitingTime but this might change in the future
934 16 : for (const MEVehicle* veh : q.getVehicles()) {
935 3 : result += veh->getWaitingSeconds();
936 : }
937 : }
938 9 : return result;
939 : }
940 :
941 :
942 : /****************************************************************************/
|