Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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/output/MSXMLRawOut.h>
33 : #include <microsim/output/MSDetectorFileOutput.h>
34 : #include <microsim/MSVehicleControl.h>
35 : #include <microsim/devices/MSDevice.h>
36 : #include <utils/common/FileHelpers.h>
37 : #include <utils/iodevices/OutputDevice.h>
38 : #include <utils/common/RandHelper.h>
39 : #include "MEVehicle.h"
40 : #include "MELoop.h"
41 : #include "MESegment.h"
42 :
43 : #define DEFAULT_VEH_LENGTH_WITH_GAP (SUMOVTypeParameter::getDefault().length + SUMOVTypeParameter::getDefault().minGap)
44 : // avoid division by zero when driving very slowly
45 : #define MESO_MIN_SPEED (0.05)
46 :
47 : //#define DEBUG_OPENED
48 : //#define DEBUG_JAMTHRESHOLD
49 : //#define DEBUG_COND (getID() == "blocker")
50 : //#define DEBUG_COND (true)
51 : #define DEBUG_COND (myEdge.isSelected())
52 : #define DEBUG_COND2(obj) ((obj != 0 && (obj)->isSelected()))
53 :
54 :
55 : // ===========================================================================
56 : // static member definition
57 : // ===========================================================================
58 : MSEdge MESegment::myDummyParent("MESegmentDummyParent", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", -1, 0);
59 : MESegment MESegment::myVaporizationTarget("vaporizationTarget");
60 : const double MESegment::DO_NOT_PATCH_JAM_THRESHOLD(std::numeric_limits<double>::max());
61 :
62 :
63 : // ===========================================================================
64 : // MESegment::Queue method definitions
65 : // ===========================================================================
66 : MEVehicle*
67 33757994 : MESegment::Queue::remove(MEVehicle* v) {
68 33757994 : myOccupancy -= v->getVehicleType().getLengthWithGap();
69 : assert(std::find(myVehicles.begin(), myVehicles.end(), v) != myVehicles.end());
70 33757994 : if (v == myVehicles.back()) {
71 : myVehicles.pop_back();
72 33751715 : if (myVehicles.empty()) {
73 11668425 : myOccupancy = 0.;
74 : } else {
75 22083290 : return myVehicles.back();
76 : }
77 : } else {
78 6279 : myVehicles.erase(std::find(myVehicles.begin(), myVehicles.end(), v));
79 : }
80 : return nullptr;
81 : }
82 :
83 : void
84 119963 : MESegment::Queue::addDetector(MSMoveReminder* data) {
85 119963 : myDetectorData.push_back(data);
86 125401 : for (MEVehicle* const v : myVehicles) {
87 5438 : v->addReminder(data);
88 : }
89 119963 : }
90 :
91 : void
92 33795048 : MESegment::Queue::addReminders(MEVehicle* veh) const {
93 43105891 : for (MSMoveReminder* rem : myDetectorData) {
94 9310843 : veh->addReminder(rem);
95 : }
96 33795048 : }
97 :
98 : // ===========================================================================
99 : // MESegment method definitions
100 : // ===========================================================================
101 608891 : MESegment::MESegment(const std::string& id,
102 : const MSEdge& parent, MESegment* next,
103 : const double length, const double speed,
104 : const int idx,
105 : const bool multiQueue,
106 608891 : const MesoEdgeType& edgeType):
107 608891 : Named(id), myEdge(parent), myNextSegment(next),
108 608891 : myLength(length), myIndex(idx),
109 608891 : myTau_length(TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, speed)),
110 608891 : myNumVehicles(0),
111 608891 : myLastHeadway(TIME2STEPS(-1)),
112 608891 : myMeanSpeed(speed),
113 1217539 : myLastMeanSpeedUpdate(SUMOTime_MIN) {
114 :
115 : const std::vector<MSLane*>& lanes = parent.getLanes();
116 : int usableLanes = 0;
117 1307765 : for (MSLane* const l : lanes) {
118 698874 : const SVCPermissions allow = MSEdge::getMesoPermissions(l->getPermissions());
119 698874 : if (multiQueue) {
120 30375 : myQueues.push_back(Queue(allow));
121 : }
122 698874 : if (allow != 0) {
123 672612 : usableLanes++;
124 : }
125 : }
126 608891 : if (multiQueue) {
127 13552 : if (next == nullptr) {
128 56542 : for (const MSEdge* const edge : parent.getSuccessors()) {
129 43320 : const std::vector<MSLane*>* const allowed = parent.allowedLanes(*edge);
130 : assert(allowed != nullptr);
131 : assert(allowed->size() > 0);
132 92615 : for (MSLane* const l : *allowed) {
133 49295 : std::vector<MSLane*>::const_iterator it = std::find(lanes.begin(), lanes.end(), l);
134 49295 : myFollowerMap[edge] |= (1 << distance(lanes.begin(), it));
135 : }
136 : }
137 : }
138 13552 : myQueueCapacity = length;
139 : } else {
140 595339 : myQueues.push_back(Queue(parent.getPermissions()));
141 : }
142 :
143 608891 : initSegment(edgeType, parent, length * usableLanes);
144 608891 : }
145 :
146 : void
147 609131 : MESegment::initSegment(const MesoEdgeType& edgeType, const MSEdge& parent, const double capacity) {
148 :
149 609131 : myCapacity = capacity;
150 609131 : if (myQueues.size() == 1) {
151 595963 : const double laneScale = capacity / myLength;
152 595963 : myQueueCapacity = capacity;
153 595963 : myTau_length = TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, myMeanSpeed) / laneScale;
154 : // Eissfeldt p. 90 and 151 ff.
155 595963 : myTau_ff = (SUMOTime)((double)edgeType.tauff / laneScale);
156 595963 : myTau_fj = (SUMOTime)((double)edgeType.taufj / laneScale);
157 595963 : myTau_jf = (SUMOTime)((double)edgeType.taujf / laneScale);
158 595963 : myTau_jj = (SUMOTime)((double)edgeType.taujj / laneScale);
159 : } else {
160 13168 : myTau_ff = edgeType.tauff;
161 13168 : myTau_fj = edgeType.taufj;
162 13168 : myTau_jf = edgeType.taujf;
163 13168 : myTau_jj = edgeType.taujj;
164 : }
165 :
166 609131 : myJunctionControl = myNextSegment == nullptr && (edgeType.junctionControl || MELoop::isEnteringRoundabout(parent));
167 608483 : myTLSPenalty = ((edgeType.tlsPenalty > 0 || edgeType.tlsFlowPenalty > 0) &&
168 : // only apply to the last segment of a tls-controlled edge
169 609407 : myNextSegment == nullptr && (
170 206 : parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT ||
171 206 : parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION ||
172 : parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED));
173 :
174 : // only apply to the last segment of an uncontrolled edge that has at least 1 minor link
175 1218582 : myCheckMinorPenalty = (edgeType.minorPenalty > 0 &&
176 320 : myNextSegment == nullptr &&
177 178 : parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT &&
178 178 : parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION &&
179 609309 : parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
180 178 : parent.hasMinorLink());
181 609131 : myMinorPenalty = edgeType.minorPenalty;
182 609131 : myOvertaking = edgeType.overtaking && myCapacity > myLength;
183 :
184 : //std::cout << getID() << " myMinorPenalty=" << myMinorPenalty << " myTLSPenalty=" << myTLSPenalty << " myJunctionControl=" << myJunctionControl << " myOvertaking=" << myOvertaking << "\n";
185 :
186 609131 : recomputeJamThreshold(edgeType.jamThreshold);
187 609131 : }
188 :
189 36277 : MESegment::MESegment(const std::string& id):
190 : Named(id),
191 36277 : myEdge(myDummyParent), // arbitrary edge needed to supply the needed reference
192 36277 : myNextSegment(nullptr), myLength(0), myIndex(0),
193 36277 : myTau_ff(0), myTau_fj(0), myTau_jf(0), myTau_jj(0),
194 36277 : myTLSPenalty(false),
195 36277 : myCheckMinorPenalty(false),
196 36277 : myMinorPenalty(0),
197 36277 : myJunctionControl(false),
198 36277 : myOvertaking(false),
199 36277 : myTau_length(1) {
200 36277 : }
201 :
202 :
203 : void
204 1126 : MESegment::updatePermissions() {
205 1126 : if (myQueues.size() > 1) {
206 64 : for (MSLane* lane : myEdge.getLanes()) {
207 48 : myQueues[lane->getIndex()].setPermissions(lane->getPermissions());
208 : }
209 : } else {
210 1110 : myQueues.back().setPermissions(myEdge.getPermissions());
211 : }
212 1126 : }
213 :
214 :
215 : void
216 610102 : MESegment::recomputeJamThreshold(double jamThresh) {
217 610102 : if (jamThresh == DO_NOT_PATCH_JAM_THRESHOLD) {
218 : return;
219 : }
220 610102 : if (jamThresh < 0) {
221 : // compute based on speed
222 610098 : myJamThreshold = jamThresholdForSpeed(myEdge.getSpeedLimit(), jamThresh);
223 : } else {
224 : // compute based on specified percentage
225 4 : myJamThreshold = jamThresh * myCapacity;
226 : }
227 : }
228 :
229 :
230 : double
231 3984947 : MESegment::jamThresholdForSpeed(double speed, double jamThresh) const {
232 : // vehicles driving freely at maximum speed should not jam
233 : // we compute how many vehicles could possible enter the segment until the first vehicle leaves
234 : // and multiply by the space these vehicles would occupy
235 : // the jamThresh parameter is scale the resulting value
236 3984947 : if (speed == 0) {
237 : return std::numeric_limits<double>::max(); // never jam. Irrelevant at speed 0 anyway
238 : }
239 : #ifdef DEBUG_JAMTHRESHOLD
240 : if (true || DEBUG_COND) {
241 : 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
242 : << "\n";
243 : }
244 : #endif
245 3984726 : return std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGTH_WITH_GAP, 1.)))) * DEFAULT_VEH_LENGTH_WITH_GAP;
246 : }
247 :
248 :
249 : void
250 118417 : MESegment::addDetector(MSMoveReminder* data, int queueIndex) {
251 118417 : if (queueIndex == -1) {
252 237888 : for (Queue& q : myQueues) {
253 119717 : q.addDetector(data);
254 : }
255 : } else {
256 : assert(queueIndex < (int)myQueues.size());
257 246 : myQueues[queueIndex].addDetector(data);
258 : }
259 118417 : }
260 :
261 :
262 : /*
263 : void
264 : MESegment::removeDetector(MSMoveReminder* data) {
265 : std::vector<MSMoveReminder*>::iterator it = std::find(myDetectorData.begin(), myDetectorData.end(), data);
266 : if (it != myDetectorData.end()) {
267 : myDetectorData.erase(it);
268 : }
269 : for (const Queue& q : myQueues) {
270 : for (MEVehicle* const v : q.getVehicles()) {
271 : v->removeReminder(data);
272 : }
273 : }
274 : }
275 : */
276 :
277 :
278 : void
279 6379450 : MESegment::prepareDetectorForWriting(MSMoveReminder& data, int queueIndex) {
280 6379450 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
281 6379450 : if (queueIndex == -1) {
282 12829568 : for (const Queue& q : myQueues) {
283 : SUMOTime earliestExitTime = currentTime;
284 7820000 : for (std::vector<MEVehicle*>::const_reverse_iterator i = q.getVehicles().rbegin(); i != q.getVehicles().rend(); ++i) {
285 1369390 : const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
286 1369390 : (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
287 1369390 : earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
288 : }
289 : }
290 : } else {
291 : SUMOTime earliestExitTime = currentTime;
292 492 : for (std::vector<MEVehicle*>::const_reverse_iterator i = myQueues[queueIndex].getVehicles().rbegin(); i != myQueues[queueIndex].getVehicles().rend(); ++i) {
293 0 : const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
294 0 : (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
295 0 : earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
296 : }
297 : }
298 6379450 : }
299 :
300 :
301 : SUMOTime
302 69888042 : MESegment::hasSpaceFor(const MEVehicle* const veh, const SUMOTime entryTime, int& qIdx, const bool init) const {
303 : SUMOTime earliestEntry = SUMOTime_MAX;
304 69888042 : qIdx = 0;
305 69888042 : if (myNumVehicles == 0 && myQueues.size() == 1) {
306 : // we have always space for at least one vehicle
307 18935178 : if (myQueues.front().allows(veh->getVClass())) {
308 : return entryTime;
309 : } else {
310 237717 : return earliestEntry;
311 : }
312 : }
313 50952864 : const SUMOVehicleClass svc = veh->getVClass();
314 : int minSize = std::numeric_limits<int>::max();
315 50952864 : const MSEdge* const succ = myNextSegment == nullptr ? veh->succEdge(1) : nullptr;
316 103360819 : for (int i = 0; i < (int)myQueues.size(); i++) {
317 52407955 : const Queue& q = myQueues[i];
318 52407955 : const double newOccupancy = q.size() == 0 ? 0. : q.getOccupancy() + veh->getVehicleType().getLengthWithGap();
319 52407955 : if (newOccupancy <= myQueueCapacity) { // we must ensure that occupancy remains below capacity
320 31671963 : if (succ == nullptr || myFollowerMap.count(succ) == 0 || ((myFollowerMap.find(succ)->second & (1 << i)) != 0)) {
321 29941568 : if (q.allows(svc) && q.size() < minSize) {
322 29501722 : if (init) {
323 : // regular insertions and initial insertions must respect different constraints:
324 : // - regular insertions must respect entryBlockTime
325 : // - initial insertions should not cause additional jamming
326 : // - inserted vehicle should be able to continue at the current speed
327 7051465 : if (q.getOccupancy() <= myJamThreshold && !hasBlockedLeader() && !myTLSPenalty) {
328 3676616 : if (newOccupancy <= myJamThreshold) {
329 1327000 : qIdx = i;
330 : minSize = q.size();
331 : }
332 : } else {
333 3374849 : if (newOccupancy <= jamThresholdForSpeed(getMeanSpeed(false), -1)) {
334 2611865 : qIdx = i;
335 : minSize = q.size();
336 : }
337 : }
338 22450257 : } else if (entryTime >= q.getEntryBlockTime()) {
339 22048792 : qIdx = i;
340 : minSize = q.size();
341 : } else {
342 : earliestEntry = MIN2(earliestEntry, q.getEntryBlockTime());
343 : }
344 : }
345 : }
346 : }
347 : }
348 50952864 : if (minSize == std::numeric_limits<int>::max()) {
349 25003579 : return earliestEntry;
350 : }
351 : return entryTime;
352 : }
353 :
354 :
355 : bool
356 2048073 : MESegment::initialise(MEVehicle* veh, SUMOTime time) {
357 2048073 : int qIdx = 0;
358 2048073 : if (hasSpaceFor(veh, time, qIdx, true) == time) {
359 797652 : receive(veh, qIdx, time, true);
360 : // we can check only after insertion because insertion may change the route via devices
361 : std::string msg;
362 1594701 : if (MSGlobals::gCheckRoutes && !veh->hasValidRoute(msg)) {
363 4 : throw ProcessError("Vehicle '" + veh->getID() + "' has no valid route. " + msg);
364 : }
365 : return true;
366 : }
367 : return false;
368 : }
369 :
370 :
371 : double
372 48485921 : MESegment::getMeanSpeed(bool useCached) const {
373 48485921 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
374 48485921 : if (currentTime != myLastMeanSpeedUpdate || !useCached) {
375 48393515 : myLastMeanSpeedUpdate = currentTime;
376 : double v = 0;
377 : int count = 0;
378 97136177 : for (const Queue& q : myQueues) {
379 48742662 : const SUMOTime tau = q.getOccupancy() < myJamThreshold ? myTau_ff : myTau_jf;
380 48742662 : SUMOTime earliestExitTime = currentTime;
381 48742662 : count += q.size();
382 200345816 : for (std::vector<MEVehicle*>::const_reverse_iterator veh = q.getVehicles().rbegin(); veh != q.getVehicles().rend(); ++veh) {
383 151603154 : v += (*veh)->getConservativeSpeed(earliestExitTime); // earliestExitTime is updated!
384 151603154 : earliestExitTime += tauWithVehLength(tau, (*veh)->getVehicleType().getLengthWithGap(), (*veh)->getVehicleType().getCarFollowModel().getHeadwayTime());
385 : }
386 : }
387 48393515 : if (count == 0) {
388 18 : myMeanSpeed = myEdge.getSpeedLimit();
389 : } else {
390 48393497 : myMeanSpeed = v / (double) count;
391 : }
392 : }
393 48485921 : return myMeanSpeed;
394 : }
395 :
396 :
397 : void
398 205994 : MESegment::writeVehicles(OutputDevice& of) const {
399 412356 : for (const Queue& q : myQueues) {
400 220490 : for (const MEVehicle* const veh : q.getVehicles()) {
401 14128 : MSXMLRawOut::writeVehicle(of, *veh);
402 : }
403 : }
404 205994 : }
405 :
406 :
407 : MEVehicle*
408 33757994 : MESegment::removeCar(MEVehicle* v, SUMOTime leaveTime, const MSMoveReminder::Notification reason) {
409 33757994 : Queue& q = myQueues[v->getQueIndex()];
410 : // One could be tempted to do v->setSegment(next); here but position on lane will be invalid if next == 0
411 33757994 : v->updateDetectors(leaveTime, true, reason);
412 33757994 : myNumVehicles--;
413 33757994 : myEdge.lock();
414 33757994 : MEVehicle* nextLeader = q.remove(v);
415 33757994 : myEdge.unlock();
416 33757994 : return nextLeader;
417 : }
418 :
419 :
420 : SUMOTime
421 13548 : MESegment::getNextInsertionTime(SUMOTime earliestEntry) const {
422 : // since we do not know which queue will be used we give a conservative estimate
423 : SUMOTime earliestLeave = earliestEntry;
424 : SUMOTime latestEntry = -1;
425 27354 : for (const Queue& q : myQueues) {
426 : earliestLeave = MAX2(earliestLeave, q.getBlockTime());
427 : latestEntry = MAX2(latestEntry, q.getEntryBlockTime());
428 : }
429 13548 : if (myEdge.getSpeedLimit() == 0) {
430 12 : return MAX2(earliestEntry, latestEntry); // FIXME: This line is just an adhoc-fix to avoid division by zero (Leo)
431 : } else {
432 13536 : return MAX3(earliestEntry, earliestLeave - TIME2STEPS(myLength / myEdge.getSpeedLimit()), latestEntry);
433 : }
434 : }
435 :
436 :
437 : MSLink*
438 150855090 : MESegment::getLink(const MEVehicle* veh, bool penalty) const {
439 150855090 : if (myJunctionControl || penalty) {
440 22564212 : const MSEdge* const nextEdge = veh->succEdge(1);
441 22564212 : if (nextEdge == nullptr || veh->getQueIndex() == PARKING_QUEUE) {
442 : return nullptr;
443 : }
444 : // try to find any link leading to our next edge, start with the lane pointed to by the que index
445 21496678 : const MSLane* const bestLane = myEdge.getLanes()[veh->getQueIndex()];
446 25922784 : for (MSLink* const link : bestLane->getLinkCont()) {
447 25453219 : if (&link->getLane()->getEdge() == nextEdge) {
448 : return link;
449 : }
450 : }
451 : // this is for the non-multique case, maybe we should use caching here !!!
452 999339 : for (const MSLane* const lane : myEdge.getLanes()) {
453 999285 : if (lane != bestLane) {
454 777671 : for (MSLink* const link : lane->getLinkCont()) {
455 659260 : if (&link->getLane()->getEdge() == nextEdge) {
456 : return link;
457 : }
458 : }
459 : }
460 : }
461 : }
462 : return nullptr;
463 : }
464 :
465 :
466 : bool
467 40322031 : MESegment::isOpen(const MEVehicle* veh) const {
468 : #ifdef DEBUG_OPENED
469 : if (DEBUG_COND || DEBUG_COND2(veh)) {
470 : gDebugFlag1 = true;
471 : std::cout << SIMTIME << " opened seg=" << getID() << " veh=" << Named::getIDSecure(veh)
472 : << " tlsPenalty=" << myTLSPenalty;
473 : const MSLink* link = getLink(veh);
474 : if (link == 0) {
475 : std::cout << " link=0";
476 : } else {
477 : std::cout << " prio=" << link->havePriority()
478 : << " override=" << limitedControlOverride(link)
479 : << " isOpen=" << link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
480 : veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
481 : veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime())
482 : << " et=" << veh->getEventTime()
483 : << " v=" << veh->getSpeed()
484 : << " vLeave=" << veh->estimateLeaveSpeed(link)
485 : << " impatience=" << veh->getImpatience()
486 : << " tWait=" << veh->getWaitingTime();
487 : }
488 : std::cout << "\n";
489 : gDebugFlag1 = false;
490 : }
491 : #endif
492 40322031 : if (myTLSPenalty) {
493 : // XXX should limited control take precedence over tls penalty?
494 : return true;
495 : }
496 40273211 : const MSLink* link = getLink(veh);
497 : return (link == nullptr
498 8819652 : || link->havePriority()
499 7719301 : || limitedControlOverride(link)
500 47991748 : || link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
501 7718537 : veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
502 7718537 : veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime()));
503 : }
504 :
505 :
506 : bool
507 7722491 : MESegment::limitedControlOverride(const MSLink* link) const {
508 : assert(link != nullptr);
509 7722491 : if (!MSGlobals::gMesoLimitedJunctionControl) {
510 : return false;
511 : }
512 : // if the target segment of this link is not saturated junction control is disabled
513 : const MSEdge& targetEdge = link->getLane()->getEdge();
514 8248 : const MESegment* target = MSGlobals::gMesoNet->getSegmentForEdge(targetEdge);
515 8248 : return (target->getBruttoOccupancy() * 2 < target->myJamThreshold) && !targetEdge.isRoundabout();
516 : }
517 :
518 :
519 : void
520 33757994 : MESegment::send(MEVehicle* veh, MESegment* const next, const int nextQIdx, SUMOTime time, const MSMoveReminder::Notification reason) {
521 33757994 : Queue& q = myQueues[veh->getQueIndex()];
522 : assert(isInvalid(next) || time >= q.getBlockTime());
523 33757994 : MSLink* const link = getLink(veh);
524 33757994 : if (link != nullptr) {
525 1495344 : link->removeApproaching(veh);
526 : }
527 33757994 : if (veh->isStopped()) {
528 6948 : veh->processStop();
529 : }
530 33757994 : MEVehicle* lc = removeCar(veh, time, reason); // new leaderCar
531 : q.setBlockTime(time);
532 : if (!isInvalid(next)) {
533 32994868 : const bool nextFree = next->myQueues[nextQIdx].getOccupancy() <= next->myJamThreshold;
534 32994868 : const SUMOTime tau = (q.getOccupancy() <= myJamThreshold
535 32994868 : ? (nextFree ? myTau_ff : myTau_fj)
536 437073 : : (nextFree ? myTau_jf : getTauJJ((double)next->myQueues[nextQIdx].size(), next->myQueueCapacity, next->myJamThreshold)));
537 : assert(tau >= 0);
538 32994868 : myLastHeadway = tauWithVehLength(tau, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime());
539 32994868 : if (myTLSPenalty) {
540 48820 : const MSLink* const tllink = getLink(veh, true);
541 48820 : if (tllink != nullptr && tllink->isTLSControlled()) {
542 : assert(tllink->getGreenFraction() > 0);
543 48820 : myLastHeadway = (SUMOTime)((double)myLastHeadway / tllink->getGreenFraction());
544 : }
545 : }
546 32994868 : q.setBlockTime(q.getBlockTime() + myLastHeadway);
547 : }
548 33757994 : if (lc != nullptr) {
549 : lc->setEventTime(MAX2(lc->getEventTime(), q.getBlockTime()));
550 22083290 : MSGlobals::gMesoNet->addLeaderCar(lc, getLink(lc));
551 : }
552 33757994 : }
553 :
554 : SUMOTime
555 139296 : MESegment::getTauJJ(double nextQueueSize, double nextQueueCapacity, double nextJamThreshold) const {
556 : // compute coefficients for the jam-jam headway function
557 : // this function models the effect that "empty space" needs to move
558 : // backwards through the downstream segment before the upstream segment may
559 : // send annother vehicle.
560 : // this allows jams to clear and move upstream.
561 : // the headway function f(x) depends on the number of vehicles in the
562 : // downstream segment x
563 : // f is a linear function that passes through the following fixed points:
564 : // f(n_jam_threshold) = tau_jf_withLength (for continuity)
565 : // f(headwayCapacity) = myTau_jj * headwayCapacity
566 :
567 139296 : const SUMOTime tau_jf_withLength = tauWithVehLength(myTau_jf, DEFAULT_VEH_LENGTH_WITH_GAP, 1.);
568 : // number of vehicles that fit into the NEXT queue (could be larger than expected with DEFAULT_VEH_LENGTH_WITH_GAP!)
569 139296 : const double headwayCapacity = MAX2(nextQueueSize, nextQueueCapacity / DEFAULT_VEH_LENGTH_WITH_GAP);
570 : // number of vehicles above which the NEXT queue is jammed
571 139296 : const double n_jam_threshold = headwayCapacity * nextJamThreshold / nextQueueCapacity;
572 :
573 : // slope a and axis offset b for the jam-jam headway function
574 : // solving f(x) = a * x + b
575 139296 : const double a = (STEPS2TIME(myTau_jj) * headwayCapacity - STEPS2TIME(tau_jf_withLength)) / (headwayCapacity - n_jam_threshold);
576 139296 : const double b = headwayCapacity * (STEPS2TIME(myTau_jj) - a);
577 :
578 : // it is only well defined for nextQueueSize >= n_jam_threshold (which may not be the case for longer vehicles), so we take the MAX
579 139296 : return TIME2STEPS(a * MAX2(nextQueueSize, n_jam_threshold) + b);
580 : }
581 :
582 :
583 : bool
584 1419533 : MESegment::overtake() {
585 1419557 : return myOvertaking && RandHelper::rand() > (getBruttoOccupancy() / myCapacity);
586 : }
587 :
588 :
589 : void
590 33796189 : MESegment::addReminders(MEVehicle* veh) const {
591 33796189 : if (veh->getQueIndex() != PARKING_QUEUE) {
592 33795048 : myQueues[veh->getQueIndex()].addReminders(veh);
593 : }
594 33796189 : }
595 :
596 :
597 : void
598 33794101 : MESegment::receive(MEVehicle* veh, const int qIdx, SUMOTime time, const bool isDepart, const bool isTeleport, const bool newEdge) {
599 33794101 : const double speed = isDepart ? -1 : MAX2(veh->getSpeed(), MESO_MIN_SPEED); // on the previous segment
600 33794101 : veh->setSegment(this); // for arrival checking
601 : veh->setLastEntryTime(time);
602 : veh->setBlockTime(SUMOTime_MAX);
603 33794101 : if (!isDepart && (
604 : // arrival on entering a new edge
605 3662430 : (newEdge && veh->moveRoutePointer())
606 : // arrival on entering a new segment
607 32996291 : || veh->hasArrived())) {
608 : // route has ended
609 15214 : veh->setEventTime(time + TIME2STEPS(myLength / speed)); // for correct arrival speed
610 15214 : addReminders(veh);
611 15214 : veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
612 30324 : veh->updateDetectors(time, true,
613 15214 : veh->getEdge()->isVaporizing() ? MSMoveReminder::NOTIFICATION_VAPORIZED_VAPORIZER : MSMoveReminder::NOTIFICATION_ARRIVED);
614 15214 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
615 15214 : return;
616 : }
617 : assert(veh->getEdge() == &getEdge());
618 : // route continues
619 33778887 : Queue& q = myQueues[qIdx];
620 33778887 : const double maxSpeedOnEdge = veh->getEdge()->getLanes()[qIdx]->getVehicleMaxSpeed(veh);
621 : const double uspeed = MAX2(maxSpeedOnEdge, MESO_MIN_SPEED);
622 : std::vector<MEVehicle*>& cars = q.getModifiableVehicles();
623 : MEVehicle* newLeader = nullptr; // first vehicle in the current queue
624 33778887 : const SUMOTime stopTime = veh->checkStop(time);
625 33778887 : SUMOTime tleave = MAX2(stopTime + TIME2STEPS(myLength / uspeed) + getLinkPenalty(veh), q.getBlockTime());
626 33778887 : if (veh->isStopped()) {
627 8327 : myEdge.addWaiting(veh);
628 : }
629 33778887 : if (veh->isParking()) {
630 : veh->setEventTime(stopTime);
631 1141 : veh->setSegment(this, PARKING_QUEUE);
632 1141 : myEdge.getLanes()[0]->addParking(veh); // TODO for GUI only
633 : } else {
634 33777746 : myEdge.lock();
635 33777746 : if (cars.empty()) {
636 11673296 : cars.push_back(veh);
637 11673296 : newLeader = veh;
638 : } else {
639 22104450 : SUMOTime leaderOut = cars[0]->getEventTime();
640 22104450 : if (!isDepart && leaderOut > tleave && overtake()) {
641 20 : if (cars.size() == 1) {
642 4 : MSGlobals::gMesoNet->removeLeaderCar(cars[0]);
643 : newLeader = veh;
644 : }
645 20 : cars.insert(cars.begin() + 1, veh);
646 : } else {
647 22104430 : tleave = MAX2(leaderOut + tauWithVehLength(myTau_ff, cars[0]->getVehicleType().getLengthWithGap(), cars[0]->getVehicleType().getCarFollowModel().getHeadwayTime()), tleave);
648 22104430 : cars.insert(cars.begin(), veh);
649 : }
650 : }
651 33777746 : myEdge.unlock();
652 33777746 : myNumVehicles++;
653 33777746 : if (!isDepart && !isTeleport) {
654 : // departs and teleports could take place anywhere on the edge so they should not block regular flow
655 : // the -1 facilitates interleaving of multiple streams
656 32979123 : q.setEntryBlockTime(time + tauWithVehLength(myTau_ff, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime()) - 1);
657 : }
658 33777746 : q.setOccupancy(MIN2(myQueueCapacity, q.getOccupancy() + veh->getVehicleType().getLengthWithGap()));
659 : veh->setEventTime(tleave);
660 33777746 : veh->setSegment(this, qIdx);
661 : }
662 33778887 : addReminders(veh);
663 33778887 : if (isDepart) {
664 797652 : veh->onDepart();
665 797652 : veh->activateReminders(MSMoveReminder::NOTIFICATION_DEPARTED);
666 32981235 : } else if (newEdge) {
667 3662272 : veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
668 : } else {
669 29318963 : veh->activateReminders(MSMoveReminder::NOTIFICATION_SEGMENT);
670 : }
671 33778887 : if (veh->isParking()) {
672 1141 : MSGlobals::gMesoNet->addLeaderCar(veh, nullptr);
673 : } else {
674 33777746 : if (newLeader != nullptr) {
675 11673300 : MSGlobals::gMesoNet->addLeaderCar(newLeader, getLink(newLeader));
676 : }
677 : }
678 : }
679 :
680 :
681 : bool
682 8674 : MESegment::vaporizeAnyCar(SUMOTime currentTime, const MSDetectorFileOutput* filter) {
683 9214 : for (const Queue& q : myQueues) {
684 8688 : if (q.size() > 0) {
685 8148 : for (MEVehicle* const veh : q.getVehicles()) {
686 8148 : if (filter->vehicleApplies(*veh)) {
687 8148 : MSGlobals::gMesoNet->removeLeaderCar(veh);
688 8148 : MSGlobals::gMesoNet->changeSegment(veh, currentTime + 1, &myVaporizationTarget, MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR);
689 : return true;
690 : }
691 : }
692 : }
693 : }
694 : return false;
695 : }
696 :
697 :
698 : void
699 346 : MESegment::setSpeedForQueue(double newSpeed, SUMOTime currentTime, SUMOTime blockTime, const std::vector<MEVehicle*>& vehs) {
700 346 : MEVehicle* v = vehs.back();
701 346 : v->updateDetectors(currentTime, false);
702 346 : SUMOTime newEvent = MAX2(newArrival(v, newSpeed, currentTime), blockTime);
703 346 : if (v->getEventTime() != newEvent) {
704 324 : MSGlobals::gMesoNet->removeLeaderCar(v);
705 : v->setEventTime(newEvent);
706 324 : MSGlobals::gMesoNet->addLeaderCar(v, getLink(v));
707 : }
708 1069 : for (std::vector<MEVehicle*>::const_reverse_iterator i = vehs.rbegin() + 1; i != vehs.rend(); ++i) {
709 723 : (*i)->updateDetectors(currentTime, false);
710 723 : newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + myTau_ff);
711 : //newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + myTau_ff + (SUMOTime)((*(i - 1))->getVehicleType().getLength() / myTau_length));
712 723 : (*i)->setEventTime(newEvent);
713 : }
714 346 : }
715 :
716 :
717 : SUMOTime
718 1069 : MESegment::newArrival(const MEVehicle* const v, double newSpeed, SUMOTime currentTime) {
719 : // since speed is only an upper bound pos may be to optimistic
720 1069 : const double pos = MIN2(myLength, STEPS2TIME(currentTime - v->getLastEntryTime()) * v->getSpeed());
721 : // traveltime may not be 0
722 1069 : double tt = (myLength - pos) / MAX2(newSpeed, MESO_MIN_SPEED);
723 1069 : return currentTime + MAX2(TIME2STEPS(tt), SUMOTime(1));
724 : }
725 :
726 :
727 : void
728 971 : MESegment::setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh, int qIdx) {
729 971 : recomputeJamThreshold(jamThresh);
730 : //myTau_length = MAX2(MESO_MIN_SPEED, newSpeed) * myEdge.getLanes().size() / TIME2STEPS(1);
731 : int i = 0;
732 2024 : for (const Queue& q : myQueues) {
733 1053 : if (q.size() != 0) {
734 379 : if (qIdx == -1 || qIdx == i) {
735 346 : setSpeedForQueue(newSpeed, currentTime, q.getBlockTime(), q.getVehicles());
736 : }
737 : }
738 1053 : i++;
739 : }
740 971 : }
741 :
742 :
743 : SUMOTime
744 1185634 : MESegment::getEventTime() const {
745 : SUMOTime result = SUMOTime_MAX;
746 2655719 : for (const Queue& q : myQueues) {
747 1470085 : if (q.size() != 0 && q.getVehicles().back()->getEventTime() < result) {
748 : result = q.getVehicles().back()->getEventTime();
749 : }
750 : }
751 1185634 : if (result < SUMOTime_MAX) {
752 948165 : return result;
753 : }
754 : return -1;
755 : }
756 :
757 :
758 : void
759 5009 : MESegment::saveState(OutputDevice& out) const {
760 : bool write = false;
761 9751 : for (const Queue& q : myQueues) {
762 5048 : if (q.getBlockTime() != -1 || !q.getVehicles().empty()) {
763 : write = true;
764 : break;
765 : }
766 : }
767 5009 : if (write) {
768 612 : out.openTag(SUMO_TAG_SEGMENT).writeAttr(SUMO_ATTR_ID, getID());
769 623 : for (const Queue& q : myQueues) {
770 634 : out.openTag(SUMO_TAG_VIEWSETTINGS_VEHICLES).writeAttr(SUMO_ATTR_TIME, toString<SUMOTime>(q.getBlockTime()));
771 : out.writeAttr(SUMO_ATTR_VALUE, q.getVehicles());
772 634 : out.closeTag();
773 : }
774 612 : out.closeTag();
775 : }
776 5009 : }
777 :
778 :
779 : void
780 29 : MESegment::clearState() {
781 58 : for (Queue& q : myQueues) {
782 : q.getModifiableVehicles().clear();
783 : }
784 29 : }
785 :
786 : void
787 216 : MESegment::loadState(const std::vector<std::string>& vehIds, MSVehicleControl& vc, const SUMOTime block, const int queIdx) {
788 216 : Queue& q = myQueues[queIdx];
789 431 : for (const std::string& id : vehIds) {
790 215 : MEVehicle* v = static_cast<MEVehicle*>(vc.getVehicle(id));
791 : // vehicle could be removed due to options
792 215 : if (v != nullptr) {
793 : assert(v->getSegment() == this);
794 213 : q.getModifiableVehicles().push_back(v);
795 213 : myNumVehicles++;
796 213 : q.setOccupancy(q.getOccupancy() + v->getVehicleType().getLengthWithGap());
797 : }
798 : }
799 216 : if (q.size() != 0) {
800 : // add the last vehicle of this queue
801 : // !!! one question - what about the previously added vehicle? Is it stored twice?
802 98 : MEVehicle* veh = q.getVehicles().back();
803 98 : MSGlobals::gMesoNet->addLeaderCar(veh, getLink(veh));
804 : }
805 : q.setBlockTime(block);
806 216 : q.setOccupancy(MIN2(q.getOccupancy(), myQueueCapacity));
807 216 : }
808 :
809 :
810 : std::vector<const MEVehicle*>
811 80 : MESegment::getVehicles() const {
812 : std::vector<const MEVehicle*> result;
813 180 : for (const Queue& q : myQueues) {
814 100 : result.insert(result.end(), q.getVehicles().begin(), q.getVehicles().end());
815 : }
816 80 : return result;
817 : }
818 :
819 :
820 : bool
821 3688019 : MESegment::hasBlockedLeader() const {
822 7435649 : for (const Queue& q : myQueues) {
823 3758891 : if (q.size() > 0 && q.getVehicles().back()->getWaitingTime() > 0) {
824 : return true;
825 : }
826 : }
827 : return false;
828 : }
829 :
830 :
831 : double
832 0 : MESegment::getFlow() const {
833 0 : return 3600 * getCarNumber() * getMeanSpeed() / myLength;
834 : }
835 :
836 :
837 : SUMOTime
838 33778887 : MESegment::getLinkPenalty(const MEVehicle* veh) const {
839 67504332 : const MSLink* link = getLink(veh, myTLSPenalty || myCheckMinorPenalty);
840 33778887 : if (link != nullptr) {
841 : SUMOTime result = 0;
842 1546335 : if (link->isTLSControlled()) {
843 : result += link->getMesoTLSPenalty();
844 : }
845 : // minor tls links may get an additional penalty
846 448432 : if (!link->havePriority() &&
847 : // do not apply penalty on top of tLSPenalty
848 1546335 : !myTLSPenalty &&
849 : // do not apply penalty if limited control is active
850 413156 : (!MSGlobals::gMesoLimitedJunctionControl || limitedControlOverride(link))) {
851 410686 : result += myMinorPenalty;
852 : }
853 1546335 : return result;
854 : } else {
855 : return 0;
856 : }
857 : }
858 :
859 :
860 : double
861 3 : MESegment::getWaitingSeconds() const {
862 : double result = 0;
863 6 : for (const Queue& q : myQueues) {
864 : // @note: only the leader currently accumulates waitingTime but this might change in the future
865 4 : for (const MEVehicle* veh : q.getVehicles()) {
866 1 : result += veh->getWaitingSeconds();
867 : }
868 : }
869 3 : return result;
870 : }
871 :
872 :
873 : /****************************************************************************/
|