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