Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MSE3Collector.cpp
15 : /// @author Christian Roessel
16 : /// @author Daniel Krajzewicz
17 : /// @author Jakob Erdmann
18 : /// @author Michael Behrisch
19 : /// @author Laura Bieker
20 : /// @date Tue Dec 02 2003 22:17 CET
21 : ///
22 : // A detector of vehicles passing an area between entry/exit points
23 : /****************************************************************************/
24 : #include <config.h>
25 :
26 : #include <algorithm>
27 : #ifdef HAVE_FOX
28 : #include <utils/common/ScopedLocker.h>
29 : #endif
30 : #include <microsim/MSLane.h>
31 : #include <microsim/MSEdge.h>
32 : #include <microsim/MSNet.h>
33 : #include <microsim/MSVehicle.h>
34 : #include <microsim/transportables/MSTransportable.h>
35 : #include <microsim/transportables/MSPModel.h>
36 : #include "MSE3Collector.h"
37 :
38 : //#define DEBUG_E3_NOTIFY_MOVE
39 : //#define DEBUG_E3_NOTIFY_ENTER
40 : //#define DEBUG_E3_NOTIFY_LEAVE
41 : //#define DEBUG_E3_DETECTORUPDATE
42 :
43 : //#define DEBUG_COND(obj) ((obj.getID() == ""))
44 : //#define DEBUG_COND_VEH(veh) ((veh).getID() == "")
45 : //#define DEBUG_COND_VEH(veh) ((veh).isSelected())
46 : //#define DEBUG_COND(collector) (true)
47 : //#define DEBUG_COND_VEH(veh) (true)
48 :
49 :
50 : // ===========================================================================
51 : // method definitions
52 : // ===========================================================================
53 : /* -------------------------------------------------------------------------
54 : * MSE3Collector::MSE3EntryReminder - definitions
55 : * ----------------------------------------------------------------------- */
56 1820 : MSE3Collector::MSE3EntryReminder::MSE3EntryReminder(
57 1820 : const MSCrossSection& crossSection, MSE3Collector& collector) :
58 3640 : MSMoveReminder(collector.getID() + "_entry", crossSection.myLane),
59 1820 : myCollector(collector), myPosition(crossSection.myPosition) {
60 1820 : }
61 :
62 :
63 : bool
64 76777 : MSE3Collector::MSE3EntryReminder::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane) {
65 : #ifdef DEBUG_E3_NOTIFY_ENTER
66 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
67 : std::cout << SIMTIME
68 : << " MSE3EntryReminder::notifyEnter() (" << getDescription() << " on lane '" << myLane->getID() << "')"
69 : << " vehicle '" << veh.getID() << "'"
70 : << " enteredLane=" << enteredLane->getID()
71 : << " reason=" << reason
72 : << "\n";
73 : }
74 : #endif
75 76777 : if (reason != NOTIFICATION_JUNCTION) {
76 36959 : const double posOnLane = veh.getBackPositionOnLane(enteredLane) + veh.getVehicleType().getLength();
77 36959 : if (myLane == enteredLane && posOnLane > myPosition) {
78 : #ifdef HAVE_FOX
79 3551 : ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
80 : #endif
81 3551 : const auto& itVeh = myCollector.myEnteredContainer.find(&veh);
82 3551 : if (itVeh == myCollector.myEnteredContainer.end() ||
83 3551 : itVeh->second.entryReminder != this) {
84 : #ifdef DEBUG_E3_NOTIFY_ENTER
85 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
86 : std::cout << " assume already known\n";
87 : }
88 : #endif
89 : // if the vehicle changes into a covered section we assume it was already registered on another lane
90 : return false;
91 : }
92 : }
93 : }
94 : return true;
95 : }
96 :
97 :
98 : bool
99 7792118 : MSE3Collector::MSE3EntryReminder::notifyMove(SUMOTrafficObject& veh, double oldPos,
100 : double newPos, double newSpeed) {
101 : #ifdef DEBUG_E3_NOTIFY_MOVE
102 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
103 : std::cout << SIMTIME
104 : << " MSE3EntryReminder::notifyMove() (" << getDescription() << " on lane '" << myLane->getID() << "')"
105 : << " vehicle '" << veh.getID() << "'"
106 : << " entered. oldPos=" << oldPos << " newPos=" << newPos << " newSpeed=" << newSpeed
107 : << " myPosition=" << myPosition
108 : << "\n";
109 : }
110 : #endif
111 : #ifdef HAVE_FOX
112 7792118 : ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
113 : #endif
114 15047704 : if ((myCollector.myEnteredContainer.find(&veh) == myCollector.myEnteredContainer.end() ||
115 7260806 : (veh.isPerson() && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD))
116 7797206 : && newPos > myPosition) {
117 105040 : if (oldPos > myPosition) {
118 : // was behind the detector already in the last step
119 : #ifdef DEBUG_E3_NOTIFY_MOVE
120 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
121 : std::cout << " already behind, isPerson=" << veh.isPerson() << "\n";
122 : }
123 : #endif
124 : return false;
125 : } else {
126 66152 : if (veh.isVehicle() && &veh.getLane()->getEdge() == &myLane->getEdge() && veh.getLane() != myLane) {
127 : #ifdef DEBUG_E3_NOTIFY_ENTER
128 : std::cout << veh.getID() << " is on the wrong lane\n";
129 : #endif
130 : return true;
131 : }
132 : // entered in this step
133 65104 : const double oldSpeed = veh.getPreviousSpeed();
134 65104 : const double entryTime = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep());
135 : assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
136 65104 : const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
137 65104 : const double fractionTimeOnDet = TS - timeBeforeEnter;
138 65104 : myCollector.enter(veh, entryTime - fractionTimeOnDet, fractionTimeOnDet, this);
139 : #ifdef DEBUG_E3_NOTIFY_MOVE
140 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
141 : std::cout << " enter\n";
142 : }
143 : #endif
144 : }
145 : }
146 : return true;
147 : }
148 :
149 :
150 : bool
151 249690 : MSE3Collector::MSE3EntryReminder::notifyLeave(SUMOTrafficObject& veh, double, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
152 : #ifdef DEBUG_E3_NOTIFY_LEAVE
153 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
154 : std::cout << SIMTIME
155 : << " MSE3EntryReminder::notifyLeave() (" << getDescription() << " on lane '" << myLane->getID() << "')"
156 : << " vehicle '" << veh.getID() << "'"
157 : << " reason=" << reason
158 : << "\n";
159 : }
160 : #endif
161 249690 : if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
162 : #ifdef HAVE_FOX
163 26106 : ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
164 : #endif
165 26106 : if (myCollector.myEnteredContainer.erase(&veh) > 0) {
166 24325 : if (!myCollector.myExpectArrival) {
167 96568 : WRITE_WARNINGF("Vehicle '%' arrived inside % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID(), time2string(SIMSTEP));
168 : }
169 : }
170 : return false;
171 : }
172 : return true;
173 : }
174 :
175 :
176 : /* -------------------------------------------------------------------------
177 : * MSE3Collector::MSE3LeaveReminder - definitions
178 : * ----------------------------------------------------------------------- */
179 1784 : MSE3Collector::MSE3LeaveReminder::MSE3LeaveReminder(
180 1784 : const MSCrossSection& crossSection, MSE3Collector& collector) :
181 3568 : MSMoveReminder(collector.getID() + "_exit", crossSection.myLane),
182 3568 : myCollector(collector), myPosition(crossSection.myPosition) {}
183 :
184 :
185 : bool
186 76395 : MSE3Collector::MSE3LeaveReminder::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane) {
187 : #ifdef DEBUG_E3_NOTIFY_ENTER
188 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
189 : std::cout << SIMTIME
190 : << " MSE3LeaveReminder::notifyEnter() (" << getDescription() << " on lane '" << myLane->getID() << "')"
191 : << " vehicle '" << veh.getID() << "'"
192 : << " enteredLane=" << enteredLane->getID()
193 : << " reason=" << reason
194 : << "\n";
195 : }
196 : #endif
197 : // this method does not access containers, so no locking here
198 76395 : if (reason != NOTIFICATION_JUNCTION) {
199 13526 : const double backPosOnLane = veh.getBackPositionOnLane(enteredLane);
200 13526 : if (backPosOnLane > myPosition) {
201 : // if the vehicle changes into a covered section we assume it was already registered on another lane
202 : // however, if it is not fully past the detector we still need to track it
203 : #ifdef DEBUG_E3_NOTIFY_ENTER
204 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
205 : std::cout << " assume already known\n";
206 : }
207 : #endif
208 : return false;
209 : }
210 : }
211 : return true;
212 : }
213 :
214 :
215 : bool
216 5761485 : MSE3Collector::MSE3LeaveReminder::notifyMove(SUMOTrafficObject& veh, double oldPos,
217 : double newPos, double newSpeed) {
218 : #ifdef DEBUG_E3_NOTIFY_MOVE
219 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
220 : std::cout << SIMTIME
221 : << " MSE3LeaveReminder::notifyMove() (" << getDescription() << " on lane '" << myLane->getID() << "')"
222 : << " vehicle '" << veh.getID() << "'"
223 : << " entered. oldPos=" << oldPos << " newPos=" << newPos << " newSpeed=" << newSpeed
224 : << " myPosition=" << myPosition
225 : << "\n";
226 : }
227 : #endif
228 5761485 : if (newPos < myPosition) {
229 : // crossSection not yet reached
230 : return true;
231 : }
232 : #ifdef HAVE_FOX
233 259638 : ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
234 : #endif
235 259638 : const double oldSpeed = veh.getPreviousSpeed();
236 259638 : if (oldPos < myPosition) {
237 : assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
238 71970 : const double timeBeforeLeave = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
239 : // const double leaveTimeFront = SIMTIME - TS + (myPosition - oldPos) / newSpeed;
240 71970 : const double leaveTimeFront = SIMTIME - TS + timeBeforeLeave;
241 71970 : myCollector.leaveFront(veh, leaveTimeFront);
242 : #ifdef DEBUG_E3_NOTIFY_MOVE
243 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
244 : std::cout << " leaveFront\n";
245 : }
246 : #endif
247 : }
248 259638 : const double backPos = newPos - veh.getVehicleType().getLength();
249 259638 : if (backPos < myPosition) {
250 : // crossSection not yet left
251 : return true;
252 : }
253 : // crossSection left
254 71934 : const double oldBackPos = oldPos - veh.getVehicleType().getLength();
255 71934 : const double leaveStep = SIMTIME;
256 : assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
257 71934 : const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, backPos, oldSpeed, newSpeed);
258 71934 : myCollector.leave(veh, leaveStep - TS + timeBeforeLeave, timeBeforeLeave);
259 : #ifdef DEBUG_E3_NOTIFY_MOVE
260 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
261 : std::cout << " leave\n";
262 : }
263 : #endif
264 : return false;
265 : }
266 :
267 :
268 : bool
269 42025 : MSE3Collector::MSE3LeaveReminder::notifyLeave(SUMOTrafficObject& veh, double /* lastPos */, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
270 : #ifdef DEBUG_E3_NOTIFY_LEAVE
271 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
272 : std::cout << SIMTIME
273 : << " MSE3LeaveReminder::notifyLeave() (" << getDescription() << " on lane '" << myLane->getID() << "')"
274 : << " vehicle '" << veh.getID() << "'"
275 : << " reason=" << reason
276 : << "\n";
277 : }
278 : #endif
279 42025 : if (reason == MSMoveReminder::NOTIFICATION_LANE_CHANGE && &enteredLane->getEdge() == &myLane->getEdge()) {
280 : // keep the detector when changing while still on the exit detector but already on a new lane (#4803)
281 : #ifdef DEBUG_E3_NOTIFY_LEAVE
282 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
283 : std::cout << " remove reminder, keep in container\n";
284 : }
285 : #endif
286 : return false;
287 : }
288 : #ifdef HAVE_FOX
289 40918 : ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
290 : #endif
291 40918 : if (reason == MSMoveReminder::NOTIFICATION_TELEPORT) {
292 192 : WRITE_WARNINGF("Vehicle '%' teleported from % '%'.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID());
293 48 : myCollector.myEnteredContainer.erase(&veh);
294 48 : return false;
295 : }
296 40870 : if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
297 1266 : if (myCollector.myEnteredContainer.erase(&veh) > 0) {
298 0 : if (!myCollector.myExpectArrival) {
299 0 : WRITE_WARNINGF("Vehicle '%' arrived inside % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID(), time2string(SIMSTEP));
300 : }
301 : }
302 1266 : return false;
303 : }
304 : return true;
305 : }
306 :
307 : /* -------------------------------------------------------------------------
308 : * MSE3Collector - definitions
309 : * ----------------------------------------------------------------------- */
310 1514 : MSE3Collector::MSE3Collector(const std::string& id,
311 : const CrossSectionVector& entries,
312 : const CrossSectionVector& exits,
313 : double haltingSpeedThreshold,
314 : SUMOTime haltingTimeThreshold,
315 : const std::string name, const std::string& vTypes,
316 : const std::string& nextEdges,
317 : int detectPersons,
318 1514 : bool openEntry, bool expectArrival) :
319 : MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
320 1514 : myName(name),
321 1514 : myEntries(entries),
322 1514 : myExits(exits),
323 1514 : myHaltingTimeThreshold(haltingTimeThreshold), myHaltingSpeedThreshold(haltingSpeedThreshold),
324 1514 : myCurrentMeanSpeed(0), myCurrentHaltingsNumber(0),
325 1514 : myLastMeanTravelTime(0), myLastMeanHaltsPerVehicle(0), myLastMeanTimeLoss(0), myLastVehicleSum(0),
326 3028 : myLastResetTime(-1), myOpenEntry(openEntry), myExpectArrival(expectArrival) {
327 : // Set MoveReminders to entries and exits
328 3334 : for (CrossSectionVectorConstIt crossSec1 = entries.begin(); crossSec1 != entries.end(); ++crossSec1) {
329 1820 : myEntryReminders.push_back(new MSE3EntryReminder(*crossSec1, *this));
330 : }
331 3298 : for (CrossSectionVectorConstIt crossSec2 = exits.begin(); crossSec2 != exits.end(); ++crossSec2) {
332 1784 : myLeaveReminders.push_back(new MSE3LeaveReminder(*crossSec2, *this));
333 : }
334 1514 : reset();
335 1514 : }
336 :
337 :
338 2860 : MSE3Collector::~MSE3Collector() {
339 3334 : for (std::vector<MSE3EntryReminder*>::iterator i = myEntryReminders.begin(); i != myEntryReminders.end(); ++i) {
340 1820 : delete *i;
341 : }
342 3298 : for (std::vector<MSE3LeaveReminder*>::iterator i = myLeaveReminders.begin(); i != myLeaveReminders.end(); ++i) {
343 1784 : delete *i;
344 : }
345 4374 : }
346 :
347 :
348 : void
349 1514 : MSE3Collector::reset() {
350 : myLeftContainer.clear();
351 1514 : }
352 :
353 :
354 :
355 : void
356 65466 : MSE3Collector::enter(const SUMOTrafficObject& veh, const double entryTimestep, const double fractionTimeOnDet, MSE3EntryReminder* entryReminder, bool isBackward) {
357 65466 : if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
358 42 : const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
359 84 : for (MSTransportable* p : v.getPersons()) {
360 42 : enter(*p, entryTimestep, fractionTimeOnDet, entryReminder);
361 : }
362 : return;
363 : }
364 65424 : if (!vehicleApplies(veh)) {
365 : return;
366 : }
367 64386 : if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
368 : // walking backward over an entry detector means "leaving"
369 : // std::cout << veh.getID() << " leave at entryDetector\n";
370 320 : leave(veh, entryTimestep, fractionTimeOnDet, true);
371 320 : return;
372 : }
373 64066 : if (myEnteredContainer.find(&veh) != myEnteredContainer.end()) {
374 0 : WRITE_WARNINGF("Vehicle '%' reentered % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
375 0 : return;
376 : }
377 : #ifdef DEBUG_E3_NOTIFY_ENTER
378 : std::cout << veh.getID() << " enters\n";
379 : #endif
380 64066 : const double speedFraction = veh.getSpeed() * fractionTimeOnDet;
381 : E3Values v;
382 : v.entryTime = entryTimestep;
383 : v.frontLeaveTime = 0;
384 : v.backLeaveTime = 0;
385 : v.speedSum = speedFraction;
386 64066 : v.haltingBegin = veh.getSpeed() < myHaltingSpeedThreshold ? TIME2STEPS(entryTimestep) : -1;
387 64066 : v.intervalSpeedSum = entryTimestep >= STEPS2TIME(myLastResetTime) ? speedFraction : 0;
388 : v.haltings = 0;
389 : v.intervalHaltings = 0;
390 64066 : if (veh.getSpeed() < myHaltingSpeedThreshold) {
391 1410 : if (TIME2STEPS(fractionTimeOnDet) > myHaltingTimeThreshold) {
392 : v.haltings++;
393 : v.intervalHaltings++;
394 : }
395 : }
396 : v.hadUpdate = false;
397 64066 : if (!MSGlobals::gUseMesoSim && veh.isVehicle()) {
398 62924 : v.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss();
399 : v.intervalTimeLoss = v.timeLoss;
400 : }
401 : v.entryReminder = entryReminder;
402 64066 : myEnteredContainer[&veh] = v;
403 : }
404 :
405 :
406 : void
407 72012 : MSE3Collector::leaveFront(const SUMOTrafficObject& veh, const double leaveTimestep) {
408 72012 : if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
409 42 : const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
410 84 : for (MSTransportable* p : v.getPersons()) {
411 42 : leaveFront(*p, leaveTimestep);
412 : }
413 : return;
414 : }
415 71970 : if (!vehicleApplies(veh)) {
416 : return;
417 : }
418 71280 : if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
419 33508 : if (!myOpenEntry && veh.isVehicle()) {
420 84752 : WRITE_WARNINGF("Vehicle '%' left % '%' without entering it, time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
421 : }
422 : } else {
423 37772 : myEnteredContainer[&veh].frontLeaveTime = leaveTimestep;
424 : }
425 : }
426 :
427 :
428 : void
429 72296 : MSE3Collector::leave(const SUMOTrafficObject& veh, const double leaveTimestep, const double fractionTimeOnDet, bool isBackward) {
430 72296 : if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
431 42 : const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
432 84 : for (MSTransportable* p : v.getPersons()) {
433 42 : leave(*p, leaveTimestep, fractionTimeOnDet);
434 : }
435 : return;
436 : }
437 72254 : if (!vehicleApplies(veh)) {
438 : return;
439 : }
440 71480 : if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
441 : // walking backward over an exit detector means "entering"
442 : // std::cout << veh.getID() << " enter at exitDetector\n";
443 320 : enter(veh, leaveTimestep, fractionTimeOnDet, nullptr, true);
444 320 : return;
445 : }
446 71160 : if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
447 33180 : if (!myOpenEntry && veh.isVehicle()) {
448 84720 : WRITE_WARNINGF("Vehicle '%' left % '%' without entering it, time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
449 : }
450 : } else {
451 : #ifdef DEBUG_E3_NOTIFY_LEAVE
452 : std::cout << veh.getID() << " leaves\n";
453 : #endif
454 37980 : E3Values values = myEnteredContainer[&veh];
455 37980 : values.backLeaveTime = leaveTimestep;
456 37980 : const double speedFraction = veh.getSpeed() * (TS - fractionTimeOnDet);
457 37980 : values.speedSum -= speedFraction;
458 37980 : values.intervalSpeedSum -= speedFraction;
459 37980 : if (MSGlobals::gUseMesoSim || !veh.isVehicle()) {
460 : // not yet supported
461 1142 : values.timeLoss = 0;
462 1142 : if (isBackward) {
463 : // leaveFront may not have been called
464 320 : values.frontLeaveTime = leaveTimestep;
465 : }
466 : } else {
467 : // timeLoss was initialized when entering
468 36838 : values.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss() - values.timeLoss;
469 : }
470 37980 : myEnteredContainer.erase(&veh);
471 37980 : myLeftContainer.push_back(values);
472 : }
473 : }
474 :
475 :
476 : void
477 250953 : MSE3Collector::writeXMLOutput(OutputDevice& dev,
478 : SUMOTime startTime, SUMOTime stopTime) {
479 501906 : dev << " <interval begin=\"" << time2string(startTime) << "\" end=\"" << time2string(stopTime) << "\" " << "id=\"" << myID << "\" ";
480 : // collect values about vehicles that have left the area
481 250953 : myLastVehicleSum = (int) myLeftContainer.size();
482 250953 : myLastMeanTravelTime = 0;
483 250953 : double meanOverlapTravelTime = 0.;
484 250953 : double meanSpeed = 0.;
485 250953 : myLastMeanHaltsPerVehicle = 0;
486 250953 : myLastMeanTimeLoss = 0.;
487 288918 : for (const E3Values& values : myLeftContainer) {
488 37965 : myLastMeanHaltsPerVehicle += (double)values.haltings;
489 37965 : myLastMeanTravelTime += values.frontLeaveTime - values.entryTime;
490 37965 : const double steps = values.backLeaveTime - values.entryTime;
491 37965 : meanOverlapTravelTime += steps;
492 37965 : meanSpeed += (values.speedSum / steps);
493 37965 : myLastMeanTimeLoss += STEPS2TIME(values.timeLoss);
494 : }
495 250953 : myLastMeanTravelTime = myLastVehicleSum != 0 ? myLastMeanTravelTime / (double)myLastVehicleSum : -1;
496 250953 : meanOverlapTravelTime = myLastVehicleSum != 0 ? meanOverlapTravelTime / (double)myLastVehicleSum : -1;
497 250953 : meanSpeed = myLastVehicleSum != 0 ? meanSpeed / (double)myLastVehicleSum : -1;
498 250953 : myLastMeanHaltsPerVehicle = myLastVehicleSum != 0 ? myLastMeanHaltsPerVehicle / (double) myLastVehicleSum : -1;
499 250953 : myLastMeanTimeLoss = myLastVehicleSum != 0 ? myLastMeanTimeLoss / (double) myLastVehicleSum : -1;
500 : // clear container
501 : myLeftContainer.clear();
502 :
503 : // collect values about vehicles within the container
504 250953 : const int vehicleSumWithin = (int) myEnteredContainer.size();
505 250953 : double meanSpeedWithin = 0.;
506 250953 : double meanDurationWithin = 0.;
507 250953 : double meanHaltsPerVehicleWithin = 0.;
508 250953 : double meanIntervalSpeedWithin = 0.;
509 250953 : double meanIntervalHaltsPerVehicleWithin = 0.;
510 250953 : double meanIntervalDurationWithin = 0.;
511 250953 : double meanTimeLossWithin = 0.;
512 1646056 : for (std::map<const SUMOTrafficObject*, E3Values>::iterator i = myEnteredContainer.begin(); i != myEnteredContainer.end(); ++i) {
513 1395103 : meanHaltsPerVehicleWithin += (double)(*i).second.haltings;
514 1395103 : meanIntervalHaltsPerVehicleWithin += (double)(*i).second.intervalHaltings;
515 1395103 : const double end = (*i).second.backLeaveTime == 0 ? STEPS2TIME(stopTime) : (*i).second.backLeaveTime;
516 1395103 : const double time = end - (*i).second.entryTime;
517 1395103 : const double timeWithin = MIN2(time, end - STEPS2TIME(startTime));
518 1395103 : if (i->second.speedSum > 0.) {
519 1395103 : meanSpeedWithin += i->second.speedSum / time;
520 : }
521 1395103 : if (i->second.intervalSpeedSum > 0.) {
522 195119 : meanIntervalSpeedWithin += i->second.intervalSpeedSum / timeWithin;
523 : }
524 1395103 : meanDurationWithin += time;
525 1395103 : meanIntervalDurationWithin += timeWithin;
526 : // reset interval values
527 1395103 : (*i).second.intervalHaltings = 0;
528 1395103 : (*i).second.intervalSpeedSum = 0;
529 :
530 1395103 : if (!MSGlobals::gUseMesoSim && i->first->isVehicle()) {
531 1395039 : const SUMOTime currentTimeLoss = dynamic_cast<const MSVehicle*>(i->first)->getTimeLoss();
532 1395039 : meanTimeLossWithin += STEPS2TIME(currentTimeLoss - (*i).second.intervalTimeLoss);
533 1395039 : (*i).second.intervalTimeLoss = currentTimeLoss;
534 : }
535 : }
536 250953 : myLastResetTime = stopTime;
537 250953 : meanSpeedWithin = vehicleSumWithin != 0 ? meanSpeedWithin / (double) vehicleSumWithin : -1;
538 250953 : meanHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
539 250953 : meanDurationWithin = vehicleSumWithin != 0 ? meanDurationWithin / (double) vehicleSumWithin : -1;
540 250953 : meanIntervalSpeedWithin = vehicleSumWithin != 0 ? meanIntervalSpeedWithin / (double) vehicleSumWithin : -1;
541 250953 : meanIntervalHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanIntervalHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
542 250953 : meanIntervalDurationWithin = vehicleSumWithin != 0 ? meanIntervalDurationWithin / (double) vehicleSumWithin : -1;
543 250953 : meanTimeLossWithin = vehicleSumWithin != 0 ? meanTimeLossWithin / (double) vehicleSumWithin : -1;
544 :
545 : // write values
546 250953 : dev << "meanTravelTime=\"" << myLastMeanTravelTime
547 250953 : << "\" meanOverlapTravelTime=\"" << meanOverlapTravelTime
548 250953 : << "\" meanSpeed=\"" << meanSpeed
549 250953 : << "\" meanHaltsPerVehicle=\"" << myLastMeanHaltsPerVehicle
550 250953 : << "\" meanTimeLoss=\"" << myLastMeanTimeLoss
551 250953 : << "\" vehicleSum=\"" << myLastVehicleSum
552 250953 : << "\" meanSpeedWithin=\"" << meanSpeedWithin
553 250953 : << "\" meanHaltsPerVehicleWithin=\"" << meanHaltsPerVehicleWithin
554 250953 : << "\" meanDurationWithin=\"" << meanDurationWithin
555 250953 : << "\" vehicleSumWithin=\"" << vehicleSumWithin
556 250953 : << "\" meanIntervalSpeedWithin=\"" << meanIntervalSpeedWithin
557 250953 : << "\" meanIntervalHaltsPerVehicleWithin=\"" << meanIntervalHaltsPerVehicleWithin
558 250953 : << "\" meanIntervalDurationWithin=\"" << meanIntervalDurationWithin
559 250953 : << "\" meanTimeLossWithin=\"" << meanTimeLossWithin
560 250953 : << "\"/>\n";
561 250953 : }
562 :
563 :
564 : void
565 1506 : MSE3Collector::writeXMLDetectorProlog(OutputDevice& dev) const {
566 3012 : dev.writeXMLHeader("e3Detector", "det_e3_file.xsd");
567 1506 : }
568 :
569 :
570 : void
571 130928 : MSE3Collector::notifyMovePerson(MSTransportable* p, MSMoveReminder* rem, double detPos, int dir, double pos) {
572 130928 : if (personApplies(*p, dir)) {
573 87280 : const double newSpeed = p->getSpeed();
574 87280 : const double newPos = (dir == MSPModel::FORWARD
575 87280 : ? pos
576 : // position relative to detector end position
577 21600 : : detPos - (pos - detPos));
578 87280 : const double oldPos = newPos - SPEED2DIST(newSpeed);
579 87280 : if (oldPos - p->getVehicleType().getLength() <= detPos) {
580 48432 : rem->notifyMove(*p, oldPos, newPos, newSpeed);
581 : }
582 : }
583 130928 : }
584 :
585 :
586 : void
587 3164998 : MSE3Collector::detectorUpdate(const SUMOTime step) {
588 :
589 3164998 : if (myDetectPersons != (int)PersonMode::NONE) {
590 39942 : for (auto rem : myEntryReminders) {
591 : const MSLane* lane = rem->getLane();
592 22524 : if (lane->hasPedestrians()) {
593 117636 : for (MSTransportable* p : lane->getEdge().getPersons()) {
594 105544 : if (p->getLane() == lane && vehicleApplies(*p)) {
595 65464 : notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
596 : }
597 : }
598 : }
599 : }
600 39942 : for (auto rem : myLeaveReminders) {
601 : const MSLane* lane = rem->getLane();
602 22524 : if (lane->hasPedestrians()) {
603 117636 : for (MSTransportable* p : lane->getEdge().getPersons()) {
604 105544 : if (p->getLane() == lane && vehicleApplies(*p)) {
605 65464 : notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
606 : }
607 : }
608 : }
609 : }
610 : }
611 :
612 3164998 : myCurrentMeanSpeed = 0;
613 3164998 : myCurrentHaltingsNumber = 0;
614 10259318 : for (std::map<const SUMOTrafficObject*, E3Values>::iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
615 7094320 : const SUMOTrafficObject* veh = pair->first;
616 : #ifdef DEBUG_E3_DETECTORUPDATE
617 : //if (DEBUG_COND(*this) && DEBUG_COND_VEH(*veh)) {
618 : if (DEBUG_COND(*this)) {
619 : std::cout << SIMTIME << " vehPtr=" << veh << "\n";
620 : std::cout << " veh=" << veh->getID() << "\n";
621 : }
622 : #endif
623 : E3Values& values = pair->second;
624 7094320 : myCurrentMeanSpeed += veh->getSpeed();
625 7094320 : values.hadUpdate = true;
626 7094320 : values.speedSum += veh->getSpeed() * TS;
627 7094320 : values.intervalSpeedSum += veh->getSpeed() * TS;
628 7094320 : if (veh->getSpeed() < myHaltingSpeedThreshold) {
629 5600909 : if (values.haltingBegin == -1) {
630 57976 : values.haltingBegin = step;
631 : }
632 5600909 : SUMOTime haltingDuration = step - values.haltingBegin;
633 5600909 : if (haltingDuration >= myHaltingTimeThreshold
634 5536991 : && haltingDuration < (myHaltingTimeThreshold + DELTA_T)) {
635 53942 : values.haltings++;
636 53942 : values.intervalHaltings++;
637 53942 : myCurrentHaltingsNumber++;
638 : }
639 : } else {
640 1493411 : values.haltingBegin = -1;
641 : }
642 : }
643 3164998 : if (myEnteredContainer.size() == 0) {
644 2668438 : myCurrentMeanSpeed = -1;
645 : } else {
646 496560 : myCurrentMeanSpeed /= (double)myEnteredContainer.size();
647 : }
648 3164998 : }
649 :
650 :
651 : const CrossSectionVector&
652 363 : MSE3Collector::getEntries() const {
653 363 : return myEntries;
654 : }
655 :
656 :
657 : const CrossSectionVector&
658 363 : MSE3Collector::getExits() const {
659 363 : return myExits;
660 : }
661 :
662 :
663 : double
664 57 : MSE3Collector::getCurrentMeanSpeed() const {
665 57 : return myCurrentMeanSpeed;
666 : }
667 :
668 :
669 : int
670 15 : MSE3Collector::getCurrentHaltingNumber() const {
671 15 : return myCurrentHaltingsNumber;
672 : }
673 :
674 :
675 : int
676 588 : MSE3Collector::getVehiclesWithin() const {
677 588 : return (int) myEnteredContainer.size();
678 : }
679 :
680 :
681 : std::vector<std::string>
682 257 : MSE3Collector::getCurrentVehicleIDs() const {
683 : std::vector<std::string> ret;
684 379 : for (std::map<const SUMOTrafficObject*, E3Values>::const_iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
685 122 : ret.push_back((*pair).first->getID());
686 : }
687 257 : std::sort(ret.begin(), ret.end());
688 257 : return ret;
689 0 : }
690 :
691 : void
692 20 : MSE3Collector::clearState(SUMOTime /* step */) {
693 : myEnteredContainer.clear();
694 : myLeftContainer.clear();
695 20 : }
696 :
697 : /****************************************************************************/
|