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

Generated by: LCOV version 2.0-1