Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 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 <utils/common/StringUtils.h>
37 : #include <utils/iodevices/OutputDevice.h>
38 : #include "MSE3Collector.h"
39 :
40 : //#define DEBUG_E3_NOTIFY_MOVE
41 : //#define DEBUG_E3_NOTIFY_ENTER
42 : //#define DEBUG_E3_NOTIFY_LEAVE
43 : //#define DEBUG_E3_DETECTORUPDATE
44 :
45 : //#define DEBUG_COND(obj) ((obj.getID() == ""))
46 : //#define DEBUG_COND_VEH(veh) ((veh).getID() == "")
47 : //#define DEBUG_COND_VEH(veh) ((veh).isSelected())
48 : //#define DEBUG_COND(collector) (true)
49 : //#define DEBUG_COND_VEH(veh) (true)
50 :
51 :
52 : // ===========================================================================
53 : // method definitions
54 : // ===========================================================================
55 : /* -------------------------------------------------------------------------
56 : * MSE3Collector::MSE3EntryReminder - definitions
57 : * ----------------------------------------------------------------------- */
58 1732 : MSE3Collector::MSE3EntryReminder::MSE3EntryReminder(
59 1732 : const MSCrossSection& crossSection, MSE3Collector& collector) :
60 3464 : MSMoveReminder(collector.getID() + "_entry", crossSection.myLane),
61 1732 : myCollector(collector), myPosition(crossSection.myPosition) {
62 1732 : }
63 :
64 :
65 : bool
66 71759 : MSE3Collector::MSE3EntryReminder::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane) {
67 : #ifdef DEBUG_E3_NOTIFY_ENTER
68 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
69 : std::cout << SIMTIME
70 : << " MSE3EntryReminder::notifyEnter() (" << getDescription() << " on lane '" << myLane->getID() << "')"
71 : << " vehicle '" << veh.getID() << "'"
72 : << " enteredLane=" << enteredLane->getID()
73 : << " reason=" << reason
74 : << "\n";
75 : }
76 : #endif
77 71759 : if (reason != NOTIFICATION_JUNCTION) {
78 34063 : const double posOnLane = veh.getBackPositionOnLane(enteredLane) + veh.getVehicleType().getLength();
79 34063 : if (myLane == enteredLane && posOnLane > myPosition) {
80 : #ifdef HAVE_FOX
81 3563 : ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
82 : #endif
83 3563 : const auto& itVeh = myCollector.myEnteredContainer.find(&veh);
84 3563 : if (itVeh == myCollector.myEnteredContainer.end() ||
85 3563 : itVeh->second.entryReminder != this) {
86 : #ifdef DEBUG_E3_NOTIFY_ENTER
87 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
88 : std::cout << " assume already known\n";
89 : }
90 : #endif
91 : // if the vehicle changes into a covered section we assume it was already registered on another lane
92 : return false;
93 : }
94 : }
95 : }
96 : return true;
97 : }
98 :
99 :
100 : bool
101 7790473 : MSE3Collector::MSE3EntryReminder::notifyMove(SUMOTrafficObject& veh, double oldPos,
102 : double newPos, double newSpeed) {
103 : #ifdef DEBUG_E3_NOTIFY_MOVE
104 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
105 : std::cout << SIMTIME
106 : << " MSE3EntryReminder::notifyMove() (" << getDescription() << " on lane '" << myLane->getID() << "')"
107 : << " vehicle '" << veh.getID() << "'"
108 : << " entered. oldPos=" << oldPos << " newPos=" << newPos << " newSpeed=" << newSpeed
109 : << " myPosition=" << myPosition
110 : << "\n";
111 : }
112 : #endif
113 : #ifdef HAVE_FOX
114 7790473 : ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
115 : #endif
116 15044802 : if ((myCollector.myEnteredContainer.find(&veh) == myCollector.myEnteredContainer.end() ||
117 7259549 : (veh.isPerson() && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD))
118 7795561 : && newPos > myPosition) {
119 100819 : if (oldPos > myPosition) {
120 : // was behind the detector already in the last step
121 : #ifdef DEBUG_E3_NOTIFY_MOVE
122 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
123 : std::cout << " already behind, isPerson=" << veh.isPerson() << "\n";
124 : }
125 : #endif
126 : return false;
127 : } else {
128 61278 : if (veh.isVehicle() && &veh.getLane()->getEdge() == &myLane->getEdge() && veh.getLane() != myLane) {
129 : #ifdef DEBUG_E3_NOTIFY_ENTER
130 : std::cout << veh.getID() << " is on the wrong lane\n";
131 : #endif
132 : return true;
133 : }
134 : // entered in this step
135 60225 : const double oldSpeed = veh.getPreviousSpeed();
136 60225 : const double entryTime = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep());
137 : assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
138 60225 : const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
139 60225 : const double fractionTimeOnDet = TS - timeBeforeEnter;
140 60225 : myCollector.enter(veh, entryTime - fractionTimeOnDet, fractionTimeOnDet, this);
141 : #ifdef DEBUG_E3_NOTIFY_MOVE
142 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
143 : std::cout << " enter\n";
144 : }
145 : #endif
146 : }
147 : }
148 : return true;
149 : }
150 :
151 :
152 : bool
153 239109 : MSE3Collector::MSE3EntryReminder::notifyLeave(SUMOTrafficObject& veh, double, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
154 : #ifdef DEBUG_E3_NOTIFY_LEAVE
155 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
156 : std::cout << SIMTIME
157 : << " MSE3EntryReminder::notifyLeave() (" << getDescription() << " on lane '" << myLane->getID() << "')"
158 : << " vehicle '" << veh.getID() << "'"
159 : << " reason=" << reason
160 : << "\n";
161 : }
162 : #endif
163 239109 : if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
164 : #ifdef HAVE_FOX
165 20299 : ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
166 : #endif
167 20299 : if (myCollector.myEnteredContainer.erase(&veh) > 0) {
168 18724 : if (!myCollector.myExpectArrival) {
169 74160 : WRITE_WARNINGF("Vehicle '%' arrived inside % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID(), time2string(SIMSTEP));
170 : }
171 : }
172 : return false;
173 : }
174 : return true;
175 : }
176 :
177 :
178 : /* -------------------------------------------------------------------------
179 : * MSE3Collector::MSE3LeaveReminder - definitions
180 : * ----------------------------------------------------------------------- */
181 1696 : MSE3Collector::MSE3LeaveReminder::MSE3LeaveReminder(
182 1696 : const MSCrossSection& crossSection, MSE3Collector& collector) :
183 3392 : MSMoveReminder(collector.getID() + "_exit", crossSection.myLane),
184 3392 : myCollector(collector), myPosition(crossSection.myPosition) {}
185 :
186 :
187 : bool
188 70942 : MSE3Collector::MSE3LeaveReminder::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane) {
189 : #ifdef DEBUG_E3_NOTIFY_ENTER
190 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
191 : std::cout << SIMTIME
192 : << " MSE3LeaveReminder::notifyEnter() (" << getDescription() << " on lane '" << myLane->getID() << "')"
193 : << " vehicle '" << veh.getID() << "'"
194 : << " enteredLane=" << enteredLane->getID()
195 : << " reason=" << reason
196 : << "\n";
197 : }
198 : #endif
199 : // this method does not access containers, so no locking here
200 70942 : if (reason != NOTIFICATION_JUNCTION) {
201 10397 : const double backPosOnLane = veh.getBackPositionOnLane(enteredLane);
202 10397 : if (backPosOnLane > myPosition) {
203 : // if the vehicle changes into a covered section we assume it was already registered on another lane
204 : // however, if it is not fully past the detector we still need to track it
205 : #ifdef DEBUG_E3_NOTIFY_ENTER
206 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
207 : std::cout << " assume already known\n";
208 : }
209 : #endif
210 : return false;
211 : }
212 : }
213 : return true;
214 : }
215 :
216 :
217 : bool
218 5771516 : MSE3Collector::MSE3LeaveReminder::notifyMove(SUMOTrafficObject& veh, double oldPos,
219 : double newPos, double newSpeed) {
220 : #ifdef DEBUG_E3_NOTIFY_MOVE
221 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
222 : std::cout << SIMTIME
223 : << " MSE3LeaveReminder::notifyMove() (" << getDescription() << " on lane '" << myLane->getID() << "')"
224 : << " vehicle '" << veh.getID() << "'"
225 : << " entered. oldPos=" << oldPos << " newPos=" << newPos << " newSpeed=" << newSpeed
226 : << " myPosition=" << myPosition
227 : << "\n";
228 : }
229 : #endif
230 5771516 : if (newPos < myPosition) {
231 : // crossSection not yet reached
232 : return true;
233 : }
234 : #ifdef HAVE_FOX
235 251519 : ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
236 : #endif
237 251519 : const double oldSpeed = veh.getPreviousSpeed();
238 251519 : if (oldPos < myPosition) {
239 : assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
240 66372 : const double timeBeforeLeave = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
241 : // const double leaveTimeFront = SIMTIME - TS + (myPosition - oldPos) / newSpeed;
242 66372 : const double leaveTimeFront = SIMTIME - TS + timeBeforeLeave;
243 66372 : myCollector.leaveFront(veh, leaveTimeFront);
244 : #ifdef DEBUG_E3_NOTIFY_MOVE
245 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
246 : std::cout << " leaveFront\n";
247 : }
248 : #endif
249 : }
250 251519 : const double backPos = newPos - veh.getVehicleType().getLength();
251 251519 : if (backPos < myPosition) {
252 : // crossSection not yet left
253 : return true;
254 : }
255 : // crossSection left
256 66336 : const double oldBackPos = oldPos - veh.getVehicleType().getLength();
257 66336 : const double leaveStep = SIMTIME;
258 : assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
259 66336 : const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, backPos, oldSpeed, newSpeed);
260 66336 : myCollector.leave(veh, leaveStep - TS + timeBeforeLeave, timeBeforeLeave);
261 : #ifdef DEBUG_E3_NOTIFY_MOVE
262 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
263 : std::cout << " leave\n";
264 : }
265 : #endif
266 : return false;
267 : }
268 :
269 :
270 : bool
271 39557 : MSE3Collector::MSE3LeaveReminder::notifyLeave(SUMOTrafficObject& veh, double /* lastPos */, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
272 : #ifdef DEBUG_E3_NOTIFY_LEAVE
273 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
274 : std::cout << SIMTIME
275 : << " MSE3LeaveReminder::notifyLeave() (" << getDescription() << " on lane '" << myLane->getID() << "')"
276 : << " vehicle '" << veh.getID() << "'"
277 : << " reason=" << reason
278 : << "\n";
279 : }
280 : #endif
281 39557 : if (reason == MSMoveReminder::NOTIFICATION_LANE_CHANGE && &enteredLane->getEdge() == &myLane->getEdge()) {
282 : // keep the detector when changing while still on the exit detector but already on a new lane (#4803)
283 : #ifdef DEBUG_E3_NOTIFY_LEAVE
284 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
285 : std::cout << " remove reminder, keep in container\n";
286 : }
287 : #endif
288 : return false;
289 : }
290 : #ifdef HAVE_FOX
291 38452 : ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
292 : #endif
293 38452 : if (reason == MSMoveReminder::NOTIFICATION_TELEPORT) {
294 192 : WRITE_WARNINGF("Vehicle '%' teleported from % '%'.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID());
295 48 : myCollector.myEnteredContainer.erase(&veh);
296 48 : return false;
297 : }
298 38404 : if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
299 1266 : if (myCollector.myEnteredContainer.erase(&veh) > 0) {
300 0 : if (!myCollector.myExpectArrival) {
301 0 : WRITE_WARNINGF("Vehicle '%' arrived inside % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID(), time2string(SIMSTEP));
302 : }
303 : }
304 1266 : return false;
305 : }
306 : return true;
307 : }
308 :
309 : /* -------------------------------------------------------------------------
310 : * MSE3Collector - definitions
311 : * ----------------------------------------------------------------------- */
312 1406 : MSE3Collector::MSE3Collector(const std::string& id,
313 : const CrossSectionVector& entries,
314 : const CrossSectionVector& exits,
315 : double haltingSpeedThreshold,
316 : SUMOTime haltingTimeThreshold,
317 : const std::string name, const std::string& vTypes,
318 : const std::string& nextEdges,
319 : int detectPersons,
320 1406 : bool openEntry, bool expectArrival) :
321 : MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
322 1406 : myName(name),
323 1406 : myEntries(entries),
324 1406 : myExits(exits),
325 1406 : myHaltingTimeThreshold(haltingTimeThreshold), myHaltingSpeedThreshold(haltingSpeedThreshold),
326 1406 : myCurrentMeanSpeed(0), myCurrentHaltingsNumber(0),
327 1406 : myLastMeanTravelTime(0), myLastMeanHaltsPerVehicle(0), myLastMeanTimeLoss(0), myLastVehicleSum(0),
328 2812 : myLastResetTime(-1), myOpenEntry(openEntry), myExpectArrival(expectArrival) {
329 : // Set MoveReminders to entries and exits
330 3138 : for (CrossSectionVectorConstIt crossSec1 = entries.begin(); crossSec1 != entries.end(); ++crossSec1) {
331 1732 : myEntryReminders.push_back(new MSE3EntryReminder(*crossSec1, *this));
332 : }
333 3102 : for (CrossSectionVectorConstIt crossSec2 = exits.begin(); crossSec2 != exits.end(); ++crossSec2) {
334 1696 : myLeaveReminders.push_back(new MSE3LeaveReminder(*crossSec2, *this));
335 : }
336 1406 : reset();
337 1406 : }
338 :
339 :
340 2648 : MSE3Collector::~MSE3Collector() {
341 3138 : for (std::vector<MSE3EntryReminder*>::iterator i = myEntryReminders.begin(); i != myEntryReminders.end(); ++i) {
342 1732 : delete *i;
343 : }
344 3102 : for (std::vector<MSE3LeaveReminder*>::iterator i = myLeaveReminders.begin(); i != myLeaveReminders.end(); ++i) {
345 1696 : delete *i;
346 : }
347 4054 : }
348 :
349 :
350 : void
351 1406 : MSE3Collector::reset() {
352 : myLeftContainer.clear();
353 1406 : }
354 :
355 :
356 :
357 : void
358 60587 : MSE3Collector::enter(const SUMOTrafficObject& veh, const double entryTimestep, const double fractionTimeOnDet, MSE3EntryReminder* entryReminder, bool isBackward) {
359 60587 : if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
360 42 : const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
361 84 : for (MSTransportable* p : v.getPersons()) {
362 42 : enter(*p, entryTimestep, fractionTimeOnDet, entryReminder);
363 : }
364 : return;
365 : }
366 60545 : if (!vehicleApplies(veh)) {
367 : return;
368 : }
369 59507 : if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
370 : // walking backward over an entry detector means "leaving"
371 : // std::cout << veh.getID() << " leave at entryDetector\n";
372 320 : leave(veh, entryTimestep, fractionTimeOnDet, true);
373 320 : return;
374 : }
375 59187 : if (myEnteredContainer.find(&veh) != myEnteredContainer.end()) {
376 0 : WRITE_WARNINGF("Vehicle '%' reentered % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
377 0 : return;
378 : }
379 : #ifdef DEBUG_E3_NOTIFY_ENTER
380 : std::cout << veh.getID() << " enters\n";
381 : #endif
382 59187 : const double speedFraction = veh.getSpeed() * fractionTimeOnDet;
383 : E3Values v;
384 : v.entryTime = entryTimestep;
385 : v.frontLeaveTime = 0;
386 : v.backLeaveTime = 0;
387 : v.speedSum = speedFraction;
388 59187 : v.haltingBegin = veh.getSpeed() < myHaltingSpeedThreshold ? TIME2STEPS(entryTimestep) : -1;
389 59187 : v.intervalSpeedSum = entryTimestep >= STEPS2TIME(myLastResetTime) ? speedFraction : 0;
390 : v.haltings = 0;
391 : v.intervalHaltings = 0;
392 59187 : if (veh.getSpeed() < myHaltingSpeedThreshold) {
393 1405 : if (TIME2STEPS(fractionTimeOnDet) > myHaltingTimeThreshold) {
394 : v.haltings++;
395 : v.intervalHaltings++;
396 : }
397 : }
398 : v.hadUpdate = false;
399 59187 : if (!MSGlobals::gUseMesoSim && veh.isVehicle()) {
400 58045 : v.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss();
401 : v.intervalTimeLoss = v.timeLoss;
402 : }
403 : v.entryReminder = entryReminder;
404 59187 : myEnteredContainer[&veh] = v;
405 : }
406 :
407 :
408 : void
409 66414 : MSE3Collector::leaveFront(const SUMOTrafficObject& veh, const double leaveTimestep) {
410 66414 : if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
411 42 : const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
412 84 : for (MSTransportable* p : v.getPersons()) {
413 42 : leaveFront(*p, leaveTimestep);
414 : }
415 : return;
416 : }
417 66372 : if (!vehicleApplies(veh)) {
418 : return;
419 : }
420 65682 : if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
421 27266 : if (!myOpenEntry && veh.isVehicle()) {
422 59784 : WRITE_WARNINGF("Vehicle '%' left % '%' without entering it, time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
423 : }
424 : } else {
425 38416 : myEnteredContainer[&veh].frontLeaveTime = leaveTimestep;
426 : }
427 : }
428 :
429 :
430 : void
431 66698 : MSE3Collector::leave(const SUMOTrafficObject& veh, const double leaveTimestep, const double fractionTimeOnDet, bool isBackward) {
432 66698 : if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
433 42 : const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
434 84 : for (MSTransportable* p : v.getPersons()) {
435 42 : leave(*p, leaveTimestep, fractionTimeOnDet);
436 : }
437 : return;
438 : }
439 66656 : if (!vehicleApplies(veh)) {
440 : return;
441 : }
442 65882 : if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
443 : // walking backward over an exit detector means "entering"
444 : // std::cout << veh.getID() << " enter at exitDetector\n";
445 320 : enter(veh, leaveTimestep, fractionTimeOnDet, nullptr, true);
446 320 : return;
447 : }
448 65562 : if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
449 26938 : if (!myOpenEntry && veh.isVehicle()) {
450 59752 : WRITE_WARNINGF("Vehicle '%' left % '%' without entering it, time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
451 : }
452 : } else {
453 : #ifdef DEBUG_E3_NOTIFY_LEAVE
454 : std::cout << veh.getID() << " leaves\n";
455 : #endif
456 38624 : E3Values values = myEnteredContainer[&veh];
457 38624 : values.backLeaveTime = leaveTimestep;
458 38624 : const double speedFraction = veh.getSpeed() * (TS - fractionTimeOnDet);
459 38624 : values.speedSum -= speedFraction;
460 38624 : values.intervalSpeedSum -= speedFraction;
461 38624 : if (MSGlobals::gUseMesoSim || !veh.isVehicle()) {
462 : // not yet supported
463 1142 : values.timeLoss = 0;
464 1142 : if (isBackward) {
465 : // leaveFront may not have been called
466 320 : values.frontLeaveTime = leaveTimestep;
467 : }
468 : } else {
469 : // timeLoss was initialized when entering
470 37482 : values.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss() - values.timeLoss;
471 : }
472 38624 : myEnteredContainer.erase(&veh);
473 38624 : myLeftContainer.push_back(values);
474 : }
475 : }
476 :
477 :
478 : void
479 249274 : MSE3Collector::writeXMLOutput(OutputDevice& dev,
480 : SUMOTime startTime, SUMOTime stopTime) {
481 249274 : dev.openTag(SUMO_TAG_INTERVAL).writeTime(SUMO_ATTR_BEGIN, startTime).writeTime(SUMO_ATTR_END, stopTime);
482 249274 : dev.writeAttr(SUMO_ATTR_ID, myID);
483 : // collect values about vehicles that have left the area
484 249274 : myLastVehicleSum = (int) myLeftContainer.size();
485 249274 : myLastMeanTravelTime = 0;
486 249274 : double meanOverlapTravelTime = 0.;
487 249274 : double meanSpeed = 0.;
488 249274 : myLastMeanHaltsPerVehicle = 0;
489 249274 : myLastMeanTimeLoss = 0.;
490 287886 : for (const E3Values& values : myLeftContainer) {
491 38612 : myLastMeanHaltsPerVehicle += (double)values.haltings;
492 38612 : myLastMeanTravelTime += values.frontLeaveTime - values.entryTime;
493 38612 : const double steps = values.backLeaveTime - values.entryTime;
494 38612 : meanOverlapTravelTime += steps;
495 38612 : meanSpeed += (values.speedSum / steps);
496 38612 : myLastMeanTimeLoss += STEPS2TIME(values.timeLoss);
497 : }
498 249274 : myLastMeanTravelTime = myLastVehicleSum != 0 ? myLastMeanTravelTime / (double)myLastVehicleSum : -1;
499 249274 : meanOverlapTravelTime = myLastVehicleSum != 0 ? meanOverlapTravelTime / (double)myLastVehicleSum : -1;
500 249274 : meanSpeed = myLastVehicleSum != 0 ? meanSpeed / (double)myLastVehicleSum : -1;
501 249274 : myLastMeanHaltsPerVehicle = myLastVehicleSum != 0 ? myLastMeanHaltsPerVehicle / (double) myLastVehicleSum : -1;
502 249274 : myLastMeanTimeLoss = myLastVehicleSum != 0 ? myLastMeanTimeLoss / (double) myLastVehicleSum : -1;
503 : // clear container
504 : myLeftContainer.clear();
505 :
506 : // collect values about vehicles within the container
507 249274 : const int vehicleSumWithin = (int) myEnteredContainer.size();
508 249274 : double meanSpeedWithin = 0.;
509 249274 : double meanDurationWithin = 0.;
510 249274 : double meanHaltsPerVehicleWithin = 0.;
511 249274 : double meanIntervalSpeedWithin = 0.;
512 249274 : double meanIntervalHaltsPerVehicleWithin = 0.;
513 249274 : double meanIntervalDurationWithin = 0.;
514 249274 : double meanTimeLossWithin = 0.;
515 1644663 : for (std::map<const SUMOTrafficObject*, E3Values>::iterator i = myEnteredContainer.begin(); i != myEnteredContainer.end(); ++i) {
516 1395389 : meanHaltsPerVehicleWithin += (double)(*i).second.haltings;
517 1395389 : meanIntervalHaltsPerVehicleWithin += (double)(*i).second.intervalHaltings;
518 1395389 : const double end = (*i).second.backLeaveTime == 0 ? STEPS2TIME(stopTime) : (*i).second.backLeaveTime;
519 1395389 : const double time = end - (*i).second.entryTime;
520 1395389 : const double timeWithin = MIN2(time, end - STEPS2TIME(startTime));
521 1395389 : if (i->second.speedSum > 0.) {
522 1395389 : meanSpeedWithin += i->second.speedSum / time;
523 : }
524 1395389 : if (i->second.intervalSpeedSum > 0.) {
525 195405 : meanIntervalSpeedWithin += i->second.intervalSpeedSum / timeWithin;
526 : }
527 1395389 : meanDurationWithin += time;
528 1395389 : meanIntervalDurationWithin += timeWithin;
529 : // reset interval values
530 1395389 : (*i).second.intervalHaltings = 0;
531 1395389 : (*i).second.intervalSpeedSum = 0;
532 :
533 1395389 : if (!MSGlobals::gUseMesoSim && i->first->isVehicle()) {
534 1395325 : const SUMOTime currentTimeLoss = dynamic_cast<const MSVehicle*>(i->first)->getTimeLoss();
535 1395325 : meanTimeLossWithin += STEPS2TIME(currentTimeLoss - (*i).second.intervalTimeLoss);
536 1395325 : (*i).second.intervalTimeLoss = currentTimeLoss;
537 : }
538 : }
539 249274 : myLastResetTime = stopTime;
540 249274 : meanSpeedWithin = vehicleSumWithin != 0 ? meanSpeedWithin / (double) vehicleSumWithin : -1;
541 249274 : meanHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
542 249274 : meanDurationWithin = vehicleSumWithin != 0 ? meanDurationWithin / (double) vehicleSumWithin : -1;
543 249274 : meanIntervalSpeedWithin = vehicleSumWithin != 0 ? meanIntervalSpeedWithin / (double) vehicleSumWithin : -1;
544 249274 : meanIntervalHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanIntervalHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
545 249274 : meanIntervalDurationWithin = vehicleSumWithin != 0 ? meanIntervalDurationWithin / (double) vehicleSumWithin : -1;
546 249274 : meanTimeLossWithin = vehicleSumWithin != 0 ? meanTimeLossWithin / (double) vehicleSumWithin : -1;
547 :
548 : // write values
549 249274 : dev.writeAttr("meanTravelTime", myLastMeanTravelTime)
550 249274 : .writeAttr("meanOverlapTravelTime", meanOverlapTravelTime)
551 249274 : .writeAttr("meanSpeed", meanSpeed)
552 249274 : .writeAttr("meanHaltsPerVehicle", myLastMeanHaltsPerVehicle)
553 249274 : .writeAttr("meanTimeLoss", myLastMeanTimeLoss)
554 249274 : .writeAttr("vehicleSum", myLastVehicleSum)
555 249274 : .writeAttr("meanSpeedWithin", meanSpeedWithin)
556 249274 : .writeAttr("meanHaltsPerVehicleWithin", meanHaltsPerVehicleWithin)
557 249274 : .writeAttr("meanDurationWithin", meanDurationWithin)
558 249274 : .writeAttr("vehicleSumWithin", vehicleSumWithin)
559 249274 : .writeAttr("meanIntervalSpeedWithin", meanIntervalSpeedWithin)
560 249274 : .writeAttr("meanIntervalHaltsPerVehicleWithin", meanIntervalHaltsPerVehicleWithin)
561 249274 : .writeAttr("meanIntervalDurationWithin", meanIntervalDurationWithin)
562 249274 : .writeAttr("meanTimeLossWithin", meanTimeLossWithin)
563 249274 : .closeTag();
564 249274 : }
565 :
566 :
567 : void
568 1398 : MSE3Collector::writeXMLDetectorProlog(OutputDevice& dev) const {
569 2796 : dev.writeXMLHeader("e3Detector", "det_e3_file.xsd");
570 1398 : }
571 :
572 :
573 : void
574 130928 : MSE3Collector::notifyMovePerson(MSTransportable* p, MSMoveReminder* rem, double detPos, int dir, double pos) {
575 130928 : if (personApplies(*p, dir)) {
576 87280 : const double newSpeed = p->getSpeed();
577 87280 : const double newPos = (dir == MSPModel::FORWARD
578 87280 : ? pos
579 : // position relative to detector end position
580 21600 : : detPos - (pos - detPos));
581 87280 : const double oldPos = newPos - SPEED2DIST(newSpeed);
582 87280 : if (oldPos - p->getVehicleType().getLength() <= detPos) {
583 48432 : rem->notifyMove(*p, oldPos, newPos, newSpeed);
584 : }
585 : }
586 130928 : }
587 :
588 :
589 : void
590 2532218 : MSE3Collector::detectorUpdate(const SUMOTime step) {
591 :
592 2532218 : if (myDetectPersons != (int)PersonMode::NONE) {
593 39942 : for (auto rem : myEntryReminders) {
594 : const MSLane* lane = rem->getLane();
595 22524 : if (lane->hasPedestrians()) {
596 117636 : for (MSTransportable* p : lane->getEdge().getPersons()) {
597 105544 : if (p->getLane() == lane && vehicleApplies(*p)) {
598 65464 : notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
599 : }
600 : }
601 : }
602 : }
603 39942 : for (auto rem : myLeaveReminders) {
604 : const MSLane* lane = rem->getLane();
605 22524 : if (lane->hasPedestrians()) {
606 117636 : for (MSTransportable* p : lane->getEdge().getPersons()) {
607 105544 : if (p->getLane() == lane && vehicleApplies(*p)) {
608 65464 : notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
609 : }
610 : }
611 : }
612 : }
613 : }
614 :
615 2532218 : myCurrentMeanSpeed = 0;
616 2532218 : myCurrentHaltingsNumber = 0;
617 9626133 : for (std::map<const SUMOTrafficObject*, E3Values>::iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
618 7093915 : const SUMOTrafficObject* veh = pair->first;
619 : #ifdef DEBUG_E3_DETECTORUPDATE
620 : //if (DEBUG_COND(*this) && DEBUG_COND_VEH(*veh)) {
621 : if (DEBUG_COND(*this)) {
622 : std::cout << SIMTIME << " vehPtr=" << veh << "\n";
623 : std::cout << " veh=" << veh->getID() << "\n";
624 : }
625 : #endif
626 : E3Values& values = pair->second;
627 7093915 : myCurrentMeanSpeed += veh->getSpeed();
628 7093915 : values.hadUpdate = true;
629 7093915 : values.speedSum += veh->getSpeed() * TS;
630 7093915 : values.intervalSpeedSum += veh->getSpeed() * TS;
631 7093915 : if (veh->getSpeed() < myHaltingSpeedThreshold) {
632 5606436 : if (values.haltingBegin == -1) {
633 58956 : values.haltingBegin = step;
634 : }
635 5606436 : SUMOTime haltingDuration = step - values.haltingBegin;
636 5606436 : if (haltingDuration >= myHaltingTimeThreshold
637 5541542 : && haltingDuration < (myHaltingTimeThreshold + DELTA_T)) {
638 54960 : values.haltings++;
639 54960 : values.intervalHaltings++;
640 54960 : myCurrentHaltingsNumber++;
641 : }
642 : } else {
643 1487479 : values.haltingBegin = -1;
644 : }
645 : }
646 2532218 : if (myEnteredContainer.size() == 0) {
647 2045852 : myCurrentMeanSpeed = -1;
648 : } else {
649 486366 : myCurrentMeanSpeed /= (double)myEnteredContainer.size();
650 : }
651 2532218 : }
652 :
653 :
654 : const CrossSectionVector&
655 322 : MSE3Collector::getEntries() const {
656 322 : return myEntries;
657 : }
658 :
659 :
660 : const CrossSectionVector&
661 322 : MSE3Collector::getExits() const {
662 322 : return myExits;
663 : }
664 :
665 :
666 : double
667 55 : MSE3Collector::getCurrentMeanSpeed() const {
668 55 : return myCurrentMeanSpeed;
669 : }
670 :
671 :
672 : int
673 13 : MSE3Collector::getCurrentHaltingNumber() const {
674 13 : return myCurrentHaltingsNumber;
675 : }
676 :
677 :
678 : int
679 546 : MSE3Collector::getVehiclesWithin() const {
680 546 : return (int) myEnteredContainer.size();
681 : }
682 :
683 :
684 : std::vector<std::string>
685 215 : MSE3Collector::getCurrentVehicleIDs() const {
686 : std::vector<std::string> ret;
687 315 : for (std::map<const SUMOTrafficObject*, E3Values>::const_iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
688 100 : ret.push_back((*pair).first->getID());
689 : }
690 215 : std::sort(ret.begin(), ret.end());
691 215 : return ret;
692 0 : }
693 :
694 : void
695 17 : MSE3Collector::clearState(SUMOTime /* step */) {
696 : myEnteredContainer.clear();
697 : myLeftContainer.clear();
698 17 : }
699 :
700 : /****************************************************************************/
|