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