1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file    MSMeanData.cpp
11 /// @author  Daniel Krajzewicz
12 /// @author  Jakob Erdmann
13 /// @author  Michael Behrisch
14 /// @author  Laura Bieker
15 /// @author  Leonhard Luecken
16 /// @date    Mon, 10.05.2004
17 /// @version $Id$
18 ///
19 // Data collector for edges/lanes
20 /****************************************************************************/
21 
22 
23 // ===========================================================================
24 // included modules
25 // ===========================================================================
26 #include <config.h>
27 
28 #include <limits>
29 #include <microsim/MSEdgeControl.h>
30 #include <microsim/MSEdge.h>
31 #include <microsim/MSLane.h>
32 #include <microsim/MSVehicle.h>
33 #include <microsim/cfmodels/MSCFModel.h>
34 #include <microsim/MSNet.h>
35 #include <utils/common/SUMOTime.h>
36 #include <utils/common/ToString.h>
37 #include <utils/iodevices/OutputDevice.h>
38 #include "MSMeanData_Amitran.h"
39 #include "MSMeanData.h"
40 
41 #include <microsim/MSGlobals.h>
42 #include <mesosim/MESegment.h>
43 #include <mesosim/MELoop.h>
44 
45 
46 // ===========================================================================
47 // debug constants
48 // ===========================================================================
49 //#define DEBUG_NOTIFY_MOVE
50 //#define DEBUG_NOTIFY_ENTER
51 
52 // ===========================================================================
53 // method definitions
54 // ===========================================================================
55 // ---------------------------------------------------------------------------
56 // MSMeanData::MeanDataValues - methods
57 // ---------------------------------------------------------------------------
MeanDataValues(MSLane * const lane,const double length,const bool doAdd,const MSMeanData * const parent)58 MSMeanData::MeanDataValues::MeanDataValues(
59     MSLane* const lane, const double length, const bool doAdd,
60     const MSMeanData* const parent) :
61     MSMoveReminder("meandata_" + (lane == nullptr ? "NULL" :  lane->getID()), lane, doAdd),
62     myParent(parent),
63     myLaneLength(length),
64     sampleSeconds(0),
65     travelledDistance(0) {}
66 
67 
~MeanDataValues()68 MSMeanData::MeanDataValues::~MeanDataValues() {
69 }
70 
71 
72 bool
notifyEnter(SUMOTrafficObject & veh,MSMoveReminder::Notification reason,const MSLane * enteredLane)73 MSMeanData::MeanDataValues::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
74 #ifdef DEBUG_NOTIFY_ENTER
75     std::cout << "\n" << SIMTIME << " MSMeanData_Net::MSLaneMeanDataValues: veh '" << veh.getID() << "' enters lane '" << enteredLane->getID() << "'" << std::endl;
76 #else
77     UNUSED_PARAMETER(enteredLane);
78 #endif
79     UNUSED_PARAMETER(reason);
80     return myParent == nullptr || myParent->vehicleApplies(veh);
81 }
82 
83 
84 bool
notifyMove(SUMOTrafficObject & veh,double oldPos,double newPos,double newSpeed)85 MSMeanData::MeanDataValues::notifyMove(SUMOTrafficObject& veh, double oldPos, double newPos, double newSpeed) {
86     // if the vehicle has arrived, the reminder must be kept so it can be
87     // notified of the arrival subsequently
88     const double oldSpeed = veh.getPreviousSpeed();
89     double enterSpeed = MSGlobals::gSemiImplicitEulerUpdate ? newSpeed : oldSpeed; // NOTE: For the euler update, the vehicle is assumed to travel at constant speed for the whole time step
90     double leaveSpeed = newSpeed, leaveSpeedFront = newSpeed;
91 
92     // These values will be further decreased below
93     double timeOnLane = TS;
94     double frontOnLane = oldPos > myLaneLength ? 0. : TS;
95     bool ret = true;
96 
97     // entry and exit times (will be modified below)
98     double timeBeforeEnter = 0.;
99     double timeBeforeEnterBack = 0.;
100     double timeBeforeLeaveFront = newPos < myLaneLength ? TS : 0.;
101     double timeBeforeLeave = TS;
102 
103     // Treat the case that the vehicle entered the lane in the last step
104     if (oldPos < 0 && newPos >= 0) {
105         // Vehicle was not on this lane in the last time step
106         timeBeforeEnter = MSCFModel::passingTime(oldPos, 0, newPos, oldSpeed, newSpeed);
107         timeOnLane = TS - timeBeforeEnter;
108         frontOnLane = timeOnLane;
109         enterSpeed = MSCFModel::speedAfterTime(timeBeforeEnter, oldSpeed, newPos - oldPos);
110     }
111 
112     const double oldBackPos = oldPos - veh.getVehicleType().getLength();
113     const double newBackPos = newPos - veh.getVehicleType().getLength();
114 
115     // Determine the time before the vehicle back enters
116     if (oldBackPos < 0. && newBackPos > 0.) {
117         timeBeforeEnterBack = MSCFModel::passingTime(oldBackPos, 0., newBackPos, oldSpeed, newSpeed);
118     } else if (newBackPos <= 0) {
119         timeBeforeEnterBack = TS;
120     } else {
121         timeBeforeEnterBack = 0.;
122     }
123 
124     // Treat the case that the vehicle's back left the lane in the last step
125     if (newBackPos > myLaneLength // vehicle's back has left the lane
126             && oldBackPos <= myLaneLength) { // and hasn't left the lane before
127         assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the lane boundary otherwise
128         // (Leo) vehicle left this lane (it can also have skipped over it in one time step -> therefore we use "timeOnLane -= ..." and ( ... - timeOnLane) below)
129         timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myLaneLength, newBackPos, oldSpeed, newSpeed);
130         const double timeAfterLeave = TS - timeBeforeLeave;
131         timeOnLane -= timeAfterLeave;
132         leaveSpeed = MSCFModel::speedAfterTime(timeBeforeLeave, oldSpeed, newPos - oldPos);
133         // XXX: Do we really need this? Why would this "reduce rounding errors"? (Leo) Refs. #2579
134         if (fabs(timeOnLane) < NUMERICAL_EPS) { // reduce rounding errors
135             timeOnLane = 0.;
136         }
137         ret = veh.hasArrived();
138     }
139 
140     // Treat the case that the vehicle's front left the lane in the last step
141     if (newPos > myLaneLength && oldPos <= myLaneLength) {
142         // vehicle's front has left the lane and has not left before
143         assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0);
144         timeBeforeLeaveFront = MSCFModel::passingTime(oldPos, myLaneLength, newPos, oldSpeed, newSpeed);
145         const double timeAfterLeave = TS - timeBeforeLeaveFront;
146         frontOnLane -= timeAfterLeave;
147         // XXX: Do we really need this? Why would this "reduce rounding errors"? (Leo) Refs. #2579
148         if (fabs(frontOnLane) < NUMERICAL_EPS) { // reduce rounding errors
149             frontOnLane = 0.;
150         }
151         leaveSpeedFront = MSCFModel::speedAfterTime(timeBeforeLeaveFront, oldSpeed, newPos - oldPos);
152     }
153 
154     assert(frontOnLane <= TS);
155     assert(timeOnLane <= TS);
156 
157     if (timeOnLane < 0) {
158         WRITE_ERROR("Negative vehicle step fraction for '" + veh.getID() + "' on lane '" + getLane()->getID() + "'.");
159         return veh.hasArrived();
160     }
161     if (timeOnLane == 0) {
162         return veh.hasArrived();
163     }
164 
165 #ifdef DEBUG_NOTIFY_MOVE
166     std::stringstream ss;
167     ss << "\n"
168        << "lane length: " << myLaneLength
169        << "\noldPos: " << oldPos
170        << "\nnewPos: " << newPos
171        << "\noldPosBack: " << oldBackPos
172        << "\nnewPosBack: " << newBackPos
173        << "\ntimeBeforeEnter: " << timeBeforeEnter
174        << "\ntimeBeforeEnterBack: " << timeBeforeEnterBack
175        << "\ntimeBeforeLeaveFront: " << timeBeforeLeaveFront
176        << "\ntimeBeforeLeave: " << timeBeforeLeave;
177     if (!(timeBeforeLeave >= MAX2(timeBeforeEnterBack, timeBeforeLeaveFront))
178             || !(timeBeforeEnter <= MIN2(timeBeforeEnterBack, timeBeforeLeaveFront))) {
179         WRITE_ERROR(ss.str());
180     } else {
181         std::cout << ss.str() << std::endl;
182     }
183 
184 #endif
185 
186     assert(timeBeforeEnter <= MIN2(timeBeforeEnterBack, timeBeforeLeaveFront));
187     assert(timeBeforeLeave >= MAX2(timeBeforeEnterBack, timeBeforeLeaveFront));
188     // compute average vehicle length on lane in last step
189     double vehLength = veh.getVehicleType().getLength();
190     // occupied lane length at timeBeforeEnter (resp. stepStart if already on lane)
191     double lengthOnLaneAtStepStart = MAX2(0., MIN4(myLaneLength, vehLength, vehLength - (oldPos - myLaneLength), oldPos));
192     // occupied lane length at timeBeforeLeave (resp. stepEnd if still on lane)
193     double lengthOnLaneAtStepEnd = MAX2(0., MIN4(myLaneLength, vehLength, vehLength - (newPos - myLaneLength), newPos));
194     double integratedLengthOnLane = 0.;
195     if (timeBeforeEnterBack < timeBeforeLeaveFront) {
196         // => timeBeforeLeaveFront>0, myLaneLength>vehLength
197         // vehicle length on detector at timeBeforeEnterBack
198         double lengthOnLaneAtBackEnter = MIN2(veh.getVehicleType().getLength(), newPos);
199         // linear quadrature of occupancy between timeBeforeEnter and timeBeforeEnterBack
200         integratedLengthOnLane += (timeBeforeEnterBack - timeBeforeEnter) * (lengthOnLaneAtBackEnter + lengthOnLaneAtStepStart) * 0.5;
201         // linear quadrature of occupancy between timeBeforeEnterBack and timeBeforeLeaveFront
202         // (vehicle is completely on the edge in between)
203         integratedLengthOnLane += (timeBeforeLeaveFront - timeBeforeEnterBack) * vehLength;
204         // and until vehicle leaves/stepEnd
205         integratedLengthOnLane += (timeBeforeLeave - timeBeforeLeaveFront) * (vehLength + lengthOnLaneAtStepEnd) * 0.5;
206     } else if (timeBeforeEnterBack >= timeBeforeLeaveFront) {
207         // => myLaneLength <= vehLength or (timeBeforeLeaveFront == timeBeforeEnterBack == 0)
208         // vehicle length on detector at timeBeforeLeaveFront
209         double lengthOnLaneAtLeaveFront;
210         if (timeBeforeLeaveFront == timeBeforeEnter) {
211             // for the case that front already left
212             lengthOnLaneAtLeaveFront = lengthOnLaneAtStepStart;
213         } else if (timeBeforeLeaveFront == timeBeforeLeave) {
214             // for the case that front doesn't leave in this step
215             lengthOnLaneAtLeaveFront = lengthOnLaneAtStepEnd;
216         } else {
217             lengthOnLaneAtLeaveFront = myLaneLength;
218         }
219 #ifdef DEBUG_NOTIFY_MOVE
220         std::cout << "lengthOnLaneAtLeaveFront=" << lengthOnLaneAtLeaveFront << std::endl;
221 #endif
222         // linear quadrature of occupancy between timeBeforeEnter and timeBeforeLeaveFront
223         integratedLengthOnLane += (timeBeforeLeaveFront - timeBeforeEnter) * (lengthOnLaneAtLeaveFront + lengthOnLaneAtStepStart) * 0.5;
224         // linear quadrature of occupancy between timeBeforeLeaveFront and timeBeforeEnterBack
225         integratedLengthOnLane += (timeBeforeEnterBack - timeBeforeLeaveFront) * lengthOnLaneAtLeaveFront;
226         // and until vehicle leaves/stepEnd
227         integratedLengthOnLane += (timeBeforeLeave - timeBeforeEnterBack) * (lengthOnLaneAtLeaveFront + lengthOnLaneAtStepEnd) * 0.5;
228     }
229 
230     double meanLengthOnLane = integratedLengthOnLane / TS;
231 #ifdef DEBUG_NOTIFY_MOVE
232     std::cout << "Calculated mean length on lane '" << myLane->getID() << "' in last step as " << meanLengthOnLane
233               << "\nlengthOnLaneAtStepStart=" << lengthOnLaneAtStepStart << ", lengthOnLaneAtStepEnd=" << lengthOnLaneAtStepEnd << ", integratedLengthOnLane=" << integratedLengthOnLane
234               << std::endl;
235 #endif
236 
237 //    // XXX: use this, when #2556 is fixed! Refs. #2575
238 //    const double travelledDistanceFrontOnLane = MAX2(0., MIN2(newPos, myLaneLength) - MAX2(oldPos, 0.));
239 //    const double travelledDistanceVehicleOnLane = MIN2(newPos, myLaneLength) - MAX2(oldPos, 0.) + MIN2(MAX2(0., newPos - myLaneLength), veh.getVehicleType().getLength());
240 //    // XXX: #2556 fixed for ballistic update
241     const double travelledDistanceFrontOnLane = MSGlobals::gSemiImplicitEulerUpdate ? frontOnLane * newSpeed
242             : MAX2(0., MIN2(newPos, myLaneLength) - MAX2(oldPos, 0.));
243     const double travelledDistanceVehicleOnLane = MSGlobals::gSemiImplicitEulerUpdate ? timeOnLane * newSpeed
244             : MIN2(newPos, myLaneLength) - MAX2(oldPos, 0.) + MIN2(MAX2(0., newPos - myLaneLength), veh.getVehicleType().getLength());
245 //    // XXX: no fix
246 //    const double travelledDistanceFrontOnLane = frontOnLane*newSpeed;
247 //    const double travelledDistanceVehicleOnLane = timeOnLane*newSpeed;
248 
249     notifyMoveInternal(veh, frontOnLane, timeOnLane, (enterSpeed + leaveSpeedFront) / 2., (enterSpeed + leaveSpeed) / 2., travelledDistanceFrontOnLane, travelledDistanceVehicleOnLane, meanLengthOnLane);
250     return ret;
251 }
252 
253 
254 bool
notifyLeave(SUMOTrafficObject &,double,MSMoveReminder::Notification reason,const MSLane *)255 MSMeanData::MeanDataValues::notifyLeave(SUMOTrafficObject& /*veh*/, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
256     if (MSGlobals::gUseMesoSim) {
257         return false; // reminder is re-added on every segment (@recheck for performance)
258     }
259     return reason == MSMoveReminder::NOTIFICATION_JUNCTION;
260 }
261 
262 
263 bool
isEmpty() const264 MSMeanData::MeanDataValues::isEmpty() const {
265     return sampleSeconds == 0;
266 }
267 
268 
269 void
update()270 MSMeanData::MeanDataValues::update() {
271 }
272 
273 
274 double
getSamples() const275 MSMeanData::MeanDataValues::getSamples() const {
276     return sampleSeconds;
277 }
278 
279 
280 // ---------------------------------------------------------------------------
281 // MSMeanData::MeanDataValueTracker - methods
282 // ---------------------------------------------------------------------------
MeanDataValueTracker(MSLane * const lane,const double length,const MSMeanData * const parent)283 MSMeanData::MeanDataValueTracker::MeanDataValueTracker(MSLane* const lane,
284         const double length,
285         const MSMeanData* const parent)
286     : MSMeanData::MeanDataValues(lane, length, true, parent) {
287     myCurrentData.push_back(new TrackerEntry(parent->createValues(lane, length, false)));
288 }
289 
290 
~MeanDataValueTracker()291 MSMeanData::MeanDataValueTracker::~MeanDataValueTracker() {
292     std::list<TrackerEntry*>::iterator i;
293     for (i = myCurrentData.begin(); i != myCurrentData.end(); i++) {
294         delete *i;
295     }
296 
297     // FIXME: myTrackedData may still hold some undeleted TrackerEntries. When to delete those? (Leo), refers to #2251
298     // code below fails
299 
300 //	std::map<SUMOTrafficObject*, TrackerEntry*>::iterator j;
301 //	for(j=myTrackedData.begin(); j!=myTrackedData.end();j++){
302 //		delete j->second;
303 //	}
304 }
305 
306 
307 void
reset(bool afterWrite)308 MSMeanData::MeanDataValueTracker::reset(bool afterWrite) {
309     if (afterWrite) {
310         if (myCurrentData.begin() != myCurrentData.end()) {
311             myCurrentData.pop_front();
312         }
313     } else {
314         myCurrentData.push_back(new TrackerEntry(myParent->createValues(myLane, myLaneLength, false)));
315     }
316 }
317 
318 
319 void
addTo(MSMeanData::MeanDataValues & val) const320 MSMeanData::MeanDataValueTracker::addTo(MSMeanData::MeanDataValues& val) const {
321     myCurrentData.front()->myValues->addTo(val);
322 }
323 
324 
325 void
notifyMoveInternal(const SUMOTrafficObject & veh,const double frontOnLane,const double timeOnLane,const double meanSpeedFrontOnLane,const double meanSpeedVehicleOnLane,const double travelledDistanceFrontOnLane,const double travelledDistanceVehicleOnLane,const double meanLengthOnLane)326 MSMeanData::MeanDataValueTracker::notifyMoveInternal(const SUMOTrafficObject& veh, const double frontOnLane, const double timeOnLane, const double meanSpeedFrontOnLane, const double meanSpeedVehicleOnLane, const double travelledDistanceFrontOnLane, const double travelledDistanceVehicleOnLane, const double meanLengthOnLane) {
327     myTrackedData[&veh]->myValues->notifyMoveInternal(veh, frontOnLane, timeOnLane, meanSpeedFrontOnLane, meanSpeedVehicleOnLane, travelledDistanceFrontOnLane, travelledDistanceVehicleOnLane, meanLengthOnLane);
328 }
329 
330 
331 bool
notifyLeave(SUMOTrafficObject & veh,double lastPos,MSMoveReminder::Notification reason,const MSLane *)332 MSMeanData::MeanDataValueTracker::notifyLeave(SUMOTrafficObject& veh, double lastPos, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
333     if (myParent == nullptr || reason != MSMoveReminder::NOTIFICATION_SEGMENT) {
334         myTrackedData[&veh]->myNumVehicleLeft++;
335     }
336     return myTrackedData[&veh]->myValues->notifyLeave(veh, lastPos, reason);
337 }
338 
339 
340 bool
notifyEnter(SUMOTrafficObject & veh,MSMoveReminder::Notification reason,const MSLane * enteredLane)341 MSMeanData::MeanDataValueTracker::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
342 #ifdef DEBUG_NOTIFY_ENTER
343     std::cout << "\n" << SIMTIME << " MSMeanData::MeanDataValueTracker: veh '" << veh.getID() << "' enters lane '" << enteredLane->getID() << "'" << std::endl;
344 #else
345     UNUSED_PARAMETER(enteredLane);
346 #endif
347     if (reason == MSMoveReminder::NOTIFICATION_SEGMENT) {
348         return true;
349     }
350     if (myParent->vehicleApplies(veh) && myTrackedData.find(&veh) == myTrackedData.end()) {
351         myTrackedData[&veh] = myCurrentData.back();
352         myTrackedData[&veh]->myNumVehicleEntered++;
353         if (!myTrackedData[&veh]->myValues->notifyEnter(veh, reason)) {
354             myTrackedData[&veh]->myNumVehicleLeft++;
355             myTrackedData.erase(&veh);
356             return false;
357         }
358         return true;
359     }
360     return false;
361 }
362 
363 
364 bool
isEmpty() const365 MSMeanData::MeanDataValueTracker::isEmpty() const {
366     return myCurrentData.front()->myValues->isEmpty();
367 }
368 
369 
370 void
write(OutputDevice & dev,const SUMOTime period,const double numLanes,const double defaultTravelTime,const int) const371 MSMeanData::MeanDataValueTracker::write(OutputDevice& dev,
372                                         const SUMOTime period,
373                                         const double numLanes,
374                                         const double defaultTravelTime,
375                                         const int /*numVehicles*/) const {
376     myCurrentData.front()->myValues->write(dev, period, numLanes,
377                                            defaultTravelTime,
378                                            myCurrentData.front()->myNumVehicleEntered);
379 }
380 
381 
382 int
getNumReady() const383 MSMeanData::MeanDataValueTracker::getNumReady() const {
384     int result = 0;
385     for (std::list<TrackerEntry*>::const_iterator it = myCurrentData.begin(); it != myCurrentData.end(); ++it) {
386         if ((*it)->myNumVehicleEntered == (*it)->myNumVehicleLeft) {
387             result++;
388         } else {
389             break;
390         }
391     }
392     return result;
393 }
394 
395 
396 double
getSamples() const397 MSMeanData::MeanDataValueTracker::getSamples() const {
398     return myCurrentData.front()->myValues->getSamples();
399 }
400 
401 
402 // ---------------------------------------------------------------------------
403 // MSMeanData - methods
404 // ---------------------------------------------------------------------------
MSMeanData(const std::string & id,const SUMOTime dumpBegin,const SUMOTime dumpEnd,const bool useLanes,const bool withEmpty,const bool printDefaults,const bool withInternal,const bool trackVehicles,const int detectPersons,const double maxTravelTime,const double minSamples,const std::string & vTypes)405 MSMeanData::MSMeanData(const std::string& id,
406                        const SUMOTime dumpBegin, const SUMOTime dumpEnd,
407                        const bool useLanes, const bool withEmpty,
408                        const bool printDefaults, const bool withInternal,
409                        const bool trackVehicles,
410                        const int detectPersons,
411                        const double maxTravelTime,
412                        const double minSamples,
413                        const std::string& vTypes) :
414     MSDetectorFileOutput(id, vTypes, detectPersons),
415     myMinSamples(minSamples),
416     myMaxTravelTime(maxTravelTime),
417     myDumpEmpty(withEmpty),
418     myAmEdgeBased(!useLanes),
419     myDumpBegin(dumpBegin),
420     myDumpEnd(dumpEnd),
421     myPrintDefaults(printDefaults),
422     myDumpInternal(withInternal),
423     myTrackVehicles(trackVehicles) {
424 }
425 
426 
427 void
init()428 MSMeanData::init() {
429     const MSEdgeVector& edges = MSNet::getInstance()->getEdgeControl().getEdges();
430     for (MSEdgeVector::const_iterator e = edges.begin(); e != edges.end(); ++e) {
431         if ((myDumpInternal || !(*e)->isInternal()) &&
432                 ((detectPersons() && myDumpInternal) || (!(*e)->isCrossing() && !(*e)->isWalkingArea()))) {
433             myEdges.push_back(*e);
434             myMeasures.push_back(std::vector<MeanDataValues*>());
435             const std::vector<MSLane*>& lanes = (*e)->getLanes();
436             if (MSGlobals::gUseMesoSim) {
437                 MeanDataValues* data;
438                 if (myTrackVehicles) {
439                     data = new MeanDataValueTracker(nullptr, lanes[0]->getLength(), this);
440                 } else {
441                     data = createValues(nullptr, lanes[0]->getLength(), false);
442                 }
443                 data->setDescription("meandata_" + (*e)->getID());
444                 myMeasures.back().push_back(data);
445                 MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(**e);
446                 while (s != nullptr) {
447                     s->addDetector(data);
448                     s->prepareDetectorForWriting(*data);
449                     s = s->getNextSegment();
450                 }
451                 data->reset();
452                 data->reset(true);
453                 continue;
454             }
455             if (myAmEdgeBased && myTrackVehicles) {
456                 myMeasures.back().push_back(new MeanDataValueTracker(nullptr, lanes[0]->getLength(), this));
457             }
458             for (std::vector<MSLane*>::const_iterator lane = lanes.begin(); lane != lanes.end(); ++lane) {
459                 if (myTrackVehicles) {
460                     if (myAmEdgeBased) {
461                         (*lane)->addMoveReminder(myMeasures.back().back());
462                     } else {
463                         myMeasures.back().push_back(new MeanDataValueTracker(*lane, (*lane)->getLength(), this));
464                     }
465                 } else {
466                     myMeasures.back().push_back(createValues(*lane, (*lane)->getLength(), true));
467                 }
468             }
469         }
470     }
471 }
472 
473 
~MSMeanData()474 MSMeanData::~MSMeanData() {
475     for (std::vector<std::vector<MeanDataValues*> >::const_iterator i = myMeasures.begin(); i != myMeasures.end(); ++i) {
476         for (std::vector<MeanDataValues*>::const_iterator j = (*i).begin(); j != (*i).end(); ++j) {
477             delete *j;
478         }
479     }
480 }
481 
482 
483 void
resetOnly(SUMOTime stopTime)484 MSMeanData::resetOnly(SUMOTime stopTime) {
485     UNUSED_PARAMETER(stopTime);
486     if (MSGlobals::gUseMesoSim) {
487         MSEdgeVector::iterator edge = myEdges.begin();
488         for (std::vector<std::vector<MeanDataValues*> >::const_iterator i = myMeasures.begin(); i != myMeasures.end(); ++i, ++edge) {
489             MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(**edge);
490             MeanDataValues* data = i->front();
491             while (s != nullptr) {
492                 s->prepareDetectorForWriting(*data);
493                 s = s->getNextSegment();
494             }
495             data->reset();
496         }
497         return;
498     }
499     for (std::vector<std::vector<MeanDataValues*> >::const_iterator i = myMeasures.begin(); i != myMeasures.end(); ++i) {
500         for (std::vector<MeanDataValues*>::const_iterator j = (*i).begin(); j != (*i).end(); ++j) {
501             (*j)->reset();
502         }
503     }
504 }
505 
506 
507 std::string
getEdgeID(const MSEdge * const edge)508 MSMeanData::getEdgeID(const MSEdge* const edge) {
509     return edge->getID();
510 }
511 
512 
513 void
writeEdge(OutputDevice & dev,const std::vector<MeanDataValues * > & edgeValues,MSEdge * edge,SUMOTime startTime,SUMOTime stopTime)514 MSMeanData::writeEdge(OutputDevice& dev,
515                       const std::vector<MeanDataValues*>& edgeValues,
516                       MSEdge* edge, SUMOTime startTime, SUMOTime stopTime) {
517     if (MSGlobals::gUseMesoSim) {
518         MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*edge);
519         MeanDataValues* data = edgeValues.front();
520         while (s != nullptr) {
521             s->prepareDetectorForWriting(*data);
522             s = s->getNextSegment();
523         }
524         if (writePrefix(dev, *data, SUMO_TAG_EDGE, getEdgeID(edge))) {
525             data->write(dev, stopTime - startTime,
526                         (double)edge->getLanes().size(),
527                         myPrintDefaults ? edge->getLength() / edge->getSpeedLimit() : -1.);
528         }
529         data->reset(true);
530         return;
531     }
532     std::vector<MeanDataValues*>::const_iterator lane;
533     if (!myAmEdgeBased) {
534         bool writeCheck = myDumpEmpty;
535         if (!writeCheck) {
536             for (lane = edgeValues.begin(); lane != edgeValues.end(); ++lane) {
537                 if (!(*lane)->isEmpty()) {
538                     writeCheck = true;
539                     break;
540                 }
541             }
542         }
543         if (writeCheck) {
544             dev.openTag(SUMO_TAG_EDGE).writeAttr(SUMO_ATTR_ID, edge->getID());
545         }
546         for (lane = edgeValues.begin(); lane != edgeValues.end(); ++lane) {
547             MeanDataValues& meanData = **lane;
548             if (writePrefix(dev, meanData, SUMO_TAG_LANE, meanData.getLane()->getID())) {
549                 meanData.write(dev, stopTime - startTime, 1.f, myPrintDefaults ? meanData.getLane()->getLength() / meanData.getLane()->getSpeedLimit() : -1.);
550             }
551             meanData.reset(true);
552         }
553         if (writeCheck) {
554             dev.closeTag();
555         }
556     } else {
557         if (myTrackVehicles) {
558             MeanDataValues& meanData = **edgeValues.begin();
559             if (writePrefix(dev, meanData, SUMO_TAG_EDGE, edge->getID())) {
560                 meanData.write(dev, stopTime - startTime, (double)edge->getLanes().size(), myPrintDefaults ? edge->getLength() / edge->getSpeedLimit() : -1.);
561             }
562             meanData.reset(true);
563         } else {
564             MeanDataValues* sumData = createValues(nullptr, edge->getLength(), false);
565             for (lane = edgeValues.begin(); lane != edgeValues.end(); ++lane) {
566                 MeanDataValues& meanData = **lane;
567                 meanData.addTo(*sumData);
568                 meanData.reset();
569             }
570             if (writePrefix(dev, *sumData, SUMO_TAG_EDGE, getEdgeID(edge))) {
571                 sumData->write(dev, stopTime - startTime, (double)edge->getLanes().size(), myPrintDefaults ? edge->getLength() / edge->getSpeedLimit() : -1.);
572             }
573             delete sumData;
574         }
575     }
576 }
577 
578 
579 void
openInterval(OutputDevice & dev,const SUMOTime startTime,const SUMOTime stopTime)580 MSMeanData::openInterval(OutputDevice& dev, const SUMOTime startTime, const SUMOTime stopTime) {
581     dev.openTag(SUMO_TAG_INTERVAL).writeAttr(SUMO_ATTR_BEGIN, time2string(startTime)).writeAttr(SUMO_ATTR_END, time2string(stopTime));
582     dev.writeAttr(SUMO_ATTR_ID, myID);
583 }
584 
585 
586 bool
writePrefix(OutputDevice & dev,const MeanDataValues & values,const SumoXMLTag tag,const std::string id) const587 MSMeanData::writePrefix(OutputDevice& dev, const MeanDataValues& values, const SumoXMLTag tag, const std::string id) const {
588     if (myDumpEmpty || !values.isEmpty()) {
589         dev.openTag(tag).writeAttr(SUMO_ATTR_ID, id).writeAttr("sampledSeconds", values.getSamples());
590         return true;
591     }
592     return false;
593 }
594 
595 
596 void
writeXMLOutput(OutputDevice & dev,SUMOTime startTime,SUMOTime stopTime)597 MSMeanData::writeXMLOutput(OutputDevice& dev,
598                            SUMOTime startTime, SUMOTime stopTime) {
599     // check whether this dump shall be written for the current time
600     int numReady = myDumpBegin < stopTime && myDumpEnd - DELTA_T >= startTime ? 1 : 0;
601     if (myTrackVehicles && myDumpBegin < stopTime) {
602         myPendingIntervals.push_back(std::make_pair(startTime, stopTime));
603         numReady = (int)myPendingIntervals.size();
604         for (std::vector<std::vector<MeanDataValues*> >::const_iterator i = myMeasures.begin(); i != myMeasures.end(); ++i) {
605             for (std::vector<MeanDataValues*>::const_iterator j = (*i).begin(); j != (*i).end(); ++j) {
606                 numReady = MIN2(numReady, ((MeanDataValueTracker*)*j)->getNumReady());
607                 if (numReady == 0) {
608                     break;
609                 }
610             }
611             if (numReady == 0) {
612                 break;
613             }
614         }
615     }
616     if (numReady == 0 || myTrackVehicles) {
617         resetOnly(stopTime);
618     }
619     while (numReady-- > 0) {
620         if (!myPendingIntervals.empty()) {
621             startTime = myPendingIntervals.front().first;
622             stopTime = myPendingIntervals.front().second;
623             myPendingIntervals.pop_front();
624         }
625         openInterval(dev, startTime, stopTime);
626         MSEdgeVector::iterator edge = myEdges.begin();
627         for (std::vector<std::vector<MeanDataValues*> >::const_iterator i = myMeasures.begin(); i != myMeasures.end(); ++i, ++edge) {
628             writeEdge(dev, (*i), *edge, startTime, stopTime);
629         }
630         dev.closeTag();
631         dev.flush();
632     }
633 }
634 
635 
636 void
writeXMLDetectorProlog(OutputDevice & dev) const637 MSMeanData::writeXMLDetectorProlog(OutputDevice& dev) const {
638     dev.writeXMLHeader("meandata", "meandata_file.xsd");
639 }
640 
641 
642 void
detectorUpdate(const SUMOTime step)643 MSMeanData::detectorUpdate(const SUMOTime step) {
644     if (step + DELTA_T == myDumpBegin) {
645         init();
646     }
647 }
648 
649 
650 /****************************************************************************/
651 
652