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 23770312 : MESegment::Queue::remove(MEVehicle* v) {
68 23770312 : myOccupancy -= v->getVehicleType().getLengthWithGap();
69 : assert(std::find(myVehicles.begin(), myVehicles.end(), v) != myVehicles.end());
70 23770312 : if (v == myVehicles.back()) {
71 : myVehicles.pop_back();
72 23764033 : if (myVehicles.empty()) {
73 6261913 : myOccupancy = 0.;
74 : } else {
75 17502120 : 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 122121 : MESegment::Queue::addDetector(MSMoveReminder* data) {
85 122121 : myDetectorData.push_back(data);
86 127833 : for (MEVehicle* const v : myVehicles) {
87 5712 : v->addReminder(data);
88 : }
89 122121 : }
90 :
91 : void
92 23807575 : MESegment::Queue::addReminders(MEVehicle* veh) const {
93 33138922 : for (MSMoveReminder* rem : myDetectorData) {
94 9331347 : veh->addReminder(rem);
95 : }
96 23807575 : }
97 :
98 : // ===========================================================================
99 : // MESegment method definitions
100 : // ===========================================================================
101 562854 : 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 562854 : const MesoEdgeType& edgeType):
107 562854 : Named(id), myEdge(parent), myNextSegment(next),
108 562854 : myLength(length), myIndex(idx),
109 562854 : myTau_length(TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, speed)),
110 562854 : myNumVehicles(0),
111 562854 : myLastHeadway(TIME2STEPS(-1)),
112 562854 : myMeanSpeed(speed),
113 1125417 : myLastMeanSpeedUpdate(SUMOTime_MIN) {
114 :
115 : const std::vector<MSLane*>& lanes = parent.getLanes();
116 : int usableLanes = 0;
117 1221633 : for (MSLane* const l : lanes) {
118 658779 : const SVCPermissions allow = MSEdge::getMesoPermissions(l->getPermissions());
119 658779 : if (multiQueue) {
120 64742 : myQueues.push_back(Queue(allow));
121 : }
122 658779 : if (allow != 0) {
123 630495 : usableLanes++;
124 : }
125 : }
126 562854 : if (usableLanes == 0) {
127 : // cars won't drive here. Give sensible tau values capacity for the ignored classes
128 : usableLanes = 1;
129 : }
130 562854 : if (multiQueue) {
131 14480 : if (next == nullptr) {
132 60506 : for (const MSEdge* const edge : parent.getSuccessors()) {
133 46370 : const std::vector<MSLane*>* const allowed = parent.allowedLanes(*edge);
134 : assert(allowed != nullptr);
135 : assert(allowed->size() > 0);
136 99059 : for (MSLane* const l : *allowed) {
137 52689 : std::vector<MSLane*>::const_iterator it = std::find(lanes.begin(), lanes.end(), l);
138 52689 : myFollowerMap[edge] |= (1 << distance(lanes.begin(), it));
139 : }
140 : }
141 : }
142 14480 : myQueueCapacity = length;
143 : } else {
144 1096748 : myQueues.push_back(Queue(parent.getPermissions()));
145 : }
146 :
147 562854 : initSegment(edgeType, parent, length * usableLanes);
148 562854 : }
149 :
150 : void
151 563094 : MESegment::initSegment(const MesoEdgeType& edgeType, const MSEdge& parent, const double capacity) {
152 :
153 563094 : myCapacity = capacity;
154 563094 : if (myQueues.size() == 1) {
155 549002 : const double laneScale = capacity / myLength;
156 549002 : myQueueCapacity = capacity;
157 549002 : myTau_length = TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, myMeanSpeed) / laneScale;
158 : // Eissfeldt p. 90 and 151 ff.
159 549002 : myTau_ff = (SUMOTime)((double)edgeType.tauff / laneScale);
160 549002 : myTau_fj = (SUMOTime)((double)edgeType.taufj / laneScale);
161 549002 : myTau_jf = (SUMOTime)((double)edgeType.taujf / laneScale);
162 549002 : myTau_jj = (SUMOTime)((double)edgeType.taujj / laneScale);
163 : } else {
164 14092 : myTau_ff = edgeType.tauff;
165 14092 : myTau_fj = edgeType.taufj;
166 14092 : myTau_jf = edgeType.taujf;
167 14092 : myTau_jj = edgeType.taujj;
168 : }
169 :
170 563094 : myJunctionControl = myNextSegment == nullptr && (edgeType.junctionControl || MELoop::isEnteringRoundabout(parent));
171 562446 : myTLSPenalty = ((edgeType.tlsPenalty > 0 || edgeType.tlsFlowPenalty > 0) &&
172 : // only apply to the last segment of a tls-controlled edge
173 563370 : myNextSegment == nullptr && (
174 206 : parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT ||
175 206 : parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION ||
176 : parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED));
177 :
178 : // only apply to the last segment of an uncontrolled edge that has at least 1 minor link
179 1126508 : myCheckMinorPenalty = (edgeType.minorPenalty > 0 &&
180 320 : myNextSegment == nullptr &&
181 : parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT &&
182 : parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION &&
183 563272 : parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
184 178 : parent.hasMinorLink());
185 563094 : myMinorPenalty = edgeType.minorPenalty;
186 563094 : myOvertaking = edgeType.overtaking && myCapacity > myLength;
187 :
188 : //std::cout << getID() << " myMinorPenalty=" << myMinorPenalty << " myTLSPenalty=" << myTLSPenalty << " myJunctionControl=" << myJunctionControl << " myOvertaking=" << myOvertaking << "\n";
189 :
190 563094 : recomputeJamThreshold(edgeType.jamThreshold);
191 563094 : }
192 :
193 43383 : MESegment::MESegment(const std::string& id):
194 : Named(id),
195 43383 : myEdge(myDummyParent), // arbitrary edge needed to supply the needed reference
196 43383 : myNextSegment(nullptr), myLength(0), myIndex(0),
197 43383 : myTau_ff(0), myTau_fj(0), myTau_jf(0), myTau_jj(0),
198 43383 : myTLSPenalty(false),
199 43383 : myCheckMinorPenalty(false),
200 43383 : myMinorPenalty(0),
201 43383 : myJunctionControl(false),
202 43383 : myOvertaking(false),
203 43383 : myTau_length(1) {
204 43383 : }
205 :
206 :
207 : void
208 1128 : MESegment::updatePermissions() {
209 1128 : if (myQueues.size() > 1) {
210 64 : for (MSLane* lane : myEdge.getLanes()) {
211 48 : myQueues[lane->getIndex()].setPermissions(lane->getPermissions());
212 : }
213 : } else {
214 1112 : myQueues.back().setPermissions(myEdge.getPermissions());
215 : }
216 1128 : }
217 :
218 :
219 : void
220 564065 : MESegment::recomputeJamThreshold(double jamThresh) {
221 564065 : if (jamThresh == DO_NOT_PATCH_JAM_THRESHOLD) {
222 : return;
223 : }
224 564065 : if (jamThresh < 0) {
225 : // compute based on speed
226 564061 : myJamThreshold = jamThresholdForSpeed(myEdge.getSpeedLimit(), jamThresh);
227 : } else {
228 : // compute based on specified percentage
229 4 : myJamThreshold = jamThresh * myCapacity;
230 : }
231 : }
232 :
233 :
234 : double
235 3943596 : MESegment::jamThresholdForSpeed(double speed, double jamThresh) const {
236 : // vehicles driving freely at maximum speed should not jam
237 : // we compute how many vehicles could possible enter the segment until the first vehicle leaves
238 : // and multiply by the space these vehicles would occupy
239 : // the jamThresh parameter is scale the resulting value
240 3943596 : if (speed == 0) {
241 : return std::numeric_limits<double>::max(); // never jam. Irrelevant at speed 0 anyway
242 : }
243 : #ifdef DEBUG_JAMTHRESHOLD
244 : if (true || DEBUG_COND) {
245 : 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
246 : << "\n";
247 : }
248 : #endif
249 3943375 : return std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGTH_WITH_GAP, 1.)))) * DEFAULT_VEH_LENGTH_WITH_GAP;
250 : }
251 :
252 :
253 : void
254 120511 : MESegment::addDetector(MSMoveReminder* data, int queueIndex) {
255 120511 : if (queueIndex == -1) {
256 238764 : for (Queue& q : myQueues) {
257 120187 : q.addDetector(data);
258 : }
259 : } else {
260 : assert(queueIndex < (int)myQueues.size());
261 1934 : myQueues[queueIndex].addDetector(data);
262 : }
263 120511 : }
264 :
265 :
266 : /*
267 : void
268 : MESegment::removeDetector(MSMoveReminder* data) {
269 : std::vector<MSMoveReminder*>::iterator it = std::find(myDetectorData.begin(), myDetectorData.end(), data);
270 : if (it != myDetectorData.end()) {
271 : myDetectorData.erase(it);
272 : }
273 : for (const Queue& q : myQueues) {
274 : for (MEVehicle* const v : q.getVehicles()) {
275 : v->removeReminder(data);
276 : }
277 : }
278 : }
279 : */
280 :
281 :
282 : void
283 6380864 : MESegment::prepareDetectorForWriting(MSMoveReminder& data, int queueIndex) {
284 6380864 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
285 6380864 : if (queueIndex == -1) {
286 12833364 : for (const Queue& q : myQueues) {
287 : SUMOTime earliestExitTime = currentTime;
288 7827398 : for (std::vector<MEVehicle*>::const_reverse_iterator i = q.getVehicles().rbegin(); i != q.getVehicles().rend(); ++i) {
289 1374298 : const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
290 1374298 : (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
291 1374298 : earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
292 : }
293 : }
294 : } else {
295 : SUMOTime earliestExitTime = currentTime;
296 612 : for (std::vector<MEVehicle*>::const_reverse_iterator i = myQueues[queueIndex].getVehicles().rbegin(); i != myQueues[queueIndex].getVehicles().rend(); ++i) {
297 12 : const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
298 12 : (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
299 12 : earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
300 : }
301 : }
302 6380864 : }
303 :
304 :
305 : SUMOTime
306 61047410 : MESegment::hasSpaceFor(const MEVehicle* const veh, const SUMOTime entryTime, int& qIdx, const bool init) const {
307 : SUMOTime earliestEntry = SUMOTime_MAX;
308 61047410 : qIdx = 0;
309 61047410 : if (myNumVehicles == 0 && myQueues.size() == 1) {
310 : // we have always space for at least one vehicle
311 14935909 : if (myQueues.front().allows(veh->getVClass())) {
312 : return entryTime;
313 : } else {
314 : return earliestEntry;
315 : }
316 : }
317 46111501 : const SUMOVehicleClass svc = veh->getVClass();
318 : int minSize = std::numeric_limits<int>::max();
319 46111501 : const MSEdge* const succ = myNextSegment == nullptr ? veh->succEdge(1) : nullptr;
320 93727113 : for (int i = 0; i < (int)myQueues.size(); i++) {
321 47615612 : const Queue& q = myQueues[i];
322 47615612 : const double newOccupancy = q.size() == 0 ? 0. : q.getOccupancy() + veh->getVehicleType().getLengthWithGap();
323 47615612 : if (newOccupancy <= myQueueCapacity) { // we must ensure that occupancy remains below capacity
324 26972408 : if (succ == nullptr || myFollowerMap.count(succ) == 0 || ((myFollowerMap.find(succ)->second & (1 << i)) != 0)) {
325 25191026 : if (q.allows(svc) && q.size() < minSize) {
326 24722026 : if (init) {
327 : // regular insertions and initial insertions must respect different constraints:
328 : // - regular insertions must respect entryBlockTime
329 : // - initial insertions should not cause additional jamming
330 : // - inserted vehicle should be able to continue at the current speed
331 6949492 : if (q.getOccupancy() <= myJamThreshold && !hasBlockedLeader() && !myTLSPenalty) {
332 3569957 : if (newOccupancy <= myJamThreshold) {
333 1219975 : qIdx = i;
334 : minSize = q.size();
335 : }
336 : } else {
337 3379535 : if (newOccupancy <= jamThresholdForSpeed(getMeanSpeed(false), -1)) {
338 2616525 : qIdx = i;
339 : minSize = q.size();
340 : }
341 : }
342 17772534 : } else if (entryTime >= q.getEntryBlockTime()) {
343 17477965 : qIdx = i;
344 : minSize = q.size();
345 : } else {
346 : earliestEntry = MIN2(earliestEntry, q.getEntryBlockTime());
347 : }
348 : }
349 : }
350 : }
351 : }
352 46111501 : if (minSize == std::numeric_limits<int>::max()) {
353 : return earliestEntry;
354 : }
355 : return entryTime;
356 : }
357 :
358 :
359 : bool
360 1965903 : MESegment::initialise(MEVehicle* veh, SUMOTime time) {
361 1965903 : int qIdx = 0;
362 1965903 : if (hasSpaceFor(veh, time, qIdx, true) == time) {
363 677568 : receive(veh, qIdx, time, true);
364 : // we can check only after insertion because insertion may change the route via devices
365 : std::string msg;
366 1354482 : if (MSGlobals::gCheckRoutes && !veh->hasValidRoute(msg)) {
367 4 : throw ProcessError("Vehicle '" + veh->getID() + "' has no valid route. " + msg);
368 : }
369 : return true;
370 : }
371 : return false;
372 : }
373 :
374 :
375 : double
376 26858148 : MESegment::getMeanSpeed(bool useCached) const {
377 26858148 : const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
378 26858148 : if (currentTime != myLastMeanSpeedUpdate || !useCached) {
379 26765652 : myLastMeanSpeedUpdate = currentTime;
380 : double v = 0;
381 : int count = 0;
382 53877551 : for (const Queue& q : myQueues) {
383 27111899 : const SUMOTime tau = q.getOccupancy() < myJamThreshold ? myTau_ff : myTau_jf;
384 27111899 : SUMOTime earliestExitTime = currentTime;
385 27111899 : count += q.size();
386 131913974 : for (std::vector<MEVehicle*>::const_reverse_iterator veh = q.getVehicles().rbegin(); veh != q.getVehicles().rend(); ++veh) {
387 104802075 : v += (*veh)->getConservativeSpeed(earliestExitTime); // earliestExitTime is updated!
388 104802075 : earliestExitTime += tauWithVehLength(tau, (*veh)->getVehicleType().getLengthWithGap(), (*veh)->getVehicleType().getCarFollowModel().getHeadwayTime());
389 : }
390 : }
391 26765652 : if (count == 0) {
392 18 : myMeanSpeed = myEdge.getSpeedLimit();
393 : } else {
394 26765634 : myMeanSpeed = v / (double) count;
395 : }
396 : }
397 26858148 : return myMeanSpeed;
398 : }
399 :
400 :
401 : void
402 206604 : MESegment::writeVehicles(OutputDevice& of) const {
403 413626 : for (const Queue& q : myQueues) {
404 221272 : for (const MEVehicle* const veh : q.getVehicles()) {
405 14250 : MSXMLRawOut::writeVehicle(of, *veh);
406 : }
407 : }
408 206604 : }
409 :
410 :
411 : MEVehicle*
412 23770312 : MESegment::removeCar(MEVehicle* v, SUMOTime leaveTime, const MSMoveReminder::Notification reason) {
413 23770312 : Queue& q = myQueues[v->getQueIndex()];
414 : // One could be tempted to do v->setSegment(next); here but position on lane will be invalid if next == 0
415 23770312 : v->updateDetectors(leaveTime, true, reason);
416 23770312 : myNumVehicles--;
417 23770312 : myEdge.lock();
418 23770312 : MEVehicle* nextLeader = q.remove(v);
419 23770312 : myEdge.unlock();
420 23770312 : return nextLeader;
421 : }
422 :
423 :
424 : SUMOTime
425 13548 : MESegment::getNextInsertionTime(SUMOTime earliestEntry) const {
426 : // since we do not know which queue will be used we give a conservative estimate
427 : SUMOTime earliestLeave = earliestEntry;
428 : SUMOTime latestEntry = -1;
429 27354 : for (const Queue& q : myQueues) {
430 : earliestLeave = MAX2(earliestLeave, q.getBlockTime());
431 : latestEntry = MAX2(latestEntry, q.getEntryBlockTime());
432 : }
433 13548 : if (myEdge.getSpeedLimit() == 0) {
434 12 : return MAX2(earliestEntry, latestEntry); // FIXME: This line is just an adhoc-fix to avoid division by zero (Leo)
435 : } else {
436 13536 : return MAX3(earliestEntry, earliestLeave - TIME2STEPS(myLength / myEdge.getSpeedLimit()), latestEntry);
437 : }
438 : }
439 :
440 :
441 : MSLink*
442 113213468 : MESegment::getLink(const MEVehicle* veh, bool penalty) const {
443 113213468 : if (myJunctionControl || penalty) {
444 23010617 : const MSEdge* const nextEdge = veh->succEdge(1);
445 23010617 : if (nextEdge == nullptr || veh->getQueIndex() == PARKING_QUEUE) {
446 : return nullptr;
447 : }
448 : // try to find any link leading to our next edge, start with the lane pointed to by the que index
449 22093035 : const MSLane* const bestLane = myEdge.getLanes()[veh->getQueIndex()];
450 25067837 : for (MSLink* const link : bestLane->getLinkCont()) {
451 24595719 : if (&link->getLane()->getEdge() == nextEdge) {
452 : return link;
453 : }
454 : }
455 : // this is for the non-multique case, maybe we should use caching here !!!
456 1006870 : for (const MSLane* const lane : myEdge.getLanes()) {
457 1006770 : if (lane != bestLane) {
458 785063 : for (MSLink* const link : lane->getLinkCont()) {
459 664227 : if (&link->getLane()->getEdge() == nextEdge) {
460 : return link;
461 : }
462 : }
463 : }
464 : }
465 : }
466 : return nullptr;
467 : }
468 :
469 :
470 : bool
471 31532328 : MESegment::isOpen(const MEVehicle* veh) const {
472 : #ifdef DEBUG_OPENED
473 : if (DEBUG_COND || DEBUG_COND2(veh)) {
474 : gDebugFlag1 = true;
475 : std::cout << SIMTIME << " opened seg=" << getID() << " veh=" << Named::getIDSecure(veh)
476 : << " tlsPenalty=" << myTLSPenalty;
477 : const MSLink* link = getLink(veh);
478 : if (link == 0) {
479 : std::cout << " link=0";
480 : } else {
481 : std::cout << " prio=" << link->havePriority()
482 : << " override=" << limitedControlOverride(link)
483 : << " isOpen=" << link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
484 : veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
485 : veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime(),
486 : 0, nullptr, false, veh)
487 : << " et=" << veh->getEventTime()
488 : << " v=" << veh->getSpeed()
489 : << " vLeave=" << veh->estimateLeaveSpeed(link)
490 : << " impatience=" << veh->getImpatience()
491 : << " tWait=" << veh->getWaitingTime();
492 : }
493 : std::cout << "\n";
494 : gDebugFlag1 = false;
495 : }
496 : #endif
497 31532328 : if (myTLSPenalty) {
498 : // XXX should limited control take precedence over tls penalty?
499 : return true;
500 : }
501 31483508 : const MSLink* link = getLink(veh);
502 : return (link == nullptr
503 9471465 : || link->havePriority()
504 8659672 : || limitedControlOverride(link)
505 40142416 : || link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
506 8658908 : veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
507 8658908 : veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime(),
508 : 0, nullptr, false, veh));
509 : }
510 :
511 :
512 : bool
513 8662862 : MESegment::limitedControlOverride(const MSLink* link) const {
514 : assert(link != nullptr);
515 8662862 : if (!MSGlobals::gMesoLimitedJunctionControl) {
516 : return false;
517 : }
518 : // if the target segment of this link is not saturated junction control is disabled
519 : const MSEdge& targetEdge = link->getLane()->getEdge();
520 8248 : const MESegment* target = MSGlobals::gMesoNet->getSegmentForEdge(targetEdge);
521 8248 : return (target->getBruttoOccupancy() * 2 < target->myJamThreshold) && !targetEdge.isRoundabout();
522 : }
523 :
524 :
525 : void
526 23770312 : MESegment::send(MEVehicle* veh, MESegment* const next, const int nextQIdx, SUMOTime time, const MSMoveReminder::Notification reason) {
527 23770312 : Queue& q = myQueues[veh->getQueIndex()];
528 : assert(isInvalid(next) || time >= q.getBlockTime());
529 23770312 : MSLink* const link = getLink(veh);
530 23770312 : if (link != nullptr) {
531 1069669 : link->removeApproaching(veh);
532 : }
533 23770312 : if (veh->isStopped()) {
534 7320 : veh->processStop();
535 : }
536 23770312 : MEVehicle* lc = removeCar(veh, time, reason); // new leaderCar
537 : q.setBlockTime(time);
538 : if (!isInvalid(next)) {
539 23127490 : const bool nextFree = next->myQueues[nextQIdx].getOccupancy() <= next->myJamThreshold;
540 23127490 : const SUMOTime tau = (q.getOccupancy() <= myJamThreshold
541 23127490 : ? (nextFree ? myTau_ff : myTau_fj)
542 402668 : : (nextFree ? myTau_jf : getTauJJ((double)next->myQueues[nextQIdx].size(), next->myQueueCapacity, next->myJamThreshold)));
543 : assert(tau >= 0);
544 23127490 : myLastHeadway = tauWithVehLength(tau, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime());
545 23127490 : if (myTLSPenalty) {
546 48820 : const MSLink* const tllink = getLink(veh, true);
547 48820 : if (tllink != nullptr && tllink->isTLSControlled()) {
548 : assert(tllink->getGreenFraction() > 0);
549 48820 : myLastHeadway = (SUMOTime)((double)myLastHeadway / tllink->getGreenFraction());
550 : }
551 : }
552 23127490 : q.setBlockTime(q.getBlockTime() + myLastHeadway);
553 : }
554 23770312 : if (lc != nullptr) {
555 : lc->setEventTime(MAX2(lc->getEventTime(), q.getBlockTime()));
556 17502120 : MSGlobals::gMesoNet->addLeaderCar(lc, getLink(lc));
557 : }
558 23770312 : }
559 :
560 : SUMOTime
561 135148 : MESegment::getTauJJ(double nextQueueSize, double nextQueueCapacity, double nextJamThreshold) const {
562 : // compute coefficients for the jam-jam headway function
563 : // this function models the effect that "empty space" needs to move
564 : // backwards through the downstream segment before the upstream segment may
565 : // send annother vehicle.
566 : // this allows jams to clear and move upstream.
567 : // the headway function f(x) depends on the number of vehicles in the
568 : // downstream segment x
569 : // f is a linear function that passes through the following fixed points:
570 : // f(n_jam_threshold) = tau_jf_withLength (for continuity)
571 : // f(headwayCapacity) = myTau_jj * headwayCapacity
572 :
573 135148 : const SUMOTime tau_jf_withLength = tauWithVehLength(myTau_jf, DEFAULT_VEH_LENGTH_WITH_GAP, 1.);
574 : // number of vehicles that fit into the NEXT queue (could be larger than expected with DEFAULT_VEH_LENGTH_WITH_GAP!)
575 135148 : const double headwayCapacity = MAX2(nextQueueSize, nextQueueCapacity / DEFAULT_VEH_LENGTH_WITH_GAP);
576 : // number of vehicles above which the NEXT queue is jammed
577 135148 : const double n_jam_threshold = headwayCapacity * nextJamThreshold / nextQueueCapacity;
578 :
579 : // slope a and axis offset b for the jam-jam headway function
580 : // solving f(x) = a * x + b
581 135148 : const double a = (STEPS2TIME(myTau_jj) * headwayCapacity - STEPS2TIME(tau_jf_withLength)) / (headwayCapacity - n_jam_threshold);
582 135148 : const double b = headwayCapacity * (STEPS2TIME(myTau_jj) - a);
583 :
584 : // it is only well defined for nextQueueSize >= n_jam_threshold (which may not be the case for longer vehicles), so we take the MAX
585 135148 : return TIME2STEPS(a * MAX2(nextQueueSize, n_jam_threshold) + b);
586 : }
587 :
588 :
589 : bool
590 1146736 : MESegment::overtake() {
591 1146760 : return myOvertaking && RandHelper::rand() > (getBruttoOccupancy() / myCapacity);
592 : }
593 :
594 :
595 : void
596 23808907 : MESegment::addReminders(MEVehicle* veh) const {
597 23808907 : if (veh->getQueIndex() != PARKING_QUEUE) {
598 23807575 : myQueues[veh->getQueIndex()].addReminders(veh);
599 : }
600 23808907 : }
601 :
602 :
603 : void
604 23806816 : MESegment::receive(MEVehicle* veh, const int qIdx, SUMOTime time, const bool isDepart, const bool isTeleport, const bool newEdge) {
605 23806816 : const double speed = isDepart ? -1 : MAX2(veh->getSpeed(), MESO_MIN_SPEED); // on the previous segment
606 23806816 : veh->setSegment(this); // for arrival checking
607 : veh->setLastEntryTime(time);
608 : veh->setBlockTime(SUMOTime_MAX);
609 23806816 : if (!isDepart && (
610 : // arrival on entering a new edge
611 2754544 : (newEdge && veh->moveRoutePointer())
612 : // arrival on entering a new segment
613 23129090 : || veh->hasArrived())) {
614 : // route has ended
615 15234 : veh->setEventTime(time + TIME2STEPS(myLength / speed)); // for correct arrival speed
616 15234 : addReminders(veh);
617 15234 : veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
618 30364 : veh->updateDetectors(time, true,
619 15234 : veh->getEdge()->isVaporizing() ? MSMoveReminder::NOTIFICATION_VAPORIZED_VAPORIZER : MSMoveReminder::NOTIFICATION_ARRIVED);
620 15234 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
621 15234 : return;
622 : }
623 : assert(veh->getEdge() == &getEdge());
624 : // route continues
625 23791582 : Queue& q = myQueues[qIdx];
626 23791582 : const double maxSpeedOnEdge = veh->getEdge()->getLanes()[qIdx]->getVehicleMaxSpeed(veh);
627 : const double uspeed = MAX2(maxSpeedOnEdge, MESO_MIN_SPEED);
628 : std::vector<MEVehicle*>& cars = q.getModifiableVehicles();
629 : MEVehicle* newLeader = nullptr; // first vehicle in the current queue
630 23791582 : const SUMOTime stopTime = veh->checkStop(time);
631 23791582 : SUMOTime tleave = MAX2(stopTime + TIME2STEPS(myLength / uspeed) + getLinkPenalty(veh), q.getBlockTime());
632 23791582 : if (veh->isStopped()) {
633 8965 : myEdge.addWaiting(veh);
634 : }
635 23791582 : if (veh->isParking()) {
636 : veh->setEventTime(stopTime);
637 1332 : veh->setSegment(this, PARKING_QUEUE);
638 1332 : myEdge.getLanes()[0]->addParking(veh); // TODO for GUI only
639 : } else {
640 23790250 : myEdge.lock();
641 23790250 : if (cars.empty()) {
642 6266824 : cars.push_back(veh);
643 : newLeader = veh;
644 : } else {
645 17523426 : SUMOTime leaderOut = cars[0]->getEventTime();
646 17523426 : if (!isDepart && leaderOut > tleave && overtake()) {
647 20 : if (cars.size() == 1) {
648 4 : MSGlobals::gMesoNet->removeLeaderCar(cars[0]);
649 : newLeader = veh;
650 : }
651 20 : cars.insert(cars.begin() + 1, veh);
652 : } else {
653 17523406 : tleave = MAX2(leaderOut + tauWithVehLength(myTau_ff, cars[0]->getVehicleType().getLengthWithGap(), cars[0]->getVehicleType().getCarFollowModel().getHeadwayTime()), tleave);
654 17523406 : cars.insert(cars.begin(), veh);
655 : }
656 : }
657 23790250 : myEdge.unlock();
658 23790250 : myNumVehicles++;
659 23790250 : if (!isDepart && !isTeleport) {
660 : // departs and teleports could take place anywhere on the edge so they should not block regular flow
661 : // the -1 facilitates interleaving of multiple streams
662 23111709 : q.setEntryBlockTime(time + tauWithVehLength(myTau_ff, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime()) - 1);
663 : }
664 23790250 : q.setOccupancy(MIN2(myQueueCapacity, q.getOccupancy() + veh->getVehicleType().getLengthWithGap()));
665 : veh->setEventTime(tleave);
666 23790250 : veh->setSegment(this, qIdx);
667 : }
668 23791582 : addReminders(veh);
669 23791582 : if (isDepart) {
670 677568 : veh->onDepart();
671 677568 : veh->activateReminders(MSMoveReminder::NOTIFICATION_DEPARTED);
672 23114014 : } else if (newEdge) {
673 2754386 : veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
674 : } else {
675 20359628 : veh->activateReminders(MSMoveReminder::NOTIFICATION_SEGMENT);
676 : }
677 23791582 : if (veh->isParking()) {
678 1332 : MSGlobals::gMesoNet->addLeaderCar(veh, nullptr);
679 : } else {
680 23790250 : if (newLeader != nullptr) {
681 6266828 : MSGlobals::gMesoNet->addLeaderCar(newLeader, getLink(newLeader));
682 : }
683 : }
684 : }
685 :
686 :
687 : bool
688 8674 : MESegment::vaporizeAnyCar(SUMOTime currentTime, const MSDetectorFileOutput* filter) {
689 9214 : for (const Queue& q : myQueues) {
690 8688 : if (q.size() > 0) {
691 8148 : for (MEVehicle* const veh : q.getVehicles()) {
692 8148 : if (filter->vehicleApplies(*veh)) {
693 8148 : MSGlobals::gMesoNet->removeLeaderCar(veh);
694 8148 : MSGlobals::gMesoNet->changeSegment(veh, currentTime + 1, &myVaporizationTarget, MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR);
695 : return true;
696 : }
697 : }
698 : }
699 : }
700 : return false;
701 : }
702 :
703 :
704 : void
705 346 : MESegment::setSpeedForQueue(double newSpeed, SUMOTime currentTime, SUMOTime blockTime, const std::vector<MEVehicle*>& vehs) {
706 346 : MEVehicle* v = vehs.back();
707 346 : v->updateDetectors(currentTime, false);
708 346 : SUMOTime newEvent = MAX2(newArrival(v, newSpeed, currentTime), blockTime);
709 346 : if (v->getEventTime() != newEvent) {
710 324 : MSGlobals::gMesoNet->removeLeaderCar(v);
711 : v->setEventTime(newEvent);
712 324 : MSGlobals::gMesoNet->addLeaderCar(v, getLink(v));
713 : }
714 1069 : for (std::vector<MEVehicle*>::const_reverse_iterator i = vehs.rbegin() + 1; i != vehs.rend(); ++i) {
715 723 : (*i)->updateDetectors(currentTime, false);
716 723 : newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + myTau_ff);
717 : //newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + myTau_ff + (SUMOTime)((*(i - 1))->getVehicleType().getLength() / myTau_length));
718 723 : (*i)->setEventTime(newEvent);
719 : }
720 346 : }
721 :
722 :
723 : SUMOTime
724 1069 : MESegment::newArrival(const MEVehicle* const v, double newSpeed, SUMOTime currentTime) {
725 : // since speed is only an upper bound pos may be to optimistic
726 1069 : const double pos = MIN2(myLength, STEPS2TIME(currentTime - v->getLastEntryTime()) * v->getSpeed());
727 : // traveltime may not be 0
728 1069 : double tt = (myLength - pos) / MAX2(newSpeed, MESO_MIN_SPEED);
729 1069 : return currentTime + MAX2(TIME2STEPS(tt), SUMOTime(1));
730 : }
731 :
732 :
733 : void
734 971 : MESegment::setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh, int qIdx) {
735 971 : recomputeJamThreshold(jamThresh);
736 : //myTau_length = MAX2(MESO_MIN_SPEED, newSpeed) * myEdge.getLanes().size() / TIME2STEPS(1);
737 : int i = 0;
738 2024 : for (const Queue& q : myQueues) {
739 1053 : if (q.size() != 0) {
740 379 : if (qIdx == -1 || qIdx == i) {
741 346 : setSpeedForQueue(newSpeed, currentTime, q.getBlockTime(), q.getVehicles());
742 : }
743 : }
744 1053 : i++;
745 : }
746 971 : }
747 :
748 :
749 : SUMOTime
750 1309049 : MESegment::getEventTime() const {
751 : SUMOTime result = SUMOTime_MAX;
752 2903357 : for (const Queue& q : myQueues) {
753 1594308 : if (q.size() != 0 && q.getVehicles().back()->getEventTime() < result) {
754 : result = q.getVehicles().back()->getEventTime();
755 : }
756 : }
757 1309049 : if (result < SUMOTime_MAX) {
758 851140 : return result;
759 : }
760 : return -1;
761 : }
762 :
763 :
764 : void
765 5193 : MESegment::saveState(OutputDevice& out) const {
766 : bool write = false;
767 10175 : for (const Queue& q : myQueues) {
768 5236 : if (q.getBlockTime() != -1 || !q.getVehicles().empty()) {
769 : write = true;
770 : break;
771 : }
772 : }
773 5193 : if (write) {
774 508 : out.openTag(SUMO_TAG_SEGMENT).writeAttr(SUMO_ATTR_ID, getID());
775 519 : for (const Queue& q : myQueues) {
776 530 : out.openTag(SUMO_TAG_VIEWSETTINGS_VEHICLES).writeAttr(SUMO_ATTR_TIME, toString<SUMOTime>(q.getBlockTime()));
777 : out.writeAttr(SUMO_ATTR_VALUE, q.getVehicles());
778 530 : out.closeTag();
779 : }
780 508 : out.closeTag();
781 : }
782 5193 : }
783 :
784 :
785 : void
786 277 : MESegment::clearState() {
787 554 : for (Queue& q : myQueues) {
788 : q.getModifiableVehicles().clear();
789 : }
790 277 : }
791 :
792 : void
793 181 : MESegment::loadState(const std::vector<std::string>& vehIds, MSVehicleControl& vc, const SUMOTime block, const int queIdx) {
794 181 : Queue& q = myQueues[queIdx];
795 389 : for (const std::string& id : vehIds) {
796 208 : MEVehicle* v = static_cast<MEVehicle*>(vc.getVehicle(id));
797 : // vehicle could be removed due to options
798 208 : if (v != nullptr) {
799 : assert(v->getSegment() == this);
800 206 : q.getModifiableVehicles().push_back(v);
801 206 : myNumVehicles++;
802 206 : q.setOccupancy(q.getOccupancy() + v->getVehicleType().getLengthWithGap());
803 : }
804 : }
805 181 : if (q.size() != 0) {
806 : // add the last vehicle of this queue
807 : // !!! one question - what about the previously added vehicle? Is it stored twice?
808 91 : MEVehicle* veh = q.getVehicles().back();
809 91 : MSGlobals::gMesoNet->addLeaderCar(veh, getLink(veh));
810 : }
811 : q.setBlockTime(block);
812 181 : q.setOccupancy(MIN2(q.getOccupancy(), myQueueCapacity));
813 181 : }
814 :
815 :
816 : std::vector<const MEVehicle*>
817 80 : MESegment::getVehicles() const {
818 : std::vector<const MEVehicle*> result;
819 180 : for (const Queue& q : myQueues) {
820 100 : result.insert(result.end(), q.getVehicles().begin(), q.getVehicles().end());
821 : }
822 80 : return result;
823 0 : }
824 :
825 :
826 : bool
827 3582472 : MESegment::hasBlockedLeader() const {
828 7227618 : for (const Queue& q : myQueues) {
829 3657519 : if (q.size() > 0 && q.getVehicles().back()->getWaitingTime() > 0) {
830 : return true;
831 : }
832 : }
833 : return false;
834 : }
835 :
836 :
837 : double
838 0 : MESegment::getFlow() const {
839 0 : return 3600 * getCarNumber() * getMeanSpeed() / myLength;
840 : }
841 :
842 :
843 : SUMOTime
844 23791582 : MESegment::getLinkPenalty(const MEVehicle* veh) const {
845 23791582 : const MSLink* link = getLink(veh, myTLSPenalty || myCheckMinorPenalty);
846 23791582 : if (link != nullptr) {
847 : SUMOTime result = 0;
848 1120619 : if (link->isTLSControlled()) {
849 : result += link->getMesoTLSPenalty();
850 : }
851 : // minor tls links may get an additional penalty
852 311726 : if (!link->havePriority() &&
853 : // do not apply penalty on top of tLSPenalty
854 1120619 : !myTLSPenalty &&
855 : // do not apply penalty if limited control is active
856 276450 : (!MSGlobals::gMesoLimitedJunctionControl || limitedControlOverride(link))) {
857 273980 : result += myMinorPenalty;
858 : }
859 1120619 : return result;
860 : } else {
861 : return 0;
862 : }
863 : }
864 :
865 :
866 : double
867 3 : MESegment::getWaitingSeconds() const {
868 : double result = 0;
869 6 : for (const Queue& q : myQueues) {
870 : // @note: only the leader currently accumulates waitingTime but this might change in the future
871 4 : for (const MEVehicle* veh : q.getVehicles()) {
872 1 : result += veh->getWaitingSeconds();
873 : }
874 : }
875 3 : return result;
876 : }
877 :
878 :
879 : /****************************************************************************/
|