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