Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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 1657 : MSE3Collector::MSE3EntryReminder::MSE3EntryReminder(
57 1657 : const MSCrossSection& crossSection, MSE3Collector& collector) :
58 3314 : MSMoveReminder(collector.getID() + "_entry", crossSection.myLane),
59 1657 : myCollector(collector), myPosition(crossSection.myPosition) {
60 1657 : }
61 :
62 :
63 : bool
64 69379 : 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 69379 : if (reason != NOTIFICATION_JUNCTION) {
76 32627 : const double posOnLane = veh.getBackPositionOnLane(enteredLane) + veh.getVehicleType().getLength();
77 32627 : if (myLane == enteredLane && posOnLane > myPosition) {
78 : #ifdef HAVE_FOX
79 3326 : ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
80 : #endif
81 3326 : const auto& itVeh = myCollector.myEnteredContainer.find(&veh);
82 3326 : if (itVeh == myCollector.myEnteredContainer.end() ||
83 3326 : 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 7929218 : 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 7929218 : ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
113 : #endif
114 15332960 : if ((myCollector.myEnteredContainer.find(&veh) == myCollector.myEnteredContainer.end() ||
115 7408962 : (veh.isPerson() && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD))
116 7934306 : && newPos > myPosition) {
117 97812 : 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\n";
122 : }
123 : #endif
124 : return false;
125 : } else {
126 : // entered in this step
127 59246 : const double oldSpeed = veh.getPreviousSpeed();
128 59246 : const double entryTime = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep());
129 : assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
130 59246 : const double timeBeforeEnter = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
131 59246 : const double fractionTimeOnDet = TS - timeBeforeEnter;
132 59246 : myCollector.enter(veh, entryTime - fractionTimeOnDet, fractionTimeOnDet, this);
133 : #ifdef DEBUG_E3_NOTIFY_MOVE
134 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
135 : std::cout << " enter\n";
136 : }
137 : #endif
138 : }
139 : }
140 : return true;
141 : }
142 :
143 :
144 : bool
145 235305 : MSE3Collector::MSE3EntryReminder::notifyLeave(SUMOTrafficObject& veh, double, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
146 : #ifdef DEBUG_E3_NOTIFY_LEAVE
147 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
148 : std::cout << SIMTIME
149 : << " MSE3EntryReminder::notifyLeave() (" << getDescription() << "on lane '" << myLane->getID() << "')"
150 : << " vehicle '" << veh.getID() << "'"
151 : << " reason=" << reason
152 : << "\n";
153 : }
154 : #endif
155 235305 : if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
156 : #ifdef HAVE_FOX
157 20015 : ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
158 : #endif
159 20015 : if (myCollector.myEnteredContainer.erase(&veh) > 0) {
160 18469 : if (!myCollector.myExpectArrival) {
161 73144 : WRITE_WARNINGF("Vehicle '%' arrived inside % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID(), time2string(SIMSTEP));
162 : }
163 : }
164 : return false;
165 : }
166 : return true;
167 : }
168 :
169 :
170 : /* -------------------------------------------------------------------------
171 : * MSE3Collector::MSE3LeaveReminder - definitions
172 : * ----------------------------------------------------------------------- */
173 1621 : MSE3Collector::MSE3LeaveReminder::MSE3LeaveReminder(
174 1621 : const MSCrossSection& crossSection, MSE3Collector& collector) :
175 3242 : MSMoveReminder(collector.getID() + "_exit", crossSection.myLane),
176 3242 : myCollector(collector), myPosition(crossSection.myPosition) {}
177 :
178 :
179 : bool
180 70273 : MSE3Collector::MSE3LeaveReminder::notifyEnter(SUMOTrafficObject& veh, Notification reason, const MSLane* enteredLane) {
181 : #ifdef DEBUG_E3_NOTIFY_ENTER
182 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
183 : std::cout << SIMTIME
184 : << " MSE3LeaveReminder::notifyEnter() (" << getDescription() << "on lane '" << myLane->getID() << "')"
185 : << " vehicle '" << veh.getID() << "'"
186 : << " enteredLane=" << enteredLane->getID()
187 : << " reason=" << reason
188 : << "\n";
189 : }
190 : #endif
191 : // this method does not access containers, so no locking here
192 70273 : if (reason != NOTIFICATION_JUNCTION) {
193 10470 : const double backPosOnLane = veh.getBackPositionOnLane(enteredLane);
194 10470 : if (backPosOnLane > myPosition) {
195 : // if the vehicle changes into a covered section we assume it was already registered on another lane
196 : // however, if it is not fully past the detector we still need to track it
197 : #ifdef DEBUG_E3_NOTIFY_ENTER
198 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
199 : std::cout << " assume already known\n";
200 : }
201 : #endif
202 : return false;
203 : }
204 : }
205 : return true;
206 : }
207 :
208 :
209 : bool
210 5761250 : MSE3Collector::MSE3LeaveReminder::notifyMove(SUMOTrafficObject& veh, double oldPos,
211 : double newPos, double newSpeed) {
212 : #ifdef DEBUG_E3_NOTIFY_MOVE
213 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
214 : std::cout << SIMTIME
215 : << " MSE3LeaveReminder::notifyMove() (" << getDescription() << " on lane '" << myLane->getID() << "')"
216 : << " vehicle '" << veh.getID() << "'"
217 : << " entered. oldPos=" << oldPos << " newPos=" << newPos << " newSpeed=" << newSpeed
218 : << " myPosition=" << myPosition
219 : << "\n";
220 : }
221 : #endif
222 5761250 : if (newPos < myPosition) {
223 : // crossSection not yet reached
224 : return true;
225 : }
226 : #ifdef HAVE_FOX
227 250185 : ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
228 : #endif
229 250185 : const double oldSpeed = veh.getPreviousSpeed();
230 250185 : if (oldPos < myPosition) {
231 : assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
232 65902 : const double timeBeforeLeave = MSCFModel::passingTime(oldPos, myPosition, newPos, oldSpeed, newSpeed);
233 : // const double leaveTimeFront = SIMTIME - TS + (myPosition - oldPos) / newSpeed;
234 65902 : const double leaveTimeFront = SIMTIME - TS + timeBeforeLeave;
235 65902 : myCollector.leaveFront(veh, leaveTimeFront);
236 : #ifdef DEBUG_E3_NOTIFY_MOVE
237 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
238 : std::cout << " leaveFront\n";
239 : }
240 : #endif
241 : }
242 250185 : const double backPos = newPos - veh.getVehicleType().getLength();
243 250185 : if (backPos < myPosition) {
244 : // crossSection not yet left
245 : return true;
246 : }
247 : // crossSection left
248 65866 : const double oldBackPos = oldPos - veh.getVehicleType().getLength();
249 65866 : const double leaveStep = SIMTIME;
250 : assert(!MSGlobals::gSemiImplicitEulerUpdate || newSpeed != 0); // how could it move across the detector otherwise
251 65866 : const double timeBeforeLeave = MSCFModel::passingTime(oldBackPos, myPosition, backPos, oldSpeed, newSpeed);
252 65866 : myCollector.leave(veh, leaveStep - TS + timeBeforeLeave, timeBeforeLeave);
253 : #ifdef DEBUG_E3_NOTIFY_MOVE
254 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
255 : std::cout << " leave\n";
256 : }
257 : #endif
258 : return false;
259 : }
260 :
261 :
262 : bool
263 38950 : MSE3Collector::MSE3LeaveReminder::notifyLeave(SUMOTrafficObject& veh, double /* lastPos */, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
264 : #ifdef DEBUG_E3_NOTIFY_LEAVE
265 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
266 : std::cout << SIMTIME
267 : << " MSE3LeaveReminder::notifyLeave() (" << getDescription() << "on lane '" << myLane->getID() << "')"
268 : << " vehicle '" << veh.getID() << "'"
269 : << " reason=" << reason
270 : << "\n";
271 : }
272 : #endif
273 38950 : if (reason == MSMoveReminder::NOTIFICATION_LANE_CHANGE && &enteredLane->getEdge() == &myLane->getEdge()) {
274 : // keep the detector when changing while still on the exit detector but already on a new lane (#4803)
275 : #ifdef DEBUG_E3_NOTIFY_LEAVE
276 : if (DEBUG_COND(myCollector) && DEBUG_COND_VEH(veh)) {
277 : std::cout << " remove reminder, keep in container\n";
278 : }
279 : #endif
280 : return false;
281 : }
282 : #ifdef HAVE_FOX
283 37837 : ScopedLocker<> lock(myCollector.myContainerMutex, MSGlobals::gNumSimThreads > 1);
284 : #endif
285 37837 : if (reason == MSMoveReminder::NOTIFICATION_TELEPORT) {
286 192 : WRITE_WARNINGF("Vehicle '%' teleported from % '%'.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID());
287 48 : myCollector.myEnteredContainer.erase(&veh);
288 48 : return false;
289 : }
290 37789 : if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
291 1226 : if (myCollector.myEnteredContainer.erase(&veh) > 0) {
292 0 : if (!myCollector.myExpectArrival) {
293 0 : WRITE_WARNINGF("Vehicle '%' arrived inside % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), myCollector.getID(), time2string(SIMSTEP));
294 : }
295 : }
296 1226 : return false;
297 : }
298 : return true;
299 : }
300 :
301 : /* -------------------------------------------------------------------------
302 : * MSE3Collector - definitions
303 : * ----------------------------------------------------------------------- */
304 1362 : MSE3Collector::MSE3Collector(const std::string& id,
305 : const CrossSectionVector& entries,
306 : const CrossSectionVector& exits,
307 : double haltingSpeedThreshold,
308 : SUMOTime haltingTimeThreshold,
309 : const std::string name, const std::string& vTypes,
310 : const std::string& nextEdges,
311 : int detectPersons,
312 1362 : bool openEntry, bool expectArrival) :
313 : MSDetectorFileOutput(id, vTypes, nextEdges, detectPersons),
314 1362 : myName(name),
315 1362 : myEntries(entries),
316 1362 : myExits(exits),
317 1362 : myHaltingTimeThreshold(haltingTimeThreshold), myHaltingSpeedThreshold(haltingSpeedThreshold),
318 1362 : myCurrentMeanSpeed(0), myCurrentHaltingsNumber(0),
319 1362 : myLastMeanTravelTime(0), myLastMeanHaltsPerVehicle(0), myLastMeanTimeLoss(0), myLastVehicleSum(0),
320 2724 : myLastResetTime(-1), myOpenEntry(openEntry), myExpectArrival(expectArrival) {
321 : // Set MoveReminders to entries and exits
322 3019 : for (CrossSectionVectorConstIt crossSec1 = entries.begin(); crossSec1 != entries.end(); ++crossSec1) {
323 1657 : myEntryReminders.push_back(new MSE3EntryReminder(*crossSec1, *this));
324 : }
325 2983 : for (CrossSectionVectorConstIt crossSec2 = exits.begin(); crossSec2 != exits.end(); ++crossSec2) {
326 1621 : myLeaveReminders.push_back(new MSE3LeaveReminder(*crossSec2, *this));
327 : }
328 1362 : reset();
329 1362 : }
330 :
331 :
332 2559 : MSE3Collector::~MSE3Collector() {
333 3019 : for (std::vector<MSE3EntryReminder*>::iterator i = myEntryReminders.begin(); i != myEntryReminders.end(); ++i) {
334 1657 : delete *i;
335 : }
336 2983 : for (std::vector<MSE3LeaveReminder*>::iterator i = myLeaveReminders.begin(); i != myLeaveReminders.end(); ++i) {
337 1621 : delete *i;
338 : }
339 3921 : }
340 :
341 :
342 : void
343 1362 : MSE3Collector::reset() {
344 : myLeftContainer.clear();
345 1362 : }
346 :
347 :
348 :
349 : void
350 59596 : MSE3Collector::enter(const SUMOTrafficObject& veh, const double entryTimestep, const double fractionTimeOnDet, MSE3EntryReminder* entryReminder, bool isBackward) {
351 59596 : if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
352 30 : const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
353 60 : for (MSTransportable* p : v.getPersons()) {
354 30 : enter(*p, entryTimestep, fractionTimeOnDet, entryReminder);
355 : }
356 : return;
357 : }
358 59566 : if (!vehicleApplies(veh)) {
359 : return;
360 : }
361 58522 : if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
362 : // walking backward over an entry detector means "leaving"
363 : // std::cout << veh.getID() << " leave at entryDetector\n";
364 320 : leave(veh, entryTimestep, fractionTimeOnDet, true);
365 320 : return;
366 : }
367 58202 : if (myEnteredContainer.find(&veh) != myEnteredContainer.end()) {
368 0 : WRITE_WARNINGF("Vehicle '%' reentered % '%', time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
369 0 : return;
370 : }
371 : #ifdef DEBUG_E3_NOTIFY_ENTER
372 : std::cout << veh.getID() << " enters\n";
373 : #endif
374 58202 : const double speedFraction = veh.getSpeed() * fractionTimeOnDet;
375 : E3Values v;
376 : v.entryTime = entryTimestep;
377 : v.frontLeaveTime = 0;
378 : v.backLeaveTime = 0;
379 : v.speedSum = speedFraction;
380 58202 : v.haltingBegin = veh.getSpeed() < myHaltingSpeedThreshold ? TIME2STEPS(entryTimestep) : -1;
381 58202 : v.intervalSpeedSum = entryTimestep >= STEPS2TIME(myLastResetTime) ? speedFraction : 0;
382 : v.haltings = 0;
383 : v.intervalHaltings = 0;
384 58202 : if (veh.getSpeed() < myHaltingSpeedThreshold) {
385 1475 : if (TIME2STEPS(fractionTimeOnDet) > myHaltingTimeThreshold) {
386 : v.haltings++;
387 : v.intervalHaltings++;
388 : }
389 : }
390 : v.hadUpdate = false;
391 58202 : if (!MSGlobals::gUseMesoSim && veh.isVehicle()) {
392 57072 : v.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss();
393 : v.intervalTimeLoss = v.timeLoss;
394 : }
395 : v.entryReminder = entryReminder;
396 58202 : myEnteredContainer[&veh] = v;
397 : }
398 :
399 :
400 : void
401 65932 : MSE3Collector::leaveFront(const SUMOTrafficObject& veh, const double leaveTimestep) {
402 65932 : if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
403 30 : const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
404 60 : for (MSTransportable* p : v.getPersons()) {
405 30 : leaveFront(*p, leaveTimestep);
406 : }
407 : return;
408 : }
409 65902 : if (!vehicleApplies(veh)) {
410 : return;
411 : }
412 65212 : if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
413 27448 : if (!myOpenEntry && veh.isVehicle()) {
414 60512 : WRITE_WARNINGF("Vehicle '%' left % '%' without entering it, time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
415 : }
416 : } else {
417 37764 : myEnteredContainer[&veh].frontLeaveTime = leaveTimestep;
418 : }
419 : }
420 :
421 :
422 : void
423 66216 : MSE3Collector::leave(const SUMOTrafficObject& veh, const double leaveTimestep, const double fractionTimeOnDet, bool isBackward) {
424 66216 : if (myDetectPersons > (int)PersonMode::WALK && !veh.isPerson()) {
425 30 : const MSBaseVehicle& v = dynamic_cast<const MSBaseVehicle&>(veh);
426 60 : for (MSTransportable* p : v.getPersons()) {
427 30 : leave(*p, leaveTimestep, fractionTimeOnDet);
428 : }
429 : return;
430 : }
431 66186 : if (!vehicleApplies(veh)) {
432 : return;
433 : }
434 65412 : if (veh.isPerson() && !isBackward && dynamic_cast<const MSTransportable&>(veh).getDirection() != MSPModel::FORWARD) {
435 : // walking backward over an exit detector means "entering"
436 : // std::cout << veh.getID() << " enter at exitDetector\n";
437 320 : enter(veh, leaveTimestep, fractionTimeOnDet, nullptr, true);
438 320 : return;
439 : }
440 65092 : if (myEnteredContainer.find(&veh) == myEnteredContainer.end()) {
441 27120 : if (!myOpenEntry && veh.isVehicle()) {
442 60480 : WRITE_WARNINGF("Vehicle '%' left % '%' without entering it, time=%.", veh.getID(), toString(SUMO_TAG_E3DETECTOR), getID(), time2string(SIMSTEP));
443 : }
444 : } else {
445 : #ifdef DEBUG_E3_NOTIFY_LEAVE
446 : std::cout << veh.getID() << " leaves\n";
447 : #endif
448 37972 : E3Values values = myEnteredContainer[&veh];
449 37972 : values.backLeaveTime = leaveTimestep;
450 37972 : const double speedFraction = veh.getSpeed() * (TS - fractionTimeOnDet);
451 37972 : values.speedSum -= speedFraction;
452 37972 : values.intervalSpeedSum -= speedFraction;
453 37972 : if (MSGlobals::gUseMesoSim || !veh.isVehicle()) {
454 : // not yet supported
455 1130 : values.timeLoss = 0;
456 1130 : if (isBackward) {
457 : // leaveFront may not have been called
458 320 : values.frontLeaveTime = leaveTimestep;
459 : }
460 : } else {
461 : // timeLoss was initialized when entering
462 36842 : values.timeLoss = dynamic_cast<const MSVehicle&>(veh).getTimeLoss() - values.timeLoss;
463 : }
464 37972 : myEnteredContainer.erase(&veh);
465 37972 : myLeftContainer.push_back(values);
466 : }
467 : }
468 :
469 :
470 : void
471 288949 : MSE3Collector::writeXMLOutput(OutputDevice& dev,
472 : SUMOTime startTime, SUMOTime stopTime) {
473 577898 : dev << " <interval begin=\"" << time2string(startTime) << "\" end=\"" << time2string(stopTime) << "\" " << "id=\"" << myID << "\" ";
474 : // collect values about vehicles that have left the area
475 288949 : myLastVehicleSum = (int) myLeftContainer.size();
476 288949 : myLastMeanTravelTime = 0;
477 288949 : double meanOverlapTravelTime = 0.;
478 288949 : double meanSpeed = 0.;
479 288949 : myLastMeanHaltsPerVehicle = 0;
480 288949 : myLastMeanTimeLoss = 0.;
481 326906 : for (const E3Values& values : myLeftContainer) {
482 37957 : myLastMeanHaltsPerVehicle += (double)values.haltings;
483 37957 : myLastMeanTravelTime += values.frontLeaveTime - values.entryTime;
484 37957 : const double steps = values.backLeaveTime - values.entryTime;
485 37957 : meanOverlapTravelTime += steps;
486 37957 : meanSpeed += (values.speedSum / steps);
487 37957 : myLastMeanTimeLoss += STEPS2TIME(values.timeLoss);
488 : }
489 288949 : myLastMeanTravelTime = myLastVehicleSum != 0 ? myLastMeanTravelTime / (double)myLastVehicleSum : -1;
490 288949 : meanOverlapTravelTime = myLastVehicleSum != 0 ? meanOverlapTravelTime / (double)myLastVehicleSum : -1;
491 288949 : meanSpeed = myLastVehicleSum != 0 ? meanSpeed / (double)myLastVehicleSum : -1;
492 288949 : myLastMeanHaltsPerVehicle = myLastVehicleSum != 0 ? myLastMeanHaltsPerVehicle / (double) myLastVehicleSum : -1;
493 288949 : myLastMeanTimeLoss = myLastVehicleSum != 0 ? myLastMeanTimeLoss / (double) myLastVehicleSum : -1;
494 : // clear container
495 : myLeftContainer.clear();
496 :
497 : // collect values about vehicles within the container
498 288949 : const int vehicleSumWithin = (int) myEnteredContainer.size();
499 288949 : double meanSpeedWithin = 0.;
500 288949 : double meanDurationWithin = 0.;
501 288949 : double meanHaltsPerVehicleWithin = 0.;
502 288949 : double meanIntervalSpeedWithin = 0.;
503 288949 : double meanIntervalHaltsPerVehicleWithin = 0.;
504 288949 : double meanIntervalDurationWithin = 0.;
505 288949 : double meanTimeLossWithin = 0.;
506 1685112 : for (std::map<const SUMOTrafficObject*, E3Values>::iterator i = myEnteredContainer.begin(); i != myEnteredContainer.end(); ++i) {
507 1396163 : meanHaltsPerVehicleWithin += (double)(*i).second.haltings;
508 1396163 : meanIntervalHaltsPerVehicleWithin += (double)(*i).second.intervalHaltings;
509 1396163 : const double end = (*i).second.backLeaveTime == 0 ? STEPS2TIME(stopTime) : (*i).second.backLeaveTime;
510 1396163 : const double time = end - (*i).second.entryTime;
511 1396163 : const double timeWithin = MIN2(time, end - STEPS2TIME(startTime));
512 1396163 : if (i->second.speedSum > 0.) {
513 1396163 : meanSpeedWithin += i->second.speedSum / time;
514 : }
515 1396163 : if (i->second.intervalSpeedSum > 0.) {
516 196179 : meanIntervalSpeedWithin += i->second.intervalSpeedSum / timeWithin;
517 : }
518 1396163 : meanDurationWithin += time;
519 1396163 : meanIntervalDurationWithin += timeWithin;
520 : // reset interval values
521 1396163 : (*i).second.intervalHaltings = 0;
522 1396163 : (*i).second.intervalSpeedSum = 0;
523 :
524 1396163 : if (!MSGlobals::gUseMesoSim && i->first->isVehicle()) {
525 1396099 : const SUMOTime currentTimeLoss = dynamic_cast<const MSVehicle*>(i->first)->getTimeLoss();
526 1396099 : meanTimeLossWithin += STEPS2TIME(currentTimeLoss - (*i).second.intervalTimeLoss);
527 1396099 : (*i).second.intervalTimeLoss = currentTimeLoss;
528 : }
529 : }
530 288949 : myLastResetTime = stopTime;
531 288949 : meanSpeedWithin = vehicleSumWithin != 0 ? meanSpeedWithin / (double) vehicleSumWithin : -1;
532 288949 : meanHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
533 288949 : meanDurationWithin = vehicleSumWithin != 0 ? meanDurationWithin / (double) vehicleSumWithin : -1;
534 288949 : meanIntervalSpeedWithin = vehicleSumWithin != 0 ? meanIntervalSpeedWithin / (double) vehicleSumWithin : -1;
535 288949 : meanIntervalHaltsPerVehicleWithin = vehicleSumWithin != 0 ? meanIntervalHaltsPerVehicleWithin / (double) vehicleSumWithin : -1;
536 288949 : meanIntervalDurationWithin = vehicleSumWithin != 0 ? meanIntervalDurationWithin / (double) vehicleSumWithin : -1;
537 288949 : meanTimeLossWithin = vehicleSumWithin != 0 ? meanTimeLossWithin / (double) vehicleSumWithin : -1;
538 :
539 : // write values
540 288949 : dev << "meanTravelTime=\"" << myLastMeanTravelTime
541 288949 : << "\" meanOverlapTravelTime=\"" << meanOverlapTravelTime
542 288949 : << "\" meanSpeed=\"" << meanSpeed
543 288949 : << "\" meanHaltsPerVehicle=\"" << myLastMeanHaltsPerVehicle
544 288949 : << "\" meanTimeLoss=\"" << myLastMeanTimeLoss
545 288949 : << "\" vehicleSum=\"" << myLastVehicleSum
546 288949 : << "\" meanSpeedWithin=\"" << meanSpeedWithin
547 288949 : << "\" meanHaltsPerVehicleWithin=\"" << meanHaltsPerVehicleWithin
548 288949 : << "\" meanDurationWithin=\"" << meanDurationWithin
549 288949 : << "\" vehicleSumWithin=\"" << vehicleSumWithin
550 288949 : << "\" meanIntervalSpeedWithin=\"" << meanIntervalSpeedWithin
551 288949 : << "\" meanIntervalHaltsPerVehicleWithin=\"" << meanIntervalHaltsPerVehicleWithin
552 288949 : << "\" meanIntervalDurationWithin=\"" << meanIntervalDurationWithin
553 288949 : << "\" meanTimeLossWithin=\"" << meanTimeLossWithin
554 288949 : << "\"/>\n";
555 288949 : }
556 :
557 :
558 : void
559 1354 : MSE3Collector::writeXMLDetectorProlog(OutputDevice& dev) const {
560 2708 : dev.writeXMLHeader("e3Detector", "det_e3_file.xsd");
561 1354 : }
562 :
563 :
564 : void
565 125472 : MSE3Collector::notifyMovePerson(MSTransportable* p, MSMoveReminder* rem, double detPos, int dir, double pos) {
566 125472 : if (personApplies(*p, dir)) {
567 87280 : const double newSpeed = p->getSpeed();
568 87280 : const double newPos = (dir == MSPModel::FORWARD
569 87280 : ? pos
570 : // position relative to detector end position
571 21600 : : detPos - (pos - detPos));
572 87280 : const double oldPos = newPos - SPEED2DIST(newSpeed);
573 87280 : if (oldPos - p->getVehicleType().getLength() <= detPos) {
574 48432 : rem->notifyMove(*p, oldPos, newPos, newSpeed);
575 : }
576 : }
577 125472 : }
578 :
579 :
580 : void
581 2698647 : MSE3Collector::detectorUpdate(const SUMOTime step) {
582 :
583 2698647 : if (myDetectPersons != (int)PersonMode::NONE) {
584 38079 : for (auto rem : myEntryReminders) {
585 : const MSLane* lane = rem->getLane();
586 21282 : if (lane->hasPedestrians()) {
587 114648 : for (MSTransportable* p : lane->getEdge().getPersons()) {
588 102816 : if (p->getLane() == lane && vehicleApplies(*p)) {
589 62736 : notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
590 : }
591 : }
592 : }
593 : }
594 38079 : for (auto rem : myLeaveReminders) {
595 : const MSLane* lane = rem->getLane();
596 21282 : if (lane->hasPedestrians()) {
597 114648 : for (MSTransportable* p : lane->getEdge().getPersons()) {
598 102816 : if (p->getLane() == lane && vehicleApplies(*p)) {
599 62736 : notifyMovePerson(p, rem, rem->getPosition(), p->getDirection(), p->getPositionOnLane());
600 : }
601 : }
602 : }
603 : }
604 : }
605 :
606 2698647 : myCurrentMeanSpeed = 0;
607 2698647 : myCurrentHaltingsNumber = 0;
608 9966101 : for (std::map<const SUMOTrafficObject*, E3Values>::iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
609 7267454 : const SUMOTrafficObject* veh = pair->first;
610 : #ifdef DEBUG_E3_DETECTORUPDATE
611 : //if (DEBUG_COND(*this) && DEBUG_COND_VEH(*veh)) {
612 : if (DEBUG_COND(*this)) {
613 : std::cout << SIMTIME << " vehPtr=" << veh << "\n";
614 : std::cout << " veh=" << veh->getID() << "\n";
615 : }
616 : #endif
617 : E3Values& values = pair->second;
618 7267454 : myCurrentMeanSpeed += veh->getSpeed();
619 7267454 : values.hadUpdate = true;
620 7267454 : values.speedSum += veh->getSpeed() * TS;
621 7267454 : values.intervalSpeedSum += veh->getSpeed() * TS;
622 7267454 : if (veh->getSpeed() < myHaltingSpeedThreshold) {
623 5780361 : if (values.haltingBegin == -1) {
624 60987 : values.haltingBegin = step;
625 : }
626 5780361 : SUMOTime haltingDuration = step - values.haltingBegin;
627 5780361 : if (haltingDuration >= myHaltingTimeThreshold
628 5713373 : && haltingDuration < (myHaltingTimeThreshold + DELTA_T)) {
629 57317 : values.haltings++;
630 57317 : values.intervalHaltings++;
631 57317 : myCurrentHaltingsNumber++;
632 : }
633 : } else {
634 1487093 : values.haltingBegin = -1;
635 : }
636 : }
637 2698647 : if (myEnteredContainer.size() == 0) {
638 2215137 : myCurrentMeanSpeed = -1;
639 : } else {
640 483510 : myCurrentMeanSpeed /= (double)myEnteredContainer.size();
641 : }
642 2698647 : }
643 :
644 :
645 : const CrossSectionVector&
646 306 : MSE3Collector::getEntries() const {
647 306 : return myEntries;
648 : }
649 :
650 :
651 : const CrossSectionVector&
652 306 : MSE3Collector::getExits() const {
653 306 : return myExits;
654 : }
655 :
656 :
657 : double
658 47 : MSE3Collector::getCurrentMeanSpeed() const {
659 47 : return myCurrentMeanSpeed;
660 : }
661 :
662 :
663 : int
664 5 : MSE3Collector::getCurrentHaltingNumber() const {
665 5 : return myCurrentHaltingsNumber;
666 : }
667 :
668 :
669 : int
670 578 : MSE3Collector::getVehiclesWithin() const {
671 578 : return (int) myEnteredContainer.size();
672 : }
673 :
674 :
675 : std::vector<std::string>
676 247 : MSE3Collector::getCurrentVehicleIDs() const {
677 : std::vector<std::string> ret;
678 369 : for (std::map<const SUMOTrafficObject*, E3Values>::const_iterator pair = myEnteredContainer.begin(); pair != myEnteredContainer.end(); ++pair) {
679 122 : ret.push_back((*pair).first->getID());
680 : }
681 247 : std::sort(ret.begin(), ret.end());
682 247 : return ret;
683 0 : }
684 :
685 : void
686 20 : MSE3Collector::clearState(SUMOTime /* step */) {
687 : myEnteredContainer.clear();
688 : myLeftContainer.clear();
689 20 : }
690 :
691 : /****************************************************************************/
|