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
63bool
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
98bool
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
144bool
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
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
177bool
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
207bool
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
260bool
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 }
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 * ----------------------------------------------------------------------- */
300MSE3Collector::MSE3Collector(const std::string& id,
301 const CrossSectionVector& entries,
302 const CrossSectionVector& exits,
303 double haltingSpeedThreshold,
304 SUMOTime haltingTimeThreshold,
305 const std::string name, const std::string& vTypes,
306 const std::string& nextEdges,
307 int detectPersons,
308 bool openEntry) :
309 MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
310 myName(name),
311 myEntries(entries),
312 myExits(exits),
313 myHaltingTimeThreshold(haltingTimeThreshold), myHaltingSpeedThreshold(haltingSpeedThreshold),
316 myLastResetTime(-1), myOpenEntry(openEntry) {
317 // Set MoveReminders to entries and exits
318 for (CrossSectionVectorConstIt crossSec1 = entries.begin(); crossSec1 != entries.end(); ++crossSec1) {
319 myEntryReminders.push_back(new MSE3EntryReminder(*crossSec1, *this));
320 }
321 for (CrossSectionVectorConstIt crossSec2 = exits.begin(); crossSec2 != exits.end(); ++crossSec2) {
322 myLeaveReminders.push_back(new MSE3LeaveReminder(*crossSec2, *this));
323 }
324 reset();
325}
326
327
329 for (std::vector<MSE3EntryReminder*>::iterator i = myEntryReminders.begin(); i != myEntryReminders.end(); ++i) {
330 delete *i;
331 }
332 for (std::vector<MSE3LeaveReminder*>::iterator i = myLeaveReminders.begin(); i != myLeaveReminders.end(); ++i) {
333 delete *i;
334 }
335}
336
337
338void
340 myLeftContainer.clear();
341}
342
343
344
345void
346MSE3Collector::enter(const SUMOTrafficObject& veh, const double entryTimestep, const double fractionTimeOnDet, MSE3EntryReminder* entryReminder, bool isBackward) {
347 if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
348 const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
349 for (MSTransportable* p : v.getPersons()) {
350 enter(*p, entryTimestep, fractionTimeOnDet, entryReminder);
351 }
352 return;
353 }
354 if (!vehicleApplies(veh)) {
355 return;
356 }
357 if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
358 // walking backward over an entry detector means "leaving"
359 // std::cout << veh.getID() << " leave at entryDetector\n";
360 leave(veh, entryTimestep, fractionTimeOnDet, true);
361 return;
362 }
363 if (myEnteredContainer.find(&veh) != myEnteredContainer.end()) {
364 WRITE_WARNING("Vehicle '" + veh.getID() + "' reentered " + toString(SUMO_TAG_E3DETECTOR) + " '" + getID() + "'.");
365 return;
366 }
367#ifdef DEBUG_E3_NOTIFY_ENTER
368 std::cout << veh.getID() << " enters\n";
369#endif
370 const double speedFraction = veh.getSpeed() * fractionTimeOnDet;
371 E3Values v;
372 v.entryTime = entryTimestep;
373 v.frontLeaveTime = 0;
374 v.backLeaveTime = 0;
375 v.speedSum = speedFraction;
376 v.haltingBegin = veh.getSpeed() < myHaltingSpeedThreshold ? TIME2STEPS(entryTimestep) : -1;
377 v.intervalSpeedSum = entryTimestep >= STEPS2TIME(myLastResetTime) ? speedFraction : 0;
378 v.haltings = 0;
379 v.intervalHaltings = 0;
380 if (veh.getSpeed() < myHaltingSpeedThreshold) {
381 if (TIME2STEPS(fractionTimeOnDet) > myHaltingTimeThreshold) {
382 v.haltings++;
384 }
385 }
386 v.hadUpdate = false;
387 if (!MSGlobals::gUseMesoSim && veh.isVehicle()) {
388 v.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss();
390 }
391 v.entryReminder = entryReminder;
392 myEnteredContainer[&veh] = v;
393}
394
395
396void
397MSE3Collector::leaveFront(const SUMOTrafficObject& veh, const double leaveTimestep) {
398 if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
399 const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
400 for (MSTransportable* p : v.getPersons()) {
401 leaveFront(*p, leaveTimestep);
402 }
403 return;
404 }
405 if (!vehicleApplies(veh)) {
406 return;
407 }
408 if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
409 if (!myOpenEntry && veh.isVehicle()) {
410 WRITE_WARNING("Vehicle '" + veh.getID() + "' left " + toString(SUMO_TAG_E3DETECTOR) + " '" + getID() + "' without entering it.");
411 }
412 } else {
413 myEnteredContainer[&veh].frontLeaveTime = leaveTimestep;
414 }
415}
416
417
418void
419MSE3Collector::leave(const SUMOTrafficObject& veh, const double leaveTimestep, const double fractionTimeOnDet, bool isBackward) {
420 if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
421 const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
422 for (MSTransportable* p : v.getPersons()) {
423 leave(*p, leaveTimestep, fractionTimeOnDet);
424 }
425 return;
426 }
427 if (!vehicleApplies(veh)) {
428 return;
429 }
430 if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
431 // walking backward over an exit detector means "entering"
432 // std::cout << veh.getID() << " enter at exitDetector\n";
433 enter(veh, leaveTimestep, fractionTimeOnDet, nullptr, true);
434 return;
435 }
436 if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
437 if (!myOpenEntry && veh.isVehicle()) {
438 WRITE_WARNING("Vehicle '" + veh.getID() + "' left " + toString(SUMO_TAG_E3DETECTOR) + " '" + getID() + "' without entering it.");
439 }
440 } else {
441 E3Values values = myEnteredContainer[&veh];
442 values.backLeaveTime = leaveTimestep;
443 const double speedFraction = veh.getSpeed() * (TS - fractionTimeOnDet);
444 values.speedSum -= speedFraction;
445 values.intervalSpeedSum -= speedFraction;
446 if (MSGlobals::gUseMesoSim || !veh.isVehicle()) {
447 // not yet supported
448 values.timeLoss = 0;
449 if (isBackward) {
450 // leaveFront may not have been called
451 values.frontLeaveTime = leaveTimestep;
452 }
453 } else {
454 // timeLoss was initialized when entering
455 values.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss() - values.timeLoss;
456 }
457 myEnteredContainer.erase(&veh);
458 myLeftContainer.push_back(values);
459 }
460}
461
462
463void
465 SUMOTime startTime, SUMOTime stopTime) {
466 dev << " <interval begin=\"" << time2string(startTime) << "\" end=\"" << time2string(stopTime) << "\" " << "id=\"" << myID << "\" ";
467 // collect values about vehicles that have left the area
468 myLastVehicleSum = (int) myLeftContainer.size();
470 double meanOverlapTravelTime = 0.;
471 double meanSpeed = 0.;
474 for (const E3Values& values : myLeftContainer) {
475 myLastMeanHaltsPerVehicle += (double)values.haltings;
476 myLastMeanTravelTime += values.frontLeaveTime - values.entryTime;
477 const double steps = values.backLeaveTime - values.entryTime;
478 meanOverlapTravelTime += steps;
479 meanSpeed += (values.speedSum / steps);
480 myLastMeanTimeLoss += STEPS2TIME(values.timeLoss);
481 }
483 meanOverlapTravelTime = myLastVehicleSum != 0 ? meanOverlapTravelTime / (double)myLastVehicleSum : -1;
484 meanSpeed = myLastVehicleSum != 0 ? meanSpeed / (double)myLastVehicleSum : -1;
487 // clear container
488 myLeftContainer.clear();
489
490 // collect values about vehicles within the container
491 const int vehicleSumWithin = (int) myEnteredContainer.size();
492 double meanSpeedWithin = 0.;
493 double meanDurationWithin = 0.;
494 double meanHaltsPerVehicleWithin = 0.;
495 double meanIntervalSpeedWithin = 0.;
496 double meanIntervalHaltsPerVehicleWithin = 0.;
497 double meanIntervalDurationWithin = 0.;
498 double meanTimeLossWithin = 0.;
499 for (std::map<const SUMOTrafficObject*, E3Values>::iterator i = myEnteredContainer.begin(); i != myEnteredContainer.end(); ++i) {
500 meanHaltsPerVehicleWithin += (double)(*i).second.haltings;
501 meanIntervalHaltsPerVehicleWithin += (double)(*i).second.intervalHaltings;
502 const double end = (*i).second.backLeaveTime == 0 ? STEPS2TIME(stopTime) : (*i).second.backLeaveTime;
503 const double time = end - (*i).second.entryTime;
504 const double timeWithin = MIN2(time, end - STEPS2TIME(startTime));
505 if (i->second.speedSum > 0.) {
506 meanSpeedWithin += i->second.speedSum / time;
507 }
508 if (i->second.intervalSpeedSum > 0.) {
509 meanIntervalSpeedWithin += i->second.intervalSpeedSum / timeWithin;
510 }
511 meanDurationWithin += time;
512 meanIntervalDurationWithin += timeWithin;
513 // reset interval values
514 (*i).second.intervalHaltings = 0;
515 (*i).second.intervalSpeedSum = 0;
516
517 if (!MSGlobals::gUseMesoSim && i->first->isVehicle()) {
518 const SUMOTime currentTimeLoss = dynamic_cast<const MSVehicle*>(i->first)->getTimeLoss();
519 meanTimeLossWithin += STEPS2TIME(currentTimeLoss - (*i).second.intervalTimeLoss);
520 (*i).second.intervalTimeLoss = currentTimeLoss;
521 }
522 }
523 myLastResetTime = stopTime;
524 meanSpeedWithin = vehicleSumWithin != 0 ? meanSpeedWithin / (double) vehicleSumWithin : -1;
525 meanHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
526 meanDurationWithin = vehicleSumWithin != 0 ? meanDurationWithin / (double) vehicleSumWithin : -1;
527 meanIntervalSpeedWithin = vehicleSumWithin != 0 ? meanIntervalSpeedWithin / (double) vehicleSumWithin : -1;
528 meanIntervalHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanIntervalHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
529 meanIntervalDurationWithin = vehicleSumWithin != 0 ? meanIntervalDurationWithin / (double) vehicleSumWithin : -1;
530 meanTimeLossWithin = vehicleSumWithin != 0 ? meanTimeLossWithin / (double) vehicleSumWithin : -1;
531
532 // write values
533 dev << "meanTravelTime=\"" << myLastMeanTravelTime
534 << "\" meanOverlapTravelTime=\"" << meanOverlapTravelTime
535 << "\" meanSpeed=\"" << meanSpeed
536 << "\" meanHaltsPerVehicle=\"" << myLastMeanHaltsPerVehicle
537 << "\" meanTimeLoss=\"" << myLastMeanTimeLoss
538 << "\" vehicleSum=\"" << myLastVehicleSum
539 << "\" meanSpeedWithin=\"" << meanSpeedWithin
540 << "\" meanHaltsPerVehicleWithin=\"" << meanHaltsPerVehicleWithin
541 << "\" meanDurationWithin=\"" << meanDurationWithin
542 << "\" vehicleSumWithin=\"" << vehicleSumWithin
543 << "\" meanIntervalSpeedWithin=\"" << meanIntervalSpeedWithin
544 << "\" meanIntervalHaltsPerVehicleWithin=\"" << meanIntervalHaltsPerVehicleWithin
545 << "\" meanIntervalDurationWithin=\"" << meanIntervalDurationWithin
546 << "\" meanTimeLossWithin=\"" << meanTimeLossWithin
547 << "\"/>\n";
548}
549
550
551void
553 dev.writeXMLHeader("e3Detector", "det_e3_file.xsd");
554}
555
556
557void
558MSE3Collector::notifyMovePerson(MSTransportable* p, MSMoveReminder* rem, double detPos, int dir, double pos) {
559 if (personApplies(*p, dir)) {
560 const double newSpeed = p->getSpeed();
561 const double newPos = (dir == MSPModel::FORWARD
562 ? pos
563 // position relative to detector end position
564 : detPos - (pos - detPos));
565 const double oldPos = newPos - SPEED2DIST(newSpeed);
566 if (oldPos - p->getVehicleType().getLength() <= detPos) {
567 rem->notifyMove(*p, oldPos, newPos, newSpeed);
568 }
569 }
570}
571
572
573void
575
576 if (myDetectPersons != (int)PersonMode::NONE) {
577 for (auto rem : myEntryReminders) {
578 const MSLane* lane = rem->getLane();
579 if (lane->hasPedestrians()) {
580 for (MSTransportable* p : lane->getEdge().getPersons()) {
581 if (p->getLane() == lane && vehicleApplies(*p)) {
582 notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
583 }
584 }
585 }
586 }
587 for (auto rem : myLeaveReminders) {
588 const MSLane* lane = rem->getLane();
589 if (lane->hasPedestrians()) {
590 for (MSTransportable* p : lane->getEdge().getPersons()) {
591 if (p->getLane() == lane && vehicleApplies(*p)) {
592 notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
593 }
594 }
595 }
596 }
597 }
598
601 for (std::map<const SUMOTrafficObject*, E3Values>::iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
602 const SUMOTrafficObject* veh = pair->first;
603#ifdef DEBUG_E3_DETECTORUPDATE
604 //if (DEBUG_COND(*this) && DEBUG_COND_VEH(*veh)) {
605 if (DEBUG_COND(*this)) {
606 std::cout << SIMTIME << " vehPtr=" << veh << "\n";
607 std::cout << " veh=" << veh->getID() << "\n";
608 }
609#endif
610 E3Values& values = pair->second;
612 values.hadUpdate = true;
613 values.speedSum += veh->getSpeed() * TS;
614 values.intervalSpeedSum += veh->getSpeed() * TS;
615 if (veh->getSpeed() < myHaltingSpeedThreshold) {
616 if (values.haltingBegin == -1) {
617 values.haltingBegin = step;
618 }
619 SUMOTime haltingDuration = step - values.haltingBegin;
620 if (haltingDuration >= myHaltingTimeThreshold
621 && haltingDuration < (myHaltingTimeThreshold + DELTA_T)) {
622 values.haltings++;
623 values.intervalHaltings++;
625 }
626 } else {
627 values.haltingBegin = -1;
628 }
629 }
630 if (myEnteredContainer.size() == 0) {
632 } else {
633 myCurrentMeanSpeed /= (double)myEnteredContainer.size();
634 }
635}
636
637
640 return myEntries;
641}
642
643
646 return myExits;
647}
648
649
650double
652 return myCurrentMeanSpeed;
653}
654
655
656int
659}
660
661
662int
664 return (int) myEnteredContainer.size();
665}
666
667
668std::vector<std::string>
670 std::vector<std::string> ret;
671 for (std::map<const SUMOTrafficObject*, E3Values>::const_iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
672 ret.push_back((*pair).first->getID());
673 }
674 std::sort(ret.begin(), ret.end());
675 return ret;
676}
677
678void
680 myEnteredContainer.clear();
681}
682
683/****************************************************************************/
long long int SUMOTime
Definition: GUI.h:36
CrossSectionVector::const_iterator CrossSectionVectorConstIt
std::vector< MSCrossSection > CrossSectionVector
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:265
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:54
#define SPEED2DIST(x)
Definition: SUMOTime.h:44
#define TS
Definition: SUMOTime.h:41
#define SIMTIME
Definition: SUMOTime.h:61
#define TIME2STEPS(x)
Definition: SUMOTime.h:56
@ SUMO_TAG_E3DETECTOR
an e3 detector
T MIN2(T a, T b)
Definition: StdDefs.h:71
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:636
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.
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)
Constructor.
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.
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
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:142
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:4171
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:713
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:183
static const int FORWARD
Definition: MSPModel.h:117
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 const MSVehicleType & getVehicleType() const =0
Returns the object's "vehicle" type.
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 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.