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