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.dev/sumo
3 // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
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  if (!myCollector.myExpectArrival) {
161  WRITE_WARNINGF("Vehicle '%' arrived inside % '%'.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID());
162  }
163  }
164  return false;
165  }
166  return true;
167 }
168 
169 
170 /* -------------------------------------------------------------------------
171  * MSE3Collector::MSE3LeaveReminder - definitions
172  * ----------------------------------------------------------------------- */
174  const MSCrossSection& crossSection, MSE3Collector& collector) :
175  MSMoveReminder(collector.getID() + "_exit", crossSection.myLane),
176  myCollector(collector), myPosition(crossSection.myPosition) {}
177 
178 
179 bool
181 #ifdef DEBUG_E3_NOTIFY_ENTER
182  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
183  std::cout << SIMTIME
184  << " MSE3LeaveReminder::notifyEnter() (" << getDescription() << "on lane '" << myLane->getID() << "')"
185  << " vehicle '" << veh.getID() << "'"
186  << " enteredLane=" << enteredLane->getID()
187  << " reason=" << reason
188  << "\n";
189  }
190 #endif
191  // this method does not access containers, so no locking here
192  if (reason != NOTIFICATION_JUNCTION) {
193  const double backPosOnLane = veh.getBackPositionOnLane(enteredLane);
194  if (backPosOnLane > myPosition) {
195  // if the vehicle changes into a covered section we assume it was already registered on another lane
196  // however, if it is not fully past the detector we still need to track it
197 #ifdef DEBUG_E3_NOTIFY_ENTER
198  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
199  std::cout << " assume already known\n";
200  }
201 #endif
202  return false;
203  }
204  }
205  return true;
206 }
207 
208 
209 bool
211  double newPos, double newSpeed) {
212 #ifdef DEBUG_E3_NOTIFY_MOVE
213  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
214  std::cout << SIMTIME
215  << " MSE3LeaveReminder::notifyMove() (" << getDescription() << " on lane '" << myLane->getID() << "')"
216  << " vehicle '" << veh.getID() << "'"
217  << " entered. oldPos=" << oldPos << " newPos=" << newPos << " newSpeed=" << newSpeed
218  << " myPosition=" << myPosition
219  << "\n";
220  }
221 #endif
222  if (newPos < myPosition) {
223  // crossSection not yet reached
224  return true;
225  }
226 #ifdef HAVE_FOX
227  ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
228 #endif
229  const double oldSpeed = veh.getPreviousSpeed();
230  if (oldPos < myPosition) {
231  assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
232  const double timeBeforeLeave = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
233 // const double leaveTimeFront = SIMTIME - TS + (myPosition - oldPos) / newSpeed;
234  const double leaveTimeFront = SIMTIME - TS + timeBeforeLeave;
235  myCollector.leaveFront(veh, leaveTimeFront);
236 #ifdef DEBUG_E3_NOTIFY_MOVE
237  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
238  std::cout << " leaveFront\n";
239  }
240 #endif
241  }
242  const double backPos = newPos - veh.getVehicleType().getLength();
243  if (backPos < myPosition) {
244  // crossSection not yet left
245  return true;
246  }
247  // crossSection left
248  const double oldBackPos = oldPos - veh.getVehicleType().getLength();
249  const double leaveStep = SIMTIME;
250  assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
251  const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, backPos, oldSpeed, newSpeed);
252  myCollector.leave(veh, leaveStep - TS + timeBeforeLeave, timeBeforeLeave);
253 #ifdef DEBUG_E3_NOTIFY_MOVE
254  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
255  std::cout << " leave\n";
256  }
257 #endif
258  return false;
259 }
260 
261 
262 bool
264 #ifdef DEBUG_E3_NOTIFY_LEAVE
265  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
266  std::cout << SIMTIME
267  << " MSE3LeaveReminder::notifyLeave() (" << getDescription() << "on lane '" << myLane->getID() << "')"
268  << " vehicle '" << veh.getID() << "'"
269  << " reason=" << reason
270  << "\n";
271  }
272 #endif
273  if (reason == MSMoveReminder::NOTIFICATION_LANE_CHANGE && &enteredLane->getEdge() == &myLane->getEdge()) {
274  // keep the detector when changing while still on the exit detector but already on a new lane (#4803)
275 #ifdef DEBUG_E3_NOTIFY_LEAVE
276  if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
277  std::cout << " remove reminder, keep in container\n";
278  }
279 #endif
280  return false;
281  }
282 #ifdef HAVE_FOX
283  ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
284 #endif
286  WRITE_WARNINGF("Vehicle '%' teleported from % '%'.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID());
287  myCollector.myEnteredContainer.erase(&veh);
288  return false;
289  }
290  if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
291  if (myCollector.myEnteredContainer.erase(&veh) > 0) {
292  if (!myCollector.myExpectArrival) {
293  WRITE_WARNINGF("Vehicle '%' arrived inside % '%'.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID());
294  }
295  }
296  return false;
297  }
298  return true;
299 }
300 
301 /* -------------------------------------------------------------------------
302  * MSE3Collector - definitions
303  * ----------------------------------------------------------------------- */
304 MSE3Collector::MSE3Collector(const std::string& id,
305  const CrossSectionVector& entries,
306  const CrossSectionVector& exits,
307  double haltingSpeedThreshold,
308  SUMOTime haltingTimeThreshold,
309  const std::string name, const std::string& vTypes,
310  const std::string& nextEdges,
311  int detectPersons,
312  bool openEntry, bool expectArrival) :
313  MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
314  myName(name),
315  myEntries(entries),
316  myExits(exits),
317  myHaltingTimeThreshold(haltingTimeThreshold), myHaltingSpeedThreshold(haltingSpeedThreshold),
320  myLastResetTime(-1), myOpenEntry(openEntry), myExpectArrival(expectArrival) {
321  // Set MoveReminders to entries and exits
322  for (CrossSectionVectorConstIt crossSec1 = entries.begin(); crossSec1 != entries.end(); ++crossSec1) {
323  myEntryReminders.push_back(new MSE3EntryReminder(*crossSec1, *this));
324  }
325  for (CrossSectionVectorConstIt crossSec2 = exits.begin(); crossSec2 != exits.end(); ++crossSec2) {
326  myLeaveReminders.push_back(new MSE3LeaveReminder(*crossSec2, *this));
327  }
328  reset();
329 }
330 
331 
333  for (std::vector<MSE3EntryReminder*>::iterator i = myEntryReminders.begin(); i != myEntryReminders.end(); ++i) {
334  delete *i;
335  }
336  for (std::vector<MSE3LeaveReminder*>::iterator i = myLeaveReminders.begin(); i != myLeaveReminders.end(); ++i) {
337  delete *i;
338  }
339 }
340 
341 
342 void
344  myLeftContainer.clear();
345 }
346 
347 
348 
349 void
350 MSE3Collector::enter(const SUMOTrafficObject& veh, const double entryTimestep, const double fractionTimeOnDet, MSE3EntryReminder* entryReminder, bool isBackward) {
351  if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
352  const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
353  for (MSTransportable* p : v.getPersons()) {
354  enter(*p, entryTimestep, fractionTimeOnDet, entryReminder);
355  }
356  return;
357  }
358  if (!vehicleApplies(veh)) {
359  return;
360  }
361  if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
362  // walking backward over an entry detector means "leaving"
363  // std::cout << veh.getID() << " leave at entryDetector\n";
364  leave(veh, entryTimestep, fractionTimeOnDet, true);
365  return;
366  }
367  if (myEnteredContainer.find(&veh) != myEnteredContainer.end()) {
368  WRITE_WARNINGF("Vehicle '%' reentered % '%'.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID());
369  return;
370  }
371 #ifdef DEBUG_E3_NOTIFY_ENTER
372  std::cout << veh.getID() << " enters\n";
373 #endif
374  const double speedFraction = veh.getSpeed() * fractionTimeOnDet;
375  E3Values v;
376  v.entryTime = entryTimestep;
377  v.frontLeaveTime = 0;
378  v.backLeaveTime = 0;
379  v.speedSum = speedFraction;
380  v.haltingBegin = veh.getSpeed() < myHaltingSpeedThreshold ? TIME2STEPS(entryTimestep) : -1;
381  v.intervalSpeedSum = entryTimestep >= STEPS2TIME(myLastResetTime) ? speedFraction : 0;
382  v.haltings = 0;
383  v.intervalHaltings = 0;
384  if (veh.getSpeed() < myHaltingSpeedThreshold) {
385  if (TIME2STEPS(fractionTimeOnDet) > myHaltingTimeThreshold) {
386  v.haltings++;
387  v.intervalHaltings++;
388  }
389  }
390  v.hadUpdate = false;
391  if (!MSGlobals::gUseMesoSim && veh.isVehicle()) {
392  v.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss();
394  }
395  v.entryReminder = entryReminder;
396  myEnteredContainer[&veh] = v;
397 }
398 
399 
400 void
401 MSE3Collector::leaveFront(const SUMOTrafficObject& veh, const double leaveTimestep) {
402  if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
403  const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
404  for (MSTransportable* p : v.getPersons()) {
405  leaveFront(*p, leaveTimestep);
406  }
407  return;
408  }
409  if (!vehicleApplies(veh)) {
410  return;
411  }
412  if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
413  if (!myOpenEntry && veh.isVehicle()) {
414  WRITE_WARNINGF("Vehicle '%' left % '%' without entering it.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID());
415  }
416  } else {
417  myEnteredContainer[&veh].frontLeaveTime = leaveTimestep;
418  }
419 }
420 
421 
422 void
423 MSE3Collector::leave(const SUMOTrafficObject& veh, const double leaveTimestep, const double fractionTimeOnDet, bool isBackward) {
424  if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
425  const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
426  for (MSTransportable* p : v.getPersons()) {
427  leave(*p, leaveTimestep, fractionTimeOnDet);
428  }
429  return;
430  }
431  if (!vehicleApplies(veh)) {
432  return;
433  }
434  if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
435  // walking backward over an exit detector means "entering"
436  // std::cout << veh.getID() << " enter at exitDetector\n";
437  enter(veh, leaveTimestep, fractionTimeOnDet, nullptr, true);
438  return;
439  }
440  if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
441  if (!myOpenEntry && veh.isVehicle()) {
442  WRITE_WARNINGF("Vehicle '%' left % '%' without entering it.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID());
443  }
444  } else {
445 #ifdef DEBUG_E3_NOTIFY_LEAVE
446  std::cout << veh.getID() << " leaves\n";
447 #endif
448  E3Values values = myEnteredContainer[&veh];
449  values.backLeaveTime = leaveTimestep;
450  const double speedFraction = veh.getSpeed() * (TS - fractionTimeOnDet);
451  values.speedSum -= speedFraction;
452  values.intervalSpeedSum -= speedFraction;
453  if (MSGlobals::gUseMesoSim || !veh.isVehicle()) {
454  // not yet supported
455  values.timeLoss = 0;
456  if (isBackward) {
457  // leaveFront may not have been called
458  values.frontLeaveTime = leaveTimestep;
459  }
460  } else {
461  // timeLoss was initialized when entering
462  values.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss() - values.timeLoss;
463  }
464  myEnteredContainer.erase(&veh);
465  myLeftContainer.push_back(values);
466  }
467 }
468 
469 
470 void
472  SUMOTime startTime, SUMOTime stopTime) {
473  dev << " <interval begin=\"" << time2string(startTime) << "\" end=\"" << time2string(stopTime) << "\" " << "id=\"" << myID << "\" ";
474  // collect values about vehicles that have left the area
475  myLastVehicleSum = (int) myLeftContainer.size();
477  double meanOverlapTravelTime = 0.;
478  double meanSpeed = 0.;
480  myLastMeanTimeLoss = 0.;
481  for (const E3Values& values : myLeftContainer) {
482  myLastMeanHaltsPerVehicle += (double)values.haltings;
483  myLastMeanTravelTime += values.frontLeaveTime - values.entryTime;
484  const double steps = values.backLeaveTime - values.entryTime;
485  meanOverlapTravelTime += steps;
486  meanSpeed += (values.speedSum / steps);
487  myLastMeanTimeLoss += STEPS2TIME(values.timeLoss);
488  }
490  meanOverlapTravelTime = myLastVehicleSum != 0 ? meanOverlapTravelTime / (double)myLastVehicleSum : -1;
491  meanSpeed = myLastVehicleSum != 0 ? meanSpeed / (double)myLastVehicleSum : -1;
494  // clear container
495  myLeftContainer.clear();
496 
497  // collect values about vehicles within the container
498  const int vehicleSumWithin = (int) myEnteredContainer.size();
499  double meanSpeedWithin = 0.;
500  double meanDurationWithin = 0.;
501  double meanHaltsPerVehicleWithin = 0.;
502  double meanIntervalSpeedWithin = 0.;
503  double meanIntervalHaltsPerVehicleWithin = 0.;
504  double meanIntervalDurationWithin = 0.;
505  double meanTimeLossWithin = 0.;
506  for (std::map<const SUMOTrafficObject*, E3Values>::iterator i = myEnteredContainer.begin(); i != myEnteredContainer.end(); ++i) {
507  meanHaltsPerVehicleWithin += (double)(*i).second.haltings;
508  meanIntervalHaltsPerVehicleWithin += (double)(*i).second.intervalHaltings;
509  const double end = (*i).second.backLeaveTime == 0 ? STEPS2TIME(stopTime) : (*i).second.backLeaveTime;
510  const double time = end - (*i).second.entryTime;
511  const double timeWithin = MIN2(time, end - STEPS2TIME(startTime));
512  if (i->second.speedSum > 0.) {
513  meanSpeedWithin += i->second.speedSum / time;
514  }
515  if (i->second.intervalSpeedSum > 0.) {
516  meanIntervalSpeedWithin += i->second.intervalSpeedSum / timeWithin;
517  }
518  meanDurationWithin += time;
519  meanIntervalDurationWithin += timeWithin;
520  // reset interval values
521  (*i).second.intervalHaltings = 0;
522  (*i).second.intervalSpeedSum = 0;
523 
524  if (!MSGlobals::gUseMesoSim && i->first->isVehicle()) {
525  const SUMOTime currentTimeLoss = dynamic_cast<const MSVehicle*>(i->first)->getTimeLoss();
526  meanTimeLossWithin += STEPS2TIME(currentTimeLoss - (*i).second.intervalTimeLoss);
527  (*i).second.intervalTimeLoss = currentTimeLoss;
528  }
529  }
530  myLastResetTime = stopTime;
531  meanSpeedWithin = vehicleSumWithin != 0 ? meanSpeedWithin / (double) vehicleSumWithin : -1;
532  meanHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
533  meanDurationWithin = vehicleSumWithin != 0 ? meanDurationWithin / (double) vehicleSumWithin : -1;
534  meanIntervalSpeedWithin = vehicleSumWithin != 0 ? meanIntervalSpeedWithin / (double) vehicleSumWithin : -1;
535  meanIntervalHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanIntervalHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
536  meanIntervalDurationWithin = vehicleSumWithin != 0 ? meanIntervalDurationWithin / (double) vehicleSumWithin : -1;
537  meanTimeLossWithin = vehicleSumWithin != 0 ? meanTimeLossWithin / (double) vehicleSumWithin : -1;
538 
539  // write values
540  dev << "meanTravelTime=\"" << myLastMeanTravelTime
541  << "\" meanOverlapTravelTime=\"" << meanOverlapTravelTime
542  << "\" meanSpeed=\"" << meanSpeed
543  << "\" meanHaltsPerVehicle=\"" << myLastMeanHaltsPerVehicle
544  << "\" meanTimeLoss=\"" << myLastMeanTimeLoss
545  << "\" vehicleSum=\"" << myLastVehicleSum
546  << "\" meanSpeedWithin=\"" << meanSpeedWithin
547  << "\" meanHaltsPerVehicleWithin=\"" << meanHaltsPerVehicleWithin
548  << "\" meanDurationWithin=\"" << meanDurationWithin
549  << "\" vehicleSumWithin=\"" << vehicleSumWithin
550  << "\" meanIntervalSpeedWithin=\"" << meanIntervalSpeedWithin
551  << "\" meanIntervalHaltsPerVehicleWithin=\"" << meanIntervalHaltsPerVehicleWithin
552  << "\" meanIntervalDurationWithin=\"" << meanIntervalDurationWithin
553  << "\" meanTimeLossWithin=\"" << meanTimeLossWithin
554  << "\"/>\n";
555 }
556 
557 
558 void
560  dev.writeXMLHeader("e3Detector", "det_e3_file.xsd");
561 }
562 
563 
564 void
565 MSE3Collector::notifyMovePerson(MSTransportable* p, MSMoveReminder* rem, double detPos, int dir, double pos) {
566  if (personApplies(*p, dir)) {
567  const double newSpeed = p->getSpeed();
568  const double newPos = (dir == MSPModel::FORWARD
569  ? pos
570  // position relative to detector end position
571  : detPos - (pos - detPos));
572  const double oldPos = newPos - SPEED2DIST(newSpeed);
573  if (oldPos - p->getVehicleType().getLength() <= detPos) {
574  rem->notifyMove(*p, oldPos, newPos, newSpeed);
575  }
576  }
577 }
578 
579 
580 void
582 
583  if (myDetectPersons != (int)PersonMode::NONE) {
584  for (auto rem : myEntryReminders) {
585  const MSLane* lane = rem->getLane();
586  if (lane->hasPedestrians()) {
587  for (MSTransportable* p : lane->getEdge().getPersons()) {
588  if (p->getLane() == lane && vehicleApplies(*p)) {
589  notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
590  }
591  }
592  }
593  }
594  for (auto rem : myLeaveReminders) {
595  const MSLane* lane = rem->getLane();
596  if (lane->hasPedestrians()) {
597  for (MSTransportable* p : lane->getEdge().getPersons()) {
598  if (p->getLane() == lane && vehicleApplies(*p)) {
599  notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
600  }
601  }
602  }
603  }
604  }
605 
606  myCurrentMeanSpeed = 0;
608  for (std::map<const SUMOTrafficObject*, E3Values>::iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
609  const SUMOTrafficObject* veh = pair->first;
610 #ifdef DEBUG_E3_DETECTORUPDATE
611  //if (DEBUG_COND(*this) && DEBUG_COND_VEH(*veh)) {
612  if (DEBUG_COND(*this)) {
613  std::cout << SIMTIME << " vehPtr=" << veh << "\n";
614  std::cout << " veh=" << veh->getID() << "\n";
615  }
616 #endif
617  E3Values& values = pair->second;
618  myCurrentMeanSpeed += veh->getSpeed();
619  values.hadUpdate = true;
620  values.speedSum += veh->getSpeed() * TS;
621  values.intervalSpeedSum += veh->getSpeed() * TS;
622  if (veh->getSpeed() < myHaltingSpeedThreshold) {
623  if (values.haltingBegin == -1) {
624  values.haltingBegin = step;
625  }
626  SUMOTime haltingDuration = step - values.haltingBegin;
627  if (haltingDuration >= myHaltingTimeThreshold
628  && haltingDuration < (myHaltingTimeThreshold + DELTA_T)) {
629  values.haltings++;
630  values.intervalHaltings++;
632  }
633  } else {
634  values.haltingBegin = -1;
635  }
636  }
637  if (myEnteredContainer.size() == 0) {
638  myCurrentMeanSpeed = -1;
639  } else {
640  myCurrentMeanSpeed /= (double)myEnteredContainer.size();
641  }
642 }
643 
644 
645 const CrossSectionVector&
647  return myEntries;
648 }
649 
650 
651 const CrossSectionVector&
653  return myExits;
654 }
655 
656 
657 double
659  return myCurrentMeanSpeed;
660 }
661 
662 
663 int
666 }
667 
668 
669 int
671  return (int) myEnteredContainer.size();
672 }
673 
674 
675 std::vector<std::string>
677  std::vector<std::string> ret;
678  for (std::map<const SUMOTrafficObject*, E3Values>::const_iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
679  ret.push_back((*pair).first->getID());
680  }
681  std::sort(ret.begin(), ret.end());
682  return ret;
683 }
684 
685 void
687  myEnteredContainer.clear();
688  myLeftContainer.clear();
689 }
690 
691 /****************************************************************************/
long long int SUMOTime
Definition: GUI.h:35
CrossSectionVector::const_iterator CrossSectionVectorConstIt
std::vector< MSCrossSection > CrossSectionVector
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
SUMOTime DELTA_T
Definition: SUMOTime.cpp:38
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition: SUMOTime.cpp:69
#define STEPS2TIME(x)
Definition: SUMOTime.h:55
#define SPEED2DIST(x)
Definition: SUMOTime.h:45
#define TS
Definition: SUMOTime.h:42
#define SIMTIME
Definition: SUMOTime.h:62
#define TIME2STEPS(x)
Definition: SUMOTime.h:57
@ SUMO_TAG_E3DETECTOR
an e3 detector
T MIN2(T a, T b)
Definition: StdDefs.h:76
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
The base class for microscopic and mesoscopic vehicles.
Definition: MSBaseVehicle.h:55
const std::vector< MSTransportable * > & getPersons() const
retrieve riding persons
static double passingTime(const double lastPos, const double passedPos, const double currentPos, const double lastSpeed, const double currentSpeed)
Calculates the time at which the position passedPosition has been passed In case of a ballistic updat...
Definition: MSCFModel.cpp:658
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.
const CrossSectionVector & getEntries() const
Returns the entry cross sections.
virtual void clearState(SUMOTime step)
Remove all vehicles before quick-loading state.
double myCurrentMeanSpeed
The current mean speed of known vehicles (inside)
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
const CrossSectionVector & getExits() const
Returns the exit cross sections.
double myLastMeanTimeLoss
void notifyMovePerson(MSTransportable *p, MSMoveReminder *rem, double detPos, int dir, double pos)
std::string myName
name
std::vector< std::string > getCurrentVehicleIDs() const
Returns the number of vehicles within the area.
const bool myExpectArrival
Whether the detector expects vehicles to arrive inside (and doesn't issue a warning in this case)
virtual ~MSE3Collector()
Destructor.
MSE3Collector(const std::string &id, const CrossSectionVector &entries, const CrossSectionVector &exits, double haltingSpeedThreshold, SUMOTime haltingTimeThreshold, const std::string name, const std::string &vTypes, const std::string &nextEdges, int detectPersons, bool openEntry, bool expectArrival)
Constructor.
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
CrossSectionVector myEntries
The detector's entrys.
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 *, ComparatorNumericalIdLess > & getPersons() const
Returns this edge's persons set.
Definition: MSEdge.h:201
static bool gUseMesoSim
Definition: MSGlobals.h:103
static bool gSemiImplicitEulerUpdate
Definition: MSGlobals.h:53
static int gNumSimThreads
how many threads to use for simulation
Definition: MSGlobals.h:143
Representation of a lane in the micro simulation.
Definition: MSLane.h:84
bool hasPedestrians() const
whether the lane has pedestrians on it
Definition: MSLane.cpp:4413
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:752
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:182
static const int FORWARD
Definition: MSPModel.h:119
virtual double getSpeed() const
the current speed of the transportable
const MSVehicleType & getVehicleType() const
Returns the object's "vehicle" type.
virtual int getDirection() const
Return the movement directon on the edge.
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:77
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.