LCOV - code coverage report
Current view: top level - src/microsim/output - MSE2Collector.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 93.1 % 519 483
Test Date: 2026-03-26 16:31:35 Functions: 94.1 % 34 32

            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    MSE2Collector.cpp
      15              : /// @author  Christian Roessel
      16              : /// @author  Daniel Krajzewicz
      17              : /// @author  Sascha Krieg
      18              : /// @author  Michael Behrisch
      19              : /// @author  Robbin Blokpoel
      20              : /// @author  Jakob Erdmann
      21              : /// @author  Leonhard Luecken
      22              : /// @date    Mon Feb 03 2014 10:13 CET
      23              : ///
      24              : // An areal detector covering a sequence of consecutive lanes
      25              : /****************************************************************************/
      26              : 
      27              : 
      28              : /* TODO:
      29              :  * tests:
      30              :  *  - subsecond variant, ballistic variant
      31              :  * allow omitting jam processing (?)
      32              :  *
      33              :  * Meso-compatibility? (esp. enteredLane-argument for MSBaseVehicle::notifyEnter() is not treated)
      34              :  * Compatibility without internal lanes?
      35              :  * Include leftVehicles into output?
      36              :  */
      37              : #include <config.h>
      38              : 
      39              : #include <cassert>
      40              : #include <algorithm>
      41              : #ifdef HAVE_FOX
      42              : #include <utils/common/ScopedLocker.h>
      43              : #endif
      44              : #include <microsim/MSLane.h>
      45              : #include <microsim/MSEdge.h>
      46              : #include <microsim/MSLink.h>
      47              : #include <microsim/MSNet.h>
      48              : #include <microsim/MSVehicle.h>
      49              : #include <microsim/MSVehicleType.h>
      50              : #include <microsim/transportables/MSTransportable.h>
      51              : #include <microsim/transportables/MSPModel.h>
      52              : #include <utils/common/StringUtils.h>
      53              : #include <utils/iodevices/OutputDevice.h>
      54              : #include "MSE2Collector.h"
      55              : 
      56              : //#define DEBUG_E2_CONSTRUCTOR
      57              : //#define DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
      58              : //#define DEBUG_E2_NOTIFY_MOVE
      59              : //#define DEBUG_E2_MAKE_VEHINFO
      60              : //#define DEBUG_E2_DETECTOR_UPDATE
      61              : //#define DEBUG_E2_TIME_ON_DETECTOR
      62              : //#define DEBUG_E2_JAMS
      63              : //#define DEBUG_E2_XML_OUT
      64              : //#define DEBUG_COND (true)
      65              : //#define DEBUG_COND (getID()=="e2Detector_e5.601A_1_SAa")
      66              : //#define DEBUG_COND (getID()=="702057")
      67              : //#define DEBUG_COND (getID()=="det0")
      68              : 
      69         6470 : MSE2Collector::MSE2Collector(const std::string& id,
      70              :                              DetectorUsage usage, MSLane* lane, double startPos, double endPos, double length,
      71              :                              SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold,
      72              :                              const std::string name, const std::string& vTypes,
      73              :                              const std::string& nextEdges,
      74         6470 :                              int detectPersons) :
      75              :     MSMoveReminder(id, lane, false),
      76              :     MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
      77         6470 :     myUsage(usage),
      78         6470 :     myName(name),
      79         6470 :     myJamHaltingSpeedThreshold(haltingSpeedThreshold),
      80         6470 :     myJamHaltingTimeThreshold(haltingTimeThreshold),
      81        12940 :     myJamDistanceThreshold(jamDistThreshold) {
      82              : 
      83              : #ifdef DEBUG_E2_CONSTRUCTOR
      84              :     if (DEBUG_COND) {
      85              :         std::cout << "\n" << "Creating MSE2Collector " << id
      86              :                   << " with lane = " << lane->getID()
      87              :                   << " startPos = " << startPos
      88              :                   << " endPos = " << endPos
      89              :                   << " length = " << length
      90              :                   << " haltingTimeThreshold = " << haltingTimeThreshold
      91              :                   << " haltingSpeedThreshold = " << haltingSpeedThreshold
      92              :                   << " jamDistThreshold = " << jamDistThreshold
      93              :                   << std::endl;
      94              :     }
      95              : #endif
      96              : 
      97              :     assert(lane != 0);
      98              : 
      99              :     // check that exactly one of length, startPos, endPos is invalid
     100         6470 :     bool lengthInvalid = length == std::numeric_limits<double>::max() || length <= 0;
     101         6470 :     bool endPosInvalid = endPos == std::numeric_limits<double>::max();
     102              :     bool posInvalid = startPos == std::numeric_limits<double>::max();
     103              : 
     104              :     // check and normalize positions (assure positive values for pos and endPos, snap to lane-ends)
     105         6470 :     if (lengthInvalid) {
     106              :         // assume that the detector is only located on a single lane
     107           29 :         if (posInvalid) {
     108            0 :             WRITE_WARNING(TL("No valid detector length and start position given. Assuming startPos = 0 and length = end position"));
     109              :             startPos = 0;
     110              :         }
     111           29 :         if (endPosInvalid) {
     112            0 :             WRITE_WARNING(TL("No valid detector length and end position given. Assuming endPos = lane length and length = endPos-startPos"));
     113              :             endPos = lane->getLength();
     114              :         }
     115           29 :         endPos = endPos < 0 ? lane->getLength() + endPos : endPos;
     116           29 :         startPos = startPos < 0 ? lane->getLength() + startPos : startPos;
     117           29 :         bool valid = endPos <= lane->getLength() && 0 <= startPos && startPos < endPos;
     118              :         if (!valid) {
     119            0 :             throw InvalidArgument("Error in specification for E2Detector '" + id + "'. Positional argument is malformed. 0 <= pos < endPos <= lane.getLength() is required.");
     120              :         }
     121              :         // snap detector ends to lane ends
     122           29 :         endPos = snap(endPos, lane->getLength(), POSITION_EPS);
     123           29 :         startPos = snap(startPos, 0., POSITION_EPS);
     124           29 :         length = endPos - startPos;
     125         6441 :     } else if (posInvalid) {
     126              :         // endPosInvalid == false
     127         2202 :         endPos = endPos < 0 ? lane->getLength() + endPos : endPos;
     128         2202 :         endPos = snap(endPos, lane->getLength(), POSITION_EPS);
     129              :     } else {
     130              :         // posInvalid == false
     131         4239 :         startPos = startPos < 0 ? lane->getLength() + startPos : startPos;
     132         4239 :         startPos = snap(startPos, 0., POSITION_EPS);
     133              :     }
     134              : 
     135         6470 :     myStartPos = startPos;
     136         6470 :     myEndPos = endPos;
     137              : 
     138              :     std::vector<MSLane*> lanes;
     139         6470 :     if (posInvalid) {
     140         4404 :         lanes = selectLanes(lane, length, "bw");
     141         4268 :     } else if (endPosInvalid) {
     142         8478 :         lanes = selectLanes(lane, length, "fw");
     143              :     } else {
     144              :         // assuming detector is only located at a single lane
     145           29 :         lanes.push_back(lane);
     146              :     }
     147              : 
     148         6470 :     initAuxiliaries(lanes);
     149         6470 :     checkPositioning(endPosInvalid, length);
     150         6470 :     addDetectorToLanes(lanes);
     151         6470 : }
     152              : 
     153              : 
     154          252 : MSE2Collector::MSE2Collector(const std::string& id,
     155              :                              DetectorUsage usage, std::vector<MSLane*> lanes, double startPos, double endPos,
     156              :                              SUMOTime haltingTimeThreshold, double haltingSpeedThreshold, double jamDistThreshold,
     157              :                              const std::string name, const std::string& vTypes,
     158              :                              const std::string& nextEdges,
     159          252 :                              int detectPersons) :
     160              :     MSMoveReminder(id, lanes[lanes.size() - 1], false), // assure that lanes.size() > 0 at caller side!!!
     161              :     MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
     162          252 :     myUsage(usage),
     163          252 :     myName(name),
     164          252 :     myFirstLane(lanes[0]),
     165          252 :     myLastLane(lanes[lanes.size() - 1]),
     166          252 :     myStartPos(startPos),
     167          252 :     myEndPos(endPos),
     168          252 :     myJamHaltingSpeedThreshold(haltingSpeedThreshold),
     169          252 :     myJamHaltingTimeThreshold(haltingTimeThreshold),
     170          504 :     myJamDistanceThreshold(jamDistThreshold) {
     171              : 
     172              :     for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
     173              :         assert((*i) != 0);
     174              :     }
     175              : 
     176              : #ifdef DEBUG_E2_CONSTRUCTOR
     177              :     if (DEBUG_COND) {
     178              :         std::cout << "\n" << "Creating MSE2Collector " << id
     179              :                   << " with endLane = " << myLastLane->getID()
     180              :                   << " endPos = " << endPos
     181              :                   << " startLane = " << myFirstLane->getID()
     182              :                   << " startPos = " << startPos
     183              :                   << " haltingTimeThreshold = " << haltingTimeThreshold
     184              :                   << " haltingSpeedThreshold = " << haltingSpeedThreshold
     185              :                   << " jamDistThreshold = " << jamDistThreshold
     186              :                   << std::endl;
     187              :     }
     188              : #endif
     189              : 
     190          252 :     myStartPos = myStartPos < 0 ? lanes[0]->getLength() + myStartPos : myStartPos;
     191          252 :     myEndPos = myEndPos < 0 ? lanes[lanes.size() - 1]->getLength() + myEndPos : myEndPos;
     192              : 
     193          252 :     if (myStartPos < POSITION_EPS) {
     194            1 :         myStartPos = 0;
     195              :     }
     196          252 :     if (myEndPos > lanes[lanes.size() - 1]->getLength() - POSITION_EPS) {
     197            2 :         myEndPos = lanes[lanes.size() - 1]->getLength();
     198              :     }
     199              : 
     200              : 
     201          252 :     initAuxiliaries(lanes);
     202          246 :     checkPositioning();
     203          246 :     addDetectorToLanes(lanes);
     204          288 : }
     205              : 
     206              : 
     207              : void
     208         6716 : MSE2Collector::checkPositioning(bool posGiven, double desiredLength) {
     209              :     // check if detector was truncated
     210         6716 :     if (desiredLength > 0 && myDetectorLength < desiredLength - NUMERICAL_EPS) {
     211           88 :         std::stringstream ss;
     212              :         ss << "Cannot build detector of length " << desiredLength
     213           88 :            << " because no further continuation lane was found for lane '" << (posGiven ? myLastLane->getID() : myFirstLane->getID())
     214          176 :            << "'! Truncated detector at length " << myDetectorLength << ".";
     215           88 :         WRITE_WARNING(ss.str());
     216           88 :     }
     217              : 
     218         6716 :     if (myDetectorLength < POSITION_EPS && (myStartPos > 0. || myEndPos < myLastLane->getLength())) {
     219              :         // assure minimal detector length
     220            4 :         double prolong = POSITION_EPS - myDetectorLength;
     221            4 :         double startPos = MAX2(0., myStartPos - prolong); // new startPos
     222            4 :         prolong -= myStartPos - startPos;
     223            4 :         myStartPos = startPos;
     224            4 :         if (prolong > 0.) {
     225            4 :             myEndPos = MIN2(myEndPos + prolong, myLastLane->getLength());
     226              :         }
     227           20 :         WRITE_WARNING("Adjusted detector positioning to meet requirement length >= " + toString(POSITION_EPS)
     228              :                       + ". New position is [" + toString(myStartPos) + "," + toString(myEndPos) + "]");
     229              :     }
     230              : 
     231              :     // do some regularization snapping...
     232         6716 :     myStartPos = snap(myStartPos, 0., POSITION_EPS);
     233         6716 :     myStartPos = snap(myStartPos, myFirstLane->getLength() - POSITION_EPS, POSITION_EPS);
     234         6716 :     myStartPos = snap(myStartPos, 0., POSITION_EPS);
     235         6716 :     myEndPos = snap(myEndPos, myLastLane->getLength(), POSITION_EPS);
     236         6716 :     myEndPos = snap(myEndPos, POSITION_EPS, POSITION_EPS);
     237         6716 :     myEndPos = snap(myEndPos, myLastLane->getLength(), POSITION_EPS);
     238         6716 :     recalculateDetectorLength();
     239              : 
     240              : #ifdef DEBUG_E2_CONSTRUCTOR
     241              :     if (DEBUG_COND) {
     242              :         std::stringstream ss;
     243              :         //    ss << std::setprecision(32) << myEndPos << " : " << POSITION_EPS;
     244              :         //    std::cout << ss.str() << std::endl;
     245              :         std::cout << "myStartPos = " << myStartPos << std::endl;
     246              :         std::cout << "myEndPos = " << myEndPos << std::endl;
     247              :         std::cout << "myLastLane->getLength() = " << myLastLane->getLength() << std::endl;
     248              :     }
     249              : #endif
     250              : 
     251              : 
     252              :     assert((myStartPos >= POSITION_EPS  || myStartPos == 0) && myStartPos < myFirstLane->getLength());
     253              :     assert(myEndPos <= myLastLane->getLength() - POSITION_EPS || myEndPos == myLastLane->getLength());
     254              :     assert(myFirstLane != myLastLane || myEndPos - myStartPos > 0);
     255         6716 : }
     256              : 
     257              : 
     258              : double
     259        46795 : MSE2Collector::snap(double value, double snapPoint, double snapDist) {
     260        46795 :     if (fabs(value - snapPoint) < snapDist) {
     261              :         return snapPoint;
     262              :     } else {
     263        31499 :         return value;
     264              :     }
     265              : }
     266              : 
     267              : 
     268              : void
     269         6716 : MSE2Collector::recalculateDetectorLength() {
     270              :     std::vector<std::string>::const_iterator i;
     271              :     std::vector<MSLane*> lanes;
     272              :     // get real lanes
     273      2038565 :     for (i = myLanes.begin(); i != myLanes.end(); ++i) {
     274      2031849 :         MSLane* lane = MSLane::dictionary(*i);
     275      2031849 :         lanes.push_back(lane);
     276              :     }
     277              : 
     278              :     // sum up their lengths
     279              :     std::vector<MSLane*>::const_iterator j;
     280              :     MSLane* previous = nullptr;
     281         6716 :     myDetectorLength = 0;
     282      2038565 :     for (j = lanes.begin(); j != lanes.end(); ++j) {
     283              :         // lane length
     284      2031849 :         myDetectorLength += (*j)->getLength();
     285      2031849 :         if (previous != nullptr && !MSGlobals::gUsingInternalLanes) {
     286              :             // eventually link length
     287           14 :             myDetectorLength += previous->getLinkTo(*j)->getLength();
     288              :         }
     289      2031849 :         previous = *j;
     290              :     }
     291              :     // subtract uncovered area on first and last lane
     292         6716 :     myDetectorLength -= myStartPos;
     293         6716 :     myDetectorLength -= myLastLane->getLength() - myEndPos;
     294              : 
     295              : #ifdef DEBUG_E2_CONSTRUCTOR
     296              :     if (DEBUG_COND) {
     297              :         std::cout << "Total detector length after recalculation = " << myDetectorLength << std::endl;
     298              :     }
     299              : #endif
     300         6716 : }
     301              : 
     302              : 
     303        12659 : MSE2Collector::~MSE2Collector() {
     304              :     // clear move notifications
     305         6716 :     clearState(SUMOTime_MAX);
     306        32807 : }
     307              : 
     308              : 
     309              : std::vector<MSLane*>
     310         6441 : MSE2Collector::selectLanes(MSLane* lane, double length, std::string dir) {
     311              :     // direction of detector extension
     312              :     assert(dir == "fw" || dir == "bw");
     313         6441 :     bool fw = dir == "fw";
     314              :     double linkLength = 0; // linkLength (used if no internal lanes are present)
     315              :     bool subtractedLinkLength = false; // whether linkLength was subtracted during the last iteration.
     316              : 
     317              : #ifdef DEBUG_E2_CONSTRUCTOR
     318              :     if (DEBUG_COND) {
     319              :         std::cout << "\n" << "selectLanes()" << (fw ? "(forward)" : "(backward)") << std::endl;
     320              :     }
     321              : #endif
     322              :     std::vector<MSLane*> lanes;
     323              :     // Selected lanes are stacked into vector 'lanes'. If dir == "bw" lanes will be reversed after this is done.
     324              :     // The length is reduced while adding lanes to the detector
     325              :     // First we adjust the starting value for length (in the first iteration, the whole length of the first considered lane is subtracted,
     326              :     // while it might only be partially covered by the detector)
     327         6441 :     if (fw) {
     328              :         assert(myStartPos != std::numeric_limits<double>::max());
     329         4239 :         length += myStartPos;
     330              :     } else {
     331              :         assert(myEndPos != std::numeric_limits<double>::max());
     332         2202 :         length += lane->getLength() - myEndPos;
     333              :     }
     334              :     length = MAX2(POSITION_EPS, length); // this assures to add at least one lane to lanes
     335      2037366 :     while (length >= POSITION_EPS && lane != nullptr) {
     336              :         // Break loop for length <= NUMERICAL_EPS to avoid placement of very small
     337              :         // detector piece on the end or beginning of one lane due to numerical rounding errors.
     338      2030925 :         lanes.push_back(lane);
     339              : #ifdef DEBUG_E2_CONSTRUCTOR
     340              :         if (DEBUG_COND) {
     341              :             std::cout << "Added lane " << lane->getID()
     342              :                       << " (length: " << lane->getLength() << ")" << std::endl;
     343              :         }
     344              : #endif
     345              : 
     346      2030925 :         length -= lane->getLength();
     347              : 
     348              :         // proceed to upstream predecessor
     349      2030925 :         if (fw) {
     350      2027439 :             lane = lane->getCanonicalSuccessorLane();
     351              :         } else {
     352         3486 :             lane = lane->getCanonicalPredecessorLane();
     353              :         }
     354              : 
     355              : 
     356              :         subtractedLinkLength = false;
     357      2030925 :         if (lane != nullptr && !MSGlobals::gUsingInternalLanes && length > POSITION_EPS) {
     358              :             // In case wher no internal lanes are used,
     359              :             // take into account the link length for the detector range
     360              :             linkLength = 0;
     361            8 :             if (fw) {
     362            8 :                 linkLength = lanes.back()->getLinkTo(lane)->getLength();
     363              :             } else {
     364            0 :                 linkLength = lane->getLinkTo(lanes.back())->getLength();
     365              :             }
     366            8 :             length -= linkLength;
     367              :             subtractedLinkLength = true;
     368              :         }
     369              : 
     370              : 
     371              : #ifdef DEBUG_E2_CONSTRUCTOR
     372              :         if (DEBUG_COND) {
     373              :             if (lane != 0) {
     374              :                 std::cout << (fw ? "Successor lane: " : "Predecessor lane: ") << "'" << lane->getID() << "'";
     375              :             }
     376              :             std::cout << std::endl;
     377              :         }
     378              : #endif
     379              :     }
     380              : 
     381         6441 :     if (subtractedLinkLength) {
     382              :         // if the link's length was subtracted during the last step,
     383              :         // the start/endPos would lie on a non-existing internal lane,
     384              :         // therefore revert and truncate detector part on the non-existing internal lane.
     385            0 :         length += linkLength;
     386              :     }
     387              : 
     388              : 
     389              :     // 1) At this point a negative <length> means that not the whole last stored lane lanes[lanes.size()-1]
     390              :     // should be added to the detector, but the detector should spare out a part with length = -<length>
     391              :     // If this part is too small (of length < POSITION_EPS) we take the whole lane
     392              :     // 2) The whole lane is also taken for the case that <length> is positive. This corresponds to on
     393              :     // of three situations: i) <length> < POSITION_EPS (break condition -> don't take too small pieces on the next lane)
     394              :     //                 ii&iii) <length> >= POS_EPSILON may arise either if no continuation lane was found (lane==0), or
     395              :     //                         in case of not using internal lanes if the detector end/start falls on a link.
     396              :     // In all cases we take the whole last lane.
     397         6441 :     if (fw) {
     398         4239 :         if (length > -POSITION_EPS) {
     399         2289 :             myEndPos = lanes[lanes.size() - 1]->getLength();
     400         1950 :         } else if (length < 0) {
     401         1950 :             myEndPos = lanes[lanes.size() - 1]->getLength() + length;
     402              :         }
     403              :     } else {
     404         2202 :         if (length > -POSITION_EPS) {
     405          536 :             myStartPos = 0;
     406         1666 :         } else if (length < 0) {
     407         1666 :             myStartPos = -length;
     408              :         }
     409              :     }
     410              : 
     411              :     // reverse lanes if lane selection was backwards
     412         6441 :     if (!fw) {
     413              :         std::reverse(lanes.begin(), lanes.end());
     414              :     }
     415              : 
     416         6441 :     return lanes;
     417            0 : }
     418              : 
     419              : void
     420         6716 : MSE2Collector::addDetectorToLanes(std::vector<MSLane*>& lanes) {
     421              : #ifdef DEBUG_E2_CONSTRUCTOR
     422              :     if (DEBUG_COND) {
     423              :         std::cout << "\n" << "Adding detector " << myID << " to lanes:" << std::endl;
     424              :     }
     425              : #endif
     426      2038565 :     for (std::vector<MSLane*>::iterator l = lanes.begin(); l != lanes.end(); ++l) {
     427      2031849 :         (*l)->addMoveReminder(this);
     428              : #ifdef DEBUG_E2_CONSTRUCTOR
     429              :         if (DEBUG_COND) {
     430              :             std::cout << (*l)->getID() << std::endl;
     431              :         }
     432              : #endif
     433              :     }
     434         6716 : }
     435              : 
     436              : void
     437         6722 : MSE2Collector::initAuxiliaries(std::vector<MSLane*>& lanes) {
     438              :     // Checks integrity of myLanes, adds internal-lane information, inits myLength, myFirstLane, myLastLane, myOffsets, myEndPos/myStartPos
     439         6722 :     myFirstLane = lanes[0];
     440         6722 :     myLastLane = lanes[lanes.size() - 1];
     441              : 
     442              : #ifdef DEBUG_E2_CONSTRUCTOR
     443              :     if (DEBUG_COND) {
     444              :         std::cout << "\n" << "Initializing auxiliaries:"
     445              :                   << "\nFirst lane: " << myFirstLane->getID() << " (startPos = " << myStartPos << ")"
     446              :                   << "\nLast lane: " << myLastLane->getID() << " (endPos = " << myEndPos << ")"
     447              :                   << std::endl;
     448              :     }
     449              : #endif
     450              : 
     451              :     // Init myOffsets and myDetectorLength.
     452              :     // The loop below runs through the given lanes assuming the possibility that only non-internal lanes are given
     453              :     // or at least not all relevant internal lanes are considered. During this a new, complete list of lane ids is
     454              :     // built into myLanes.
     455              :     myLanes.clear();
     456              : 
     457              :     // myDetectorLength will be increased in the loop below, always giving
     458              :     // the offset of the currently considered lane to the detector start
     459         6722 :     myDetectorLength = -myStartPos;
     460              :     myOffsets.clear();
     461              : 
     462              :     // loop over detector lanes and accumulate offsets with respect to the first lane's begin
     463              :     // (these will be corrected afterwards by subtracting the start position.)
     464              :     std::vector<MSLane*>::iterator il = lanes.begin();
     465              : 
     466              :     // start on an internal lane?
     467              :     // (This may happen if specifying the detector by its upstream
     468              :     //  length starting from a given end position)
     469         6722 :     const MSLane* internal = (*il)->isInternal() ? *il : nullptr;
     470              : 
     471              : #ifdef DEBUG_E2_CONSTRUCTOR
     472              :     if (DEBUG_COND) {
     473              :         std::cout << "\n" << "Initializing offsets:" << std::endl;
     474              :     }
     475              : #endif
     476              : 
     477              :     while (true) {
     478              :         // Consider the next internal lanes
     479      2030753 :         while (internal != nullptr) {
     480         1111 :             myLanes.push_back(internal->getID());
     481         1111 :             myOffsets.push_back(myDetectorLength);
     482              : 
     483              : #ifdef DEBUG_E2_CONSTRUCTOR
     484              :             if (DEBUG_COND) {
     485              :                 std::cout << "Offset for lane " << internal->getID() << " = " << myDetectorLength
     486              :                           << std::endl;
     487              :             }
     488              : #endif
     489              : 
     490         1111 :             myDetectorLength += internal->getLength();
     491         1111 :             if (internal->getID() == myLastLane->getID()) {
     492              :                 break;
     493              :             }
     494              : 
     495              :             // There should be a unique continuation for each internal lane
     496              :             assert(internal->getLinkCont().size() == 1);
     497              : 
     498         1111 :             internal = internal->getLinkCont()[0]->getViaLaneOrLane();
     499         1111 :             if (!internal->isInternal()) {
     500              :                 // passed the junction
     501              :                 internal = nullptr;
     502              :                 break;
     503              :             }
     504              :         }
     505              : 
     506              :         // Consider the next non-internal lane
     507              :         // This is the first lane in the first iteration, if it is non-internal
     508              :         // However, it can equal myLanes.end() if the myLastLane is internal. In that case we break.
     509              : 
     510              :         // Move il to next non-internal
     511      2031544 :         while (il != lanes.end() && (*il)->isInternal()) {
     512              :             il++;
     513              :         }
     514      2030744 :         if (il == lanes.end()) {
     515              :             break;
     516              :         }
     517              : 
     518              :         // There is still a non-internal lane to consider
     519      2030744 :         MSLane* lane = *il;
     520      2030744 :         myLanes.push_back(lane->getID());
     521              : 
     522              : #ifdef DEBUG_E2_CONSTRUCTOR
     523              :         if (DEBUG_COND) {
     524              :             std::cout << "Offset for lane " << lane->getID() << " = " << myDetectorLength
     525              :                       << std::endl;
     526              :         }
     527              : #endif
     528              : 
     529              :         // Offset to detector start for this lane
     530      2030744 :         myOffsets.push_back(myDetectorLength);
     531              : 
     532              :         // Add the lanes length to the detector offset
     533      2030744 :         myDetectorLength += lane->getLength();
     534              : 
     535              :         // Get the next lane if this lane isn't the last one
     536      2030744 :         if (++il == lanes.end()) {
     537              :             break;
     538              :         }
     539              : 
     540      2024028 :         if ((*il)->isInternal()) {
     541              :             // next lane in myLanes is internal
     542          536 :             internal = *il;
     543          536 :             continue;
     544              :         }
     545              : 
     546              :         // find the connection to next
     547      2023492 :         const MSLink* link = lane->getLinkTo(*il);
     548      2023492 :         if (link == nullptr) {
     549           18 :             throw InvalidArgument("Lanes '" + lane->getID() + "' and '" + (*il)->getID() + "' are not consecutive in definition of e2Detector '" + getID() + "'");
     550              :         }
     551              : 
     552      2023486 :         if (!MSGlobals::gUsingInternalLanes) {
     553           14 :             myDetectorLength += link->getLength();
     554              :         } else {
     555              :             internal = link->getViaLane();
     556              :         }
     557              :     }
     558              : 
     559              :     // Subtract distance not covered on the last considered lane
     560         6716 :     bool fw = myEndPos == std::numeric_limits<double>::max();
     561         6716 :     if (fw) {
     562            0 :         myDetectorLength -= myStartPos;
     563              :     } else {
     564         6716 :         myDetectorLength -= myLastLane->getLength() - myEndPos;
     565              :     }
     566              : 
     567              : #ifdef DEBUG_E2_CONSTRUCTOR
     568              :     if (DEBUG_COND) {
     569              :         std::cout << "Total detector length after initAuxiliaries() = " << myDetectorLength << std::endl;
     570              :     }
     571              : #endif
     572              : 
     573              : // make lanes a complete list including internal lanes
     574         6716 :     lanes = getLanes();
     575         6716 : }
     576              : 
     577              : 
     578              : std::vector<MSLane*>
     579       102029 : MSE2Collector::getLanes() {
     580              :     std::vector<MSLane*> res;
     581      2729277 :     for (std::vector<std::string>::const_iterator i = myLanes.begin(); i != myLanes.end(); ++i) {
     582      2627248 :         res.push_back(MSLane::dictionary(*i));
     583              :     }
     584       102029 :     return res;
     585            0 : }
     586              : 
     587              : 
     588              : bool
     589    109585659 : MSE2Collector::notifyMove(SUMOTrafficObject& veh, double oldPos,
     590              :                           double newPos, double newSpeed) {
     591              : 
     592    109585659 :     if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
     593              :         bool keep = false;
     594          270 :         MSBaseVehicle& v = dynamic_cast<MSBaseVehicle&>(veh);
     595          540 :         for (MSTransportable* p : v.getPersons()) {
     596          270 :             keep = notifyMove(*p, oldPos, newPos, newSpeed);
     597              :         }
     598          270 :         return keep;
     599              :     }
     600              : #ifdef HAVE_FOX
     601    109585389 :     ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
     602              : #endif
     603              :     VehicleInfoMap::iterator vi = myVehicleInfos.find(veh.getID());
     604    109585389 :     if (vi == myVehicleInfos.end()) {
     605            0 :         const std::string objectType = veh.isPerson() ? "Person" : "Vehicle";
     606            0 :         if (myNextEdges.size() > 0) {
     607            0 :             WRITE_WARNING(objectType + " '" + veh.getID() + "' appeared inside detector '" + getID() + "' after previously being filtered out. time=" + time2string(SIMSTEP) + ".");
     608              :         } else {
     609            0 :             WRITE_WARNING(objectType + " '" + veh.getID() + "' suddenly appeared inside detector '" + getID() + "'. time=" + time2string(SIMSTEP) + ".");
     610              :         }
     611              :         return false;
     612              :     }
     613              : 
     614              :     const std::string& vehID = veh.getID();
     615    109585389 :     VehicleInfo& vehInfo = *(vi->second);
     616              : 
     617              :     // position relative to the detector start
     618    109585389 :     double relPos = vehInfo.entryOffset + newPos;
     619              : 
     620              :     // update current distance to the detector end
     621    109585389 :     vehInfo.distToDetectorEnd = myDetectorLength - relPos;
     622              : 
     623              : #ifdef DEBUG_E2_NOTIFY_MOVE
     624              :     if (DEBUG_COND) {
     625              :         std::cout << "\n" << SIMTIME
     626              :                   << " MSE2Collector::notifyMove() (detID = " << myID << " on lane '" << myLane->getID() << "')"
     627              :                   << " called by vehicle '" << vehID << "'"
     628              :                   << " at relative position " << relPos
     629              :                   << ", distToDetectorEnd = " << vehInfo.distToDetectorEnd << std::endl;
     630              :     }
     631              : #endif
     632              : 
     633              :     // Check whether vehicle has reached the detector begin
     634    109585389 :     if (relPos <= 0) {
     635              :         // detector not yet reached, request being informed further
     636              : #ifdef DEBUG_E2_NOTIFY_MOVE
     637              :         if (DEBUG_COND) {
     638              :             std::cout << "Vehicle has not yet reached the detector start position." << std::endl;
     639              :         }
     640              : #endif
     641              :         return true;
     642     49016228 :     } else if (!vehInfo.hasEntered) {
     643       664480 :         vehInfo.hasEntered = true;
     644       664480 :         myNumberOfEnteredVehicles++;
     645       664480 :         myNumberOfSeenVehicles++;
     646              :     }
     647              : 
     648              : 
     649              :     // determine whether vehicle has moved beyond the detector's end
     650     49016228 :     bool vehPassedDetectorEnd = - vehInfo.exitOffset <= newPos - veh.getVehicleType().getLength();
     651              : 
     652              :     // determine whether vehicle has been on the detector at all
     653     49016228 :     bool vehicleEnteredLaneAfterDetector = vehPassedDetectorEnd && (-vehInfo.exitOffset <= oldPos - veh.getVehicleType().getLength());
     654              :     // ... if not, dont create any notification at all
     655              :     if (vehicleEnteredLaneAfterDetector) {
     656              : #ifdef DEBUG_E2_NOTIFY_MOVE
     657              :         if (DEBUG_COND) {
     658              :             std::cout << "Vehicle entered lane behind detector." << std::endl;
     659              :         }
     660              : #endif
     661              :     } else {
     662     49016164 :         myMoveNotifications.push_back(makeMoveNotification(veh, oldPos, newPos, newSpeed, vehInfo));
     663              :     }
     664              : 
     665              : 
     666     49016228 :     if (vehPassedDetectorEnd) {
     667              : #ifdef DEBUG_E2_NOTIFY_MOVE
     668              :         if (DEBUG_COND) {
     669              :             std::cout << "Vehicle has left the detector longitudinally." << std::endl;
     670              :         }
     671              : #endif
     672              :         // Vehicle is beyond the detector, unsubscribe and register removal from myVehicleInfos
     673              :         myLeftVehicles.insert(vehID);
     674              :         return false;
     675              :     } else {
     676              :         // Receive further notifications
     677              :         return true;
     678              :     }
     679              : }
     680              : 
     681              : bool
     682       864534 : MSE2Collector::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     683              : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
     684              :     if (DEBUG_COND) {
     685              :         std::cout << "\n" << SIMTIME << " notifyLeave() (detID = " << myID << " on lane '" << myLane->getID() << "')"
     686              :                   << "called by vehicle '" << veh.getID() << "'" << std::endl;
     687              :     }
     688              : #endif
     689              : 
     690              : #ifdef HAVE_FOX
     691       864534 :     ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
     692              : #endif
     693       864534 :     if (reason == MSMoveReminder::NOTIFICATION_JUNCTION && !veh.isPerson()) {
     694              :         // vehicle left lane via junction, unsubscription and registering in myLeftVehicles when
     695              :         // moving beyond the detector end is controlled in notifyMove.
     696              : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
     697              :         if (DEBUG_COND) {
     698              :             std::cout << SIMTIME << " Left longitudinally (along junction) -> keep subscription [handle exit in notifyMove()]" << std::endl;
     699              :         }
     700              : #endif
     701              : 
     702       853390 :         if (enteredLane == nullptr || std::find(myLanes.begin(), myLanes.end(), enteredLane->getID()) == myLanes.end()) {
     703              :             // Entered lane is not part of the detector
     704              :             VehicleInfoMap::iterator vi = myVehicleInfos.find(veh.getID());
     705              :             // Determine exit offset, where vehicle left the detector
     706       795788 :             double exitOffset = vi->second->entryOffset - myOffsets[vi->second->currentOffsetIndex] - vi->second->currentLane->getLength();
     707      1590270 :             vi->second->exitOffset = MAX2(vi->second->exitOffset, exitOffset);
     708              : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
     709              :             if (DEBUG_COND) {
     710              :                 std::cout << SIMTIME << " Vehicle '" << veh.getID() << "' leaves the detector. Exit offset = " << vi->second->exitOffset << std::endl;
     711              :             }
     712              : #endif
     713              :         }
     714              : 
     715       853390 :         return true;
     716              :     } else {
     717              :         VehicleInfoMap::iterator vi = myVehicleInfos.find(veh.getID());
     718        11144 :         if (vi != myVehicleInfos.end()) {
     719              :             // erase vehicle, which leaves in a non-longitudinal way, immediately
     720         9834 :             if (vi->second->hasEntered) {
     721         2018 :                 myNumberOfLeftVehicles++;
     722              :             }
     723         9834 :             delete vi->second;
     724              :             myVehicleInfos.erase(vi);
     725              : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
     726              :             if (DEBUG_COND) {
     727              :                 std::cout << SIMTIME << " Left non-longitudinally (lanechange, teleport, parking, etc) -> discard subscription" << std::endl;
     728              :             }
     729              : #endif
     730              :         } else {
     731              :             assert(veh.isPerson());
     732              :         }
     733              :         return false;
     734              :     }
     735              : }
     736              : 
     737              : 
     738              : bool
     739       735250 : MSE2Collector::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     740              : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
     741              :     if (DEBUG_COND) {
     742              :         std::cout << std::endl << SIMTIME << " notifyEnter() (detID = " << myID << " on lane '" << myLane->getID() << "')"
     743              :                   << " called by vehicle '" << veh.getID()
     744              :                   << "' entering lane '" << (enteredLane != 0 ? enteredLane->getID() : "NULL") << "'" << std::endl;
     745              :     }
     746              : #endif
     747              :     // notifyEnter() should only be called for lanes of the detector
     748              :     assert(std::find(myLanes.begin(), myLanes.end(), enteredLane->getID()) != myLanes.end());
     749              :     assert(veh.getLane() == enteredLane || !veh.isVehicle());
     750              : 
     751              :     // vehicles must be kept if the "inductionloop" wants to detect passeengers
     752       735250 :     if (!vehicleApplies(veh) && (veh.isPerson() || myDetectPersons <= (int)PersonMode::WALK)) {
     753              :         // That's not my type...
     754              :         return false;
     755              :     }
     756       730899 :     if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
     757              :         bool keep = false;
     758           40 :         MSBaseVehicle& v = dynamic_cast<MSBaseVehicle&>(veh);
     759           80 :         for (MSTransportable* p : v.getPersons()) {
     760           40 :             keep = notifyEnter(*p, reason, enteredLane);
     761              :         }
     762           40 :         return keep;
     763              :     }
     764              : 
     765              :     // determine whether the vehicle entered the lane behind the detector end
     766              :     // e.g. due to lane change manoeuver
     767       730859 :     if (reason != NOTIFICATION_JUNCTION) {
     768       418416 :         const double vehBackPos = veh.getBackPositionOnLane(enteredLane);
     769       418416 :         bool vehEnteredBehindDetectorEnd = (enteredLane == myLastLane) && myEndPos <= vehBackPos;
     770              :         if (vehEnteredBehindDetectorEnd) {
     771              :             // this vehicle cannot influence detector readings, do not subscribe
     772              :             // to move notifications
     773              : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
     774              :             if (DEBUG_COND) {
     775              :                 std::cout << "Vehicle entered the lane behind the detector, ignoring it." << std::endl;
     776              :                 std::cout << "(myEndPos = " << this->myEndPos << ", veh.getBackPositionOnLane() = " << vehBackPos << ")" << std::endl;
     777              :             }
     778              : #endif
     779              :             return false;
     780              :         }
     781              :     }
     782              : 
     783              : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
     784              :     if (DEBUG_COND) {
     785              :         if (veh.isVehicle() && !dynamic_cast<SUMOVehicle&>(veh).isOnRoad()) {
     786              :             // Vehicle is teleporting over the edge
     787              :             std::cout << "Vehicle is off road (teleporting over edge)..." << std::endl;
     788              :         }
     789              :     }
     790              : #endif
     791              : 
     792              : #ifdef HAVE_FOX
     793       730566 :     ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
     794              : #endif
     795              :     const std::string& vehID = veh.getID();
     796              :     VehicleInfoMap::iterator vi = myVehicleInfos.find(vehID);
     797       730566 :     if (vi != myVehicleInfos.end()) {
     798              :         // Register move current offset to the next lane
     799        57611 :         if (vi->second->currentLane != enteredLane) {
     800        57602 :             vi->second->currentOffsetIndex++;
     801        57602 :             vi->second->currentLane = enteredLane;
     802              :         }
     803              : 
     804              : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
     805              :         if (DEBUG_COND) {
     806              :             std::cout << SIMTIME << " Vehicle '" << veh.getID() << "' on lane '" << veh.getLane()->getID()
     807              :                       << "' already known. No new VehicleInfo is created.\n"
     808              :                       << "enteredLane = " << enteredLane->getID() << "\nmyLanes[vi->offset] = " << myLanes[vi->second->currentOffsetIndex]
     809              :                       << std::endl;
     810              :         }
     811              : #endif
     812              :         assert(myLanes[vi->second->currentOffsetIndex] == enteredLane->getID());
     813              : 
     814              :         // but don't add a second subscription for another lane
     815        57611 :         return false;
     816              :     }
     817              : 
     818              : 
     819              : 
     820              : #ifdef DEBUG_E2_NOTIFY_ENTER_AND_LEAVE
     821              :     if (DEBUG_COND) {
     822              :         std::cout << SIMTIME << " Adding VehicleInfo for vehicle '" << veh.getID() << "'." << std::endl;
     823              :     }
     824              : #endif
     825              : 
     826              :     // Add vehicle info
     827      1345910 :     myVehicleInfos.insert(std::make_pair(vehID, makeVehicleInfo(veh, enteredLane)));
     828              :     // Subscribe to vehicle's movement notifications
     829       672955 :     return true;
     830              : }
     831              : 
     832              : 
     833              : MSE2Collector::VehicleInfo*
     834       672955 : MSE2Collector::makeVehicleInfo(const SUMOTrafficObject& veh, const MSLane* enteredLane) const {
     835              :     // The vehicle's distance to the detector end
     836       672955 :     int j = (int)(std::find(myLanes.begin(), myLanes.end(), enteredLane->getID()) - myLanes.begin());
     837              :     assert(j >= 0 && j < (int)myLanes.size());
     838       672955 :     double entryOffset = myOffsets[j];
     839       672955 :     double distToDetectorEnd = myDetectorLength - (entryOffset + veh.getPositionOnLane());
     840       672955 :     bool onDetector = -entryOffset < veh.getPositionOnLane() && distToDetectorEnd > -veh.getVehicleType().getLength();
     841              : 
     842              : #ifdef DEBUG_E2_MAKE_VEHINFO
     843              :     if (DEBUG_COND) {
     844              :         std::cout << SIMTIME << " Making VehicleInfo for vehicle '" << veh.getID() << "'."
     845              :                   << "\ndistToDetectorEnd = " << distToDetectorEnd
     846              :                   << "\nveh.getPositionOnLane() = " << veh.getPositionOnLane()
     847              :                   << "\nentry lane offset (lane begin from detector begin) = " << entryOffset
     848              :                   << std::endl;
     849              :     }
     850              : #endif
     851       672955 :     return new VehicleInfo(veh.getID(), veh.getVehicleType().getID(), veh.getVehicleType().getLength(), veh.getVehicleType().getMinGap(), enteredLane, entryOffset, j,
     852      2018865 :                            myOffsets[j] - myDetectorLength, distToDetectorEnd, onDetector);
     853              : }
     854              : 
     855              : 
     856              : void
     857        77072 : MSE2Collector::notifyMovePerson(MSTransportable* p, int dir, double pos) {
     858        77072 :     if (personApplies(*p, dir)) {
     859        55248 :         const double newSpeed = p->getSpeed();
     860        55248 :         const double newPos = (dir == MSPModel::FORWARD
     861        55248 :                                ? pos
     862              :                                // position relative to detector end position
     863        15552 :                                : myEndPos - (pos - myEndPos));
     864        55248 :         const double oldPos = newPos - SPEED2DIST(newSpeed);
     865        55248 :         if (oldPos - p->getVehicleType().getLength() <= myEndPos) {
     866        32824 :             notifyMove(*p, oldPos, newPos, newSpeed);
     867              :         }
     868              :     }
     869        77072 : }
     870              : 
     871              : 
     872              : void
     873     15250745 : MSE2Collector::detectorUpdate(const SUMOTime /* step */) {
     874              : 
     875     15250745 :     if (myDetectPersons != (int)PersonMode::NONE) {
     876        93909 :         if (myLanes.size() > 1) {
     877              :             /// code is more complicated because we have to make persons with
     878              :             //dir=BACKWARD send a virtual forward-lane-sequence
     879           18 :             throw ProcessError(TL("Multi-lane e2Detector does not support detecting persons yet"));
     880              :         }
     881       187800 :         for (MSLane* lane : getLanes()) {
     882        93900 :             if (lane->hasPedestrians()) {
     883       117636 :                 for (MSTransportable* p : myLane->getEdge().getPersons()) {
     884       105544 :                     if (p->getLane() == lane && vehicleApplies(*p)) {
     885        77072 :                         notifyMovePerson(p, p->getDirection(), p->getPositionOnLane());
     886              :                     }
     887              :                 }
     888              :             }
     889        93900 :         }
     890              :     }
     891              : 
     892              : #ifdef DEBUG_E2_DETECTOR_UPDATE
     893              :     if (DEBUG_COND) {
     894              :         std::cout << "\n" << SIMTIME << " detectorUpdate() for detector '" << myID << "'"
     895              :                   << "\nmyCurrentMeanSpeed = " << myCurrentMeanSpeed
     896              :                   << "\nmyCurrentMeanLength = " << myCurrentMeanLength
     897              :                   << "\nmyNumberOfEnteredVehicles = " << myNumberOfEnteredVehicles
     898              :                   << "\nmyNumberOfLeftVehicles = " << myNumberOfLeftVehicles
     899              :                   << "\nmyNumberOfSeenVehicles = " << myNumberOfSeenVehicles
     900              :                   << std::endl;
     901              :     }
     902              : #endif
     903              : 
     904              : // sort myMoveNotifications (required for jam processing) ascendingly according to vehicle's distance to the detector end
     905              : // (min = myMoveNotifications[0].distToDetectorEnd)
     906     15250736 :     std::sort(myMoveNotifications.begin(), myMoveNotifications.end(), compareMoveNotification);
     907              : 
     908              :     // reset values concerning current time step (these are updated in integrateMoveNotification() and aggregateOutputValues())
     909     15250736 :     myCurrentVehicleSamples = 0;
     910     15250736 :     myCurrentMeanSpeed = 0;
     911     15250736 :     myCurrentMeanLength = 0;
     912     15250736 :     myCurrentStartedHalts = 0;
     913     15250736 :     myCurrentHaltingsNumber = 0;
     914              : 
     915     15250736 :     JamInfo* currentJam = nullptr;
     916              :     std::vector<JamInfo*> jams;
     917              :     std::map<std::string, SUMOTime> haltingVehicles;
     918              :     std::map<std::string, SUMOTime> intervalHaltingVehicles;
     919              : 
     920              :     // go through the list of vehicles positioned on the detector
     921     64266900 :     for (std::vector<MoveNotificationInfo*>::iterator i = myMoveNotifications.begin(); i != myMoveNotifications.end(); ++i) {
     922              :         // The ID of the vehicle that has sent this notification in the last step
     923     49016164 :         const std::string& vehID = (*i)->id;
     924              :         VehicleInfoMap::iterator vi = myVehicleInfos.find(vehID);
     925              : 
     926     49016164 :         if (vi == myVehicleInfos.end()) {
     927              :             // The vehicle has already left the detector by lanechange, teleport, etc. (not longitudinal)
     928         1934 :             integrateMoveNotification(nullptr, *i);
     929              :         } else {
     930              :             // Add move notification infos to detector values and VehicleInfo
     931     49014230 :             integrateMoveNotification(vi->second, *i);
     932              :         }
     933              :         // construct jam structure
     934     49016164 :         bool isInJam = checkJam(i, haltingVehicles, intervalHaltingVehicles);
     935     49016164 :         buildJam(isInJam, i, currentJam, jams);
     936              :     }
     937              : 
     938              :     // extract some aggregated values from the jam structure
     939     15250736 :     processJams(jams, currentJam);
     940              : 
     941              :     // Aggregate and normalize values for the detector output
     942     15250736 :     aggregateOutputValues();
     943              : 
     944              :     // save information about halting vehicles
     945              :     myHaltingVehicleDurations = haltingVehicles;
     946              :     myIntervalHaltingVehicleDurations = intervalHaltingVehicles;
     947              : 
     948              : #ifdef DEBUG_E2_DETECTOR_UPDATE
     949              :     if (DEBUG_COND) {
     950              :         std::cout << "\n" << SIMTIME << " Current lanes for vehicles still on or approaching the detector:" << std::endl;
     951              :     }
     952              : #endif
     953              : // update current and entered lanes for remaining vehicles
     954              :     VehicleInfoMap::iterator iv;
     955              :     for (iv = myVehicleInfos.begin(); iv != myVehicleInfos.end(); ++iv) {
     956              : #ifdef DEBUG_E2_DETECTOR_UPDATE
     957              :         if (DEBUG_COND) {
     958              :             std::cout << " Vehicle '" << iv->second->id << "'" << ": '"
     959              :                       << iv->second->currentLane->getID() << "'"
     960              :                       << std::endl;
     961              :         }
     962              : #endif
     963              :     }
     964              : 
     965              : #ifdef DEBUG_E2_DETECTOR_UPDATE
     966              :     if (DEBUG_COND) {
     967              :         std::cout << SIMTIME << " Discarding vehicles that have left the detector:" << std::endl;
     968              :     }
     969              : #endif
     970              : // Remove the vehicles that have left the detector
     971              :     std::set<std::string>::const_iterator i;
     972     15909358 :     for (i = myLeftVehicles.begin(); i != myLeftVehicles.end(); ++i) {
     973              :         VehicleInfoMap::iterator j = myVehicleInfos.find(*i);
     974       658622 :         delete j->second;
     975              :         myVehicleInfos.erase(*i);
     976       658622 :         myNumberOfLeftVehicles++;
     977              : #ifdef DEBUG_E2_DETECTOR_UPDATE
     978              :         if (DEBUG_COND) {
     979              :             std::cout << "Erased vehicle '" << *i << "'" << std::endl;
     980              :         }
     981              : #endif
     982              :     }
     983              :     myLeftVehicles.clear();
     984              : 
     985              :     // reset move notifications
     986     64266900 :     for (std::vector<MoveNotificationInfo*>::iterator j = myMoveNotifications.begin(); j != myMoveNotifications.end(); ++j) {
     987     49016164 :         delete *j;
     988              :     }
     989              :     myMoveNotifications.clear();
     990     15250736 : }
     991              : 
     992              : 
     993              : void
     994     15250736 : MSE2Collector::aggregateOutputValues() {
     995     15250736 :     myTimeSamples += 1;
     996              :     // compute occupancy values (note myCurrentMeanLength is still not normalized here, but holds the sum of all vehicle lengths)
     997     15250736 :     const double currentOccupancy = myCurrentMeanLength / myDetectorLength * (double) 100.;
     998     15250736 :     myCurrentOccupancy = currentOccupancy;
     999     15250736 :     myOccupancySum += currentOccupancy;
    1000     15250736 :     myMaxOccupancy = MAX2(myMaxOccupancy, currentOccupancy);
    1001              :     // compute jam values
    1002     15250736 :     myMeanMaxJamInVehicles += myCurrentMaxJamLengthInVehicles;
    1003     15250736 :     myMeanMaxJamInMeters += myCurrentMaxJamLengthInMeters;
    1004     15250736 :     myMaxJamInVehicles = MAX2(myMaxJamInVehicles, myCurrentMaxJamLengthInVehicles);
    1005     29034415 :     myMaxJamInMeters = MAX2(myMaxJamInMeters, myCurrentMaxJamLengthInMeters);
    1006              :     // compute information about vehicle numbers
    1007     15250736 :     const int numVehicles = (int)myMoveNotifications.size();
    1008     15250736 :     myMeanVehicleNumber += numVehicles;
    1009     15250736 :     myMaxVehicleNumber = MAX2(numVehicles, myMaxVehicleNumber);
    1010              :     // norm current values
    1011     15250736 :     myCurrentMeanSpeed = numVehicles != 0 ? myCurrentMeanSpeed / myCurrentVehicleSamples : -1;
    1012     15250736 :     myCurrentMeanLength = numVehicles != 0 ? myCurrentMeanLength / (double) numVehicles : -1;
    1013     15250736 : }
    1014              : 
    1015              : 
    1016              : 
    1017              : void
    1018     49016164 : MSE2Collector::integrateMoveNotification(VehicleInfo* vi, const MoveNotificationInfo* mni) {
    1019              : 
    1020              : #ifdef DEBUG_E2_DETECTOR_UPDATE
    1021              :     if (DEBUG_COND) {
    1022              :         std::cout << SIMTIME << " integrateMoveNotification() for vehicle '" << mni->id << "'"
    1023              :                   << "\ntimeOnDetector = " << mni->timeOnDetector
    1024              :                   << "\nlengthOnDetector = " << mni->lengthOnDetector
    1025              :                   << "\ntimeLoss = " << mni->timeLoss
    1026              :                   << "\nspeed = " << mni->speed
    1027              :                   << std::endl;
    1028              :     }
    1029              : #endif
    1030              : 
    1031              : // Accumulate detector values
    1032     49016164 :     myVehicleSamples += mni->timeOnDetector;
    1033     49016164 :     myTotalTimeLoss += mni->timeLoss;
    1034     49016164 :     mySpeedSum += mni->speed * mni->timeOnDetector;
    1035     49016164 :     myCurrentVehicleSamples += mni->timeOnDetector;
    1036     49016164 :     myCurrentMeanSpeed += mni->speed * mni->timeOnDetector;
    1037     49016164 :     myCurrentMeanLength += mni->lengthOnDetector;
    1038              : 
    1039     49016164 :     if (vi != nullptr) {
    1040              :         // Accumulate individual values for the vehicle.
    1041              :         // @note vi==0 occurs, if the vehicle info has been erased at
    1042              :         //       notifyLeave() in case of a non-longitudinal exit (lanechange, teleport, etc.)
    1043     49014230 :         vi->totalTimeOnDetector += mni->timeOnDetector;
    1044     49014230 :         vi->accumulatedTimeLoss += mni->timeLoss;
    1045     49014230 :         vi->lastAccel = mni->accel;
    1046     49014230 :         vi->lastSpeed = mni->speed;
    1047     49014230 :         vi->lastPos = myStartPos + vi->entryOffset + mni->newPos;
    1048     49014230 :         vi->onDetector = mni->onDetector;
    1049              :     }
    1050     49016164 : }
    1051              : 
    1052              : 
    1053              : 
    1054              : MSE2Collector::MoveNotificationInfo*
    1055     49016164 : MSE2Collector::makeMoveNotification(const SUMOTrafficObject& veh, double oldPos, double newPos, double newSpeed, const VehicleInfo& vehInfo) const {
    1056              : #ifdef DEBUG_E2_NOTIFY_MOVE
    1057              :     if (DEBUG_COND) {
    1058              :         std::cout << SIMTIME << " makeMoveNotification() for vehicle '" << veh.getID() << "'"
    1059              :                   << " oldPos = " << oldPos << " newPos = " << newPos << " newSpeed = " << newSpeed
    1060              :                   << std::endl;
    1061              :     }
    1062              : #endif
    1063              : 
    1064              :     // Timefraction in [0,TS] the vehicle has spend on the detector in the last step
    1065              :     double timeOnDetector;
    1066              :     // Note that at this point, vehInfo.currentLane points to the lane at the beginning of the last timestep,
    1067              :     // and vehInfo.enteredLanes is a list of lanes entered in the last timestep
    1068              :     double timeLoss;
    1069     49016164 :     calculateTimeLossAndTimeOnDetector(veh, oldPos, newPos, vehInfo, timeOnDetector, timeLoss);
    1070              : 
    1071              :     // The length of the part of the vehicle on the detector at the end of the last time step
    1072              :     // may be shorter than vehicle's length if its back reaches out
    1073     49016164 :     double lengthOnDetector = MAX2(MIN2(vehInfo.length, newPos + vehInfo.entryOffset), 0.);
    1074              : 
    1075              :     // XXX: Fulfulling the specifications of the documentation (lengthOnDetector = time integral
    1076              :     //      over length of the vehicle's part on the detector) would be much more cumbersome.
    1077     49016164 :     double distToExit = -vehInfo.exitOffset - newPos;
    1078              :     // Eventually decrease further to account for the front reaching out
    1079     49016164 :     lengthOnDetector = MAX2(0., lengthOnDetector + MIN2(0., distToExit));
    1080              : 
    1081              :     // whether the vehicle is still on the detector at the end of the time step
    1082     49016164 :     bool stillOnDetector = -distToExit < vehInfo.length;
    1083              : 
    1084              : #ifdef DEBUG_E2_NOTIFY_MOVE
    1085              :     if (DEBUG_COND) {
    1086              :         std::cout << SIMTIME << " lengthOnDetector = " << lengthOnDetector
    1087              :                   << "\nvehInfo.exitOffset = " << vehInfo.exitOffset
    1088              :                   << " vehInfo.entryOffset = " << vehInfo.entryOffset
    1089              :                   << " distToExit = " << distToExit
    1090              :                   << std::endl;
    1091              :     }
    1092              : #endif
    1093              : 
    1094              :     /* Store new infos */
    1095     49016164 :     return new MoveNotificationInfo(veh.getID(), oldPos, newPos, newSpeed, veh.getAcceleration(),
    1096     49016164 :                                     myDetectorLength - (vehInfo.entryOffset + newPos),
    1097              :                                     timeOnDetector, lengthOnDetector, timeLoss,
    1098     98032328 :                                     STEPS2TIME(veh.getWaitingTime()), stillOnDetector);
    1099              : }
    1100              : 
    1101              : void
    1102     49016164 : MSE2Collector::buildJam(bool isInJam, std::vector<MoveNotificationInfo*>::const_iterator mni, JamInfo*& currentJam, std::vector<JamInfo*>& jams) {
    1103              : #ifdef DEBUG_E2_JAMS
    1104              :     if (DEBUG_COND) {
    1105              :         std::cout << SIMTIME << " buildJam() for vehicle '" << (*mni)->id << "'" << std::endl;
    1106              :     }
    1107              : #endif
    1108     49016164 :     if (isInJam) {
    1109              :         // The vehicle is in a jam;
    1110              :         //  it may be a new one or already an existing one
    1111     34025824 :         if (currentJam == nullptr) {
    1112              : #ifdef DEBUG_E2_JAMS
    1113              :             if (DEBUG_COND) {
    1114              :                 std::cout << SIMTIME << " vehicle '" << (*mni)->id << "' forms the start of the first jam" << std::endl;
    1115              :             }
    1116              : #endif
    1117              :             // the vehicle is the first vehicle in a jam
    1118      2247152 :             currentJam = new JamInfo();
    1119      2247152 :             currentJam->firstStandingVehicle = mni;
    1120              :         } else {
    1121              :             // ok, we have a jam already. But - maybe it is too far away
    1122              :             //  ... honestly, I can hardly find a reason for doing this,
    1123              :             //  but jams were defined this way in an earlier version...
    1124     31778672 :             MoveNotificationInfo* lastVeh = *currentJam->lastStandingVehicle;
    1125     31778672 :             MoveNotificationInfo* currVeh = *mni;
    1126     31778672 :             if (lastVeh->distToDetectorEnd - currVeh->distToDetectorEnd > myJamDistanceThreshold) {
    1127              : #ifdef DEBUG_E2_JAMS
    1128              :                 if (DEBUG_COND) {
    1129              :                     std::cout << SIMTIME << " vehicle '" << (*mni)->id << "' forms the start of a new jam" << std::endl;
    1130              :                 }
    1131              : #endif
    1132              :                 // yep, yep, yep - it's a new one...
    1133              :                 //  close the frist, build a new
    1134            0 :                 jams.push_back(currentJam);
    1135            0 :                 currentJam = new JamInfo();
    1136            0 :                 currentJam->firstStandingVehicle = mni;
    1137              :             }
    1138              :         }
    1139     34025824 :         currentJam->lastStandingVehicle = mni;
    1140              :     } else {
    1141              :         // the vehicle is not part of a jam...
    1142              :         //  maybe we have to close an already computed jam
    1143     14990340 :         if (currentJam != nullptr) {
    1144              : #ifdef DEBUG_E2_JAMS
    1145              :             if (DEBUG_COND) {
    1146              :                 std::cout << SIMTIME << " Closing current jam." << std::endl;
    1147              :             }
    1148              : #endif
    1149      1019046 :             jams.push_back(currentJam);
    1150      1019046 :             currentJam = nullptr;
    1151              :         }
    1152              :     }
    1153     49016164 : }
    1154              : 
    1155              : 
    1156              : bool
    1157     49016164 : MSE2Collector::checkJam(std::vector<MoveNotificationInfo*>::const_iterator mni, std::map<std::string, SUMOTime>& haltingVehicles, std::map<std::string, SUMOTime>& intervalHaltingVehicles) {
    1158              : #ifdef DEBUG_E2_JAMS
    1159              :     if (DEBUG_COND) {
    1160              :         std::cout << SIMTIME << " CheckJam() for vehicle '" << (*mni)->id << "'" << std::endl;
    1161              :     }
    1162              : #endif
    1163              :     // jam-checking begins
    1164              :     bool isInJam = false;
    1165              :     // first, check whether the vehicle is slow enough to be counted as halting
    1166     49016164 :     if ((*mni)->speed < myJamHaltingSpeedThreshold) {
    1167     34774056 :         myCurrentHaltingsNumber++;
    1168              :         // we have to track the time it was halting;
    1169              :         // so let's look up whether it was halting before and compute the overall halting time
    1170     34774056 :         bool wasHalting = myHaltingVehicleDurations.count((*mni)->id) > 0;
    1171              :         if (wasHalting) {
    1172     33958911 :             haltingVehicles[(*mni)->id] = myHaltingVehicleDurations[(*mni)->id] + DELTA_T;
    1173     33958911 :             intervalHaltingVehicles[(*mni)->id] = myIntervalHaltingVehicleDurations[(*mni)->id] + DELTA_T;
    1174              :         } else {
    1175              : #ifdef DEBUG_E2_JAMS
    1176              :             if (DEBUG_COND) {
    1177              :                 std::cout << SIMTIME << " vehicle '" << (*mni)->id << "' starts halting." << std::endl;
    1178              :             }
    1179              : #endif
    1180       815145 :             haltingVehicles[(*mni)->id] = DELTA_T;
    1181       815145 :             intervalHaltingVehicles[(*mni)->id] = DELTA_T;
    1182       815145 :             myCurrentStartedHalts++;
    1183       815145 :             myStartedHalts++;
    1184              :         }
    1185              :         // we now check whether the halting time is large enough
    1186     34774056 :         if (haltingVehicles[(*mni)->id] > myJamHaltingTimeThreshold) {
    1187              :             // yep --> the vehicle is a part of a jam
    1188              :             isInJam = true;
    1189              :         }
    1190              :     } else {
    1191              :         // is not standing anymore; keep duration information
    1192     14242108 :         std::map<std::string, SUMOTime>::iterator v = myHaltingVehicleDurations.find((*mni)->id);
    1193     14242108 :         if (v != myHaltingVehicleDurations.end()) {
    1194       810438 :             myPastStandingDurations.push_back(v->second);
    1195              :             myHaltingVehicleDurations.erase(v);
    1196              :         }
    1197     14242108 :         v = myIntervalHaltingVehicleDurations.find((*mni)->id);
    1198     14242108 :         if (v != myIntervalHaltingVehicleDurations.end()) {
    1199       810438 :             myPastIntervalStandingDurations.push_back((*v).second);
    1200              :             myIntervalHaltingVehicleDurations.erase(v);
    1201              :         }
    1202              :     }
    1203              : #ifdef DEBUG_E2_JAMS
    1204              :     if (DEBUG_COND) {
    1205              :         std::cout << SIMTIME << " vehicle '" << (*mni)->id << "'" << (isInJam ? "is jammed." : "is not jammed.") << std::endl;
    1206              :     }
    1207              : #endif
    1208     49016164 :     return isInJam;
    1209              : }
    1210              : 
    1211              : 
    1212              : void
    1213     15250736 : MSE2Collector::processJams(std::vector<JamInfo*>& jams, JamInfo* currentJam) {
    1214              :     // push last jam
    1215     15250736 :     if (currentJam != nullptr) {
    1216      1228106 :         jams.push_back(currentJam);
    1217      1228106 :         currentJam = nullptr;
    1218              :     }
    1219              : 
    1220              : #ifdef DEBUG_E2_JAMS
    1221              :     if (DEBUG_COND) {
    1222              :         std::cout << "\n" << SIMTIME << " processJams()"
    1223              :                   << "\nNumber of jams: " << jams.size() << std::endl;
    1224              :     }
    1225              : #endif
    1226              : 
    1227              :     // process jam information
    1228     15250736 :     myCurrentMaxJamLengthInMeters = 0;
    1229     15250736 :     myCurrentMaxJamLengthInVehicles = 0;
    1230     15250736 :     myCurrentJamLengthInMeters = 0;
    1231     15250736 :     myCurrentJamLengthInVehicles = 0;
    1232     15250736 :     myCurrentJamDuration = 0;
    1233     17497888 :     for (std::vector<JamInfo*>::const_iterator i = jams.begin(); i != jams.end(); ++i) {
    1234              :         // compute current jam's values
    1235      2247152 :         MoveNotificationInfo* lastVeh = *((*i)->lastStandingVehicle);
    1236      2247152 :         MoveNotificationInfo* firstVeh = *((*i)->firstStandingVehicle);
    1237      2247152 :         const double jamLengthInMeters = MAX2(lastVeh->distToDetectorEnd, 0.) -
    1238      2247152 :                                          MAX2(firstVeh->distToDetectorEnd, 0.) +
    1239      2247152 :                                          lastVeh->lengthOnDetector;
    1240      2247152 :         const int jamLengthInVehicles = (int) distance((*i)->firstStandingVehicle, (*i)->lastStandingVehicle) + 1;
    1241              :         // apply them to the statistics
    1242      2247152 :         myCurrentMaxJamLengthInMeters = MAX2(myCurrentMaxJamLengthInMeters, jamLengthInMeters);
    1243      2247152 :         myCurrentMaxJamLengthInVehicles = MAX2(myCurrentMaxJamLengthInVehicles, jamLengthInVehicles);
    1244      2247152 :         myJamLengthInMetersSum += jamLengthInMeters;
    1245      2247152 :         myJamLengthInVehiclesSum += jamLengthInVehicles;
    1246      2247152 :         myCurrentJamLengthInMeters += jamLengthInMeters;
    1247      2247152 :         myCurrentJamLengthInVehicles += jamLengthInVehicles;
    1248      4487634 :         myCurrentJamDuration = MAX2(myCurrentJamDuration, firstVeh->waitingTime);
    1249              : #ifdef DEBUG_E2_JAMS
    1250              :         if (DEBUG_COND) {
    1251              :             std::cout << SIMTIME << " processing jam nr." << ((int) distance((std::vector<JamInfo*>::const_iterator) jams.begin(), i) + 1)
    1252              :                       << "\njamLengthInMeters = " << jamLengthInMeters
    1253              :                       << " jamLengthInVehicles = " << jamLengthInVehicles
    1254              :                       << std::endl;
    1255              :         }
    1256              : #endif
    1257              :     }
    1258     15250736 :     myCurrentJamNo = (int) jams.size();
    1259              : 
    1260              :     // clean up jam structure
    1261     17497888 :     for (std::vector<JamInfo*>::iterator i = jams.begin(); i != jams.end(); ++i) {
    1262      2247152 :         delete *i;
    1263              :     }
    1264     15250736 : }
    1265              : 
    1266              : void
    1267     49016164 : MSE2Collector::calculateTimeLossAndTimeOnDetector(const SUMOTrafficObject& veh, double oldPos, double newPos, const VehicleInfo& vi, double& timeOnDetector, double& timeLoss) const {
    1268              :     assert(veh.getID() == vi.id);
    1269              :     assert(newPos + vi.entryOffset >= 0);
    1270              : 
    1271     49016164 :     if (oldPos == newPos) {
    1272              :         // vehicle is stopped
    1273     34298613 :         timeLoss = TS;
    1274     34298613 :         timeOnDetector = TS;
    1275     34298613 :         return;
    1276              :     }
    1277              : 
    1278              :     // Eventual positional offset of the detector start from the lane's start
    1279     14717551 :     double entryPos = MAX2(-vi.entryOffset, 0.);
    1280              :     // Time of this vehicle entering the detector in the last time step
    1281              :     double entryTime = 0;
    1282              :     // Take into account the time before entering the detector, if there is.
    1283     14717551 :     if (oldPos < entryPos) {
    1284              :         // Vehicle entered the detector in the last step, either traversing the detector start or somewhere in the middle.
    1285       660113 :         entryTime = MSCFModel::passingTime(oldPos, entryPos, newPos, veh.getPreviousSpeed(), veh.getSpeed());
    1286              :     }
    1287              :     // speed at detector entry
    1288     14717551 :     double entrySpeed = MSCFModel::speedAfterTime(entryTime, veh.getPreviousSpeed(), newPos - oldPos);
    1289              :     // Calculate time spent on detector until reaching newPos or a detector exit
    1290     14717551 :     double exitPos = MIN2(newPos, -vi.exitOffset + vi.length);
    1291              :     assert(entryPos < exitPos);
    1292              : 
    1293              :     // calculate vehicle's time spent on the detector
    1294              :     double exitTime;
    1295     14717551 :     if (exitPos == newPos) {
    1296     14059061 :         exitTime  = TS;
    1297              :     } else {
    1298       658490 :         exitTime = MSCFModel::passingTime(oldPos, exitPos, newPos, veh.getPreviousSpeed(), veh.getSpeed());
    1299              :     }
    1300              : 
    1301              :     // Vehicle's Speed when leaving the detector
    1302     14717551 :     double exitSpeed = MSCFModel::speedAfterTime(exitTime, veh.getPreviousSpeed(), newPos - oldPos);
    1303              : 
    1304              :     // Maximal speed on vehicle's current lane (== lane before last time step)
    1305              :     // Note: this disregards the possibility of different maximal speeds on different traversed lanes.
    1306              :     //       (we accept this as discretization error)
    1307     14717551 :     double vmax = MAX2(veh.getLane()->getVehicleMaxSpeed(&veh), NUMERICAL_EPS);
    1308              : 
    1309              :     // Time loss suffered on the detector
    1310     14717551 :     timeOnDetector = exitTime - entryTime;
    1311     29405294 :     timeLoss = MAX2(0., timeOnDetector * (vmax - (entrySpeed + exitSpeed) / 2) / vmax);
    1312              : 
    1313              : #ifdef DEBUG_E2_TIME_ON_DETECTOR
    1314              :     if (DEBUG_COND) {
    1315              :         std::cout << SIMTIME << " calculateTimeLoss() for vehicle '" << veh.getID() << "'"
    1316              :                   << " oldPos = " << oldPos << " newPos = " << newPos
    1317              :                   << " entryPos = " << entryPos << " exitPos = " << exitPos
    1318              :                   << " timeOnDetector = " << timeOnDetector
    1319              :                   << " timeLoss = " << timeLoss
    1320              :                   << std::endl;
    1321              :     }
    1322              : #endif
    1323              : }
    1324              : 
    1325              : 
    1326              : void
    1327         5176 : MSE2Collector::writeXMLDetectorProlog(OutputDevice& dev) const {
    1328        10352 :     dev.writeXMLHeader("detector", "det_e2_file.xsd");
    1329         5176 : }
    1330              : 
    1331              : void
    1332       320475 : MSE2Collector::writeXMLOutput(OutputDevice& dev, SUMOTime startTime, SUMOTime stopTime) {
    1333       320475 :     const double meanSpeed = getIntervalMeanSpeed();
    1334       320475 :     const double meanOccupancy = getIntervalOccupancy();
    1335       320475 :     const double meanTimeLoss = getIntervalMeanTimeLoss();
    1336       320475 :     myPreviousMeanOccupancy = meanOccupancy;
    1337       320475 :     myPreviousMeanSpeed = meanSpeed;
    1338       320475 :     myPreviousMaxJamLengthInMeters = myMaxJamInMeters;
    1339       320475 :     myPreviousNumberOfSeenVehicles = myNumberOfSeenVehicles;
    1340       320475 :     myPreviousMeanTimeLoss = meanTimeLoss;
    1341              : 
    1342       320475 :     if (dev.isNull()) {
    1343        28099 :         reset();
    1344        28099 :         return;
    1345              :     }
    1346       292376 :     const double meanJamLengthInMeters = myTimeSamples != 0 ? myMeanMaxJamInMeters / (double) myTimeSamples : 0;
    1347       292376 :     const double meanJamLengthInVehicles = myTimeSamples != 0 ? myMeanMaxJamInVehicles / (double) myTimeSamples : 0;
    1348       292376 :     const double meanVehicleNumber = myTimeSamples != 0 ? (double) myMeanVehicleNumber / (double) myTimeSamples : 0;
    1349              : 
    1350              :     SUMOTime haltingDurationSum = 0;
    1351              :     SUMOTime maxHaltingDuration = 0;
    1352              :     int haltingNo = 0;
    1353       950238 :     for (std::vector<SUMOTime>::iterator i = myPastStandingDurations.begin(); i != myPastStandingDurations.end(); ++i) {
    1354       657862 :         haltingDurationSum += (*i);
    1355              :         maxHaltingDuration = MAX2(maxHaltingDuration, (*i));
    1356       657862 :         haltingNo++;
    1357              :     }
    1358      5210625 :     for (std::map<std::string, SUMOTime> ::iterator i = myHaltingVehicleDurations.begin(); i != myHaltingVehicleDurations.end(); ++i) {
    1359      4918249 :         haltingDurationSum += (*i).second;
    1360              :         maxHaltingDuration = MAX2(maxHaltingDuration, (*i).second);
    1361      4918249 :         haltingNo++;
    1362              :     }
    1363       292376 :     const SUMOTime meanHaltingDuration = haltingNo != 0 ? haltingDurationSum / haltingNo : 0;
    1364              : 
    1365              :     SUMOTime intervalHaltingDurationSum = 0;
    1366              :     SUMOTime intervalMaxHaltingDuration = 0;
    1367              :     int intervalHaltingNo = 0;
    1368       950238 :     for (std::vector<SUMOTime>::iterator i = myPastIntervalStandingDurations.begin(); i != myPastIntervalStandingDurations.end(); ++i) {
    1369       657862 :         intervalHaltingDurationSum += (*i);
    1370              :         intervalMaxHaltingDuration = MAX2(intervalMaxHaltingDuration, (*i));
    1371       657862 :         intervalHaltingNo++;
    1372              :     }
    1373      5210625 :     for (std::map<std::string, SUMOTime> ::iterator i = myIntervalHaltingVehicleDurations.begin(); i != myIntervalHaltingVehicleDurations.end(); ++i) {
    1374      4918249 :         intervalHaltingDurationSum += (*i).second;
    1375              :         intervalMaxHaltingDuration = MAX2(intervalMaxHaltingDuration, (*i).second);
    1376      4918249 :         intervalHaltingNo++;
    1377              :     }
    1378       292376 :     const SUMOTime intervalMeanHaltingDuration = intervalHaltingNo != 0 ? intervalHaltingDurationSum / intervalHaltingNo : 0;
    1379              : 
    1380              : #ifdef DEBUG_E2_XML_OUT
    1381              :     if (DEBUG_COND) {
    1382              :         std::stringstream ss;
    1383              :         ss  << "sampledSeconds=\"" << myVehicleSamples << "\" "
    1384              :             << "myTimeSamples=\"" << myTimeSamples << "\" "
    1385              :             << "myOccupancySum=\"" << myOccupancySum << "\" "
    1386              :             << "myMeanVehicleNumber=\"" << myMeanVehicleNumber << "\" "
    1387              :             << "nVehEntered=\"" << myNumberOfEnteredVehicles << "\" "
    1388              :             << "meanSpeed=\"" << meanSpeed << "\"";
    1389              :         std::cout << ss.str() << std::endl;
    1390              :     }
    1391              : #endif
    1392              : 
    1393       584752 :     dev.openTag(SUMO_TAG_INTERVAL).writeTime(SUMO_ATTR_BEGIN, startTime).writeTime(SUMO_ATTR_END, stopTime);
    1394       292376 :     dev.writeAttr(SUMO_ATTR_ID, StringUtils::escapeXML(getID()));
    1395       292376 :     dev.writeAttr("sampledSeconds", myVehicleSamples)
    1396       292376 :     .writeAttr("nVehEntered", myNumberOfEnteredVehicles)
    1397       292376 :     .writeAttr("nVehLeft", myNumberOfLeftVehicles)
    1398       292376 :     .writeAttr("nVehSeen", myNumberOfSeenVehicles)
    1399       292376 :     .writeAttr("meanSpeed", meanSpeed)
    1400       292376 :     .writeAttr("meanTimeLoss", meanTimeLoss)
    1401       292376 :     .writeAttr("meanOccupancy", meanOccupancy)
    1402       292376 :     .writeAttr("maxOccupancy", myMaxOccupancy)
    1403       292376 :     .writeAttr("meanMaxJamLengthInVehicles", meanJamLengthInVehicles)
    1404       292376 :     .writeAttr("meanMaxJamLengthInMeters", meanJamLengthInMeters)
    1405       292376 :     .writeAttr("maxJamLengthInVehicles", myMaxJamInVehicles)
    1406       292376 :     .writeAttr("maxJamLengthInMeters", myMaxJamInMeters)
    1407       292376 :     .writeAttr("jamLengthInVehiclesSum", myJamLengthInVehiclesSum)
    1408       292376 :     .writeAttr("jamLengthInMetersSum", myJamLengthInMetersSum)
    1409       292376 :     .writeAttr("meanHaltingDuration", STEPS2TIME(meanHaltingDuration))
    1410       292376 :     .writeAttr("maxHaltingDuration", STEPS2TIME(maxHaltingDuration))
    1411       292376 :     .writeAttr("haltingDurationSum", STEPS2TIME(haltingDurationSum))
    1412       292376 :     .writeAttr("meanIntervalHaltingDuration", STEPS2TIME(intervalMeanHaltingDuration))
    1413       292376 :     .writeAttr("maxIntervalHaltingDuration", STEPS2TIME(intervalMaxHaltingDuration))
    1414       292376 :     .writeAttr("intervalHaltingDurationSum", STEPS2TIME(intervalHaltingDurationSum))
    1415       292376 :     .writeAttr("startedHalts", myStartedHalts)
    1416       292376 :     .writeAttr("meanVehicleNumber", meanVehicleNumber)
    1417       292376 :     .writeAttr("maxVehicleNumber", myMaxVehicleNumber)
    1418       292376 :     .closeTag();
    1419              : 
    1420       292376 :     reset();
    1421              : }
    1422              : 
    1423              : void
    1424       320531 : MSE2Collector::reset() {
    1425       320531 :     myVehicleSamples = 0;
    1426       320531 :     myTotalTimeLoss = 0.;
    1427       320531 :     myNumberOfEnteredVehicles = 0;
    1428       320531 :     myNumberOfSeenVehicles -= myNumberOfLeftVehicles;
    1429       320531 :     myNumberOfLeftVehicles = 0;
    1430       320531 :     myMaxVehicleNumber = 0;
    1431              : 
    1432       320531 :     mySpeedSum = 0;
    1433       320531 :     myStartedHalts = 0;
    1434       320531 :     myJamLengthInMetersSum = 0;
    1435       320531 :     myJamLengthInVehiclesSum = 0;
    1436       320531 :     myOccupancySum = 0;
    1437       320531 :     myMaxOccupancy = 0;
    1438       320531 :     myMeanMaxJamInVehicles = 0;
    1439       320531 :     myMeanMaxJamInMeters = 0;
    1440       320531 :     myMaxJamInVehicles = 0;
    1441       320531 :     myMaxJamInMeters = 0;
    1442       320531 :     myTimeSamples = 0;
    1443       320531 :     myMeanVehicleNumber = 0;
    1444      5242961 :     for (std::map<std::string, SUMOTime>::iterator i = myIntervalHaltingVehicleDurations.begin(); i != myIntervalHaltingVehicleDurations.end(); ++i) {
    1445      4922430 :         (*i).second = 0;
    1446              :     }
    1447              :     myPastStandingDurations.clear();
    1448              :     myPastIntervalStandingDurations.clear();
    1449       320531 : }
    1450              : 
    1451              : 
    1452              : int
    1453      2946699 : MSE2Collector::getCurrentVehicleNumber() const {
    1454              :     int result = 0;
    1455      2946699 :     if (myOverrideVehNumber >= 0) {
    1456              :         result = myOverrideVehNumber;
    1457              :     } else {
    1458     19933112 :         for (VehicleInfoMap::const_iterator it = myVehicleInfos.begin(); it != myVehicleInfos.end(); it++) {
    1459     16986473 :             if (it->second->onDetector) {
    1460      2778863 :                 result++;
    1461              :             }
    1462              :         }
    1463              :     }
    1464      2946699 :     return result;
    1465              : }
    1466              : 
    1467              : void
    1468           25 : MSE2Collector::overrideVehicleNumber(int num) {
    1469           25 :     myOverrideVehNumber = num;
    1470           25 : }
    1471              : 
    1472              : 
    1473              : 
    1474              : std::vector<std::string>
    1475          588 : MSE2Collector::getCurrentVehicleIDs() const {
    1476              :     std::vector<std::string> ret;
    1477          908 :     for (VehicleInfoMap::const_iterator i = myVehicleInfos.begin(); i != myVehicleInfos.end(); ++i) {
    1478          320 :         if (i->second->onDetector) {
    1479          184 :             ret.push_back(i->second->id);
    1480              :         }
    1481              :     }
    1482          588 :     std::sort(ret.begin(), ret.end());
    1483          588 :     return ret;
    1484            0 : }
    1485              : 
    1486              : 
    1487              : std::vector<MSE2Collector::VehicleInfo*>
    1488      4689640 : MSE2Collector::getCurrentVehicles() const {
    1489              :     std::vector<VehicleInfo*> res;
    1490              :     VehicleInfoMap::const_iterator i;
    1491     10038828 :     for (i = myVehicleInfos.begin(); i != myVehicleInfos.end(); ++i) {
    1492      5349188 :         if (i->second->onDetector) {
    1493      3618788 :             res.push_back(i->second);
    1494              :         }
    1495              :     }
    1496      4689640 :     return res;
    1497            0 : }
    1498              : 
    1499              : 
    1500              : 
    1501              : int
    1502            0 : MSE2Collector::getEstimatedCurrentVehicleNumber(double speedThreshold) const {
    1503              : 
    1504              :     //    double distance = std::numeric_limits<double>::max();
    1505            0 :     double thresholdSpeed = myLane->getSpeedLimit() / speedThreshold;
    1506              : 
    1507              :     int count = 0;
    1508            0 :     for (VehicleInfoMap::const_iterator it = myVehicleInfos.begin();
    1509            0 :             it != myVehicleInfos.end(); it++) {
    1510            0 :         if (it->second->onDetector) {
    1511              :             //            if (it->position < distance) {
    1512              :             //                distance = it->position;
    1513              :             //            }
    1514              :             //            const double realDistance = myLane->getLength() - distance; // the closer vehicle get to the light the greater is the distance
    1515            0 :             const double realDistance = it->second->distToDetectorEnd;
    1516            0 :             if (it->second->lastSpeed <= thresholdSpeed || it->second->lastAccel > 0) { //TODO speed less half of the maximum speed for the lane NEED TUNING
    1517            0 :                 count = (int)(realDistance / (it->second->length + it->second->minGap)) + 1;
    1518              :             }
    1519              :         }
    1520              :     }
    1521              : 
    1522            0 :     return count;
    1523              : }
    1524              : 
    1525              : double
    1526            0 : MSE2Collector::getEstimateQueueLength() const {
    1527              : 
    1528            0 :     if (myVehicleInfos.empty()) {
    1529              :         return 0;
    1530              :     }
    1531              : 
    1532              :     double distance = 0;
    1533              :     double realDistance = 0;
    1534              :     bool flowing =  true;
    1535            0 :     for (VehicleInfoMap::const_iterator it = myVehicleInfos.begin();
    1536            0 :             it != myVehicleInfos.end(); it++) {
    1537            0 :         if (it->second->onDetector && it->second->totalTimeOnDetector > 0) {
    1538              :             //  double distanceTemp = myLane->getLength() - distance;
    1539            0 :             if (it->second->lastSpeed <= myJamHaltingSpeedThreshold) {
    1540            0 :                 distance = MAX2(it->second->distToDetectorEnd, distance);
    1541            0 :                 realDistance = distance + it->second->length;
    1542              :                 flowing = false;
    1543              :             }
    1544              :             //            DBG(
    1545              :             //                std::ostringstream str;
    1546              :             //                str << time2string(MSNet::getInstance()->getCurrentTimeStep())
    1547              :             //                << " MSE2Collector::getEstimateQueueLength::"
    1548              :             //                << " lane " << myLane->getID()
    1549              :             //                << " vehicle " << it->second.id
    1550              :             //                << " positionOnLane " << it->second.position
    1551              :             //                << " vel " << it->second.speed
    1552              :             //                << " realDistance " << realDistance;
    1553              :             //                WRITE_MESSAGE(str.str());
    1554              :             //            )
    1555              :         }
    1556              :     }
    1557            0 :     if (flowing) {
    1558              :         return 0;
    1559              :     } else {
    1560              :         return realDistance;
    1561              :     }
    1562              : }
    1563              : 
    1564              : 
    1565              : void
    1566         6733 : MSE2Collector::clearState(SUMOTime /* step */) {
    1567         6733 :     for (std::vector<MoveNotificationInfo*>::iterator j = myMoveNotifications.begin(); j != myMoveNotifications.end(); ++j) {
    1568            0 :         delete *j;
    1569              :     }
    1570              :     myMoveNotifications.clear();
    1571              : 
    1572              :     // clear vehicle infos
    1573        11232 :     for (VehicleInfoMap::iterator j = myVehicleInfos.begin(); j != myVehicleInfos.end(); ++j) {
    1574         4499 :         delete j->second;
    1575              :     }
    1576              :     myVehicleInfos.clear();
    1577         6733 : }
    1578              : 
    1579              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1