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