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 % 524 508
Test Date: 2026-10-12 15:53:19 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        46427 : MSDevice_Tripinfo::insertOptions(OptionsCont& oc) {
      87        46427 :     oc.addOptionSubTopic("Tripinfo Device");
      88        92854 :     insertDefaultAssignmentOptions("tripinfo", "Tripinfo Device", oc);
      89        46427 : }
      90              : 
      91              : 
      92              : void
      93      5496629 : MSDevice_Tripinfo::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
      94      5496629 :     OptionsCont& oc = OptionsCont::getOptions();
      95     10718080 :     const bool enableByOutputOption = oc.isSet("tripinfo-output") || oc.getBool("duration-log.statistics");
      96     10993258 :     if (equippedByDefaultAssignmentOptions(oc, "tripinfo", v, enableByOutputOption)) {
      97      2492729 :         MSDevice_Tripinfo* device = new MSDevice_Tripinfo(v, "tripinfo_" + v.getID());
      98      2492729 :         into.push_back(device);
      99              :         myPendingOutput.insert(device);
     100              :     }
     101      5496629 : }
     102              : 
     103              : 
     104              : // ---------------------------------------------------------------------------
     105              : // MSDevice_Tripinfo-methods
     106              : // ---------------------------------------------------------------------------
     107      2492729 : MSDevice_Tripinfo::MSDevice_Tripinfo(SUMOVehicle& holder, const std::string& id) :
     108              :     MSVehicleDevice(holder, id),
     109            0 :     myDepartLane(""),
     110      2492729 :     myDepartSpeed(-1),
     111      2492729 :     myDepartPosLat(0),
     112      2492729 :     myWaitingTime(0),
     113      2492729 :     myAmWaiting(false),
     114      2492729 :     myWaitingCount(0),
     115      2492729 :     myStoppingTime(0),
     116      2492729 :     myParkingStarted(-1),
     117      2492729 :     myArrivalTime(NOT_ARRIVED),
     118      2492729 :     myArrivalLane(""),
     119      2492729 :     myArrivalPos(-1),
     120      2492729 :     myArrivalPosLat(0.),
     121      2492729 :     myArrivalSpeed(-1),
     122      2492729 :     myArrivalReason(MSMoveReminder::NOTIFICATION_ARRIVED),
     123      2492729 :     myMesoTimeLoss(0),
     124      2492729 :     myRouteLength(0.) {
     125      2492729 : }
     126              : 
     127              : 
     128      4985404 : MSDevice_Tripinfo::~MSDevice_Tripinfo() {
     129              :     // ensure clean up for vaporized vehicles which do not generate output
     130      2492702 :     myPendingOutput.erase(this);
     131      4985404 : }
     132              : 
     133              : void
     134        43204 : MSDevice_Tripinfo::cleanup() {
     135        43204 :     myVehicleCount = 0;
     136        43204 :     myTotalRouteLength = 0;
     137        43204 :     myTotalSpeed = 0;
     138        43204 :     myTotalDuration = 0;
     139        43204 :     myTotalWaitingTime = 0;
     140        43204 :     myTotalTimeLoss = 0;
     141        43204 :     myTotalDepartDelay = 0;
     142        43204 :     myWaitingDepartDelay = -1;
     143              : 
     144        43204 :     myBikeCount = 0;
     145        43204 :     myTotalBikeRouteLength = 0;
     146        43204 :     myTotalBikeSpeed = 0;
     147        43204 :     myTotalBikeDuration = 0;
     148        43204 :     myTotalBikeWaitingTime = 0;
     149        43204 :     myTotalBikeTimeLoss = 0;
     150        43204 :     myTotalBikeDepartDelay = 0;
     151              : 
     152        43204 :     myWalkCount = 0;
     153        43204 :     myTotalWalkRouteLength = 0;
     154        43204 :     myTotalWalkDuration = 0;
     155        43204 :     myTotalWalkTimeLoss = 0;
     156              : 
     157        43204 :     myRideCount = {0, 0};
     158        43204 :     myRideBusCount = {0, 0};
     159        43204 :     myRideRailCount = {0, 0};
     160        43204 :     myRideTaxiCount = {0, 0};
     161        43204 :     myRideBikeCount = {0, 0};
     162        43204 :     myRideAbortCount = {0, 0};
     163        43204 :     myTotalRideWaitingTime = {0, 0};
     164        43204 :     myTotalRideRouteLength = {0., 0.};
     165        43204 :     myTotalRideDuration = {0, 0};
     166        43204 : }
     167              : 
     168              : bool
     169         4977 : MSDevice_Tripinfo::notifyIdle(SUMOTrafficObject& veh) {
     170         4977 :     if (veh.isVehicle()) {
     171         4977 :         myWaitingTime += DELTA_T;
     172         4977 :         if (!myAmWaiting) {
     173          167 :             myWaitingCount++;
     174          167 :             myAmWaiting = true;
     175              :         }
     176              :     }
     177         4977 :     return true;
     178              : }
     179              : 
     180              : 
     181              : bool
     182    357387947 : MSDevice_Tripinfo::notifyMove(SUMOTrafficObject& veh, double /*oldPos*/,
     183              :                               double /*newPos*/, double newSpeed) {
     184    357387947 :     if (veh.isStopped()) {
     185      2278546 :         if (newSpeed <= SUMO_const_haltingSpeed) {
     186      2278350 :             myStoppingTime += DELTA_T;
     187              :         }
     188    355109401 :     } else if (newSpeed <= SUMO_const_haltingSpeed && lowAcceleration(veh)) {
     189     59955464 :         myWaitingTime += DELTA_T;
     190     59955464 :         if (!myAmWaiting) {
     191      2835696 :             myWaitingCount++;
     192      2835696 :             myAmWaiting = true;
     193              :         }
     194              :     } else {
     195    295153937 :         myAmWaiting = false;
     196              :     }
     197    357387947 :     return true;
     198              : }
     199              : 
     200              : 
     201              : bool
     202     59956293 : MSDevice_Tripinfo::lowAcceleration(const SUMOTrafficObject& veh) {
     203     59956293 :     if (MSGlobals::gUseMesoSim) {
     204              :         // acceleration is not modelled
     205              :         return false;
     206              :     } else {
     207     59956293 :         const MSVehicle& v = dynamic_cast<const MSVehicle&>(veh);
     208     59956293 :         return v.getAcceleration() <= v.accelThresholdForWaiting();
     209              :     }
     210              : }
     211              : 
     212              : 
     213              : void
     214     14966906 : 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     14966906 :     const double vmax = veh.getEdge()->getVehicleMaxSpeed(&veh);
     225     14966906 :     if (vmax > 0) {
     226     18711699 :         myMesoTimeLoss += TIME2STEPS(timeOnLane * (vmax - meanSpeedVehicleOnLane) / vmax);
     227              :     }
     228     14966906 :     myWaitingTime += veh.getWaitingTime();
     229     14966906 :     if (veh.getWaitingTime() >= TIME2STEPS(1)) {
     230              :         // waiting counts the time spent waiting to enter the next link (when it's occupied).
     231       107552 :         myWaitingCount++;
     232              :     }
     233     14966906 : }
     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      1904853 : MSDevice_Tripinfo::updateParkingStopTime() {
     245      1904853 :     if (myParkingStarted >= 0) {
     246         4525 :         myStoppingTime += (MSNet::getInstance()->getCurrentTimeStep() - myParkingStarted);
     247         4525 :         myParkingStarted = -1;
     248              :     }
     249      1904853 : }
     250              : 
     251              : bool
     252     29980177 : MSDevice_Tripinfo::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     253     29980177 :     if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
     254      1937681 :         if (!MSGlobals::gUseMesoSim) {
     255      1441424 :             myDepartLane = static_cast<MSVehicle&>(veh).getLane()->getID();
     256      1441424 :             myDepartPosLat = static_cast<MSVehicle&>(veh).getLateralPositionOnLane();
     257              :         } else {
     258       496257 :             myDepartLane = veh.getEdge()->getFirstAllowed(veh.getVClass(), true)->getID();
     259              :         }
     260      1937681 :         myDepartSpeed = veh.getSpeed();
     261      1937681 :         myRouteLength = -veh.getPositionOnLane();
     262     28042496 :     } else if (reason == MSMoveReminder::NOTIFICATION_PARKING) {
     263              :         // notifyMove is not called while parking
     264              :         // @note insertion delay when resuming after parking is included
     265         3870 :         updateParkingStopTime();
     266              :     }
     267     29980177 :     return true;
     268              : }
     269              : 
     270              : 
     271              : bool
     272     29904011 : MSDevice_Tripinfo::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/,
     273              :                                MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     274     29904011 :     if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
     275      1864685 :         myArrivalTime = MSNet::getInstance()->getCurrentTimeStep();
     276      1864685 :         myArrivalReason = reason;
     277      1864685 :         if (!MSGlobals::gUseMesoSim) {
     278      1376283 :             myArrivalLane = static_cast<MSVehicle&>(veh).getLane()->getID();
     279      1376283 :             myArrivalPosLat = static_cast<MSVehicle&>(veh).getLateralPositionOnLane();
     280              :         } else {
     281       488402 :             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      1864685 :         if (reason > MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED) {
     287              :             // vaporized
     288          549 :             myArrivalPos = veh.getPositionOnLane();
     289              :         } else {
     290      1864136 :             myArrivalPos = myHolder.getArrivalPos();
     291              :         }
     292      1864685 :         myArrivalSpeed = veh.getSpeed();
     293      1864685 :         updateParkingStopTime();
     294     28039326 :     } else if (reason == MSMoveReminder::NOTIFICATION_PARKING) {
     295         4708 :         myParkingStarted = MSNet::getInstance()->getCurrentTimeStep();
     296     28034618 :     } else if (reason == NOTIFICATION_JUNCTION
     297     28034618 :                || reason == NOTIFICATION_TELEPORT
     298     12673168 :                || reason == NOTIFICATION_TELEPORT_CONTINUATION) {
     299     15366921 :         if (MSGlobals::gUseMesoSim) {
     300      2632833 :             myRouteLength += myHolder.getCurrentEdge()->getLength();
     301              :         } else {
     302     12734088 :             const MSLane* lane = static_cast<MSVehicle&>(veh).getLane();
     303     12734088 :             if (lane != nullptr) {
     304     12734064 :                 myRouteLength += lane->getLength();
     305              :             }
     306              :         }
     307              :     }
     308     29904011 :     return true;
     309              : }
     310              : 
     311              : 
     312              : void
     313      1902101 : MSDevice_Tripinfo::generateOutput(OutputDevice* tripinfoOut) const {
     314      1902101 :     const SUMOTime timeLoss = MSGlobals::gUseMesoSim ? myMesoTimeLoss : static_cast<MSVehicle&>(myHolder).getTimeLoss();
     315      1902101 :     const double routeLength = myRouteLength + (myArrivalTime == NOT_ARRIVED ? myHolder.getPositionOnLane() : myArrivalPos);
     316              :     SUMOTime duration = 0;
     317      1902101 :     if (myHolder.hasDeparted()) {
     318      1939243 :         duration = (myArrivalTime == NOT_ARRIVED ? SIMSTEP : myArrivalTime) - myHolder.getDeparture();
     319      1901857 :         const SUMOTime drivingDuration = duration - myStoppingTime;
     320      1901857 :         const double speed = drivingDuration > 0 ? routeLength / STEPS2TIME(drivingDuration) : 0;
     321      1901857 :         if (myHolder.getVClass() == SVC_BICYCLE) {
     322        25602 :             myBikeCount++;
     323        25602 :             myTotalBikeRouteLength += routeLength;
     324        25602 :             myTotalBikeSpeed += speed;
     325        25602 :             myTotalBikeDuration += duration;
     326        25602 :             myTotalBikeWaitingTime += myWaitingTime;
     327        25602 :             myTotalBikeTimeLoss += timeLoss;
     328        25602 :             myTotalBikeDepartDelay += myHolder.getDepartDelay();
     329              :         } else {
     330      1876255 :             myVehicleCount++;
     331      1876255 :             myTotalRouteLength += routeLength;
     332      1876255 :             myTotalSpeed += speed;
     333      1876255 :             myTotalDuration += duration;
     334      1876255 :             myTotalWaitingTime += myWaitingTime;
     335      1876255 :             myTotalTimeLoss += timeLoss;
     336      1876255 :             myTotalDepartDelay += myHolder.getDepartDelay();
     337              :         }
     338              :     }
     339              : 
     340      1902101 :     myPendingOutput.erase(this);
     341      1902101 :     if (tripinfoOut == nullptr) {
     342      1658327 :         return;
     343              :     }
     344              :     // write
     345              :     OutputDevice& os = *tripinfoOut;
     346       243774 :     os.openTag("tripinfo").writeAttr("id", myHolder.getID());
     347       243774 :     os.writeAttr("depart", myHolder.hasDeparted() ? time2string(myHolder.getDeparture()) : "-1");
     348       243774 :     os.writeAttr("departLane", myDepartLane);
     349       243774 :     os.writeAttr("departPos", myHolder.getDepartPos());
     350       243774 :     if (MSGlobals::gLateralResolution > 0) {
     351        26150 :         os.writeAttr("departPosLat", myDepartPosLat);
     352              :     }
     353       243774 :     os.writeAttr("departSpeed", myDepartSpeed);
     354       243774 :     SUMOTime departDelay = myHolder.getDepartDelay();
     355       243774 :     const SUMOVehicleParameter& param = myHolder.getParameter();
     356       243774 :     if (!myHolder.hasDeparted()) {
     357              :         assert(param.depart <= SIMSTEP || param.departProcedure != DepartDefinition::GIVEN);
     358          244 :         departDelay = SIMSTEP - param.depart;
     359              :     }
     360       243774 :     os.writeAttr("departDelay", time2string(departDelay));
     361       243774 :     os.writeAttr("arrival", time2string(myArrivalTime));
     362       243774 :     os.writeAttr("arrivalLane", myArrivalLane);
     363       243774 :     os.writeAttr("arrivalPos", myArrivalPos);
     364       243774 :     if (MSGlobals::gLateralResolution > 0) {
     365        26150 :         os.writeAttr("arrivalPosLat", myArrivalPosLat);
     366              :     }
     367       243774 :     os.writeAttr("arrivalSpeed", myArrivalSpeed);
     368       243774 :     os.writeAttr("duration", time2string(duration));
     369       243774 :     os.writeAttr("routeLength", routeLength);
     370       243774 :     os.writeAttr(SUMO_ATTR_WAITINGTIME, time2string(myWaitingTime));
     371       243774 :     os.writeAttr(SUMO_ATTR_WAITINGCOUNT, myWaitingCount);
     372       243774 :     os.writeAttr(SUMO_ATTR_STOPTIME, time2string(myStoppingTime));
     373       243774 :     os.writeAttr(SUMO_ATTR_TIMELOSS, time2string(timeLoss));
     374       243774 :     os.writeAttr("rerouteNo", myHolder.getNumberReroutes());
     375       487548 :     os.writeAttr("devices", toString(myHolder.getDevices()));
     376       243774 :     os.writeAttr("vType", myHolder.getVehicleType().getID());
     377       243774 :     os.writeAttr("speedFactor", myHolder.getChosenSpeedFactor());
     378              :     std::string vaporized;
     379       243774 :     switch (myArrivalReason) {
     380              :         case MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR:
     381              :             vaporized = "calibrator";
     382              :             break;
     383              :         case MSMoveReminder::NOTIFICATION_VAPORIZED_GUI:
     384              :             vaporized = "gui";
     385              :             break;
     386              :         case MSMoveReminder::NOTIFICATION_VAPORIZED_COLLISION:
     387              :             vaporized = "collision";
     388              :             break;
     389              :         case MSMoveReminder::NOTIFICATION_VAPORIZED_VAPORIZER:
     390              :             vaporized = "vaporizer";
     391              :             break;
     392              :         case MSMoveReminder::NOTIFICATION_VAPORIZED_TRACI:
     393              :             vaporized = "traci";
     394              :             break;
     395              :         case MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED:
     396              :             vaporized = "teleport";
     397              :             break;
     398       243371 :         default:
     399       243371 :             if (myHolder.getEdge() == myHolder.getRoute().getLastEdge() ||
     400         1632 :                     (param.arrivalEdge >= 0 && myHolder.getRoutePosition() >= param.arrivalEdge)) {
     401              :                 vaporized = "";
     402              :             } else {
     403              :                 vaporized = "end";
     404              :             }
     405              :             break;
     406              :     }
     407       243774 :     os.writeAttr("vaporized", vaporized);
     408              :     // cannot close tag because emission device output might follow
     409              : }
     410              : 
     411              : 
     412              : void
     413         1114 : MSDevice_Tripinfo::generateOutputForUnfinished() {
     414         1114 :     MSNet* net = MSNet::getInstance();
     415         1114 :     OutputDevice* tripinfoOut = (OptionsCont::getOptions().isSet("tripinfo-output") ?
     416         1965 :                                  &OutputDevice::getDeviceByOption("tripinfo-output") : nullptr);
     417         1114 :     myWaitingDepartDelay = 0;
     418         1114 :     myUndepartedVehicleCount = 0;
     419         2228 :     const bool writeUndeparted = OptionsCont::getOptions().getBool("tripinfo-output.write-undeparted");
     420              :     const SUMOTime t = net->getCurrentTimeStep();
     421        69129 :     while (myPendingOutput.size() > 0) {
     422        68015 :         const MSDevice_Tripinfo* d = *myPendingOutput.begin();
     423        68015 :         const bool departed = d->myHolder.hasDeparted();
     424        68015 :         const bool departDelayed = d->myHolder.getParameter().depart <= t;
     425        68015 :         if (!departed && departDelayed) {
     426        31949 :             myUndepartedVehicleCount++;
     427        31949 :             myWaitingDepartDelay += (t - d->myHolder.getParameter().depart);
     428              :         }
     429        68015 :         if (departed || (writeUndeparted && departDelayed)) {
     430        36298 :             const_cast<MSDevice_Tripinfo*>(d)->updateParkingStopTime();
     431        36298 :             d->generateOutput(tripinfoOut);
     432        36298 :             if (tripinfoOut != nullptr) {
     433         8048 :                 for (MSVehicleDevice* const dev : d->myHolder.getDevices()) {
     434         5773 :                     if (typeid(*dev) == typeid(MSDevice_Tripinfo) || typeid(*dev) == typeid(MSDevice_Vehroutes)) {
     435              :                         // tripinfo is special and vehroute has its own write-unfinished option
     436         2947 :                         continue;
     437              :                     }
     438         2826 :                     dev->generateOutput(tripinfoOut);
     439              :                 }
     440         4550 :                 OutputDevice::getDeviceByOption("tripinfo-output").closeTag();
     441              :             }
     442              :         } else {
     443              :             myPendingOutput.erase(d);
     444              :         }
     445              :     }
     446              :     // unfinished persons
     447         1114 :     if (net->hasPersons()) {
     448          646 :         net->getPersonControl().eraseAll();
     449              :     }
     450              : 
     451         1114 : }
     452              : 
     453              : 
     454              : void
     455        55558 : MSDevice_Tripinfo::addPedestrianData(double walkLength, SUMOTime walkDuration, SUMOTime walkTimeLoss) {
     456        55558 :     myWalkCount++;
     457        55558 :     myTotalWalkRouteLength += walkLength;
     458        55558 :     myTotalWalkDuration += walkDuration;
     459        55558 :     myTotalWalkTimeLoss += walkTimeLoss;
     460        55558 : }
     461              : 
     462              : 
     463              : void
     464         7626 : MSDevice_Tripinfo::addRideTransportData(const bool isPerson, const double distance, const SUMOTime duration,
     465              :                                         const SUMOVehicleClass vClass, const std::string& line, const SUMOTime waitingTime) {
     466         7626 :     const int index = isPerson ? 0 : 1;
     467         7626 :     myRideCount[index]++;
     468         7626 :     if (duration > 0) {
     469         7289 :         myTotalRideWaitingTime[index] += waitingTime;
     470         7289 :         myTotalRideRouteLength[index] += distance;
     471         7289 :         myTotalRideDuration[index] += duration;
     472         7289 :         if (vClass == SVC_BICYCLE) {
     473           25 :             myRideBikeCount[index]++;
     474         7264 :         } else if (!line.empty()) {
     475         6046 :             if (isRailway(vClass)) {
     476          847 :                 myRideRailCount[index]++;
     477         5199 :             } else if (vClass == SVC_TAXI) {
     478         1941 :                 myRideTaxiCount[index]++;
     479              :             } else {
     480              :                 // some kind of road vehicle
     481         3258 :                 myRideBusCount[index]++;
     482              :             }
     483              :         }
     484              :     } else {
     485          337 :         myRideAbortCount[index]++;
     486              :     }
     487         7626 : }
     488              : 
     489              : 
     490              : std::string
     491         3527 : MSDevice_Tripinfo::printStatistics() {
     492         3527 :     std::ostringstream msg;
     493              :     msg.setf(msg.fixed);
     494         3527 :     msg.precision(gPrecision);
     495         3527 :     if (myBikeCount == 0 || myVehicleCount > 0) {
     496         3456 :         msg << "Statistics (avg of " << myVehicleCount << "):\n";
     497         3456 :         msg << " RouteLength: " << getAvgRouteLength() << "\n"
     498         3456 :             << " Speed: " << getAvgTripSpeed() << "\n"
     499         3456 :             << " Duration: " << getAvgDuration() << "\n"
     500         3456 :             << " WaitingTime: " << getAvgWaitingTime() << "\n"
     501         3456 :             << " TimeLoss: " << getAvgTimeLoss() << "\n"
     502         6912 :             << " DepartDelay: " << getAvgDepartDelay() << "\n";
     503              :     }
     504         3527 :     if (myBikeCount > 0) {
     505              :         msg << "Bike Statistics (avg of " << myBikeCount << "):\n"
     506          320 :             << " RouteLength: " << getAvgBikeRouteLength() << "\n"
     507          160 :             << " Speed: " << getAvgBikeTripSpeed() << "\n"
     508          160 :             << " Duration: " << getAvgBikeDuration() << "\n"
     509          160 :             << " WaitingTime: " << getAvgBikeWaitingTime() << "\n"
     510          160 :             << " TimeLoss: " << getAvgBikeTimeLoss() << "\n"
     511          320 :             << " DepartDelay: " << getAvgBikeDepartDelay() << "\n";
     512          160 :         if (myVehicleCount > 0 && myWaitingDepartDelay >= 0) {
     513           19 :             msg << "Statistics (avg of " << (myVehicleCount + myBikeCount) << "):\n";
     514              :         }
     515              :     }
     516         3527 :     if (myWaitingDepartDelay >= 0) {
     517          828 :         msg << " DepartDelayWaiting: " << getAvgDepartDelayWaiting() << "\n";
     518              :     }
     519         3527 :     if (myWalkCount > 0) {
     520              :         msg << "Pedestrian Statistics (avg of " << myWalkCount << " walks):\n"
     521          600 :             << " RouteLength: " << getAvgWalkRouteLength() << "\n"
     522          300 :             << " Duration: " << getAvgWalkDuration() << "\n"
     523          600 :             << " TimeLoss: " << getAvgWalkTimeLoss() << "\n";
     524              :     }
     525         7054 :     printRideStatistics(msg, "Ride", "rides", 0);
     526         7054 :     printRideStatistics(msg, "Transport", "transports", 1);
     527         3527 :     return msg.str();
     528         3527 : }
     529              : 
     530              : void
     531         7054 : MSDevice_Tripinfo::printRideStatistics(std::ostringstream& msg, const std::string& category, const std::string& modeName, const int index) {
     532         7054 :     if (myRideCount[index] > 0) {
     533          441 :         msg << category << " Statistics (avg of " << myRideCount[index] << " " << modeName << "):\n";
     534          147 :         msg << " WaitingTime: " << STEPS2TIME(myTotalRideWaitingTime[index] / myRideCount[index]) << "\n";
     535          147 :         msg << " RouteLength: " << myTotalRideRouteLength[index] / myRideCount[index] << "\n";
     536          147 :         msg << " Duration: " << STEPS2TIME(myTotalRideDuration[index] / myRideCount[index]) << "\n";
     537          147 :         if (myRideBusCount[index] > 0) {
     538           15 :             msg << " Bus: " << myRideBusCount[index] << "\n";
     539              :         }
     540          147 :         if (myRideRailCount[index] > 0) {
     541           10 :             msg << " Train: " << myRideRailCount[index] << "\n";
     542              :         }
     543          147 :         if (myRideTaxiCount[index] > 0) {
     544           93 :             msg << " Taxi: " << myRideTaxiCount[index] << "\n";
     545              :         }
     546          147 :         if (myRideBikeCount[index] > 0) {
     547           19 :             msg << " Bike: " << myRideBikeCount[index] << "\n";
     548              :         }
     549          147 :         if (myRideAbortCount[index] > 0) {
     550           13 :             msg << " Aborted: " << myRideAbortCount[index] << "\n";
     551              :         }
     552              :     }
     553              : 
     554         7054 : }
     555              : 
     556              : 
     557              : void
     558          264 : MSDevice_Tripinfo::writeStatistics(OutputDevice& od) {
     559          264 :     od.setPrecision(gPrecision);
     560          264 :     od.openTag("vehicleTripStatistics");
     561          264 :     od.writeAttr("count", myVehicleCount);
     562          264 :     od.writeAttr("routeLength", getAvgRouteLength());
     563          264 :     od.writeAttr("speed", getAvgTripSpeed());
     564          264 :     od.writeAttr("duration", getAvgDuration());
     565          264 :     od.writeAttr("waitingTime", getAvgWaitingTime());
     566          264 :     od.writeAttr("timeLoss", getAvgTimeLoss());
     567          264 :     od.writeAttr("departDelay", getAvgDepartDelay());
     568          264 :     od.writeAttr("departDelayWaiting", getAvgDepartDelayWaiting());
     569          264 :     od.writeAttr("totalTravelTime", time2string(myTotalDuration));
     570          264 :     od.writeAttr("totalDepartDelay", time2string(TIME2STEPS(getTotalDepartDelay() + getTotalBikeDepartDelay())));
     571          264 :     od.closeTag();
     572          264 :     if (myBikeCount > 0) {
     573            6 :         od.openTag("bikeTripStatistics");
     574            6 :         od.writeAttr("count", myBikeCount);
     575            6 :         od.writeAttr("routeLength", getAvgBikeRouteLength());
     576            6 :         od.writeAttr("speed", getAvgBikeTripSpeed());
     577            6 :         od.writeAttr("duration", getAvgBikeDuration());
     578            6 :         od.writeAttr("waitingTime", getAvgBikeWaitingTime());
     579            6 :         od.writeAttr("timeLoss", getAvgBikeTimeLoss());
     580            6 :         od.writeAttr("departDelay", getAvgBikeDepartDelay());
     581            6 :         od.writeAttr("totalTravelTime", time2string(myTotalBikeDuration));
     582           12 :         od.closeTag();
     583              :     }
     584          264 :     od.openTag("pedestrianStatistics");
     585          264 :     od.writeAttr("number", myWalkCount);
     586          264 :     od.writeAttr("routeLength", getAvgWalkRouteLength());
     587          264 :     od.writeAttr("duration", getAvgWalkDuration());
     588          264 :     od.writeAttr("timeLoss", getAvgWalkTimeLoss());
     589          264 :     od.closeTag();
     590          264 :     writeRideStatistics(od, "rideStatistics", 0);
     591          264 :     writeRideStatistics(od, "transportStatistics", 1);
     592          264 : }
     593              : 
     594              : void
     595          528 : MSDevice_Tripinfo::writeRideStatistics(OutputDevice& od, const std::string& category, const int index) {
     596          528 :     od.openTag(category);
     597          528 :     od.writeAttr("number", myRideCount[index]);
     598          528 :     if (myRideCount[index] > 0) {
     599            2 :         od.writeAttr("waitingTime", STEPS2TIME(myTotalRideWaitingTime[index] / myRideCount[index]));
     600            2 :         od.writeAttr("routeLength", myTotalRideRouteLength[index] / myRideCount[index]);
     601            2 :         od.writeAttr("duration", STEPS2TIME(myTotalRideDuration[index] / myRideCount[index]));
     602            2 :         od.writeAttr("bus", myRideBusCount[index]);
     603            2 :         od.writeAttr("train", myRideRailCount[index]);
     604            2 :         od.writeAttr("taxi", myRideTaxiCount[index]);
     605            2 :         od.writeAttr("bike", myRideBikeCount[index]);
     606            2 :         od.writeAttr("aborted", myRideAbortCount[index]);
     607              :     }
     608          528 :     od.closeTag();
     609          528 : }
     610              : 
     611              : 
     612              : double
     613         3836 : MSDevice_Tripinfo::getAvgRouteLength() {
     614         3836 :     if (myVehicleCount > 0) {
     615         3582 :         return myTotalRouteLength / myVehicleCount;
     616              :     } else {
     617              :         return 0;
     618              :     }
     619              : }
     620              : 
     621              : double
     622         3836 : MSDevice_Tripinfo::getAvgTripSpeed() {
     623         3836 :     if (myVehicleCount > 0) {
     624         3582 :         return myTotalSpeed / myVehicleCount;
     625              :     } else {
     626              :         return 0;
     627              :     }
     628              : }
     629              : 
     630              : double
     631         3836 : MSDevice_Tripinfo::getAvgDuration() {
     632         3836 :     if (myVehicleCount > 0) {
     633         3582 :         return STEPS2TIME(myTotalDuration / myVehicleCount);
     634              :     } else {
     635              :         return 0;
     636              :     }
     637              : }
     638              : 
     639              : double
     640         3836 : MSDevice_Tripinfo::getAvgWaitingTime() {
     641         3836 :     if (myVehicleCount > 0) {
     642         3582 :         return STEPS2TIME(myTotalWaitingTime / myVehicleCount);
     643              :     } else {
     644              :         return 0;
     645              :     }
     646              : }
     647              : 
     648              : 
     649              : double
     650         3836 : MSDevice_Tripinfo::getAvgTimeLoss() {
     651         3836 :     if (myVehicleCount > 0) {
     652         3582 :         return STEPS2TIME(myTotalTimeLoss / myVehicleCount);
     653              :     } else {
     654              :         return 0;
     655              :     }
     656              : }
     657              : 
     658              : 
     659              : double
     660         3836 : MSDevice_Tripinfo::getAvgDepartDelay() {
     661         3836 :     if (myVehicleCount > 0) {
     662         3582 :         return STEPS2TIME(myTotalDepartDelay / myVehicleCount);
     663              :     } else {
     664              :         return 0;
     665              :     }
     666              : }
     667              : 
     668              : double
     669          794 : MSDevice_Tripinfo::getAvgDepartDelayWaiting() {
     670          794 :     if (myWaitingDepartDelay >= 0) {
     671          426 :         return STEPS2TIME(myWaitingDepartDelay / MAX2(1, myUndepartedVehicleCount));
     672              :     } else {
     673              :         return -1;
     674              :     }
     675              : }
     676              : 
     677              : 
     678              : double
     679          380 : MSDevice_Tripinfo::getTotalDepartDelay() {
     680          380 :     return STEPS2TIME(myTotalDepartDelay + MAX2((SUMOTime)0, myWaitingDepartDelay));
     681              : }
     682              : 
     683              : double
     684          224 : MSDevice_Tripinfo::getAvgBikeRouteLength() {
     685          224 :     if (myBikeCount > 0) {
     686          166 :         return myTotalBikeRouteLength / myBikeCount;
     687              :     } else {
     688              :         return 0;
     689              :     }
     690              : }
     691              : 
     692              : double
     693          224 : MSDevice_Tripinfo::getAvgBikeTripSpeed() {
     694          224 :     if (myBikeCount > 0) {
     695          166 :         return myTotalBikeSpeed / myBikeCount;
     696              :     } else {
     697              :         return 0;
     698              :     }
     699              : }
     700              : 
     701              : double
     702          224 : MSDevice_Tripinfo::getAvgBikeDuration() {
     703          224 :     if (myBikeCount > 0) {
     704          166 :         return STEPS2TIME(myTotalBikeDuration / myBikeCount);
     705              :     } else {
     706              :         return 0;
     707              :     }
     708              : }
     709              : 
     710              : double
     711          224 : MSDevice_Tripinfo::getAvgBikeWaitingTime() {
     712          224 :     if (myBikeCount > 0) {
     713          166 :         return STEPS2TIME(myTotalBikeWaitingTime / myBikeCount);
     714              :     } else {
     715              :         return 0;
     716              :     }
     717              : }
     718              : 
     719              : 
     720              : double
     721          224 : MSDevice_Tripinfo::getAvgBikeTimeLoss() {
     722          224 :     if (myBikeCount > 0) {
     723          166 :         return STEPS2TIME(myTotalBikeTimeLoss / myBikeCount);
     724              :     } else {
     725              :         return 0;
     726              :     }
     727              : }
     728              : 
     729              : double
     730          166 : MSDevice_Tripinfo::getAvgBikeDepartDelay() {
     731          166 :     if (myBikeCount > 0) {
     732          166 :         return STEPS2TIME(myTotalBikeDepartDelay / myBikeCount);
     733              :     } else {
     734              :         return 0;
     735              :     }
     736              : }
     737              : 
     738              : 
     739              : double
     740          264 : MSDevice_Tripinfo::getTotalBikeDepartDelay() {
     741          264 :     return STEPS2TIME(myTotalBikeDepartDelay);
     742              : }
     743              : 
     744              : double
     745          622 : MSDevice_Tripinfo::getAvgWalkRouteLength() {
     746          622 :     if (myWalkCount > 0) {
     747          306 :         return myTotalWalkRouteLength / myWalkCount;
     748              :     } else {
     749              :         return 0;
     750              :     }
     751              : }
     752              : 
     753              : double
     754          622 : MSDevice_Tripinfo::getAvgWalkDuration() {
     755          622 :     if (myWalkCount > 0) {
     756          306 :         return STEPS2TIME(myTotalWalkDuration / myWalkCount);
     757              :     } else {
     758              :         return 0;
     759              :     }
     760              : }
     761              : 
     762              : 
     763              : double
     764          622 : MSDevice_Tripinfo::getAvgWalkTimeLoss() {
     765          622 :     if (myWalkCount > 0) {
     766          306 :         return STEPS2TIME(myTotalWalkTimeLoss / myWalkCount);
     767              :     } else {
     768              :         return 0;
     769              :     }
     770              : }
     771              : 
     772              : 
     773              : double
     774            0 : MSDevice_Tripinfo::getAvgRideDuration() {
     775            0 :     if (myRideCount[0] > 0) {
     776            0 :         return STEPS2TIME(myTotalRideDuration[0] / myRideCount[0]);
     777              :     } else {
     778              :         return 0;
     779              :     }
     780              : }
     781              : 
     782              : double
     783            0 : MSDevice_Tripinfo::getAvgRideWaitingTime() {
     784            0 :     if (myRideCount[0] > 0) {
     785            0 :         return STEPS2TIME(myTotalRideWaitingTime[0] / myRideCount[0]);
     786              :     } else {
     787              :         return 0;
     788              :     }
     789              : }
     790              : 
     791              : double
     792            0 : MSDevice_Tripinfo::getAvgRideRouteLength() {
     793            0 :     if (myRideCount[0] > 0) {
     794            0 :         return myTotalRideRouteLength[0] / myRideCount[0];
     795              :     } else {
     796              :         return 0;
     797              :     }
     798              : }
     799              : 
     800              : 
     801              : std::string
     802          254 : MSDevice_Tripinfo::getParameter(const std::string& key) const {
     803          254 :     if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     804           48 :         return toString(STEPS2TIME(myWaitingTime));
     805          206 :     } else if (key == toString(SUMO_ATTR_WAITINGCOUNT)) {
     806           48 :         return toString(myWaitingCount);
     807          158 :     } else if (key == toString(SUMO_ATTR_STOPTIME)) {
     808           48 :         return toString(STEPS2TIME(myStoppingTime));
     809          110 :     } else if (key == toString(SUMO_ATTR_ARRIVALTIME)) {
     810           22 :         return toString(STEPS2TIME(myArrivalTime));
     811           88 :     } else if (key == toString(SUMO_ATTR_ARRIVALLANE)) {
     812              :         return toString(myArrivalLane);
     813           66 :     } else if (key == toString(SUMO_ATTR_ARRIVALPOS)) {
     814           22 :         return toString(myArrivalPos);
     815           44 :     } else if (key == toString(SUMO_ATTR_ARRIVALPOS_LAT)) {
     816           22 :         return toString(myArrivalPosLat);
     817           22 :     } else if (key == toString(SUMO_ATTR_ARRIVALSPEED)) {
     818           22 :         return toString(myArrivalSpeed);
     819              :     }
     820            0 :     throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     821              : }
     822              : 
     823              : 
     824              : std::string
     825         3016 : MSDevice_Tripinfo::getGlobalParameter(const std::string& prefixedKey) {
     826              :     std::string key = prefixedKey; // by default, assume vehicleTripStatistics;
     827         3016 :     const std::string err = "Parameter '" + prefixedKey + "' is not supported for device of type 'tripinfo'";
     828         6032 :     if (StringUtils::startsWith(key, "vehicleTripStatistics.")) {
     829         1160 :         key = prefixedKey.substr(22);
     830         4872 :     } else if (StringUtils::startsWith(key, "bikeTripStatistics.")) {
     831          406 :         key = prefixedKey.substr(19);
     832          406 :         if (key == toString(SUMO_ATTR_COUNT)) {
     833           58 :             return toString(myBikeCount);
     834          348 :         } else if (key == "routeLength") {
     835           58 :             return toString(getAvgBikeRouteLength());
     836          290 :         } else if (key == toString(SUMO_ATTR_SPEED)) {
     837           58 :             return toString(getAvgBikeTripSpeed());
     838          232 :         } else if (key == toString(SUMO_ATTR_DURATION)) {
     839           58 :             return toString(getAvgBikeDuration());
     840          174 :         } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     841           58 :             return toString(getAvgBikeWaitingTime());
     842          116 :         } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
     843           58 :             return toString(getAvgBikeTimeLoss());
     844           58 :         } else if (key == "departDelay") {
     845            0 :             return toString(getAvgBikeDepartDelay());
     846           58 :         } else if (key == "totalTravelTime") {
     847              :             // avoid human readable output
     848           58 :             return toString(STEPS2TIME((myTotalBikeDuration)));
     849              :         }
     850            0 :         throw InvalidArgument(err);
     851              : 
     852         4060 :     } else if (StringUtils::startsWith(key, "pedestrianStatistics.")) {
     853          290 :         key = prefixedKey.substr(21);
     854          522 :         if (key == toString(SUMO_ATTR_NUMBER) || key == toString(SUMO_ATTR_COUNT)) {
     855          116 :             return toString(myWalkCount);
     856          174 :         } else if (key == "routeLength") {
     857           58 :             return toString(getAvgWalkRouteLength());
     858          116 :         } else if (key == toString(SUMO_ATTR_DURATION)) {
     859           58 :             return toString(getAvgWalkDuration());
     860           58 :         } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
     861           58 :             return toString(getAvgWalkTimeLoss());
     862              :         }
     863            0 :         throw InvalidArgument(err);
     864              : 
     865         3480 :     } else if (StringUtils::startsWith(key, "rideStatistics.") ||
     866         2900 :                StringUtils::startsWith(key, "transportStatistics.")) {
     867              :         int index = 0;
     868         2320 :         if (StringUtils::startsWith(key, "rideStatistics.")) {
     869         1160 :             key = prefixedKey.substr(15);
     870              :         } else {
     871              :             index = 1;
     872         1160 :             key = prefixedKey.substr(20);
     873              :         }
     874         2204 :         if (key == toString(SUMO_ATTR_NUMBER) || key == toString(SUMO_ATTR_COUNT)) {
     875          232 :             return toString(myRideCount[index]);
     876          928 :         } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     877          116 :             return toString(STEPS2TIME(myTotalRideWaitingTime[index] / MAX2(1, myRideCount[index])));
     878          812 :         } else if (key == "routeLength") {
     879          116 :             return toString(myTotalRideRouteLength[index] / MAX2(1, myRideCount[index]));
     880          696 :         } else if (key == toString(SUMO_ATTR_DURATION)) {
     881          116 :             return toString(myTotalRideRouteLength[index] / MAX2(1, myRideCount[index]));
     882          580 :         } else if (key == "bus") {
     883          116 :             return toString(myRideBusCount[index]);
     884          464 :         } else if (key == "train") {
     885          116 :             return toString(myRideRailCount[index]);
     886          348 :         } else if (key == "taxi") {
     887          116 :             return toString(myRideTaxiCount[index]);
     888          232 :         } else if (key == "bike") {
     889          116 :             return toString(myRideBikeCount[index]);
     890          116 :         } else if (key == "aborted") {
     891          116 :             return toString(myRideAbortCount[index]);
     892              :         }
     893            0 :         throw InvalidArgument(err);
     894              :     }
     895              :     // vehicleTripStatistics
     896         1160 :     if (key == toString(SUMO_ATTR_COUNT)) {
     897          116 :         return toString(myVehicleCount);
     898         1044 :     } else if (key == "routeLength") {
     899          116 :         return toString(getAvgRouteLength());
     900          928 :     } else if (key == toString(SUMO_ATTR_SPEED)) {
     901          116 :         return toString(getAvgTripSpeed());
     902          812 :     } else if (key == toString(SUMO_ATTR_DURATION)) {
     903          116 :         return toString(getAvgDuration());
     904          696 :     } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
     905          116 :         return toString(getAvgWaitingTime());
     906          580 :     } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
     907          116 :         return toString(getAvgTimeLoss());
     908          464 :     } else if (key == "departDelay") {
     909          116 :         return toString(getAvgDepartDelay());
     910          348 :     } else if (key == "departDelayWaiting") {
     911          116 :         return toString(getAvgDepartDelayWaiting());
     912          232 :     } else if (key == "totalTravelTime") {
     913              :         // avoid human readable output
     914          116 :         return toString(STEPS2TIME((myTotalDuration)));
     915          116 :     } else if (key == "totalDepartDelay") {
     916          116 :         return toString(getTotalDepartDelay());
     917              :     }
     918            0 :     throw InvalidArgument(err);
     919              : }
     920              : 
     921              : 
     922              : void
     923          396 : MSDevice_Tripinfo::saveState(OutputDevice& out) const {
     924              :     // always write device id to replicate stochastic assignment
     925          396 :     out.openTag(SUMO_TAG_DEVICE);
     926          396 :     out.writeAttr(SUMO_ATTR_ID, getID());
     927          396 :     if (myHolder.hasDeparted()) {
     928          303 :         std::ostringstream internals;
     929          303 :         internals << myDepartLane << " ";
     930          303 :         if (!MSGlobals::gUseMesoSim) {
     931          221 :             internals << myDepartPosLat << " ";
     932              :         }
     933          303 :         std::string state_arrivalLane = myArrivalLane == "" ? STATE_EMPTY_ARRIVALLANE : myArrivalLane;
     934         1515 :         internals << myDepartSpeed << " " << myRouteLength << " " << myWaitingTime << " " << myAmWaiting << " " << myWaitingCount << " ";
     935          606 :         internals << myStoppingTime << " " << myParkingStarted << " ";
     936         1212 :         internals << myArrivalTime << " " << state_arrivalLane << " " << myArrivalPos << " " << myArrivalPosLat << " " << myArrivalSpeed;
     937          303 :         out.writeAttr(SUMO_ATTR_STATE, internals.str());
     938          303 :     }
     939          396 :     out.closeTag();
     940          396 : }
     941              : 
     942              : 
     943              : void
     944          357 : MSDevice_Tripinfo::loadState(const SUMOSAXAttributes& attrs) {
     945          357 :     if (attrs.hasAttribute(SUMO_ATTR_STATE)) {
     946          282 :         std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
     947          282 :         bis >> myDepartLane;
     948          282 :         if (!MSGlobals::gUseMesoSim) {
     949          211 :             bis >> myDepartPosLat;
     950              :         }
     951          282 :         bis >> myDepartSpeed >> myRouteLength >> myWaitingTime >> myAmWaiting >> myWaitingCount;
     952          282 :         bis >> myStoppingTime >> myParkingStarted;
     953          282 :         bis >> myArrivalTime >> myArrivalLane >> myArrivalPos >> myArrivalPosLat >> myArrivalSpeed;
     954          282 :         if (myArrivalLane == STATE_EMPTY_ARRIVALLANE) {
     955              :             myArrivalLane = "";
     956              :         }
     957          282 :     }
     958          357 : }
     959              : 
     960              : 
     961              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1