LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDevice_Tripinfo.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.9 % 522 506
Test Date: 2026-04-16 16:39:47 Functions: 93.6 % 47 44

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2009-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    MSDevice_Tripinfo.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Laura Bieker
      17              : /// @author  Michael Behrisch
      18              : /// @author  Jakob Erdmann
      19              : /// @date    Fri, 30.01.2009
      20              : ///
      21              : // A device which collects info on the vehicle trip
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <microsim/MSGlobals.h>
      26              : #include <microsim/MSNet.h>
      27              : #include <microsim/MSLane.h>
      28              : #include <microsim/MSEdge.h>
      29              : #include <microsim/MSVehicle.h>
      30              : #include <microsim/transportables/MSTransportableControl.h>
      31              : #include <mesosim/MEVehicle.h>
      32              : #include <utils/options/OptionsCont.h>
      33              : #include <utils/iodevices/OutputDevice.h>
      34              : #include <utils/xml/SUMOSAXAttributes.h>
      35              : #include "MSDevice_Vehroutes.h"
      36              : #include "MSDevice_Tripinfo.h"
      37              : 
      38              : #define NOT_ARRIVED TIME2STEPS(-1)
      39              : #define STATE_EMPTY_ARRIVALLANE "NONE"
      40              : 
      41              : 
      42              : // ===========================================================================
      43              : // static members
      44              : // ===========================================================================
      45              : std::set<const MSDevice_Tripinfo*, ComparatorNumericalIdLess> MSDevice_Tripinfo::myPendingOutput;
      46              : 
      47              : int MSDevice_Tripinfo::myVehicleCount(0);
      48              : int MSDevice_Tripinfo::myUndepartedVehicleCount(0);
      49              : double MSDevice_Tripinfo::myTotalRouteLength(0);
      50              : double MSDevice_Tripinfo::myTotalSpeed(0);
      51              : SUMOTime MSDevice_Tripinfo::myTotalDuration(0);
      52              : SUMOTime MSDevice_Tripinfo::myTotalWaitingTime(0);
      53              : SUMOTime MSDevice_Tripinfo::myTotalTimeLoss(0);
      54              : SUMOTime MSDevice_Tripinfo::myTotalDepartDelay(0);
      55              : SUMOTime MSDevice_Tripinfo::myWaitingDepartDelay(-1);
      56              : 
      57              : int MSDevice_Tripinfo::myBikeCount(0);
      58              : double MSDevice_Tripinfo::myTotalBikeRouteLength(0);
      59              : double MSDevice_Tripinfo::myTotalBikeSpeed(0);
      60              : SUMOTime MSDevice_Tripinfo::myTotalBikeDuration(0);
      61              : SUMOTime MSDevice_Tripinfo::myTotalBikeWaitingTime(0);
      62              : SUMOTime MSDevice_Tripinfo::myTotalBikeTimeLoss(0);
      63              : SUMOTime MSDevice_Tripinfo::myTotalBikeDepartDelay(0);
      64              : 
      65              : int MSDevice_Tripinfo::myWalkCount(0);
      66              : double MSDevice_Tripinfo::myTotalWalkRouteLength(0);
      67              : SUMOTime MSDevice_Tripinfo::myTotalWalkDuration(0);
      68              : SUMOTime MSDevice_Tripinfo::myTotalWalkTimeLoss(0);
      69              : std::vector<int> MSDevice_Tripinfo::myRideCount({0, 0});
      70              : std::vector<int> MSDevice_Tripinfo::myRideBusCount({0, 0});
      71              : std::vector<int> MSDevice_Tripinfo::myRideRailCount({0, 0});
      72              : std::vector<int> MSDevice_Tripinfo::myRideTaxiCount({0, 0});
      73              : std::vector<int> MSDevice_Tripinfo::myRideBikeCount({0, 0});
      74              : std::vector<int> MSDevice_Tripinfo::myRideAbortCount({0, 0});
      75              : std::vector<SUMOTime> MSDevice_Tripinfo::myTotalRideWaitingTime({0, 0});
      76              : std::vector<double> MSDevice_Tripinfo::myTotalRideRouteLength({0., 0.});
      77              : std::vector<SUMOTime> MSDevice_Tripinfo::myTotalRideDuration({0, 0});
      78              : 
      79              : // ===========================================================================
      80              : // method definitions
      81              : // ===========================================================================
      82              : // ---------------------------------------------------------------------------
      83              : // static initialisation methods
      84              : // ---------------------------------------------------------------------------
      85              : void
      86        44603 : MSDevice_Tripinfo::insertOptions(OptionsCont& oc) {
      87        44603 :     oc.addOptionSubTopic("Tripinfo Device");
      88        89206 :     insertDefaultAssignmentOptions("tripinfo", "Tripinfo Device", oc);
      89        44603 : }
      90              : 
      91              : 
      92              : void
      93      5255351 : MSDevice_Tripinfo::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
      94      5255351 :     OptionsCont& oc = OptionsCont::getOptions();
      95     10242493 :     const bool enableByOutputOption = oc.isSet("tripinfo-output") || oc.getBool("duration-log.statistics");
      96     10510702 :     if (equippedByDefaultAssignmentOptions(oc, "tripinfo", v, enableByOutputOption)) {
      97      2306565 :         MSDevice_Tripinfo* device = new MSDevice_Tripinfo(v, "tripinfo_" + v.getID());
      98      2306565 :         into.push_back(device);
      99              :         myPendingOutput.insert(device);
     100              :     }
     101      5255351 : }
     102              : 
     103              : 
     104              : // ---------------------------------------------------------------------------
     105              : // MSDevice_Tripinfo-methods
     106              : // ---------------------------------------------------------------------------
     107      2306565 : MSDevice_Tripinfo::MSDevice_Tripinfo(SUMOVehicle& holder, const std::string& id) :
     108              :     MSVehicleDevice(holder, id),
     109            0 :     myDepartLane(""),
     110      2306565 :     myDepartSpeed(-1),
     111      2306565 :     myDepartPosLat(0),
     112      2306565 :     myWaitingTime(0),
     113      2306565 :     myAmWaiting(false),
     114      2306565 :     myWaitingCount(0),
     115      2306565 :     myStoppingTime(0),
     116      2306565 :     myParkingStarted(-1),
     117      2306565 :     myArrivalTime(NOT_ARRIVED),
     118      2306565 :     myArrivalLane(""),
     119      2306565 :     myArrivalPos(-1),
     120      2306565 :     myArrivalPosLat(0.),
     121      2306565 :     myArrivalSpeed(-1),
     122      2306565 :     myArrivalReason(MSMoveReminder::NOTIFICATION_ARRIVED),
     123      2306565 :     myMesoTimeLoss(0),
     124      2306565 :     myRouteLength(0.) {
     125      2306565 : }
     126              : 
     127              : 
     128      4613080 : MSDevice_Tripinfo::~MSDevice_Tripinfo() {
     129              :     // ensure clean up for vaporized vehicles which do not generate output
     130      2306540 :     myPendingOutput.erase(this);
     131      4613080 : }
     132              : 
     133              : void
     134        41448 : MSDevice_Tripinfo::cleanup() {
     135        41448 :     myVehicleCount = 0;
     136        41448 :     myTotalRouteLength = 0;
     137        41448 :     myTotalSpeed = 0;
     138        41448 :     myTotalDuration = 0;
     139        41448 :     myTotalWaitingTime = 0;
     140        41448 :     myTotalTimeLoss = 0;
     141        41448 :     myTotalDepartDelay = 0;
     142        41448 :     myWaitingDepartDelay = -1;
     143              : 
     144        41448 :     myBikeCount = 0;
     145        41448 :     myTotalBikeRouteLength = 0;
     146        41448 :     myTotalBikeSpeed = 0;
     147        41448 :     myTotalBikeDuration = 0;
     148        41448 :     myTotalBikeWaitingTime = 0;
     149        41448 :     myTotalBikeTimeLoss = 0;
     150        41448 :     myTotalBikeDepartDelay = 0;
     151              : 
     152        41448 :     myWalkCount = 0;
     153        41448 :     myTotalWalkRouteLength = 0;
     154        41448 :     myTotalWalkDuration = 0;
     155        41448 :     myTotalWalkTimeLoss = 0;
     156              : 
     157        41448 :     myRideCount = {0, 0};
     158        41448 :     myRideBusCount = {0, 0};
     159        41448 :     myRideRailCount = {0, 0};
     160        41448 :     myRideTaxiCount = {0, 0};
     161        41448 :     myRideBikeCount = {0, 0};
     162        41448 :     myRideAbortCount = {0, 0};
     163        41448 :     myTotalRideWaitingTime = {0, 0};
     164        41448 :     myTotalRideRouteLength = {0., 0.};
     165        41448 :     myTotalRideDuration = {0, 0};
     166        41448 : }
     167              : 
     168              : bool
     169         4910 : MSDevice_Tripinfo::notifyIdle(SUMOTrafficObject& veh) {
     170         4910 :     if (veh.isVehicle()) {
     171         4910 :         myWaitingTime += DELTA_T;
     172         4910 :         if (!myAmWaiting) {
     173          150 :             myWaitingCount++;
     174          150 :             myAmWaiting = true;
     175              :         }
     176              :     }
     177         4910 :     return true;
     178              : }
     179              : 
     180              : 
     181              : bool
     182    346547706 : MSDevice_Tripinfo::notifyMove(SUMOTrafficObject& veh, double /*oldPos*/,
     183              :                               double /*newPos*/, double newSpeed) {
     184    346547706 :     if (veh.isStopped()) {
     185      2247962 :         if (newSpeed <= SUMO_const_haltingSpeed) {
     186      2247767 :             myStoppingTime += DELTA_T;
     187              :         }
     188    344299744 :     } else if (newSpeed <= SUMO_const_haltingSpeed && lowAcceleration(veh)) {
     189     53675352 :         myWaitingTime += DELTA_T;
     190     53675352 :         if (!myAmWaiting) {
     191      2665787 :             myWaitingCount++;
     192      2665787 :             myAmWaiting = true;
     193              :         }
     194              :     } else {
     195    290624392 :         myAmWaiting = false;
     196              :     }
     197    346547706 :     return true;
     198              : }
     199              : 
     200              : 
     201              : bool
     202     53676207 : MSDevice_Tripinfo::lowAcceleration(const SUMOTrafficObject& veh) {
     203     53676207 :     if (MSGlobals::gUseMesoSim) {
     204              :         // acceleration is not modelled
     205              :         return false;
     206              :     } else {
     207     53676207 :         const MSVehicle& v = dynamic_cast<const MSVehicle&>(veh);
     208     53676207 :         return v.getAcceleration() <= v.accelThresholdForWaiting();
     209              :     }
     210              : }
     211              : 
     212              : 
     213              : void
     214     14304649 : MSDevice_Tripinfo::notifyMoveInternal(const SUMOTrafficObject& veh,
     215              :                                       const double /* frontOnLane */,
     216              :                                       const double timeOnLane,
     217              :                                       const double /* meanSpeedFrontOnLane */,
     218              :                                       const double meanSpeedVehicleOnLane,
     219              :                                       const double /* travelledDistanceFrontOnLane */,
     220              :                                       const double /* travelledDistanceVehicleOnLane */,
     221              :                                       const double /* meanLengthOnLane */) {
     222              : 
     223              :     // called by meso
     224     14304649 :     const double vmax = veh.getEdge()->getVehicleMaxSpeed(&veh);
     225     14304649 :     if (vmax > 0) {
     226     17682696 :         myMesoTimeLoss += TIME2STEPS(timeOnLane * (vmax - meanSpeedVehicleOnLane) / vmax);
     227              :     }
     228     14304649 :     myWaitingTime += veh.getWaitingTime();
     229     14304649 :     if (veh.getWaitingTime() >= TIME2STEPS(1)) {
     230              :         // waiting counts the time spent waiting to enter the next link (when it's occupied).
     231       177385 :         myWaitingCount++;
     232              :     }
     233     14304649 : }
     234              : 
     235              : 
     236              : void
     237            5 : MSDevice_Tripinfo::recordMesoParkingTimeLoss(SUMOTime waitingTime) {
     238            5 :     myMesoTimeLoss += waitingTime;
     239            5 :     myWaitingTime += waitingTime;
     240            5 :     myWaitingCount++;
     241            5 : }
     242              : 
     243              : void
     244      1747765 : MSDevice_Tripinfo::updateParkingStopTime() {
     245      1747765 :     if (myParkingStarted >= 0) {
     246         4352 :         myStoppingTime += (MSNet::getInstance()->getCurrentTimeStep() - myParkingStarted);
     247         4352 :         myParkingStarted = -1;
     248              :     }
     249      1747765 : }
     250              : 
     251              : bool
     252     28867645 : MSDevice_Tripinfo::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     253     28867645 :     if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
     254      1779581 :         if (!MSGlobals::gUseMesoSim) {
     255      1393288 :             myDepartLane = static_cast<MSVehicle&>(veh).getLane()->getID();
     256      1393288 :             myDepartPosLat = static_cast<MSVehicle&>(veh).getLateralPositionOnLane();
     257              :         } else {
     258       386293 :             myDepartLane = veh.getEdge()->getFirstAllowed(veh.getVClass(), true)->getID();
     259              :         }
     260      1779581 :         myDepartSpeed = veh.getSpeed();
     261      1779581 :         myRouteLength = -veh.getPositionOnLane();
     262     27088064 :     } else if (reason == MSMoveReminder::NOTIFICATION_PARKING) {
     263              :         // notifyMove is not called while parking
     264              :         // @note insertion delay when resuming after parking is included
     265         3736 :         updateParkingStopTime();
     266              :     }
     267     28867645 :     return true;
     268              : }
     269              : 
     270              : 
     271              : bool
     272     28795320 : MSDevice_Tripinfo::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/,
     273              :                                MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     274     28795320 :     if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
     275      1710366 :         myArrivalTime = MSNet::getInstance()->getCurrentTimeStep();
     276      1710366 :         myArrivalReason = reason;
     277      1710366 :         if (!MSGlobals::gUseMesoSim) {
     278      1330824 :             myArrivalLane = static_cast<MSVehicle&>(veh).getLane()->getID();
     279      1330824 :             myArrivalPosLat = static_cast<MSVehicle&>(veh).getLateralPositionOnLane();
     280              :         } else {
     281       379542 :             myArrivalLane = veh.getEdge()->getFirstAllowed(veh.getVClass(), true)->getID();
     282              :         }
     283              :         // @note vehicle may have moved past its arrivalPos during the last step
     284              :         // due to non-zero arrivalspeed but we consider it as arrived at the desired position
     285              :         // However, vaporization may happen anywhere (via TraCI)
     286      1710366 :         if (reason > MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED) {
     287              :             // vaporized
     288          549 :             myArrivalPos = veh.getPositionOnLane();
     289              :         } else {
     290      1709817 :             myArrivalPos = myHolder.getArrivalPos();
     291              :         }
     292      1710366 :         myArrivalSpeed = veh.getSpeed();
     293      1710366 :         updateParkingStopTime();
     294     27084954 :     } else if (reason == MSMoveReminder::NOTIFICATION_PARKING) {
     295         4516 :         myParkingStarted = MSNet::getInstance()->getCurrentTimeStep();
     296     27080438 :     } else if (reason == NOTIFICATION_JUNCTION
     297     27080438 :                || reason == NOTIFICATION_TELEPORT
     298     12387696 :                || reason == NOTIFICATION_TELEPORT_CONTINUATION) {
     299     14698051 :         if (MSGlobals::gUseMesoSim) {
     300      2344638 :             myRouteLength += myHolder.getCurrentEdge()->getLength();
     301              :         } else {
     302     12353413 :             const MSLane* lane = static_cast<MSVehicle&>(veh).getLane();
     303     12353413 :             if (lane != nullptr) {
     304     12353389 :                 myRouteLength += lane->getLength();
     305              :             }
     306              :         }
     307              :     }
     308     28795320 :     return true;
     309              : }
     310              : 
     311              : 
     312              : void
     313      1745149 : MSDevice_Tripinfo::generateOutput(OutputDevice* tripinfoOut) const {
     314      1745149 :     const SUMOTime timeLoss = MSGlobals::gUseMesoSim ? myMesoTimeLoss : static_cast<MSVehicle&>(myHolder).getTimeLoss();
     315      1745149 :     const double routeLength = myRouteLength + (myArrivalTime == NOT_ARRIVED ? myHolder.getPositionOnLane() : myArrivalPos);
     316              :     SUMOTime duration = 0;
     317      1745149 :     if (myHolder.hasDeparted()) {
     318      1779658 :         duration = (myArrivalTime == NOT_ARRIVED ? SIMSTEP : myArrivalTime) - myHolder.getDeparture();
     319      1744905 :         if (myHolder.getVClass() == SVC_BICYCLE) {
     320        25203 :             myBikeCount++;
     321        25203 :             myTotalBikeRouteLength += routeLength;
     322        25203 :             myTotalBikeSpeed += routeLength / STEPS2TIME(duration);
     323        25203 :             myTotalBikeDuration += duration;
     324        25203 :             myTotalBikeWaitingTime += myWaitingTime;
     325        25203 :             myTotalBikeTimeLoss += timeLoss;
     326        25203 :             myTotalBikeDepartDelay += myHolder.getDepartDelay();
     327              :         } else {
     328      1719702 :             myVehicleCount++;
     329      1719702 :             myTotalRouteLength += routeLength;
     330      1719702 :             myTotalSpeed += routeLength / STEPS2TIME(duration);
     331      1719702 :             myTotalDuration += duration;
     332      1719702 :             myTotalWaitingTime += myWaitingTime;
     333      1719702 :             myTotalTimeLoss += timeLoss;
     334      1719702 :             myTotalDepartDelay += myHolder.getDepartDelay();
     335              :         }
     336              :     }
     337              : 
     338      1745149 :     myPendingOutput.erase(this);
     339      1745149 :     if (tripinfoOut == nullptr) {
     340      1506127 :         return;
     341              :     }
     342              :     // write
     343              :     OutputDevice& os = *tripinfoOut;
     344       239022 :     os.openTag("tripinfo").writeAttr("id", myHolder.getID());
     345       239022 :     os.writeAttr("depart", myHolder.hasDeparted() ? time2string(myHolder.getDeparture()) : "-1");
     346       239022 :     os.writeAttr("departLane", myDepartLane);
     347       239022 :     os.writeAttr("departPos", myHolder.getDepartPos());
     348       239022 :     if (MSGlobals::gLateralResolution > 0) {
     349        25489 :         os.writeAttr("departPosLat", myDepartPosLat);
     350              :     }
     351       239022 :     os.writeAttr("departSpeed", myDepartSpeed);
     352       239022 :     SUMOTime departDelay = myHolder.getDepartDelay();
     353       239022 :     const SUMOVehicleParameter& param = myHolder.getParameter();
     354       239022 :     if (!myHolder.hasDeparted()) {
     355              :         assert(param.depart <= SIMSTEP || param.departProcedure != DepartDefinition::GIVEN);
     356          244 :         departDelay = SIMSTEP - param.depart;
     357              :     }
     358       239022 :     os.writeAttr("departDelay", time2string(departDelay));
     359       239022 :     os.writeAttr("arrival", time2string(myArrivalTime));
     360       239022 :     os.writeAttr("arrivalLane", myArrivalLane);
     361       239022 :     os.writeAttr("arrivalPos", myArrivalPos);
     362       239022 :     if (MSGlobals::gLateralResolution > 0) {
     363        25489 :         os.writeAttr("arrivalPosLat", myArrivalPosLat);
     364              :     }
     365       239022 :     os.writeAttr("arrivalSpeed", myArrivalSpeed);
     366       239022 :     os.writeAttr("duration", time2string(duration));
     367       239022 :     os.writeAttr("routeLength", routeLength);
     368       239022 :     os.writeAttr(SUMO_ATTR_WAITINGTIME, time2string(myWaitingTime));
     369       239022 :     os.writeAttr(SUMO_ATTR_WAITINGCOUNT, myWaitingCount);
     370       239022 :     os.writeAttr(SUMO_ATTR_STOPTIME, time2string(myStoppingTime));
     371       239022 :     os.writeAttr(SUMO_ATTR_TIMELOSS, time2string(timeLoss));
     372       239022 :     os.writeAttr("rerouteNo", myHolder.getNumberReroutes());
     373       478044 :     os.writeAttr("devices", toString(myHolder.getDevices()));
     374       239022 :     os.writeAttr("vType", myHolder.getVehicleType().getID());
     375       239022 :     os.writeAttr("speedFactor", myHolder.getChosenSpeedFactor());
     376              :     std::string vaporized;
     377       239022 :     switch (myArrivalReason) {
     378              :         case MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR:
     379              :             vaporized = "calibrator";
     380              :             break;
     381              :         case MSMoveReminder::NOTIFICATION_VAPORIZED_GUI:
     382              :             vaporized = "gui";
     383              :             break;
     384              :         case MSMoveReminder::NOTIFICATION_VAPORIZED_COLLISION:
     385              :             vaporized = "collision";
     386              :             break;
     387              :         case MSMoveReminder::NOTIFICATION_VAPORIZED_VAPORIZER:
     388              :             vaporized = "vaporizer";
     389              :             break;
     390              :         case MSMoveReminder::NOTIFICATION_VAPORIZED_TRACI:
     391              :             vaporized = "traci";
     392              :             break;
     393              :         case MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED:
     394              :             vaporized = "teleport";
     395              :             break;
     396       238639 :         default:
     397       238639 :             if (myHolder.getEdge() == myHolder.getRoute().getLastEdge() ||
     398         1591 :                     (param.arrivalEdge >= 0 && myHolder.getRoutePosition() >= param.arrivalEdge)) {
     399              :                 vaporized = "";
     400              :             } else {
     401              :                 vaporized = "end";
     402              :             }
     403              :             break;
     404              :     }
     405       239022 :     os.writeAttr("vaporized", vaporized);
     406              :     // cannot close tag because emission device output might follow
     407              : }
     408              : 
     409              : 
     410              : void
     411         1001 : MSDevice_Tripinfo::generateOutputForUnfinished() {
     412         1001 :     MSNet* net = MSNet::getInstance();
     413         1001 :     OutputDevice* tripinfoOut = (OptionsCont::getOptions().isSet("tripinfo-output") ?
     414         1748 :                                  &OutputDevice::getDeviceByOption("tripinfo-output") : nullptr);
     415         1001 :     myWaitingDepartDelay = 0;
     416         1001 :     myUndepartedVehicleCount = 0;
     417         2002 :     const bool writeUndeparted = OptionsCont::getOptions().getBool("tripinfo-output.write-undeparted");
     418              :     const SUMOTime t = net->getCurrentTimeStep();
     419        66381 :     while (myPendingOutput.size() > 0) {
     420        65380 :         const MSDevice_Tripinfo* d = *myPendingOutput.begin();
     421        65380 :         const bool departed = d->myHolder.hasDeparted();
     422        65380 :         const bool departDelayed = d->myHolder.getParameter().depart <= t;
     423        65380 :         if (!departed && departDelayed) {
     424        31949 :             myUndepartedVehicleCount++;
     425        31949 :             myWaitingDepartDelay += (t - d->myHolder.getParameter().depart);
     426              :         }
     427        65380 :         if (departed || (writeUndeparted && departDelayed)) {
     428        33663 :             const_cast<MSDevice_Tripinfo*>(d)->updateParkingStopTime();
     429        33663 :             d->generateOutput(tripinfoOut);
     430        33663 :             if (tripinfoOut != nullptr) {
     431         7627 :                 for (MSVehicleDevice* const dev : d->myHolder.getDevices()) {
     432         5453 :                     if (typeid(*dev) == typeid(MSDevice_Tripinfo) || typeid(*dev) == typeid(MSDevice_Vehroutes)) {
     433              :                         // tripinfo is special and vehroute has its own write-unfinished option
     434         2779 :                         continue;
     435              :                     }
     436         2674 :                     dev->generateOutput(tripinfoOut);
     437              :                 }
     438         4348 :                 OutputDevice::getDeviceByOption("tripinfo-output").closeTag();
     439              :             }
     440              :         } else {
     441              :             myPendingOutput.erase(d);
     442              :         }
     443              :     }
     444              :     // unfinished persons
     445         1001 :     if (net->hasPersons()) {
     446          614 :         net->getPersonControl().eraseAll();
     447              :     }
     448              : 
     449         1001 : }
     450              : 
     451              : 
     452              : void
     453        55403 : MSDevice_Tripinfo::addPedestrianData(double walkLength, SUMOTime walkDuration, SUMOTime walkTimeLoss) {
     454        55403 :     myWalkCount++;
     455        55403 :     myTotalWalkRouteLength += walkLength;
     456        55403 :     myTotalWalkDuration += walkDuration;
     457        55403 :     myTotalWalkTimeLoss += walkTimeLoss;
     458        55403 : }
     459              : 
     460              : 
     461              : void
     462         7480 : MSDevice_Tripinfo::addRideTransportData(const bool isPerson, const double distance, const SUMOTime duration,
     463              :                                         const SUMOVehicleClass vClass, const std::string& line, const SUMOTime waitingTime) {
     464         7480 :     const int index = isPerson ? 0 : 1;
     465         7480 :     myRideCount[index]++;
     466         7480 :     if (duration > 0) {
     467         7144 :         myTotalRideWaitingTime[index] += waitingTime;
     468         7144 :         myTotalRideRouteLength[index] += distance;
     469         7144 :         myTotalRideDuration[index] += duration;
     470         7144 :         if (vClass == SVC_BICYCLE) {
     471           23 :             myRideBikeCount[index]++;
     472         7121 :         } else if (!line.empty()) {
     473         5917 :             if (isRailway(vClass)) {
     474          832 :                 myRideRailCount[index]++;
     475         5085 :             } else if (vClass == SVC_TAXI) {
     476         1855 :                 myRideTaxiCount[index]++;
     477              :             } else {
     478              :                 // some kind of road vehicle
     479         3230 :                 myRideBusCount[index]++;
     480              :             }
     481              :         }
     482              :     } else {
     483          336 :         myRideAbortCount[index]++;
     484              :     }
     485         7480 : }
     486              : 
     487              : 
     488              : std::string
     489         3195 : MSDevice_Tripinfo::printStatistics() {
     490         3195 :     std::ostringstream msg;
     491              :     msg.setf(msg.fixed);
     492         3195 :     msg.precision(gPrecision);
     493         3195 :     if (myBikeCount == 0 || myVehicleCount > 0) {
     494         3124 :         msg << "Statistics (avg of " << myVehicleCount << "):\n";
     495         3124 :         msg << " RouteLength: " << getAvgRouteLength() << "\n"
     496         3124 :             << " Speed: " << getAvgTripSpeed() << "\n"
     497         3124 :             << " Duration: " << getAvgDuration() << "\n"
     498         3124 :             << " WaitingTime: " << getAvgWaitingTime() << "\n"
     499         3124 :             << " TimeLoss: " << getAvgTimeLoss() << "\n"
     500         6248 :             << " DepartDelay: " << getAvgDepartDelay() << "\n";
     501              :     }
     502         3195 :     if (myBikeCount > 0) {
     503              :         msg << "Bike Statistics (avg of " << myBikeCount << "):\n"
     504          314 :             << " RouteLength: " << getAvgBikeRouteLength() << "\n"
     505          157 :             << " Speed: " << getAvgBikeTripSpeed() << "\n"
     506          157 :             << " Duration: " << getAvgBikeDuration() << "\n"
     507          157 :             << " WaitingTime: " << getAvgBikeWaitingTime() << "\n"
     508          157 :             << " TimeLoss: " << getAvgBikeTimeLoss() << "\n"
     509          314 :             << " DepartDelay: " << getAvgBikeDepartDelay() << "\n";
     510          157 :         if (myVehicleCount > 0 && myWaitingDepartDelay >= 0) {
     511           19 :             msg << "Statistics (avg of " << (myVehicleCount + myBikeCount) << "):\n";
     512              :         }
     513              :     }
     514         3195 :     if (myWaitingDepartDelay >= 0) {
     515          790 :         msg << " DepartDelayWaiting: " << getAvgDepartDelayWaiting() << "\n";
     516              :     }
     517         3195 :     if (myWalkCount > 0) {
     518              :         msg << "Pedestrian Statistics (avg of " << myWalkCount << " walks):\n"
     519          586 :             << " RouteLength: " << getAvgWalkRouteLength() << "\n"
     520          293 :             << " Duration: " << getAvgWalkDuration() << "\n"
     521          586 :             << " TimeLoss: " << getAvgWalkTimeLoss() << "\n";
     522              :     }
     523         6390 :     printRideStatistics(msg, "Ride", "rides", 0);
     524         6390 :     printRideStatistics(msg, "Transport", "transports", 1);
     525         3195 :     return msg.str();
     526         3195 : }
     527              : 
     528              : void
     529         6390 : MSDevice_Tripinfo::printRideStatistics(std::ostringstream& msg, const std::string& category, const std::string& modeName, const int index) {
     530         6390 :     if (myRideCount[index] > 0) {
     531          411 :         msg << category << " Statistics (avg of " << myRideCount[index] << " " << modeName << "):\n";
     532          137 :         msg << " WaitingTime: " << STEPS2TIME(myTotalRideWaitingTime[index] / myRideCount[index]) << "\n";
     533          137 :         msg << " RouteLength: " << myTotalRideRouteLength[index] / myRideCount[index] << "\n";
     534          137 :         msg << " Duration: " << STEPS2TIME(myTotalRideDuration[index] / myRideCount[index]) << "\n";
     535          137 :         if (myRideBusCount[index] > 0) {
     536           15 :             msg << " Bus: " << myRideBusCount[index] << "\n";
     537              :         }
     538          137 :         if (myRideRailCount[index] > 0) {
     539            9 :             msg << " Train: " << myRideRailCount[index] << "\n";
     540              :         }
     541          137 :         if (myRideTaxiCount[index] > 0) {
     542           86 :             msg << " Taxi: " << myRideTaxiCount[index] << "\n";
     543              :         }
     544          137 :         if (myRideBikeCount[index] > 0) {
     545           18 :             msg << " Bike: " << myRideBikeCount[index] << "\n";
     546              :         }
     547          137 :         if (myRideAbortCount[index] > 0) {
     548           11 :             msg << " Aborted: " << myRideAbortCount[index] << "\n";
     549              :         }
     550              :     }
     551              : 
     552         6390 : }
     553              : 
     554              : 
     555              : void
     556          264 : MSDevice_Tripinfo::writeStatistics(OutputDevice& od) {
     557          264 :     od.setPrecision(gPrecision);
     558          264 :     od.openTag("vehicleTripStatistics");
     559          264 :     od.writeAttr("count", myVehicleCount);
     560          264 :     od.writeAttr("routeLength", getAvgRouteLength());
     561          264 :     od.writeAttr("speed", getAvgTripSpeed());
     562          264 :     od.writeAttr("duration", getAvgDuration());
     563          264 :     od.writeAttr("waitingTime", getAvgWaitingTime());
     564          264 :     od.writeAttr("timeLoss", getAvgTimeLoss());
     565          264 :     od.writeAttr("departDelay", getAvgDepartDelay());
     566          264 :     od.writeAttr("departDelayWaiting", getAvgDepartDelayWaiting());
     567          264 :     od.writeAttr("totalTravelTime", time2string(myTotalDuration));
     568          264 :     od.writeAttr("totalDepartDelay", time2string(TIME2STEPS(getTotalDepartDelay() + getTotalBikeDepartDelay())));
     569          264 :     od.closeTag();
     570          264 :     if (myBikeCount > 0) {
     571            6 :         od.openTag("bikeTripStatistics");
     572            6 :         od.writeAttr("count", myBikeCount);
     573            6 :         od.writeAttr("routeLength", getAvgBikeRouteLength());
     574            6 :         od.writeAttr("speed", getAvgBikeTripSpeed());
     575            6 :         od.writeAttr("duration", getAvgBikeDuration());
     576            6 :         od.writeAttr("waitingTime", getAvgBikeWaitingTime());
     577            6 :         od.writeAttr("timeLoss", getAvgBikeTimeLoss());
     578            6 :         od.writeAttr("departDelay", getAvgBikeDepartDelay());
     579            6 :         od.writeAttr("totalTravelTime", time2string(myTotalBikeDuration));
     580           12 :         od.closeTag();
     581              :     }
     582          264 :     od.openTag("pedestrianStatistics");
     583          264 :     od.writeAttr("number", myWalkCount);
     584          264 :     od.writeAttr("routeLength", getAvgWalkRouteLength());
     585          264 :     od.writeAttr("duration", getAvgWalkDuration());
     586          264 :     od.writeAttr("timeLoss", getAvgWalkTimeLoss());
     587          264 :     od.closeTag();
     588          264 :     writeRideStatistics(od, "rideStatistics", 0);
     589          264 :     writeRideStatistics(od, "transportStatistics", 1);
     590          264 : }
     591              : 
     592              : void
     593          528 : MSDevice_Tripinfo::writeRideStatistics(OutputDevice& od, const std::string& category, const int index) {
     594          528 :     od.openTag(category);
     595          528 :     od.writeAttr("number", myRideCount[index]);
     596          528 :     if (myRideCount[index] > 0) {
     597            2 :         od.writeAttr("waitingTime", STEPS2TIME(myTotalRideWaitingTime[index] / myRideCount[index]));
     598            2 :         od.writeAttr("routeLength", myTotalRideRouteLength[index] / myRideCount[index]);
     599            2 :         od.writeAttr("duration", STEPS2TIME(myTotalRideDuration[index] / myRideCount[index]));
     600            2 :         od.writeAttr("bus", myRideBusCount[index]);
     601            2 :         od.writeAttr("train", myRideRailCount[index]);
     602            2 :         od.writeAttr("taxi", myRideTaxiCount[index]);
     603            2 :         od.writeAttr("bike", myRideBikeCount[index]);
     604            2 :         od.writeAttr("aborted", myRideAbortCount[index]);
     605              :     }
     606          528 :     od.closeTag();
     607          528 : }
     608              : 
     609              : 
     610              : double
     611         3486 : MSDevice_Tripinfo::getAvgRouteLength() {
     612         3486 :     if (myVehicleCount > 0) {
     613         3250 :         return myTotalRouteLength / myVehicleCount;
     614              :     } else {
     615              :         return 0;
     616              :     }
     617              : }
     618              : 
     619              : double
     620         3486 : MSDevice_Tripinfo::getAvgTripSpeed() {
     621         3486 :     if (myVehicleCount > 0) {
     622         3250 :         return myTotalSpeed / myVehicleCount;
     623              :     } else {
     624              :         return 0;
     625              :     }
     626              : }
     627              : 
     628              : double
     629         3486 : MSDevice_Tripinfo::getAvgDuration() {
     630         3486 :     if (myVehicleCount > 0) {
     631         3250 :         return STEPS2TIME(myTotalDuration / myVehicleCount);
     632              :     } else {
     633              :         return 0;
     634              :     }
     635              : }
     636              : 
     637              : double
     638         3486 : MSDevice_Tripinfo::getAvgWaitingTime() {
     639         3486 :     if (myVehicleCount > 0) {
     640         3250 :         return STEPS2TIME(myTotalWaitingTime / myVehicleCount);
     641              :     } else {
     642              :         return 0;
     643              :     }
     644              : }
     645              : 
     646              : 
     647              : double
     648         3486 : MSDevice_Tripinfo::getAvgTimeLoss() {
     649         3486 :     if (myVehicleCount > 0) {
     650         3250 :         return STEPS2TIME(myTotalTimeLoss / myVehicleCount);
     651              :     } else {
     652              :         return 0;
     653              :     }
     654              : }
     655              : 
     656              : 
     657              : double
     658         3486 : MSDevice_Tripinfo::getAvgDepartDelay() {
     659         3486 :     if (myVehicleCount > 0) {
     660         3250 :         return STEPS2TIME(myTotalDepartDelay / myVehicleCount);
     661              :     } else {
     662              :         return 0;
     663              :     }
     664              : }
     665              : 
     666              : double
     667          757 : MSDevice_Tripinfo::getAvgDepartDelayWaiting() {
     668          757 :     if (myWaitingDepartDelay >= 0) {
     669          407 :         return STEPS2TIME(myWaitingDepartDelay / MAX2(1, myUndepartedVehicleCount));
     670              :     } else {
     671              :         return -1;
     672              :     }
     673              : }
     674              : 
     675              : 
     676              : double
     677          626 : MSDevice_Tripinfo::getTotalDepartDelay() {
     678          626 :     return STEPS2TIME(myTotalDepartDelay + MAX2((SUMOTime)0, myWaitingDepartDelay));
     679              : }
     680              : 
     681              : double
     682          212 : MSDevice_Tripinfo::getAvgBikeRouteLength() {
     683          212 :     if (myBikeCount > 0) {
     684          163 :         return myTotalBikeRouteLength / myBikeCount;
     685              :     } else {
     686              :         return 0;
     687              :     }
     688              : }
     689              : 
     690              : double
     691          212 : MSDevice_Tripinfo::getAvgBikeTripSpeed() {
     692          212 :     if (myBikeCount > 0) {
     693          163 :         return myTotalBikeSpeed / myBikeCount;
     694              :     } else {
     695              :         return 0;
     696              :     }
     697              : }
     698              : 
     699              : double
     700          212 : MSDevice_Tripinfo::getAvgBikeDuration() {
     701          212 :     if (myBikeCount > 0) {
     702          163 :         return STEPS2TIME(myTotalBikeDuration / myBikeCount);
     703              :     } else {
     704              :         return 0;
     705              :     }
     706              : }
     707              : 
     708              : double
     709          212 : MSDevice_Tripinfo::getAvgBikeWaitingTime() {
     710          212 :     if (myBikeCount > 0) {
     711          163 :         return STEPS2TIME(myTotalBikeWaitingTime / myBikeCount);
     712              :     } else {
     713              :         return 0;
     714              :     }
     715              : }
     716              : 
     717              : 
     718              : double
     719          212 : MSDevice_Tripinfo::getAvgBikeTimeLoss() {
     720          212 :     if (myBikeCount > 0) {
     721          163 :         return STEPS2TIME(myTotalBikeTimeLoss / myBikeCount);
     722              :     } else {
     723              :         return 0;
     724              :     }
     725              : }
     726              : 
     727              : double
     728          163 : MSDevice_Tripinfo::getAvgBikeDepartDelay() {
     729          163 :     if (myBikeCount > 0) {
     730          163 :         return STEPS2TIME(myTotalBikeDepartDelay / myBikeCount);
     731              :     } else {
     732              :         return 0;
     733              :     }
     734              : }
     735              : 
     736              : 
     737              : double
     738          528 : MSDevice_Tripinfo::getTotalBikeDepartDelay() {
     739          528 :     return STEPS2TIME(myTotalBikeDepartDelay);
     740              : }
     741              : 
     742              : double
     743          606 : MSDevice_Tripinfo::getAvgWalkRouteLength() {
     744          606 :     if (myWalkCount > 0) {
     745          299 :         return myTotalWalkRouteLength / myWalkCount;
     746              :     } else {
     747              :         return 0;
     748              :     }
     749              : }
     750              : 
     751              : double
     752          606 : MSDevice_Tripinfo::getAvgWalkDuration() {
     753          606 :     if (myWalkCount > 0) {
     754          299 :         return STEPS2TIME(myTotalWalkDuration / myWalkCount);
     755              :     } else {
     756              :         return 0;
     757              :     }
     758              : }
     759              : 
     760              : 
     761              : double
     762          606 : MSDevice_Tripinfo::getAvgWalkTimeLoss() {
     763          606 :     if (myWalkCount > 0) {
     764          299 :         return STEPS2TIME(myTotalWalkTimeLoss / myWalkCount);
     765              :     } else {
     766              :         return 0;
     767              :     }
     768              : }
     769              : 
     770              : 
     771              : double
     772            0 : MSDevice_Tripinfo::getAvgRideDuration() {
     773            0 :     if (myRideCount[0] > 0) {
     774            0 :         return STEPS2TIME(myTotalRideDuration[0] / myRideCount[0]);
     775              :     } else {
     776              :         return 0;
     777              :     }
     778              : }
     779              : 
     780              : double
     781            0 : MSDevice_Tripinfo::getAvgRideWaitingTime() {
     782            0 :     if (myRideCount[0] > 0) {
     783            0 :         return STEPS2TIME(myTotalRideWaitingTime[0] / myRideCount[0]);
     784              :     } else {
     785              :         return 0;
     786              :     }
     787              : }
     788              : 
     789              : double
     790            0 : MSDevice_Tripinfo::getAvgRideRouteLength() {
     791            0 :     if (myRideCount[0] > 0) {
     792            0 :         return myTotalRideRouteLength[0] / myRideCount[0];
     793              :     } else {
     794              :         return 0;
     795              :     }
     796              : }
     797              : 
     798              : 
     799              : std::string
     800          255 : MSDevice_Tripinfo::getParameter(const std::string& key) const {
     801          255 :     if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     802           40 :         return toString(STEPS2TIME(myWaitingTime));
     803          215 :     } else if (key == toString(SUMO_ATTR_WAITINGCOUNT)) {
     804           40 :         return toString(myWaitingCount);
     805          175 :     } else if (key == toString(SUMO_ATTR_STOPTIME)) {
     806           40 :         return toString(STEPS2TIME(myStoppingTime));
     807          135 :     } else if (key == toString(SUMO_ATTR_ARRIVALTIME)) {
     808           27 :         return toString(STEPS2TIME(myArrivalTime));
     809          108 :     } else if (key == toString(SUMO_ATTR_ARRIVALLANE)) {
     810              :         return toString(myArrivalLane);
     811           81 :     } else if (key == toString(SUMO_ATTR_ARRIVALPOS)) {
     812           27 :         return toString(myArrivalPos);
     813           54 :     } else if (key == toString(SUMO_ATTR_ARRIVALPOS_LAT)) {
     814           27 :         return toString(myArrivalPosLat);
     815           27 :     } else if (key == toString(SUMO_ATTR_ARRIVALSPEED)) {
     816           27 :         return toString(myArrivalSpeed);
     817              :     }
     818            0 :     throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     819              : }
     820              : 
     821              : 
     822              : std::string
     823         2548 : MSDevice_Tripinfo::getGlobalParameter(const std::string& prefixedKey) {
     824              :     std::string key = prefixedKey; // by default, assume vehicleTripStatistics;
     825         2548 :     const std::string err = "Parameter '" + prefixedKey + "' is not supported for device of type 'tripinfo'";
     826         5096 :     if (StringUtils::startsWith(key, "vehicleTripStatistics.")) {
     827          980 :         key = prefixedKey.substr(22);
     828         4116 :     } else if (StringUtils::startsWith(key, "bikeTripStatistics.")) {
     829          343 :         key = prefixedKey.substr(19);
     830          343 :         if (key == toString(SUMO_ATTR_COUNT)) {
     831           49 :             return toString(myBikeCount);
     832          294 :         } else if (key == "routeLength") {
     833           49 :             return toString(getAvgBikeRouteLength());
     834          245 :         } else if (key == toString(SUMO_ATTR_SPEED)) {
     835           49 :             return toString(getAvgBikeTripSpeed());
     836          196 :         } else if (key == toString(SUMO_ATTR_DURATION)) {
     837           49 :             return toString(getAvgBikeDuration());
     838          147 :         } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     839           49 :             return toString(getAvgBikeWaitingTime());
     840           98 :         } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
     841           49 :             return toString(getAvgBikeTimeLoss());
     842           49 :         } else if (key == "departDelay") {
     843            0 :             return toString(getAvgBikeDepartDelay());
     844           49 :         } else if (key == "totalTravelTime") {
     845              :             // avoid human readable output
     846           49 :             return toString(STEPS2TIME((myTotalBikeDuration)));
     847              :         }
     848            0 :         throw InvalidArgument(err);
     849              : 
     850         3430 :     } else if (StringUtils::startsWith(key, "pedestrianStatistics.")) {
     851          245 :         key = prefixedKey.substr(21);
     852          441 :         if (key == toString(SUMO_ATTR_NUMBER) || key == toString(SUMO_ATTR_COUNT)) {
     853           98 :             return toString(myWalkCount);
     854          147 :         } else if (key == "routeLength") {
     855           49 :             return toString(getAvgWalkRouteLength());
     856           98 :         } else if (key == toString(SUMO_ATTR_DURATION)) {
     857           49 :             return toString(getAvgWalkDuration());
     858           49 :         } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
     859           49 :             return toString(getAvgWalkTimeLoss());
     860              :         }
     861            0 :         throw InvalidArgument(err);
     862              : 
     863         2940 :     } else if (StringUtils::startsWith(key, "rideStatistics.") ||
     864         2450 :                StringUtils::startsWith(key, "transportStatistics.")) {
     865              :         int index = 0;
     866         1960 :         if (StringUtils::startsWith(key, "rideStatistics.")) {
     867          980 :             key = prefixedKey.substr(15);
     868              :         } else {
     869              :             index = 1;
     870          980 :             key = prefixedKey.substr(20);
     871              :         }
     872         1862 :         if (key == toString(SUMO_ATTR_NUMBER) || key == toString(SUMO_ATTR_COUNT)) {
     873          196 :             return toString(myRideCount[index]);
     874          784 :         } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     875           98 :             return toString(STEPS2TIME(myTotalRideWaitingTime[index] / MAX2(1, myRideCount[index])));
     876          686 :         } else if (key == "routeLength") {
     877           98 :             return toString(myTotalRideRouteLength[index] / MAX2(1, myRideCount[index]));
     878          588 :         } else if (key == toString(SUMO_ATTR_DURATION)) {
     879           98 :             return toString(myTotalRideRouteLength[index] / MAX2(1, myRideCount[index]));
     880          490 :         } else if (key == "bus") {
     881           98 :             return toString(myRideBusCount[index]);
     882          392 :         } else if (key == "train") {
     883           98 :             return toString(myRideRailCount[index]);
     884          294 :         } else if (key == "taxi") {
     885           98 :             return toString(myRideTaxiCount[index]);
     886          196 :         } else if (key == "bike") {
     887           98 :             return toString(myRideBikeCount[index]);
     888           98 :         } else if (key == "aborted") {
     889           98 :             return toString(myRideAbortCount[index]);
     890              :         }
     891            0 :         throw InvalidArgument(err);
     892              :     }
     893              :     // vehicleTripStatistics
     894          980 :     if (key == toString(SUMO_ATTR_COUNT)) {
     895           98 :         return toString(myVehicleCount);
     896          882 :     } else if (key == "routeLength") {
     897           98 :         return toString(getAvgRouteLength());
     898          784 :     } else if (key == toString(SUMO_ATTR_SPEED)) {
     899           98 :         return toString(getAvgTripSpeed());
     900          686 :     } else if (key == toString(SUMO_ATTR_DURATION)) {
     901           98 :         return toString(getAvgDuration());
     902          588 :     } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     903           98 :         return toString(getAvgWaitingTime());
     904          490 :     } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
     905           98 :         return toString(getAvgTimeLoss());
     906          392 :     } else if (key == "departDelay") {
     907           98 :         return toString(getAvgDepartDelay());
     908          294 :     } else if (key == "departDelayWaiting") {
     909           98 :         return toString(getAvgDepartDelayWaiting());
     910          196 :     } else if (key == "totalTravelTime") {
     911              :         // avoid human readable output
     912           98 :         return toString(STEPS2TIME((myTotalDuration)));
     913           98 :     } else if (key == "totalDepartDelay") {
     914           98 :         return toString(getTotalDepartDelay());
     915              :     }
     916            0 :     throw InvalidArgument(err);
     917              : }
     918              : 
     919              : 
     920              : void
     921          259 : MSDevice_Tripinfo::saveState(OutputDevice& out) const {
     922              :     // always write device id to replicate stochastic assignment
     923          259 :     out.openTag(SUMO_TAG_DEVICE);
     924          259 :     out.writeAttr(SUMO_ATTR_ID, getID());
     925          259 :     if (myHolder.hasDeparted()) {
     926          181 :         std::ostringstream internals;
     927          181 :         internals << myDepartLane << " ";
     928          181 :         if (!MSGlobals::gUseMesoSim) {
     929          105 :             internals << myDepartPosLat << " ";
     930              :         }
     931          181 :         std::string state_arrivalLane = myArrivalLane == "" ? STATE_EMPTY_ARRIVALLANE : myArrivalLane;
     932          905 :         internals << myDepartSpeed << " " << myRouteLength << " " << myWaitingTime << " " << myAmWaiting << " " << myWaitingCount << " ";
     933          362 :         internals << myStoppingTime << " " << myParkingStarted << " ";
     934          724 :         internals << myArrivalTime << " " << state_arrivalLane << " " << myArrivalPos << " " << myArrivalPosLat << " " << myArrivalSpeed;
     935          181 :         out.writeAttr(SUMO_ATTR_STATE, internals.str());
     936          181 :     }
     937          259 :     out.closeTag();
     938          259 : }
     939              : 
     940              : 
     941              : void
     942          220 : MSDevice_Tripinfo::loadState(const SUMOSAXAttributes& attrs) {
     943          220 :     if (attrs.hasAttribute(SUMO_ATTR_STATE)) {
     944          160 :         std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
     945          160 :         bis >> myDepartLane;
     946          160 :         if (!MSGlobals::gUseMesoSim) {
     947           95 :             bis >> myDepartPosLat;
     948              :         }
     949          160 :         bis >> myDepartSpeed >> myRouteLength >> myWaitingTime >> myAmWaiting >> myWaitingCount;
     950          160 :         bis >> myStoppingTime >> myParkingStarted;
     951          160 :         bis >> myArrivalTime >> myArrivalLane >> myArrivalPos >> myArrivalPosLat >> myArrivalSpeed;
     952          160 :         if (myArrivalLane == STATE_EMPTY_ARRIVALLANE) {
     953              :             myArrivalLane = "";
     954              :         }
     955          160 :     }
     956          220 : }
     957              : 
     958              : 
     959              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1