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