LCOV - code coverage report
Current view: top level - src/microsim/output - MSE3Collector.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 98.2 % 277 272
Test Date: 2025-07-30 21:30:17 Functions: 100.0 % 26 26

            Line data    Source code
       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              : /****************************************************************************/
      14              : /// @file    MSE3Collector.cpp
      15              : /// @author  Christian Roessel
      16              : /// @author  Daniel Krajzewicz
      17              : /// @author  Jakob Erdmann
      18              : /// @author  Michael Behrisch
      19              : /// @author  Laura Bieker
      20              : /// @date    Tue Dec 02 2003 22:17 CET
      21              : ///
      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
      28              : #include <utils/common/ScopedLocker.h>
      29              : #endif
      30              : #include <microsim/MSLane.h>
      31              : #include <microsim/MSEdge.h>
      32              : #include <microsim/MSNet.h>
      33              : #include <microsim/MSVehicle.h>
      34              : #include <microsim/transportables/MSTransportable.h>
      35              : #include <microsim/transportables/MSPModel.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              :  * ----------------------------------------------------------------------- */
      56         1820 : MSE3Collector::MSE3EntryReminder::MSE3EntryReminder(
      57         1820 :     const MSCrossSection& crossSection, MSE3Collector& collector) :
      58         3640 :     MSMoveReminder(collector.getID() + "_entry", crossSection.myLane),
      59         1820 :     myCollector(collector), myPosition(crossSection.myPosition) {
      60         1820 : }
      61              : 
      62              : 
      63              : bool
      64        76777 : MSE3Collector::MSE3EntryReminder::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane) {
      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        76777 :     if (reason != NOTIFICATION_JUNCTION) {
      76        36959 :         const double posOnLane = veh.getBackPositionOnLane(enteredLane) + veh.getVehicleType().getLength();
      77        36959 :         if (myLane == enteredLane && posOnLane > myPosition) {
      78              : #ifdef HAVE_FOX
      79         3551 :             ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
      80              : #endif
      81         3551 :             const auto& itVeh = myCollector.myEnteredContainer.find(&veh);
      82         3551 :             if (itVeh == myCollector.myEnteredContainer.end() ||
      83         3551 :                     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
      99      7792118 : MSE3Collector::MSE3EntryReminder::notifyMove(SUMOTrafficObject& veh, double oldPos,
     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      7792118 :     ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     113              : #endif
     114     15047704 :     if ((myCollector.myEnteredContainer.find(&veh) == myCollector.myEnteredContainer.end() ||
     115      7260806 :             (veh.isPerson() && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD))
     116      7797206 :             && newPos > myPosition) {
     117       105040 :         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        66152 :             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        65104 :             const double oldSpeed = veh.getPreviousSpeed();
     134        65104 :             const double entryTime = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep());
     135              :             assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
     136        65104 :             const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
     137        65104 :             const double fractionTimeOnDet = TS - timeBeforeEnter;
     138        65104 :             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              : 
     150              : bool
     151       249690 : MSE3Collector::MSE3EntryReminder::notifyLeave(SUMOTrafficObject& veh, double, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     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
     161       249690 :     if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
     162              : #ifdef HAVE_FOX
     163        26106 :         ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     164              : #endif
     165        26106 :         if (myCollector.myEnteredContainer.erase(&veh) > 0) {
     166        24325 :             if (!myCollector.myExpectArrival) {
     167        96568 :                 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              :  * ----------------------------------------------------------------------- */
     179         1784 : MSE3Collector::MSE3LeaveReminder::MSE3LeaveReminder(
     180         1784 :     const MSCrossSection& crossSection, MSE3Collector& collector) :
     181         3568 :     MSMoveReminder(collector.getID() + "_exit", crossSection.myLane),
     182         3568 :     myCollector(collector), myPosition(crossSection.myPosition) {}
     183              : 
     184              : 
     185              : bool
     186        76395 : MSE3Collector::MSE3LeaveReminder::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane) {
     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        76395 :     if (reason != NOTIFICATION_JUNCTION) {
     199        13526 :         const double backPosOnLane = veh.getBackPositionOnLane(enteredLane);
     200        13526 :         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              : 
     215              : bool
     216      5761485 : MSE3Collector::MSE3LeaveReminder::notifyMove(SUMOTrafficObject& veh, double oldPos,
     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      5761485 :     if (newPos < myPosition) {
     229              :         // crossSection not yet reached
     230              :         return true;
     231              :     }
     232              : #ifdef HAVE_FOX
     233       259638 :     ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     234              : #endif
     235       259638 :     const double oldSpeed = veh.getPreviousSpeed();
     236       259638 :     if (oldPos < myPosition) {
     237              :         assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
     238        71970 :         const double timeBeforeLeave = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
     239              : //        const double leaveTimeFront = SIMTIME - TS + (myPosition - oldPos) / newSpeed;
     240        71970 :         const double leaveTimeFront = SIMTIME - TS + timeBeforeLeave;
     241        71970 :         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       259638 :     const double backPos = newPos - veh.getVehicleType().getLength();
     249       259638 :     if (backPos < myPosition) {
     250              :         // crossSection not yet left
     251              :         return true;
     252              :     }
     253              :     // crossSection left
     254        71934 :     const double oldBackPos = oldPos - veh.getVehicleType().getLength();
     255        71934 :     const double leaveStep = SIMTIME;
     256              :     assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
     257        71934 :     const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, backPos, oldSpeed, newSpeed);
     258        71934 :     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              : 
     268              : bool
     269        42025 : MSE3Collector::MSE3LeaveReminder::notifyLeave(SUMOTrafficObject&  veh, double /* lastPos */, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     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        42025 :     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        40918 :     ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     290              : #endif
     291        40918 :     if (reason == MSMoveReminder::NOTIFICATION_TELEPORT) {
     292          192 :         WRITE_WARNINGF("Vehicle '%' teleported from % '%'.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID());
     293           48 :         myCollector.myEnteredContainer.erase(&veh);
     294           48 :         return false;
     295              :     }
     296        40870 :     if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
     297         1266 :         if (myCollector.myEnteredContainer.erase(&veh) > 0) {
     298            0 :             if (!myCollector.myExpectArrival) {
     299            0 :                 WRITE_WARNINGF("Vehicle '%' arrived inside % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID(), time2string(SIMSTEP));
     300              :             }
     301              :         }
     302         1266 :         return false;
     303              :     }
     304              :     return true;
     305              : }
     306              : 
     307              : /* -------------------------------------------------------------------------
     308              :  * MSE3Collector - definitions
     309              :  * ----------------------------------------------------------------------- */
     310         1514 : MSE3Collector::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         1514 :                              bool openEntry, bool expectArrival) :
     319              :     MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
     320         1514 :     myName(name),
     321         1514 :     myEntries(entries),
     322         1514 :     myExits(exits),
     323         1514 :     myHaltingTimeThreshold(haltingTimeThreshold), myHaltingSpeedThreshold(haltingSpeedThreshold),
     324         1514 :     myCurrentMeanSpeed(0), myCurrentHaltingsNumber(0),
     325         1514 :     myLastMeanTravelTime(0), myLastMeanHaltsPerVehicle(0), myLastMeanTimeLoss(0), myLastVehicleSum(0),
     326         3028 :     myLastResetTime(-1), myOpenEntry(openEntry), myExpectArrival(expectArrival) {
     327              :     // Set MoveReminders to entries and exits
     328         3334 :     for (CrossSectionVectorConstIt crossSec1 = entries.begin(); crossSec1 != entries.end(); ++crossSec1) {
     329         1820 :         myEntryReminders.push_back(new MSE3EntryReminder(*crossSec1, *this));
     330              :     }
     331         3298 :     for (CrossSectionVectorConstIt crossSec2 = exits.begin(); crossSec2 != exits.end(); ++crossSec2) {
     332         1784 :         myLeaveReminders.push_back(new MSE3LeaveReminder(*crossSec2, *this));
     333              :     }
     334         1514 :     reset();
     335         1514 : }
     336              : 
     337              : 
     338         2860 : MSE3Collector::~MSE3Collector() {
     339         3334 :     for (std::vector<MSE3EntryReminder*>::iterator i = myEntryReminders.begin(); i != myEntryReminders.end(); ++i) {
     340         1820 :         delete *i;
     341              :     }
     342         3298 :     for (std::vector<MSE3LeaveReminder*>::iterator i = myLeaveReminders.begin(); i != myLeaveReminders.end(); ++i) {
     343         1784 :         delete *i;
     344              :     }
     345         4374 : }
     346              : 
     347              : 
     348              : void
     349         1514 : MSE3Collector::reset() {
     350              :     myLeftContainer.clear();
     351         1514 : }
     352              : 
     353              : 
     354              : 
     355              : void
     356        65466 : MSE3Collector::enter(const SUMOTrafficObject& veh, const double entryTimestep, const double fractionTimeOnDet, MSE3EntryReminder* entryReminder, bool isBackward) {
     357        65466 :     if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
     358           42 :         const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
     359           84 :         for (MSTransportable* p : v.getPersons()) {
     360           42 :             enter(*p, entryTimestep, fractionTimeOnDet, entryReminder);
     361              :         }
     362              :         return;
     363              :     }
     364        65424 :     if (!vehicleApplies(veh)) {
     365              :         return;
     366              :     }
     367        64386 :     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          320 :         leave(veh, entryTimestep, fractionTimeOnDet, true);
     371          320 :         return;
     372              :     }
     373        64066 :     if (myEnteredContainer.find(&veh) != myEnteredContainer.end()) {
     374            0 :         WRITE_WARNINGF("Vehicle '%' reentered % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
     375            0 :         return;
     376              :     }
     377              : #ifdef DEBUG_E3_NOTIFY_ENTER
     378              :     std::cout << veh.getID() << " enters\n";
     379              : #endif
     380        64066 :     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        64066 :     v.haltingBegin = veh.getSpeed() < myHaltingSpeedThreshold ? TIME2STEPS(entryTimestep) : -1;
     387        64066 :     v.intervalSpeedSum = entryTimestep >= STEPS2TIME(myLastResetTime) ? speedFraction : 0;
     388              :     v.haltings = 0;
     389              :     v.intervalHaltings = 0;
     390        64066 :     if (veh.getSpeed() < myHaltingSpeedThreshold) {
     391         1410 :         if (TIME2STEPS(fractionTimeOnDet) > myHaltingTimeThreshold) {
     392              :             v.haltings++;
     393              :             v.intervalHaltings++;
     394              :         }
     395              :     }
     396              :     v.hadUpdate = false;
     397        64066 :     if (!MSGlobals::gUseMesoSim && veh.isVehicle()) {
     398        62924 :         v.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss();
     399              :         v.intervalTimeLoss = v.timeLoss;
     400              :     }
     401              :     v.entryReminder = entryReminder;
     402        64066 :     myEnteredContainer[&veh] = v;
     403              : }
     404              : 
     405              : 
     406              : void
     407        72012 : MSE3Collector::leaveFront(const SUMOTrafficObject& veh, const double leaveTimestep) {
     408        72012 :     if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
     409           42 :         const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
     410           84 :         for (MSTransportable* p : v.getPersons()) {
     411           42 :             leaveFront(*p, leaveTimestep);
     412              :         }
     413              :         return;
     414              :     }
     415        71970 :     if (!vehicleApplies(veh)) {
     416              :         return;
     417              :     }
     418        71280 :     if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
     419        33508 :         if (!myOpenEntry && veh.isVehicle()) {
     420        84752 :             WRITE_WARNINGF("Vehicle '%' left % '%' without entering it, time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
     421              :         }
     422              :     } else {
     423        37772 :         myEnteredContainer[&veh].frontLeaveTime = leaveTimestep;
     424              :     }
     425              : }
     426              : 
     427              : 
     428              : void
     429        72296 : MSE3Collector::leave(const SUMOTrafficObject& veh, const double leaveTimestep, const double fractionTimeOnDet, bool isBackward) {
     430        72296 :     if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
     431           42 :         const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
     432           84 :         for (MSTransportable* p : v.getPersons()) {
     433           42 :             leave(*p, leaveTimestep, fractionTimeOnDet);
     434              :         }
     435              :         return;
     436              :     }
     437        72254 :     if (!vehicleApplies(veh)) {
     438              :         return;
     439              :     }
     440        71480 :     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          320 :         enter(veh, leaveTimestep, fractionTimeOnDet, nullptr, true);
     444          320 :         return;
     445              :     }
     446        71160 :     if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
     447        33180 :         if (!myOpenEntry && veh.isVehicle()) {
     448        84720 :             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        37980 :         E3Values values = myEnteredContainer[&veh];
     455        37980 :         values.backLeaveTime = leaveTimestep;
     456        37980 :         const double speedFraction = veh.getSpeed() * (TS - fractionTimeOnDet);
     457        37980 :         values.speedSum -= speedFraction;
     458        37980 :         values.intervalSpeedSum -= speedFraction;
     459        37980 :         if (MSGlobals::gUseMesoSim || !veh.isVehicle()) {
     460              :             // not yet supported
     461         1142 :             values.timeLoss = 0;
     462         1142 :             if (isBackward) {
     463              :                 // leaveFront may not have been called
     464          320 :                 values.frontLeaveTime = leaveTimestep;
     465              :             }
     466              :         } else {
     467              :             // timeLoss was initialized when entering
     468        36838 :             values.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss() - values.timeLoss;
     469              :         }
     470        37980 :         myEnteredContainer.erase(&veh);
     471        37980 :         myLeftContainer.push_back(values);
     472              :     }
     473              : }
     474              : 
     475              : 
     476              : void
     477       250953 : MSE3Collector::writeXMLOutput(OutputDevice& dev,
     478              :                               SUMOTime startTime, SUMOTime stopTime) {
     479       501906 :     dev << "   <interval begin=\"" << time2string(startTime) << "\" end=\"" << time2string(stopTime) << "\" " << "id=\"" << myID << "\" ";
     480              :     // collect values about vehicles that have left the area
     481       250953 :     myLastVehicleSum = (int) myLeftContainer.size();
     482       250953 :     myLastMeanTravelTime = 0;
     483       250953 :     double meanOverlapTravelTime = 0.;
     484       250953 :     double meanSpeed = 0.;
     485       250953 :     myLastMeanHaltsPerVehicle = 0;
     486       250953 :     myLastMeanTimeLoss = 0.;
     487       288918 :     for (const E3Values& values : myLeftContainer) {
     488        37965 :         myLastMeanHaltsPerVehicle += (double)values.haltings;
     489        37965 :         myLastMeanTravelTime += values.frontLeaveTime - values.entryTime;
     490        37965 :         const double steps = values.backLeaveTime - values.entryTime;
     491        37965 :         meanOverlapTravelTime += steps;
     492        37965 :         meanSpeed += (values.speedSum / steps);
     493        37965 :         myLastMeanTimeLoss += STEPS2TIME(values.timeLoss);
     494              :     }
     495       250953 :     myLastMeanTravelTime = myLastVehicleSum != 0 ? myLastMeanTravelTime / (double)myLastVehicleSum : -1;
     496       250953 :     meanOverlapTravelTime = myLastVehicleSum != 0 ? meanOverlapTravelTime / (double)myLastVehicleSum : -1;
     497       250953 :     meanSpeed = myLastVehicleSum != 0 ? meanSpeed / (double)myLastVehicleSum : -1;
     498       250953 :     myLastMeanHaltsPerVehicle = myLastVehicleSum != 0 ? myLastMeanHaltsPerVehicle / (double) myLastVehicleSum : -1;
     499       250953 :     myLastMeanTimeLoss = myLastVehicleSum != 0 ? myLastMeanTimeLoss / (double) myLastVehicleSum : -1;
     500              :     // clear container
     501              :     myLeftContainer.clear();
     502              : 
     503              :     // collect values about vehicles within the container
     504       250953 :     const int vehicleSumWithin = (int) myEnteredContainer.size();
     505       250953 :     double meanSpeedWithin = 0.;
     506       250953 :     double meanDurationWithin = 0.;
     507       250953 :     double meanHaltsPerVehicleWithin = 0.;
     508       250953 :     double meanIntervalSpeedWithin = 0.;
     509       250953 :     double meanIntervalHaltsPerVehicleWithin = 0.;
     510       250953 :     double meanIntervalDurationWithin = 0.;
     511       250953 :     double meanTimeLossWithin = 0.;
     512      1646056 :     for (std::map<const SUMOTrafficObject*, E3Values>::iterator i = myEnteredContainer.begin(); i != myEnteredContainer.end(); ++i) {
     513      1395103 :         meanHaltsPerVehicleWithin += (double)(*i).second.haltings;
     514      1395103 :         meanIntervalHaltsPerVehicleWithin += (double)(*i).second.intervalHaltings;
     515      1395103 :         const double end = (*i).second.backLeaveTime == 0 ? STEPS2TIME(stopTime) : (*i).second.backLeaveTime;
     516      1395103 :         const double time = end - (*i).second.entryTime;
     517      1395103 :         const double timeWithin = MIN2(time, end - STEPS2TIME(startTime));
     518      1395103 :         if (i->second.speedSum > 0.) {
     519      1395103 :             meanSpeedWithin += i->second.speedSum / time;
     520              :         }
     521      1395103 :         if (i->second.intervalSpeedSum > 0.) {
     522       195119 :             meanIntervalSpeedWithin += i->second.intervalSpeedSum / timeWithin;
     523              :         }
     524      1395103 :         meanDurationWithin += time;
     525      1395103 :         meanIntervalDurationWithin += timeWithin;
     526              :         // reset interval values
     527      1395103 :         (*i).second.intervalHaltings = 0;
     528      1395103 :         (*i).second.intervalSpeedSum = 0;
     529              : 
     530      1395103 :         if (!MSGlobals::gUseMesoSim && i->first->isVehicle()) {
     531      1395039 :             const SUMOTime currentTimeLoss = dynamic_cast<const MSVehicle*>(i->first)->getTimeLoss();
     532      1395039 :             meanTimeLossWithin += STEPS2TIME(currentTimeLoss - (*i).second.intervalTimeLoss);
     533      1395039 :             (*i).second.intervalTimeLoss = currentTimeLoss;
     534              :         }
     535              :     }
     536       250953 :     myLastResetTime = stopTime;
     537       250953 :     meanSpeedWithin = vehicleSumWithin != 0 ?  meanSpeedWithin / (double) vehicleSumWithin : -1;
     538       250953 :     meanHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
     539       250953 :     meanDurationWithin = vehicleSumWithin != 0 ? meanDurationWithin / (double) vehicleSumWithin : -1;
     540       250953 :     meanIntervalSpeedWithin = vehicleSumWithin != 0 ?  meanIntervalSpeedWithin / (double) vehicleSumWithin : -1;
     541       250953 :     meanIntervalHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanIntervalHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
     542       250953 :     meanIntervalDurationWithin = vehicleSumWithin != 0 ? meanIntervalDurationWithin / (double) vehicleSumWithin : -1;
     543       250953 :     meanTimeLossWithin = vehicleSumWithin != 0 ? meanTimeLossWithin / (double) vehicleSumWithin : -1;
     544              : 
     545              :     // write values
     546       250953 :     dev << "meanTravelTime=\"" << myLastMeanTravelTime
     547       250953 :         << "\" meanOverlapTravelTime=\"" << meanOverlapTravelTime
     548       250953 :         << "\" meanSpeed=\"" << meanSpeed
     549       250953 :         << "\" meanHaltsPerVehicle=\"" << myLastMeanHaltsPerVehicle
     550       250953 :         << "\" meanTimeLoss=\"" << myLastMeanTimeLoss
     551       250953 :         << "\" vehicleSum=\"" << myLastVehicleSum
     552       250953 :         << "\" meanSpeedWithin=\"" << meanSpeedWithin
     553       250953 :         << "\" meanHaltsPerVehicleWithin=\"" << meanHaltsPerVehicleWithin
     554       250953 :         << "\" meanDurationWithin=\"" << meanDurationWithin
     555       250953 :         << "\" vehicleSumWithin=\"" << vehicleSumWithin
     556       250953 :         << "\" meanIntervalSpeedWithin=\"" << meanIntervalSpeedWithin
     557       250953 :         << "\" meanIntervalHaltsPerVehicleWithin=\"" << meanIntervalHaltsPerVehicleWithin
     558       250953 :         << "\" meanIntervalDurationWithin=\"" << meanIntervalDurationWithin
     559       250953 :         << "\" meanTimeLossWithin=\"" << meanTimeLossWithin
     560       250953 :         << "\"/>\n";
     561       250953 : }
     562              : 
     563              : 
     564              : void
     565         1506 : MSE3Collector::writeXMLDetectorProlog(OutputDevice& dev) const {
     566         3012 :     dev.writeXMLHeader("e3Detector", "det_e3_file.xsd");
     567         1506 : }
     568              : 
     569              : 
     570              : void
     571       130928 : MSE3Collector::notifyMovePerson(MSTransportable* p, MSMoveReminder* rem, double detPos, int dir, double pos) {
     572       130928 :     if (personApplies(*p, dir)) {
     573        87280 :         const double newSpeed = p->getSpeed();
     574        87280 :         const double newPos = (dir == MSPModel::FORWARD
     575        87280 :                                ? pos
     576              :                                // position relative to detector end position
     577        21600 :                                : detPos - (pos - detPos));
     578        87280 :         const double oldPos = newPos - SPEED2DIST(newSpeed);
     579        87280 :         if (oldPos - p->getVehicleType().getLength() <= detPos) {
     580        48432 :             rem->notifyMove(*p, oldPos, newPos, newSpeed);
     581              :         }
     582              :     }
     583       130928 : }
     584              : 
     585              : 
     586              : void
     587      3164998 : MSE3Collector::detectorUpdate(const SUMOTime step) {
     588              : 
     589      3164998 :     if (myDetectPersons != (int)PersonMode::NONE) {
     590        39942 :         for (auto rem : myEntryReminders) {
     591              :             const MSLane* lane = rem->getLane();
     592        22524 :             if (lane->hasPedestrians()) {
     593       117636 :                 for (MSTransportable* p : lane->getEdge().getPersons()) {
     594       105544 :                     if (p->getLane() == lane && vehicleApplies(*p)) {
     595        65464 :                         notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
     596              :                     }
     597              :                 }
     598              :             }
     599              :         }
     600        39942 :         for (auto rem : myLeaveReminders) {
     601              :             const MSLane* lane = rem->getLane();
     602        22524 :             if (lane->hasPedestrians()) {
     603       117636 :                 for (MSTransportable* p : lane->getEdge().getPersons()) {
     604       105544 :                     if (p->getLane() == lane && vehicleApplies(*p)) {
     605        65464 :                         notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
     606              :                     }
     607              :                 }
     608              :             }
     609              :         }
     610              :     }
     611              : 
     612      3164998 :     myCurrentMeanSpeed = 0;
     613      3164998 :     myCurrentHaltingsNumber = 0;
     614     10259318 :     for (std::map<const SUMOTrafficObject*, E3Values>::iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
     615      7094320 :         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;
     624      7094320 :         myCurrentMeanSpeed += veh->getSpeed();
     625      7094320 :         values.hadUpdate = true;
     626      7094320 :         values.speedSum += veh->getSpeed() * TS;
     627      7094320 :         values.intervalSpeedSum += veh->getSpeed() * TS;
     628      7094320 :         if (veh->getSpeed() < myHaltingSpeedThreshold) {
     629      5600909 :             if (values.haltingBegin == -1) {
     630        57976 :                 values.haltingBegin = step;
     631              :             }
     632      5600909 :             SUMOTime haltingDuration = step - values.haltingBegin;
     633      5600909 :             if (haltingDuration >= myHaltingTimeThreshold
     634      5536991 :                     && haltingDuration < (myHaltingTimeThreshold + DELTA_T)) {
     635        53942 :                 values.haltings++;
     636        53942 :                 values.intervalHaltings++;
     637        53942 :                 myCurrentHaltingsNumber++;
     638              :             }
     639              :         } else {
     640      1493411 :             values.haltingBegin = -1;
     641              :         }
     642              :     }
     643      3164998 :     if (myEnteredContainer.size() == 0) {
     644      2668438 :         myCurrentMeanSpeed = -1;
     645              :     } else {
     646       496560 :         myCurrentMeanSpeed /= (double)myEnteredContainer.size();
     647              :     }
     648      3164998 : }
     649              : 
     650              : 
     651              : const CrossSectionVector&
     652          363 : MSE3Collector::getEntries() const {
     653          363 :     return myEntries;
     654              : }
     655              : 
     656              : 
     657              : const CrossSectionVector&
     658          363 : MSE3Collector::getExits() const {
     659          363 :     return myExits;
     660              : }
     661              : 
     662              : 
     663              : double
     664           57 : MSE3Collector::getCurrentMeanSpeed() const {
     665           57 :     return myCurrentMeanSpeed;
     666              : }
     667              : 
     668              : 
     669              : int
     670           15 : MSE3Collector::getCurrentHaltingNumber() const {
     671           15 :     return myCurrentHaltingsNumber;
     672              : }
     673              : 
     674              : 
     675              : int
     676          588 : MSE3Collector::getVehiclesWithin() const {
     677          588 :     return (int) myEnteredContainer.size();
     678              : }
     679              : 
     680              : 
     681              : std::vector<std::string>
     682          257 : MSE3Collector::getCurrentVehicleIDs() const {
     683              :     std::vector<std::string> ret;
     684          379 :     for (std::map<const SUMOTrafficObject*, E3Values>::const_iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
     685          122 :         ret.push_back((*pair).first->getID());
     686              :     }
     687          257 :     std::sort(ret.begin(), ret.end());
     688          257 :     return ret;
     689            0 : }
     690              : 
     691              : void
     692           20 : MSE3Collector::clearState(SUMOTime /* step */) {
     693              :     myEnteredContainer.clear();
     694              :     myLeftContainer.clear();
     695           20 : }
     696              : 
     697              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1