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    MSE3Collector.cpp
11 /// @author  Christian Roessel
12 /// @author  Daniel Krajzewicz
13 /// @author  Jakob Erdmann
14 /// @author  Michael Behrisch
15 /// @author  Laura Bieker
16 /// @date    Tue Dec 02 2003 22:17 CET
17 /// @version $Id$
18 ///
19 // A detector of vehicles passing an area between entry/exit points
20 /****************************************************************************/
21 
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #include <config.h>
26 
27 #include <algorithm>
28 
29 #include "MSE3Collector.h"
30 #include <microsim/MSNet.h>
31 #include <microsim/MSVehicle.h>
32 
33 //#define DEBUG_E3_NOTIFY_MOVE
34 //#define DEBUG_E3_NOTIFY_ENTER
35 //#define DEBUG_E3_NOTIFY_LEAVE
36 //#define DEBUG_E3_DETECTORUPDATE
37 
38 //#define DEBUG_COND(obj) ((obj.getID() == ""))
39 //#define DEBUG_COND_VEH(veh) ((veh).getID() == "")
40 //#define DEBUG_COND_VEH(veh) ((veh).isSelected())
41 //#define DEBUG_COND(collector) (true)
42 //#define DEBUG_COND_VEH(veh) (true)
43 
44 
45 // ===========================================================================
46 // method definitions
47 // ===========================================================================
48 /* -------------------------------------------------------------------------
49  * MSE3Collector::MSE3EntryReminder - definitions
50  * ----------------------------------------------------------------------- */
MSE3EntryReminder(const MSCrossSection & crossSection,MSE3Collector & collector)51 MSE3Collector::MSE3EntryReminder::MSE3EntryReminder(
52     const MSCrossSection& crossSection, MSE3Collector& collector) :
53     MSMoveReminder(collector.getID() + "_entry", crossSection.myLane),
54     myCollector(collector), myPosition(crossSection.myPosition) {
55 }
56 
57 
58 bool
notifyEnter(SUMOTrafficObject & veh,Notification reason,const MSLane * enteredLane)59 MSE3Collector::MSE3EntryReminder::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane) {
60 #ifdef DEBUG_E3_NOTIFY_ENTER
61     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
62         std::cout << SIMTIME
63                   << " MSE3EntryReminder::notifyEnter() (" << getDescription() << "on lane '" << myLane->getID() << "')"
64                   << " vehicle '" << veh.getID() << "'"
65                   << " enteredLane=" << enteredLane->getID()
66                   << " reason=" << reason
67                   << "\n";
68     }
69 #endif
70     if (reason != NOTIFICATION_JUNCTION) {
71         const double posOnLane = veh.getBackPositionOnLane(enteredLane) + veh.getVehicleType().getLength();
72         if (myLane == enteredLane && posOnLane > myPosition) {
73             const auto& itVeh = myCollector.myEnteredContainer.find(&veh);
74             if (itVeh == myCollector.myEnteredContainer.end() ||
75                     itVeh->second.entryReminder != this) {
76 #ifdef DEBUG_E3_NOTIFY_ENTER
77                 if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
78                     std::cout << "  assume already known\n";
79                 }
80 #endif
81                 // if the vehicle changes into a covered section we assume it was already registered on another lane
82                 return false;
83             }
84         }
85     }
86     return true;
87 }
88 
89 
90 bool
notifyMove(SUMOTrafficObject & veh,double oldPos,double newPos,double newSpeed)91 MSE3Collector::MSE3EntryReminder::notifyMove(SUMOTrafficObject& veh, double oldPos,
92         double newPos, double newSpeed) {
93 #ifdef DEBUG_E3_NOTIFY_MOVE
94     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
95         std::cout << SIMTIME
96                   << " MSE3EntryReminder::notifyMove() (" << getDescription() << "on lane '" << myLane->getID() << "')"
97                   << " vehicle '" << veh.getID() << "'"
98                   << " entered. oldPos=" << oldPos << " newPos=" << newPos << " newSpeed=" << newSpeed
99                   << " myPosition=" << myPosition
100                   << "\n";
101     }
102 #endif
103     if (myCollector.myEnteredContainer.find(&veh) == myCollector.myEnteredContainer.end() && newPos > myPosition) {
104         if (oldPos > myPosition) {
105             // was behind the detector already in the last step
106 #ifdef DEBUG_E3_NOTIFY_MOVE
107             if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
108                 std::cout << "    already behind\n";
109             }
110 #endif
111             return false;
112         } else {
113             // entered in this step
114             const double oldSpeed = veh.getPreviousSpeed();
115             const double entryTime = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep());
116             assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
117             const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
118             const double fractionTimeOnDet = TS - timeBeforeEnter;
119             myCollector.enter(veh, entryTime - fractionTimeOnDet, fractionTimeOnDet, this);
120 #ifdef DEBUG_E3_NOTIFY_MOVE
121             if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
122                 std::cout << "    enter\n";
123             }
124 #endif
125         }
126     }
127     return true;
128 }
129 
130 
131 bool
notifyLeave(SUMOTrafficObject & veh,double,MSMoveReminder::Notification reason,const MSLane *)132 MSE3Collector::MSE3EntryReminder::notifyLeave(SUMOTrafficObject& veh, double, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
133 #ifdef DEBUG_E3_NOTIFY_LEAVE
134     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
135         std::cout << SIMTIME
136                   << " MSE3EntryReminder::notifyLeave() (" << getDescription() << "on lane '" << myLane->getID() << "')"
137                   << " vehicle '" << veh.getID() << "'"
138                   << " reason=" << reason
139                   << "\n";
140     }
141 #endif
142     if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
143         if (myCollector.myEnteredContainer.erase(&veh) > 0) {
144             WRITE_WARNING("Vehicle '" + veh.getID() + "' arrived inside " + toString(SUMO_TAG_E3DETECTOR) + " '" + myCollector.getID() + "'.");
145         }
146         return false;
147     }
148     return true;
149 }
150 
151 
152 /* -------------------------------------------------------------------------
153  * MSE3Collector::MSE3LeaveReminder - definitions
154  * ----------------------------------------------------------------------- */
MSE3LeaveReminder(const MSCrossSection & crossSection,MSE3Collector & collector)155 MSE3Collector::MSE3LeaveReminder::MSE3LeaveReminder(
156     const MSCrossSection& crossSection, MSE3Collector& collector) :
157     MSMoveReminder(collector.getID() + "_exit", crossSection.myLane),
158     myCollector(collector), myPosition(crossSection.myPosition) {}
159 
160 
161 bool
notifyEnter(SUMOTrafficObject & veh,Notification reason,const MSLane * enteredLane)162 MSE3Collector::MSE3LeaveReminder::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane) {
163 #ifdef DEBUG_E3_NOTIFY_ENTER
164     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
165         std::cout << SIMTIME
166                   << " MSE3LeaveReminder::notifyEnter() (" << getDescription() << "on lane '" << myLane->getID() << "')"
167                   << " vehicle '" << veh.getID() << "'"
168                   << " enteredLane=" << enteredLane->getID()
169                   << " reason=" << reason
170                   << "\n";
171     }
172 #endif
173     if (reason != NOTIFICATION_JUNCTION) {
174         const double backPosOnLane = veh.getBackPositionOnLane(enteredLane);
175         if (backPosOnLane > myPosition) {
176             // if the vehicle changes into a covered section we assume it was already registered on another lane
177             // however, if it is not fully past the detector we still need to track it
178 #ifdef DEBUG_E3_NOTIFY_ENTER
179             if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
180                 std::cout << "  assume already known\n";
181             }
182 #endif
183             return false;
184         }
185     }
186     return true;
187 }
188 
189 
190 bool
notifyMove(SUMOTrafficObject & veh,double oldPos,double newPos,double newSpeed)191 MSE3Collector::MSE3LeaveReminder::notifyMove(SUMOTrafficObject& veh, double oldPos,
192         double newPos, double newSpeed) {
193 #ifdef DEBUG_E3_NOTIFY_MOVE
194     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
195         std::cout << SIMTIME
196                   << " MSE3LeaveReminder::notifyMove() (" << getDescription() << " on lane '" << myLane->getID() << "')"
197                   << " vehicle '" << veh.getID() << "'"
198                   << " entered. oldPos=" << oldPos << " newPos=" << newPos << " newSpeed=" << newSpeed
199                   << " myPosition=" << myPosition
200                   << "\n";
201     }
202 #endif
203     if (newPos < myPosition) {
204         // crossSection not yet reached
205         return true;
206     }
207     const double oldSpeed = veh.getPreviousSpeed();
208     if (oldPos < myPosition) {
209         assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
210         const double timeBeforeLeave = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
211 //        const double leaveTimeFront = SIMTIME - TS + (myPosition - oldPos) / newSpeed;
212         const double leaveTimeFront = SIMTIME - TS + timeBeforeLeave;
213         myCollector.leaveFront(veh, leaveTimeFront);
214 #ifdef DEBUG_E3_NOTIFY_MOVE
215         if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
216             std::cout << "    leaveFront\n";
217         }
218 #endif
219     }
220     const double backPos = newPos - veh.getVehicleType().getLength();
221     if (backPos < myPosition) {
222         // crossSection not yet left
223         return true;
224     }
225     // crossSection left
226     const double oldBackPos = oldPos - veh.getVehicleType().getLength();
227     const double leaveStep = SIMTIME;
228     assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
229     const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, backPos, oldSpeed, newSpeed);
230     myCollector.leave(veh, leaveStep - TS + timeBeforeLeave, timeBeforeLeave);
231 #ifdef DEBUG_E3_NOTIFY_MOVE
232     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
233         std::cout << "    leave\n";
234     }
235 #endif
236     return false;
237 }
238 
239 
240 bool
notifyLeave(SUMOTrafficObject & veh,double,MSMoveReminder::Notification reason,const MSLane * enteredLane)241 MSE3Collector::MSE3LeaveReminder::notifyLeave(SUMOTrafficObject&  veh, double /* lastPos */, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
242 #ifdef DEBUG_E3_NOTIFY_LEAVE
243     if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
244         std::cout << SIMTIME
245                   << " MSE3LeaveReminder::notifyLeave() (" << getDescription() << "on lane '" << myLane->getID() << "')"
246                   << " vehicle '" << veh.getID() << "'"
247                   << " reason=" << reason
248                   << "\n";
249     }
250 #endif
251     if (reason == MSMoveReminder::NOTIFICATION_LANE_CHANGE && &enteredLane->getEdge() == &myLane->getEdge()) {
252         // keep the detector when changing while still on the exit detector but already on a new lane (#4803)
253 #ifdef DEBUG_E3_NOTIFY_LEAVE
254         if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
255             std::cout << "  remove reminder, keep in container\n";
256         }
257 #endif
258         return false;
259     }
260     if (reason == MSMoveReminder::NOTIFICATION_TELEPORT) {
261         WRITE_WARNING("Vehicle '" + veh.getID() + "' teleported from " + toString(SUMO_TAG_E3DETECTOR) + " '" + myCollector.getID() + "'.");
262         myCollector.myEnteredContainer.erase(&veh);
263         return false;
264     }
265     if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
266         if (myCollector.myEnteredContainer.erase(&veh) > 0) {
267             WRITE_WARNING("Vehicle '" + veh.getID() + "' arrived inside " + toString(SUMO_TAG_E3DETECTOR) + " '" + myCollector.getID() + "'.");
268         }
269         return false;
270     }
271     return true;
272 }
273 
274 /* -------------------------------------------------------------------------
275  * MSE3Collector - definitions
276  * ----------------------------------------------------------------------- */
MSE3Collector(const std::string & id,const CrossSectionVector & entries,const CrossSectionVector & exits,double haltingSpeedThreshold,SUMOTime haltingTimeThreshold,const std::string & vTypes,bool openEntry)277 MSE3Collector::MSE3Collector(const std::string& id,
278                              const CrossSectionVector& entries,
279                              const CrossSectionVector& exits,
280                              double haltingSpeedThreshold,
281                              SUMOTime haltingTimeThreshold,
282                              const std::string& vTypes,
283                              bool openEntry) :
284     MSDetectorFileOutput(id, vTypes), myEntries(entries), myExits(exits),
285     myHaltingTimeThreshold(haltingTimeThreshold), myHaltingSpeedThreshold(haltingSpeedThreshold),
286     myCurrentMeanSpeed(0), myCurrentHaltingsNumber(0), myLastResetTime(-1),
287     myOpenEntry(openEntry) {
288     // Set MoveReminders to entries and exits
289     for (CrossSectionVectorConstIt crossSec1 = entries.begin(); crossSec1 != entries.end(); ++crossSec1) {
290         myEntryReminders.push_back(new MSE3EntryReminder(*crossSec1, *this));
291     }
292     for (CrossSectionVectorConstIt crossSec2 = exits.begin(); crossSec2 != exits.end(); ++crossSec2) {
293         myLeaveReminders.push_back(new MSE3LeaveReminder(*crossSec2, *this));
294     }
295     reset();
296 }
297 
298 
~MSE3Collector()299 MSE3Collector::~MSE3Collector() {
300     for (std::vector<MSE3EntryReminder*>::iterator i = myEntryReminders.begin(); i != myEntryReminders.end(); ++i) {
301         delete *i;
302     }
303     for (std::vector<MSE3LeaveReminder*>::iterator i = myLeaveReminders.begin(); i != myLeaveReminders.end(); ++i) {
304         delete *i;
305     }
306 }
307 
308 
309 void
reset()310 MSE3Collector::reset() {
311     myLeftContainer.clear();
312 }
313 
314 
315 
316 void
enter(const SUMOTrafficObject & veh,const double entryTimestep,const double fractionTimeOnDet,MSE3EntryReminder * entryReminder)317 MSE3Collector::enter(const SUMOTrafficObject& veh, const double entryTimestep, const double fractionTimeOnDet, MSE3EntryReminder* entryReminder) {
318     if (!vehicleApplies(veh)) {
319         return;
320     }
321     if (myEnteredContainer.find(&veh) != myEnteredContainer.end()) {
322         WRITE_WARNING("Vehicle '" + veh.getID() + "' reentered " + toString(SUMO_TAG_E3DETECTOR) + " '" + getID() + "'.");
323         return;
324     }
325     const double speedFraction = veh.getSpeed() * fractionTimeOnDet;
326     E3Values v;
327     v.entryTime = entryTimestep;
328     v.frontLeaveTime = 0;
329     v.backLeaveTime = 0;
330     v.speedSum = speedFraction;
331     v.haltingBegin = veh.getSpeed() < myHaltingSpeedThreshold ? TIME2STEPS(entryTimestep) : -1;
332     v.intervalSpeedSum = entryTimestep >= STEPS2TIME(myLastResetTime) ? speedFraction : 0;
333     v.haltings = 0;
334     v.intervalHaltings = 0;
335     if (veh.getSpeed() < myHaltingSpeedThreshold) {
336         if (fractionTimeOnDet > myHaltingTimeThreshold) {
337             v.haltings++;
338             v.intervalHaltings++;
339         }
340     }
341     v.hadUpdate = false;
342     if (!MSGlobals::gUseMesoSim) {
343         v.timeLoss = static_cast<const MSVehicle&>(veh).getTimeLoss();
344         v.intervalTimeLoss = v.timeLoss;
345     }
346     v.entryReminder = entryReminder;
347     myEnteredContainer[&veh] = v;
348 }
349 
350 
351 void
leaveFront(const SUMOTrafficObject & veh,const double leaveTimestep)352 MSE3Collector::leaveFront(const SUMOTrafficObject& veh, const double leaveTimestep) {
353     if (!vehicleApplies(veh)) {
354         return;
355     }
356     if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
357         if (!myOpenEntry) {
358             WRITE_WARNING("Vehicle '" + veh.getID() + "' left " + toString(SUMO_TAG_E3DETECTOR) + " '" + getID() + "' without entering it.");
359         }
360     } else {
361         myEnteredContainer[&veh].frontLeaveTime = leaveTimestep;
362     }
363 }
364 
365 
366 void
leave(const SUMOTrafficObject & veh,const double leaveTimestep,const double fractionTimeOnDet)367 MSE3Collector::leave(const SUMOTrafficObject& veh, const double leaveTimestep, const double fractionTimeOnDet) {
368     if (!vehicleApplies(veh)) {
369         return;
370     }
371     if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
372         if (!myOpenEntry) {
373             WRITE_WARNING("Vehicle '" + veh.getID() + "' left " + toString(SUMO_TAG_E3DETECTOR) + " '" + getID() + "' without entering it.");
374         }
375     } else {
376         E3Values values = myEnteredContainer[&veh];
377         values.backLeaveTime = leaveTimestep;
378         const double speedFraction = veh.getSpeed() * (TS - fractionTimeOnDet);
379         values.speedSum -= speedFraction;
380         values.intervalSpeedSum -= speedFraction;
381         if (MSGlobals::gUseMesoSim) {
382             // not yet supported
383             values.timeLoss = 0;
384         } else {
385             // timeLoss was initialized when entering
386             values.timeLoss = static_cast<const MSVehicle&>(veh).getTimeLoss() - values.timeLoss;
387         }
388         myEnteredContainer.erase(&veh);
389         myLeftContainer.push_back(values);
390     }
391 }
392 
393 
394 void
writeXMLOutput(OutputDevice & dev,SUMOTime startTime,SUMOTime stopTime)395 MSE3Collector::writeXMLOutput(OutputDevice& dev,
396                               SUMOTime startTime, SUMOTime stopTime) {
397     dev << "   <interval begin=\"" << time2string(startTime) << "\" end=\"" << time2string(stopTime) << "\" " << "id=\"" << myID << "\" ";
398     // collect values about vehicles that have left the area
399     const int vehicleSum = (int) myLeftContainer.size();
400     double meanTravelTime = 0.;
401     double meanOverlapTravelTime = 0.;
402     double meanSpeed = 0.;
403     double meanHaltsPerVehicle = 0.;
404     double meanTimeLoss = 0.;
405     for (const E3Values& values : myLeftContainer) {
406         meanHaltsPerVehicle += (double)values.haltings;
407         meanTravelTime += values.frontLeaveTime - values.entryTime;
408         const double steps = values.backLeaveTime - values.entryTime;
409         meanOverlapTravelTime += steps;
410         meanSpeed += (values.speedSum / steps);
411         meanTimeLoss += STEPS2TIME(values.timeLoss);
412     }
413     meanTravelTime = vehicleSum != 0 ? meanTravelTime / (double)vehicleSum : -1;
414     meanOverlapTravelTime = vehicleSum != 0 ? meanOverlapTravelTime / (double)vehicleSum : -1;
415     meanSpeed = vehicleSum != 0 ? meanSpeed / (double)vehicleSum : -1;
416     meanHaltsPerVehicle = vehicleSum != 0 ? meanHaltsPerVehicle / (double) vehicleSum : -1;
417     meanTimeLoss = vehicleSum != 0 ? meanTimeLoss / (double) vehicleSum : -1;
418     // clear container
419     myLeftContainer.clear();
420 
421     // collect values about vehicles within the container
422     const int vehicleSumWithin = (int) myEnteredContainer.size();
423     double meanSpeedWithin = 0.;
424     double meanDurationWithin = 0.;
425     double meanHaltsPerVehicleWithin = 0.;
426     double meanIntervalSpeedWithin = 0.;
427     double meanIntervalHaltsPerVehicleWithin = 0.;
428     double meanIntervalDurationWithin = 0.;
429     double meanTimeLossWithin = 0.;
430     for (std::map<const SUMOTrafficObject*, E3Values>::iterator i = myEnteredContainer.begin(); i != myEnteredContainer.end(); ++i) {
431         meanHaltsPerVehicleWithin += (double)(*i).second.haltings;
432         meanIntervalHaltsPerVehicleWithin += (double)(*i).second.intervalHaltings;
433         const double end = (*i).second.backLeaveTime == 0 ? STEPS2TIME(stopTime) : (*i).second.backLeaveTime;
434         const double time = end - (*i).second.entryTime;
435         const double timeWithin = MIN2(time, end - STEPS2TIME(startTime));
436         if (i->second.speedSum > 0.) {
437             meanSpeedWithin += i->second.speedSum / time;
438         }
439         if (i->second.intervalSpeedSum > 0.) {
440             meanIntervalSpeedWithin += i->second.intervalSpeedSum / timeWithin;
441         }
442         meanDurationWithin += time;
443         meanIntervalDurationWithin += timeWithin;
444         // reset interval values
445         (*i).second.intervalHaltings = 0;
446         (*i).second.intervalSpeedSum = 0;
447 
448         if (!MSGlobals::gUseMesoSim) {
449             const SUMOTime currentTimeLoss = static_cast<const MSVehicle*>(i->first)->getTimeLoss();
450             meanTimeLossWithin += STEPS2TIME(currentTimeLoss - (*i).second.intervalTimeLoss);
451             (*i).second.intervalTimeLoss = currentTimeLoss;
452         }
453     }
454     myLastResetTime = stopTime;
455     meanSpeedWithin = vehicleSumWithin != 0 ?  meanSpeedWithin / (double) vehicleSumWithin : -1;
456     meanHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
457     meanDurationWithin = vehicleSumWithin != 0 ? meanDurationWithin / (double) vehicleSumWithin : -1;
458     meanIntervalSpeedWithin = vehicleSumWithin != 0 ?  meanIntervalSpeedWithin / (double) vehicleSumWithin : -1;
459     meanIntervalHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanIntervalHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
460     meanIntervalDurationWithin = vehicleSumWithin != 0 ? meanIntervalDurationWithin / (double) vehicleSumWithin : -1;
461     meanTimeLossWithin = vehicleSumWithin != 0 ? meanTimeLossWithin / (double) vehicleSumWithin : -1;
462 
463     // write values
464     dev << "meanTravelTime=\"" << meanTravelTime
465         << "\" meanOverlapTravelTime=\"" << meanOverlapTravelTime
466         << "\" meanSpeed=\"" << meanSpeed
467         << "\" meanHaltsPerVehicle=\"" << meanHaltsPerVehicle
468         << "\" meanTimeLoss=\"" << meanTimeLoss
469         << "\" vehicleSum=\"" << vehicleSum
470         << "\" meanSpeedWithin=\"" << meanSpeedWithin
471         << "\" meanHaltsPerVehicleWithin=\"" << meanHaltsPerVehicleWithin
472         << "\" meanDurationWithin=\"" << meanDurationWithin
473         << "\" vehicleSumWithin=\"" << vehicleSumWithin
474         << "\" meanIntervalSpeedWithin=\"" << meanIntervalSpeedWithin
475         << "\" meanIntervalHaltsPerVehicleWithin=\"" << meanIntervalHaltsPerVehicleWithin
476         << "\" meanIntervalDurationWithin=\"" << meanIntervalDurationWithin
477         << "\" meanTimeLossWithin=\"" << meanTimeLossWithin
478         << "\"/>\n";
479 }
480 
481 
482 void
writeXMLDetectorProlog(OutputDevice & dev) const483 MSE3Collector::writeXMLDetectorProlog(OutputDevice& dev) const {
484     dev.writeXMLHeader("e3Detector", "det_e3_file.xsd");
485 }
486 
487 
488 void
detectorUpdate(const SUMOTime step)489 MSE3Collector::detectorUpdate(const SUMOTime step) {
490     myCurrentMeanSpeed = 0;
491     myCurrentHaltingsNumber = 0;
492     for (std::map<const SUMOTrafficObject*, E3Values>::iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
493         const SUMOTrafficObject* veh = pair->first;
494 #ifdef DEBUG_E3_DETECTORUPDATE
495         //if (DEBUG_COND(*this) && DEBUG_COND_VEH(*veh)) {
496         if (DEBUG_COND(*this)) {
497             std::cout << SIMTIME << " vehPtr=" << veh << "\n";
498             std::cout << "       veh=" << veh->getID() << "\n";
499         }
500 #endif
501         E3Values& values = pair->second;
502         myCurrentMeanSpeed += veh->getSpeed();
503         values.hadUpdate = true;
504         values.speedSum += veh->getSpeed() * TS;
505         values.intervalSpeedSum += veh->getSpeed() * TS;
506         if (veh->getSpeed() < myHaltingSpeedThreshold) {
507             if (values.haltingBegin == -1) {
508                 values.haltingBegin = step;
509             }
510             SUMOTime haltingDuration = step - values.haltingBegin;
511             if (haltingDuration >= myHaltingTimeThreshold
512                     && haltingDuration < (myHaltingTimeThreshold + DELTA_T)) {
513                 values.haltings++;
514                 values.intervalHaltings++;
515                 myCurrentHaltingsNumber++;
516             }
517         } else {
518             values.haltingBegin = -1;
519         }
520     }
521     if (myEnteredContainer.size() == 0) {
522         myCurrentMeanSpeed = -1;
523     } else {
524         myCurrentMeanSpeed /= myEnteredContainer.size();
525     }
526 }
527 
528 
529 double
getCurrentMeanSpeed() const530 MSE3Collector::getCurrentMeanSpeed() const {
531     return myCurrentMeanSpeed;
532 }
533 
534 
535 int
getCurrentHaltingNumber() const536 MSE3Collector::getCurrentHaltingNumber() const {
537     return myCurrentHaltingsNumber;
538 }
539 
540 
541 int
getVehiclesWithin() const542 MSE3Collector::getVehiclesWithin() const {
543     return (int) myEnteredContainer.size();
544 }
545 
546 
547 std::vector<std::string>
getCurrentVehicleIDs() const548 MSE3Collector::getCurrentVehicleIDs() const {
549     std::vector<std::string> ret;
550     for (std::map<const SUMOTrafficObject*, E3Values>::const_iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
551         ret.push_back((*pair).first->getID());
552     }
553     std::sort(ret.begin(), ret.end());
554     return ret;
555 }
556 
557 
558 /****************************************************************************/
559 
560