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