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