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