LCOV - code coverage report
Current view: top level - src/microsim/output - MSE3Collector.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 98.2 % 278 273
Test Date: 2026-03-26 16:31:35 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-2026 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 <utils/common/StringUtils.h>
      37              : #include <utils/iodevices/OutputDevice.h>
      38              : #include "MSE3Collector.h"
      39              : 
      40              : //#define DEBUG_E3_NOTIFY_MOVE
      41              : //#define DEBUG_E3_NOTIFY_ENTER
      42              : //#define DEBUG_E3_NOTIFY_LEAVE
      43              : //#define DEBUG_E3_DETECTORUPDATE
      44              : 
      45              : //#define DEBUG_COND(obj) ((obj.getID() == ""))
      46              : //#define DEBUG_COND_VEH(veh) ((veh).getID() == "")
      47              : //#define DEBUG_COND_VEH(veh) ((veh).isSelected())
      48              : //#define DEBUG_COND(collector) (true)
      49              : //#define DEBUG_COND_VEH(veh) (true)
      50              : 
      51              : 
      52              : // ===========================================================================
      53              : // method definitions
      54              : // ===========================================================================
      55              : /* -------------------------------------------------------------------------
      56              :  * MSE3Collector::MSE3EntryReminder - definitions
      57              :  * ----------------------------------------------------------------------- */
      58         1732 : MSE3Collector::MSE3EntryReminder::MSE3EntryReminder(
      59         1732 :     const MSCrossSection& crossSection, MSE3Collector& collector) :
      60         3464 :     MSMoveReminder(collector.getID() + "_entry", crossSection.myLane),
      61         1732 :     myCollector(collector), myPosition(crossSection.myPosition) {
      62         1732 : }
      63              : 
      64              : 
      65              : bool
      66        71759 : MSE3Collector::MSE3EntryReminder::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane) {
      67              : #ifdef DEBUG_E3_NOTIFY_ENTER
      68              :     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
      69              :         std::cout << SIMTIME
      70              :                   << " MSE3EntryReminder::notifyEnter() (" << getDescription() << " on lane '" << myLane->getID() << "')"
      71              :                   << " vehicle '" << veh.getID() << "'"
      72              :                   << " enteredLane=" << enteredLane->getID()
      73              :                   << " reason=" << reason
      74              :                   << "\n";
      75              :     }
      76              : #endif
      77        71759 :     if (reason != NOTIFICATION_JUNCTION) {
      78        34063 :         const double posOnLane = veh.getBackPositionOnLane(enteredLane) + veh.getVehicleType().getLength();
      79        34063 :         if (myLane == enteredLane && posOnLane > myPosition) {
      80              : #ifdef HAVE_FOX
      81         3563 :             ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
      82              : #endif
      83         3563 :             const auto& itVeh = myCollector.myEnteredContainer.find(&veh);
      84         3563 :             if (itVeh == myCollector.myEnteredContainer.end() ||
      85         3563 :                     itVeh->second.entryReminder != this) {
      86              : #ifdef DEBUG_E3_NOTIFY_ENTER
      87              :                 if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
      88              :                     std::cout << "  assume already known\n";
      89              :                 }
      90              : #endif
      91              :                 // if the vehicle changes into a covered section we assume it was already registered on another lane
      92              :                 return false;
      93              :             }
      94              :         }
      95              :     }
      96              :     return true;
      97              : }
      98              : 
      99              : 
     100              : bool
     101      7790473 : MSE3Collector::MSE3EntryReminder::notifyMove(SUMOTrafficObject& veh, double oldPos,
     102              :         double newPos, double newSpeed) {
     103              : #ifdef DEBUG_E3_NOTIFY_MOVE
     104              :     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     105              :         std::cout << SIMTIME
     106              :                   << " MSE3EntryReminder::notifyMove() (" << getDescription() << " on lane '" << myLane->getID() << "')"
     107              :                   << " vehicle '" << veh.getID() << "'"
     108              :                   << " entered. oldPos=" << oldPos << " newPos=" << newPos << " newSpeed=" << newSpeed
     109              :                   << " myPosition=" << myPosition
     110              :                   << "\n";
     111              :     }
     112              : #endif
     113              : #ifdef HAVE_FOX
     114      7790473 :     ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     115              : #endif
     116     15044802 :     if ((myCollector.myEnteredContainer.find(&veh) == myCollector.myEnteredContainer.end() ||
     117      7259549 :             (veh.isPerson() && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD))
     118      7795561 :             && newPos > myPosition) {
     119       100819 :         if (oldPos > myPosition) {
     120              :             // was behind the detector already in the last step
     121              : #ifdef DEBUG_E3_NOTIFY_MOVE
     122              :             if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     123              :                 std::cout << "    already behind, isPerson=" << veh.isPerson() << "\n";
     124              :             }
     125              : #endif
     126              :             return false;
     127              :         } else {
     128        61278 :             if (veh.isVehicle() && &veh.getLane()->getEdge() == &myLane->getEdge() && veh.getLane() != myLane) {
     129              : #ifdef DEBUG_E3_NOTIFY_ENTER
     130              :                 std::cout << veh.getID() << " is on the wrong lane\n";
     131              : #endif
     132              :                 return true;
     133              :             }
     134              :             // entered in this step
     135        60225 :             const double oldSpeed = veh.getPreviousSpeed();
     136        60225 :             const double entryTime = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep());
     137              :             assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
     138        60225 :             const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
     139        60225 :             const double fractionTimeOnDet = TS - timeBeforeEnter;
     140        60225 :             myCollector.enter(veh, entryTime - fractionTimeOnDet, fractionTimeOnDet, this);
     141              : #ifdef DEBUG_E3_NOTIFY_MOVE
     142              :             if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     143              :                 std::cout << "    enter\n";
     144              :             }
     145              : #endif
     146              :         }
     147              :     }
     148              :     return true;
     149              : }
     150              : 
     151              : 
     152              : bool
     153       239109 : MSE3Collector::MSE3EntryReminder::notifyLeave(SUMOTrafficObject& veh, double, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     154              : #ifdef DEBUG_E3_NOTIFY_LEAVE
     155              :     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     156              :         std::cout << SIMTIME
     157              :                   << " MSE3EntryReminder::notifyLeave() (" << getDescription() << " on lane '" << myLane->getID() << "')"
     158              :                   << " vehicle '" << veh.getID() << "'"
     159              :                   << " reason=" << reason
     160              :                   << "\n";
     161              :     }
     162              : #endif
     163       239109 :     if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
     164              : #ifdef HAVE_FOX
     165        20299 :         ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     166              : #endif
     167        20299 :         if (myCollector.myEnteredContainer.erase(&veh) > 0) {
     168        18724 :             if (!myCollector.myExpectArrival) {
     169        74160 :                 WRITE_WARNINGF("Vehicle '%' arrived inside % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID(), time2string(SIMSTEP));
     170              :             }
     171              :         }
     172              :         return false;
     173              :     }
     174              :     return true;
     175              : }
     176              : 
     177              : 
     178              : /* -------------------------------------------------------------------------
     179              :  * MSE3Collector::MSE3LeaveReminder - definitions
     180              :  * ----------------------------------------------------------------------- */
     181         1696 : MSE3Collector::MSE3LeaveReminder::MSE3LeaveReminder(
     182         1696 :     const MSCrossSection& crossSection, MSE3Collector& collector) :
     183         3392 :     MSMoveReminder(collector.getID() + "_exit", crossSection.myLane),
     184         3392 :     myCollector(collector), myPosition(crossSection.myPosition) {}
     185              : 
     186              : 
     187              : bool
     188        70942 : MSE3Collector::MSE3LeaveReminder::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane) {
     189              : #ifdef DEBUG_E3_NOTIFY_ENTER
     190              :     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     191              :         std::cout << SIMTIME
     192              :                   << " MSE3LeaveReminder::notifyEnter() (" << getDescription() << " on lane '" << myLane->getID() << "')"
     193              :                   << " vehicle '" << veh.getID() << "'"
     194              :                   << " enteredLane=" << enteredLane->getID()
     195              :                   << " reason=" << reason
     196              :                   << "\n";
     197              :     }
     198              : #endif
     199              :     // this method does not access containers, so no locking here
     200        70942 :     if (reason != NOTIFICATION_JUNCTION) {
     201        10397 :         const double backPosOnLane = veh.getBackPositionOnLane(enteredLane);
     202        10397 :         if (backPosOnLane > myPosition) {
     203              :             // if the vehicle changes into a covered section we assume it was already registered on another lane
     204              :             // however, if it is not fully past the detector we still need to track it
     205              : #ifdef DEBUG_E3_NOTIFY_ENTER
     206              :             if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     207              :                 std::cout << "  assume already known\n";
     208              :             }
     209              : #endif
     210              :             return false;
     211              :         }
     212              :     }
     213              :     return true;
     214              : }
     215              : 
     216              : 
     217              : bool
     218      5771516 : MSE3Collector::MSE3LeaveReminder::notifyMove(SUMOTrafficObject& veh, double oldPos,
     219              :         double newPos, double newSpeed) {
     220              : #ifdef DEBUG_E3_NOTIFY_MOVE
     221              :     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     222              :         std::cout << SIMTIME
     223              :                   << " MSE3LeaveReminder::notifyMove() (" << getDescription() << " on lane '" << myLane->getID() << "')"
     224              :                   << " vehicle '" << veh.getID() << "'"
     225              :                   << " entered. oldPos=" << oldPos << " newPos=" << newPos << " newSpeed=" << newSpeed
     226              :                   << " myPosition=" << myPosition
     227              :                   << "\n";
     228              :     }
     229              : #endif
     230      5771516 :     if (newPos < myPosition) {
     231              :         // crossSection not yet reached
     232              :         return true;
     233              :     }
     234              : #ifdef HAVE_FOX
     235       251519 :     ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     236              : #endif
     237       251519 :     const double oldSpeed = veh.getPreviousSpeed();
     238       251519 :     if (oldPos < myPosition) {
     239              :         assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
     240        66372 :         const double timeBeforeLeave = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
     241              : //        const double leaveTimeFront = SIMTIME - TS + (myPosition - oldPos) / newSpeed;
     242        66372 :         const double leaveTimeFront = SIMTIME - TS + timeBeforeLeave;
     243        66372 :         myCollector.leaveFront(veh, leaveTimeFront);
     244              : #ifdef DEBUG_E3_NOTIFY_MOVE
     245              :         if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     246              :             std::cout << "    leaveFront\n";
     247              :         }
     248              : #endif
     249              :     }
     250       251519 :     const double backPos = newPos - veh.getVehicleType().getLength();
     251       251519 :     if (backPos < myPosition) {
     252              :         // crossSection not yet left
     253              :         return true;
     254              :     }
     255              :     // crossSection left
     256        66336 :     const double oldBackPos = oldPos - veh.getVehicleType().getLength();
     257        66336 :     const double leaveStep = SIMTIME;
     258              :     assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
     259        66336 :     const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, backPos, oldSpeed, newSpeed);
     260        66336 :     myCollector.leave(veh, leaveStep - TS + timeBeforeLeave, timeBeforeLeave);
     261              : #ifdef DEBUG_E3_NOTIFY_MOVE
     262              :     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     263              :         std::cout << "    leave\n";
     264              :     }
     265              : #endif
     266              :     return false;
     267              : }
     268              : 
     269              : 
     270              : bool
     271        39557 : MSE3Collector::MSE3LeaveReminder::notifyLeave(SUMOTrafficObject&  veh, double /* lastPos */, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     272              : #ifdef DEBUG_E3_NOTIFY_LEAVE
     273              :     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     274              :         std::cout << SIMTIME
     275              :                   << " MSE3LeaveReminder::notifyLeave() (" << getDescription() << " on lane '" << myLane->getID() << "')"
     276              :                   << " vehicle '" << veh.getID() << "'"
     277              :                   << " reason=" << reason
     278              :                   << "\n";
     279              :     }
     280              : #endif
     281        39557 :     if (reason == MSMoveReminder::NOTIFICATION_LANE_CHANGE && &enteredLane->getEdge() == &myLane->getEdge()) {
     282              :         // keep the detector when changing while still on the exit detector but already on a new lane (#4803)
     283              : #ifdef DEBUG_E3_NOTIFY_LEAVE
     284              :         if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     285              :             std::cout << "  remove reminder, keep in container\n";
     286              :         }
     287              : #endif
     288              :         return false;
     289              :     }
     290              : #ifdef HAVE_FOX
     291        38452 :     ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     292              : #endif
     293        38452 :     if (reason == MSMoveReminder::NOTIFICATION_TELEPORT) {
     294          192 :         WRITE_WARNINGF("Vehicle '%' teleported from % '%'.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID());
     295           48 :         myCollector.myEnteredContainer.erase(&veh);
     296           48 :         return false;
     297              :     }
     298        38404 :     if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
     299         1266 :         if (myCollector.myEnteredContainer.erase(&veh) > 0) {
     300            0 :             if (!myCollector.myExpectArrival) {
     301            0 :                 WRITE_WARNINGF("Vehicle '%' arrived inside % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID(), time2string(SIMSTEP));
     302              :             }
     303              :         }
     304         1266 :         return false;
     305              :     }
     306              :     return true;
     307              : }
     308              : 
     309              : /* -------------------------------------------------------------------------
     310              :  * MSE3Collector - definitions
     311              :  * ----------------------------------------------------------------------- */
     312         1406 : MSE3Collector::MSE3Collector(const std::string& id,
     313              :                              const CrossSectionVector& entries,
     314              :                              const CrossSectionVector& exits,
     315              :                              double haltingSpeedThreshold,
     316              :                              SUMOTime haltingTimeThreshold,
     317              :                              const std::string name, const std::string& vTypes,
     318              :                              const std::string& nextEdges,
     319              :                              int detectPersons,
     320         1406 :                              bool openEntry, bool expectArrival) :
     321              :     MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
     322         1406 :     myName(name),
     323         1406 :     myEntries(entries),
     324         1406 :     myExits(exits),
     325         1406 :     myHaltingTimeThreshold(haltingTimeThreshold), myHaltingSpeedThreshold(haltingSpeedThreshold),
     326         1406 :     myCurrentMeanSpeed(0), myCurrentHaltingsNumber(0),
     327         1406 :     myLastMeanTravelTime(0), myLastMeanHaltsPerVehicle(0), myLastMeanTimeLoss(0), myLastVehicleSum(0),
     328         2812 :     myLastResetTime(-1), myOpenEntry(openEntry), myExpectArrival(expectArrival) {
     329              :     // Set MoveReminders to entries and exits
     330         3138 :     for (CrossSectionVectorConstIt crossSec1 = entries.begin(); crossSec1 != entries.end(); ++crossSec1) {
     331         1732 :         myEntryReminders.push_back(new MSE3EntryReminder(*crossSec1, *this));
     332              :     }
     333         3102 :     for (CrossSectionVectorConstIt crossSec2 = exits.begin(); crossSec2 != exits.end(); ++crossSec2) {
     334         1696 :         myLeaveReminders.push_back(new MSE3LeaveReminder(*crossSec2, *this));
     335              :     }
     336         1406 :     reset();
     337         1406 : }
     338              : 
     339              : 
     340         2648 : MSE3Collector::~MSE3Collector() {
     341         3138 :     for (std::vector<MSE3EntryReminder*>::iterator i = myEntryReminders.begin(); i != myEntryReminders.end(); ++i) {
     342         1732 :         delete *i;
     343              :     }
     344         3102 :     for (std::vector<MSE3LeaveReminder*>::iterator i = myLeaveReminders.begin(); i != myLeaveReminders.end(); ++i) {
     345         1696 :         delete *i;
     346              :     }
     347         4054 : }
     348              : 
     349              : 
     350              : void
     351         1406 : MSE3Collector::reset() {
     352              :     myLeftContainer.clear();
     353         1406 : }
     354              : 
     355              : 
     356              : 
     357              : void
     358        60587 : MSE3Collector::enter(const SUMOTrafficObject& veh, const double entryTimestep, const double fractionTimeOnDet, MSE3EntryReminder* entryReminder, bool isBackward) {
     359        60587 :     if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
     360           42 :         const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
     361           84 :         for (MSTransportable* p : v.getPersons()) {
     362           42 :             enter(*p, entryTimestep, fractionTimeOnDet, entryReminder);
     363              :         }
     364              :         return;
     365              :     }
     366        60545 :     if (!vehicleApplies(veh)) {
     367              :         return;
     368              :     }
     369        59507 :     if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
     370              :         // walking backward over an entry detector means "leaving"
     371              :         // std::cout << veh.getID() << " leave at entryDetector\n";
     372          320 :         leave(veh, entryTimestep, fractionTimeOnDet, true);
     373          320 :         return;
     374              :     }
     375        59187 :     if (myEnteredContainer.find(&veh) != myEnteredContainer.end()) {
     376            0 :         WRITE_WARNINGF("Vehicle '%' reentered % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
     377            0 :         return;
     378              :     }
     379              : #ifdef DEBUG_E3_NOTIFY_ENTER
     380              :     std::cout << veh.getID() << " enters\n";
     381              : #endif
     382        59187 :     const double speedFraction = veh.getSpeed() * fractionTimeOnDet;
     383              :     E3Values v;
     384              :     v.entryTime = entryTimestep;
     385              :     v.frontLeaveTime = 0;
     386              :     v.backLeaveTime = 0;
     387              :     v.speedSum = speedFraction;
     388        59187 :     v.haltingBegin = veh.getSpeed() < myHaltingSpeedThreshold ? TIME2STEPS(entryTimestep) : -1;
     389        59187 :     v.intervalSpeedSum = entryTimestep >= STEPS2TIME(myLastResetTime) ? speedFraction : 0;
     390              :     v.haltings = 0;
     391              :     v.intervalHaltings = 0;
     392        59187 :     if (veh.getSpeed() < myHaltingSpeedThreshold) {
     393         1405 :         if (TIME2STEPS(fractionTimeOnDet) > myHaltingTimeThreshold) {
     394              :             v.haltings++;
     395              :             v.intervalHaltings++;
     396              :         }
     397              :     }
     398              :     v.hadUpdate = false;
     399        59187 :     if (!MSGlobals::gUseMesoSim && veh.isVehicle()) {
     400        58045 :         v.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss();
     401              :         v.intervalTimeLoss = v.timeLoss;
     402              :     }
     403              :     v.entryReminder = entryReminder;
     404        59187 :     myEnteredContainer[&veh] = v;
     405              : }
     406              : 
     407              : 
     408              : void
     409        66414 : MSE3Collector::leaveFront(const SUMOTrafficObject& veh, const double leaveTimestep) {
     410        66414 :     if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
     411           42 :         const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
     412           84 :         for (MSTransportable* p : v.getPersons()) {
     413           42 :             leaveFront(*p, leaveTimestep);
     414              :         }
     415              :         return;
     416              :     }
     417        66372 :     if (!vehicleApplies(veh)) {
     418              :         return;
     419              :     }
     420        65682 :     if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
     421        27266 :         if (!myOpenEntry && veh.isVehicle()) {
     422        59784 :             WRITE_WARNINGF("Vehicle '%' left % '%' without entering it, time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
     423              :         }
     424              :     } else {
     425        38416 :         myEnteredContainer[&veh].frontLeaveTime = leaveTimestep;
     426              :     }
     427              : }
     428              : 
     429              : 
     430              : void
     431        66698 : MSE3Collector::leave(const SUMOTrafficObject& veh, const double leaveTimestep, const double fractionTimeOnDet, bool isBackward) {
     432        66698 :     if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
     433           42 :         const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
     434           84 :         for (MSTransportable* p : v.getPersons()) {
     435           42 :             leave(*p, leaveTimestep, fractionTimeOnDet);
     436              :         }
     437              :         return;
     438              :     }
     439        66656 :     if (!vehicleApplies(veh)) {
     440              :         return;
     441              :     }
     442        65882 :     if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
     443              :         // walking backward over an exit detector means "entering"
     444              :         // std::cout << veh.getID() << " enter at exitDetector\n";
     445          320 :         enter(veh, leaveTimestep, fractionTimeOnDet, nullptr, true);
     446          320 :         return;
     447              :     }
     448        65562 :     if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
     449        26938 :         if (!myOpenEntry && veh.isVehicle()) {
     450        59752 :             WRITE_WARNINGF("Vehicle '%' left % '%' without entering it, time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
     451              :         }
     452              :     } else {
     453              : #ifdef DEBUG_E3_NOTIFY_LEAVE
     454              :         std::cout << veh.getID() << " leaves\n";
     455              : #endif
     456        38624 :         E3Values values = myEnteredContainer[&veh];
     457        38624 :         values.backLeaveTime = leaveTimestep;
     458        38624 :         const double speedFraction = veh.getSpeed() * (TS - fractionTimeOnDet);
     459        38624 :         values.speedSum -= speedFraction;
     460        38624 :         values.intervalSpeedSum -= speedFraction;
     461        38624 :         if (MSGlobals::gUseMesoSim || !veh.isVehicle()) {
     462              :             // not yet supported
     463         1142 :             values.timeLoss = 0;
     464         1142 :             if (isBackward) {
     465              :                 // leaveFront may not have been called
     466          320 :                 values.frontLeaveTime = leaveTimestep;
     467              :             }
     468              :         } else {
     469              :             // timeLoss was initialized when entering
     470        37482 :             values.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss() - values.timeLoss;
     471              :         }
     472        38624 :         myEnteredContainer.erase(&veh);
     473        38624 :         myLeftContainer.push_back(values);
     474              :     }
     475              : }
     476              : 
     477              : 
     478              : void
     479       249274 : MSE3Collector::writeXMLOutput(OutputDevice& dev,
     480              :                               SUMOTime startTime, SUMOTime stopTime) {
     481       249274 :     dev.openTag(SUMO_TAG_INTERVAL).writeTime(SUMO_ATTR_BEGIN, startTime).writeTime(SUMO_ATTR_END, stopTime);
     482       249274 :     dev.writeAttr(SUMO_ATTR_ID, myID);
     483              :     // collect values about vehicles that have left the area
     484       249274 :     myLastVehicleSum = (int) myLeftContainer.size();
     485       249274 :     myLastMeanTravelTime = 0;
     486       249274 :     double meanOverlapTravelTime = 0.;
     487       249274 :     double meanSpeed = 0.;
     488       249274 :     myLastMeanHaltsPerVehicle = 0;
     489       249274 :     myLastMeanTimeLoss = 0.;
     490       287886 :     for (const E3Values& values : myLeftContainer) {
     491        38612 :         myLastMeanHaltsPerVehicle += (double)values.haltings;
     492        38612 :         myLastMeanTravelTime += values.frontLeaveTime - values.entryTime;
     493        38612 :         const double steps = values.backLeaveTime - values.entryTime;
     494        38612 :         meanOverlapTravelTime += steps;
     495        38612 :         meanSpeed += (values.speedSum / steps);
     496        38612 :         myLastMeanTimeLoss += STEPS2TIME(values.timeLoss);
     497              :     }
     498       249274 :     myLastMeanTravelTime = myLastVehicleSum != 0 ? myLastMeanTravelTime / (double)myLastVehicleSum : -1;
     499       249274 :     meanOverlapTravelTime = myLastVehicleSum != 0 ? meanOverlapTravelTime / (double)myLastVehicleSum : -1;
     500       249274 :     meanSpeed = myLastVehicleSum != 0 ? meanSpeed / (double)myLastVehicleSum : -1;
     501       249274 :     myLastMeanHaltsPerVehicle = myLastVehicleSum != 0 ? myLastMeanHaltsPerVehicle / (double) myLastVehicleSum : -1;
     502       249274 :     myLastMeanTimeLoss = myLastVehicleSum != 0 ? myLastMeanTimeLoss / (double) myLastVehicleSum : -1;
     503              :     // clear container
     504              :     myLeftContainer.clear();
     505              : 
     506              :     // collect values about vehicles within the container
     507       249274 :     const int vehicleSumWithin = (int) myEnteredContainer.size();
     508       249274 :     double meanSpeedWithin = 0.;
     509       249274 :     double meanDurationWithin = 0.;
     510       249274 :     double meanHaltsPerVehicleWithin = 0.;
     511       249274 :     double meanIntervalSpeedWithin = 0.;
     512       249274 :     double meanIntervalHaltsPerVehicleWithin = 0.;
     513       249274 :     double meanIntervalDurationWithin = 0.;
     514       249274 :     double meanTimeLossWithin = 0.;
     515      1644663 :     for (std::map<const SUMOTrafficObject*, E3Values>::iterator i = myEnteredContainer.begin(); i != myEnteredContainer.end(); ++i) {
     516      1395389 :         meanHaltsPerVehicleWithin += (double)(*i).second.haltings;
     517      1395389 :         meanIntervalHaltsPerVehicleWithin += (double)(*i).second.intervalHaltings;
     518      1395389 :         const double end = (*i).second.backLeaveTime == 0 ? STEPS2TIME(stopTime) : (*i).second.backLeaveTime;
     519      1395389 :         const double time = end - (*i).second.entryTime;
     520      1395389 :         const double timeWithin = MIN2(time, end - STEPS2TIME(startTime));
     521      1395389 :         if (i->second.speedSum > 0.) {
     522      1395389 :             meanSpeedWithin += i->second.speedSum / time;
     523              :         }
     524      1395389 :         if (i->second.intervalSpeedSum > 0.) {
     525       195405 :             meanIntervalSpeedWithin += i->second.intervalSpeedSum / timeWithin;
     526              :         }
     527      1395389 :         meanDurationWithin += time;
     528      1395389 :         meanIntervalDurationWithin += timeWithin;
     529              :         // reset interval values
     530      1395389 :         (*i).second.intervalHaltings = 0;
     531      1395389 :         (*i).second.intervalSpeedSum = 0;
     532              : 
     533      1395389 :         if (!MSGlobals::gUseMesoSim && i->first->isVehicle()) {
     534      1395325 :             const SUMOTime currentTimeLoss = dynamic_cast<const MSVehicle*>(i->first)->getTimeLoss();
     535      1395325 :             meanTimeLossWithin += STEPS2TIME(currentTimeLoss - (*i).second.intervalTimeLoss);
     536      1395325 :             (*i).second.intervalTimeLoss = currentTimeLoss;
     537              :         }
     538              :     }
     539       249274 :     myLastResetTime = stopTime;
     540       249274 :     meanSpeedWithin = vehicleSumWithin != 0 ?  meanSpeedWithin / (double) vehicleSumWithin : -1;
     541       249274 :     meanHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
     542       249274 :     meanDurationWithin = vehicleSumWithin != 0 ? meanDurationWithin / (double) vehicleSumWithin : -1;
     543       249274 :     meanIntervalSpeedWithin = vehicleSumWithin != 0 ?  meanIntervalSpeedWithin / (double) vehicleSumWithin : -1;
     544       249274 :     meanIntervalHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanIntervalHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
     545       249274 :     meanIntervalDurationWithin = vehicleSumWithin != 0 ? meanIntervalDurationWithin / (double) vehicleSumWithin : -1;
     546       249274 :     meanTimeLossWithin = vehicleSumWithin != 0 ? meanTimeLossWithin / (double) vehicleSumWithin : -1;
     547              : 
     548              :     // write values
     549       249274 :     dev.writeAttr("meanTravelTime", myLastMeanTravelTime)
     550       249274 :     .writeAttr("meanOverlapTravelTime", meanOverlapTravelTime)
     551       249274 :     .writeAttr("meanSpeed", meanSpeed)
     552       249274 :     .writeAttr("meanHaltsPerVehicle", myLastMeanHaltsPerVehicle)
     553       249274 :     .writeAttr("meanTimeLoss", myLastMeanTimeLoss)
     554       249274 :     .writeAttr("vehicleSum", myLastVehicleSum)
     555       249274 :     .writeAttr("meanSpeedWithin", meanSpeedWithin)
     556       249274 :     .writeAttr("meanHaltsPerVehicleWithin", meanHaltsPerVehicleWithin)
     557       249274 :     .writeAttr("meanDurationWithin", meanDurationWithin)
     558       249274 :     .writeAttr("vehicleSumWithin", vehicleSumWithin)
     559       249274 :     .writeAttr("meanIntervalSpeedWithin", meanIntervalSpeedWithin)
     560       249274 :     .writeAttr("meanIntervalHaltsPerVehicleWithin", meanIntervalHaltsPerVehicleWithin)
     561       249274 :     .writeAttr("meanIntervalDurationWithin", meanIntervalDurationWithin)
     562       249274 :     .writeAttr("meanTimeLossWithin", meanTimeLossWithin)
     563       249274 :     .closeTag();
     564       249274 : }
     565              : 
     566              : 
     567              : void
     568         1398 : MSE3Collector::writeXMLDetectorProlog(OutputDevice& dev) const {
     569         2796 :     dev.writeXMLHeader("e3Detector", "det_e3_file.xsd");
     570         1398 : }
     571              : 
     572              : 
     573              : void
     574       130928 : MSE3Collector::notifyMovePerson(MSTransportable* p, MSMoveReminder* rem, double detPos, int dir, double pos) {
     575       130928 :     if (personApplies(*p, dir)) {
     576        87280 :         const double newSpeed = p->getSpeed();
     577        87280 :         const double newPos = (dir == MSPModel::FORWARD
     578        87280 :                                ? pos
     579              :                                // position relative to detector end position
     580        21600 :                                : detPos - (pos - detPos));
     581        87280 :         const double oldPos = newPos - SPEED2DIST(newSpeed);
     582        87280 :         if (oldPos - p->getVehicleType().getLength() <= detPos) {
     583        48432 :             rem->notifyMove(*p, oldPos, newPos, newSpeed);
     584              :         }
     585              :     }
     586       130928 : }
     587              : 
     588              : 
     589              : void
     590      2532218 : MSE3Collector::detectorUpdate(const SUMOTime step) {
     591              : 
     592      2532218 :     if (myDetectPersons != (int)PersonMode::NONE) {
     593        39942 :         for (auto rem : myEntryReminders) {
     594              :             const MSLane* lane = rem->getLane();
     595        22524 :             if (lane->hasPedestrians()) {
     596       117636 :                 for (MSTransportable* p : lane->getEdge().getPersons()) {
     597       105544 :                     if (p->getLane() == lane && vehicleApplies(*p)) {
     598        65464 :                         notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
     599              :                     }
     600              :                 }
     601              :             }
     602              :         }
     603        39942 :         for (auto rem : myLeaveReminders) {
     604              :             const MSLane* lane = rem->getLane();
     605        22524 :             if (lane->hasPedestrians()) {
     606       117636 :                 for (MSTransportable* p : lane->getEdge().getPersons()) {
     607       105544 :                     if (p->getLane() == lane && vehicleApplies(*p)) {
     608        65464 :                         notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
     609              :                     }
     610              :                 }
     611              :             }
     612              :         }
     613              :     }
     614              : 
     615      2532218 :     myCurrentMeanSpeed = 0;
     616      2532218 :     myCurrentHaltingsNumber = 0;
     617      9626133 :     for (std::map<const SUMOTrafficObject*, E3Values>::iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
     618      7093915 :         const SUMOTrafficObject* veh = pair->first;
     619              : #ifdef DEBUG_E3_DETECTORUPDATE
     620              :         //if (DEBUG_COND(*this) && DEBUG_COND_VEH(*veh)) {
     621              :         if (DEBUG_COND(*this)) {
     622              :             std::cout << SIMTIME << " vehPtr=" << veh << "\n";
     623              :             std::cout << "       veh=" << veh->getID() << "\n";
     624              :         }
     625              : #endif
     626              :         E3Values& values = pair->second;
     627      7093915 :         myCurrentMeanSpeed += veh->getSpeed();
     628      7093915 :         values.hadUpdate = true;
     629      7093915 :         values.speedSum += veh->getSpeed() * TS;
     630      7093915 :         values.intervalSpeedSum += veh->getSpeed() * TS;
     631      7093915 :         if (veh->getSpeed() < myHaltingSpeedThreshold) {
     632      5606436 :             if (values.haltingBegin == -1) {
     633        58956 :                 values.haltingBegin = step;
     634              :             }
     635      5606436 :             SUMOTime haltingDuration = step - values.haltingBegin;
     636      5606436 :             if (haltingDuration >= myHaltingTimeThreshold
     637      5541542 :                     && haltingDuration < (myHaltingTimeThreshold + DELTA_T)) {
     638        54960 :                 values.haltings++;
     639        54960 :                 values.intervalHaltings++;
     640        54960 :                 myCurrentHaltingsNumber++;
     641              :             }
     642              :         } else {
     643      1487479 :             values.haltingBegin = -1;
     644              :         }
     645              :     }
     646      2532218 :     if (myEnteredContainer.size() == 0) {
     647      2045852 :         myCurrentMeanSpeed = -1;
     648              :     } else {
     649       486366 :         myCurrentMeanSpeed /= (double)myEnteredContainer.size();
     650              :     }
     651      2532218 : }
     652              : 
     653              : 
     654              : const CrossSectionVector&
     655          322 : MSE3Collector::getEntries() const {
     656          322 :     return myEntries;
     657              : }
     658              : 
     659              : 
     660              : const CrossSectionVector&
     661          322 : MSE3Collector::getExits() const {
     662          322 :     return myExits;
     663              : }
     664              : 
     665              : 
     666              : double
     667           55 : MSE3Collector::getCurrentMeanSpeed() const {
     668           55 :     return myCurrentMeanSpeed;
     669              : }
     670              : 
     671              : 
     672              : int
     673           13 : MSE3Collector::getCurrentHaltingNumber() const {
     674           13 :     return myCurrentHaltingsNumber;
     675              : }
     676              : 
     677              : 
     678              : int
     679          546 : MSE3Collector::getVehiclesWithin() const {
     680          546 :     return (int) myEnteredContainer.size();
     681              : }
     682              : 
     683              : 
     684              : std::vector<std::string>
     685          215 : MSE3Collector::getCurrentVehicleIDs() const {
     686              :     std::vector<std::string> ret;
     687          315 :     for (std::map<const SUMOTrafficObject*, E3Values>::const_iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
     688          100 :         ret.push_back((*pair).first->getID());
     689              :     }
     690          215 :     std::sort(ret.begin(), ret.end());
     691          215 :     return ret;
     692            0 : }
     693              : 
     694              : void
     695           17 : MSE3Collector::clearState(SUMOTime /* step */) {
     696              :     myEnteredContainer.clear();
     697              :     myLeftContainer.clear();
     698           17 : }
     699              : 
     700              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1