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