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