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