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