Eclipse SUMO - Simulation of Urban MObility
MSE3Collector.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 /****************************************************************************/
22 // A detector of vehicles passing an area between entry/exit points
23 /****************************************************************************/
24 #include <config.h>
25 
26 #include <algorithm>
27 #ifdef HAVE_FOX
29 #endif
30 #include <microsim/MSLane.h>
31 #include <microsim/MSEdge.h>
32 #include <microsim/MSNet.h>
33 #include <microsim/MSVehicle.h>
36 #include "MSE3Collector.h"
37 
38 //#define DEBUG_E3_NOTIFY_MOVE
39 //#define DEBUG_E3_NOTIFY_ENTER
40 //#define DEBUG_E3_NOTIFY_LEAVE
41 //#define DEBUG_E3_DETECTORUPDATE
42 
43 //#define DEBUG_COND(obj) ((obj.getID() == ""))
44 //#define DEBUG_COND_VEH(veh) ((veh).getID() == "")
45 //#define DEBUG_COND_VEH(veh) ((veh).isSelected())
46 //#define DEBUG_COND(collector) (true)
47 //#define DEBUG_COND_VEH(veh) (true)
48 
49 
50 // ===========================================================================
51 // method definitions
52 // ===========================================================================
53 /* -------------------------------------------------------------------------
54  * MSE3Collector::MSE3EntryReminder - definitions
55  * ----------------------------------------------------------------------- */
57  const MSCrossSection& crossSection, MSE3Collector& collector) :
58  MSMoveReminder(collector.getID() + "_entry", crossSection.myLane),
59  myCollector(collector), myPosition(crossSection.myPosition) {
60 }
61 
62 
63 bool
65 #ifdef DEBUG_E3_NOTIFY_ENTER
66  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
67  std::cout << SIMTIME
68  << " MSE3EntryReminder::notifyEnter() (" << getDescription() << "on lane '" << myLane->getID() << "')"
69  << " vehicle '" << veh.getID() << "'"
70  << " enteredLane=" << enteredLane->getID()
71  << " reason=" << reason
72  << "\n";
73  }
74 #endif
75  if (reason != NOTIFICATION_JUNCTION) {
76  const double posOnLane = veh.getBackPositionOnLane(enteredLane) + veh.getVehicleType().getLength();
77  if (myLane == enteredLane && posOnLane > myPosition) {
78 #ifdef HAVE_FOX
79  ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
80 #endif
81  const auto& itVeh = myCollector.myEnteredContainer.find(&veh);
82  if (itVeh == myCollector.myEnteredContainer.end() ||
83  itVeh->second.entryReminder != this) {
84 #ifdef DEBUG_E3_NOTIFY_ENTER
85  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
86  std::cout << " assume already known\n";
87  }
88 #endif
89  // if the vehicle changes into a covered section we assume it was already registered on another lane
90  return false;
91  }
92  }
93  }
94  return true;
95 }
96 
97 
98 bool
100  double newPos, double newSpeed) {
101 #ifdef DEBUG_E3_NOTIFY_MOVE
102  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
103  std::cout << SIMTIME
104  << " MSE3EntryReminder::notifyMove() (" << getDescription() << "on lane '" << myLane->getID() << "')"
105  << " vehicle '" << veh.getID() << "'"
106  << " entered. oldPos=" << oldPos << " newPos=" << newPos << " newSpeed=" << newSpeed
107  << " myPosition=" << myPosition
108  << "\n";
109  }
110 #endif
111 #ifdef HAVE_FOX
112  ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
113 #endif
114  if ((myCollector.myEnteredContainer.find(&veh) == myCollector.myEnteredContainer.end() ||
115  (veh.isPerson() && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD))
116  && newPos > myPosition) {
117  if (oldPos > myPosition) {
118  // was behind the detector already in the last step
119 #ifdef DEBUG_E3_NOTIFY_MOVE
120  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
121  std::cout << " already behind\n";
122  }
123 #endif
124  return false;
125  } else {
126  // entered in this step
127  const double oldSpeed = veh.getPreviousSpeed();
128  const double entryTime = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep());
129  assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
130  const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
131  const double fractionTimeOnDet = TS - timeBeforeEnter;
132  myCollector.enter(veh, entryTime - fractionTimeOnDet, fractionTimeOnDet, this);
133 #ifdef DEBUG_E3_NOTIFY_MOVE
134  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
135  std::cout << " enter\n";
136  }
137 #endif
138  }
139  }
140  return true;
141 }
142 
143 
144 bool
146 #ifdef DEBUG_E3_NOTIFY_LEAVE
147  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
148  std::cout << SIMTIME
149  << " MSE3EntryReminder::notifyLeave() (" << getDescription() << "on lane '" << myLane->getID() << "')"
150  << " vehicle '" << veh.getID() << "'"
151  << " reason=" << reason
152  << "\n";
153  }
154 #endif
155  if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
156 #ifdef HAVE_FOX
157  ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
158 #endif
159  if (myCollector.myEnteredContainer.erase(&veh) > 0) {
160  WRITE_WARNING("Vehicle '" + veh.getID() + "' arrived inside " + toString(SUMO_TAG_E3DETECTOR) + " '" + myCollector.getID() + "'.");
161  }
162  return false;
163  }
164  return true;
165 }
166 
167 
168 /* -------------------------------------------------------------------------
169  * MSE3Collector::MSE3LeaveReminder - definitions
170  * ----------------------------------------------------------------------- */
172  const MSCrossSection& crossSection, MSE3Collector& collector) :
173  MSMoveReminder(collector.getID() + "_exit", crossSection.myLane),
174  myCollector(collector), myPosition(crossSection.myPosition) {}
175 
176 
177 bool
179 #ifdef DEBUG_E3_NOTIFY_ENTER
180  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
181  std::cout << SIMTIME
182  << " MSE3LeaveReminder::notifyEnter() (" << getDescription() << "on lane '" << myLane->getID() << "')"
183  << " vehicle '" << veh.getID() << "'"
184  << " enteredLane=" << enteredLane->getID()
185  << " reason=" << reason
186  << "\n";
187  }
188 #endif
189  // this method does not access containers, so no locking here
190  if (reason != NOTIFICATION_JUNCTION) {
191  const double backPosOnLane = veh.getBackPositionOnLane(enteredLane);
192  if (backPosOnLane > myPosition) {
193  // if the vehicle changes into a covered section we assume it was already registered on another lane
194  // however, if it is not fully past the detector we still need to track it
195 #ifdef DEBUG_E3_NOTIFY_ENTER
196  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
197  std::cout << " assume already known\n";
198  }
199 #endif
200  return false;
201  }
202  }
203  return true;
204 }
205 
206 
207 bool
209  double newPos, double newSpeed) {
210 #ifdef DEBUG_E3_NOTIFY_MOVE
211  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
212  std::cout << SIMTIME
213  << " MSE3LeaveReminder::notifyMove() (" << getDescription() << " on lane '" << myLane->getID() << "')"
214  << " vehicle '" << veh.getID() << "'"
215  << " entered. oldPos=" << oldPos << " newPos=" << newPos << " newSpeed=" << newSpeed
216  << " myPosition=" << myPosition
217  << "\n";
218  }
219 #endif
220  if (newPos < myPosition) {
221  // crossSection not yet reached
222  return true;
223  }
224 #ifdef HAVE_FOX
225  ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
226 #endif
227  const double oldSpeed = veh.getPreviousSpeed();
228  if (oldPos < myPosition) {
229  assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
230  const double timeBeforeLeave = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
231 // const double leaveTimeFront = SIMTIME - TS + (myPosition - oldPos) / newSpeed;
232  const double leaveTimeFront = SIMTIME - TS + timeBeforeLeave;
233  myCollector.leaveFront(veh, leaveTimeFront);
234 #ifdef DEBUG_E3_NOTIFY_MOVE
235  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
236  std::cout << " leaveFront\n";
237  }
238 #endif
239  }
240  const double backPos = newPos - veh.getVehicleType().getLength();
241  if (backPos < myPosition) {
242  // crossSection not yet left
243  return true;
244  }
245  // crossSection left
246  const double oldBackPos = oldPos - veh.getVehicleType().getLength();
247  const double leaveStep = SIMTIME;
248  assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
249  const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, backPos, oldSpeed, newSpeed);
250  myCollector.leave(veh, leaveStep - TS + timeBeforeLeave, timeBeforeLeave);
251 #ifdef DEBUG_E3_NOTIFY_MOVE
252  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
253  std::cout << " leave\n";
254  }
255 #endif
256  return false;
257 }
258 
259 
260 bool
262 #ifdef DEBUG_E3_NOTIFY_LEAVE
263  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
264  std::cout << SIMTIME
265  << " MSE3LeaveReminder::notifyLeave() (" << getDescription() << "on lane '" << myLane->getID() << "')"
266  << " vehicle '" << veh.getID() << "'"
267  << " reason=" << reason
268  << "\n";
269  }
270 #endif
271  if (reason == MSMoveReminder::NOTIFICATION_LANE_CHANGE && &enteredLane->getEdge() == &myLane->getEdge()) {
272  // keep the detector when changing while still on the exit detector but already on a new lane (#4803)
273 #ifdef DEBUG_E3_NOTIFY_LEAVE
274  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
275  std::cout << " remove reminder, keep in container\n";
276  }
277 #endif
278  return false;
279  }
280 #ifdef HAVE_FOX
281  ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
282 #endif
284  WRITE_WARNING("Vehicle '" + veh.getID() + "' teleported from " + toString(SUMO_TAG_E3DETECTOR) + " '" + myCollector.getID() + "'.");
285  myCollector.myEnteredContainer.erase(&veh);
286  return false;
287  }
288  if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
289  if (myCollector.myEnteredContainer.erase(&veh) > 0) {
290  WRITE_WARNING("Vehicle '" + veh.getID() + "' arrived inside " + toString(SUMO_TAG_E3DETECTOR) + " '" + myCollector.getID() + "'.");
291  }
292  return false;
293  }
294  return true;
295 }
296 
297 /* -------------------------------------------------------------------------
298  * MSE3Collector - definitions
299  * ----------------------------------------------------------------------- */
300 MSE3Collector::MSE3Collector(const std::string& id,
301  const CrossSectionVector& entries,
302  const CrossSectionVector& exits,
303  double haltingSpeedThreshold,
304  SUMOTime haltingTimeThreshold,
305  const std::string& vTypes,
306  int detectPersons,
307  bool openEntry) :
308  MSDetectorFileOutput(id, vTypes, detectPersons),
309  myEntries(entries),
310  myExits(exits),
311  myHaltingTimeThreshold(haltingTimeThreshold), myHaltingSpeedThreshold(haltingSpeedThreshold),
314  myLastResetTime(-1), myOpenEntry(openEntry) {
315  // Set MoveReminders to entries and exits
316  for (CrossSectionVectorConstIt crossSec1 = entries.begin(); crossSec1 != entries.end(); ++crossSec1) {
317  myEntryReminders.push_back(new MSE3EntryReminder(*crossSec1, *this));
318  }
319  for (CrossSectionVectorConstIt crossSec2 = exits.begin(); crossSec2 != exits.end(); ++crossSec2) {
320  myLeaveReminders.push_back(new MSE3LeaveReminder(*crossSec2, *this));
321  }
322  reset();
323 }
324 
325 
327  for (std::vector<MSE3EntryReminder*>::iterator i = myEntryReminders.begin(); i != myEntryReminders.end(); ++i) {
328  delete *i;
329  }
330  for (std::vector<MSE3LeaveReminder*>::iterator i = myLeaveReminders.begin(); i != myLeaveReminders.end(); ++i) {
331  delete *i;
332  }
333 }
334 
335 
336 void
338  myLeftContainer.clear();
339 }
340 
341 
342 
343 void
344 MSE3Collector::enter(const SUMOTrafficObject& veh, const double entryTimestep, const double fractionTimeOnDet, MSE3EntryReminder* entryReminder, bool isBackward) {
345  if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
346  const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
347  for (MSTransportable* p : v.getPersons()) {
348  enter(*p, entryTimestep, fractionTimeOnDet, entryReminder);
349  }
350  return;
351  }
352  if (!vehicleApplies(veh)) {
353  return;
354  }
355  if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
356  // walking backward over an entry detector means "leaving"
357  // std::cout << veh.getID() << " leave at entryDetector\n";
358  leave(veh, entryTimestep, fractionTimeOnDet, true);
359  return;
360  }
361  if (myEnteredContainer.find(&veh) != myEnteredContainer.end()) {
362  WRITE_WARNING("Vehicle '" + veh.getID() + "' reentered " + toString(SUMO_TAG_E3DETECTOR) + " '" + getID() + "'.");
363  return;
364  }
365 #ifdef DEBUG_E3_NOTIFY_ENTER
366  std::cout << veh.getID() << " enters\n";
367 #endif
368  const double speedFraction = veh.getSpeed() * fractionTimeOnDet;
369  E3Values v;
370  v.entryTime = entryTimestep;
371  v.frontLeaveTime = 0;
372  v.backLeaveTime = 0;
373  v.speedSum = speedFraction;
374  v.haltingBegin = veh.getSpeed() < myHaltingSpeedThreshold ? TIME2STEPS(entryTimestep) : -1;
375  v.intervalSpeedSum = entryTimestep >= STEPS2TIME(myLastResetTime) ? speedFraction : 0;
376  v.haltings = 0;
377  v.intervalHaltings = 0;
378  if (veh.getSpeed() < myHaltingSpeedThreshold) {
379  if (fractionTimeOnDet > myHaltingTimeThreshold) {
380  v.haltings++;
381  v.intervalHaltings++;
382  }
383  }
384  v.hadUpdate = false;
385  if (!MSGlobals::gUseMesoSim && veh.isVehicle()) {
386  v.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss();
388  }
389  v.entryReminder = entryReminder;
390  myEnteredContainer[&veh] = v;
391 }
392 
393 
394 void
395 MSE3Collector::leaveFront(const SUMOTrafficObject& veh, const double leaveTimestep) {
396  if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
397  const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
398  for (MSTransportable* p : v.getPersons()) {
399  leaveFront(*p, leaveTimestep);
400  }
401  return;
402  }
403  if (!vehicleApplies(veh)) {
404  return;
405  }
406  if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
407  if (!myOpenEntry && veh.isVehicle()) {
408  WRITE_WARNING("Vehicle '" + veh.getID() + "' left " + toString(SUMO_TAG_E3DETECTOR) + " '" + getID() + "' without entering it.");
409  }
410  } else {
411  myEnteredContainer[&veh].frontLeaveTime = leaveTimestep;
412  }
413 }
414 
415 
416 void
417 MSE3Collector::leave(const SUMOTrafficObject& veh, const double leaveTimestep, const double fractionTimeOnDet, bool isBackward) {
418  if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
419  const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
420  for (MSTransportable* p : v.getPersons()) {
421  leave(*p, leaveTimestep, fractionTimeOnDet);
422  }
423  return;
424  }
425  if (!vehicleApplies(veh)) {
426  return;
427  }
428  if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
429  // walking backward over an exit detector means "entering"
430  // std::cout << veh.getID() << " enter at exitDetector\n";
431  enter(veh, leaveTimestep, fractionTimeOnDet, nullptr, true);
432  return;
433  }
434  if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
435  if (!myOpenEntry && veh.isVehicle()) {
436  WRITE_WARNING("Vehicle '" + veh.getID() + "' left " + toString(SUMO_TAG_E3DETECTOR) + " '" + getID() + "' without entering it.");
437  }
438  } else {
439  E3Values values = myEnteredContainer[&veh];
440  values.backLeaveTime = leaveTimestep;
441  const double speedFraction = veh.getSpeed() * (TS - fractionTimeOnDet);
442  values.speedSum -= speedFraction;
443  values.intervalSpeedSum -= speedFraction;
444  if (MSGlobals::gUseMesoSim || !veh.isVehicle()) {
445  // not yet supported
446  values.timeLoss = 0;
447  if (isBackward) {
448  // leaveFront may not have been called
449  values.frontLeaveTime = leaveTimestep;
450  }
451  } else {
452  // timeLoss was initialized when entering
453  values.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss() - values.timeLoss;
454  }
455  myEnteredContainer.erase(&veh);
456  myLeftContainer.push_back(values);
457  }
458 }
459 
460 
461 void
463  SUMOTime startTime, SUMOTime stopTime) {
464  dev << " <interval begin=\"" << time2string(startTime) << "\" end=\"" << time2string(stopTime) << "\" " << "id=\"" << myID << "\" ";
465  // collect values about vehicles that have left the area
466  myLastVehicleSum = (int) myLeftContainer.size();
468  double meanOverlapTravelTime = 0.;
469  double meanSpeed = 0.;
471  myLastMeanTimeLoss = 0.;
472  for (const E3Values& values : myLeftContainer) {
473  myLastMeanHaltsPerVehicle += (double)values.haltings;
474  myLastMeanTravelTime += values.frontLeaveTime - values.entryTime;
475  const double steps = values.backLeaveTime - values.entryTime;
476  meanOverlapTravelTime += steps;
477  meanSpeed += (values.speedSum / steps);
478  myLastMeanTimeLoss += STEPS2TIME(values.timeLoss);
479  }
481  meanOverlapTravelTime = myLastVehicleSum != 0 ? meanOverlapTravelTime / (double)myLastVehicleSum : -1;
482  meanSpeed = myLastVehicleSum != 0 ? meanSpeed / (double)myLastVehicleSum : -1;
485  // clear container
486  myLeftContainer.clear();
487 
488  // collect values about vehicles within the container
489  const int vehicleSumWithin = (int) myEnteredContainer.size();
490  double meanSpeedWithin = 0.;
491  double meanDurationWithin = 0.;
492  double meanHaltsPerVehicleWithin = 0.;
493  double meanIntervalSpeedWithin = 0.;
494  double meanIntervalHaltsPerVehicleWithin = 0.;
495  double meanIntervalDurationWithin = 0.;
496  double meanTimeLossWithin = 0.;
497  for (std::map<const SUMOTrafficObject*, E3Values>::iterator i = myEnteredContainer.begin(); i != myEnteredContainer.end(); ++i) {
498  meanHaltsPerVehicleWithin += (double)(*i).second.haltings;
499  meanIntervalHaltsPerVehicleWithin += (double)(*i).second.intervalHaltings;
500  const double end = (*i).second.backLeaveTime == 0 ? STEPS2TIME(stopTime) : (*i).second.backLeaveTime;
501  const double time = end - (*i).second.entryTime;
502  const double timeWithin = MIN2(time, end - STEPS2TIME(startTime));
503  if (i->second.speedSum > 0.) {
504  meanSpeedWithin += i->second.speedSum / time;
505  }
506  if (i->second.intervalSpeedSum > 0.) {
507  meanIntervalSpeedWithin += i->second.intervalSpeedSum / timeWithin;
508  }
509  meanDurationWithin += time;
510  meanIntervalDurationWithin += timeWithin;
511  // reset interval values
512  (*i).second.intervalHaltings = 0;
513  (*i).second.intervalSpeedSum = 0;
514 
515  if (!MSGlobals::gUseMesoSim && i->first->isVehicle()) {
516  const SUMOTime currentTimeLoss = dynamic_cast<const MSVehicle*>(i->first)->getTimeLoss();
517  meanTimeLossWithin += STEPS2TIME(currentTimeLoss - (*i).second.intervalTimeLoss);
518  (*i).second.intervalTimeLoss = currentTimeLoss;
519  }
520  }
521  myLastResetTime = stopTime;
522  meanSpeedWithin = vehicleSumWithin != 0 ? meanSpeedWithin / (double) vehicleSumWithin : -1;
523  meanHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
524  meanDurationWithin = vehicleSumWithin != 0 ? meanDurationWithin / (double) vehicleSumWithin : -1;
525  meanIntervalSpeedWithin = vehicleSumWithin != 0 ? meanIntervalSpeedWithin / (double) vehicleSumWithin : -1;
526  meanIntervalHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanIntervalHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
527  meanIntervalDurationWithin = vehicleSumWithin != 0 ? meanIntervalDurationWithin / (double) vehicleSumWithin : -1;
528  meanTimeLossWithin = vehicleSumWithin != 0 ? meanTimeLossWithin / (double) vehicleSumWithin : -1;
529 
530  // write values
531  dev << "meanTravelTime=\"" << myLastMeanTravelTime
532  << "\" meanOverlapTravelTime=\"" << meanOverlapTravelTime
533  << "\" meanSpeed=\"" << meanSpeed
534  << "\" meanHaltsPerVehicle=\"" << myLastMeanHaltsPerVehicle
535  << "\" meanTimeLoss=\"" << myLastMeanTimeLoss
536  << "\" vehicleSum=\"" << myLastVehicleSum
537  << "\" meanSpeedWithin=\"" << meanSpeedWithin
538  << "\" meanHaltsPerVehicleWithin=\"" << meanHaltsPerVehicleWithin
539  << "\" meanDurationWithin=\"" << meanDurationWithin
540  << "\" vehicleSumWithin=\"" << vehicleSumWithin
541  << "\" meanIntervalSpeedWithin=\"" << meanIntervalSpeedWithin
542  << "\" meanIntervalHaltsPerVehicleWithin=\"" << meanIntervalHaltsPerVehicleWithin
543  << "\" meanIntervalDurationWithin=\"" << meanIntervalDurationWithin
544  << "\" meanTimeLossWithin=\"" << meanTimeLossWithin
545  << "\"/>\n";
546 }
547 
548 
549 void
551  dev.writeXMLHeader("e3Detector", "det_e3_file.xsd");
552 }
553 
554 
555 void
556 MSE3Collector::notifyMovePerson(MSTransportable* p, MSMoveReminder* rem, double detPos, int dir, double pos) {
557  if (personApplies(*p, dir)) {
558  const double newSpeed = p->getSpeed();
559  const double newPos = (dir == MSPModel::FORWARD
560  ? pos
561  // position relative to detector end position
562  : detPos - (pos - detPos));
563  const double oldPos = newPos - SPEED2DIST(newSpeed);
564  if (oldPos - p->getVehicleType().getLength() <= detPos) {
565  rem->notifyMove(*p, oldPos, newPos, newSpeed);
566  }
567  }
568 }
569 
570 
571 void
573 
574  if (myDetectPersons != (int)PersonMode::NONE) {
575  for (auto rem : myEntryReminders) {
576  const MSLane* lane = rem->getLane();
577  if (lane->hasPedestrians()) {
578  for (MSTransportable* p : lane->getEdge().getPersons()) {
579  if (p->getLane() == lane && vehicleApplies(*p)) {
580  notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
581  }
582  }
583  }
584  }
585  for (auto rem : myLeaveReminders) {
586  const MSLane* lane = rem->getLane();
587  if (lane->hasPedestrians()) {
588  for (MSTransportable* p : lane->getEdge().getPersons()) {
589  if (p->getLane() == lane && vehicleApplies(*p)) {
590  notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
591  }
592  }
593  }
594  }
595  }
596 
597  myCurrentMeanSpeed = 0;
599  for (std::map<const SUMOTrafficObject*, E3Values>::iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
600  const SUMOTrafficObject* veh = pair->first;
601 #ifdef DEBUG_E3_DETECTORUPDATE
602  //if (DEBUG_COND(*this) && DEBUG_COND_VEH(*veh)) {
603  if (DEBUG_COND(*this)) {
604  std::cout << SIMTIME << " vehPtr=" << veh << "\n";
605  std::cout << " veh=" << veh->getID() << "\n";
606  }
607 #endif
608  E3Values& values = pair->second;
609  myCurrentMeanSpeed += veh->getSpeed();
610  values.hadUpdate = true;
611  values.speedSum += veh->getSpeed() * TS;
612  values.intervalSpeedSum += veh->getSpeed() * TS;
613  if (veh->getSpeed() < myHaltingSpeedThreshold) {
614  if (values.haltingBegin == -1) {
615  values.haltingBegin = step;
616  }
617  SUMOTime haltingDuration = step - values.haltingBegin;
618  if (haltingDuration >= myHaltingTimeThreshold
619  && haltingDuration < (myHaltingTimeThreshold + DELTA_T)) {
620  values.haltings++;
621  values.intervalHaltings++;
623  }
624  } else {
625  values.haltingBegin = -1;
626  }
627  }
628  if (myEnteredContainer.size() == 0) {
629  myCurrentMeanSpeed = -1;
630  } else {
632  }
633 }
634 
635 
636 double
638  return myCurrentMeanSpeed;
639 }
640 
641 
642 int
645 }
646 
647 
648 int
650  return (int) myEnteredContainer.size();
651 }
652 
653 
654 std::vector<std::string>
656  std::vector<std::string> ret;
657  for (std::map<const SUMOTrafficObject*, E3Values>::const_iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
658  ret.push_back((*pair).first->getID());
659  }
660  std::sort(ret.begin(), ret.end());
661  return ret;
662 }
663 
664 void
666  myEnteredContainer.clear();
667 }
668 
669 /****************************************************************************/
CrossSectionVector::const_iterator CrossSectionVectorConstIt
std::vector< MSCrossSection > CrossSectionVector
#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
#define TIME2STEPS(x)
Definition: SUMOTime.h:55
long long int SUMOTime
Definition: SUMOTime.h:32
@ SUMO_TAG_E3DETECTOR
an e3 detector
T MIN2(T a, T b)
Definition: StdDefs.h:74
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 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
A simple description of a position on a lane (crossing of a lane)
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
A place on the road net (at a certain lane and position on it) where the E3 area begins.
Definition: MSE3Collector.h:65
bool notifyMove(SUMOTrafficObject &veh, double, double newPos, double)
Checks whether the vehicle enters.
MSE3EntryReminder(const MSCrossSection &crossSection, MSE3Collector &collector)
Constructor.
bool notifyLeave(SUMOTrafficObject &veh, double lastPos, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Processes state changes of a vehicle.
bool notifyEnter(SUMOTrafficObject &veh, Notification reason, const MSLane *enteredLane)
Checks whether the reminder is activated by a vehicle entering the lane.
A place on the road net (at a certain lane and position on it) where the E3 area ends.
MSE3LeaveReminder(const MSCrossSection &crossSection, MSE3Collector &collector)
Constructor.
bool notifyEnter(SUMOTrafficObject &veh, Notification reason, const MSLane *enteredLane)
Checks whether the reminder is activated by a vehicle entering the lane.
bool notifyMove(SUMOTrafficObject &veh, double oldPos, double newPos, double)
Checks whether the vehicle leaves.
bool notifyLeave(SUMOTrafficObject &veh, double lastPos, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Processes state changes of a vehicle.
A detector of vehicles passing an area between entry/exit points.
Definition: MSE3Collector.h:59
std::vector< E3Values > myLeftContainer
Container for vehicles that have left the area.
std::map< const SUMOTrafficObject *, E3Values > myEnteredContainer
Container for vehicles that have entered the area.
double myHaltingSpeedThreshold
Speed-threshold to determine if a vehicle is halting.
double myCurrentMeanSpeed
The current mean speed of known vehicles (inside)
virtual void clearState()
Remove all vehicles before quick-loading state.
void reset()
Resets all generated values to allow computation of next interval.
double myLastMeanTravelTime
CrossSectionVector myExits
The detector's exits.
void enter(const SUMOTrafficObject &veh, const double entryTimestep, const double fractionTimeOnDet, MSE3EntryReminder *entryReminder, bool isBackward=false)
Called if a vehicle touches an entry-cross-section.
int myCurrentHaltingsNumber
The current number of haltings (inside)
SUMOTime myLastResetTime
Information when the last reset has been done.
int getVehiclesWithin() const
Returns the number of vehicles within the area.
std::vector< MSE3EntryReminder * > myEntryReminders
The detector's built entry reminder.
const bool myOpenEntry
whether this dector is declared as having incomplete entry detectors
std::vector< MSE3LeaveReminder * > myLeaveReminders
The detector's built exit reminder.
double myLastMeanHaltsPerVehicle
double myLastMeanTimeLoss
void notifyMovePerson(MSTransportable *p, MSMoveReminder *rem, double detPos, int dir, double pos)
std::vector< std::string > getCurrentVehicleIDs() const
Returns the number of vehicles within the area.
virtual ~MSE3Collector()
Destructor.
void writeXMLDetectorProlog(OutputDevice &dev) const
Opens the XML-output using "e3Detector" as root element.
double getCurrentMeanSpeed() const
Returns the mean speed within the area.
int getCurrentHaltingNumber() const
Returns the number of current haltings within the area.
void detectorUpdate(const SUMOTime step)
Computes the detector values in each time step.
SUMOTime myHaltingTimeThreshold
MSE3Collector(const std::string &id, const CrossSectionVector &entries, const CrossSectionVector &exits, double haltingSpeedThreshold, SUMOTime haltingTimeThreshold, const std::string &vTypes, int detectPersons, bool openEntry)
Constructor.
CrossSectionVector myEntries
void writeXMLOutput(OutputDevice &dev, SUMOTime startTime, SUMOTime stopTime)
Writes collected values into the given stream.
void leave(const SUMOTrafficObject &veh, const double leaveTimestep, const double fractionTimeOnDet, bool isBackward=false)
Called if a vehicle back passes a leave-cross-section.
void leaveFront(const SUMOTrafficObject &veh, const double leaveTimestep)
Called if a vehicle front passes a leave-cross-section.
const std::set< MSTransportable * > & getPersons() const
Returns this edge's persons set.
Definition: MSEdge.h:198
static bool gUseMesoSim
Definition: MSGlobals.h:94
static bool gSemiImplicitEulerUpdate
Definition: MSGlobals.h:53
static int gNumSimThreads
how many threads to use for simulation
Definition: MSGlobals.h:133
Representation of a lane in the micro simulation.
Definition: MSLane.h:82
bool hasPedestrians() const
whether the lane has pedestrians on it
Definition: MSLane.cpp:3971
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:674
Something on a lane to be noticed about vehicle movement.
virtual bool notifyMove(SUMOTrafficObject &veh, double oldPos, double newPos, double newSpeed)
Checks whether the reminder still has to be notified about the vehicle moves.
Notification
Definition of a vehicle state.
@ NOTIFICATION_ARRIVED
The vehicle arrived at its destination (is deleted)
@ NOTIFICATION_LANE_CHANGE
The vehicle changes lanes (micro only)
@ NOTIFICATION_TELEPORT
The vehicle is being teleported.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:174
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.
virtual int getDirection() const
Return the movement directon on the edge.
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:75
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
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 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.
A scoped lock which only triggers on condition.
Definition: ScopedLocker.h:40
#define DEBUG_COND
Internal storage for values from a vehicle.
int intervalHaltings
The sum of haltings the vehicle has/had within the area during the current interval.
MSE3EntryReminder * entryReminder
the reminder on which the vehicle entered the detector
SUMOTime timeLoss
The timeLoss of the vehicle when entering. Updated to the actual time loss within the area when leavi...
double frontLeaveTime
The time the vehicle's front was crossing the leave line.
double entryTime
The vehicle's entry time.
SUMOTime intervalTimeLoss
The timeLoss of the vehicle when entering. Updated to the current timeLoss at interval write.
double speedSum
The sum of registered speeds the vehicle has/had inside the area.
bool hadUpdate
An internal information whether the update step was performed.
SUMOTime haltingBegin
Begin time of last halt begin.
double intervalSpeedSum
The sum of registered speeds the vehicle has/had inside the area during the current interval.
int haltings
The sum of haltings the vehicle has/had within the area.
double backLeaveTime
The time the vehicle's back was crossing the leave line.