LCOV - code coverage report
Current view: top level - src/microsim/output - MSMeanData.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 93.0 % 412 383
Test Date: 2026-09-20 15:45:03 Functions: 84.6 % 39 33

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    MSMeanData.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @author  Laura Bieker
      19              : /// @author  Leonhard Luecken
      20              : /// @date    Mon, 10.05.2004
      21              : ///
      22              : // Data collector for edges/lanes
      23              : /****************************************************************************/
      24              : #include <config.h>
      25              : 
      26              : #include <limits>
      27              : #ifdef HAVE_FOX
      28              : #include <utils/common/ScopedLocker.h>
      29              : #endif
      30              : #include <utils/common/SUMOTime.h>
      31              : #include <utils/common/ToString.h>
      32              : #include <utils/common/StringTokenizer.h>
      33              : #include <utils/iodevices/OutputDevice.h>
      34              : #include <microsim/MSEdgeControl.h>
      35              : #include <microsim/MSEdge.h>
      36              : #include <microsim/MSLane.h>
      37              : #include <microsim/MSVehicle.h>
      38              : #include <microsim/cfmodels/MSCFModel.h>
      39              : #include <microsim/MSNet.h>
      40              : #include "MSMeanData_Amitran.h"
      41              : #include "MSMeanData.h"
      42              : 
      43              : #include <microsim/MSGlobals.h>
      44              : #include <mesosim/MESegment.h>
      45              : #include <mesosim/MELoop.h>
      46              : 
      47              : 
      48              : // ===========================================================================
      49              : // debug constants
      50              : // ===========================================================================
      51              : //#define DEBUG_NOTIFY_MOVE
      52              : //#define DEBUG_NOTIFY_ENTER
      53              : 
      54              : // ===========================================================================
      55              : // method definitions
      56              : // ===========================================================================
      57              : // ---------------------------------------------------------------------------
      58              : // MSMeanData::MeanDataValues - methods
      59              : // ---------------------------------------------------------------------------
      60      9145610 : MSMeanData::MeanDataValues::MeanDataValues(
      61              :     MSLane* const lane, const double length, const bool doAdd,
      62      9145610 :     const MSMeanData* const parent) :
      63     18291220 :     MSMoveReminder("meandata_" + (parent == nullptr ? "" : parent->getID() + "|") + (lane == nullptr ? "NULL" :  lane->getID()), lane, doAdd),
      64      9145610 :     myParent(parent),
      65      9145610 :     myLaneLength(length),
      66      9145610 :     sampleSeconds(0),
      67     27436830 :     travelledDistance(0) { }
      68              : 
      69              : 
      70      9144316 : MSMeanData::MeanDataValues::~MeanDataValues() {
      71      9144316 : }
      72              : 
      73              : 
      74              : bool
      75       692777 : MSMeanData::MeanDataValues::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
      76              : #ifdef DEBUG_NOTIFY_ENTER
      77              :     std::cout << "\n" << SIMTIME << " MSMeanData_Net::MSLaneMeanDataValues: veh '" << veh.getID() << "' enters lane '" << enteredLane->getID() << "'" << std::endl;
      78              : #else
      79              :     UNUSED_PARAMETER(enteredLane);
      80              : #endif
      81              :     UNUSED_PARAMETER(reason);
      82       692777 :     return myParent == nullptr || myParent->vehicleApplies(veh);
      83              : }
      84              : 
      85              : 
      86              : bool
      87    482196356 : MSMeanData::MeanDataValues::notifyMove(SUMOTrafficObject& veh, double oldPos, double newPos, double newSpeed) {
      88              :     // if the vehicle has arrived, the reminder must be kept so it can be
      89              :     // notified of the arrival subsequently
      90    482196356 :     const double oldSpeed = veh.getPreviousSpeed();
      91    482196356 :     double enterSpeed = MSGlobals::gSemiImplicitEulerUpdate ? newSpeed : oldSpeed; // NOTE: For the euler update, the vehicle is assumed to travel at constant speed for the whole time step
      92              :     double leaveSpeed = newSpeed, leaveSpeedFront = newSpeed;
      93              : 
      94              :     // These values will be further decreased below
      95    482196356 :     double timeOnLane = TS;
      96    482196356 :     double frontOnLane = oldPos > myLaneLength ? 0. : TS;
      97              :     bool ret = true;
      98              : 
      99              :     // entry and exit times (will be modified below)
     100              :     double timeBeforeEnter = 0.;
     101              :     double timeBeforeEnterBack = 0.;
     102    482196356 :     double timeBeforeLeaveFront = newPos <= myLaneLength ? TS : 0.;
     103              :     double timeBeforeLeave = TS;
     104              : 
     105              :     // Treat the case that the vehicle entered the lane in the last step
     106    482196356 :     if (oldPos < 0 && newPos >= 0) {
     107              :         // Vehicle was not on this lane in the last time step
     108     11236838 :         timeBeforeEnter = MSCFModel::passingTime(oldPos, 0, newPos, oldSpeed, newSpeed);
     109     11236838 :         timeOnLane = TS - timeBeforeEnter;
     110              :         frontOnLane = timeOnLane;
     111     11236838 :         enterSpeed = MSCFModel::speedAfterTime(timeBeforeEnter, oldSpeed, newPos - oldPos);
     112              :     }
     113              : 
     114    482196356 :     const double oldBackPos = oldPos - veh.getVehicleType().getLength();
     115    482196356 :     const double newBackPos = newPos - veh.getVehicleType().getLength();
     116              : 
     117              :     // Determine the time before the vehicle back enters
     118    482196356 :     if (oldBackPos < 0. && newBackPos > 0.) {
     119     11517687 :         timeBeforeEnterBack = MSCFModel::passingTime(oldBackPos, 0., newBackPos, oldSpeed, newSpeed);
     120    470678669 :     } else if (newBackPos <= 0) {
     121      7949967 :         timeBeforeEnterBack = TS;
     122              :     } else {
     123              :         timeBeforeEnterBack = 0.;
     124              :     }
     125              : 
     126              :     // Treat the case that the vehicle's back left the lane in the last step
     127    482196356 :     if (newBackPos > myLaneLength // vehicle's back has left the lane
     128     12964893 :             && oldBackPos <= myLaneLength) { // and hasn't left the lane before
     129              :         assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the lane boundary otherwise
     130              :         // (Leo) vehicle left this lane (it can also have skipped over it in one time step -> therefore we use "timeOnLane -= ..." and ( ... - timeOnLane) below)
     131     12964683 :         timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myLaneLength, newBackPos, oldSpeed, newSpeed);
     132     12964683 :         const double timeAfterLeave = TS - timeBeforeLeave;
     133     12964683 :         timeOnLane -= timeAfterLeave;
     134     12964683 :         leaveSpeed = MSCFModel::speedAfterTime(timeBeforeLeave, oldSpeed, newPos - oldPos);
     135              :         // XXX: Do we really need this? Why would this "reduce rounding errors"? (Leo) Refs. #2579
     136     12964683 :         if (fabs(timeOnLane) < NUMERICAL_EPS) { // reduce rounding errors
     137              :             timeOnLane = 0.;
     138              :         }
     139     12964683 :         ret = veh.hasArrived();
     140              :     }
     141              : 
     142              :     // Treat the case that the vehicle's front left the lane in the last step
     143    482196356 :     if (newPos > myLaneLength && oldPos <= myLaneLength) {
     144              :         // vehicle's front has left the lane and has not left before
     145              :         assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0);
     146     14170641 :         timeBeforeLeaveFront = MSCFModel::passingTime(oldPos, myLaneLength, newPos, oldSpeed, newSpeed);
     147     14170641 :         const double timeAfterLeave = TS - timeBeforeLeaveFront;
     148     14170641 :         frontOnLane -= timeAfterLeave;
     149              :         // XXX: Do we really need this? Why would this "reduce rounding errors"? (Leo) Refs. #2579
     150     14170641 :         if (fabs(frontOnLane) < NUMERICAL_EPS) { // reduce rounding errors
     151              :             frontOnLane = 0.;
     152              :         }
     153     14170641 :         leaveSpeedFront = MSCFModel::speedAfterTime(timeBeforeLeaveFront, oldSpeed, newPos - oldPos);
     154              :     }
     155              : 
     156              :     assert(frontOnLane <= TS);
     157              :     assert(timeOnLane <= TS);
     158              : 
     159    482196356 :     if (timeOnLane < 0) {
     160            0 :         WRITE_ERRORF(TL("Negative vehicle step fraction for '%' on lane '%'."), veh.getID(), getLane()->getID());
     161            0 :         return veh.hasArrived();
     162              :     }
     163    482196356 :     if (timeOnLane == 0) {
     164        21963 :         return veh.hasArrived();
     165              :     }
     166              : 
     167              : #ifdef DEBUG_NOTIFY_MOVE
     168              :     std::stringstream ss;
     169              :     ss << "\n"
     170              :        << "lane length: " << myLaneLength
     171              :        << "\noldPos: " << oldPos
     172              :        << "\nnewPos: " << newPos
     173              :        << "\noldPosBack: " << oldBackPos
     174              :        << "\nnewPosBack: " << newBackPos
     175              :        << "\ntimeBeforeEnter: " << timeBeforeEnter
     176              :        << "\ntimeBeforeEnterBack: " << timeBeforeEnterBack
     177              :        << "\ntimeBeforeLeaveFront: " << timeBeforeLeaveFront
     178              :        << "\ntimeBeforeLeave: " << timeBeforeLeave;
     179              :     if (!(timeBeforeLeave >= MAX2(timeBeforeEnterBack, timeBeforeLeaveFront))
     180              :             || !(timeBeforeEnter <= MIN2(timeBeforeEnterBack, timeBeforeLeaveFront))) {
     181              :         WRITE_ERROR(ss.str());
     182              :     } else {
     183              :         std::cout << ss.str() << std::endl;
     184              :     }
     185              : 
     186              : #endif
     187              : 
     188              :     assert(timeBeforeEnter <= MIN2(timeBeforeEnterBack, timeBeforeLeaveFront));
     189              :     assert(timeBeforeLeave >= MAX2(timeBeforeEnterBack, timeBeforeLeaveFront));
     190              :     // compute average vehicle length on lane in last step
     191    482174393 :     double vehLength = veh.getVehicleType().getLength();
     192              :     // occupied lane length at timeBeforeEnter (resp. stepStart if already on lane)
     193    482174393 :     double lengthOnLaneAtStepStart = MAX2(0., MIN4(myLaneLength, vehLength, vehLength - (oldPos - myLaneLength), oldPos));
     194              :     // occupied lane length at timeBeforeLeave (resp. stepEnd if still on lane)
     195    482174393 :     double lengthOnLaneAtStepEnd = MAX2(0., MIN4(myLaneLength, vehLength, vehLength - (newPos - myLaneLength), newPos));
     196              :     double integratedLengthOnLane = 0.;
     197    482174393 :     if (timeBeforeEnterBack < timeBeforeLeaveFront) {
     198              :         // => timeBeforeLeaveFront>0, myLaneLength>vehLength
     199              :         // vehicle length on detector at timeBeforeEnterBack
     200    466271371 :         double lengthOnLaneAtBackEnter = MIN2(veh.getVehicleType().getLength(), newPos);
     201              :         // linear quadrature of occupancy between timeBeforeEnter and timeBeforeEnterBack
     202    466271371 :         integratedLengthOnLane += (timeBeforeEnterBack - timeBeforeEnter) * (lengthOnLaneAtBackEnter + lengthOnLaneAtStepStart) * 0.5;
     203              :         // linear quadrature of occupancy between timeBeforeEnterBack and timeBeforeLeaveFront
     204              :         // (vehicle is completely on the edge in between)
     205    466271371 :         integratedLengthOnLane += (timeBeforeLeaveFront - timeBeforeEnterBack) * vehLength;
     206              :         // and until vehicle leaves/stepEnd
     207    466271371 :         integratedLengthOnLane += (timeBeforeLeave - timeBeforeLeaveFront) * (vehLength + lengthOnLaneAtStepEnd) * 0.5;
     208     15903022 :     } else if (timeBeforeEnterBack >= timeBeforeLeaveFront) {
     209              :         // => myLaneLength <= vehLength or (timeBeforeLeaveFront == timeBeforeEnterBack == 0)
     210              :         // vehicle length on detector at timeBeforeLeaveFront
     211              :         double lengthOnLaneAtLeaveFront;
     212     15903022 :         if (timeBeforeLeaveFront == timeBeforeEnter) {
     213              :             // for the case that front already left
     214              :             lengthOnLaneAtLeaveFront = lengthOnLaneAtStepStart;
     215      7974432 :         } else if (timeBeforeLeaveFront == timeBeforeLeave) {
     216              :             // for the case that front doesn't leave in this step
     217              :             lengthOnLaneAtLeaveFront = lengthOnLaneAtStepEnd;
     218              :         } else {
     219              :             lengthOnLaneAtLeaveFront = myLaneLength;
     220              :         }
     221              : #ifdef DEBUG_NOTIFY_MOVE
     222              :         std::cout << "lengthOnLaneAtLeaveFront=" << lengthOnLaneAtLeaveFront << std::endl;
     223              : #endif
     224              :         // linear quadrature of occupancy between timeBeforeEnter and timeBeforeLeaveFront
     225     15903022 :         integratedLengthOnLane += (timeBeforeLeaveFront - timeBeforeEnter) * (lengthOnLaneAtLeaveFront + lengthOnLaneAtStepStart) * 0.5;
     226              :         // linear quadrature of occupancy between timeBeforeLeaveFront and timeBeforeEnterBack
     227     15903022 :         integratedLengthOnLane += (timeBeforeEnterBack - timeBeforeLeaveFront) * lengthOnLaneAtLeaveFront;
     228              :         // and until vehicle leaves/stepEnd
     229     15903022 :         integratedLengthOnLane += (timeBeforeLeave - timeBeforeEnterBack) * (lengthOnLaneAtLeaveFront + lengthOnLaneAtStepEnd) * 0.5;
     230              :     }
     231              : 
     232    482174393 :     double meanLengthOnLane = integratedLengthOnLane / TS;
     233              : #ifdef DEBUG_NOTIFY_MOVE
     234              :     std::cout << "Calculated mean length on lane '" << myLane->getID() << "' in last step as " << meanLengthOnLane
     235              :               << "\nlengthOnLaneAtStepStart=" << lengthOnLaneAtStepStart << ", lengthOnLaneAtStepEnd=" << lengthOnLaneAtStepEnd << ", integratedLengthOnLane=" << integratedLengthOnLane
     236              :               << std::endl;
     237              : #endif
     238              : 
     239              : //    // XXX: use this, when #2556 is fixed! Refs. #2575
     240              : //    const double travelledDistanceFrontOnLane = MAX2(0., MIN2(newPos, myLaneLength) - MAX2(oldPos, 0.));
     241              : //    const double travelledDistanceVehicleOnLane = MIN2(newPos, myLaneLength) - MAX2(oldPos, 0.) + MIN2(MAX2(0., newPos - myLaneLength), veh.getVehicleType().getLength());
     242              : //    // XXX: #2556 fixed for ballistic update
     243    482174393 :     const double travelledDistanceFrontOnLane = MSGlobals::gSemiImplicitEulerUpdate ? frontOnLane * newSpeed
     244    162629688 :             : MAX2(0., MIN2(newPos, myLaneLength) - MAX2(oldPos, 0.));
     245    563489237 :     const double travelledDistanceVehicleOnLane = MSGlobals::gSemiImplicitEulerUpdate ? timeOnLane * newSpeed
     246    162629688 :             : MIN2(newPos, myLaneLength) - MAX2(oldPos, 0.) + MIN2(MAX2(0., newPos - myLaneLength), veh.getVehicleType().getLength());
     247              : //    // XXX: no fix
     248              : //    const double travelledDistanceFrontOnLane = frontOnLane*newSpeed;
     249              : //    const double travelledDistanceVehicleOnLane = timeOnLane*newSpeed;
     250              : 
     251              : #ifdef HAVE_FOX
     252    482174393 :     ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
     253              : #endif
     254    482174393 :     notifyMoveInternal(veh, frontOnLane, timeOnLane, (enterSpeed + leaveSpeedFront) / 2., (enterSpeed + leaveSpeed) / 2., travelledDistanceFrontOnLane, travelledDistanceVehicleOnLane, meanLengthOnLane);
     255              :     return ret;
     256              : }
     257              : 
     258              : 
     259              : bool
     260      1183104 : MSMeanData::MeanDataValues::notifyLeave(SUMOTrafficObject& /*veh*/, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     261      1183104 :     if (MSGlobals::gUseMesoSim) {
     262              :         return false; // reminder is re-added on every segment (@recheck for performance)
     263              :     }
     264      1028810 :     return reason == MSMoveReminder::NOTIFICATION_JUNCTION;
     265              : }
     266              : 
     267              : 
     268              : bool
     269      2951641 : MSMeanData::MeanDataValues::isEmpty() const {
     270      2951641 :     return sampleSeconds == 0;
     271              : }
     272              : 
     273              : 
     274              : void
     275            0 : MSMeanData::MeanDataValues::update() {
     276            0 : }
     277              : 
     278              : 
     279              : double
     280      1033803 : MSMeanData::MeanDataValues::getSamples() const {
     281      1033803 :     return sampleSeconds;
     282              : }
     283              : 
     284              : 
     285              : // ---------------------------------------------------------------------------
     286              : // MSMeanData::MeanDataValueTracker - methods
     287              : // ---------------------------------------------------------------------------
     288         2744 : MSMeanData::MeanDataValueTracker::MeanDataValueTracker(MSLane* const lane,
     289              :         const double length,
     290         2744 :         const MSMeanData* const parent)
     291         2744 :     : MSMeanData::MeanDataValues(lane, length, true, parent) {
     292         2744 :     myCurrentData.push_back(std::make_shared<TrackerEntry>(parent->createValuesSubData(lane, length, false)));
     293         2744 : }
     294              : 
     295              : 
     296         8232 : MSMeanData::MeanDataValueTracker::~MeanDataValueTracker() {}
     297              : 
     298              : 
     299              : void
     300       164304 : MSMeanData::MeanDataValueTracker::reset(bool afterWrite) {
     301       164304 :     if (afterWrite) {
     302        70360 :         if (!myCurrentData.empty()) {
     303        70360 :             myCurrentData.pop_front();
     304              :         }
     305              :     } else {
     306       187888 :         myCurrentData.push_back(std::make_shared<TrackerEntry>(myParent->createValuesSubData(myLane, myLaneLength, false)));
     307              :     }
     308       164304 : }
     309              : 
     310              : 
     311              : void
     312            0 : MSMeanData::MeanDataValueTracker::addTo(MSMeanData::MeanDataValues& val) const {
     313            0 :     myCurrentData.front()->myValues->addTo(val);
     314            0 : }
     315              : 
     316              : 
     317              : void
     318        15012 : MSMeanData::MeanDataValueTracker::notifyMoveInternal(const SUMOTrafficObject& veh, const double frontOnLane, const double timeOnLane, const double meanSpeedFrontOnLane, const double meanSpeedVehicleOnLane, const double travelledDistanceFrontOnLane, const double travelledDistanceVehicleOnLane, const double meanLengthOnLane) {
     319        15012 :     myTrackedData[&veh]->myValues->notifyMoveInternal(veh, frontOnLane, timeOnLane, meanSpeedFrontOnLane, meanSpeedVehicleOnLane, travelledDistanceFrontOnLane, travelledDistanceVehicleOnLane, meanLengthOnLane);
     320        15012 : }
     321              : 
     322              : 
     323              : bool
     324          787 : MSMeanData::MeanDataValueTracker::notifyLeave(SUMOTrafficObject& veh, double lastPos, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
     325          787 :     if (myParent == nullptr || reason != MSMoveReminder::NOTIFICATION_SEGMENT) {
     326          387 :         myTrackedData[&veh]->myNumVehicleLeft++;
     327              :     }
     328          787 :     return myTrackedData[&veh]->myValues->notifyLeave(veh, lastPos, reason);
     329              : }
     330              : 
     331              : 
     332              : bool
     333         3402 : MSMeanData::MeanDataValueTracker::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     334              : #ifdef DEBUG_NOTIFY_ENTER
     335              :     std::cout << "\n" << SIMTIME << " MSMeanData::MeanDataValueTracker: veh '" << veh.getID() << "' enters lane '" << enteredLane->getID() << "'" << std::endl;
     336              : #else
     337              :     UNUSED_PARAMETER(enteredLane);
     338              : #endif
     339         3402 :     if (reason == MSMoveReminder::NOTIFICATION_SEGMENT) {
     340              :         return true;
     341              :     }
     342         5772 :     if (myParent->vehicleApplies(veh) && myTrackedData.find(&veh) == myTrackedData.end()) {
     343          507 :         myTrackedData[&veh] = myCurrentData.back();
     344          507 :         myTrackedData[&veh]->myNumVehicleEntered++;
     345          507 :         if (!myTrackedData[&veh]->myValues->notifyEnter(veh, reason)) {
     346            0 :             myTrackedData[&veh]->myNumVehicleLeft++;
     347            0 :             myTrackedData.erase(&veh);
     348            0 :             return false;
     349              :         }
     350              :         return true;
     351              :     }
     352              :     return false;
     353              : }
     354              : 
     355              : 
     356              : bool
     357        91696 : MSMeanData::MeanDataValueTracker::isEmpty() const {
     358        91696 :     return myCurrentData.front()->myValues->isEmpty();
     359              : }
     360              : 
     361              : 
     362              : void
     363          368 : MSMeanData::MeanDataValueTracker::write(OutputDevice& dev,
     364              :                                         const SumoXMLAttrMask& attributeMask,
     365              :                                         const SUMOTime period,
     366              :                                         const int numLanes,
     367              :                                         const double speedLimit,
     368              :                                         const double defaultTravelTime,
     369              :                                         const int /*numVehicles*/) const {
     370          368 :     myCurrentData.front()->myValues->write(dev, attributeMask, period, numLanes, speedLimit,
     371              :                                            defaultTravelTime,
     372              :                                            myCurrentData.front()->myNumVehicleEntered);
     373          368 : }
     374              : 
     375              : 
     376              : int
     377        63116 : MSMeanData::MeanDataValueTracker::getNumReady() const {
     378              :     int result = 0;
     379      1445056 :     for (const auto& it : myCurrentData) {
     380      1384592 :         if (it->myNumVehicleEntered == it->myNumVehicleLeft) {
     381      1381940 :             result++;
     382              :         } else {
     383              :             break;
     384              :         }
     385              :     }
     386        63116 :     return result;
     387              : }
     388              : 
     389              : 
     390              : double
     391          368 : MSMeanData::MeanDataValueTracker::getSamples() const {
     392          368 :     return myCurrentData.front()->myValues->getSamples();
     393              : }
     394              : 
     395              : 
     396              : // ---------------------------------------------------------------------------
     397              : // MSMeanData - methods
     398              : // ---------------------------------------------------------------------------
     399        24276 : MSMeanData::MSMeanData(const std::string& id,
     400              :                        const SUMOTime dumpBegin, const SUMOTime dumpEnd,
     401              :                        const bool useLanes, const std::string& excludeEmpty, const bool withInternal,
     402              :                        const bool trackVehicles,
     403              :                        const int detectPersons,
     404              :                        const double maxTravelTime,
     405              :                        const double minSamples,
     406              :                        const std::string& vTypes,
     407              :                        const std::string& writeAttributes,
     408              :                        const std::vector<MSEdge*>& edges,
     409        24276 :                        AggregateType aggregate) :
     410              :     MSDetectorFileOutput(id, vTypes, "", detectPersons),
     411        24276 :     myMinSamples(minSamples),
     412        24276 :     myMaxTravelTime(maxTravelTime),
     413        24276 :     myAmEdgeBased(!useLanes),
     414        24276 :     myDumpBegin(dumpBegin),
     415        24276 :     myDumpEnd(dumpEnd),
     416        24276 :     myInitTime(SUMOTime_MAX),
     417        24276 :     myEdges(edges),
     418          166 :     myDumpInternal(withInternal && MSGlobals::gUsingInternalLanes),
     419        24276 :     myTrackVehicles(trackVehicles),
     420        97104 :     myWrittenAttributes(OutputDevice::parseWrittenAttributes(StringTokenizer(writeAttributes).getVector(), "meandata '" + id + "'")),
     421        72828 :     myAggregate(aggregate) {
     422              :     try {
     423        24276 :         myDumpEmpty = !StringUtils::toBool(excludeEmpty);
     424           84 :     } catch (const BoolFormatException&) {
     425           84 :         if (excludeEmpty == "default" || excludeEmpty == "defaults") {
     426           78 :             myPrintDefaults = true;
     427            6 :         } else if (excludeEmpty == "modified") {
     428            6 :             myDumpEmpty = false;
     429            6 :             myPrintDefaults = true;
     430            6 :             myPrintModified = true;
     431              :         } else {
     432            0 :             throw;
     433              :         }
     434           84 :     }
     435        24276 : }
     436              : 
     437              : 
     438              : void
     439        23351 : MSMeanData::init() {
     440        23351 :     myInitTime = MSNet::getInstance()->getCurrentTimeStep();
     441        23351 :     if (myEdges.empty()) {
     442              :         // use all edges by default
     443       819534 :         for (MSEdge* const edge : MSNet::getInstance()->getEdgeControl().getEdges()) {
     444       796253 :             if ((myDumpInternal || !edge->isInternal()) &&
     445       529751 :                     ((detectsPersons() && myDumpInternal) || (!edge->isCrossing() && !edge->isWalkingArea()))) {
     446       351652 :                 myEdges.push_back(edge);
     447              :             }
     448              :         }
     449              :     }
     450              :     int index = 0;
     451       375117 :     for (MSEdge* edge : myEdges) {
     452       351766 :         myMeasures.push_back(std::vector<MeanDataValues*>());
     453       351766 :         myEdgeIndex[edge] = index++;
     454       351766 :         const std::vector<MSLane*>& lanes = edge->getLanes();
     455       351766 :         if (MSGlobals::gUseMesoSim) {
     456              :             MeanDataValues* data;
     457        30538 :             if (!myAmEdgeBased) {
     458           85 :                 for (MSLane* const lane : lanes) {
     459           52 :                     data = createValues(lane, lanes[0]->getLength(), false);
     460           52 :                     myMeasures.back().push_back(data);
     461           52 :                     MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*edge);
     462          310 :                     while (s != nullptr) {
     463          258 :                         s->addDetector(data, lane->getIndex());
     464          258 :                         s->prepareDetectorForWriting(*data, lane->getIndex());
     465              :                         s = s->getNextSegment();
     466              :                     }
     467           52 :                     data->reset();
     468           52 :                     data->reset(true);
     469              :                 }
     470              :             } else {
     471        30505 :                 if (myTrackVehicles) {
     472          880 :                     data = new MeanDataValueTracker(nullptr, lanes[0]->getLength(), this);
     473              :                 } else {
     474        29625 :                     data = createValues(nullptr, lanes[0]->getLength(), false);
     475              :                 }
     476        61010 :                 data->setDescription("meandata_" + getID() + "|" + edge->getID());
     477        30505 :                 myMeasures.back().push_back(data);
     478        30505 :                 MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*edge);
     479       153162 :                 while (s != nullptr) {
     480       122657 :                     s->addDetector(data);
     481       122657 :                     s->prepareDetectorForWriting(*data);
     482              :                     s = s->getNextSegment();
     483              :                 }
     484        30505 :                 data->reset();
     485        30505 :                 data->reset(true);
     486              :             }
     487              :             continue;
     488        30538 :         }
     489       321228 :         if (myAmEdgeBased && myTrackVehicles) {
     490          936 :             myMeasures.back().push_back(new MeanDataValueTracker(nullptr, lanes[0]->getLength(), this));
     491              :         }
     492       849019 :         for (MSLane* const lane : lanes) {
     493       527791 :             if (myTrackVehicles) {
     494         2016 :                 if (myAmEdgeBased) {
     495         1088 :                     lane->addMoveReminder(myMeasures.back().back());
     496              :                 } else {
     497          928 :                     myMeasures.back().push_back(new MeanDataValueTracker(lane, lane->getLength(), this));
     498              :                 }
     499              :             } else {
     500       525775 :                 myMeasures.back().push_back(createValues(lane, lane->getLength(), true));
     501              :             }
     502              :         }
     503              :     }
     504        23351 :     if (myAggregate == AggregateType::TAZ) {
     505          532 :         for (const MSEdge* e : MSEdge::getAllEdges()) {
     506          524 :             if (e->isTazConnector()) {
     507          188 :                 myTAZ.push_back(e);
     508              :             }
     509              :         }
     510              :     }
     511        23351 :     if (mySubData != nullptr) {
     512            6 :         mySubData->init();
     513            6 :         std::vector<std::vector<MeanDataValues*> >::const_iterator subMeasureList = mySubData->myMeasures.begin();
     514           48 :         for (const std::vector<MeanDataValues*>& valueList : myMeasures) {
     515              :             std::vector<MeanDataValues*>::const_iterator subMeasures = subMeasureList->begin();
     516           84 :             for (MeanDataValues* values : valueList) {
     517           42 :                 values->setSubData(*subMeasures);
     518              :                 subMeasures++;
     519              :             }
     520              :             subMeasureList++;
     521              :         }
     522              :     }
     523        23351 : }
     524              : 
     525              : 
     526        24227 : MSMeanData::~MSMeanData() {
     527       375456 :     for (const std::vector<MeanDataValues*>& valueList : myMeasures) {
     528       908416 :         for (MeanDataValues* const values : valueList) {
     529       557187 :             delete values;
     530              :         }
     531              :     }
     532        24227 :     delete mySubData;
     533        24227 : }
     534              : 
     535              : 
     536              : void
     537        12645 : MSMeanData::resetOnly(SUMOTime stopTime) {
     538              :     UNUSED_PARAMETER(stopTime);
     539        12645 :     if (MSGlobals::gUseMesoSim) {
     540              :         MSEdgeVector::iterator edge = myEdges.begin();
     541       117300 :         for (std::vector<std::vector<MeanDataValues*> >::const_iterator i = myMeasures.begin(); i != myMeasures.end(); ++i, ++edge) {
     542       113716 :             MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(**edge);
     543       227432 :             for (MeanDataValues* data : *i) {
     544       602292 :                 while (s != nullptr) {
     545       488576 :                     s->prepareDetectorForWriting(*data);
     546              :                     s = s->getNextSegment();
     547              :                 }
     548       113716 :                 data->reset();
     549              :             }
     550              :         }
     551              :         return;
     552              :     }
     553       257304 :     for (std::vector<std::vector<MeanDataValues*> >::const_iterator i = myMeasures.begin(); i != myMeasures.end(); ++i) {
     554       529990 :         for (std::vector<MeanDataValues*>::const_iterator j = (*i).begin(); j != (*i).end(); ++j) {
     555       281747 :             (*j)->reset();
     556              :         }
     557              :     }
     558              : }
     559              : 
     560              : 
     561              : std::string
     562       586108 : MSMeanData::getEdgeID(const MSEdge* const edge) {
     563       586108 :     return edge->getID();
     564              : }
     565              : 
     566              : 
     567              : void
     568          938 : MSMeanData::writeAggregated(OutputDevice& dev, SUMOTime startTime, SUMOTime stopTime) {
     569          938 :     if (myTrackVehicles) {
     570            0 :         throw ProcessError(TL("aggregated meanData output not yet implemented for trackVehicles"));
     571              :     }
     572              : 
     573              :     double edgeLengthSum = 0;
     574              :     int laneNumber = 0;
     575              :     double speedSum = 0;
     576              :     double totalTT = 0;
     577        42146 :     for (MSEdge* edge : myEdges) {
     578        41208 :         edgeLengthSum += edge->getLength();
     579        41208 :         laneNumber += edge->getNumDrivingLanes();
     580        41208 :         speedSum += edge->getSpeedLimit();
     581        41208 :         totalTT += edge->getLength() / edge->getSpeedLimit();
     582              :     }
     583          938 :     MeanDataValues* sumData = createValuesSubData(nullptr, edgeLengthSum, false);
     584        42146 :     for (const std::vector<MeanDataValues*>& edgeValues : myMeasures) {
     585        82440 :         for (MeanDataValues* meanData : edgeValues) {
     586        41232 :             meanData->addTo(*sumData);
     587        41232 :             if (!MSNet::getInstance()->skipFinalReset()) {
     588        41232 :                 meanData->reset();
     589              :             }
     590              :         }
     591              :     }
     592          938 :     if (MSGlobals::gUseMesoSim) {
     593        14040 :         for (int i = 0; i < (int)myEdges.size(); i++) {
     594        13728 :             MSEdge* edge = myEdges[i];
     595              :             std::vector<MeanDataValues*>& edgeValues = myMeasures[i];
     596        13728 :             MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*edge);
     597        68640 :             while (s != nullptr) {
     598       109824 :                 for (MeanDataValues* meanData : edgeValues) {
     599        54912 :                     s->prepareDetectorForWriting(*meanData);
     600        54912 :                     meanData->addTo(*sumData);
     601        54912 :                     if (!MSNet::getInstance()->skipFinalReset()) {
     602        54912 :                         meanData->reset();
     603              :                     }
     604              :                 }
     605              :                 s = s->getNextSegment();
     606              :             }
     607              :         }
     608              :     }
     609              : 
     610          938 :     if (myDumpEmpty || !sumData->isEmpty()) {
     611         1864 :         writePrefix(dev, *sumData, SUMO_TAG_EDGE, "AGGREGATED");
     612          932 :         dev.writeAttr(SUMO_ATTR_NUMEDGES, myEdges.size());
     613         1864 :         for (MeanDataValues* data = sumData; data != nullptr; data = data->getSubData()) {
     614          932 :             data->write(dev, myWrittenAttributes, stopTime - startTime, laneNumber, speedSum / (double)myEdges.size(),
     615          932 :                         myPrintDefaults ? totalTT : -1.);
     616              :         }
     617         1864 :         dev.closeTag();
     618              :     }
     619          938 :     delete sumData;
     620          938 : }
     621              : 
     622              : 
     623              : void
     624           20 : MSMeanData::writeAggregatedTAZ(OutputDevice& dev, SUMOTime startTime, SUMOTime stopTime) {
     625           20 :     if (myTrackVehicles) {
     626            0 :         throw ProcessError(TL("aggregated meanData output not yet implemented for trackVehicles"));
     627              :     }
     628              : 
     629          568 :     for (const MSEdge* taz : myTAZ) {
     630              :         double edgeLengthSum = 0;
     631              :         int laneNumber = 0;
     632              :         double speedSum = 0;
     633              :         double totalTT = 0;
     634              :         std::set<const MSEdge*> connected;
     635         1348 :         for (const MSEdge* edge : taz->getSuccessors()) {
     636              :             connected.insert(edge);
     637              :         }
     638         1348 :         for (const MSEdge* edge : taz->getPredecessors()) {
     639              :             connected.insert(edge);
     640              :         }
     641         2148 :         for (const MSEdge* edge : connected) {
     642         1600 :             edgeLengthSum += edge->getLength();
     643         1600 :             laneNumber += edge->getNumDrivingLanes();
     644         1600 :             speedSum += edge->getSpeedLimit();
     645         1600 :             totalTT += edge->getLength() / edge->getSpeedLimit();
     646              :         }
     647          548 :         MeanDataValues* sumData = createValuesSubData(nullptr, edgeLengthSum, false);
     648        24404 :         for (int i = 0; i < (int)myEdges.size(); i++) {
     649        23856 :             MSEdge* edge = myEdges[i];
     650              :             if (connected.count(edge) != 0) {
     651              :                 std::vector<MeanDataValues*>& edgeValues = myMeasures[i];
     652         1600 :                 if (MSGlobals::gUseMesoSim) {
     653          528 :                     MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*edge);
     654         2640 :                     while (s != nullptr) {
     655         4224 :                         for (MeanDataValues* meanData : edgeValues) {
     656         2112 :                             s->prepareDetectorForWriting(*meanData);
     657         2112 :                             meanData->addTo(*sumData);
     658              :                         }
     659              :                         s = s->getNextSegment();
     660              :                     }
     661              :                 } else {
     662         2160 :                     for (MeanDataValues* meanData : edgeValues) {
     663         1088 :                         meanData->addTo(*sumData);
     664              :                     }
     665              :                 }
     666              :             }
     667              :         }
     668          548 :         if (myDumpEmpty || !sumData->isEmpty()) {
     669          240 :             writePrefix(dev, *sumData, SUMO_TAG_EDGE, taz->getID());
     670           80 :             dev.writeAttr(SUMO_ATTR_NUMEDGES, connected.size());
     671          160 :             for (MeanDataValues* data = sumData; data != nullptr; data = data->getSubData()) {
     672           80 :                 data->write(dev, myWrittenAttributes, stopTime - startTime, laneNumber, speedSum / (double)connected.size(),
     673           80 :                             myPrintDefaults ? totalTT : -1.);
     674              :             }
     675          160 :             dev.closeTag();
     676              :         }
     677          548 :         delete sumData;
     678              :     }
     679              : 
     680           20 :     if (!MSNet::getInstance()->skipFinalReset()) {
     681          836 :         for (const std::vector<MeanDataValues*>& edgeValues : myMeasures) {
     682         1656 :             for (MeanDataValues* meanData : edgeValues) {
     683          840 :                 meanData->reset();
     684              :             }
     685              :         }
     686              :     }
     687           20 : }
     688              : 
     689              : 
     690              : void
     691     17900563 : MSMeanData::writeEdge(OutputDevice& dev,
     692              :                       const std::vector<MeanDataValues*>& edgeValues,
     693              :                       const MSEdge* const edge, SUMOTime startTime, SUMOTime stopTime) {
     694     17900563 :     if (MSGlobals::gUseMesoSim) {
     695              :         int idx = 0;
     696      2732225 :         for (MeanDataValues* const data : edgeValues) {
     697      1366136 :             MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*edge);
     698      7013948 :             while (s != nullptr) {
     699      5648154 :                 s->prepareDetectorForWriting(*data, myAmEdgeBased ? -1 : idx);
     700              :                 s = s->getNextSegment();
     701              :             }
     702      1366136 :             idx++;
     703              :         }
     704      1366089 :         if (myAmEdgeBased) {
     705      1366042 :             MeanDataValues* const data = edgeValues.front();
     706      1366042 :             if (myDumpEmpty || (myPrintModified && edge->getLanes()[0]->isSpeedModified()) || !data->isEmpty()) {
     707        63680 :                 writePrefix(dev, *data, SUMO_TAG_EDGE, getEdgeID(edge));
     708       127384 :                 for (MeanDataValues* d = data; d != nullptr; d = d->getSubData()) {
     709        63704 :                     d->write(dev, myWrittenAttributes, stopTime - startTime,
     710              :                              edge->getNumDrivingLanes(),
     711              :                              edge->getSpeedLimit(),
     712        63704 :                              myPrintDefaults ? edge->getLength() / edge->getSpeedLimit() : -1.);
     713              :                 }
     714       127360 :                 dev.closeTag();
     715              :             }
     716      1366042 :             if (!MSNet::getInstance()->skipFinalReset()) {
     717      1366042 :                 data->reset(true);
     718              :             }
     719      1366042 :             return;
     720              :         }
     721              :     }
     722     16534521 :     if (!myAmEdgeBased) {
     723      8025399 :         bool writeCheck = myDumpEmpty;
     724      8025399 :         if (!writeCheck) {
     725     15611485 :             for (const MeanDataValues* const laneData : edgeValues) {
     726      7913040 :                 if (!laneData->isEmpty() || (myPrintModified && laneData->getLane()->isSpeedModified())) {
     727              :                     writeCheck = true;
     728              :                     break;
     729              :                 }
     730              :             }
     731              :         }
     732      7901692 :         if (writeCheck) {
     733       326954 :             dev.openTag(SUMO_TAG_EDGE).writeAttr(SUMO_ATTR_ID, edge->getID());
     734              :         }
     735     16170619 :         for (MeanDataValues* const laneData : edgeValues) {
     736              :             const MSLane* const lane = laneData->getLane();
     737      8145220 :             if (myDumpEmpty || (myPrintModified && lane->isSpeedModified()) || !laneData->isEmpty()) {
     738       870722 :                 writePrefix(dev, *laneData, SUMO_TAG_LANE, lane->getID());
     739       870722 :                 for (MeanDataValues* data = laneData; data != nullptr; data = data->getSubData()) {
     740       435361 :                     data->write(dev, myWrittenAttributes, stopTime - startTime, 1, lane->getSpeedLimit(),
     741       435361 :                                 myPrintDefaults ? lane->getLength() / lane->getSpeedLimit() : -1.);
     742              :                 }
     743       870722 :                 dev.closeTag();
     744              :             }
     745      8145220 :             if (!MSNet::getInstance()->skipFinalReset()) {
     746      8145220 :                 laneData->reset(true);
     747              :             }
     748              :         }
     749      8025399 :         if (writeCheck) {
     750       653908 :             dev.closeTag();
     751              :         }
     752              :     } else {
     753      8509122 :         if (myTrackVehicles) {
     754        22440 :             MeanDataValues* meanData = *edgeValues.begin();
     755        22440 :             if (myDumpEmpty || !meanData->isEmpty()) {
     756          160 :                 writePrefix(dev, *meanData, SUMO_TAG_EDGE, edge->getID());
     757          320 :                 for (MeanDataValues* data = meanData; data != nullptr; data = data->getSubData()) {
     758          160 :                     data->write(dev, myWrittenAttributes, stopTime - startTime, edge->getNumDrivingLanes(), edge->getSpeedLimit(),
     759          160 :                                 myPrintDefaults ? edge->getLength() / edge->getSpeedLimit() : -1.);
     760              :                 }
     761          320 :                 dev.closeTag();
     762              :             }
     763        22440 :             if (!MSNet::getInstance()->skipFinalReset()) {
     764        22440 :                 meanData->reset(true);
     765              :             }
     766              :         } else {
     767      8486682 :             MeanDataValues* sumData = createValuesSubData(nullptr, edge->getLength(), false);
     768      8486682 :             bool writeCheck = myDumpEmpty;
     769     17142570 :             for (MeanDataValues* const laneData : edgeValues) {
     770      8655888 :                 laneData->addTo(*sumData);
     771      8655888 :                 if (myPrintModified && laneData->getLane()->isSpeedModified()) {
     772              :                     writeCheck = true;
     773              :                 }
     774      8655888 :                 if (!MSNet::getInstance()->skipFinalReset()) {
     775      8655888 :                     laneData->reset();
     776              :                 }
     777              :             }
     778      8486682 :             if (writeCheck || !sumData->isEmpty()) {
     779       525160 :                 writePrefix(dev, *sumData, SUMO_TAG_EDGE, getEdgeID(edge));
     780      1050372 :                 for (MeanDataValues* data = sumData; data != nullptr; data = data->getSubData()) {
     781       525212 :                     data->write(dev, myWrittenAttributes, stopTime - startTime, edge->getNumDrivingLanes(), edge->getSpeedLimit(),
     782       525212 :                                 myPrintDefaults ? edge->getLength() / edge->getSpeedLimit() : -1.);
     783              :                 }
     784      1050319 :                 dev.closeTag();
     785              :             }
     786      8486681 :             delete sumData;
     787              :         }
     788              :     }
     789              : }
     790              : 
     791              : 
     792              : void
     793       438196 : MSMeanData::openInterval(OutputDevice& dev, const SUMOTime startTime, const SUMOTime stopTime) {
     794       438196 :     dev.openTag(SUMO_TAG_INTERVAL).writeAttr(SUMO_ATTR_BEGIN, time2string(startTime)).writeAttr(SUMO_ATTR_END, time2string(stopTime));
     795       438196 :     dev.writeAttr(SUMO_ATTR_ID, myID);
     796       438196 : }
     797              : 
     798              : 
     799              : void
     800      1022617 : MSMeanData::writePrefix(OutputDevice& dev, const MeanDataValues& values, const SumoXMLTag tag, const std::string id) const {
     801      1022617 :     dev.openTag(tag);
     802      1022617 :     dev.writeAttr(SUMO_ATTR_ID, id);
     803      1022617 :     dev.writeOptionalAttr(SUMO_ATTR_SAMPLEDSECONDS, values.getSamples(), myWrittenAttributes);
     804      1022617 : }
     805              : 
     806              : 
     807              : void
     808       449507 : MSMeanData::writeXMLOutput(OutputDevice& dev,
     809              :                            SUMOTime startTime, SUMOTime stopTime) {
     810              :     // check whether this dump shall be written for the current time
     811       449507 :     int numReady = myDumpBegin < stopTime && myDumpEnd - DELTA_T >= startTime ? 1 : 0;
     812       449507 :     if (myTrackVehicles && myDumpBegin < stopTime) {
     813         2124 :         myPendingIntervals.push_back(std::make_pair(startTime, stopTime));
     814         2124 :         numReady = (int)myPendingIntervals.size();
     815        63312 :         for (std::vector<std::vector<MeanDataValues*> >::const_iterator i = myMeasures.begin(); i != myMeasures.end(); ++i) {
     816       124304 :             for (std::vector<MeanDataValues*>::const_iterator j = (*i).begin(); j != (*i).end(); ++j) {
     817        63116 :                 numReady = MIN2(numReady, ((MeanDataValueTracker*)*j)->getNumReady());
     818        63116 :                 if (numReady == 0) {
     819              :                     break;
     820              :                 }
     821              :             }
     822        63092 :             if (numReady == 0) {
     823              :                 break;
     824              :             }
     825              :         }
     826              :     }
     827       449507 :     const bool partialInterval = startTime < myInitTime;
     828       449507 :     if (numReady == 0 || myTrackVehicles || partialInterval) {
     829        12645 :         resetOnly(stopTime);
     830              :     }
     831       449507 :     if (partialInterval) {
     832              :         return;
     833              :     }
     834       887946 :     while (numReady-- > 0) {
     835       438450 :         if (!myPendingIntervals.empty()) {
     836         1588 :             startTime = myPendingIntervals.front().first;
     837         1588 :             stopTime = myPendingIntervals.front().second;
     838         1588 :             myPendingIntervals.pop_front();
     839              :         }
     840       438450 :         openInterval(dev, startTime, stopTime);
     841       438450 :         if (myAggregate == AggregateType::YES) {
     842          938 :             writeAggregated(dev, startTime, stopTime);
     843       437512 :         } else if (myAggregate == AggregateType::TAZ) {
     844           20 :             writeAggregatedTAZ(dev, startTime, stopTime);
     845              :         } else {
     846              :             MSEdgeVector::const_iterator edge = myEdges.begin();
     847     18338054 :             for (const std::vector<MeanDataValues*>& measures : myMeasures) {
     848     17900563 :                 writeEdge(dev, measures, *edge, startTime, stopTime);
     849              :                 ++edge;
     850              :             }
     851              :         }
     852       876898 :         dev.closeTag();
     853              :     }
     854              :     dev.flush();
     855              : }
     856              : 
     857              : 
     858              : void
     859        23323 : MSMeanData::writeXMLDetectorProlog(OutputDevice& dev) const {
     860        46646 :     dev.writeXMLHeader("meandata", "meandata_file.xsd");
     861        23323 : }
     862              : 
     863              : 
     864              : void
     865     26504997 : MSMeanData::detectorUpdate(const SUMOTime step) {
     866     26504997 :     if (step + DELTA_T == myDumpBegin) {
     867          639 :         init();
     868              :     }
     869     26504997 : }
     870              : 
     871              : 
     872              : const std::vector<MSMeanData::MeanDataValues*>*
     873            0 : MSMeanData::getEdgeValues(const MSEdge* edge) const {
     874              :     auto it = myEdgeIndex.find(edge);
     875            0 :     if (it != myEdgeIndex.end()) {
     876            0 :         return &myMeasures[it->second];
     877              :     } else {
     878              :         return nullptr;
     879              :     }
     880              : }
     881              : 
     882              : 
     883              : const std::vector<MSMoveReminder*>
     884            1 : MSMeanData::getReminders() const {
     885              :     std::vector<MSMoveReminder*> result;
     886           45 :     for (auto vec : myMeasures) {
     887           44 :         result.insert(result.end(), vec.begin(), vec.end());
     888           44 :     }
     889            1 :     return result;
     890            0 : }
     891              : 
     892              : 
     893              : double
     894            0 : MSMeanData::getAttributeValue(const MSLane* lane, SumoXMLAttr a, double defaultValue) const {
     895              :     double result = defaultValue;
     896            0 :     const std::vector<MeanDataValues*>* edgeValues = getEdgeValues(&lane->getEdge());
     897            0 :     if (edgeValues == nullptr) {
     898              :         return result;
     899              :     }
     900              :     MeanDataValues* values = nullptr;
     901            0 :     if (!myAmEdgeBased) {
     902            0 :         values = (*edgeValues)[lane->getIndex()];
     903              :     } else {
     904            0 :         MeanDataValues* sumData = createValuesSubData(nullptr, lane->getLength(), false);
     905            0 :         for (MeanDataValues* meanData : (*edgeValues)) {
     906            0 :             meanData->addTo(*sumData);
     907              :         }
     908              :         values = sumData;
     909              :     }
     910              :     const SUMOTime myLastResetTime = 0; // XXX store last reset time
     911            0 :     const SUMOTime period = SIMSTEP - myLastResetTime;
     912            0 :     result = values->getAttributeValue(a, period, lane->getEdge().getNumLanes(), lane->getSpeedLimit());
     913            0 :     if (myAmEdgeBased) {
     914            0 :         delete values;
     915              :     }
     916              :     return result;
     917              : }
     918              : 
     919              : 
     920              : MSMeanData::MeanDataValues*
     921      8584856 : MSMeanData::createValuesSubData(MSLane* const lane, const double length, const bool doAdd) const {
     922      8584856 :     MeanDataValues* values = createValues(lane, length, doAdd);
     923      8584856 :     if (mySubData != nullptr) {
     924          280 :         values->setSubData(mySubData->createValues(lane, length, doAdd));
     925              :     }
     926      8584856 :     return values;
     927              : }
     928              : 
     929              : 
     930              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1