Eclipse SUMO - Simulation of Urban MObility
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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-2025 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, isPerson=" << veh.isPerson() << "\n";
122 }
123#endif
124 return false;
125 } else {
126 if (veh.isVehicle() && &veh.getLane()->getEdge() == &myLane->getEdge() && veh.getLane() != myLane) {
127#ifdef DEBUG_E3_NOTIFY_ENTER
128 std::cout << veh.getID() << " is on the wrong lane\n";
129#endif
130 return true;
131 }
132 // entered in this step
133 const double oldSpeed = veh.getPreviousSpeed();
134 const double entryTime = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep());
135 assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
136 const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
137 const double fractionTimeOnDet = TS - timeBeforeEnter;
138 myCollector.enter(veh, entryTime - fractionTimeOnDet, fractionTimeOnDet, this);
139#ifdef DEBUG_E3_NOTIFY_MOVE
140 if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
141 std::cout << " enter\n";
142 }
143#endif
144 }
145 }
146 return true;
147}
148
149
150bool
152#ifdef DEBUG_E3_NOTIFY_LEAVE
153 if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
154 std::cout << SIMTIME
155 << " MSE3EntryReminder::notifyLeave() (" << getDescription() << " on lane '" << myLane->getID() << "')"
156 << " vehicle '" << veh.getID() << "'"
157 << " reason=" << reason
158 << "\n";
159 }
160#endif
162#ifdef HAVE_FOX
163 ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
164#endif
165 if (myCollector.myEnteredContainer.erase(&veh) > 0) {
166 if (!myCollector.myExpectArrival) {
167 WRITE_WARNINGF("Vehicle '%' arrived inside % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID(), time2string(SIMSTEP));
168 }
169 }
170 return false;
171 }
172 return true;
173}
174
175
176/* -------------------------------------------------------------------------
177 * MSE3Collector::MSE3LeaveReminder - definitions
178 * ----------------------------------------------------------------------- */
180 const MSCrossSection& crossSection, MSE3Collector& collector) :
181 MSMoveReminder(collector.getID() + "_exit", crossSection.myLane),
182 myCollector(collector), myPosition(crossSection.myPosition) {}
183
184
185bool
187#ifdef DEBUG_E3_NOTIFY_ENTER
188 if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
189 std::cout << SIMTIME
190 << " MSE3LeaveReminder::notifyEnter() (" << getDescription() << " on lane '" << myLane->getID() << "')"
191 << " vehicle '" << veh.getID() << "'"
192 << " enteredLane=" << enteredLane->getID()
193 << " reason=" << reason
194 << "\n";
195 }
196#endif
197 // this method does not access containers, so no locking here
198 if (reason != NOTIFICATION_JUNCTION) {
199 const double backPosOnLane = veh.getBackPositionOnLane(enteredLane);
200 if (backPosOnLane > myPosition) {
201 // if the vehicle changes into a covered section we assume it was already registered on another lane
202 // however, if it is not fully past the detector we still need to track it
203#ifdef DEBUG_E3_NOTIFY_ENTER
204 if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
205 std::cout << " assume already known\n";
206 }
207#endif
208 return false;
209 }
210 }
211 return true;
212}
213
214
215bool
217 double newPos, double newSpeed) {
218#ifdef DEBUG_E3_NOTIFY_MOVE
219 if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
220 std::cout << SIMTIME
221 << " MSE3LeaveReminder::notifyMove() (" << getDescription() << " on lane '" << myLane->getID() << "')"
222 << " vehicle '" << veh.getID() << "'"
223 << " entered. oldPos=" << oldPos << " newPos=" << newPos << " newSpeed=" << newSpeed
224 << " myPosition=" << myPosition
225 << "\n";
226 }
227#endif
228 if (newPos < myPosition) {
229 // crossSection not yet reached
230 return true;
231 }
232#ifdef HAVE_FOX
233 ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
234#endif
235 const double oldSpeed = veh.getPreviousSpeed();
236 if (oldPos < myPosition) {
237 assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
238 const double timeBeforeLeave = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
239// const double leaveTimeFront = SIMTIME - TS + (myPosition - oldPos) / newSpeed;
240 const double leaveTimeFront = SIMTIME - TS + timeBeforeLeave;
241 myCollector.leaveFront(veh, leaveTimeFront);
242#ifdef DEBUG_E3_NOTIFY_MOVE
243 if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
244 std::cout << " leaveFront\n";
245 }
246#endif
247 }
248 const double backPos = newPos - veh.getVehicleType().getLength();
249 if (backPos < myPosition) {
250 // crossSection not yet left
251 return true;
252 }
253 // crossSection left
254 const double oldBackPos = oldPos - veh.getVehicleType().getLength();
255 const double leaveStep = SIMTIME;
256 assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
257 const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, backPos, oldSpeed, newSpeed);
258 myCollector.leave(veh, leaveStep - TS + timeBeforeLeave, timeBeforeLeave);
259#ifdef DEBUG_E3_NOTIFY_MOVE
260 if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
261 std::cout << " leave\n";
262 }
263#endif
264 return false;
265}
266
267
268bool
270#ifdef DEBUG_E3_NOTIFY_LEAVE
271 if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
272 std::cout << SIMTIME
273 << " MSE3LeaveReminder::notifyLeave() (" << getDescription() << " on lane '" << myLane->getID() << "')"
274 << " vehicle '" << veh.getID() << "'"
275 << " reason=" << reason
276 << "\n";
277 }
278#endif
279 if (reason == MSMoveReminder::NOTIFICATION_LANE_CHANGE && &enteredLane->getEdge() == &myLane->getEdge()) {
280 // keep the detector when changing while still on the exit detector but already on a new lane (#4803)
281#ifdef DEBUG_E3_NOTIFY_LEAVE
282 if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
283 std::cout << " remove reminder, keep in container\n";
284 }
285#endif
286 return false;
287 }
288#ifdef HAVE_FOX
289 ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
290#endif
292 WRITE_WARNINGF("Vehicle '%' teleported from % '%'.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID());
293 myCollector.myEnteredContainer.erase(&veh);
294 return false;
295 }
297 if (myCollector.myEnteredContainer.erase(&veh) > 0) {
298 if (!myCollector.myExpectArrival) {
299 WRITE_WARNINGF("Vehicle '%' arrived inside % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID(), time2string(SIMSTEP));
300 }
301 }
302 return false;
303 }
304 return true;
305}
306
307/* -------------------------------------------------------------------------
308 * MSE3Collector - definitions
309 * ----------------------------------------------------------------------- */
310MSE3Collector::MSE3Collector(const std::string& id,
311 const CrossSectionVector& entries,
312 const CrossSectionVector& exits,
313 double haltingSpeedThreshold,
314 SUMOTime haltingTimeThreshold,
315 const std::string name, const std::string& vTypes,
316 const std::string& nextEdges,
317 int detectPersons,
318 bool openEntry, bool expectArrival) :
319 MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
320 myName(name),
321 myEntries(entries),
322 myExits(exits),
323 myHaltingTimeThreshold(haltingTimeThreshold), myHaltingSpeedThreshold(haltingSpeedThreshold),
326 myLastResetTime(-1), myOpenEntry(openEntry), myExpectArrival(expectArrival) {
327 // Set MoveReminders to entries and exits
328 for (CrossSectionVectorConstIt crossSec1 = entries.begin(); crossSec1 != entries.end(); ++crossSec1) {
329 myEntryReminders.push_back(new MSE3EntryReminder(*crossSec1, *this));
330 }
331 for (CrossSectionVectorConstIt crossSec2 = exits.begin(); crossSec2 != exits.end(); ++crossSec2) {
332 myLeaveReminders.push_back(new MSE3LeaveReminder(*crossSec2, *this));
333 }
334 reset();
335}
336
337
339 for (std::vector<MSE3EntryReminder*>::iterator i = myEntryReminders.begin(); i != myEntryReminders.end(); ++i) {
340 delete *i;
341 }
342 for (std::vector<MSE3LeaveReminder*>::iterator i = myLeaveReminders.begin(); i != myLeaveReminders.end(); ++i) {
343 delete *i;
344 }
345}
346
347
348void
352
353
354
355void
356MSE3Collector::enter(const SUMOTrafficObject& veh, const double entryTimestep, const double fractionTimeOnDet, MSE3EntryReminder* entryReminder, bool isBackward) {
357 if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
358 const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
359 for (MSTransportable* p : v.getPersons()) {
360 enter(*p, entryTimestep, fractionTimeOnDet, entryReminder);
361 }
362 return;
363 }
364 if (!vehicleApplies(veh)) {
365 return;
366 }
367 if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
368 // walking backward over an entry detector means "leaving"
369 // std::cout << veh.getID() << " leave at entryDetector\n";
370 leave(veh, entryTimestep, fractionTimeOnDet, true);
371 return;
372 }
373 if (myEnteredContainer.find(&veh) != myEnteredContainer.end()) {
374 WRITE_WARNINGF("Vehicle '%' reentered % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
375 return;
376 }
377#ifdef DEBUG_E3_NOTIFY_ENTER
378 std::cout << veh.getID() << " enters\n";
379#endif
380 const double speedFraction = veh.getSpeed() * fractionTimeOnDet;
381 E3Values v;
382 v.entryTime = entryTimestep;
383 v.frontLeaveTime = 0;
384 v.backLeaveTime = 0;
385 v.speedSum = speedFraction;
386 v.haltingBegin = veh.getSpeed() < myHaltingSpeedThreshold ? TIME2STEPS(entryTimestep) : -1;
387 v.intervalSpeedSum = entryTimestep >= STEPS2TIME(myLastResetTime) ? speedFraction : 0;
388 v.haltings = 0;
389 v.intervalHaltings = 0;
390 if (veh.getSpeed() < myHaltingSpeedThreshold) {
391 if (TIME2STEPS(fractionTimeOnDet) > myHaltingTimeThreshold) {
392 v.haltings++;
394 }
395 }
396 v.hadUpdate = false;
397 if (!MSGlobals::gUseMesoSim && veh.isVehicle()) {
398 v.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss();
400 }
401 v.entryReminder = entryReminder;
402 myEnteredContainer[&veh] = v;
403}
404
405
406void
407MSE3Collector::leaveFront(const SUMOTrafficObject& veh, const double leaveTimestep) {
408 if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
409 const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
410 for (MSTransportable* p : v.getPersons()) {
411 leaveFront(*p, leaveTimestep);
412 }
413 return;
414 }
415 if (!vehicleApplies(veh)) {
416 return;
417 }
418 if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
419 if (!myOpenEntry && veh.isVehicle()) {
420 WRITE_WARNINGF("Vehicle '%' left % '%' without entering it, time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
421 }
422 } else {
423 myEnteredContainer[&veh].frontLeaveTime = leaveTimestep;
424 }
425}
426
427
428void
429MSE3Collector::leave(const SUMOTrafficObject& veh, const double leaveTimestep, const double fractionTimeOnDet, bool isBackward) {
430 if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
431 const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
432 for (MSTransportable* p : v.getPersons()) {
433 leave(*p, leaveTimestep, fractionTimeOnDet);
434 }
435 return;
436 }
437 if (!vehicleApplies(veh)) {
438 return;
439 }
440 if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
441 // walking backward over an exit detector means "entering"
442 // std::cout << veh.getID() << " enter at exitDetector\n";
443 enter(veh, leaveTimestep, fractionTimeOnDet, nullptr, true);
444 return;
445 }
446 if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
447 if (!myOpenEntry && veh.isVehicle()) {
448 WRITE_WARNINGF("Vehicle '%' left % '%' without entering it, time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
449 }
450 } else {
451#ifdef DEBUG_E3_NOTIFY_LEAVE
452 std::cout << veh.getID() << " leaves\n";
453#endif
454 E3Values values = myEnteredContainer[&veh];
455 values.backLeaveTime = leaveTimestep;
456 const double speedFraction = veh.getSpeed() * (TS - fractionTimeOnDet);
457 values.speedSum -= speedFraction;
458 values.intervalSpeedSum -= speedFraction;
459 if (MSGlobals::gUseMesoSim || !veh.isVehicle()) {
460 // not yet supported
461 values.timeLoss = 0;
462 if (isBackward) {
463 // leaveFront may not have been called
464 values.frontLeaveTime = leaveTimestep;
465 }
466 } else {
467 // timeLoss was initialized when entering
468 values.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss() - values.timeLoss;
469 }
470 myEnteredContainer.erase(&veh);
471 myLeftContainer.push_back(values);
472 }
473}
474
475
476void
478 SUMOTime startTime, SUMOTime stopTime) {
479 dev << " <interval begin=\"" << time2string(startTime) << "\" end=\"" << time2string(stopTime) << "\" " << "id=\"" << myID << "\" ";
480 // collect values about vehicles that have left the area
481 myLastVehicleSum = (int) myLeftContainer.size();
483 double meanOverlapTravelTime = 0.;
484 double meanSpeed = 0.;
487 for (const E3Values& values : myLeftContainer) {
488 myLastMeanHaltsPerVehicle += (double)values.haltings;
489 myLastMeanTravelTime += values.frontLeaveTime - values.entryTime;
490 const double steps = values.backLeaveTime - values.entryTime;
491 meanOverlapTravelTime += steps;
492 meanSpeed += (values.speedSum / steps);
493 myLastMeanTimeLoss += STEPS2TIME(values.timeLoss);
494 }
496 meanOverlapTravelTime = myLastVehicleSum != 0 ? meanOverlapTravelTime / (double)myLastVehicleSum : -1;
497 meanSpeed = myLastVehicleSum != 0 ? meanSpeed / (double)myLastVehicleSum : -1;
500 // clear container
501 myLeftContainer.clear();
502
503 // collect values about vehicles within the container
504 const int vehicleSumWithin = (int) myEnteredContainer.size();
505 double meanSpeedWithin = 0.;
506 double meanDurationWithin = 0.;
507 double meanHaltsPerVehicleWithin = 0.;
508 double meanIntervalSpeedWithin = 0.;
509 double meanIntervalHaltsPerVehicleWithin = 0.;
510 double meanIntervalDurationWithin = 0.;
511 double meanTimeLossWithin = 0.;
512 for (std::map<const SUMOTrafficObject*, E3Values>::iterator i = myEnteredContainer.begin(); i != myEnteredContainer.end(); ++i) {
513 meanHaltsPerVehicleWithin += (double)(*i).second.haltings;
514 meanIntervalHaltsPerVehicleWithin += (double)(*i).second.intervalHaltings;
515 const double end = (*i).second.backLeaveTime == 0 ? STEPS2TIME(stopTime) : (*i).second.backLeaveTime;
516 const double time = end - (*i).second.entryTime;
517 const double timeWithin = MIN2(time, end - STEPS2TIME(startTime));
518 if (i->second.speedSum > 0.) {
519 meanSpeedWithin += i->second.speedSum / time;
520 }
521 if (i->second.intervalSpeedSum > 0.) {
522 meanIntervalSpeedWithin += i->second.intervalSpeedSum / timeWithin;
523 }
524 meanDurationWithin += time;
525 meanIntervalDurationWithin += timeWithin;
526 // reset interval values
527 (*i).second.intervalHaltings = 0;
528 (*i).second.intervalSpeedSum = 0;
529
530 if (!MSGlobals::gUseMesoSim && i->first->isVehicle()) {
531 const SUMOTime currentTimeLoss = dynamic_cast<const MSVehicle*>(i->first)->getTimeLoss();
532 meanTimeLossWithin += STEPS2TIME(currentTimeLoss - (*i).second.intervalTimeLoss);
533 (*i).second.intervalTimeLoss = currentTimeLoss;
534 }
535 }
536 myLastResetTime = stopTime;
537 meanSpeedWithin = vehicleSumWithin != 0 ? meanSpeedWithin / (double) vehicleSumWithin : -1;
538 meanHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
539 meanDurationWithin = vehicleSumWithin != 0 ? meanDurationWithin / (double) vehicleSumWithin : -1;
540 meanIntervalSpeedWithin = vehicleSumWithin != 0 ? meanIntervalSpeedWithin / (double) vehicleSumWithin : -1;
541 meanIntervalHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanIntervalHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
542 meanIntervalDurationWithin = vehicleSumWithin != 0 ? meanIntervalDurationWithin / (double) vehicleSumWithin : -1;
543 meanTimeLossWithin = vehicleSumWithin != 0 ? meanTimeLossWithin / (double) vehicleSumWithin : -1;
544
545 // write values
546 dev << "meanTravelTime=\"" << myLastMeanTravelTime
547 << "\" meanOverlapTravelTime=\"" << meanOverlapTravelTime
548 << "\" meanSpeed=\"" << meanSpeed
549 << "\" meanHaltsPerVehicle=\"" << myLastMeanHaltsPerVehicle
550 << "\" meanTimeLoss=\"" << myLastMeanTimeLoss
551 << "\" vehicleSum=\"" << myLastVehicleSum
552 << "\" meanSpeedWithin=\"" << meanSpeedWithin
553 << "\" meanHaltsPerVehicleWithin=\"" << meanHaltsPerVehicleWithin
554 << "\" meanDurationWithin=\"" << meanDurationWithin
555 << "\" vehicleSumWithin=\"" << vehicleSumWithin
556 << "\" meanIntervalSpeedWithin=\"" << meanIntervalSpeedWithin
557 << "\" meanIntervalHaltsPerVehicleWithin=\"" << meanIntervalHaltsPerVehicleWithin
558 << "\" meanIntervalDurationWithin=\"" << meanIntervalDurationWithin
559 << "\" meanTimeLossWithin=\"" << meanTimeLossWithin
560 << "\"/>\n";
561}
562
563
564void
566 dev.writeXMLHeader("e3Detector", "det_e3_file.xsd");
567}
568
569
570void
571MSE3Collector::notifyMovePerson(MSTransportable* p, MSMoveReminder* rem, double detPos, int dir, double pos) {
572 if (personApplies(*p, dir)) {
573 const double newSpeed = p->getSpeed();
574 const double newPos = (dir == MSPModel::FORWARD
575 ? pos
576 // position relative to detector end position
577 : detPos - (pos - detPos));
578 const double oldPos = newPos - SPEED2DIST(newSpeed);
579 if (oldPos - p->getVehicleType().getLength() <= detPos) {
580 rem->notifyMove(*p, oldPos, newPos, newSpeed);
581 }
582 }
583}
584
585
586void
588
589 if (myDetectPersons != (int)PersonMode::NONE) {
590 for (auto rem : myEntryReminders) {
591 const MSLane* lane = rem->getLane();
592 if (lane->hasPedestrians()) {
593 for (MSTransportable* p : lane->getEdge().getPersons()) {
594 if (p->getLane() == lane && vehicleApplies(*p)) {
595 notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
596 }
597 }
598 }
599 }
600 for (auto rem : myLeaveReminders) {
601 const MSLane* lane = rem->getLane();
602 if (lane->hasPedestrians()) {
603 for (MSTransportable* p : lane->getEdge().getPersons()) {
604 if (p->getLane() == lane && vehicleApplies(*p)) {
605 notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
606 }
607 }
608 }
609 }
610 }
611
614 for (std::map<const SUMOTrafficObject*, E3Values>::iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
615 const SUMOTrafficObject* veh = pair->first;
616#ifdef DEBUG_E3_DETECTORUPDATE
617 //if (DEBUG_COND(*this) && DEBUG_COND_VEH(*veh)) {
618 if (DEBUG_COND(*this)) {
619 std::cout << SIMTIME << " vehPtr=" << veh << "\n";
620 std::cout << " veh=" << veh->getID() << "\n";
621 }
622#endif
623 E3Values& values = pair->second;
625 values.hadUpdate = true;
626 values.speedSum += veh->getSpeed() * TS;
627 values.intervalSpeedSum += veh->getSpeed() * TS;
628 if (veh->getSpeed() < myHaltingSpeedThreshold) {
629 if (values.haltingBegin == -1) {
630 values.haltingBegin = step;
631 }
632 SUMOTime haltingDuration = step - values.haltingBegin;
633 if (haltingDuration >= myHaltingTimeThreshold
634 && haltingDuration < (myHaltingTimeThreshold + DELTA_T)) {
635 values.haltings++;
636 values.intervalHaltings++;
638 }
639 } else {
640 values.haltingBegin = -1;
641 }
642 }
643 if (myEnteredContainer.size() == 0) {
645 } else {
646 myCurrentMeanSpeed /= (double)myEnteredContainer.size();
647 }
648}
649
650
653 return myEntries;
654}
655
656
659 return myExits;
660}
661
662
663double
667
668
669int
673
674
675int
677 return (int) myEnteredContainer.size();
678}
679
680
681std::vector<std::string>
683 std::vector<std::string> ret;
684 for (std::map<const SUMOTrafficObject*, E3Values>::const_iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
685 ret.push_back((*pair).first->getID());
686 }
687 std::sort(ret.begin(), ret.end());
688 return ret;
689}
690
691void
693 myEnteredContainer.clear();
694 myLeftContainer.clear();
695}
696
697/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
CrossSectionVector::const_iterator CrossSectionVectorConstIt
std::vector< MSCrossSection > CrossSectionVector
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:288
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:91
#define STEPS2TIME(x)
Definition SUMOTime.h:55
#define SPEED2DIST(x)
Definition SUMOTime.h:45
#define SIMSTEP
Definition SUMOTime.h:61
#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.
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...
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.
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.
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:204
static bool gUseMesoSim
Definition MSGlobals.h:106
static bool gSemiImplicitEulerUpdate
Definition MSGlobals.h:53
static int gNumSimThreads
how many threads to use for simulation
Definition MSGlobals.h:146
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:4535
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:764
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:186
static const int FORWARD
Definition MSPModel.h:54
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.
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 const MSLane * getLane() const =0
Returns the lane the object is currently at.
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.
#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.