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/output/MSXMLRawOut.h>
34 : #include <microsim/output/MSDetectorFileOutput.h>
35 : #include <microsim/MSVehicleControl.h>
36 : #include <microsim/devices/MSDevice.h>
37 : #include <utils/common/FileHelpers.h>
38 : #include <utils/common/MsgHandler.h>
39 : #include <utils/iodevices/OutputDevice.h>
40 : #include <utils/common/RandHelper.h>
41 : #include "MEVehicle.h"
42 : #include "MELoop.h"
43 : #include "MESegment.h"
44 :
45 : #define DEFAULT_VEH_LENGTH_WITH_GAP (SUMOVTypeParameter::getDefault().length + SUMOVTypeParameter::getDefault().minGap)
46 : // avoid division by zero when driving very slowly
47 : #define MESO_MIN_SPEED (0.05)
48 :
49 : //#define DEBUG_OPENED
50 : //#define DEBUG_JAMTHRESHOLD
51 : //#define DEBUG_COND (getID() == "blocker")
52 : //#define DEBUG_COND (true)
53 : #define DEBUG_COND (myEdge.isSelected())
54 : #define DEBUG_COND2(obj) ((obj != 0 && (obj)->isSelected()))
55 :
56 :
57 : // ===========================================================================
58 : // static member definition
59 : // ===========================================================================
60 : MSEdge MESegment::myDummyParent("MESegmentDummyParent", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", "", -1, 0);
61 : MESegment MESegment::myVaporizationTarget("vaporizationTarget");
62 : const double MESegment::DO_NOT_PATCH_JAM_THRESHOLD(std::numeric_limits<double>::max());
63 : const std::string MESegment::OVERRIDE_TLS_PENALTIES("meso.tls.control");
64 :
65 :
66 : // ===========================================================================
67 : // MESegment::Queue method definitions
68 : // ===========================================================================
69 : MEVehicle*
70 26003076 : MESegment::Queue::remove(MEVehicle* v) {
71 26003076 : myOccupancy -= v->getVehicleType().getLengthWithGap();
72 : assert(std::find(myVehicles.begin(), myVehicles.end(), v) != myVehicles.end());
73 26003076 : if (v == myVehicles.back()) {
74 : myVehicles.pop_back();
75 25996797 : if (myVehicles.empty()) {
76 8258289 : myOccupancy = 0.;
77 : } else {
78 17738508 : return myVehicles.back();
79 : }
80 : } else {
81 6279 : myVehicles.erase(std::find(myVehicles.begin(), myVehicles.end(), v));
82 : }
83 : return nullptr;
84 : }
85 :
86 : void
87 128426 : MESegment::Queue::addDetector(MSMoveReminder* data) {
88 128426 : myDetectorData.push_back(data);
89 134176 : for (MEVehicle* const v : myVehicles) {
90 5750 : v->addReminder(data);
91 : }
92 128426 : }
93 :
94 : void
95 26041787 : MESegment::Queue::addReminders(MEVehicle* veh) const {
96 35545732 : for (MSMoveReminder* rem : myDetectorData) {
97 9503945 : veh->addReminder(rem);
98 : }
99 26041787 : }
100 :
101 : // ===========================================================================
102 : // MESegment method definitions
103 : // ===========================================================================
104 684834 : MESegment::MESegment(const std::string& id,
105 : const MSEdge& parent, MESegment* next,
106 : const double length, const double speed,
107 : const int idx,
108 : const bool multiQueue,
109 684834 : const MesoEdgeType& edgeType):
110 684834 : Named(id), myEdge(parent), myNextSegment(next),
111 684834 : myLength(length), myIndex(idx),
112 684834 : myTau_length(TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, speed)),
113 684834 : myNumVehicles(0),
114 684834 : myLastHeadway(TIME2STEPS(-1)),
115 684834 : myMeanSpeed(speed),
116 1369341 : myLastMeanSpeedUpdate(SUMOTime_MIN) {
117 :
118 : const std::vector<MSLane*>& lanes = parent.getLanes();
119 : int usableLanes = 0;
120 1483476 : for (MSLane* const l : lanes) {
121 798642 : const SVCPermissions allow = MSEdge::getMesoPermissions(l->getPermissions());
122 798642 : if (multiQueue) {
123 98520 : myQueues.push_back(Queue(allow));
124 : }
125 798642 : if (allow != 0) {
126 748367 : usableLanes++;
127 : }
128 : }
129 684834 : if (usableLanes == 0) {
130 : // cars won't drive here. Give sensible tau values capacity for the ignored classes
131 : usableLanes = 1;
132 : }
133 684834 : if (multiQueue) {
134 21205 : if (next == nullptr) {
135 98136 : for (const MSEdge* const edge : parent.getSuccessors()) {
136 77276 : if (edge->isTazConnector()) {
137 284 : continue;
138 : }
139 76992 : const std::vector<MSLane*>* const allowed = parent.allowedLanes(*edge);
140 : assert(allowed != nullptr);
141 : assert(allowed->size() > 0);
142 161687 : for (MSLane* const l : *allowed) {
143 84695 : std::vector<MSLane*>::const_iterator it = std::find(lanes.begin(), lanes.end(), l);
144 84695 : myFollowerMap[edge] |= (1 << distance(lanes.begin(), it));
145 : }
146 : }
147 : }
148 21205 : myQueueCapacity = length;
149 : } else {
150 1327258 : myQueues.push_back(Queue(parent.getPermissions()));
151 : }
152 :
153 684834 : initSegment(edgeType, parent, length * usableLanes);
154 684834 : }
155 :
156 : void
157 684834 : MESegment::initSegment(const MesoEdgeType& edgeType, const MSEdge& parent, const double capacity) {
158 :
159 684834 : myCapacity = capacity;
160 684834 : if (myQueues.size() == 1) {
161 664057 : const double laneScale = capacity / myLength;
162 664057 : myQueueCapacity = capacity;
163 664057 : myTau_length = TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, myMeanSpeed) / laneScale;
164 : // Eissfeldt p. 90 and 151 ff.
165 664057 : myTau_ff = (SUMOTime)((double)edgeType.tauff / laneScale);
166 664057 : myTau_fj = (SUMOTime)((double)edgeType.taufj / laneScale);
167 664057 : myTau_jf = (SUMOTime)((double)edgeType.taujf / laneScale);
168 664057 : myTau_jj = (SUMOTime)((double)edgeType.taujj / laneScale);
169 : } else {
170 20777 : myTau_ff = edgeType.tauff;
171 20777 : myTau_fj = edgeType.taufj;
172 20777 : myTau_jf = edgeType.taujf;
173 20777 : myTau_jj = edgeType.taujj;
174 : }
175 :
176 684834 : myJunctionControl = myNextSegment == nullptr && (edgeType.junctionControl || MELoop::isEnteringRoundabout(parent));
177 684058 : myTLSPenalty = ((edgeType.tlsPenalty > 0 || edgeType.tlsFlowPenalty > 0) &&
178 : // only apply to the last segment of a tls-controlled edge
179 685194 : myNextSegment == nullptr && (
180 298 : parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT ||
181 298 : parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION ||
182 : parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED));
183 :
184 : // only apply to the last segment of an uncontrolled edge that has at least 1 minor link
185 1369988 : myCheckMinorPenalty = (edgeType.minorPenalty > 0 &&
186 320 : myNextSegment == nullptr &&
187 : parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT &&
188 : parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION &&
189 685012 : parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
190 178 : parent.hasMinorLink());
191 684834 : myMinorPenalty = edgeType.minorPenalty;
192 684834 : myOvertaking = edgeType.overtaking && myCapacity > myLength;
193 :
194 : //std::cout << getID() << " myMinorPenalty=" << myMinorPenalty << " myTLSPenalty=" << myTLSPenalty << " myJunctionControl=" << myJunctionControl << " myOvertaking=" << myOvertaking << "\n";
195 :
196 684834 : recomputeJamThreshold(edgeType.jamThreshold);
197 684834 : }
198 :
199 44565 : MESegment::MESegment(const std::string& id):
200 : Named(id),
201 44565 : myEdge(myDummyParent), // arbitrary edge needed to supply the needed reference
202 44565 : myNextSegment(nullptr), myLength(0), myIndex(0),
203 44565 : myTau_ff(0), myTau_fj(0), myTau_jf(0), myTau_jj(0),
204 44565 : myTLSPenalty(false),
205 44565 : myCheckMinorPenalty(false),
206 44565 : myMinorPenalty(0),
207 44565 : myJunctionControl(false),
208 44565 : myOvertaking(false),
209 44565 : myTau_length(1) {
210 44565 : }
211 :
212 :
213 : void
214 2226 : MESegment::updatePermissions() {
215 2226 : if (myQueues.size() > 1) {
216 64 : for (MSLane* lane : myEdge.getLanes()) {
217 48 : myQueues[lane->getIndex()].setPermissions(lane->getPermissions());
218 : }
219 : } else {
220 2210 : myQueues.back().setPermissions(myEdge.getPermissions());
221 : }
222 2226 : }
223 :
224 :
225 : void
226 685878 : MESegment::recomputeJamThreshold(double jamThresh) {
227 685878 : if (jamThresh == DO_NOT_PATCH_JAM_THRESHOLD) {
228 : return;
229 : }
230 685878 : if (jamThresh < 0) {
231 : // compute based on speed
232 685866 : myJamThreshold = jamThresholdForSpeed(myEdge.getSpeedLimit(), jamThresh);
233 : } else {
234 : // compute based on specified percentage
235 12 : myJamThreshold = jamThresh * myCapacity;
236 : }
237 : }
238 :
239 :
240 : double
241 5393420 : MESegment::jamThresholdForSpeed(double speed, double jamThresh) const {
242 : // vehicles driving freely at maximum speed should not jam
243 : // we compute how many vehicles could possible enter the segment until the first vehicle leaves
244 : // and multiply by the space these vehicles would occupy
245 : // the jamThresh parameter is scale the resulting value
246 5393420 : if (speed == 0) {
247 : return std::numeric_limits<double>::max(); // never jam. Irrelevant at speed 0 anyway
248 : }
249 : #ifdef DEBUG_JAMTHRESHOLD
250 : if (true || DEBUG_COND) {
251 : 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
252 : << "\n";
253 : }
254 : #endif
255 5393201 : return std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGTH_WITH_GAP, 1.)))) * DEFAULT_VEH_LENGTH_WITH_GAP;
256 : }
257 :
258 :
259 : void
260 126674 : MESegment::addDetector(MSMoveReminder* data, int queueIndex) {
261 126674 : if (queueIndex == -1) {
262 249204 : for (Queue& q : myQueues) {
263 125478 : q.addDetector(data);
264 : }
265 : } else {
266 : assert(queueIndex < (int)myQueues.size());
267 2948 : myQueues[queueIndex].addDetector(data);
268 : }
269 126674 : }
270 :
271 :
272 : /*
273 : void
274 : MESegment::removeDetector(MSMoveReminder* data) {
275 : std::vector<MSMoveReminder*>::iterator it = std::find(myDetectorData.begin(), myDetectorData.end(), data);
276 : if (it != myDetectorData.end()) {
277 : myDetectorData.erase(it);
278 : }
279 : for (const Queue& q : myQueues) {
280 : for (MEVehicle* const v : q.getVehicles()) {
281 : v->removeReminder(data);
282 : }
283 : }
284 : }
285 : */
286 :
287 :
288 : void
289 6423707 : MESegment::prepareDetectorForWriting(MSMoveReminder& data, int queueIndex) {
290 6423707 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
291 6423707 : if (queueIndex == -1) {
292 12871914 : for (const Queue& q : myQueues) {
293 : SUMOTime earliestExitTime = currentTime;
294 7749906 : for (std::vector<MEVehicle*>::const_reverse_iterator i = q.getVehicles().rbegin(); i != q.getVehicles().rend(); ++i) {
295 1301099 : const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
296 1301099 : (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
297 1301099 : earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
298 : }
299 : }
300 : } else {
301 : SUMOTime earliestExitTime = currentTime;
302 612 : for (std::vector<MEVehicle*>::const_reverse_iterator i = myQueues[queueIndex].getVehicles().rbegin(); i != myQueues[queueIndex].getVehicles().rend(); ++i) {
303 12 : const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
304 12 : (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
305 12 : earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
306 : }
307 : }
308 6423707 : }
309 :
310 :
311 : SUMOTime
312 134228879 : MESegment::hasSpaceFor(const MEVehicle* const veh, const SUMOTime entryTime, int& qIdx, const bool init) const {
313 : SUMOTime earliestEntry = SUMOTime_MAX;
314 134228879 : qIdx = 0;
315 134228879 : if (myNumVehicles == 0 && myQueues.size() == 1) {
316 : // we have always space for at least one vehicle
317 18195331 : if (myQueues.front().allows(veh->getVClass())) {
318 : return entryTime;
319 : } else {
320 : return earliestEntry;
321 : }
322 : }
323 116033548 : const SUMOVehicleClass svc = veh->getVClass();
324 : int minSize = std::numeric_limits<int>::max();
325 116694403 : const MSEdge* const succ = myNextSegment == nullptr ? veh->succEdge(veh->getEdge() == &myEdge ? 1 : 2) : nullptr;
326 304586221 : for (int i = 0; i < (int)myQueues.size(); i++) {
327 188552673 : const Queue& q = myQueues[i];
328 188552673 : const double newOccupancy = q.size() == 0 ? 0. : q.getOccupancy() + veh->getVehicleType().getLengthWithGap();
329 188552673 : if (newOccupancy <= myQueueCapacity) { // we must ensure that occupancy remains below capacity
330 60156867 : if (succ == nullptr || myFollowerMap.count(succ) == 0 || ((myFollowerMap.find(succ)->second & (1 << i)) != 0)) {
331 41656963 : if (q.allows(svc) && q.size() < minSize) {
332 26457560 : if (init) {
333 : // regular insertions and initial insertions must respect different constraints:
334 : // - regular insertions must respect entryBlockTime
335 : // - initial insertions should not cause additional jamming
336 : // - inserted vehicle should be able to continue at the current speed
337 8581377 : if (veh->getInsertionChecks() == (int)InsertionCheck::NONE) {
338 44 : qIdx = i;
339 : minSize = q.size();
340 8581333 : } else if (q.getOccupancy() <= myJamThreshold && !hasBlockedLeader() && !myTLSPenalty) {
341 3873779 : if (newOccupancy <= myJamThreshold) {
342 1378584 : qIdx = i;
343 : minSize = q.size();
344 : }
345 : } else {
346 4707554 : if (newOccupancy <= jamThresholdForSpeed(getMeanSpeed(false), -1)) {
347 3960891 : qIdx = i;
348 : minSize = q.size();
349 : }
350 : }
351 17876183 : } else if (entryTime >= q.getEntryBlockTime()) {
352 17614735 : qIdx = i;
353 : minSize = q.size();
354 : } else {
355 : earliestEntry = MIN2(earliestEntry, q.getEntryBlockTime());
356 : }
357 : }
358 : }
359 : }
360 : }
361 116033548 : if (minSize == std::numeric_limits<int>::max()) {
362 : return earliestEntry;
363 : }
364 : return entryTime;
365 : }
366 :
367 :
368 : bool
369 2018786 : MESegment::initialise(MEVehicle* veh, SUMOTime time) {
370 2018786 : int qIdx = 0;
371 2018786 : if (hasSpaceFor(veh, time, qIdx, true) == time) {
372 721547 : receive(veh, qIdx, time, true);
373 : // we can check only after insertion because insertion may change the route via devices
374 : std::string msg;
375 1442356 : if (MSGlobals::gCheckRoutes && !veh->hasValidRoute(msg)) {
376 6 : throw ProcessError(TLF("Vehicle '%' has no valid route. %", veh->getID(), msg));
377 : }
378 : return true;
379 : }
380 : return false;
381 : }
382 :
383 :
384 : double
385 30145108 : MESegment::getMeanSpeed(bool useCached) const {
386 30145108 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
387 30145108 : if (currentTime != myLastMeanSpeedUpdate || !useCached) {
388 30045099 : myLastMeanSpeedUpdate = currentTime;
389 : double v = 0;
390 : int count = 0;
391 62203335 : for (const Queue& q : myQueues) {
392 32158236 : const SUMOTime tau = q.getOccupancy() < myJamThreshold ? myTau_ff : myTau_jf;
393 32158236 : SUMOTime earliestExitTime = currentTime;
394 32158236 : count += q.size();
395 191856932 : for (std::vector<MEVehicle*>::const_reverse_iterator veh = q.getVehicles().rbegin(); veh != q.getVehicles().rend(); ++veh) {
396 159698696 : v += (*veh)->getConservativeSpeed(earliestExitTime); // earliestExitTime is updated!
397 159698696 : earliestExitTime += tauWithVehLength(tau, (*veh)->getVehicleType().getLengthWithGap(), (*veh)->getVehicleType().getCarFollowModel().getHeadwayTime());
398 : }
399 : }
400 30045099 : if (count == 0) {
401 30 : myMeanSpeed = myEdge.getSpeedLimit();
402 : } else {
403 30045069 : myMeanSpeed = v / (double) count;
404 : }
405 : }
406 30145108 : return myMeanSpeed;
407 : }
408 :
409 :
410 : void
411 4518 : MESegment::resetCachedSpeeds() {
412 4518 : myLastMeanSpeedUpdate = SUMOTime_MIN;
413 4518 : }
414 :
415 : void
416 11953 : MESegment::writeVehicles(OutputDevice& of) const {
417 24082 : for (const Queue& q : myQueues) {
418 14162 : for (const MEVehicle* const veh : q.getVehicles()) {
419 2033 : MSXMLRawOut::writeVehicle(of, *veh);
420 : }
421 : }
422 11953 : }
423 :
424 :
425 : MEVehicle*
426 26003076 : MESegment::removeCar(MEVehicle* v, SUMOTime leaveTime, const MSMoveReminder::Notification reason) {
427 26003076 : Queue& q = myQueues[v->getQueIndex()];
428 : // One could be tempted to do v->setSegment(next); here but position on lane will be invalid if next == 0
429 26003076 : v->updateDetectors(leaveTime, v->getEventTime(), true, reason);
430 26003076 : myNumVehicles--;
431 26003076 : myEdge.lock();
432 26003076 : MEVehicle* nextLeader = q.remove(v);
433 26003076 : myEdge.unlock();
434 26003076 : return nextLeader;
435 : }
436 :
437 :
438 : SUMOTime
439 13655 : MESegment::getNextInsertionTime(SUMOTime earliestEntry) const {
440 : // since we do not know which queue will be used we give a conservative estimate
441 : SUMOTime earliestLeave = earliestEntry;
442 : SUMOTime latestEntry = -1;
443 27575 : for (const Queue& q : myQueues) {
444 : earliestLeave = MAX2(earliestLeave, q.getBlockTime());
445 : latestEntry = MAX2(latestEntry, q.getEntryBlockTime());
446 : }
447 13655 : if (myEdge.getSpeedLimit() == 0) {
448 12 : return MAX2(earliestEntry, latestEntry); // FIXME: This line is just an adhoc-fix to avoid division by zero (Leo)
449 : } else {
450 13643 : return MAX3(earliestEntry, earliestLeave - TIME2STEPS(myLength / myEdge.getSpeedLimit()), latestEntry);
451 : }
452 : }
453 :
454 :
455 : MSLink*
456 123828321 : MESegment::getLink(const MEVehicle* veh, bool penalty) const {
457 123828321 : if (myJunctionControl || penalty) {
458 27174458 : const MSEdge* const nextEdge = veh->succEdge(1);
459 27174458 : if (nextEdge == nullptr || veh->getQueIndex() == PARKING_QUEUE) {
460 : return nullptr;
461 : }
462 : // try to find any link leading to our next edge, start with the lane pointed to by the que index
463 26188693 : const MSLane* const bestLane = myEdge.getLanes()[veh->getQueIndex()];
464 29426741 : for (MSLink* const link : bestLane->getLinkCont()) {
465 29028787 : if (&link->getLane()->getEdge() == nextEdge) {
466 : return link;
467 : }
468 : }
469 : // this is for the non-multique case, maybe we should use caching here !!!
470 902870 : for (const MSLane* const lane : myEdge.getLanes()) {
471 885756 : if (lane != bestLane) {
472 611740 : for (MSLink* const link : lane->getLinkCont()) {
473 504450 : if (&link->getLane()->getEdge() == nextEdge) {
474 : return link;
475 : }
476 : }
477 : }
478 : }
479 : }
480 : return nullptr;
481 : }
482 :
483 :
484 : bool
485 34197414 : MESegment::isOpen(const MEVehicle* veh) const {
486 : #ifdef DEBUG_OPENED
487 : if (DEBUG_COND || DEBUG_COND2(veh)) {
488 : gDebugFlag1 = true;
489 : std::cout << SIMTIME << " opened seg=" << getID() << " veh=" << Named::getIDSecure(veh)
490 : << " tlsPenalty=" << myTLSPenalty;
491 : const MSLink* link = getLink(veh);
492 : if (link == 0) {
493 : std::cout << " link=0";
494 : } else {
495 : std::cout << " prio=" << link->havePriority()
496 : << " override=" << limitedControlOverride(link)
497 : << " isOpen=" << link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
498 : veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
499 : veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime(),
500 : 0, nullptr, false, veh)
501 : << " et=" << veh->getEventTime()
502 : << " v=" << veh->getSpeed()
503 : << " vLeave=" << veh->estimateLeaveSpeed(link)
504 : << " impatience=" << veh->getImpatience()
505 : << " tWait=" << veh->getWaitingTime();
506 : }
507 : std::cout << "\n";
508 : gDebugFlag1 = false;
509 : }
510 : #endif
511 34197414 : if (myTLSPenalty) {
512 : // XXX should limited control take precedence over tls penalty?
513 : return true;
514 : }
515 34145266 : const MSLink* link = getLink(veh);
516 : return (link == nullptr
517 10563485 : || link->havePriority()
518 9172568 : || limitedControlOverride(link)
519 43317070 : || link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
520 9171804 : veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
521 9171804 : veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime(),
522 : 0, nullptr, false, veh));
523 : }
524 :
525 :
526 : bool
527 9175758 : MESegment::limitedControlOverride(const MSLink* link) const {
528 : assert(link != nullptr);
529 9175758 : if (!MSGlobals::gMesoLimitedJunctionControl) {
530 : return false;
531 : }
532 : // if the target segment of this link is not saturated junction control is disabled
533 : const MSEdge& targetEdge = link->getLane()->getEdge();
534 8246 : const MESegment* target = MSGlobals::gMesoNet->getSegmentForEdge(targetEdge);
535 8246 : return (target->getBruttoOccupancy() * 2 < target->myJamThreshold) && !targetEdge.isRoundabout();
536 : }
537 :
538 :
539 : void
540 26003076 : MESegment::send(MEVehicle* veh, MESegment* const next, const int nextQIdx, SUMOTime time, const MSMoveReminder::Notification reason) {
541 26003076 : Queue& q = myQueues[veh->getQueIndex()];
542 : assert(isInvalid(next) || time >= q.getBlockTime());
543 26003076 : MSLink* const link = getLink(veh);
544 26003076 : if (link != nullptr) {
545 1693651 : link->removeApproaching(veh);
546 : }
547 26003076 : if (veh->isStopped()) {
548 8055 : veh->processStop();
549 : }
550 26003076 : MEVehicle* lc = removeCar(veh, time, reason); // new leaderCar
551 : q.setBlockTime(time);
552 : if (!isInvalid(next)) {
553 25317619 : const bool nextFree = next->myQueues[nextQIdx].getOccupancy() <= next->myJamThreshold;
554 25317619 : const SUMOTime tau = (q.getOccupancy() <= myJamThreshold
555 25317619 : ? (nextFree ? myTau_ff : myTau_fj)
556 471881 : : (nextFree ? myTau_jf : getTauJJ((double)next->myQueues[nextQIdx].size(), next->myQueueCapacity, next->myJamThreshold)));
557 : assert(tau >= 0);
558 25317619 : myLastHeadway = tauWithVehLength(tau, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime());
559 25317619 : if (myTLSPenalty) {
560 52148 : const MSLink* const tllink = getLink(veh, true);
561 52148 : if (tllink != nullptr && tllink->isTLSControlled()) {
562 : assert(tllink->getGreenFraction() > 0);
563 49540 : myLastHeadway = (SUMOTime)((double)myLastHeadway / tllink->getGreenFraction());
564 : }
565 : }
566 25317619 : q.setBlockTime(q.getBlockTime() + myLastHeadway);
567 : }
568 26003076 : if (lc != nullptr) {
569 : lc->setEventTime(MAX2(lc->getEventTime(), q.getBlockTime()));
570 17738508 : MSGlobals::gMesoNet->addLeaderCar(lc, getLink(lc));
571 : }
572 26003076 : }
573 :
574 : SUMOTime
575 127183 : MESegment::getTauJJ(double nextQueueSize, double nextQueueCapacity, double nextJamThreshold) const {
576 : // compute coefficients for the jam-jam headway function
577 : // this function models the effect that "empty space" needs to move
578 : // backwards through the downstream segment before the upstream segment may
579 : // send annother vehicle.
580 : // this allows jams to clear and move upstream.
581 : // the headway function f(x) depends on the number of vehicles in the
582 : // downstream segment x
583 : // f is a linear function that passes through the following fixed points:
584 : // f(n_jam_threshold) = tau_jf_withLength (for continuity)
585 : // f(headwayCapacity) = myTau_jj * headwayCapacity
586 :
587 127183 : const SUMOTime tau_jf_withLength = tauWithVehLength(myTau_jf, DEFAULT_VEH_LENGTH_WITH_GAP, 1.);
588 : // number of vehicles that fit into the NEXT queue (could be larger than expected with DEFAULT_VEH_LENGTH_WITH_GAP!)
589 127183 : const double headwayCapacity = MAX2(nextQueueSize, nextQueueCapacity / DEFAULT_VEH_LENGTH_WITH_GAP);
590 : // number of vehicles above which the NEXT queue is jammed
591 127183 : const double n_jam_threshold = headwayCapacity * nextJamThreshold / nextQueueCapacity;
592 :
593 : // slope a and axis offset b for the jam-jam headway function
594 : // solving f(x) = a * x + b
595 127183 : const double a = (STEPS2TIME(myTau_jj) * headwayCapacity - STEPS2TIME(tau_jf_withLength)) / (headwayCapacity - n_jam_threshold);
596 127183 : const double b = headwayCapacity * (STEPS2TIME(myTau_jj) - a);
597 :
598 : // it is only well defined for nextQueueSize >= n_jam_threshold (which may not be the case for longer vehicles), so we take the MAX
599 127183 : return TIME2STEPS(a * MAX2(nextQueueSize, n_jam_threshold) + b);
600 : }
601 :
602 :
603 : bool
604 1172650 : MESegment::overtake() {
605 1172674 : return myOvertaking && RandHelper::rand() > (getBruttoOccupancy() / myCapacity);
606 : }
607 :
608 :
609 : void
610 26047579 : MESegment::addReminders(MEVehicle* veh) const {
611 26047579 : if (veh->getQueIndex() != PARKING_QUEUE) {
612 26041787 : myQueues[veh->getQueIndex()].addReminders(veh);
613 : }
614 26047579 : }
615 :
616 :
617 : void
618 26045361 : MESegment::receive(MEVehicle* veh, const int qIdx, SUMOTime time, const bool isDepart, const bool isTeleport, const bool newEdge) {
619 26045361 : const double speed = isDepart ? -1 : MAX2(veh->getSpeed(), MESO_MIN_SPEED); // on the previous segment
620 26045361 : veh->setSegment(this); // for arrival checking
621 : veh->setLastEntryTime(time);
622 : veh->setBlockTime(SUMOTime_MAX);
623 26045361 : if (!isDepart && (
624 : // arrival on entering a new edge
625 4740244 : (newEdge && myEdge.isNormal() && veh->moveRoutePointer())
626 : // arrival on entering a new segment
627 25323655 : || veh->hasArrived())) {
628 : // route has ended
629 15348 : veh->setEventTime(time + TIME2STEPS(myLength / speed)); // for correct arrival speed
630 15348 : addReminders(veh);
631 15348 : veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
632 30592 : veh->updateDetectors(time, veh->getEventTime(), true,
633 15348 : veh->getEdge()->isVaporizing() ? MSMoveReminder::NOTIFICATION_VAPORIZED_VAPORIZER : MSMoveReminder::NOTIFICATION_ARRIVED);
634 15348 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
635 15348 : return;
636 : }
637 : assert(veh->getEdge() == &getEdge() || getEdge().isInternal());
638 : // route continues
639 26030013 : Queue& q = myQueues[qIdx];
640 26030013 : const double maxSpeedOnEdge = veh->getEdge()->getLanes()[qIdx]->getVehicleMaxSpeed(veh);
641 : const double uspeed = MAX2(maxSpeedOnEdge, MESO_MIN_SPEED);
642 : std::vector<MEVehicle*>& cars = q.getModifiableVehicles();
643 : MEVehicle* newLeader = nullptr; // first vehicle in the current queue
644 26030013 : const SUMOTime stopTime = veh->checkStop(time);
645 26030013 : SUMOTime tleave = MAX2(stopTime + TIME2STEPS(myLength / uspeed) + getLinkPenalty(veh), q.getBlockTime());
646 26030013 : if (veh->isStopped()) {
647 14477 : myEdge.addWaiting(veh);
648 : }
649 26030013 : if (veh->isParking()) {
650 : // parking stops should take at least 1ms
651 5792 : veh->setEventTime(MAX2(stopTime, veh->getEventTime() + 1));
652 5792 : veh->setSegment(this, PARKING_QUEUE);
653 5792 : myEdge.getLanes()[0]->addParking(veh); // TODO for GUI only
654 : } else {
655 26024221 : myEdge.lock();
656 26024221 : if (cars.empty()) {
657 8263983 : cars.push_back(veh);
658 : newLeader = veh;
659 : } else {
660 17760238 : SUMOTime leaderOut = cars[0]->getEventTime();
661 17760238 : if (!isDepart && leaderOut > tleave && overtake()) {
662 20 : if (cars.size() == 1) {
663 4 : MSGlobals::gMesoNet->removeLeaderCar(cars[0]);
664 : newLeader = veh;
665 : }
666 20 : cars.insert(cars.begin() + 1, veh);
667 : } else {
668 17760218 : tleave = MAX2(leaderOut + tauWithVehLength(myTau_ff, cars[0]->getVehicleType().getLengthWithGap(), cars[0]->getVehicleType().getCarFollowModel().getHeadwayTime()), tleave);
669 17760218 : cars.insert(cars.begin(), veh);
670 : }
671 : }
672 26024221 : myEdge.unlock();
673 26024221 : myNumVehicles++;
674 26024221 : if (!isDepart && !isTeleport) {
675 : // departs and teleports could take place anywhere on the edge so they should not block regular flow
676 : // the -1 facilitates interleaving of multiple streams
677 25302173 : q.setEntryBlockTime(time + tauWithVehLength(myTau_ff, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime()) - 1);
678 : }
679 26024221 : q.setOccupancy(MIN2(myQueueCapacity, q.getOccupancy() + veh->getVehicleType().getLengthWithGap()));
680 : veh->setEventTime(tleave);
681 26024221 : veh->setSegment(this, qIdx);
682 : }
683 26030013 : addReminders(veh);
684 26030013 : if (isDepart) {
685 721547 : veh->onDepart();
686 721547 : veh->activateReminders(MSMoveReminder::NOTIFICATION_DEPARTED);
687 25308466 : } else if (newEdge) {
688 4740085 : veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
689 : } else {
690 20568381 : veh->activateReminders(MSMoveReminder::NOTIFICATION_SEGMENT);
691 : }
692 26030012 : if (veh->isParking()) {
693 5792 : MSGlobals::gMesoNet->addLeaderCar(veh, nullptr);
694 : } else {
695 26024220 : if (newLeader != nullptr) {
696 8263986 : MSGlobals::gMesoNet->addLeaderCar(newLeader, getLink(newLeader));
697 : }
698 : }
699 : }
700 :
701 :
702 : bool
703 8752 : MESegment::vaporizeAnyCar(SUMOTime currentTime, const MSDetectorFileOutput* filter) {
704 9304 : for (const Queue& q : myQueues) {
705 8778 : if (q.size() > 0) {
706 8226 : for (MEVehicle* const veh : q.getVehicles()) {
707 8226 : if (filter->vehicleApplies(*veh)) {
708 8226 : MSGlobals::gMesoNet->removeLeaderCar(veh);
709 8226 : MSGlobals::gMesoNet->changeSegment(veh, currentTime + 1, &myVaporizationTarget, MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR);
710 : return true;
711 : }
712 : }
713 : }
714 : }
715 : return false;
716 : }
717 :
718 :
719 : void
720 352 : MESegment::setSpeedForQueue(double newSpeed, SUMOTime currentTime, SUMOTime blockTime, const std::vector<MEVehicle*>& vehs) {
721 352 : MEVehicle* v = vehs.back();
722 : SUMOTime oldEarliestExitTime = currentTime;
723 : const SUMOTime oldExit = MAX2(oldEarliestExitTime, v->getEventTime());
724 352 : v->updateDetectors(currentTime, oldExit, false);
725 352 : oldEarliestExitTime = oldExit + tauWithVehLength(myTau_ff, v->getVehicleType().getLengthWithGap(), v->getVehicleType().getCarFollowModel().getHeadwayTime());
726 352 : SUMOTime newEvent = MAX2(newArrival(v, newSpeed, currentTime), blockTime);
727 352 : if (v->getEventTime() != newEvent) {
728 330 : MSGlobals::gMesoNet->removeLeaderCar(v);
729 : v->setEventTime(newEvent);
730 330 : MSGlobals::gMesoNet->addLeaderCar(v, getLink(v));
731 : }
732 1075 : for (std::vector<MEVehicle*>::const_reverse_iterator i = vehs.rbegin() + 1; i != vehs.rend(); ++i) {
733 723 : const SUMOTime oldExitTime = MAX2(oldEarliestExitTime, (*i)->getEventTime());
734 723 : (*i)->updateDetectors(currentTime, oldExitTime, false);
735 723 : const SUMOTime minTau = tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
736 723 : oldEarliestExitTime = oldExitTime + minTau;
737 723 : newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + minTau);
738 723 : (*i)->setEventTime(newEvent);
739 : }
740 352 : }
741 :
742 :
743 : SUMOTime
744 1075 : MESegment::newArrival(const MEVehicle* const v, double newSpeed, SUMOTime currentTime) {
745 : // since speed is only an upper bound, pos may be too optimistic
746 1075 : const double pos = MIN2(myLength, STEPS2TIME(currentTime - v->getLastEntryTime()) * v->getSpeed());
747 : // traveltime may not be 0
748 1075 : double tt = (myLength - pos) / MAX2(newSpeed, MESO_MIN_SPEED);
749 1075 : return currentTime + MAX2(TIME2STEPS(tt), SUMOTime(1));
750 : }
751 :
752 :
753 : void
754 1044 : MESegment::setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh, int qIdx) {
755 1044 : recomputeJamThreshold(jamThresh);
756 : //myTau_length = MAX2(MESO_MIN_SPEED, newSpeed) * myEdge.getLanes().size() / TIME2STEPS(1);
757 : int i = 0;
758 2182 : for (const Queue& q : myQueues) {
759 1138 : if (q.size() != 0) {
760 386 : if (qIdx == -1 || qIdx == i) {
761 352 : setSpeedForQueue(newSpeed, currentTime, q.getBlockTime(), q.getVehicles());
762 : }
763 : }
764 1138 : i++;
765 : }
766 1044 : }
767 :
768 :
769 : SUMOTime
770 2020025 : MESegment::getEventTime() const {
771 : SUMOTime result = SUMOTime_MAX;
772 4266687 : for (const Queue& q : myQueues) {
773 2246662 : if (q.size() != 0 && q.getVehicles().back()->getEventTime() < result) {
774 : result = q.getVehicles().back()->getEventTime();
775 : }
776 : }
777 2020025 : if (result < SUMOTime_MAX) {
778 911608 : return result;
779 : }
780 : return -1;
781 : }
782 :
783 :
784 : void
785 10820 : MESegment::saveState(OutputDevice& out) const {
786 : bool write = false;
787 20829 : for (const Queue& q : myQueues) {
788 11191 : if (q.getBlockTime() != -1 || !q.getVehicles().empty()) {
789 : write = true;
790 : break;
791 : }
792 : }
793 10820 : if (write) {
794 1182 : out.openTag(SUMO_TAG_SEGMENT).writeAttr(SUMO_ATTR_ID, getID());
795 2408 : for (const Queue& q : myQueues) {
796 1226 : out.openTag(SUMO_TAG_VIEWSETTINGS_VEHICLES);
797 1226 : out.writeAttr(SUMO_ATTR_TIME, toString<SUMOTime>(q.getBlockTime()));
798 1226 : out.writeAttr(SUMO_ATTR_BLOCKTIME, toString<SUMOTime>(q.getEntryBlockTime()));
799 1226 : out.writeAttr(SUMO_ATTR_VALUE, q.getVehicles());
800 2452 : out.closeTag();
801 : }
802 2364 : out.closeTag();
803 : }
804 10820 : }
805 :
806 :
807 : void
808 754 : MESegment::clearState() {
809 1560 : for (Queue& q : myQueues) {
810 : q.getModifiableVehicles().clear();
811 : }
812 754 : }
813 :
814 : void
815 991 : MESegment::loadState(const std::vector<SUMOVehicle*>& vehs, const SUMOTime blockTime, const SUMOTime entryBlockTime, const int queIdx) {
816 991 : Queue& q = myQueues[queIdx];
817 1443 : for (SUMOVehicle* veh : vehs) {
818 452 : MEVehicle* v = static_cast<MEVehicle*>(veh);
819 : assert(v->getSegment() == this);
820 452 : q.getModifiableVehicles().push_back(v);
821 452 : myNumVehicles++;
822 452 : q.setOccupancy(q.getOccupancy() + v->getVehicleType().getLengthWithGap());
823 452 : addReminders(v);
824 : }
825 991 : if (q.size() != 0) {
826 : // add the last vehicle of this queue
827 : // !!! one question - what about the previously added vehicle? Is it stored twice?
828 224 : MEVehicle* veh = q.getVehicles().back();
829 224 : MSGlobals::gMesoNet->addLeaderCar(veh, getLink(veh));
830 : }
831 : q.setBlockTime(blockTime);
832 : q.setEntryBlockTime(entryBlockTime);
833 991 : q.setOccupancy(MIN2(q.getOccupancy(), myQueueCapacity));
834 991 : }
835 :
836 :
837 : std::vector<const MEVehicle*>
838 122 : MESegment::getVehicles() const {
839 : std::vector<const MEVehicle*> result;
840 316 : for (const Queue& q : myQueues) {
841 194 : result.insert(result.end(), q.getVehicles().begin(), q.getVehicles().end());
842 : }
843 122 : return result;
844 0 : }
845 :
846 :
847 : bool
848 3903765 : MESegment::hasBlockedLeader() const {
849 7854834 : for (const Queue& q : myQueues) {
850 3980781 : if (q.size() > 0 && q.getVehicles().back()->getWaitingTime() > 0) {
851 : return true;
852 : }
853 : }
854 : return false;
855 : }
856 :
857 :
858 : double
859 0 : MESegment::getFlow() const {
860 0 : return 3600 * getCarNumber() * getMeanSpeed() / myLength;
861 : }
862 :
863 :
864 : SUMOTime
865 26030013 : MESegment::getLinkPenalty(const MEVehicle* veh) const {
866 26030013 : const MSLink* link = getLink(veh, myTLSPenalty || myCheckMinorPenalty);
867 26030013 : if (link != nullptr) {
868 : SUMOTime result = 0;
869 1748029 : if (link->isTLSControlled() && myTLSPenalty) {
870 : result += link->getMesoTLSPenalty();
871 : }
872 : // minor tls links may get an additional penalty
873 358356 : if (!link->havePriority() &&
874 : // do not apply penalty on top of tLSPenalty
875 1748029 : !myTLSPenalty &&
876 : // do not apply penalty if limited control is active
877 322374 : (!MSGlobals::gMesoLimitedJunctionControl || limitedControlOverride(link))) {
878 319904 : result += myMinorPenalty;
879 : }
880 1748029 : return result;
881 : } else {
882 : return 0;
883 : }
884 : }
885 :
886 :
887 : double
888 9 : MESegment::getWaitingSeconds() const {
889 : double result = 0;
890 22 : for (const Queue& q : myQueues) {
891 : // @note: only the leader currently accumulates waitingTime but this might change in the future
892 16 : for (const MEVehicle* veh : q.getVehicles()) {
893 3 : result += veh->getWaitingSeconds();
894 : }
895 : }
896 9 : return result;
897 : }
898 :
899 :
900 : /****************************************************************************/
|