Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSE2Collector.cpp
Go to the documentation of this file.
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/****************************************************************************/
24// An areal detector covering a sequence of consecutive lanes
25/****************************************************************************/
26
27
28/* TODO:
29 * tests:
30 * - subsecond variant, ballistic variant
31 * allow omitting jam processing (?)
32 *
33 * Meso-compatibility? (esp. enteredLane-argument for MSBaseVehicle::notifyEnter() is not treated)
34 * Compatibility without internal lanes?
35 * Include leftVehicles into output?
36 */
37#include <config.h>
38
39#include <cassert>
40#include <algorithm>
41#ifdef HAVE_FOX
43#endif
44#include <microsim/MSLane.h>
45#include <microsim/MSEdge.h>
46#include <microsim/MSLink.h>
47#include <microsim/MSNet.h>
48#include <microsim/MSVehicle.h>
55#include "MSE2Collector.h"
56
57//#define DEBUG_E2_CONSTRUCTOR
58//#define DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
59//#define DEBUG_E2_NOTIFY_MOVE
60//#define DEBUG_E2_MAKE_VEHINFO
61//#define DEBUG_E2_DETECTOR_UPDATE
62//#define DEBUG_E2_TIME_ON_DETECTOR
63//#define DEBUG_E2_JAMS
64//#define DEBUG_E2_XML_OUT
65//#define DEBUG_COND (true)
66//#define DEBUG_COND (getID()=="e2Detector_e5.601A_1_SAa")
67//#define DEBUG_COND (getID()=="702057")
68//#define DEBUG_COND (getID()=="det0")
69
70MSE2Collector::MSE2Collector(const std::string& id,
71 DetectorUsage usage, MSLane* lane, double startPos, double endPos, double length,
72 SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold,
73 const std::string name, const std::string& vTypes,
74 const std::string& nextEdges,
75 int detectPersons) :
76 MSMoveReminder(id, lane, false),
77 MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
78 myUsage(usage),
79 myName(name),
80 myJamHaltingSpeedThreshold(haltingSpeedThreshold),
81 myJamHaltingTimeThreshold(haltingTimeThreshold),
82 myJamDistanceThreshold(jamDistThreshold) {
83
84#ifdef DEBUG_E2_CONSTRUCTOR
85 if (DEBUG_COND) {
86 std::cout << "\n" << "Creating MSE2Collector " << id
87 << " with lane = " << lane->getID()
88 << " startPos = " << startPos
89 << " endPos = " << endPos
90 << " length = " << length
91 << " haltingTimeThreshold = " << haltingTimeThreshold
92 << " haltingSpeedThreshold = " << haltingSpeedThreshold
93 << " jamDistThreshold = " << jamDistThreshold
94 << std::endl;
95 }
96#endif
97
98 assert(lane != 0);
99
100 // check that exactly one of length, startPos, endPos is invalid
101 bool lengthInvalid = length == std::numeric_limits<double>::max() || length <= 0;
102 bool endPosInvalid = endPos == std::numeric_limits<double>::max();
103 bool posInvalid = startPos == std::numeric_limits<double>::max();
104
105 // check and normalize positions (assure positive values for pos and endPos, snap to lane-ends)
106 if (lengthInvalid) {
107 // assume that the detector is only located on a single lane
108 if (posInvalid) {
109 WRITE_WARNING(TL("No valid detector length and start position given. Assuming startPos = 0 and length = end position"));
110 startPos = 0;
111 }
112 if (endPosInvalid) {
113 WRITE_WARNING(TL("No valid detector length and end position given. Assuming endPos = lane length and length = endPos-startPos"));
114 endPos = lane->getLength();
115 }
116 endPos = endPos < 0 ? lane->getLength() + endPos : endPos;
117 startPos = startPos < 0 ? lane->getLength() + startPos : startPos;
118 bool valid = endPos <= lane->getLength() && 0 <= startPos && startPos < endPos;
119 if (!valid) {
120 throw InvalidArgument("Error in specification for E2Detector '" + id + "'. Positional argument is malformed. 0 <= pos < endPos <= lane.getLength() is required.");
121 }
122 // snap detector ends to lane ends
123 endPos = snap(endPos, lane->getLength(), POSITION_EPS);
124 startPos = snap(startPos, 0., POSITION_EPS);
125 length = endPos - startPos;
126 } else if (posInvalid) {
127 // endPosInvalid == false
128 endPos = endPos < 0 ? lane->getLength() + endPos : endPos;
129 endPos = snap(endPos, lane->getLength(), POSITION_EPS);
130 } else {
131 // posInvalid == false
132 startPos = startPos < 0 ? lane->getLength() + startPos : startPos;
133 startPos = snap(startPos, 0., POSITION_EPS);
134 }
135
136 myStartPos = startPos;
137 myEndPos = endPos;
138
139 std::vector<MSLane*> lanes;
140 if (posInvalid) {
141 lanes = selectLanes(lane, length, "bw");
142 } else if (endPosInvalid) {
143 lanes = selectLanes(lane, length, "fw");
144 } else {
145 // assuming detector is only located at a single lane
146 lanes.push_back(lane);
147 }
148
149 initAuxiliaries(lanes);
150 checkPositioning(endPosInvalid, length);
151 addDetectorToLanes(lanes);
152}
153
154
155MSE2Collector::MSE2Collector(const std::string& id,
156 DetectorUsage usage, std::vector<MSLane*> lanes, double startPos, double endPos,
157 SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold,
158 const std::string name, const std::string& vTypes,
159 const std::string& nextEdges,
160 int detectPersons) :
161 MSMoveReminder(id, lanes[lanes.size() - 1], false), // assure that lanes.size() > 0 at caller side!!!
162 MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
163 myUsage(usage),
164 myName(name),
165 myFirstLane(lanes[0]),
166 myLastLane(lanes[lanes.size() - 1]),
167 myStartPos(startPos),
168 myEndPos(endPos),
169 myJamHaltingSpeedThreshold(haltingSpeedThreshold),
170 myJamHaltingTimeThreshold(haltingTimeThreshold),
171 myJamDistanceThreshold(jamDistThreshold) {
172
173 for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
174 assert((*i) != 0);
175 }
176
177#ifdef DEBUG_E2_CONSTRUCTOR
178 if (DEBUG_COND) {
179 std::cout << "\n" << "Creating MSE2Collector " << id
180 << " with endLane = " << myLastLane->getID()
181 << " endPos = " << endPos
182 << " startLane = " << myFirstLane->getID()
183 << " startPos = " << startPos
184 << " haltingTimeThreshold = " << haltingTimeThreshold
185 << " haltingSpeedThreshold = " << haltingSpeedThreshold
186 << " jamDistThreshold = " << jamDistThreshold
187 << std::endl;
188 }
189#endif
190
191 myStartPos = myStartPos < 0 ? lanes[0]->getLength() + myStartPos : myStartPos;
192 myEndPos = myEndPos < 0 ? lanes[lanes.size() - 1]->getLength() + myEndPos : myEndPos;
193
194 if (myStartPos < POSITION_EPS) {
195 myStartPos = 0;
196 }
197 if (myEndPos > lanes[lanes.size() - 1]->getLength() - POSITION_EPS) {
198 myEndPos = lanes[lanes.size() - 1]->getLength();
199 }
200
201
202 initAuxiliaries(lanes);
204 addDetectorToLanes(lanes);
205}
206
207
208void
209MSE2Collector::checkPositioning(bool posGiven, double desiredLength) {
210 // check if detector was truncated
211 if (desiredLength > 0 && myDetectorLength < desiredLength - NUMERICAL_EPS) {
212 std::stringstream ss;
213 ss << "Cannot build detector of length " << desiredLength
214 << " because no further continuation lane was found for lane '" << (posGiven ? myLastLane->getID() : myFirstLane->getID())
215 << "'! Truncated detector at length " << myDetectorLength << ".";
216 WRITE_WARNING(ss.str());
217 }
218
219 if (myDetectorLength < POSITION_EPS && (myStartPos > 0. || myEndPos < myLastLane->getLength())) {
220 // assure minimal detector length
221 double prolong = POSITION_EPS - myDetectorLength;
222 double startPos = MAX2(0., myStartPos - prolong); // new startPos
223 prolong -= myStartPos - startPos;
224 myStartPos = startPos;
225 if (prolong > 0.) {
226 myEndPos = MIN2(myEndPos + prolong, myLastLane->getLength());
227 }
228 WRITE_WARNING("Adjusted detector positioning to meet requirement length >= " + toString(POSITION_EPS)
229 + ". New position is [" + toString(myStartPos) + "," + toString(myEndPos) + "]");
230 }
231
232 // do some regularization snapping...
233 myStartPos = snap(myStartPos, 0., POSITION_EPS);
234 myStartPos = snap(myStartPos, myFirstLane->getLength() - POSITION_EPS, POSITION_EPS);
235 myStartPos = snap(myStartPos, 0., POSITION_EPS);
236 myEndPos = snap(myEndPos, myLastLane->getLength(), POSITION_EPS);
237 myEndPos = snap(myEndPos, POSITION_EPS, POSITION_EPS);
238 myEndPos = snap(myEndPos, myLastLane->getLength(), POSITION_EPS);
240
241#ifdef DEBUG_E2_CONSTRUCTOR
242 if (DEBUG_COND) {
243 std::stringstream ss;
244 // ss << std::setprecision(32) << myEndPos << " : " << POSITION_EPS;
245 // std::cout << ss.str() << std::endl;
246 std::cout << "myStartPos = " << myStartPos << std::endl;
247 std::cout << "myEndPos = " << myEndPos << std::endl;
248 std::cout << "myLastLane->getLength() = " << myLastLane->getLength() << std::endl;
249 }
250#endif
251
252
253 assert((myStartPos >= POSITION_EPS || myStartPos == 0) && myStartPos < myFirstLane->getLength());
254 assert(myEndPos <= myLastLane->getLength() - POSITION_EPS || myEndPos == myLastLane->getLength());
255 assert(myFirstLane != myLastLane || myEndPos - myStartPos > 0);
256}
257
258
259double
260MSE2Collector::snap(double value, double snapPoint, double snapDist) {
261 if (fabs(value - snapPoint) < snapDist) {
262 return snapPoint;
263 } else {
264 return value;
265 }
266}
267
268
269void
271 std::vector<std::string>::const_iterator i;
272 std::vector<MSLane*> lanes;
273 // get real lanes
274 for (i = myLanes.begin(); i != myLanes.end(); ++i) {
275 MSLane* lane = MSLane::dictionary(*i);
276 lanes.push_back(lane);
277 }
278
279 // sum up their lengths
280 std::vector<MSLane*>::const_iterator j;
281 MSLane* previous = nullptr;
283 for (j = lanes.begin(); j != lanes.end(); ++j) {
284 // lane length
285 myDetectorLength += (*j)->getLength();
286 if (previous != nullptr && !MSGlobals::gUsingInternalLanes) {
287 // eventually link length
288 myDetectorLength += previous->getLinkTo(*j)->getLength();
289 }
290 previous = *j;
291 }
292 // subtract uncovered area on first and last lane
295
296#ifdef DEBUG_E2_CONSTRUCTOR
297 if (DEBUG_COND) {
298 std::cout << "Total detector length after recalculation = " << myDetectorLength << std::endl;
299 }
300#endif
301}
302
303
305 // clear move notifications
307}
308
309
310std::vector<MSLane*>
311MSE2Collector::selectLanes(MSLane* lane, double length, std::string dir) {
312 // direction of detector extension
313 assert(dir == "fw" || dir == "bw");
314 bool fw = dir == "fw";
315 double linkLength = 0; // linkLength (used if no internal lanes are present)
316 bool subtractedLinkLength = false; // whether linkLength was subtracted during the last iteration.
317
318#ifdef DEBUG_E2_CONSTRUCTOR
319 if (DEBUG_COND) {
320 std::cout << "\n" << "selectLanes()" << (fw ? "(forward)" : "(backward)") << std::endl;
321 }
322#endif
323 std::vector<MSLane*> lanes;
324 // Selected lanes are stacked into vector 'lanes'. If dir == "bw" lanes will be reversed after this is done.
325 // The length is reduced while adding lanes to the detector
326 // First we adjust the starting value for length (in the first iteration, the whole length of the first considered lane is subtracted,
327 // while it might only be partially covered by the detector)
328 if (fw) {
329 assert(myStartPos != std::numeric_limits<double>::max());
330 length += myStartPos;
331 } else {
332 assert(myEndPos != std::numeric_limits<double>::max());
333 length += lane->getLength() - myEndPos;
334 }
335 length = MAX2(POSITION_EPS, length); // this assures to add at least one lane to lanes
336 while (length >= POSITION_EPS && lane != nullptr) {
337 // Break loop for length <= NUMERICAL_EPS to avoid placement of very small
338 // detector piece on the end or beginning of one lane due to numerical rounding errors.
339 lanes.push_back(lane);
340#ifdef DEBUG_E2_CONSTRUCTOR
341 if (DEBUG_COND) {
342 std::cout << "Added lane " << lane->getID()
343 << " (length: " << lane->getLength() << ")" << std::endl;
344 }
345#endif
346
347 length -= lane->getLength();
348
349 // proceed to upstream predecessor
350 if (fw) {
351 lane = lane->getCanonicalSuccessorLane();
352 } else {
353 lane = lane->getCanonicalPredecessorLane();
354 }
355
356
357 subtractedLinkLength = false;
358 if (lane != nullptr && !MSGlobals::gUsingInternalLanes && length > POSITION_EPS) {
359 // In case wher no internal lanes are used,
360 // take into account the link length for the detector range
361 linkLength = 0;
362 if (fw) {
363 linkLength = lanes.back()->getLinkTo(lane)->getLength();
364 } else {
365 linkLength = lane->getLinkTo(lanes.back())->getLength();
366 }
367 length -= linkLength;
368 subtractedLinkLength = true;
369 }
370
371
372#ifdef DEBUG_E2_CONSTRUCTOR
373 if (DEBUG_COND) {
374 if (lane != 0) {
375 std::cout << (fw ? "Successor lane: " : "Predecessor lane: ") << "'" << lane->getID() << "'";
376 }
377 std::cout << std::endl;
378 }
379#endif
380 }
381
382 if (subtractedLinkLength) {
383 // if the link's length was subtracted during the last step,
384 // the start/endPos would lie on a non-existing internal lane,
385 // therefore revert and truncate detector part on the non-existing internal lane.
386 length += linkLength;
387 }
388
389
390 // 1) At this point a negative <length> means that not the whole last stored lane lanes[lanes.size()-1]
391 // should be added to the detector, but the detector should spare out a part with length = -<length>
392 // If this part is too small (of length < POSITION_EPS) we take the whole lane
393 // 2) The whole lane is also taken for the case that <length> is positive. This corresponds to on
394 // of three situations: i) <length> < POSITION_EPS (break condition -> don't take too small pieces on the next lane)
395 // ii&iii) <length> >= POS_EPSILON may arise either if no continuation lane was found (lane==0), or
396 // in case of not using internal lanes if the detector end/start falls on a link.
397 // In all cases we take the whole last lane.
398 if (fw) {
399 if (length > -POSITION_EPS) {
400 myEndPos = lanes[lanes.size() - 1]->getLength();
401 } else if (length < 0) {
402 myEndPos = lanes[lanes.size() - 1]->getLength() + length;
403 }
404 } else {
405 if (length > -POSITION_EPS) {
406 myStartPos = 0;
407 } else if (length < 0) {
408 myStartPos = -length;
409 }
410 }
411
412 // reverse lanes if lane selection was backwards
413 if (!fw) {
414 std::reverse(lanes.begin(), lanes.end());
415 }
416
417 return lanes;
418}
419
420void
421MSE2Collector::addDetectorToLanes(std::vector<MSLane*>& lanes) {
422#ifdef DEBUG_E2_CONSTRUCTOR
423 if (DEBUG_COND) {
424 std::cout << "\n" << "Adding detector " << myID << " to lanes:" << std::endl;
425 }
426#endif
427 for (std::vector<MSLane*>::iterator l = lanes.begin(); l != lanes.end(); ++l) {
428 (*l)->addMoveReminder(this);
429#ifdef DEBUG_E2_CONSTRUCTOR
430 if (DEBUG_COND) {
431 std::cout << (*l)->getID() << std::endl;
432 }
433#endif
434 }
435}
436
437void
438MSE2Collector::initAuxiliaries(std::vector<MSLane*>& lanes) {
439 // Checks integrity of myLanes, adds internal-lane information, inits myLength, myFirstLane, myLastLane, myOffsets, myEndPos/myStartPos
440 myFirstLane = lanes[0];
441 myLastLane = lanes[lanes.size() - 1];
442
443#ifdef DEBUG_E2_CONSTRUCTOR
444 if (DEBUG_COND) {
445 std::cout << "\n" << "Initializing auxiliaries:"
446 << "\nFirst lane: " << myFirstLane->getID() << " (startPos = " << myStartPos << ")"
447 << "\nLast lane: " << myLastLane->getID() << " (endPos = " << myEndPos << ")"
448 << std::endl;
449 }
450#endif
451
452 // Init myOffsets and myDetectorLength.
453 // The loop below runs through the given lanes assuming the possibility that only non-internal lanes are given
454 // or at least not all relevant internal lanes are considered. During this a new, complete list of lane ids is
455 // built into myLanes.
456 myLanes.clear();
457
458 // myDetectorLength will be increased in the loop below, always giving
459 // the offset of the currently considered lane to the detector start
461 myOffsets.clear();
462
463 // loop over detector lanes and accumulate offsets with respect to the first lane's begin
464 // (these will be corrected afterwards by subtracting the start position.)
465 std::vector<MSLane*>::iterator il = lanes.begin();
466
467 // start on an internal lane?
468 // (This may happen if specifying the detector by its upstream
469 // length starting from a given end position)
470 const MSLane* internal = (*il)->isInternal() ? *il : nullptr;
471
472#ifdef DEBUG_E2_CONSTRUCTOR
473 if (DEBUG_COND) {
474 std::cout << "\n" << "Initializing offsets:" << std::endl;
475 }
476#endif
477
478 while (true) {
479 // Consider the next internal lanes
480 while (internal != nullptr) {
481 myLanes.push_back(internal->getID());
482 myOffsets.push_back(myDetectorLength);
483
484#ifdef DEBUG_E2_CONSTRUCTOR
485 if (DEBUG_COND) {
486 std::cout << "Offset for lane " << internal->getID() << " = " << myDetectorLength
487 << std::endl;
488 }
489#endif
490
491 myDetectorLength += internal->getLength();
492 if (internal->getID() == myLastLane->getID()) {
493 break;
494 }
495
496 // There should be a unique continuation for each internal lane
497 assert(internal->getLinkCont().size() == 1);
498
499 internal = internal->getLinkCont()[0]->getViaLaneOrLane();
500 if (!internal->isInternal()) {
501 // passed the junction
502 internal = nullptr;
503 break;
504 }
505 }
506
507 // Consider the next non-internal lane
508 // This is the first lane in the first iteration, if it is non-internal
509 // However, it can equal myLanes.end() if the myLastLane is internal. In that case we break.
510
511 // Move il to next non-internal
512 while (il != lanes.end() && (*il)->isInternal()) {
513 il++;
514 }
515 if (il == lanes.end()) {
516 break;
517 }
518
519 // There is still a non-internal lane to consider
520 MSLane* lane = *il;
521 myLanes.push_back(lane->getID());
522
523#ifdef DEBUG_E2_CONSTRUCTOR
524 if (DEBUG_COND) {
525 std::cout << "Offset for lane " << lane->getID() << " = " << myDetectorLength
526 << std::endl;
527 }
528#endif
529
530 // Offset to detector start for this lane
531 myOffsets.push_back(myDetectorLength);
532
533 // Add the lanes length to the detector offset
534 myDetectorLength += lane->getLength();
535
536 // Get the next lane if this lane isn't the last one
537 if (++il == lanes.end()) {
538 break;
539 }
540
541 if ((*il)->isInternal()) {
542 // next lane in myLanes is internal
543 internal = *il;
544 continue;
545 }
546
547 // find the connection to next
548 const MSLink* link = lane->getLinkTo(*il);
549 if (link == nullptr) {
550 throw InvalidArgument("Lanes '" + lane->getID() + "' and '" + (*il)->getID() + "' are not consecutive in definition of e2Detector '" + getID() + "'");
551 }
552
554 myDetectorLength += link->getLength();
555 } else {
556 internal = link->getViaLane();
557 }
558 }
559
560 // Subtract distance not covered on the last considered lane
561 bool fw = myEndPos == std::numeric_limits<double>::max();
562 if (fw) {
564 } else {
566 }
567
568#ifdef DEBUG_E2_CONSTRUCTOR
569 if (DEBUG_COND) {
570 std::cout << "Total detector length after initAuxiliaries() = " << myDetectorLength << std::endl;
571 }
572#endif
573
574// make lanes a complete list including internal lanes
575 lanes = getLanes();
576}
577
578
579std::vector<MSLane*>
581 std::vector<MSLane*> res;
582 for (std::vector<std::string>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
583 res.push_back(MSLane::dictionary(*i));
584 }
585 return res;
586}
587
588
589bool
591 double newPos, double newSpeed) {
592
593 if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
594 bool keep = false;
595 MSBaseVehicle& v = dynamic_cast<MSBaseVehicle&>(veh);
596 for (MSTransportable* p : v.getPersons()) {
597 keep = notifyMove(*p, oldPos, newPos, newSpeed);
598 }
599 return keep;
600 }
601#ifdef HAVE_FOX
602 ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
603#endif
604 VehicleInfoMap::iterator vi = myVehicleInfos.find(veh.getID());
605 if (vi == myVehicleInfos.end()) {
606 const std::string objectType = veh.isPerson() ? "Person" : "Vehicle";
607 if (myNextEdges.size() > 0) {
608 WRITE_WARNING(objectType + " '" + veh.getID() + "' appeared inside detector '" + getID() + "' after previously being filtered out. time=" + time2string(SIMSTEP) + ".");
609 } else {
610 WRITE_WARNING(objectType + " '" + veh.getID() + "' suddenly appeared inside detector '" + getID() + "'. time=" + time2string(SIMSTEP) + ".");
611 }
612 return false;
613 }
614
615 const std::string& vehID = veh.getID();
616 VehicleInfo& vehInfo = *(vi->second);
617
618 // position relative to the detector start
619 double relPos = vehInfo.entryOffset + newPos;
620
621 // update current distance to the detector end
622 vehInfo.distToDetectorEnd = myDetectorLength - relPos;
623
624#ifdef DEBUG_E2_NOTIFY_MOVE
625 if (DEBUG_COND) {
626 std::cout << "\n" << SIMTIME
627 << " MSE2Collector::notifyMove() (detID = " << myID << " on lane '" << myLane->getID() << "')"
628 << " called by vehicle '" << vehID << "'"
629 << " at relative position " << relPos
630 << ", distToDetectorEnd = " << vehInfo.distToDetectorEnd << std::endl;
631 }
632#endif
633
634 // Check whether vehicle has reached the detector begin
635 if (relPos <= 0) {
636 // detector not yet reached, request being informed further
637#ifdef DEBUG_E2_NOTIFY_MOVE
638 if (DEBUG_COND) {
639 std::cout << "Vehicle has not yet reached the detector start position." << std::endl;
640 }
641#endif
642 return true;
643 } else if (!vehInfo.hasEntered) {
644 vehInfo.hasEntered = true;
647 }
648
649
650 // determine whether vehicle has moved beyond the detector's end
651 bool vehPassedDetectorEnd = - vehInfo.exitOffset <= newPos - veh.getVehicleType().getLength();
652
653 // determine whether vehicle has been on the detector at all
654 bool vehicleEnteredLaneAfterDetector = vehPassedDetectorEnd && (-vehInfo.exitOffset <= oldPos - veh.getVehicleType().getLength());
655 // ... if not, dont create any notification at all
656 if (vehicleEnteredLaneAfterDetector) {
657#ifdef DEBUG_E2_NOTIFY_MOVE
658 if (DEBUG_COND) {
659 std::cout << "Vehicle entered lane behind detector." << std::endl;
660 }
661#endif
662 } else {
663 myMoveNotifications.push_back(makeMoveNotification(veh, oldPos, newPos, newSpeed, vehInfo));
664 }
665
666
667 if (vehPassedDetectorEnd) {
668#ifdef DEBUG_E2_NOTIFY_MOVE
669 if (DEBUG_COND) {
670 std::cout << "Vehicle has left the detector longitudinally." << std::endl;
671 }
672#endif
673 // Vehicle is beyond the detector, unsubscribe and register removal from myVehicleInfos
674 myLeftVehicles.insert(vehID);
675 return false;
676 } else {
677 // Receive further notifications
678 return true;
679 }
680}
681
682bool
683MSE2Collector::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
684#ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
685 if (DEBUG_COND) {
686 std::cout << "\n" << SIMTIME << " notifyLeave() (detID = " << myID << " on lane '" << myLane->getID() << "')"
687 << "called by vehicle '" << veh.getID() << "'" << std::endl;
688 }
689#endif
690
691#ifdef HAVE_FOX
692 ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
693#endif
694 if (reason == MSMoveReminder::NOTIFICATION_JUNCTION && !veh.isPerson()) {
695 // vehicle left lane via junction, unsubscription and registering in myLeftVehicles when
696 // moving beyond the detector end is controlled in notifyMove.
697#ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
698 if (DEBUG_COND) {
699 std::cout << SIMTIME << " Left longitudinally (along junction) -> keep subscription [handle exit in notifyMove()]" << std::endl;
700 }
701#endif
702
703 if (enteredLane == nullptr || std::find(myLanes.begin(), myLanes.end(), enteredLane->getID()) == myLanes.end()) {
704 // Entered lane is not part of the detector
705 VehicleInfoMap::iterator vi = myVehicleInfos.find(veh.getID());
706 // Determine exit offset, where vehicle left the detector
707 double exitOffset = vi->second->entryOffset - myOffsets[vi->second->currentOffsetIndex] - vi->second->currentLane->getLength();
708 vi->second->exitOffset = MAX2(vi->second->exitOffset, exitOffset);
709#ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
710 if (DEBUG_COND) {
711 std::cout << SIMTIME << " Vehicle '" << veh.getID() << "' leaves the detector. Exit offset = " << vi->second->exitOffset << std::endl;
712 }
713#endif
714 }
715
716 return true;
717 } else {
718 VehicleInfoMap::iterator vi = myVehicleInfos.find(veh.getID());
719 if (vi != myVehicleInfos.end()) {
720 // erase vehicle, which leaves in a non-longitudinal way, immediately
721 if (vi->second->hasEntered) {
723 }
724 delete vi->second;
725 myVehicleInfos.erase(vi);
726#ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
727 if (DEBUG_COND) {
728 std::cout << SIMTIME << " Left non-longitudinally (lanechange, teleport, parking, etc) -> discard subscription" << std::endl;
729 }
730#endif
731 } else {
732 assert(veh.isPerson());
733 }
734 return false;
735 }
736}
737
738
739bool
741#ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
742 if (DEBUG_COND) {
743 std::cout << std::endl << SIMTIME << " notifyEnter() (detID = " << myID << " on lane '" << myLane->getID() << "')"
744 << " called by vehicle '" << veh.getID()
745 << "' entering lane '" << (enteredLane != 0 ? enteredLane->getID() : "NULL") << "'" << std::endl;
746 }
747#endif
748 // notifyEnter() should only be called for lanes of the detector
749 assert(std::find(myLanes.begin(), myLanes.end(), enteredLane->getID()) != myLanes.end());
750 assert(veh.getLane() == enteredLane || !veh.isVehicle());
751
752 // vehicles must be kept if the "inductionloop" wants to detect passeengers
753 if (!vehicleApplies(veh) && (veh.isPerson() || myDetectPersons <= (int)PersonMode::WALK)) {
754 // That's not my type...
755 return false;
756 }
757 if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
758 bool keep = false;
759 MSBaseVehicle& v = dynamic_cast<MSBaseVehicle&>(veh);
760 for (MSTransportable* p : v.getPersons()) {
761 keep = notifyEnter(*p, reason, enteredLane);
762 }
763 return keep;
764 }
765
766 // determine whether the vehicle entered the lane behind the detector end
767 // e.g. due to lane change manoeuver
768 if (reason != NOTIFICATION_JUNCTION) {
769 const double vehBackPos = veh.getBackPositionOnLane(enteredLane);
770 bool vehEnteredBehindDetectorEnd = (enteredLane == myLastLane) && myEndPos <= vehBackPos;
771 if (vehEnteredBehindDetectorEnd) {
772 // this vehicle cannot influence detector readings, do not subscribe
773 // to move notifications
774#ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
775 if (DEBUG_COND) {
776 std::cout << "Vehicle entered the lane behind the detector, ignoring it." << std::endl;
777 std::cout << "(myEndPos = " << this->myEndPos << ", veh.getBackPositionOnLane() = " << vehBackPos << ")" << std::endl;
778 }
779#endif
780 return false;
781 }
782 }
783
784#ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
785 if (DEBUG_COND) {
786 if (veh.isVehicle() && !dynamic_cast<SUMOVehicle&>(veh).isOnRoad()) {
787 // Vehicle is teleporting over the edge
788 std::cout << "Vehicle is off road (teleporting over edge)..." << std::endl;
789 }
790 }
791#endif
792
793#ifdef HAVE_FOX
794 ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
795#endif
796 const std::string& vehID = veh.getID();
797 VehicleInfoMap::iterator vi = myVehicleInfos.find(vehID);
798 if (vi != myVehicleInfos.end()) {
799 // Register move current offset to the next lane
800 if (vi->second->currentLane != enteredLane) {
801 vi->second->currentOffsetIndex++;
802 vi->second->currentLane = enteredLane;
803 }
804
805#ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
806 if (DEBUG_COND) {
807 std::cout << SIMTIME << " Vehicle '" << veh.getID() << "' on lane '" << veh.getLane()->getID()
808 << "' already known. No new VehicleInfo is created.\n"
809 << "enteredLane = " << enteredLane->getID() << "\nmyLanes[vi->offset] = " << myLanes[vi->second->currentOffsetIndex]
810 << std::endl;
811 }
812#endif
813 assert(myLanes[vi->second->currentOffsetIndex] == enteredLane->getID());
814
815 // but don't add a second subscription for another lane
816 return false;
817 }
818
819
820
821#ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
822 if (DEBUG_COND) {
823 std::cout << SIMTIME << " Adding VehicleInfo for vehicle '" << veh.getID() << "'." << std::endl;
824 }
825#endif
826
827 // Add vehicle info
828 myVehicleInfos.insert(std::make_pair(vehID, makeVehicleInfo(veh, enteredLane)));
829 // Subscribe to vehicle's movement notifications
830 return true;
831}
832
833
835MSE2Collector::makeVehicleInfo(const SUMOTrafficObject& veh, const MSLane* enteredLane) const {
836 // The vehicle's distance to the detector end
837 int j = (int)(std::find(myLanes.begin(), myLanes.end(), enteredLane->getID()) - myLanes.begin());
838 assert(j >= 0 && j < (int)myLanes.size());
839 double entryOffset = myOffsets[j];
840 double distToDetectorEnd = myDetectorLength - (entryOffset + veh.getPositionOnLane());
841 bool onDetector = -entryOffset < veh.getPositionOnLane() && distToDetectorEnd > -veh.getVehicleType().getLength();
842
843#ifdef DEBUG_E2_MAKE_VEHINFO
844 if (DEBUG_COND) {
845 std::cout << SIMTIME << " Making VehicleInfo for vehicle '" << veh.getID() << "'."
846 << "\ndistToDetectorEnd = " << distToDetectorEnd
847 << "\nveh.getPositionOnLane() = " << veh.getPositionOnLane()
848 << "\nentry lane offset (lane begin from detector begin) = " << entryOffset
849 << std::endl;
850 }
851#endif
852 return new VehicleInfo(veh.getID(), veh.getVehicleType().getID(), veh.getVehicleType().getLength(), veh.getVehicleType().getMinGap(), enteredLane, entryOffset, j,
853 myOffsets[j] - myDetectorLength, distToDetectorEnd, onDetector);
854}
855
856
857void
859 if (personApplies(*p, dir)) {
860 const double newSpeed = p->getSpeed();
861 const double newPos = (dir == MSPModel::FORWARD
862 ? pos
863 // position relative to detector end position
864 : myEndPos - (pos - myEndPos));
865 const double oldPos = newPos - SPEED2DIST(newSpeed);
866 if (oldPos - p->getVehicleType().getLength() <= myEndPos) {
867 notifyMove(*p, oldPos, newPos, newSpeed);
868 }
869 }
870}
871
872
873void
875
876 if (myDetectPersons != (int)PersonMode::NONE) {
877 if (myLanes.size() > 1) {
879 //dir=BACKWARD send a virtual forward-lane-sequence
880 throw ProcessError(TL("Multi-lane e2Detector does not support detecting persons yet"));
881 }
882 for (MSLane* lane : getLanes()) {
883 if (lane->hasPedestrians()) {
884 for (MSTransportable* p : myLane->getEdge().getPersons()) {
885 if (p->getLane() == lane && vehicleApplies(*p)) {
886 notifyMovePerson(p, p->getDirection(), p->getPositionOnLane());
887 }
888 }
889 }
890 }
891 }
892
893#ifdef DEBUG_E2_DETECTOR_UPDATE
894 if (DEBUG_COND) {
895 std::cout << "\n" << SIMTIME << " detectorUpdate() for detector '" << myID << "'"
896 << "\nmyCurrentMeanSpeed = " << myCurrentMeanSpeed
897 << "\nmyCurrentMeanLength = " << myCurrentMeanLength
898 << "\nmyNumberOfEnteredVehicles = " << myNumberOfEnteredVehicles
899 << "\nmyNumberOfLeftVehicles = " << myNumberOfLeftVehicles
900 << "\nmyNumberOfSeenVehicles = " << myNumberOfSeenVehicles
901 << std::endl;
902 }
903#endif
904
905// sort myMoveNotifications (required for jam processing) ascendingly according to vehicle's distance to the detector end
906// (min = myMoveNotifications[0].distToDetectorEnd)
908
909 // reset values concerning current time step (these are updated in integrateMoveNotification() and aggregateOutputValues())
915
916 JamInfo* currentJam = nullptr;
917 std::vector<JamInfo*> jams;
918 std::map<std::string, SUMOTime> haltingVehicles;
919 std::map<std::string, SUMOTime> intervalHaltingVehicles;
920
921 // go through the list of vehicles positioned on the detector
922 for (std::vector<MoveNotificationInfo*>::iterator i = myMoveNotifications.begin(); i != myMoveNotifications.end(); ++i) {
923 // The ID of the vehicle that has sent this notification in the last step
924 const std::string& vehID = (*i)->id;
925 VehicleInfoMap::iterator vi = myVehicleInfos.find(vehID);
926
927 if (vi == myVehicleInfos.end()) {
928 // The vehicle has already left the detector by lanechange, teleport, etc. (not longitudinal)
929 integrateMoveNotification(nullptr, *i);
930 } else {
931 // Add move notification infos to detector values and VehicleInfo
932 integrateMoveNotification(vi->second, *i);
933 }
934 // construct jam structure
935 bool isInJam = checkJam(i, haltingVehicles, intervalHaltingVehicles);
936 buildJam(isInJam, i, currentJam, jams);
937 }
938
939 // extract some aggregated values from the jam structure
940 processJams(jams, currentJam);
941
942 // Aggregate and normalize values for the detector output
944
945 // save information about halting vehicles
946 myHaltingVehicleDurations = haltingVehicles;
947 myIntervalHaltingVehicleDurations = intervalHaltingVehicles;
948
949#ifdef DEBUG_E2_DETECTOR_UPDATE
950 if (DEBUG_COND) {
951 std::cout << "\n" << SIMTIME << " Current lanes for vehicles still on or approaching the detector:" << std::endl;
952 }
953#endif
954// update current and entered lanes for remaining vehicles
955 VehicleInfoMap::iterator iv;
956 for (iv = myVehicleInfos.begin(); iv != myVehicleInfos.end(); ++iv) {
957#ifdef DEBUG_E2_DETECTOR_UPDATE
958 if (DEBUG_COND) {
959 std::cout << " Vehicle '" << iv->second->id << "'" << ": '"
960 << iv->second->currentLane->getID() << "'"
961 << std::endl;
962 }
963#endif
964 }
965
966#ifdef DEBUG_E2_DETECTOR_UPDATE
967 if (DEBUG_COND) {
968 std::cout << SIMTIME << " Discarding vehicles that have left the detector:" << std::endl;
969 }
970#endif
971// Remove the vehicles that have left the detector
972 std::set<std::string>::const_iterator i;
973 for (i = myLeftVehicles.begin(); i != myLeftVehicles.end(); ++i) {
974 VehicleInfoMap::iterator j = myVehicleInfos.find(*i);
975 delete j->second;
976 myVehicleInfos.erase(*i);
978#ifdef DEBUG_E2_DETECTOR_UPDATE
979 if (DEBUG_COND) {
980 std::cout << "Erased vehicle '" << *i << "'" << std::endl;
981 }
982#endif
983 }
984 myLeftVehicles.clear();
985
986 // reset move notifications
987 for (std::vector<MoveNotificationInfo*>::iterator j = myMoveNotifications.begin(); j != myMoveNotifications.end(); ++j) {
988 delete *j;
989 }
990 myMoveNotifications.clear();
991}
992
993
994void
996 myTimeSamples += 1;
997 // compute occupancy values (note myCurrentMeanLength is still not normalized here, but holds the sum of all vehicle lengths)
998 const double currentOccupancy = myCurrentMeanLength / myDetectorLength * (double) 100.;
999 myCurrentOccupancy = currentOccupancy;
1000 myOccupancySum += currentOccupancy;
1001 myMaxOccupancy = MAX2(myMaxOccupancy, currentOccupancy);
1002 // compute jam values
1007 // compute information about vehicle numbers
1008 const int numVehicles = (int)myMoveNotifications.size();
1009 myMeanVehicleNumber += numVehicles;
1011 // norm current values
1013 myCurrentMeanLength = numVehicles != 0 ? myCurrentMeanLength / (double) numVehicles : -1;
1014}
1015
1016
1017
1018void
1020
1021#ifdef DEBUG_E2_DETECTOR_UPDATE
1022 if (DEBUG_COND) {
1023 std::cout << SIMTIME << " integrateMoveNotification() for vehicle '" << mni->id << "'"
1024 << "\ntimeOnDetector = " << mni->timeOnDetector
1025 << "\nlengthOnDetector = " << mni->lengthOnDetector
1026 << "\ntimeLoss = " << mni->timeLoss
1027 << "\nspeed = " << mni->speed
1028 << std::endl;
1029 }
1030#endif
1031
1032// Accumulate detector values
1034 myTotalTimeLoss += mni->timeLoss;
1035 mySpeedSum += mni->speed * mni->timeOnDetector;
1039
1040 if (vi != nullptr) {
1041 // Accumulate individual values for the vehicle.
1042 // @note vi==0 occurs, if the vehicle info has been erased at
1043 // notifyLeave() in case of a non-longitudinal exit (lanechange, teleport, etc.)
1045 vi->accumulatedTimeLoss += mni->timeLoss;
1046 vi->lastAccel = mni->accel;
1047 vi->lastSpeed = mni->speed;
1048 vi->lastPos = myStartPos + vi->entryOffset + mni->newPos;
1049 vi->onDetector = mni->onDetector;
1050 }
1051}
1052
1053
1054
1056MSE2Collector::makeMoveNotification(const SUMOTrafficObject& veh, double oldPos, double newPos, double newSpeed, const VehicleInfo& vehInfo) const {
1057#ifdef DEBUG_E2_NOTIFY_MOVE
1058 if (DEBUG_COND) {
1059 std::cout << SIMTIME << " makeMoveNotification() for vehicle '" << veh.getID() << "'"
1060 << " oldPos = " << oldPos << " newPos = " << newPos << " newSpeed = " << newSpeed
1061 << std::endl;
1062 }
1063#endif
1064
1065 // Timefraction in [0,TS] the vehicle has spend on the detector in the last step
1066 double timeOnDetector;
1067 // Note that at this point, vehInfo.currentLane points to the lane at the beginning of the last timestep,
1068 // and vehInfo.enteredLanes is a list of lanes entered in the last timestep
1069 double timeLoss;
1070 calculateTimeLossAndTimeOnDetector(veh, oldPos, newPos, vehInfo, timeOnDetector, timeLoss);
1071
1072 // The length of the part of the vehicle on the detector at the end of the last time step
1073 // may be shorter than vehicle's length if its back reaches out
1074 double lengthOnDetector = MAX2(MIN2(vehInfo.length, newPos + vehInfo.entryOffset), 0.);
1075
1076 // XXX: Fulfulling the specifications of the documentation (lengthOnDetector = time integral
1077 // over length of the vehicle's part on the detector) would be much more cumbersome.
1078 double distToExit = -vehInfo.exitOffset - newPos;
1079 // Eventually decrease further to account for the front reaching out
1080 lengthOnDetector = MAX2(0., lengthOnDetector + MIN2(0., distToExit));
1081
1082 // whether the vehicle is still on the detector at the end of the time step
1083 bool stillOnDetector = -distToExit < vehInfo.length;
1084
1085#ifdef DEBUG_E2_NOTIFY_MOVE
1086 if (DEBUG_COND) {
1087 std::cout << SIMTIME << " lengthOnDetector = " << lengthOnDetector
1088 << "\nvehInfo.exitOffset = " << vehInfo.exitOffset
1089 << " vehInfo.entryOffset = " << vehInfo.entryOffset
1090 << " distToExit = " << distToExit
1091 << std::endl;
1092 }
1093#endif
1094
1095 /* Store new infos */
1096 return new MoveNotificationInfo(veh.getID(), oldPos, newPos, newSpeed, veh.getAcceleration(),
1097 myDetectorLength - (vehInfo.entryOffset + newPos),
1098 timeOnDetector, lengthOnDetector, timeLoss,
1099 STEPS2TIME(veh.getWaitingTime()), stillOnDetector);
1100}
1101
1102void
1103MSE2Collector::buildJam(bool isInJam, std::vector<MoveNotificationInfo*>::const_iterator mni, JamInfo*& currentJam, std::vector<JamInfo*>& jams) {
1104#ifdef DEBUG_E2_JAMS
1105 if (DEBUG_COND) {
1106 std::cout << SIMTIME << " buildJam() for vehicle '" << (*mni)->id << "'" << std::endl;
1107 }
1108#endif
1109 if (isInJam) {
1110 // The vehicle is in a jam;
1111 // it may be a new one or already an existing one
1112 if (currentJam == nullptr) {
1113#ifdef DEBUG_E2_JAMS
1114 if (DEBUG_COND) {
1115 std::cout << SIMTIME << " vehicle '" << (*mni)->id << "' forms the start of the first jam" << std::endl;
1116 }
1117#endif
1118 // the vehicle is the first vehicle in a jam
1119 currentJam = new JamInfo();
1120 currentJam->firstStandingVehicle = mni;
1121 } else {
1122 // ok, we have a jam already. But - maybe it is too far away
1123 // ... honestly, I can hardly find a reason for doing this,
1124 // but jams were defined this way in an earlier version...
1125 MoveNotificationInfo* lastVeh = *currentJam->lastStandingVehicle;
1126 MoveNotificationInfo* currVeh = *mni;
1128#ifdef DEBUG_E2_JAMS
1129 if (DEBUG_COND) {
1130 std::cout << SIMTIME << " vehicle '" << (*mni)->id << "' forms the start of a new jam" << std::endl;
1131 }
1132#endif
1133 // yep, yep, yep - it's a new one...
1134 // close the frist, build a new
1135 jams.push_back(currentJam);
1136 currentJam = new JamInfo();
1137 currentJam->firstStandingVehicle = mni;
1138 }
1139 }
1140 currentJam->lastStandingVehicle = mni;
1141 } else {
1142 // the vehicle is not part of a jam...
1143 // maybe we have to close an already computed jam
1144 if (currentJam != nullptr) {
1145#ifdef DEBUG_E2_JAMS
1146 if (DEBUG_COND) {
1147 std::cout << SIMTIME << " Closing current jam." << std::endl;
1148 }
1149#endif
1150 jams.push_back(currentJam);
1151 currentJam = nullptr;
1152 }
1153 }
1154}
1155
1156
1157bool
1158MSE2Collector::checkJam(std::vector<MoveNotificationInfo*>::const_iterator mni, std::map<std::string, SUMOTime>& haltingVehicles, std::map<std::string, SUMOTime>& intervalHaltingVehicles) {
1159#ifdef DEBUG_E2_JAMS
1160 if (DEBUG_COND) {
1161 std::cout << SIMTIME << " CheckJam() for vehicle '" << (*mni)->id << "'" << std::endl;
1162 }
1163#endif
1164 // jam-checking begins
1165 bool isInJam = false;
1166 // first, check whether the vehicle is slow enough to be counted as halting
1167 if ((*mni)->speed < myJamHaltingSpeedThreshold) {
1169 // we have to track the time it was halting;
1170 // so let's look up whether it was halting before and compute the overall halting time
1171 bool wasHalting = myHaltingVehicleDurations.count((*mni)->id) > 0;
1172 if (wasHalting) {
1173 haltingVehicles[(*mni)->id] = myHaltingVehicleDurations[(*mni)->id] + DELTA_T;
1174 intervalHaltingVehicles[(*mni)->id] = myIntervalHaltingVehicleDurations[(*mni)->id] + DELTA_T;
1175 } else {
1176#ifdef DEBUG_E2_JAMS
1177 if (DEBUG_COND) {
1178 std::cout << SIMTIME << " vehicle '" << (*mni)->id << "' starts halting." << std::endl;
1179 }
1180#endif
1181 haltingVehicles[(*mni)->id] = DELTA_T;
1182 intervalHaltingVehicles[(*mni)->id] = DELTA_T;
1185 }
1186 // we now check whether the halting time is large enough
1187 if (haltingVehicles[(*mni)->id] > myJamHaltingTimeThreshold) {
1188 // yep --> the vehicle is a part of a jam
1189 isInJam = true;
1190 }
1191 } else {
1192 // is not standing anymore; keep duration information
1193 std::map<std::string, SUMOTime>::iterator v = myHaltingVehicleDurations.find((*mni)->id);
1194 if (v != myHaltingVehicleDurations.end()) {
1195 myPastStandingDurations.push_back(v->second);
1197 }
1198 v = myIntervalHaltingVehicleDurations.find((*mni)->id);
1199 if (v != myIntervalHaltingVehicleDurations.end()) {
1200 myPastIntervalStandingDurations.push_back((*v).second);
1202 }
1203 }
1204#ifdef DEBUG_E2_JAMS
1205 if (DEBUG_COND) {
1206 std::cout << SIMTIME << " vehicle '" << (*mni)->id << "'" << (isInJam ? "is jammed." : "is not jammed.") << std::endl;
1207 }
1208#endif
1209 return isInJam;
1210}
1211
1212
1213void
1214MSE2Collector::processJams(std::vector<JamInfo*>& jams, JamInfo* currentJam) {
1215 // push last jam
1216 if (currentJam != nullptr) {
1217 jams.push_back(currentJam);
1218 currentJam = nullptr;
1219 }
1220
1221#ifdef DEBUG_E2_JAMS
1222 if (DEBUG_COND) {
1223 std::cout << "\n" << SIMTIME << " processJams()"
1224 << "\nNumber of jams: " << jams.size() << std::endl;
1225 }
1226#endif
1227
1228 // process jam information
1234 for (std::vector<JamInfo*>::const_iterator i = jams.begin(); i != jams.end(); ++i) {
1235 // compute current jam's values
1236 MoveNotificationInfo* lastVeh = *((*i)->lastStandingVehicle);
1237 MoveNotificationInfo* firstVeh = *((*i)->firstStandingVehicle);
1238 const double jamLengthInMeters = MAX2(lastVeh->distToDetectorEnd, 0.) -
1239 MAX2(firstVeh->distToDetectorEnd, 0.) +
1240 lastVeh->lengthOnDetector;
1241 const int jamLengthInVehicles = (int) distance((*i)->firstStandingVehicle, (*i)->lastStandingVehicle) + 1;
1242 // apply them to the statistics
1245 myJamLengthInMetersSum += jamLengthInMeters;
1246 myJamLengthInVehiclesSum += jamLengthInVehicles;
1247 myCurrentJamLengthInMeters += jamLengthInMeters;
1248 myCurrentJamLengthInVehicles += jamLengthInVehicles;
1250#ifdef DEBUG_E2_JAMS
1251 if (DEBUG_COND) {
1252 std::cout << SIMTIME << " processing jam nr." << ((int) distance((std::vector<JamInfo*>::const_iterator) jams.begin(), i) + 1)
1253 << "\njamLengthInMeters = " << jamLengthInMeters
1254 << " jamLengthInVehicles = " << jamLengthInVehicles
1255 << std::endl;
1256 }
1257#endif
1258 }
1259 myCurrentJamNo = (int) jams.size();
1260
1261 // clean up jam structure
1262 for (std::vector<JamInfo*>::iterator i = jams.begin(); i != jams.end(); ++i) {
1263 delete *i;
1264 }
1265}
1266
1267void
1268MSE2Collector::calculateTimeLossAndTimeOnDetector(const SUMOTrafficObject& veh, double oldPos, double newPos, const VehicleInfo& vi, double& timeOnDetector, double& timeLoss) const {
1269 assert(veh.getID() == vi.id);
1270 assert(newPos + vi.entryOffset >= 0);
1271
1272 if (oldPos == newPos) {
1273 // vehicle is stopped
1274 timeLoss = TS;
1275 timeOnDetector = TS;
1276 return;
1277 }
1278
1279 // Eventual positional offset of the detector start from the lane's start
1280 double entryPos = MAX2(-vi.entryOffset, 0.);
1281 // Time of this vehicle entering the detector in the last time step
1282 double entryTime = 0;
1283 // Take into account the time before entering the detector, if there is.
1284 if (oldPos < entryPos) {
1285 // Vehicle entered the detector in the last step, either traversing the detector start or somewhere in the middle.
1286 entryTime = MSCFModel::passingTime(oldPos, entryPos, newPos, veh.getPreviousSpeed(), veh.getSpeed());
1287 }
1288 // speed at detector entry
1289 double entrySpeed = MSCFModel::speedAfterTime(entryTime, veh.getPreviousSpeed(), newPos - oldPos);
1290 // Calculate time spent on detector until reaching newPos or a detector exit
1291 double exitPos = MIN2(newPos, -vi.exitOffset + vi.length);
1292 assert(entryPos < exitPos);
1293
1294 // calculate vehicle's time spent on the detector
1295 double exitTime;
1296 if (exitPos == newPos) {
1297 exitTime = TS;
1298 } else {
1299 exitTime = MSCFModel::passingTime(oldPos, exitPos, newPos, veh.getPreviousSpeed(), veh.getSpeed());
1300 }
1301
1302 // Vehicle's Speed when leaving the detector
1303 double exitSpeed = MSCFModel::speedAfterTime(exitTime, veh.getPreviousSpeed(), newPos - oldPos);
1304
1305 // Maximal speed on vehicle's current lane (== lane before last time step)
1306 // Note: this disregards the possibility of different maximal speeds on different traversed lanes.
1307 // (we accept this as discretization error)
1308 double vmax = MAX2(veh.getLane()->getVehicleMaxSpeed(&veh), NUMERICAL_EPS);
1309
1310 // Time loss suffered on the detector
1311 timeOnDetector = exitTime - entryTime;
1312 timeLoss = MAX2(0., timeOnDetector * (vmax - (entrySpeed + exitSpeed) / 2) / vmax);
1313
1314#ifdef DEBUG_E2_TIME_ON_DETECTOR
1315 if (DEBUG_COND) {
1316 std::cout << SIMTIME << " calculateTimeLoss() for vehicle '" << veh.getID() << "'"
1317 << " oldPos = " << oldPos << " newPos = " << newPos
1318 << " entryPos = " << entryPos << " exitPos = " << exitPos
1319 << " timeOnDetector = " << timeOnDetector
1320 << " timeLoss = " << timeLoss
1321 << std::endl;
1322 }
1323#endif
1324}
1325
1326
1327void
1329 dev.writeXMLHeader("detector", "det_e2_file.xsd");
1330}
1331
1332void
1334 const double meanSpeed = getIntervalMeanSpeed();
1335 const double meanOccupancy = getIntervalOccupancy();
1336 const double meanTimeLoss = getIntervalMeanTimeLoss();
1337 myPreviousMeanOccupancy = meanOccupancy;
1338 myPreviousMeanSpeed = meanSpeed;
1341 myPreviousMeanTimeLoss = meanTimeLoss;
1342
1343 if (dev.isNull()) {
1344 reset();
1345 return;
1346 }
1347 const double meanJamLengthInMeters = myTimeSamples != 0 ? myMeanMaxJamInMeters / (double) myTimeSamples : 0;
1348 const double meanJamLengthInVehicles = myTimeSamples != 0 ? myMeanMaxJamInVehicles / (double) myTimeSamples : 0;
1349 const double meanVehicleNumber = myTimeSamples != 0 ? (double) myMeanVehicleNumber / (double) myTimeSamples : 0;
1350
1351 SUMOTime haltingDurationSum = 0;
1352 SUMOTime maxHaltingDuration = 0;
1353 int haltingNo = 0;
1354 for (std::vector<SUMOTime>::iterator i = myPastStandingDurations.begin(); i != myPastStandingDurations.end(); ++i) {
1355 haltingDurationSum += (*i);
1356 maxHaltingDuration = MAX2(maxHaltingDuration, (*i));
1357 haltingNo++;
1358 }
1359 for (std::map<std::string, SUMOTime> ::iterator i = myHaltingVehicleDurations.begin(); i != myHaltingVehicleDurations.end(); ++i) {
1360 haltingDurationSum += (*i).second;
1361 maxHaltingDuration = MAX2(maxHaltingDuration, (*i).second);
1362 haltingNo++;
1363 }
1364 const SUMOTime meanHaltingDuration = haltingNo != 0 ? haltingDurationSum / haltingNo : 0;
1365
1366 SUMOTime intervalHaltingDurationSum = 0;
1367 SUMOTime intervalMaxHaltingDuration = 0;
1368 int intervalHaltingNo = 0;
1369 for (std::vector<SUMOTime>::iterator i = myPastIntervalStandingDurations.begin(); i != myPastIntervalStandingDurations.end(); ++i) {
1370 intervalHaltingDurationSum += (*i);
1371 intervalMaxHaltingDuration = MAX2(intervalMaxHaltingDuration, (*i));
1372 intervalHaltingNo++;
1373 }
1374 for (std::map<std::string, SUMOTime> ::iterator i = myIntervalHaltingVehicleDurations.begin(); i != myIntervalHaltingVehicleDurations.end(); ++i) {
1375 intervalHaltingDurationSum += (*i).second;
1376 intervalMaxHaltingDuration = MAX2(intervalMaxHaltingDuration, (*i).second);
1377 intervalHaltingNo++;
1378 }
1379 const SUMOTime intervalMeanHaltingDuration = intervalHaltingNo != 0 ? intervalHaltingDurationSum / intervalHaltingNo : 0;
1380
1381#ifdef DEBUG_E2_XML_OUT
1382 if (DEBUG_COND) {
1383 std::stringstream ss;
1384 ss << "sampledSeconds=\"" << myVehicleSamples << "\" "
1385 << "myTimeSamples=\"" << myTimeSamples << "\" "
1386 << "myOccupancySum=\"" << myOccupancySum << "\" "
1387 << "myMeanVehicleNumber=\"" << myMeanVehicleNumber << "\" "
1388 << "nVehEntered=\"" << myNumberOfEnteredVehicles << "\" "
1389 << "meanSpeed=\"" << meanSpeed << "\"";
1390 std::cout << ss.str() << std::endl;
1391 }
1392#endif
1393
1396 dev.writeAttr("sampledSeconds", myVehicleSamples)
1397 .writeAttr("nVehEntered", myNumberOfEnteredVehicles)
1398 .writeAttr("nVehLeft", myNumberOfLeftVehicles)
1399 .writeAttr("nVehSeen", myNumberOfSeenVehicles)
1400 .writeAttr("meanSpeed", meanSpeed)
1401 .writeAttr("meanTimeLoss", meanTimeLoss)
1402 .writeAttr("meanOccupancy", meanOccupancy)
1403 .writeAttr("maxOccupancy", myMaxOccupancy)
1404 .writeAttr("meanMaxJamLengthInVehicles", meanJamLengthInVehicles)
1405 .writeAttr("meanMaxJamLengthInMeters", meanJamLengthInMeters)
1406 .writeAttr("maxJamLengthInVehicles", myMaxJamInVehicles)
1407 .writeAttr("maxJamLengthInMeters", myMaxJamInMeters)
1408 .writeAttr("jamLengthInVehiclesSum", myJamLengthInVehiclesSum)
1409 .writeAttr("jamLengthInMetersSum", myJamLengthInMetersSum)
1410 .writeAttr("meanHaltingDuration", STEPS2TIME(meanHaltingDuration))
1411 .writeAttr("maxHaltingDuration", STEPS2TIME(maxHaltingDuration))
1412 .writeAttr("haltingDurationSum", STEPS2TIME(haltingDurationSum))
1413 .writeAttr("meanIntervalHaltingDuration", STEPS2TIME(intervalMeanHaltingDuration))
1414 .writeAttr("maxIntervalHaltingDuration", STEPS2TIME(intervalMaxHaltingDuration))
1415 .writeAttr("intervalHaltingDurationSum", STEPS2TIME(intervalHaltingDurationSum))
1416 .writeAttr("startedHalts", myStartedHalts)
1417 .writeAttr("meanVehicleNumber", meanVehicleNumber)
1418 .writeAttr("maxVehicleNumber", myMaxVehicleNumber)
1419 .closeTag();
1420
1421 reset();
1422}
1423
1424void
1426 myVehicleSamples = 0;
1427 myTotalTimeLoss = 0.;
1432
1433 mySpeedSum = 0;
1434 myStartedHalts = 0;
1437 myOccupancySum = 0;
1438 myMaxOccupancy = 0;
1442 myMaxJamInMeters = 0;
1443 myTimeSamples = 0;
1445 for (std::map<std::string, SUMOTime>::iterator i = myIntervalHaltingVehicleDurations.begin(); i != myIntervalHaltingVehicleDurations.end(); ++i) {
1446 (*i).second = 0;
1447 }
1450}
1451
1452
1453int
1455 int result = 0;
1456 if (myOverrideVehNumber >= 0) {
1457 result = myOverrideVehNumber;
1458 } else {
1459 for (VehicleInfoMap::const_iterator it = myVehicleInfos.begin(); it != myVehicleInfos.end(); it++) {
1460 if (it->second->onDetector) {
1461 result++;
1462 }
1463 }
1464 }
1465 return result;
1466}
1467
1468void
1472
1473
1474
1475std::vector<std::string>
1477 std::vector<std::string> ret;
1478 for (VehicleInfoMap::const_iterator i = myVehicleInfos.begin(); i != myVehicleInfos.end(); ++i) {
1479 if (i->second->onDetector) {
1480 ret.push_back(i->second->id);
1481 }
1482 }
1483 std::sort(ret.begin(), ret.end());
1484 return ret;
1485}
1486
1487
1488std::vector<MSE2Collector::VehicleInfo*>
1490 std::vector<VehicleInfo*> res;
1491 VehicleInfoMap::const_iterator i;
1492 for (i = myVehicleInfos.begin(); i != myVehicleInfos.end(); ++i) {
1493 if (i->second->onDetector) {
1494 res.push_back(i->second);
1495 }
1496 }
1497 return res;
1498}
1499
1500
1501
1502int
1504
1505 // double distance = std::numeric_limits<double>::max();
1506 double thresholdSpeed = myLane->getSpeedLimit() / speedThreshold;
1507
1508 int count = 0;
1509 for (VehicleInfoMap::const_iterator it = myVehicleInfos.begin();
1510 it != myVehicleInfos.end(); it++) {
1511 if (it->second->onDetector) {
1512 // if (it->position < distance) {
1513 // distance = it->position;
1514 // }
1515 // const double realDistance = myLane->getLength() - distance; // the closer vehicle get to the light the greater is the distance
1516 const double realDistance = it->second->distToDetectorEnd;
1517 if (it->second->lastSpeed <= thresholdSpeed || it->second->lastAccel > 0) { //TODO speed less half of the maximum speed for the lane NEED TUNING
1518 count = (int)(realDistance / (it->second->length + it->second->minGap)) + 1;
1519 }
1520 }
1521 }
1522
1523 return count;
1524}
1525
1526double
1528
1529 if (myVehicleInfos.empty()) {
1530 return 0;
1531 }
1532
1533 double distance = 0;
1534 double realDistance = 0;
1535 bool flowing = true;
1536 for (VehicleInfoMap::const_iterator it = myVehicleInfos.begin();
1537 it != myVehicleInfos.end(); it++) {
1538 if (it->second->onDetector && it->second->totalTimeOnDetector > 0) {
1539 // double distanceTemp = myLane->getLength() - distance;
1540 if (it->second->lastSpeed <= myJamHaltingSpeedThreshold) {
1541 distance = MAX2(it->second->distToDetectorEnd, distance);
1542 realDistance = distance + it->second->length;
1543 flowing = false;
1544 }
1545 // DBG(
1546 // std::ostringstream str;
1547 // str << time2string(MSNet::getInstance()->getCurrentTimeStep())
1548 // << " MSE2Collector::getEstimateQueueLength::"
1549 // << " lane " << myLane->getID()
1550 // << " vehicle " << it->second.id
1551 // << " positionOnLane " << it->second.position
1552 // << " vel " << it->second.speed
1553 // << " realDistance " << realDistance;
1554 // WRITE_MESSAGE(str.str());
1555 // )
1556 }
1557 }
1558 if (flowing) {
1559 return 0;
1560 } else {
1561 return realDistance;
1562 }
1563}
1564
1565
1566double
1568#ifdef HAVE_FOX
1569 ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
1570#endif
1572 double result = -INVALID_DOUBLE;
1573 for (auto item : myVehicleInfos) {
1574 if (item.second->onDetector) {
1575 SUMOVehicle* v = vc.getVehicle(item.first);
1576 if (v != nullptr) {
1577 MSBaseVehicle* veh = dynamic_cast<MSBaseVehicle*>(v);
1578 double ad = veh->getStopArrivalDelay();
1579 if (ad != INVALID_DOUBLE) {
1580 result = MAX2(result, ad);
1581 }
1582 }
1583 }
1584 }
1585 return result;
1586}
1587
1588
1589
1590void
1592 for (std::vector<MoveNotificationInfo*>::iterator j = myMoveNotifications.begin(); j != myMoveNotifications.end(); ++j) {
1593 delete *j;
1594 }
1595 myMoveNotifications.clear();
1596
1597 // clear vehicle infos
1598 for (VehicleInfoMap::iterator j = myVehicleInfos.begin(); j != myVehicleInfos.end(); ++j) {
1599 delete j->second;
1600 }
1601 myVehicleInfos.clear();
1602}
1603
1604/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define WRITE_WARNING(msg)
Definition MsgHandler.h:286
#define TL(string)
Definition MsgHandler.h:304
SUMOTime DELTA_T
Definition SUMOTime.cpp:38
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:91
#define STEPS2TIME(x)
Definition SUMOTime.h:58
#define SPEED2DIST(x)
Definition SUMOTime.h:48
#define SIMSTEP
Definition SUMOTime.h:64
#define SUMOTime_MAX
Definition SUMOTime.h:34
#define TS
Definition SUMOTime.h:45
#define SIMTIME
Definition SUMOTime.h:65
@ SUMO_TAG_INTERVAL
an aggreagated-output interval
@ SUMO_ATTR_BEGIN
weights: time range begin
@ SUMO_ATTR_END
weights: time range end
@ SUMO_ATTR_ID
const double INVALID_DOUBLE
invalid double
Definition StdDefs.h:68
T MIN2(T a, T b)
Definition StdDefs.h:80
T MAX2(T a, T b)
Definition StdDefs.h:86
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:49
The base class for microscopic and mesoscopic vehicles.
const std::vector< MSTransportable * > & getPersons() const
retrieve riding persons
virtual double getStopArrivalDelay() const
Returns the estimated public transport stop arrival delay in seconds.
static double speedAfterTime(const double t, const double oldSpeed, const double dist)
Calculates the speed after a time t \in [0,TS] given the initial speed and the distance traveled in a...
static double passingTime(const double lastPos, const double passedPos, const double currentPos, const double lastSpeed, const double currentSpeed)
Calculates the time at which the position passedPosition has been passed In case of a ballistic updat...
Base of value-generating classes (detectors)
bool vehicleApplies(const SUMOTrafficObject &veh) const
Checks whether the detector measures vehicles of the given type.
std::vector< const MSEdge * > myNextEdges
The upcoming edges to filter by (empty means no filtering)
const int myDetectPersons
Whether pedestrians shall be detected instead of vehicles.
bool personApplies(const MSTransportable &p, int dir) const
void checkPositioning(bool posGiven=false, double desiredLength=0.)
Adjusts positioning if the detector length is less than POSITION_EPS and tests some assertions.
void notifyMovePerson(MSTransportable *p, int dir, double pos)
double myCurrentMaxJamLengthInMeters
the current maximum jam length in meters
VehicleInfo * makeVehicleInfo(const SUMOTrafficObject &veh, const MSLane *enteredLane) const
Creates and returns a VehicleInfo (called at the vehicle's entry)
double myVehicleSamples
bool checkJam(std::vector< MoveNotificationInfo * >::const_iterator mni, std::map< std::string, SUMOTime > &haltingVehicles, std::map< std::string, SUMOTime > &intervalHaltingVehicles)
checks whether the vehicle stands in a jam
void buildJam(bool isInJam, std::vector< MoveNotificationInfo * >::const_iterator mni, JamInfo *&currentJam, std::vector< JamInfo * > &jams)
Either adds the vehicle to the end of an existing jam, or closes the last jam, and/or creates a new j...
std::map< std::string, SUMOTime > myHaltingVehicleDurations
Storage for halting durations of known vehicles (for halting vehicles)
int myJamLengthInVehiclesSum
The sum of jam lengths [#veh].
int myMeanVehicleNumber
The mean number of vehicles [#veh].
int myCurrentStartedHalts
The number of started halts in the last step.
int myTimeSamples
The current aggregation duration [#steps].
static bool compareMoveNotification(MoveNotificationInfo *mni1, MoveNotificationInfo *mni2)
int myNumberOfSeenVehicles
The number of vehicles, present on the detector at the last reset.
int myCurrentMaxJamLengthInVehicles
The current maximum jam length in vehicles.
std::vector< MSLane * > getLanes()
Returns a vector containing pointers to the lanes covered by the detector ordered from its first to i...
int myNumberOfLeftVehicles
The number of vehicles, which have left the detector since the last reset.
std::vector< SUMOTime > myPastStandingDurations
Halting durations of ended halts [s].
void processJams(std::vector< JamInfo * > &jams, JamInfo *currentJam)
Calculates aggregated values from the given jam structure, deletes all jam-pointers.
std::vector< double > myOffsets
The distances of the lane-beginnings from the detector start-point.
double myPreviousMeanSpeed
int myMaxJamInVehicles
The max jam length [#veh].
virtual void reset()
Resets all values.
virtual bool notifyMove(SUMOTrafficObject &veh, double oldPos, double newPos, double newSpeed)
Adds/removes vehicles from the list of vehicles to regard.
std::vector< VehicleInfo * > getCurrentVehicles() const
Returns the VehicleInfos for the vehicles currently on the detector.
double myPreviousMaxJamLengthInMeters
double myJamHaltingSpeedThreshold
A vehicle must driver slower than this to be counted as a part of a jam.
virtual bool notifyEnter(SUMOTrafficObject &veh, MSMoveReminder::Notification reason, const MSLane *enteredLane)
Adds the vehicle to known vehicles if not beyond the dector.
VehicleInfoMap myVehicleInfos
int myNumberOfEnteredVehicles
static double snap(double value, double snapPoint, double snapDist)
Snaps value to snpPoint if they are closer than snapDist.
void initAuxiliaries(std::vector< MSLane * > &lanes)
Checks integrity of myLanes, adds internal-lane information, inits myLength, myFirstLane,...
MSLane * myFirstLane
The first lane of the detector's lane sequence.
std::vector< std::string > getCurrentVehicleIDs() const
Returns the IDs of the vehicles within the area.
double mySpeedSum
The sum of collected vehicle speeds [m/s].
std::set< std::string > myLeftVehicles
Keep track of vehicles that left the detector by a regular move along a junction (not lanechange,...
double getIntervalMeanSpeed() const
double myEndPos
The position the detector ends at on the last lane.
int myPreviousNumberOfSeenVehicles
double myDetectorLength
The total detector length.
virtual void clearState(SUMOTime step)
Remove all vehicles before quick-loading state.
std::vector< MSLane * > selectLanes(MSLane *endLane, double length, std::string dir)
This is called if no lane sequence is given to the constructor. Builds myLanes from the given informa...
int getCurrentVehicleNumber() const
Returns the number of vehicles currently on the detector.
double myCurrentMeanSpeed
The current mean speed.
double myStartPos
The position the detector starts at on the first lane.
std::vector< MoveNotificationInfo * > myMoveNotifications
Temporal storage for notifications from vehicles that did call the detector's notifyMove() in the las...
void addDetectorToLanes(std::vector< MSLane * > &lanes)
This adds the detector as a MoveReminder to the associated lanes.
SUMOTime myJamHaltingTimeThreshold
A vehicle must be that long beyond myJamHaltingSpeedThreshold to be counted as a part of a jam.
int myMaxVehicleNumber
The maximal number of vehicles located on the detector simultaneously since the last reset.
void recalculateDetectorLength()
Updates the detector length after myStartPos and myEndPos have been modified.
double myMaxOccupancy
The maximum occupancy [%].
double myPreviousMeanOccupancy
virtual void detectorUpdate(const SUMOTime step)
Computes the detector values in each time step.
int myCurrentJamNo
The current jam number.
double myCurrentVehicleSamples
The current vehicle samples.
MSE2Collector(const std::string &id, DetectorUsage usage, MSLane *lane, double startPos, double endPos, double length, SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold, const std::string name, const std::string &vTypes, const std::string &nextEdges, int detectPersons)
Constructor with given end position and detector length.
virtual bool notifyLeave(SUMOTrafficObject &veh, double lastPos, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Removes a known vehicle due to its lane-change.
double myCurrentJamDuration
The overall jam duration in s.
double getEstimateQueueLength() const
Returns an estimate of the length of the queue of vehicles currently stopped on the detector.
virtual void writeXMLOutput(OutputDevice &dev, SUMOTime startTime, SUMOTime stopTime)
Write the generated output to the given device.
double myMeanMaxJamInMeters
The mean jam length [m].
int myOverrideVehNumber
stores the overriden (via Traci) number of vehicles on detector
double getArrivalDelay() const
Returns the maximum stop arrival delay of public transport vehicles that are on the detector or passe...
double myCurrentJamLengthInMeters
The overall jam length in meters.
double myCurrentMeanLength
The current mean length.
double myMaxJamInMeters
The max jam length [m].
int myStartedHalts
The number of started halts [#].
std::vector< std::string > myLanes
The detector's lane sequence.
int myMeanMaxJamInVehicles
The mean jam length [#veh].
int myCurrentJamLengthInVehicles
The overall jam length in vehicles.
void calculateTimeLossAndTimeOnDetector(const SUMOTrafficObject &veh, double oldPos, double newPos, const VehicleInfo &vi, double &timeOnDetector, double &timeLoss) const
Calculates the time spent on the detector in the last step and the timeloss suffered in the last step...
double myJamLengthInMetersSum
The sum of jam lengths [m].
double myJamDistanceThreshold
Two standing vehicles must be closer than this to be counted into the same jam.
int getEstimatedCurrentVehicleNumber(double speedThreshold) const
Returns an estimate of the number of vehicles currently on the detector.
double getLength() const
Returns the length of the detector.
std::vector< SUMOTime > myPastIntervalStandingDurations
Halting durations of ended halts for the current interval [s].
virtual ~MSE2Collector()
Destructor.
MSLane * myLastLane
The last lane of the detector's lane sequence.
void overrideVehicleNumber(int num)
Persistently overrides the number of vehicles on top of the detector Setting a negative value removes...
double myCurrentOccupancy
The current occupancy.
double getIntervalOccupancy() const
double myOccupancySum
The sum of occupancies [%].
double myPreviousMeanTimeLoss
int myCurrentHaltingsNumber
The number of halted vehicles [#].
virtual void writeXMLDetectorProlog(OutputDevice &dev) const
Open the XML-output.
double myTotalTimeLoss
The total amount of all time losses [time x vehicle] since the last reset.
void integrateMoveNotification(VehicleInfo *vi, const MoveNotificationInfo *mni)
This updates the detector values and the VehicleInfo of a vehicle on the detector with the given Move...
std::map< std::string, SUMOTime > myIntervalHaltingVehicleDurations
Storage for halting durations of known vehicles (current interval)
MoveNotificationInfo * makeMoveNotification(const SUMOTrafficObject &veh, double oldPos, double newPos, double newSpeed, const VehicleInfo &vehInfo) const
Creates and returns a MoveNotificationInfo containing detector specific information on the vehicle's ...
double getIntervalMeanTimeLoss() const
void aggregateOutputValues()
Aggregates and normalize some values for the detector output during detectorUpdate()
const std::set< MSTransportable *, ComparatorNumericalIdLess > & getPersons() const
Returns this edge's persons set.
Definition MSEdge.h:204
static int gNumSimThreads
how many threads to use for simulation
Definition MSGlobals.h:149
static bool gUsingInternalLanes
Information whether the simulation regards internal lanes.
Definition MSGlobals.h:81
Representation of a lane in the micro simulation.
Definition MSLane.h:84
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2783
double getSpeedLimit() const
Returns the lane's maximum allowed speed.
Definition MSLane.h:603
MSLane * getCanonicalPredecessorLane() const
Definition MSLane.cpp:3309
double getLength() const
Returns the lane's length.
Definition MSLane.h:617
double getVehicleMaxSpeed(const SUMOTrafficObject *const veh) const
Returns the lane's maximum speed, given a vehicle's speed limit adaptation.
Definition MSLane.h:575
MSLane * getCanonicalSuccessorLane() const
Definition MSLane.cpp:3333
static bool dictionary(const std::string &id, MSLane *lane)
Static (sic!) container methods {.
Definition MSLane.cpp:2520
bool isInternal() const
Definition MSLane.cpp:2651
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:775
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:735
Something on a lane to be noticed about vehicle movement.
Notification
Definition of a vehicle state.
@ NOTIFICATION_JUNCTION
The vehicle arrived at a junction.
MSLane * myLane
Lane on which the reminder works.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:199
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition MSNet.h:402
static const int FORWARD
Definition MSPModel.h:54
virtual double getSpeed() const override
the current speed of the transportable
const MSVehicleType & getVehicleType() const override
Returns the object's "vehicle" type.
The class responsible for building and deletion of vehicles.
SUMOVehicle * getVehicle(const std::string &id) const
Returns the vehicle with the given id.
const std::string & getID() const
Returns the name of the vehicle type.
double getMinGap() const
Get the free space in front of vehicles of this class.
double getLength() const
Get vehicle's length [m].
std::string myID
The name of the object.
Definition Named.h:125
const std::string & getID() const
Returns the id.
Definition Named.h:74
Static storage of an output device and its base (abstract) implementation.
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const ATTR_TYPE &attr, const T &val, const bool isNull=false)
writes a named attribute
virtual bool isNull()
returns the information whether the device will discard all output
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
bool writeXMLHeader(const std::string &rootElement, const std::string &schemaFile, std::map< SumoXMLAttr, std::string > attrs=std::map< SumoXMLAttr, std::string >(), bool includeConfig=true)
Writes an XML header with optional configuration.
OutputDevice & writeTime(const SumoXMLAttr attr, const SUMOTime val)
Representation of a vehicle, person, or container.
virtual bool isVehicle() const
Whether it is a vehicle.
virtual double getAcceleration() const =0
Returns the object's acceleration.
virtual const MSVehicleType & getVehicleType() const =0
Returns the object's "vehicle" type.
virtual const MSLane * getLane() const =0
Returns the lane the object is currently at.
virtual double getPreviousSpeed() const =0
Returns the object's previous speed.
virtual double getSpeed() const =0
Returns the object's current speed.
virtual SUMOTime getWaitingTime(const bool accumulated=false) const =0
virtual bool isPerson() const
Whether it is a person.
virtual double getBackPositionOnLane(const MSLane *lane) const =0
Get the object's back position along the given lane.
virtual double getPositionOnLane() const =0
Get the object's position along the lane.
Representation of a vehicle.
Definition SUMOVehicle.h:63
A scoped lock which only triggers on condition.
static std::string escapeXML(const std::string &orig, const bool maskDoubleHyphen=false)
Replaces the standard escapes by their XML entities.
#define DEBUG_COND
Internal representation of a jam.
std::vector< MoveNotificationInfo * >::const_iterator lastStandingVehicle
The last standing vehicle.
std::vector< MoveNotificationInfo * >::const_iterator firstStandingVehicle
The first standing vehicle.
Values collected in notifyMove and needed in detectorUpdate() to calculate the accumulated quantities...
double speed
Speed after the last integration step.
double waitingTime
the current (consecutive) waitingTime on the detector in s
double newPos
Position after the last integration step (relative to the vehicle's entry lane on the detector)
double distToDetectorEnd
Distance left till the detector end after the last integration step (may become negative if the vehic...
double accel
Acceleration in the last integration step.
double timeLoss
timeloss during the last integration step
double timeOnDetector
Time spent on the detector during the last integration step.
double lengthOnDetector
The length of the part of the vehicle on the detector at the end of the last time step.
bool onDetector
whether the vehicle is on the detector at the end of the current timestep
A VehicleInfo stores values that are tracked for the individual vehicles on the detector,...
double lastAccel
Last value of the acceleration.
double length
vehicle's length
double accumulatedTimeLoss
Accumulated time loss that this vehicle suffered since it entered the detector.
bool onDetector
whether the vehicle is on the detector at the end of the current timestep
double distToDetectorEnd
Distance left till the detector end after the last integration step (may become negative if the vehic...
double lastSpeed
Last value of the speed.
bool hasEntered
Whether the vehicle has already entered the detector (don't count twice!)
std::string id
vehicle's ID
double totalTimeOnDetector
Accumulated time that this vehicle has spent on the detector since its last entry.