LCOV - code coverage report
Current view: top level - src/microsim/output - MSE3Collector.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 98.2 % 276 271
Test Date: 2024-12-21 15:45:41 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-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         1721 : MSE3Collector::MSE3EntryReminder::MSE3EntryReminder(
      57         1721 :     const MSCrossSection& crossSection, MSE3Collector& collector) :
      58         3442 :     MSMoveReminder(collector.getID() + "_entry", crossSection.myLane),
      59         1721 :     myCollector(collector), myPosition(crossSection.myPosition) {
      60         1721 : }
      61              : 
      62              : 
      63              : bool
      64        72162 : 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        72162 :     if (reason != NOTIFICATION_JUNCTION) {
      76        33996 :         const double posOnLane = veh.getBackPositionOnLane(enteredLane) + veh.getVehicleType().getLength();
      77        33996 :         if (myLane == enteredLane && posOnLane > myPosition) {
      78              : #ifdef HAVE_FOX
      79         3446 :             ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
      80              : #endif
      81         3446 :             const auto& itVeh = myCollector.myEnteredContainer.find(&veh);
      82         3446 :             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      7965087 : 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      7965087 :     ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     113              : #endif
     114     15399635 :     if ((myCollector.myEnteredContainer.find(&veh) == myCollector.myEnteredContainer.end() ||
     115      7439768 :             (veh.isPerson() && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD))
     116      7970175 :             && newPos > myPosition) {
     117       100333 :         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        61872 :             const double oldSpeed = veh.getPreviousSpeed();
     128        61872 :             const double entryTime = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep());
     129              :             assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
     130        61872 :             const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
     131        61872 :             const double fractionTimeOnDet = TS - timeBeforeEnter;
     132        61872 :             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       240583 : 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       240583 :     if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
     156              : #ifdef HAVE_FOX
     157        22843 :         ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     158              : #endif
     159        22843 :         if (myCollector.myEnteredContainer.erase(&veh) > 0) {
     160        21095 :             if (!myCollector.myExpectArrival) {
     161        83648 :                 WRITE_WARNINGF("Vehicle '%' arrived inside % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID(), time2string(SIMSTEP));
     162              :             }
     163              :         }
     164              :         return false;
     165              :     }
     166              :     return true;
     167              : }
     168              : 
     169              : 
     170              : /* -------------------------------------------------------------------------
     171              :  * MSE3Collector::MSE3LeaveReminder - definitions
     172              :  * ----------------------------------------------------------------------- */
     173         1685 : MSE3Collector::MSE3LeaveReminder::MSE3LeaveReminder(
     174         1685 :     const MSCrossSection& crossSection, MSE3Collector& collector) :
     175         3370 :     MSMoveReminder(collector.getID() + "_exit", crossSection.myLane),
     176         3370 :     myCollector(collector), myPosition(crossSection.myPosition) {}
     177              : 
     178              : 
     179              : bool
     180        72980 : 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        72980 :     if (reason != NOTIFICATION_JUNCTION) {
     193        11864 :         const double backPosOnLane = veh.getBackPositionOnLane(enteredLane);
     194        11864 :         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              :             return false;
     203              :         }
     204              :     }
     205              :     return true;
     206              : }
     207              : 
     208              : 
     209              : bool
     210      5775020 : 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      5775020 :     if (newPos < myPosition) {
     223              :         // crossSection not yet reached
     224              :         return true;
     225              :     }
     226              : #ifdef HAVE_FOX
     227       254290 :     ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     228              : #endif
     229       254290 :     const double oldSpeed = veh.getPreviousSpeed();
     230       254290 :     if (oldPos < myPosition) {
     231              :         assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
     232        68528 :         const double timeBeforeLeave = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
     233              : //        const double leaveTimeFront = SIMTIME - TS + (myPosition - oldPos) / newSpeed;
     234        68528 :         const double leaveTimeFront = SIMTIME - TS + timeBeforeLeave;
     235        68528 :         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       254290 :     const double backPos = newPos - veh.getVehicleType().getLength();
     243       254290 :     if (backPos < myPosition) {
     244              :         // crossSection not yet left
     245              :         return true;
     246              :     }
     247              :     // crossSection left
     248        68492 :     const double oldBackPos = oldPos - veh.getVehicleType().getLength();
     249        68492 :     const double leaveStep = SIMTIME;
     250              :     assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
     251        68492 :     const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, backPos, oldSpeed, newSpeed);
     252        68492 :     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        40281 : 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        40281 :     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        39087 :     ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
     284              : #endif
     285        39087 :     if (reason == MSMoveReminder::NOTIFICATION_TELEPORT) {
     286          192 :         WRITE_WARNINGF("Vehicle '%' teleported from % '%'.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID());
     287           48 :         myCollector.myEnteredContainer.erase(&veh);
     288           48 :         return false;
     289              :     }
     290        39039 :     if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
     291         1226 :         if (myCollector.myEnteredContainer.erase(&veh) > 0) {
     292            0 :             if (!myCollector.myExpectArrival) {
     293            0 :                 WRITE_WARNINGF("Vehicle '%' arrived inside % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID(), time2string(SIMSTEP));
     294              :             }
     295              :         }
     296         1226 :         return false;
     297              :     }
     298              :     return true;
     299              : }
     300              : 
     301              : /* -------------------------------------------------------------------------
     302              :  * MSE3Collector - definitions
     303              :  * ----------------------------------------------------------------------- */
     304         1422 : 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         1422 :                              bool openEntry, bool expectArrival) :
     313              :     MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
     314         1422 :     myName(name),
     315         1422 :     myEntries(entries),
     316         1422 :     myExits(exits),
     317         1422 :     myHaltingTimeThreshold(haltingTimeThreshold), myHaltingSpeedThreshold(haltingSpeedThreshold),
     318         1422 :     myCurrentMeanSpeed(0), myCurrentHaltingsNumber(0),
     319         1422 :     myLastMeanTravelTime(0), myLastMeanHaltsPerVehicle(0), myLastMeanTimeLoss(0), myLastVehicleSum(0),
     320         2844 :     myLastResetTime(-1), myOpenEntry(openEntry), myExpectArrival(expectArrival) {
     321              :     // Set MoveReminders to entries and exits
     322         3143 :     for (CrossSectionVectorConstIt crossSec1 = entries.begin(); crossSec1 != entries.end(); ++crossSec1) {
     323         1721 :         myEntryReminders.push_back(new MSE3EntryReminder(*crossSec1, *this));
     324              :     }
     325         3107 :     for (CrossSectionVectorConstIt crossSec2 = exits.begin(); crossSec2 != exits.end(); ++crossSec2) {
     326         1685 :         myLeaveReminders.push_back(new MSE3LeaveReminder(*crossSec2, *this));
     327              :     }
     328         1422 :     reset();
     329         1422 : }
     330              : 
     331              : 
     332         2679 : MSE3Collector::~MSE3Collector() {
     333         3143 :     for (std::vector<MSE3EntryReminder*>::iterator i = myEntryReminders.begin(); i != myEntryReminders.end(); ++i) {
     334         1721 :         delete *i;
     335              :     }
     336         3107 :     for (std::vector<MSE3LeaveReminder*>::iterator i = myLeaveReminders.begin(); i != myLeaveReminders.end(); ++i) {
     337         1685 :         delete *i;
     338              :     }
     339         4101 : }
     340              : 
     341              : 
     342              : void
     343         1422 : MSE3Collector::reset() {
     344              :     myLeftContainer.clear();
     345         1422 : }
     346              : 
     347              : 
     348              : 
     349              : void
     350        62222 : MSE3Collector::enter(const SUMOTrafficObject& veh, const double entryTimestep, const double fractionTimeOnDet, MSE3EntryReminder* entryReminder, bool isBackward) {
     351        62222 :     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        62192 :     if (!vehicleApplies(veh)) {
     359              :         return;
     360              :     }
     361        61148 :     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        60828 :     if (myEnteredContainer.find(&veh) != myEnteredContainer.end()) {
     368            0 :         WRITE_WARNINGF("Vehicle '%' reentered % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
     369            0 :         return;
     370              :     }
     371              : #ifdef DEBUG_E3_NOTIFY_ENTER
     372              :     std::cout << veh.getID() << " enters\n";
     373              : #endif
     374        60828 :     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        60828 :     v.haltingBegin = veh.getSpeed() < myHaltingSpeedThreshold ? TIME2STEPS(entryTimestep) : -1;
     381        60828 :     v.intervalSpeedSum = entryTimestep >= STEPS2TIME(myLastResetTime) ? speedFraction : 0;
     382              :     v.haltings = 0;
     383              :     v.intervalHaltings = 0;
     384        60828 :     if (veh.getSpeed() < myHaltingSpeedThreshold) {
     385         1460 :         if (TIME2STEPS(fractionTimeOnDet) > myHaltingTimeThreshold) {
     386              :             v.haltings++;
     387              :             v.intervalHaltings++;
     388              :         }
     389              :     }
     390              :     v.hadUpdate = false;
     391        60828 :     if (!MSGlobals::gUseMesoSim && veh.isVehicle()) {
     392        59698 :         v.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss();
     393              :         v.intervalTimeLoss = v.timeLoss;
     394              :     }
     395              :     v.entryReminder = entryReminder;
     396        60828 :     myEnteredContainer[&veh] = v;
     397              : }
     398              : 
     399              : 
     400              : void
     401        68558 : MSE3Collector::leaveFront(const SUMOTrafficObject& veh, const double leaveTimestep) {
     402        68558 :     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        68528 :     if (!vehicleApplies(veh)) {
     410              :         return;
     411              :     }
     412        67838 :     if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
     413        30074 :         if (!myOpenEntry && veh.isVehicle()) {
     414        71016 :             WRITE_WARNINGF("Vehicle '%' left % '%' without entering it, time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
     415              :         }
     416              :     } else {
     417        37764 :         myEnteredContainer[&veh].frontLeaveTime = leaveTimestep;
     418              :     }
     419              : }
     420              : 
     421              : 
     422              : void
     423        68842 : MSE3Collector::leave(const SUMOTrafficObject& veh, const double leaveTimestep, const double fractionTimeOnDet, bool isBackward) {
     424        68842 :     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        68812 :     if (!vehicleApplies(veh)) {
     432              :         return;
     433              :     }
     434        68038 :     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        67718 :     if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
     441        29746 :         if (!myOpenEntry && veh.isVehicle()) {
     442        70984 :             WRITE_WARNINGF("Vehicle '%' left % '%' without entering it, time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
     443              :         }
     444              :     } else {
     445              : #ifdef DEBUG_E3_NOTIFY_LEAVE
     446              :         std::cout << veh.getID() << " leaves\n";
     447              : #endif
     448        37972 :         E3Values values = myEnteredContainer[&veh];
     449        37972 :         values.backLeaveTime = leaveTimestep;
     450        37972 :         const double speedFraction = veh.getSpeed() * (TS - fractionTimeOnDet);
     451        37972 :         values.speedSum -= speedFraction;
     452        37972 :         values.intervalSpeedSum -= speedFraction;
     453        37972 :         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        36842 :             values.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss() - values.timeLoss;
     463              :         }
     464        37972 :         myEnteredContainer.erase(&veh);
     465        37972 :         myLeftContainer.push_back(values);
     466              :     }
     467              : }
     468              : 
     469              : 
     470              : void
     471       289669 : MSE3Collector::writeXMLOutput(OutputDevice& dev,
     472              :                               SUMOTime startTime, SUMOTime stopTime) {
     473       579338 :     dev << "   <interval begin=\"" << time2string(startTime) << "\" end=\"" << time2string(stopTime) << "\" " << "id=\"" << myID << "\" ";
     474              :     // collect values about vehicles that have left the area
     475       289669 :     myLastVehicleSum = (int) myLeftContainer.size();
     476       289669 :     myLastMeanTravelTime = 0;
     477       289669 :     double meanOverlapTravelTime = 0.;
     478       289669 :     double meanSpeed = 0.;
     479       289669 :     myLastMeanHaltsPerVehicle = 0;
     480       289669 :     myLastMeanTimeLoss = 0.;
     481       327626 :     for (const E3Values& values : myLeftContainer) {
     482        37957 :         myLastMeanHaltsPerVehicle += (double)values.haltings;
     483        37957 :         myLastMeanTravelTime += values.frontLeaveTime - values.entryTime;
     484        37957 :         const double steps = values.backLeaveTime - values.entryTime;
     485        37957 :         meanOverlapTravelTime += steps;
     486        37957 :         meanSpeed += (values.speedSum / steps);
     487        37957 :         myLastMeanTimeLoss += STEPS2TIME(values.timeLoss);
     488              :     }
     489       289669 :     myLastMeanTravelTime = myLastVehicleSum != 0 ? myLastMeanTravelTime / (double)myLastVehicleSum : -1;
     490       289669 :     meanOverlapTravelTime = myLastVehicleSum != 0 ? meanOverlapTravelTime / (double)myLastVehicleSum : -1;
     491       289669 :     meanSpeed = myLastVehicleSum != 0 ? meanSpeed / (double)myLastVehicleSum : -1;
     492       289669 :     myLastMeanHaltsPerVehicle = myLastVehicleSum != 0 ? myLastMeanHaltsPerVehicle / (double) myLastVehicleSum : -1;
     493       289669 :     myLastMeanTimeLoss = myLastVehicleSum != 0 ? myLastMeanTimeLoss / (double) myLastVehicleSum : -1;
     494              :     // clear container
     495              :     myLeftContainer.clear();
     496              : 
     497              :     // collect values about vehicles within the container
     498       289669 :     const int vehicleSumWithin = (int) myEnteredContainer.size();
     499       289669 :     double meanSpeedWithin = 0.;
     500       289669 :     double meanDurationWithin = 0.;
     501       289669 :     double meanHaltsPerVehicleWithin = 0.;
     502       289669 :     double meanIntervalSpeedWithin = 0.;
     503       289669 :     double meanIntervalHaltsPerVehicleWithin = 0.;
     504       289669 :     double meanIntervalDurationWithin = 0.;
     505       289669 :     double meanTimeLossWithin = 0.;
     506      1685850 :     for (std::map<const SUMOTrafficObject*, E3Values>::iterator i = myEnteredContainer.begin(); i != myEnteredContainer.end(); ++i) {
     507      1396181 :         meanHaltsPerVehicleWithin += (double)(*i).second.haltings;
     508      1396181 :         meanIntervalHaltsPerVehicleWithin += (double)(*i).second.intervalHaltings;
     509      1396181 :         const double end = (*i).second.backLeaveTime == 0 ? STEPS2TIME(stopTime) : (*i).second.backLeaveTime;
     510      1396181 :         const double time = end - (*i).second.entryTime;
     511      1396181 :         const double timeWithin = MIN2(time, end - STEPS2TIME(startTime));
     512      1396181 :         if (i->second.speedSum > 0.) {
     513      1396181 :             meanSpeedWithin += i->second.speedSum / time;
     514              :         }
     515      1396181 :         if (i->second.intervalSpeedSum > 0.) {
     516       196197 :             meanIntervalSpeedWithin += i->second.intervalSpeedSum / timeWithin;
     517              :         }
     518      1396181 :         meanDurationWithin += time;
     519      1396181 :         meanIntervalDurationWithin += timeWithin;
     520              :         // reset interval values
     521      1396181 :         (*i).second.intervalHaltings = 0;
     522      1396181 :         (*i).second.intervalSpeedSum = 0;
     523              : 
     524      1396181 :         if (!MSGlobals::gUseMesoSim && i->first->isVehicle()) {
     525      1396117 :             const SUMOTime currentTimeLoss = dynamic_cast<const MSVehicle*>(i->first)->getTimeLoss();
     526      1396117 :             meanTimeLossWithin += STEPS2TIME(currentTimeLoss - (*i).second.intervalTimeLoss);
     527      1396117 :             (*i).second.intervalTimeLoss = currentTimeLoss;
     528              :         }
     529              :     }
     530       289669 :     myLastResetTime = stopTime;
     531       289669 :     meanSpeedWithin = vehicleSumWithin != 0 ?  meanSpeedWithin / (double) vehicleSumWithin : -1;
     532       289669 :     meanHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
     533       289669 :     meanDurationWithin = vehicleSumWithin != 0 ? meanDurationWithin / (double) vehicleSumWithin : -1;
     534       289669 :     meanIntervalSpeedWithin = vehicleSumWithin != 0 ?  meanIntervalSpeedWithin / (double) vehicleSumWithin : -1;
     535       289669 :     meanIntervalHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanIntervalHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
     536       289669 :     meanIntervalDurationWithin = vehicleSumWithin != 0 ? meanIntervalDurationWithin / (double) vehicleSumWithin : -1;
     537       289669 :     meanTimeLossWithin = vehicleSumWithin != 0 ? meanTimeLossWithin / (double) vehicleSumWithin : -1;
     538              : 
     539              :     // write values
     540       289669 :     dev << "meanTravelTime=\"" << myLastMeanTravelTime
     541       289669 :         << "\" meanOverlapTravelTime=\"" << meanOverlapTravelTime
     542       289669 :         << "\" meanSpeed=\"" << meanSpeed
     543       289669 :         << "\" meanHaltsPerVehicle=\"" << myLastMeanHaltsPerVehicle
     544       289669 :         << "\" meanTimeLoss=\"" << myLastMeanTimeLoss
     545       289669 :         << "\" vehicleSum=\"" << myLastVehicleSum
     546       289669 :         << "\" meanSpeedWithin=\"" << meanSpeedWithin
     547       289669 :         << "\" meanHaltsPerVehicleWithin=\"" << meanHaltsPerVehicleWithin
     548       289669 :         << "\" meanDurationWithin=\"" << meanDurationWithin
     549       289669 :         << "\" vehicleSumWithin=\"" << vehicleSumWithin
     550       289669 :         << "\" meanIntervalSpeedWithin=\"" << meanIntervalSpeedWithin
     551       289669 :         << "\" meanIntervalHaltsPerVehicleWithin=\"" << meanIntervalHaltsPerVehicleWithin
     552       289669 :         << "\" meanIntervalDurationWithin=\"" << meanIntervalDurationWithin
     553       289669 :         << "\" meanTimeLossWithin=\"" << meanTimeLossWithin
     554       289669 :         << "\"/>\n";
     555       289669 : }
     556              : 
     557              : 
     558              : void
     559         1414 : MSE3Collector::writeXMLDetectorProlog(OutputDevice& dev) const {
     560         2828 :     dev.writeXMLHeader("e3Detector", "det_e3_file.xsd");
     561         1414 : }
     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      2914455 : MSE3Collector::detectorUpdate(const SUMOTime step) {
     582              : 
     583      2914455 :     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      2914455 :     myCurrentMeanSpeed = 0;
     607      2914455 :     myCurrentHaltingsNumber = 0;
     608     10229803 :     for (std::map<const SUMOTrafficObject*, E3Values>::iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
     609      7315348 :         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      7315348 :         myCurrentMeanSpeed += veh->getSpeed();
     619      7315348 :         values.hadUpdate = true;
     620      7315348 :         values.speedSum += veh->getSpeed() * TS;
     621      7315348 :         values.intervalSpeedSum += veh->getSpeed() * TS;
     622      7315348 :         if (veh->getSpeed() < myHaltingSpeedThreshold) {
     623      5819289 :             if (values.haltingBegin == -1) {
     624        65532 :                 values.haltingBegin = step;
     625              :             }
     626      5819289 :             SUMOTime haltingDuration = step - values.haltingBegin;
     627      5819289 :             if (haltingDuration >= myHaltingTimeThreshold
     628      5747768 :                     && haltingDuration < (myHaltingTimeThreshold + DELTA_T)) {
     629        60959 :                 values.haltings++;
     630        60959 :                 values.intervalHaltings++;
     631        60959 :                 myCurrentHaltingsNumber++;
     632              :             }
     633              :         } else {
     634      1496059 :             values.haltingBegin = -1;
     635              :         }
     636              :     }
     637      2914455 :     if (myEnteredContainer.size() == 0) {
     638      2424667 :         myCurrentMeanSpeed = -1;
     639              :     } else {
     640       489788 :         myCurrentMeanSpeed /= (double)myEnteredContainer.size();
     641              :     }
     642      2914455 : }
     643              : 
     644              : 
     645              : const CrossSectionVector&
     646          306 : MSE3Collector::getEntries() const {
     647          306 :     return myEntries;
     648              : }
     649              : 
     650              : 
     651              : const CrossSectionVector&
     652          306 : MSE3Collector::getExits() const {
     653          306 :     return myExits;
     654              : }
     655              : 
     656              : 
     657              : double
     658           47 : MSE3Collector::getCurrentMeanSpeed() const {
     659           47 :     return myCurrentMeanSpeed;
     660              : }
     661              : 
     662              : 
     663              : int
     664            5 : MSE3Collector::getCurrentHaltingNumber() const {
     665            5 :     return myCurrentHaltingsNumber;
     666              : }
     667              : 
     668              : 
     669              : int
     670          578 : MSE3Collector::getVehiclesWithin() const {
     671          578 :     return (int) myEnteredContainer.size();
     672              : }
     673              : 
     674              : 
     675              : std::vector<std::string>
     676          247 : MSE3Collector::getCurrentVehicleIDs() const {
     677              :     std::vector<std::string> ret;
     678          369 :     for (std::map<const SUMOTrafficObject*, E3Values>::const_iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
     679          122 :         ret.push_back((*pair).first->getID());
     680              :     }
     681          247 :     std::sort(ret.begin(), ret.end());
     682          247 :     return ret;
     683            0 : }
     684              : 
     685              : void
     686           20 : MSE3Collector::clearState(SUMOTime /* step */) {
     687              :     myEnteredContainer.clear();
     688              :     myLeftContainer.clear();
     689           20 : }
     690              : 
     691              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1