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