Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 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 24014581 : MESegment::Queue::remove(MEVehicle* v) {
71 24014581 : myOccupancy -= v->getVehicleType().getLengthWithGap();
72 : assert(std::find(myVehicles.begin(), myVehicles.end(), v) != myVehicles.end());
73 24014581 : if (v == myVehicles.back()) {
74 : myVehicles.pop_back();
75 24008302 : if (myVehicles.empty()) {
76 6419746 : myOccupancy = 0.;
77 : } else {
78 17588556 : 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 124150 : MESegment::Queue::addDetector(MSMoveReminder* data) {
88 124150 : myDetectorData.push_back(data);
89 129870 : for (MEVehicle* const v : myVehicles) {
90 5720 : v->addReminder(data);
91 : }
92 124150 : }
93 :
94 : void
95 24051749 : MESegment::Queue::addReminders(MEVehicle* veh) const {
96 33470861 : for (MSMoveReminder* rem : myDetectorData) {
97 9419112 : veh->addReminder(rem);
98 : }
99 24051749 : }
100 :
101 : // ===========================================================================
102 : // MESegment method definitions
103 : // ===========================================================================
104 629431 : 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 629431 : const MesoEdgeType& edgeType):
110 629431 : Named(id), myEdge(parent), myNextSegment(next),
111 629431 : myLength(length), myIndex(idx),
112 629431 : myTau_length(TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, speed)),
113 629431 : myNumVehicles(0),
114 629431 : myLastHeadway(TIME2STEPS(-1)),
115 629431 : myMeanSpeed(speed),
116 1258535 : myLastMeanSpeedUpdate(SUMOTime_MIN) {
117 :
118 : const std::vector<MSLane*>& lanes = parent.getLanes();
119 : int usableLanes = 0;
120 1362429 : for (MSLane* const l : lanes) {
121 732998 : const SVCPermissions allow = MSEdge::getMesoPermissions(l->getPermissions());
122 732998 : if (multiQueue) {
123 73162 : myQueues.push_back(Queue(allow));
124 : }
125 732998 : if (allow != 0) {
126 701460 : usableLanes++;
127 : }
128 : }
129 629431 : if (usableLanes == 0) {
130 : // cars won't drive here. Give sensible tau values capacity for the ignored classes
131 : usableLanes = 1;
132 : }
133 629431 : if (multiQueue) {
134 16439 : if (next == nullptr) {
135 69151 : for (const MSEdge* const edge : parent.getSuccessors()) {
136 53057 : const std::vector<MSLane*>* const allowed = parent.allowedLanes(*edge);
137 : assert(allowed != nullptr);
138 : assert(allowed->size() > 0);
139 113162 : for (MSLane* const l : *allowed) {
140 60105 : std::vector<MSLane*>::const_iterator it = std::find(lanes.begin(), lanes.end(), l);
141 60105 : myFollowerMap[edge] |= (1 << distance(lanes.begin(), it));
142 : }
143 : }
144 : }
145 16439 : myQueueCapacity = length;
146 : } else {
147 1225984 : myQueues.push_back(Queue(parent.getPermissions()));
148 : }
149 :
150 629431 : initSegment(edgeType, parent, length * usableLanes);
151 629431 : }
152 :
153 : void
154 630509 : MESegment::initSegment(const MesoEdgeType& edgeType, const MSEdge& parent, const double capacity) {
155 :
156 630509 : myCapacity = capacity;
157 630509 : if (myQueues.size() == 1) {
158 614421 : const double laneScale = capacity / myLength;
159 614421 : myQueueCapacity = capacity;
160 614421 : myTau_length = TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, myMeanSpeed) / laneScale;
161 : // Eissfeldt p. 90 and 151 ff.
162 614421 : myTau_ff = (SUMOTime)((double)edgeType.tauff / laneScale);
163 614421 : myTau_fj = (SUMOTime)((double)edgeType.taufj / laneScale);
164 614421 : myTau_jf = (SUMOTime)((double)edgeType.taujf / laneScale);
165 614421 : myTau_jj = (SUMOTime)((double)edgeType.taujj / laneScale);
166 : } else {
167 16088 : myTau_ff = edgeType.tauff;
168 16088 : myTau_fj = edgeType.taufj;
169 16088 : myTau_jf = edgeType.taujf;
170 16088 : myTau_jj = edgeType.taujj;
171 : }
172 :
173 630509 : myJunctionControl = myNextSegment == nullptr && (edgeType.junctionControl || MELoop::isEnteringRoundabout(parent));
174 629705 : myTLSPenalty = ((edgeType.tlsPenalty > 0 || edgeType.tlsFlowPenalty > 0) &&
175 : // only apply to the last segment of a tls-controlled edge
176 1164 : myNextSegment == nullptr && (
177 310 : parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT ||
178 310 : parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION ||
179 : parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED)
180 630887 : && !tlsPenaltyOverride());
181 :
182 : // only apply to the last segment of an uncontrolled edge that has at least 1 minor link
183 1261338 : myCheckMinorPenalty = (edgeType.minorPenalty > 0 &&
184 320 : myNextSegment == nullptr &&
185 : parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT &&
186 : parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION &&
187 630687 : parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
188 178 : parent.hasMinorLink());
189 630509 : myMinorPenalty = edgeType.minorPenalty;
190 630509 : myOvertaking = edgeType.overtaking && myCapacity > myLength;
191 :
192 : //std::cout << getID() << " myMinorPenalty=" << myMinorPenalty << " myTLSPenalty=" << myTLSPenalty << " myJunctionControl=" << myJunctionControl << " myOvertaking=" << myOvertaking << "\n";
193 :
194 630509 : recomputeJamThreshold(edgeType.jamThreshold);
195 630509 : }
196 :
197 39746 : MESegment::MESegment(const std::string& id):
198 : Named(id),
199 39746 : myEdge(myDummyParent), // arbitrary edge needed to supply the needed reference
200 39746 : myNextSegment(nullptr), myLength(0), myIndex(0),
201 39746 : myTau_ff(0), myTau_fj(0), myTau_jf(0), myTau_jj(0),
202 39746 : myTLSPenalty(false),
203 39746 : myCheckMinorPenalty(false),
204 39746 : myMinorPenalty(0),
205 39746 : myJunctionControl(false),
206 39746 : myOvertaking(false),
207 39746 : myTau_length(1) {
208 39746 : }
209 :
210 :
211 : void
212 1807 : MESegment::updatePermissions() {
213 1807 : if (myQueues.size() > 1) {
214 64 : for (MSLane* lane : myEdge.getLanes()) {
215 48 : myQueues[lane->getIndex()].setPermissions(lane->getPermissions());
216 : }
217 : } else {
218 1791 : myQueues.back().setPermissions(myEdge.getPermissions());
219 : }
220 1807 : }
221 :
222 :
223 : void
224 631500 : MESegment::recomputeJamThreshold(double jamThresh) {
225 631500 : if (jamThresh == DO_NOT_PATCH_JAM_THRESHOLD) {
226 : return;
227 : }
228 631500 : if (jamThresh < 0) {
229 : // compute based on speed
230 631496 : myJamThreshold = jamThresholdForSpeed(myEdge.getSpeedLimit(), jamThresh);
231 : } else {
232 : // compute based on specified percentage
233 4 : myJamThreshold = jamThresh * myCapacity;
234 : }
235 : }
236 :
237 :
238 : double
239 4083664 : MESegment::jamThresholdForSpeed(double speed, double jamThresh) const {
240 : // vehicles driving freely at maximum speed should not jam
241 : // we compute how many vehicles could possible enter the segment until the first vehicle leaves
242 : // and multiply by the space these vehicles would occupy
243 : // the jamThresh parameter is scale the resulting value
244 4083664 : if (speed == 0) {
245 : return std::numeric_limits<double>::max(); // never jam. Irrelevant at speed 0 anyway
246 : }
247 : #ifdef DEBUG_JAMTHRESHOLD
248 : if (true || DEBUG_COND) {
249 : 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
250 : << "\n";
251 : }
252 : #endif
253 4083443 : return std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGTH_WITH_GAP, 1.)))) * DEFAULT_VEH_LENGTH_WITH_GAP;
254 : }
255 :
256 :
257 : void
258 122524 : MESegment::addDetector(MSMoveReminder* data, int queueIndex) {
259 122524 : if (queueIndex == -1) {
260 241934 : for (Queue& q : myQueues) {
261 121780 : q.addDetector(data);
262 : }
263 : } else {
264 : assert(queueIndex < (int)myQueues.size());
265 2370 : myQueues[queueIndex].addDetector(data);
266 : }
267 122524 : }
268 :
269 :
270 : /*
271 : void
272 : MESegment::removeDetector(MSMoveReminder* data) {
273 : std::vector<MSMoveReminder*>::iterator it = std::find(myDetectorData.begin(), myDetectorData.end(), data);
274 : if (it != myDetectorData.end()) {
275 : myDetectorData.erase(it);
276 : }
277 : for (const Queue& q : myQueues) {
278 : for (MEVehicle* const v : q.getVehicles()) {
279 : v->removeReminder(data);
280 : }
281 : }
282 : }
283 : */
284 :
285 :
286 : void
287 6405984 : MESegment::prepareDetectorForWriting(MSMoveReminder& data, int queueIndex) {
288 6405984 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
289 6405984 : if (queueIndex == -1) {
290 12835116 : for (const Queue& q : myQueues) {
291 : SUMOTime earliestExitTime = currentTime;
292 7729602 : for (std::vector<MEVehicle*>::const_reverse_iterator i = q.getVehicles().rbegin(); i != q.getVehicles().rend(); ++i) {
293 1299870 : const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
294 1299870 : (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
295 1299870 : earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
296 : }
297 : }
298 : } else {
299 : SUMOTime earliestExitTime = currentTime;
300 612 : for (std::vector<MEVehicle*>::const_reverse_iterator i = myQueues[queueIndex].getVehicles().rbegin(); i != myQueues[queueIndex].getVehicles().rend(); ++i) {
301 12 : const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
302 12 : (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
303 12 : earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
304 : }
305 : }
306 6405984 : }
307 :
308 :
309 : SUMOTime
310 57375795 : MESegment::hasSpaceFor(const MEVehicle* const veh, const SUMOTime entryTime, int& qIdx, const bool init) const {
311 : SUMOTime earliestEntry = SUMOTime_MAX;
312 57375795 : qIdx = 0;
313 57375795 : if (myNumVehicles == 0 && myQueues.size() == 1) {
314 : // we have always space for at least one vehicle
315 10578875 : if (myQueues.front().allows(veh->getVClass())) {
316 : return entryTime;
317 : } else {
318 : return earliestEntry;
319 : }
320 : }
321 46796920 : const SUMOVehicleClass svc = veh->getVClass();
322 : int minSize = std::numeric_limits<int>::max();
323 47311403 : const MSEdge* const succ = myNextSegment == nullptr ? veh->succEdge(veh->getEdge() == &myEdge ? 1 : 2) : nullptr;
324 95395960 : for (int i = 0; i < (int)myQueues.size(); i++) {
325 48599040 : const Queue& q = myQueues[i];
326 48599040 : const double newOccupancy = q.size() == 0 ? 0. : q.getOccupancy() + veh->getVehicleType().getLengthWithGap();
327 48599040 : if (newOccupancy <= myQueueCapacity) { // we must ensure that occupancy remains below capacity
328 28342829 : if (succ == nullptr || myFollowerMap.count(succ) == 0 || ((myFollowerMap.find(succ)->second & (1 << i)) != 0)) {
329 25807589 : if (q.allows(svc) && q.size() < minSize) {
330 25262207 : if (init) {
331 : // regular insertions and initial insertions must respect different constraints:
332 : // - regular insertions must respect entryBlockTime
333 : // - initial insertions should not cause additional jamming
334 : // - inserted vehicle should be able to continue at the current speed
335 7337464 : if (veh->getInsertionChecks() == (int)InsertionCheck::NONE) {
336 44 : qIdx = i;
337 : minSize = q.size();
338 7337420 : } else if (q.getOccupancy() <= myJamThreshold && !hasBlockedLeader() && !myTLSPenalty) {
339 3885252 : if (newOccupancy <= myJamThreshold) {
340 1397420 : qIdx = i;
341 : minSize = q.size();
342 : }
343 : } else {
344 3452168 : if (newOccupancy <= jamThresholdForSpeed(getMeanSpeed(false), -1)) {
345 2693033 : qIdx = i;
346 : minSize = q.size();
347 : }
348 : }
349 17924743 : } else if (entryTime >= q.getEntryBlockTime()) {
350 17620065 : qIdx = i;
351 : minSize = q.size();
352 : } else {
353 : earliestEntry = MIN2(earliestEntry, q.getEntryBlockTime());
354 : }
355 : }
356 : }
357 : }
358 : }
359 46796920 : if (minSize == std::numeric_limits<int>::max()) {
360 : return earliestEntry;
361 : }
362 : return entryTime;
363 : }
364 :
365 :
366 : bool
367 1984632 : MESegment::initialise(MEVehicle* veh, SUMOTime time) {
368 1984632 : int qIdx = 0;
369 1984632 : if (hasSpaceFor(veh, time, qIdx, true) == time) {
370 692544 : receive(veh, qIdx, time, true);
371 : // we can check only after insertion because insertion may change the route via devices
372 : std::string msg;
373 1384376 : if (MSGlobals::gCheckRoutes && !veh->hasValidRoute(msg)) {
374 6 : throw ProcessError(TLF("Vehicle '%' has no valid route. %", veh->getID(), msg));
375 : }
376 : return true;
377 : }
378 : return false;
379 : }
380 :
381 :
382 : double
383 27437681 : MESegment::getMeanSpeed(bool useCached) const {
384 27437681 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
385 27437681 : if (currentTime != myLastMeanSpeedUpdate || !useCached) {
386 27342743 : myLastMeanSpeedUpdate = currentTime;
387 : double v = 0;
388 : int count = 0;
389 55220327 : for (const Queue& q : myQueues) {
390 27877584 : const SUMOTime tau = q.getOccupancy() < myJamThreshold ? myTau_ff : myTau_jf;
391 27877584 : SUMOTime earliestExitTime = currentTime;
392 27877584 : count += q.size();
393 134097034 : for (std::vector<MEVehicle*>::const_reverse_iterator veh = q.getVehicles().rbegin(); veh != q.getVehicles().rend(); ++veh) {
394 106219450 : v += (*veh)->getConservativeSpeed(earliestExitTime); // earliestExitTime is updated!
395 106219450 : earliestExitTime += tauWithVehLength(tau, (*veh)->getVehicleType().getLengthWithGap(), (*veh)->getVehicleType().getCarFollowModel().getHeadwayTime());
396 : }
397 : }
398 27342743 : if (count == 0) {
399 30 : myMeanSpeed = myEdge.getSpeedLimit();
400 : } else {
401 27342713 : myMeanSpeed = v / (double) count;
402 : }
403 : }
404 27437681 : return myMeanSpeed;
405 : }
406 :
407 :
408 : void
409 2542 : MESegment::resetCachedSpeeds() {
410 2542 : myLastMeanSpeedUpdate = SUMOTime_MIN;
411 2542 : }
412 :
413 : void
414 206716 : MESegment::writeVehicles(OutputDevice& of) const {
415 413850 : for (const Queue& q : myQueues) {
416 221396 : for (const MEVehicle* const veh : q.getVehicles()) {
417 14262 : MSXMLRawOut::writeVehicle(of, *veh);
418 : }
419 : }
420 206716 : }
421 :
422 :
423 : MEVehicle*
424 24014581 : MESegment::removeCar(MEVehicle* v, SUMOTime leaveTime, const MSMoveReminder::Notification reason) {
425 24014581 : Queue& q = myQueues[v->getQueIndex()];
426 : // One could be tempted to do v->setSegment(next); here but position on lane will be invalid if next == 0
427 24014581 : v->updateDetectors(leaveTime, v->getEventTime(), true, reason);
428 24014581 : myNumVehicles--;
429 24014581 : myEdge.lock();
430 24014581 : MEVehicle* nextLeader = q.remove(v);
431 24014581 : myEdge.unlock();
432 24014581 : return nextLeader;
433 : }
434 :
435 :
436 : SUMOTime
437 13548 : MESegment::getNextInsertionTime(SUMOTime earliestEntry) const {
438 : // since we do not know which queue will be used we give a conservative estimate
439 : SUMOTime earliestLeave = earliestEntry;
440 : SUMOTime latestEntry = -1;
441 27354 : for (const Queue& q : myQueues) {
442 : earliestLeave = MAX2(earliestLeave, q.getBlockTime());
443 : latestEntry = MAX2(latestEntry, q.getEntryBlockTime());
444 : }
445 13548 : if (myEdge.getSpeedLimit() == 0) {
446 12 : return MAX2(earliestEntry, latestEntry); // FIXME: This line is just an adhoc-fix to avoid division by zero (Leo)
447 : } else {
448 13536 : return MAX3(earliestEntry, earliestLeave - TIME2STEPS(myLength / myEdge.getSpeedLimit()), latestEntry);
449 : }
450 : }
451 :
452 :
453 : MSLink*
454 105207658 : MESegment::getLink(const MEVehicle* veh, bool penalty) const {
455 105207658 : if (myJunctionControl || penalty) {
456 14041389 : const MSEdge* const nextEdge = veh->succEdge(1);
457 14041389 : if (nextEdge == nullptr || veh->getQueIndex() == PARKING_QUEUE) {
458 : return nullptr;
459 : }
460 : // try to find any link leading to our next edge, start with the lane pointed to by the que index
461 13094409 : const MSLane* const bestLane = myEdge.getLanes()[veh->getQueIndex()];
462 15978574 : for (MSLink* const link : bestLane->getLinkCont()) {
463 15605559 : if (&link->getLane()->getEdge() == nextEdge) {
464 : return link;
465 : }
466 : }
467 : // this is for the non-multique case, maybe we should use caching here !!!
468 852331 : for (const MSLane* const lane : myEdge.getLanes()) {
469 835925 : if (lane != bestLane) {
470 580180 : for (MSLink* const link : lane->getLinkCont()) {
471 473101 : if (&link->getLane()->getEdge() == nextEdge) {
472 : return link;
473 : }
474 : }
475 : }
476 : }
477 : }
478 : return nullptr;
479 : }
480 :
481 :
482 : bool
483 27222020 : MESegment::isOpen(const MEVehicle* veh) const {
484 : #ifdef DEBUG_OPENED
485 : if (DEBUG_COND || DEBUG_COND2(veh)) {
486 : gDebugFlag1 = true;
487 : std::cout << SIMTIME << " opened seg=" << getID() << " veh=" << Named::getIDSecure(veh)
488 : << " tlsPenalty=" << myTLSPenalty;
489 : const MSLink* link = getLink(veh);
490 : if (link == 0) {
491 : std::cout << " link=0";
492 : } else {
493 : std::cout << " prio=" << link->havePriority()
494 : << " override=" << limitedControlOverride(link)
495 : << " isOpen=" << link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
496 : veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
497 : veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime(),
498 : 0, nullptr, false, veh)
499 : << " et=" << veh->getEventTime()
500 : << " v=" << veh->getSpeed()
501 : << " vLeave=" << veh->estimateLeaveSpeed(link)
502 : << " impatience=" << veh->getImpatience()
503 : << " tWait=" << veh->getWaitingTime();
504 : }
505 : std::cout << "\n";
506 : gDebugFlag1 = false;
507 : }
508 : #endif
509 27222020 : if (myTLSPenalty) {
510 : // XXX should limited control take precedence over tls penalty?
511 : return true;
512 : }
513 27172480 : const MSLink* link = getLink(veh);
514 : return (link == nullptr
515 4946433 : || link->havePriority()
516 4119154 : || limitedControlOverride(link)
517 31290870 : || link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
518 4118390 : veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
519 4118390 : veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime(),
520 : 0, nullptr, false, veh));
521 : }
522 :
523 :
524 : bool
525 4122344 : MESegment::limitedControlOverride(const MSLink* link) const {
526 : assert(link != nullptr);
527 4122344 : if (!MSGlobals::gMesoLimitedJunctionControl) {
528 : return false;
529 : }
530 : // if the target segment of this link is not saturated junction control is disabled
531 : const MSEdge& targetEdge = link->getLane()->getEdge();
532 8246 : const MESegment* target = MSGlobals::gMesoNet->getSegmentForEdge(targetEdge);
533 8246 : return (target->getBruttoOccupancy() * 2 < target->myJamThreshold) && !targetEdge.isRoundabout();
534 : }
535 :
536 :
537 : void
538 24014581 : MESegment::send(MEVehicle* veh, MESegment* const next, const int nextQIdx, SUMOTime time, const MSMoveReminder::Notification reason) {
539 24014581 : Queue& q = myQueues[veh->getQueIndex()];
540 : assert(isInvalid(next) || time >= q.getBlockTime());
541 24014581 : MSLink* const link = getLink(veh);
542 24014581 : if (link != nullptr) {
543 1088531 : link->removeApproaching(veh);
544 : }
545 24014581 : if (veh->isStopped()) {
546 7784 : veh->processStop();
547 : }
548 24014581 : MEVehicle* lc = removeCar(veh, time, reason); // new leaderCar
549 : q.setBlockTime(time);
550 : if (!isInvalid(next)) {
551 23356190 : const bool nextFree = next->myQueues[nextQIdx].getOccupancy() <= next->myJamThreshold;
552 23356190 : const SUMOTime tau = (q.getOccupancy() <= myJamThreshold
553 23356190 : ? (nextFree ? myTau_ff : myTau_fj)
554 407917 : : (nextFree ? myTau_jf : getTauJJ((double)next->myQueues[nextQIdx].size(), next->myQueueCapacity, next->myJamThreshold)));
555 : assert(tau >= 0);
556 23356190 : myLastHeadway = tauWithVehLength(tau, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime());
557 23356190 : if (myTLSPenalty) {
558 49540 : const MSLink* const tllink = getLink(veh, true);
559 49540 : if (tllink != nullptr && tllink->isTLSControlled()) {
560 : assert(tllink->getGreenFraction() > 0);
561 49540 : myLastHeadway = (SUMOTime)((double)myLastHeadway / tllink->getGreenFraction());
562 : }
563 : }
564 23356190 : q.setBlockTime(q.getBlockTime() + myLastHeadway);
565 : }
566 24014581 : if (lc != nullptr) {
567 : lc->setEventTime(MAX2(lc->getEventTime(), q.getBlockTime()));
568 17588556 : MSGlobals::gMesoNet->addLeaderCar(lc, getLink(lc));
569 : }
570 24014581 : }
571 :
572 : SUMOTime
573 135964 : MESegment::getTauJJ(double nextQueueSize, double nextQueueCapacity, double nextJamThreshold) const {
574 : // compute coefficients for the jam-jam headway function
575 : // this function models the effect that "empty space" needs to move
576 : // backwards through the downstream segment before the upstream segment may
577 : // send annother vehicle.
578 : // this allows jams to clear and move upstream.
579 : // the headway function f(x) depends on the number of vehicles in the
580 : // downstream segment x
581 : // f is a linear function that passes through the following fixed points:
582 : // f(n_jam_threshold) = tau_jf_withLength (for continuity)
583 : // f(headwayCapacity) = myTau_jj * headwayCapacity
584 :
585 135964 : const SUMOTime tau_jf_withLength = tauWithVehLength(myTau_jf, DEFAULT_VEH_LENGTH_WITH_GAP, 1.);
586 : // number of vehicles that fit into the NEXT queue (could be larger than expected with DEFAULT_VEH_LENGTH_WITH_GAP!)
587 135964 : const double headwayCapacity = MAX2(nextQueueSize, nextQueueCapacity / DEFAULT_VEH_LENGTH_WITH_GAP);
588 : // number of vehicles above which the NEXT queue is jammed
589 135964 : const double n_jam_threshold = headwayCapacity * nextJamThreshold / nextQueueCapacity;
590 :
591 : // slope a and axis offset b for the jam-jam headway function
592 : // solving f(x) = a * x + b
593 135964 : const double a = (STEPS2TIME(myTau_jj) * headwayCapacity - STEPS2TIME(tau_jf_withLength)) / (headwayCapacity - n_jam_threshold);
594 135964 : const double b = headwayCapacity * (STEPS2TIME(myTau_jj) - a);
595 :
596 : // it is only well defined for nextQueueSize >= n_jam_threshold (which may not be the case for longer vehicles), so we take the MAX
597 135964 : return TIME2STEPS(a * MAX2(nextQueueSize, n_jam_threshold) + b);
598 : }
599 :
600 :
601 : bool
602 1160042 : MESegment::overtake() {
603 1160066 : return myOvertaking && RandHelper::rand() > (getBruttoOccupancy() / myCapacity);
604 : }
605 :
606 :
607 : void
608 24057222 : MESegment::addReminders(MEVehicle* veh) const {
609 24057222 : if (veh->getQueIndex() != PARKING_QUEUE) {
610 24051749 : myQueues[veh->getQueIndex()].addReminders(veh);
611 : }
612 24057222 : }
613 :
614 :
615 : void
616 24054762 : MESegment::receive(MEVehicle* veh, const int qIdx, SUMOTime time, const bool isDepart, const bool isTeleport, const bool newEdge) {
617 24054762 : const double speed = isDepart ? -1 : MAX2(veh->getSpeed(), MESO_MIN_SPEED); // on the previous segment
618 24054762 : veh->setSegment(this); // for arrival checking
619 : veh->setLastEntryTime(time);
620 : veh->setBlockTime(SUMOTime_MAX);
621 24054762 : if (!isDepart && (
622 : // arrival on entering a new edge
623 2845139 : (newEdge && veh->moveRoutePointer())
624 : // arrival on entering a new segment
625 23362059 : || veh->hasArrived())) {
626 : // route has ended
627 15241 : veh->setEventTime(time + TIME2STEPS(myLength / speed)); // for correct arrival speed
628 15241 : addReminders(veh);
629 15241 : veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
630 30378 : veh->updateDetectors(time, veh->getEventTime(), true,
631 15241 : veh->getEdge()->isVaporizing() ? MSMoveReminder::NOTIFICATION_VAPORIZED_VAPORIZER : MSMoveReminder::NOTIFICATION_ARRIVED);
632 15241 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
633 15241 : return;
634 : }
635 : assert(veh->getEdge() == &getEdge());
636 : // route continues
637 24039521 : Queue& q = myQueues[qIdx];
638 24039521 : const double maxSpeedOnEdge = veh->getEdge()->getLanes()[qIdx]->getVehicleMaxSpeed(veh);
639 : const double uspeed = MAX2(maxSpeedOnEdge, MESO_MIN_SPEED);
640 : std::vector<MEVehicle*>& cars = q.getModifiableVehicles();
641 : MEVehicle* newLeader = nullptr; // first vehicle in the current queue
642 24039521 : const SUMOTime stopTime = veh->checkStop(time);
643 24039521 : SUMOTime tleave = MAX2(stopTime + TIME2STEPS(myLength / uspeed) + getLinkPenalty(veh), q.getBlockTime());
644 24039521 : if (veh->isStopped()) {
645 13576 : myEdge.addWaiting(veh);
646 : }
647 24039521 : if (veh->isParking()) {
648 : // parking stops should take at least 1ms
649 5473 : veh->setEventTime(MAX2(stopTime, veh->getEventTime() + 1));
650 5473 : veh->setSegment(this, PARKING_QUEUE);
651 5473 : myEdge.getLanes()[0]->addParking(veh); // TODO for GUI only
652 : } else {
653 24034048 : myEdge.lock();
654 24034048 : if (cars.empty()) {
655 6424583 : cars.push_back(veh);
656 : newLeader = veh;
657 : } else {
658 17609465 : SUMOTime leaderOut = cars[0]->getEventTime();
659 17609465 : if (!isDepart && leaderOut > tleave && overtake()) {
660 20 : if (cars.size() == 1) {
661 4 : MSGlobals::gMesoNet->removeLeaderCar(cars[0]);
662 : newLeader = veh;
663 : }
664 20 : cars.insert(cars.begin() + 1, veh);
665 : } else {
666 17609445 : tleave = MAX2(leaderOut + tauWithVehLength(myTau_ff, cars[0]->getVehicleType().getLengthWithGap(), cars[0]->getVehicleType().getCarFollowModel().getHeadwayTime()), tleave);
667 17609445 : cars.insert(cars.begin(), veh);
668 : }
669 : }
670 24034048 : myEdge.unlock();
671 24034048 : myNumVehicles++;
672 24034048 : if (!isDepart && !isTeleport) {
673 : // departs and teleports could take place anywhere on the edge so they should not block regular flow
674 : // the -1 facilitates interleaving of multiple streams
675 23340860 : q.setEntryBlockTime(time + tauWithVehLength(myTau_ff, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime()) - 1);
676 : }
677 24034048 : q.setOccupancy(MIN2(myQueueCapacity, q.getOccupancy() + veh->getVehicleType().getLengthWithGap()));
678 : veh->setEventTime(tleave);
679 24034048 : veh->setSegment(this, qIdx);
680 : }
681 24039521 : addReminders(veh);
682 24039521 : if (isDepart) {
683 692544 : veh->onDepart();
684 692544 : veh->activateReminders(MSMoveReminder::NOTIFICATION_DEPARTED);
685 23346977 : } else if (newEdge) {
686 2844980 : veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
687 : } else {
688 20501997 : veh->activateReminders(MSMoveReminder::NOTIFICATION_SEGMENT);
689 : }
690 24039520 : if (veh->isParking()) {
691 5473 : MSGlobals::gMesoNet->addLeaderCar(veh, nullptr);
692 : } else {
693 24034047 : if (newLeader != nullptr) {
694 6424586 : MSGlobals::gMesoNet->addLeaderCar(newLeader, getLink(newLeader));
695 : }
696 : }
697 : }
698 :
699 :
700 : bool
701 8674 : MESegment::vaporizeAnyCar(SUMOTime currentTime, const MSDetectorFileOutput* filter) {
702 9232 : for (const Queue& q : myQueues) {
703 8706 : if (q.size() > 0) {
704 8148 : for (MEVehicle* const veh : q.getVehicles()) {
705 8148 : if (filter->vehicleApplies(*veh)) {
706 8148 : MSGlobals::gMesoNet->removeLeaderCar(veh);
707 8148 : MSGlobals::gMesoNet->changeSegment(veh, currentTime + 1, &myVaporizationTarget, MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR);
708 : return true;
709 : }
710 : }
711 : }
712 : }
713 : return false;
714 : }
715 :
716 :
717 : void
718 348 : MESegment::setSpeedForQueue(double newSpeed, SUMOTime currentTime, SUMOTime blockTime, const std::vector<MEVehicle*>& vehs) {
719 348 : MEVehicle* v = vehs.back();
720 : SUMOTime oldEarliestExitTime = currentTime;
721 : const SUMOTime oldExit = MAX2(oldEarliestExitTime, v->getEventTime());
722 348 : v->updateDetectors(currentTime, oldExit, false);
723 348 : oldEarliestExitTime = oldExit + tauWithVehLength(myTau_ff, v->getVehicleType().getLengthWithGap(), v->getVehicleType().getCarFollowModel().getHeadwayTime());
724 348 : SUMOTime newEvent = MAX2(newArrival(v, newSpeed, currentTime), blockTime);
725 348 : if (v->getEventTime() != newEvent) {
726 326 : MSGlobals::gMesoNet->removeLeaderCar(v);
727 : v->setEventTime(newEvent);
728 326 : MSGlobals::gMesoNet->addLeaderCar(v, getLink(v));
729 : }
730 1071 : for (std::vector<MEVehicle*>::const_reverse_iterator i = vehs.rbegin() + 1; i != vehs.rend(); ++i) {
731 723 : const SUMOTime oldExitTime = MAX2(oldEarliestExitTime, (*i)->getEventTime());
732 723 : (*i)->updateDetectors(currentTime, oldExitTime, false);
733 723 : const SUMOTime minTau = tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
734 723 : oldEarliestExitTime = oldExitTime + minTau;
735 723 : newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + minTau);
736 723 : (*i)->setEventTime(newEvent);
737 : }
738 348 : }
739 :
740 :
741 : SUMOTime
742 1071 : MESegment::newArrival(const MEVehicle* const v, double newSpeed, SUMOTime currentTime) {
743 : // since speed is only an upper bound, pos may be too optimistic
744 1071 : const double pos = MIN2(myLength, STEPS2TIME(currentTime - v->getLastEntryTime()) * v->getSpeed());
745 : // traveltime may not be 0
746 1071 : double tt = (myLength - pos) / MAX2(newSpeed, MESO_MIN_SPEED);
747 1071 : return currentTime + MAX2(TIME2STEPS(tt), SUMOTime(1));
748 : }
749 :
750 :
751 : void
752 991 : MESegment::setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh, int qIdx) {
753 991 : recomputeJamThreshold(jamThresh);
754 : //myTau_length = MAX2(MESO_MIN_SPEED, newSpeed) * myEdge.getLanes().size() / TIME2STEPS(1);
755 : int i = 0;
756 2064 : for (const Queue& q : myQueues) {
757 1073 : if (q.size() != 0) {
758 381 : if (qIdx == -1 || qIdx == i) {
759 348 : setSpeedForQueue(newSpeed, currentTime, q.getBlockTime(), q.getVehicles());
760 : }
761 : }
762 1073 : i++;
763 : }
764 991 : }
765 :
766 :
767 : SUMOTime
768 1312982 : MESegment::getEventTime() const {
769 : SUMOTime result = SUMOTime_MAX;
770 2849489 : for (const Queue& q : myQueues) {
771 1536507 : if (q.size() != 0 && q.getVehicles().back()->getEventTime() < result) {
772 : result = q.getVehicles().back()->getEventTime();
773 : }
774 : }
775 1312982 : if (result < SUMOTime_MAX) {
776 829643 : return result;
777 : }
778 : return -1;
779 : }
780 :
781 :
782 : void
783 7688 : MESegment::saveState(OutputDevice& out) const {
784 : bool write = false;
785 14687 : for (const Queue& q : myQueues) {
786 7735 : if (q.getBlockTime() != -1 || !q.getVehicles().empty()) {
787 : write = true;
788 : break;
789 : }
790 : }
791 7688 : if (write) {
792 736 : out.openTag(SUMO_TAG_SEGMENT).writeAttr(SUMO_ATTR_ID, getID());
793 1486 : for (const Queue& q : myQueues) {
794 750 : out.openTag(SUMO_TAG_VIEWSETTINGS_VEHICLES);
795 750 : out.writeAttr(SUMO_ATTR_TIME, toString<SUMOTime>(q.getBlockTime()));
796 1500 : out.writeAttr(SUMO_ATTR_BLOCKTIME, toString<SUMOTime>(q.getEntryBlockTime()));
797 750 : out.writeAttr(SUMO_ATTR_VALUE, q.getVehicles());
798 1500 : out.closeTag();
799 : }
800 1472 : out.closeTag();
801 : }
802 7688 : }
803 :
804 :
805 : void
806 277 : MESegment::clearState() {
807 554 : for (Queue& q : myQueues) {
808 : q.getModifiableVehicles().clear();
809 : }
810 277 : }
811 :
812 : void
813 585 : MESegment::loadState(const std::vector<SUMOVehicle*>& vehs, const SUMOTime blockTime, const SUMOTime entryBlockTime, const int queIdx) {
814 585 : Queue& q = myQueues[queIdx];
815 1030 : for (SUMOVehicle* veh : vehs) {
816 445 : MEVehicle* v = static_cast<MEVehicle*>(veh);
817 : assert(v->getSegment() == this);
818 445 : q.getModifiableVehicles().push_back(v);
819 445 : myNumVehicles++;
820 445 : q.setOccupancy(q.getOccupancy() + v->getVehicleType().getLengthWithGap());
821 445 : addReminders(v);
822 : }
823 585 : if (q.size() != 0) {
824 : // add the last vehicle of this queue
825 : // !!! one question - what about the previously added vehicle? Is it stored twice?
826 230 : MEVehicle* veh = q.getVehicles().back();
827 230 : MSGlobals::gMesoNet->addLeaderCar(veh, getLink(veh));
828 : }
829 : q.setBlockTime(blockTime);
830 : q.setEntryBlockTime(entryBlockTime);
831 585 : q.setOccupancy(MIN2(q.getOccupancy(), myQueueCapacity));
832 585 : }
833 :
834 :
835 : std::vector<const MEVehicle*>
836 88 : MESegment::getVehicles() const {
837 : std::vector<const MEVehicle*> result;
838 228 : for (const Queue& q : myQueues) {
839 140 : result.insert(result.end(), q.getVehicles().begin(), q.getVehicles().end());
840 : }
841 88 : return result;
842 0 : }
843 :
844 :
845 : bool
846 3905417 : MESegment::hasBlockedLeader() const {
847 7863878 : for (const Queue& q : myQueues) {
848 3978352 : if (q.size() > 0 && q.getVehicles().back()->getWaitingTime() > 0) {
849 : return true;
850 : }
851 : }
852 : return false;
853 : }
854 :
855 :
856 : double
857 0 : MESegment::getFlow() const {
858 0 : return 3600 * getCarNumber() * getMeanSpeed() / myLength;
859 : }
860 :
861 :
862 : SUMOTime
863 24039521 : MESegment::getLinkPenalty(const MEVehicle* veh) const {
864 24039521 : const MSLink* link = getLink(veh, myTLSPenalty || myCheckMinorPenalty);
865 24039521 : if (link != nullptr) {
866 : SUMOTime result = 0;
867 1139014 : if (link->isTLSControlled() && myTLSPenalty) {
868 : result += link->getMesoTLSPenalty();
869 : }
870 : // minor tls links may get an additional penalty
871 315462 : if (!link->havePriority() &&
872 : // do not apply penalty on top of tLSPenalty
873 1139014 : !myTLSPenalty &&
874 : // do not apply penalty if limited control is active
875 279786 : (!MSGlobals::gMesoLimitedJunctionControl || limitedControlOverride(link))) {
876 277316 : result += myMinorPenalty;
877 : }
878 1139014 : return result;
879 : } else {
880 : return 0;
881 : }
882 : }
883 :
884 :
885 : bool
886 378 : MESegment::tlsPenaltyOverride() const {
887 1052 : for (const MSLane* lane : myEdge.getLanes()) {
888 1832 : for (const MSLink* link : lane->getLinkCont()) {
889 3474 : if (link->isTLSControlled() && StringUtils::toBool(link->getTLLogic()->getParameter(OVERRIDE_TLS_PENALTIES, "0"))) {
890 : return true;
891 : }
892 : }
893 : }
894 : return false;
895 : }
896 :
897 :
898 : double
899 3 : MESegment::getWaitingSeconds() const {
900 : double result = 0;
901 6 : for (const Queue& q : myQueues) {
902 : // @note: only the leader currently accumulates waitingTime but this might change in the future
903 4 : for (const MEVehicle* veh : q.getVehicles()) {
904 1 : result += veh->getWaitingSeconds();
905 : }
906 : }
907 3 : return result;
908 : }
909 :
910 :
911 : /****************************************************************************/
|