LCOV - code coverage report
Current view: top level - src/microsim/output - MSE3Collector.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 272 277 98.2 %
Date: 2024-05-06 15:32:35 Functions: 26 26 100.0 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
       4             : // This program and the accompanying materials are made available under the
       5             : // terms of the Eclipse Public License 2.0 which is available at
       6             : // https://www.eclipse.org/legal/epl-2.0/
       7             : // This Source Code may also be made available under the following Secondary
       8             : // Licenses when the conditions for such availability set forth in the Eclipse
       9             : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10             : // or later which is available at
      11             : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12             : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13             : /****************************************************************************/
      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        1679 : MSE3Collector::MSE3EntryReminder::MSE3EntryReminder(
      57        1679 :     const MSCrossSection& crossSection, MSE3Collector& collector) :
      58        3358 :     MSMoveReminder(collector.getID() + "_entry", crossSection.myLane),
      59        1679 :     myCollector(collector), myPosition(crossSection.myPosition) {
      60        1679 : }
      61             : 
      62             : 
      63             : bool
      64       61483 : 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       61483 :     if (reason != NOTIFICATION_JUNCTION) {
      76       32298 :         const double posOnLane = veh.getBackPositionOnLane(enteredLane) + veh.getVehicleType().getLength();
      77       32298 :         if (myLane == enteredLane && posOnLane > myPosition) {
      78             : #ifdef HAVE_FOX
      79        4346 :             ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
      80             : #endif
      81        4346 :             const auto& itVeh = myCollector.myEnteredContainer.find(&veh);
      82        4346 :             if (itVeh == myCollector.myEnteredContainer.end() ||
      83        3446 :                     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    12656565 : 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    12656565 :     ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     113             : #endif
     114    24792912 :     if ((myCollector.myEnteredContainer.find(&veh) == myCollector.myEnteredContainer.end() ||
     115    12141567 :             (veh.isPerson() && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD))
     116    12661653 :             && newPos > myPosition) {
     117       95247 :         if (oldPos > myPosition) {
     118             :             // was behind the detector already in the last step
     119             : #ifdef DEBUG_E3_NOTIFY_MOVE
     120             :             if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     121             :                 std::cout << "    already behind\n";
     122             :             }
     123             : #endif
     124             :             return false;
     125             :         } else {
     126             :             // entered in this step
     127       50102 :             const double oldSpeed = veh.getPreviousSpeed();
     128       50102 :             const double entryTime = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep());
     129             :             assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
     130       50102 :             const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
     131       50102 :             const double fractionTimeOnDet = TS - timeBeforeEnter;
     132       50102 :             myCollector.enter(veh, entryTime - fractionTimeOnDet, fractionTimeOnDet, this);
     133             : #ifdef DEBUG_E3_NOTIFY_MOVE
     134             :             if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     135             :                 std::cout << "    enter\n";
     136             :             }
     137             : #endif
     138             :         }
     139             :     }
     140             :     return true;
     141             : }
     142             : 
     143             : 
     144             : bool
     145      242499 : MSE3Collector::MSE3EntryReminder::notifyLeave(SUMOTrafficObject& veh, double, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     146             : #ifdef DEBUG_E3_NOTIFY_LEAVE
     147             :     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     148             :         std::cout << SIMTIME
     149             :                   << " MSE3EntryReminder::notifyLeave() (" << getDescription() << "on lane '" << myLane->getID() << "')"
     150             :                   << " vehicle '" << veh.getID() << "'"
     151             :                   << " reason=" << reason
     152             :                   << "\n";
     153             :     }
     154             : #endif
     155      242499 :     if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
     156             : #ifdef HAVE_FOX
     157        3103 :         ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     158             : #endif
     159        3103 :         if (myCollector.myEnteredContainer.erase(&veh) > 0) {
     160         909 :             if (!myCollector.myExpectArrival) {
     161        4215 :                 WRITE_WARNINGF("Vehicle '%' arrived inside % '%'.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID());
     162             :             }
     163             :         }
     164             :         return false;
     165             :     }
     166             :     return true;
     167             : }
     168             : 
     169             : 
     170             : /* -------------------------------------------------------------------------
     171             :  * MSE3Collector::MSE3LeaveReminder - definitions
     172             :  * ----------------------------------------------------------------------- */
     173        1643 : MSE3Collector::MSE3LeaveReminder::MSE3LeaveReminder(
     174        1643 :     const MSCrossSection& crossSection, MSE3Collector& collector) :
     175        3286 :     MSMoveReminder(collector.getID() + "_exit", crossSection.myLane),
     176        3286 :     myCollector(collector), myPosition(crossSection.myPosition) {}
     177             : 
     178             : 
     179             : bool
     180       66458 : MSE3Collector::MSE3LeaveReminder::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane) {
     181             : #ifdef DEBUG_E3_NOTIFY_ENTER
     182             :     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     183             :         std::cout << SIMTIME
     184             :                   << " MSE3LeaveReminder::notifyEnter() (" << getDescription() << "on lane '" << myLane->getID() << "')"
     185             :                   << " vehicle '" << veh.getID() << "'"
     186             :                   << " enteredLane=" << enteredLane->getID()
     187             :                   << " reason=" << reason
     188             :                   << "\n";
     189             :     }
     190             : #endif
     191             :     // this method does not access containers, so no locking here
     192       66458 :     if (reason != NOTIFICATION_JUNCTION) {
     193        7641 :         const double backPosOnLane = veh.getBackPositionOnLane(enteredLane);
     194        7641 :         if (backPosOnLane > myPosition) {
     195             :             // if the vehicle changes into a covered section we assume it was already registered on another lane
     196             :             // however, if it is not fully past the detector we still need to track it
     197             : #ifdef DEBUG_E3_NOTIFY_ENTER
     198             :             if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     199             :                 std::cout << "  assume already known\n";
     200             :             }
     201             : #endif
     202         180 :             return false;
     203             :         }
     204             :     }
     205             :     return true;
     206             : }
     207             : 
     208             : 
     209             : bool
     210    10394225 : MSE3Collector::MSE3LeaveReminder::notifyMove(SUMOTrafficObject& veh, double oldPos,
     211             :         double newPos, double newSpeed) {
     212             : #ifdef DEBUG_E3_NOTIFY_MOVE
     213             :     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     214             :         std::cout << SIMTIME
     215             :                   << " MSE3LeaveReminder::notifyMove() (" << getDescription() << " on lane '" << myLane->getID() << "')"
     216             :                   << " vehicle '" << veh.getID() << "'"
     217             :                   << " entered. oldPos=" << oldPos << " newPos=" << newPos << " newSpeed=" << newSpeed
     218             :                   << " myPosition=" << myPosition
     219             :                   << "\n";
     220             :     }
     221             : #endif
     222    10394225 :     if (newPos < myPosition) {
     223             :         // crossSection not yet reached
     224             :         return true;
     225             :     }
     226             : #ifdef HAVE_FOX
     227      373130 :     ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     228             : #endif
     229      373130 :     const double oldSpeed = veh.getPreviousSpeed();
     230      373130 :     if (oldPos < myPosition) {
     231             :         assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
     232       60161 :         const double timeBeforeLeave = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
     233             : //        const double leaveTimeFront = SIMTIME - TS + (myPosition - oldPos) / newSpeed;
     234       60161 :         const double leaveTimeFront = SIMTIME - TS + timeBeforeLeave;
     235       60161 :         myCollector.leaveFront(veh, leaveTimeFront);
     236             : #ifdef DEBUG_E3_NOTIFY_MOVE
     237             :         if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     238             :             std::cout << "    leaveFront\n";
     239             :         }
     240             : #endif
     241             :     }
     242      373130 :     const double backPos = newPos - veh.getVehicleType().getLength();
     243      373130 :     if (backPos < myPosition) {
     244             :         // crossSection not yet left
     245             :         return true;
     246             :     }
     247             :     // crossSection left
     248       60206 :     const double oldBackPos = oldPos - veh.getVehicleType().getLength();
     249       60206 :     const double leaveStep = SIMTIME;
     250             :     assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
     251       60206 :     const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, backPos, oldSpeed, newSpeed);
     252       60206 :     myCollector.leave(veh, leaveStep - TS + timeBeforeLeave, timeBeforeLeave);
     253             : #ifdef DEBUG_E3_NOTIFY_MOVE
     254             :     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     255             :         std::cout << "    leave\n";
     256             :     }
     257             : #endif
     258             :     return false;
     259             : }
     260             : 
     261             : 
     262             : bool
     263       36527 : MSE3Collector::MSE3LeaveReminder::notifyLeave(SUMOTrafficObject&  veh, double /* lastPos */, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     264             : #ifdef DEBUG_E3_NOTIFY_LEAVE
     265             :     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     266             :         std::cout << SIMTIME
     267             :                   << " MSE3LeaveReminder::notifyLeave() (" << getDescription() << "on lane '" << myLane->getID() << "')"
     268             :                   << " vehicle '" << veh.getID() << "'"
     269             :                   << " reason=" << reason
     270             :                   << "\n";
     271             :     }
     272             : #endif
     273       36527 :     if (reason == MSMoveReminder::NOTIFICATION_LANE_CHANGE && &enteredLane->getEdge() == &myLane->getEdge()) {
     274             :         // keep the detector when changing while still on the exit detector but already on a new lane (#4803)
     275             : #ifdef DEBUG_E3_NOTIFY_LEAVE
     276             :         if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
     277             :             std::cout << "  remove reminder, keep in container\n";
     278             :         }
     279             : #endif
     280             :         return false;
     281             :     }
     282             : #ifdef HAVE_FOX
     283       35360 :     ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     284             : #endif
     285       35360 :     if (reason == MSMoveReminder::NOTIFICATION_TELEPORT) {
     286         384 :         WRITE_WARNINGF("Vehicle '%' teleported from % '%'.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID());
     287          96 :         myCollector.myEnteredContainer.erase(&veh);
     288          96 :         return false;
     289             :     }
     290       35264 :     if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
     291        1325 :         if (myCollector.myEnteredContainer.erase(&veh) > 0) {
     292           0 :             if (!myCollector.myExpectArrival) {
     293           0 :                 WRITE_WARNINGF("Vehicle '%' arrived inside % '%'.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID());
     294             :             }
     295             :         }
     296        1325 :         return false;
     297             :     }
     298             :     return true;
     299             : }
     300             : 
     301             : /* -------------------------------------------------------------------------
     302             :  * MSE3Collector - definitions
     303             :  * ----------------------------------------------------------------------- */
     304        1400 : MSE3Collector::MSE3Collector(const std::string& id,
     305             :                              const CrossSectionVector& entries,
     306             :                              const CrossSectionVector& exits,
     307             :                              double haltingSpeedThreshold,
     308             :                              SUMOTime haltingTimeThreshold,
     309             :                              const std::string name, const std::string& vTypes,
     310             :                              const std::string& nextEdges,
     311             :                              int detectPersons,
     312        1400 :                              bool openEntry, bool expectArrival) :
     313             :     MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
     314        1400 :     myName(name),
     315        1400 :     myEntries(entries),
     316        1400 :     myExits(exits),
     317        1400 :     myHaltingTimeThreshold(haltingTimeThreshold), myHaltingSpeedThreshold(haltingSpeedThreshold),
     318        1400 :     myCurrentMeanSpeed(0), myCurrentHaltingsNumber(0),
     319        1400 :     myLastMeanTravelTime(0), myLastMeanHaltsPerVehicle(0), myLastMeanTimeLoss(0), myLastVehicleSum(0),
     320        2800 :     myLastResetTime(-1), myOpenEntry(openEntry), myExpectArrival(expectArrival) {
     321             :     // Set MoveReminders to entries and exits
     322        3079 :     for (CrossSectionVectorConstIt crossSec1 = entries.begin(); crossSec1 != entries.end(); ++crossSec1) {
     323        1679 :         myEntryReminders.push_back(new MSE3EntryReminder(*crossSec1, *this));
     324             :     }
     325        3043 :     for (CrossSectionVectorConstIt crossSec2 = exits.begin(); crossSec2 != exits.end(); ++crossSec2) {
     326        1643 :         myLeaveReminders.push_back(new MSE3LeaveReminder(*crossSec2, *this));
     327             :     }
     328        1400 :     reset();
     329        1400 : }
     330             : 
     331             : 
     332        2638 : MSE3Collector::~MSE3Collector() {
     333        3079 :     for (std::vector<MSE3EntryReminder*>::iterator i = myEntryReminders.begin(); i != myEntryReminders.end(); ++i) {
     334        1679 :         delete *i;
     335             :     }
     336        3043 :     for (std::vector<MSE3LeaveReminder*>::iterator i = myLeaveReminders.begin(); i != myLeaveReminders.end(); ++i) {
     337        1643 :         delete *i;
     338             :     }
     339        4038 : }
     340             : 
     341             : 
     342             : void
     343        1400 : MSE3Collector::reset() {
     344             :     myLeftContainer.clear();
     345        1400 : }
     346             : 
     347             : 
     348             : 
     349             : void
     350       50452 : MSE3Collector::enter(const SUMOTrafficObject& veh, const double entryTimestep, const double fractionTimeOnDet, MSE3EntryReminder* entryReminder, bool isBackward) {
     351       50452 :     if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
     352          30 :         const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
     353          60 :         for (MSTransportable* p : v.getPersons()) {
     354          30 :             enter(*p, entryTimestep, fractionTimeOnDet, entryReminder);
     355             :         }
     356             :         return;
     357             :     }
     358       50422 :     if (!vehicleApplies(veh)) {
     359             :         return;
     360             :     }
     361       49378 :     if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
     362             :         // walking backward over an entry detector means "leaving"
     363             :         // std::cout << veh.getID() << " leave at entryDetector\n";
     364         320 :         leave(veh, entryTimestep, fractionTimeOnDet, true);
     365         320 :         return;
     366             :     }
     367       49058 :     if (myEnteredContainer.find(&veh) != myEnteredContainer.end()) {
     368           0 :         WRITE_WARNINGF("Vehicle '%' reentered % '%'.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID());
     369           0 :         return;
     370             :     }
     371             : #ifdef DEBUG_E3_NOTIFY_ENTER
     372             :     std::cout << veh.getID() << " enters\n";
     373             : #endif
     374       49058 :     const double speedFraction = veh.getSpeed() * fractionTimeOnDet;
     375             :     E3Values v;
     376             :     v.entryTime = entryTimestep;
     377             :     v.frontLeaveTime = 0;
     378             :     v.backLeaveTime = 0;
     379             :     v.speedSum = speedFraction;
     380       49058 :     v.haltingBegin = veh.getSpeed() < myHaltingSpeedThreshold ? TIME2STEPS(entryTimestep) : -1;
     381       49058 :     v.intervalSpeedSum = entryTimestep >= STEPS2TIME(myLastResetTime) ? speedFraction : 0;
     382             :     v.haltings = 0;
     383             :     v.intervalHaltings = 0;
     384       49058 :     if (veh.getSpeed() < myHaltingSpeedThreshold) {
     385        1752 :         if (TIME2STEPS(fractionTimeOnDet) > myHaltingTimeThreshold) {
     386             :             v.haltings++;
     387             :             v.intervalHaltings++;
     388             :         }
     389             :     }
     390             :     v.hadUpdate = false;
     391       49058 :     if (!MSGlobals::gUseMesoSim && veh.isVehicle()) {
     392       47928 :         v.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss();
     393             :         v.intervalTimeLoss = v.timeLoss;
     394             :     }
     395             :     v.entryReminder = entryReminder;
     396       49058 :     myEnteredContainer[&veh] = v;
     397             : }
     398             : 
     399             : 
     400             : void
     401       60191 : MSE3Collector::leaveFront(const SUMOTrafficObject& veh, const double leaveTimestep) {
     402       60191 :     if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
     403          30 :         const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
     404          60 :         for (MSTransportable* p : v.getPersons()) {
     405          30 :             leaveFront(*p, leaveTimestep);
     406             :         }
     407             :         return;
     408             :     }
     409       60161 :     if (!vehicleApplies(veh)) {
     410             :         return;
     411             :     }
     412       59111 :     if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
     413       14481 :         if (!myOpenEntry && veh.isVehicle()) {
     414       10421 :             WRITE_WARNINGF("Vehicle '%' left % '%' without entering it.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID());
     415             :         }
     416             :     } else {
     417       44630 :         myEnteredContainer[&veh].frontLeaveTime = leaveTimestep;
     418             :     }
     419             : }
     420             : 
     421             : 
     422             : void
     423       60556 : MSE3Collector::leave(const SUMOTrafficObject& veh, const double leaveTimestep, const double fractionTimeOnDet, bool isBackward) {
     424       60556 :     if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
     425          30 :         const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
     426          60 :         for (MSTransportable* p : v.getPersons()) {
     427          30 :             leave(*p, leaveTimestep, fractionTimeOnDet);
     428             :         }
     429             :         return;
     430             :     }
     431       60526 :     if (!vehicleApplies(veh)) {
     432             :         return;
     433             :     }
     434       59392 :     if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
     435             :         // walking backward over an exit detector means "entering"
     436             :         // std::cout << veh.getID() << " enter at exitDetector\n";
     437         320 :         enter(veh, leaveTimestep, fractionTimeOnDet, nullptr, true);
     438         320 :         return;
     439             :     }
     440       59072 :     if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
     441       14152 :         if (!myOpenEntry && veh.isVehicle()) {
     442       10392 :             WRITE_WARNINGF("Vehicle '%' left % '%' without entering it.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID());
     443             :         }
     444             :     } else {
     445             : #ifdef DEBUG_E3_NOTIFY_LEAVE
     446             :         std::cout << veh.getID() << " leaves\n";
     447             : #endif
     448       44920 :         E3Values values = myEnteredContainer[&veh];
     449       44920 :         values.backLeaveTime = leaveTimestep;
     450       44920 :         const double speedFraction = veh.getSpeed() * (TS - fractionTimeOnDet);
     451       44920 :         values.speedSum -= speedFraction;
     452       44920 :         values.intervalSpeedSum -= speedFraction;
     453       44920 :         if (MSGlobals::gUseMesoSim || !veh.isVehicle()) {
     454             :             // not yet supported
     455        1130 :             values.timeLoss = 0;
     456        1130 :             if (isBackward) {
     457             :                 // leaveFront may not have been called
     458         320 :                 values.frontLeaveTime = leaveTimestep;
     459             :             }
     460             :         } else {
     461             :             // timeLoss was initialized when entering
     462       43790 :             values.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss() - values.timeLoss;
     463             :         }
     464       44920 :         myEnteredContainer.erase(&veh);
     465       44920 :         myLeftContainer.push_back(values);
     466             :     }
     467             : }
     468             : 
     469             : 
     470             : void
     471      483491 : MSE3Collector::writeXMLOutput(OutputDevice& dev,
     472             :                               SUMOTime startTime, SUMOTime stopTime) {
     473      966982 :     dev << "   <interval begin=\"" << time2string(startTime) << "\" end=\"" << time2string(stopTime) << "\" " << "id=\"" << myID << "\" ";
     474             :     // collect values about vehicles that have left the area
     475      483491 :     myLastVehicleSum = (int) myLeftContainer.size();
     476      483491 :     myLastMeanTravelTime = 0;
     477      483491 :     double meanOverlapTravelTime = 0.;
     478      483491 :     double meanSpeed = 0.;
     479      483491 :     myLastMeanHaltsPerVehicle = 0;
     480      483491 :     myLastMeanTimeLoss = 0.;
     481      528393 :     for (const E3Values& values : myLeftContainer) {
     482       44902 :         myLastMeanHaltsPerVehicle += (double)values.haltings;
     483       44902 :         myLastMeanTravelTime += values.frontLeaveTime - values.entryTime;
     484       44902 :         const double steps = values.backLeaveTime - values.entryTime;
     485       44902 :         meanOverlapTravelTime += steps;
     486       44902 :         meanSpeed += (values.speedSum / steps);
     487       44902 :         myLastMeanTimeLoss += STEPS2TIME(values.timeLoss);
     488             :     }
     489      483491 :     myLastMeanTravelTime = myLastVehicleSum != 0 ? myLastMeanTravelTime / (double)myLastVehicleSum : -1;
     490      483491 :     meanOverlapTravelTime = myLastVehicleSum != 0 ? meanOverlapTravelTime / (double)myLastVehicleSum : -1;
     491      483491 :     meanSpeed = myLastVehicleSum != 0 ? meanSpeed / (double)myLastVehicleSum : -1;
     492      483491 :     myLastMeanHaltsPerVehicle = myLastVehicleSum != 0 ? myLastMeanHaltsPerVehicle / (double) myLastVehicleSum : -1;
     493      483491 :     myLastMeanTimeLoss = myLastVehicleSum != 0 ? myLastMeanTimeLoss / (double) myLastVehicleSum : -1;
     494             :     // clear container
     495             :     myLeftContainer.clear();
     496             : 
     497             :     // collect values about vehicles within the container
     498      483491 :     const int vehicleSumWithin = (int) myEnteredContainer.size();
     499      483491 :     double meanSpeedWithin = 0.;
     500      483491 :     double meanDurationWithin = 0.;
     501      483491 :     double meanHaltsPerVehicleWithin = 0.;
     502      483491 :     double meanIntervalSpeedWithin = 0.;
     503      483491 :     double meanIntervalHaltsPerVehicleWithin = 0.;
     504      483491 :     double meanIntervalDurationWithin = 0.;
     505      483491 :     double meanTimeLossWithin = 0.;
     506     3268500 :     for (std::map<const SUMOTrafficObject*, E3Values>::iterator i = myEnteredContainer.begin(); i != myEnteredContainer.end(); ++i) {
     507     2785009 :         meanHaltsPerVehicleWithin += (double)(*i).second.haltings;
     508     2785009 :         meanIntervalHaltsPerVehicleWithin += (double)(*i).second.intervalHaltings;
     509     2785009 :         const double end = (*i).second.backLeaveTime == 0 ? STEPS2TIME(stopTime) : (*i).second.backLeaveTime;
     510     2785009 :         const double time = end - (*i).second.entryTime;
     511     2785009 :         const double timeWithin = MIN2(time, end - STEPS2TIME(startTime));
     512     2785009 :         if (i->second.speedSum > 0.) {
     513     2785009 :             meanSpeedWithin += i->second.speedSum / time;
     514             :         }
     515     2785009 :         if (i->second.intervalSpeedSum > 0.) {
     516      385041 :             meanIntervalSpeedWithin += i->second.intervalSpeedSum / timeWithin;
     517             :         }
     518     2785009 :         meanDurationWithin += time;
     519     2785009 :         meanIntervalDurationWithin += timeWithin;
     520             :         // reset interval values
     521     2785009 :         (*i).second.intervalHaltings = 0;
     522     2785009 :         (*i).second.intervalSpeedSum = 0;
     523             : 
     524     2785009 :         if (!MSGlobals::gUseMesoSim && i->first->isVehicle()) {
     525     2784945 :             const SUMOTime currentTimeLoss = dynamic_cast<const MSVehicle*>(i->first)->getTimeLoss();
     526     2784945 :             meanTimeLossWithin += STEPS2TIME(currentTimeLoss - (*i).second.intervalTimeLoss);
     527     2784945 :             (*i).second.intervalTimeLoss = currentTimeLoss;
     528             :         }
     529             :     }
     530      483491 :     myLastResetTime = stopTime;
     531      483491 :     meanSpeedWithin = vehicleSumWithin != 0 ?  meanSpeedWithin / (double) vehicleSumWithin : -1;
     532      483491 :     meanHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
     533      483491 :     meanDurationWithin = vehicleSumWithin != 0 ? meanDurationWithin / (double) vehicleSumWithin : -1;
     534      483491 :     meanIntervalSpeedWithin = vehicleSumWithin != 0 ?  meanIntervalSpeedWithin / (double) vehicleSumWithin : -1;
     535      483491 :     meanIntervalHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanIntervalHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
     536      483491 :     meanIntervalDurationWithin = vehicleSumWithin != 0 ? meanIntervalDurationWithin / (double) vehicleSumWithin : -1;
     537      483491 :     meanTimeLossWithin = vehicleSumWithin != 0 ? meanTimeLossWithin / (double) vehicleSumWithin : -1;
     538             : 
     539             :     // write values
     540      483491 :     dev << "meanTravelTime=\"" << myLastMeanTravelTime
     541      483491 :         << "\" meanOverlapTravelTime=\"" << meanOverlapTravelTime
     542      483491 :         << "\" meanSpeed=\"" << meanSpeed
     543      483491 :         << "\" meanHaltsPerVehicle=\"" << myLastMeanHaltsPerVehicle
     544      483491 :         << "\" meanTimeLoss=\"" << myLastMeanTimeLoss
     545      483491 :         << "\" vehicleSum=\"" << myLastVehicleSum
     546      483491 :         << "\" meanSpeedWithin=\"" << meanSpeedWithin
     547      483491 :         << "\" meanHaltsPerVehicleWithin=\"" << meanHaltsPerVehicleWithin
     548      483491 :         << "\" meanDurationWithin=\"" << meanDurationWithin
     549      483491 :         << "\" vehicleSumWithin=\"" << vehicleSumWithin
     550      483491 :         << "\" meanIntervalSpeedWithin=\"" << meanIntervalSpeedWithin
     551      483491 :         << "\" meanIntervalHaltsPerVehicleWithin=\"" << meanIntervalHaltsPerVehicleWithin
     552      483491 :         << "\" meanIntervalDurationWithin=\"" << meanIntervalDurationWithin
     553      483491 :         << "\" meanTimeLossWithin=\"" << meanTimeLossWithin
     554      483491 :         << "\"/>\n";
     555      483491 : }
     556             : 
     557             : 
     558             : void
     559        1392 : MSE3Collector::writeXMLDetectorProlog(OutputDevice& dev) const {
     560        2784 :     dev.writeXMLHeader("e3Detector", "det_e3_file.xsd");
     561        1392 : }
     562             : 
     563             : 
     564             : void
     565      125472 : MSE3Collector::notifyMovePerson(MSTransportable* p, MSMoveReminder* rem, double detPos, int dir, double pos) {
     566      125472 :     if (personApplies(*p, dir)) {
     567       87280 :         const double newSpeed = p->getSpeed();
     568       87280 :         const double newPos = (dir == MSPModel::FORWARD
     569       87280 :                                ? pos
     570             :                                // position relative to detector end position
     571       21600 :                                : detPos - (pos - detPos));
     572       87280 :         const double oldPos = newPos - SPEED2DIST(newSpeed);
     573       87280 :         if (oldPos - p->getVehicleType().getLength() <= detPos) {
     574       48432 :             rem->notifyMove(*p, oldPos, newPos, newSpeed);
     575             :         }
     576             :     }
     577      125472 : }
     578             : 
     579             : 
     580             : void
     581     2325249 : MSE3Collector::detectorUpdate(const SUMOTime step) {
     582             : 
     583     2325249 :     if (myDetectPersons != (int)PersonMode::NONE) {
     584       38079 :         for (auto rem : myEntryReminders) {
     585             :             const MSLane* lane = rem->getLane();
     586       21282 :             if (lane->hasPedestrians()) {
     587      114648 :                 for (MSTransportable* p : lane->getEdge().getPersons()) {
     588      102816 :                     if (p->getLane() == lane && vehicleApplies(*p)) {
     589       62736 :                         notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
     590             :                     }
     591             :                 }
     592             :             }
     593             :         }
     594       38079 :         for (auto rem : myLeaveReminders) {
     595             :             const MSLane* lane = rem->getLane();
     596       21282 :             if (lane->hasPedestrians()) {
     597      114648 :                 for (MSTransportable* p : lane->getEdge().getPersons()) {
     598      102816 :                     if (p->getLane() == lane && vehicleApplies(*p)) {
     599       62736 :                         notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
     600             :                     }
     601             :                 }
     602             :             }
     603             :         }
     604             :     }
     605             : 
     606     2325249 :     myCurrentMeanSpeed = 0;
     607     2325249 :     myCurrentHaltingsNumber = 0;
     608    14327443 :     for (std::map<const SUMOTrafficObject*, E3Values>::iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
     609    12002194 :         const SUMOTrafficObject* veh = pair->first;
     610             : #ifdef DEBUG_E3_DETECTORUPDATE
     611             :         //if (DEBUG_COND(*this) && DEBUG_COND_VEH(*veh)) {
     612             :         if (DEBUG_COND(*this)) {
     613             :             std::cout << SIMTIME << " vehPtr=" << veh << "\n";
     614             :             std::cout << "       veh=" << veh->getID() << "\n";
     615             :         }
     616             : #endif
     617             :         E3Values& values = pair->second;
     618    12002194 :         myCurrentMeanSpeed += veh->getSpeed();
     619    12002194 :         values.hadUpdate = true;
     620    12002194 :         values.speedSum += veh->getSpeed() * TS;
     621    12002194 :         values.intervalSpeedSum += veh->getSpeed() * TS;
     622    12002194 :         if (veh->getSpeed() < myHaltingSpeedThreshold) {
     623     9875751 :             if (values.haltingBegin == -1) {
     624       66564 :                 values.haltingBegin = step;
     625             :             }
     626     9875751 :             SUMOTime haltingDuration = step - values.haltingBegin;
     627     9875751 :             if (haltingDuration >= myHaltingTimeThreshold
     628     9792402 :                     && haltingDuration < (myHaltingTimeThreshold + DELTA_T)) {
     629       62054 :                 values.haltings++;
     630       62054 :                 values.intervalHaltings++;
     631       62054 :                 myCurrentHaltingsNumber++;
     632             :             }
     633             :         } else {
     634     2126443 :             values.haltingBegin = -1;
     635             :         }
     636             :     }
     637     2325249 :     if (myEnteredContainer.size() == 0) {
     638     1522805 :         myCurrentMeanSpeed = -1;
     639             :     } else {
     640      802444 :         myCurrentMeanSpeed /= (double)myEnteredContainer.size();
     641             :     }
     642     2325249 : }
     643             : 
     644             : 
     645             : const CrossSectionVector&
     646         197 : MSE3Collector::getEntries() const {
     647         197 :     return myEntries;
     648             : }
     649             : 
     650             : 
     651             : const CrossSectionVector&
     652         197 : MSE3Collector::getExits() const {
     653         197 :     return myExits;
     654             : }
     655             : 
     656             : 
     657             : double
     658          48 : MSE3Collector::getCurrentMeanSpeed() const {
     659          48 :     return myCurrentMeanSpeed;
     660             : }
     661             : 
     662             : 
     663             : int
     664           6 : MSE3Collector::getCurrentHaltingNumber() const {
     665           6 :     return myCurrentHaltingsNumber;
     666             : }
     667             : 
     668             : 
     669             : int
     670         726 : MSE3Collector::getVehiclesWithin() const {
     671         726 :     return (int) myEnteredContainer.size();
     672             : }
     673             : 
     674             : 
     675             : std::vector<std::string>
     676         288 : MSE3Collector::getCurrentVehicleIDs() const {
     677             :     std::vector<std::string> ret;
     678         426 :     for (std::map<const SUMOTrafficObject*, E3Values>::const_iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
     679         138 :         ret.push_back((*pair).first->getID());
     680             :     }
     681         288 :     std::sort(ret.begin(), ret.end());
     682         288 :     return ret;
     683           0 : }
     684             : 
     685             : void
     686          24 : MSE3Collector::clearState(SUMOTime /* step */) {
     687             :     myEnteredContainer.clear();
     688             :     myLeftContainer.clear();
     689          24 : }
     690             : 
     691             : /****************************************************************************/

Generated by: LCOV version 1.14