Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2009-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 MSDevice_Tripinfo.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Laura Bieker
17 : /// @author Michael Behrisch
18 : /// @author Jakob Erdmann
19 : /// @date Fri, 30.01.2009
20 : ///
21 : // A device which collects info on the vehicle trip
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <microsim/MSGlobals.h>
26 : #include <microsim/MSNet.h>
27 : #include <microsim/MSLane.h>
28 : #include <microsim/MSEdge.h>
29 : #include <microsim/MSVehicle.h>
30 : #include <microsim/transportables/MSTransportableControl.h>
31 : #include <mesosim/MEVehicle.h>
32 : #include <utils/options/OptionsCont.h>
33 : #include <utils/iodevices/OutputDevice.h>
34 : #include <utils/xml/SUMOSAXAttributes.h>
35 : #include "MSDevice_Vehroutes.h"
36 : #include "MSDevice_Tripinfo.h"
37 :
38 : #define NOT_ARRIVED TIME2STEPS(-1)
39 : #define STATE_EMPTY_ARRIVALLANE "NONE"
40 :
41 :
42 : // ===========================================================================
43 : // static members
44 : // ===========================================================================
45 : std::set<const MSDevice_Tripinfo*, ComparatorNumericalIdLess> MSDevice_Tripinfo::myPendingOutput;
46 :
47 : int MSDevice_Tripinfo::myVehicleCount(0);
48 : int MSDevice_Tripinfo::myUndepartedVehicleCount(0);
49 : double MSDevice_Tripinfo::myTotalRouteLength(0);
50 : double MSDevice_Tripinfo::myTotalSpeed(0);
51 : SUMOTime MSDevice_Tripinfo::myTotalDuration(0);
52 : SUMOTime MSDevice_Tripinfo::myTotalWaitingTime(0);
53 : SUMOTime MSDevice_Tripinfo::myTotalTimeLoss(0);
54 : SUMOTime MSDevice_Tripinfo::myTotalDepartDelay(0);
55 : SUMOTime MSDevice_Tripinfo::myWaitingDepartDelay(-1);
56 :
57 : int MSDevice_Tripinfo::myBikeCount(0);
58 : double MSDevice_Tripinfo::myTotalBikeRouteLength(0);
59 : double MSDevice_Tripinfo::myTotalBikeSpeed(0);
60 : SUMOTime MSDevice_Tripinfo::myTotalBikeDuration(0);
61 : SUMOTime MSDevice_Tripinfo::myTotalBikeWaitingTime(0);
62 : SUMOTime MSDevice_Tripinfo::myTotalBikeTimeLoss(0);
63 : SUMOTime MSDevice_Tripinfo::myTotalBikeDepartDelay(0);
64 :
65 : int MSDevice_Tripinfo::myWalkCount(0);
66 : double MSDevice_Tripinfo::myTotalWalkRouteLength(0);
67 : SUMOTime MSDevice_Tripinfo::myTotalWalkDuration(0);
68 : SUMOTime MSDevice_Tripinfo::myTotalWalkTimeLoss(0);
69 : std::vector<int> MSDevice_Tripinfo::myRideCount({0, 0});
70 : std::vector<int> MSDevice_Tripinfo::myRideBusCount({0, 0});
71 : std::vector<int> MSDevice_Tripinfo::myRideRailCount({0, 0});
72 : std::vector<int> MSDevice_Tripinfo::myRideTaxiCount({0, 0});
73 : std::vector<int> MSDevice_Tripinfo::myRideBikeCount({0, 0});
74 : std::vector<int> MSDevice_Tripinfo::myRideAbortCount({0, 0});
75 : std::vector<SUMOTime> MSDevice_Tripinfo::myTotalRideWaitingTime({0, 0});
76 : std::vector<double> MSDevice_Tripinfo::myTotalRideRouteLength({0., 0.});
77 : std::vector<SUMOTime> MSDevice_Tripinfo::myTotalRideDuration({0, 0});
78 :
79 : // ===========================================================================
80 : // method definitions
81 : // ===========================================================================
82 : // ---------------------------------------------------------------------------
83 : // static initialisation methods
84 : // ---------------------------------------------------------------------------
85 : void
86 46427 : MSDevice_Tripinfo::insertOptions(OptionsCont& oc) {
87 46427 : oc.addOptionSubTopic("Tripinfo Device");
88 92854 : insertDefaultAssignmentOptions("tripinfo", "Tripinfo Device", oc);
89 46427 : }
90 :
91 :
92 : void
93 5496629 : MSDevice_Tripinfo::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
94 5496629 : OptionsCont& oc = OptionsCont::getOptions();
95 10718080 : const bool enableByOutputOption = oc.isSet("tripinfo-output") || oc.getBool("duration-log.statistics");
96 10993258 : if (equippedByDefaultAssignmentOptions(oc, "tripinfo", v, enableByOutputOption)) {
97 2492729 : MSDevice_Tripinfo* device = new MSDevice_Tripinfo(v, "tripinfo_" + v.getID());
98 2492729 : into.push_back(device);
99 : myPendingOutput.insert(device);
100 : }
101 5496629 : }
102 :
103 :
104 : // ---------------------------------------------------------------------------
105 : // MSDevice_Tripinfo-methods
106 : // ---------------------------------------------------------------------------
107 2492729 : MSDevice_Tripinfo::MSDevice_Tripinfo(SUMOVehicle& holder, const std::string& id) :
108 : MSVehicleDevice(holder, id),
109 0 : myDepartLane(""),
110 2492729 : myDepartSpeed(-1),
111 2492729 : myDepartPosLat(0),
112 2492729 : myWaitingTime(0),
113 2492729 : myAmWaiting(false),
114 2492729 : myWaitingCount(0),
115 2492729 : myStoppingTime(0),
116 2492729 : myParkingStarted(-1),
117 2492729 : myArrivalTime(NOT_ARRIVED),
118 2492729 : myArrivalLane(""),
119 2492729 : myArrivalPos(-1),
120 2492729 : myArrivalPosLat(0.),
121 2492729 : myArrivalSpeed(-1),
122 2492729 : myArrivalReason(MSMoveReminder::NOTIFICATION_ARRIVED),
123 2492729 : myMesoTimeLoss(0),
124 2492729 : myRouteLength(0.) {
125 2492729 : }
126 :
127 :
128 4985404 : MSDevice_Tripinfo::~MSDevice_Tripinfo() {
129 : // ensure clean up for vaporized vehicles which do not generate output
130 2492702 : myPendingOutput.erase(this);
131 4985404 : }
132 :
133 : void
134 43204 : MSDevice_Tripinfo::cleanup() {
135 43204 : myVehicleCount = 0;
136 43204 : myTotalRouteLength = 0;
137 43204 : myTotalSpeed = 0;
138 43204 : myTotalDuration = 0;
139 43204 : myTotalWaitingTime = 0;
140 43204 : myTotalTimeLoss = 0;
141 43204 : myTotalDepartDelay = 0;
142 43204 : myWaitingDepartDelay = -1;
143 :
144 43204 : myBikeCount = 0;
145 43204 : myTotalBikeRouteLength = 0;
146 43204 : myTotalBikeSpeed = 0;
147 43204 : myTotalBikeDuration = 0;
148 43204 : myTotalBikeWaitingTime = 0;
149 43204 : myTotalBikeTimeLoss = 0;
150 43204 : myTotalBikeDepartDelay = 0;
151 :
152 43204 : myWalkCount = 0;
153 43204 : myTotalWalkRouteLength = 0;
154 43204 : myTotalWalkDuration = 0;
155 43204 : myTotalWalkTimeLoss = 0;
156 :
157 43204 : myRideCount = {0, 0};
158 43204 : myRideBusCount = {0, 0};
159 43204 : myRideRailCount = {0, 0};
160 43204 : myRideTaxiCount = {0, 0};
161 43204 : myRideBikeCount = {0, 0};
162 43204 : myRideAbortCount = {0, 0};
163 43204 : myTotalRideWaitingTime = {0, 0};
164 43204 : myTotalRideRouteLength = {0., 0.};
165 43204 : myTotalRideDuration = {0, 0};
166 43204 : }
167 :
168 : bool
169 4977 : MSDevice_Tripinfo::notifyIdle(SUMOTrafficObject& veh) {
170 4977 : if (veh.isVehicle()) {
171 4977 : myWaitingTime += DELTA_T;
172 4977 : if (!myAmWaiting) {
173 167 : myWaitingCount++;
174 167 : myAmWaiting = true;
175 : }
176 : }
177 4977 : return true;
178 : }
179 :
180 :
181 : bool
182 357387947 : MSDevice_Tripinfo::notifyMove(SUMOTrafficObject& veh, double /*oldPos*/,
183 : double /*newPos*/, double newSpeed) {
184 357387947 : if (veh.isStopped()) {
185 2278546 : if (newSpeed <= SUMO_const_haltingSpeed) {
186 2278350 : myStoppingTime += DELTA_T;
187 : }
188 355109401 : } else if (newSpeed <= SUMO_const_haltingSpeed && lowAcceleration(veh)) {
189 59955464 : myWaitingTime += DELTA_T;
190 59955464 : if (!myAmWaiting) {
191 2835696 : myWaitingCount++;
192 2835696 : myAmWaiting = true;
193 : }
194 : } else {
195 295153937 : myAmWaiting = false;
196 : }
197 357387947 : return true;
198 : }
199 :
200 :
201 : bool
202 59956293 : MSDevice_Tripinfo::lowAcceleration(const SUMOTrafficObject& veh) {
203 59956293 : if (MSGlobals::gUseMesoSim) {
204 : // acceleration is not modelled
205 : return false;
206 : } else {
207 59956293 : const MSVehicle& v = dynamic_cast<const MSVehicle&>(veh);
208 59956293 : return v.getAcceleration() <= v.accelThresholdForWaiting();
209 : }
210 : }
211 :
212 :
213 : void
214 14966906 : MSDevice_Tripinfo::notifyMoveInternal(const SUMOTrafficObject& veh,
215 : const double /* frontOnLane */,
216 : const double timeOnLane,
217 : const double /* meanSpeedFrontOnLane */,
218 : const double meanSpeedVehicleOnLane,
219 : const double /* travelledDistanceFrontOnLane */,
220 : const double /* travelledDistanceVehicleOnLane */,
221 : const double /* meanLengthOnLane */) {
222 :
223 : // called by meso
224 14966906 : const double vmax = veh.getEdge()->getVehicleMaxSpeed(&veh);
225 14966906 : if (vmax > 0) {
226 18711699 : myMesoTimeLoss += TIME2STEPS(timeOnLane * (vmax - meanSpeedVehicleOnLane) / vmax);
227 : }
228 14966906 : myWaitingTime += veh.getWaitingTime();
229 14966906 : if (veh.getWaitingTime() >= TIME2STEPS(1)) {
230 : // waiting counts the time spent waiting to enter the next link (when it's occupied).
231 107552 : myWaitingCount++;
232 : }
233 14966906 : }
234 :
235 :
236 : void
237 5 : MSDevice_Tripinfo::recordMesoParkingTimeLoss(SUMOTime waitingTime) {
238 5 : myMesoTimeLoss += waitingTime;
239 5 : myWaitingTime += waitingTime;
240 5 : myWaitingCount++;
241 5 : }
242 :
243 : void
244 1904853 : MSDevice_Tripinfo::updateParkingStopTime() {
245 1904853 : if (myParkingStarted >= 0) {
246 4525 : myStoppingTime += (MSNet::getInstance()->getCurrentTimeStep() - myParkingStarted);
247 4525 : myParkingStarted = -1;
248 : }
249 1904853 : }
250 :
251 : bool
252 29980177 : MSDevice_Tripinfo::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
253 29980177 : if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
254 1937681 : if (!MSGlobals::gUseMesoSim) {
255 1441424 : myDepartLane = static_cast<MSVehicle&>(veh).getLane()->getID();
256 1441424 : myDepartPosLat = static_cast<MSVehicle&>(veh).getLateralPositionOnLane();
257 : } else {
258 496257 : myDepartLane = veh.getEdge()->getFirstAllowed(veh.getVClass(), true)->getID();
259 : }
260 1937681 : myDepartSpeed = veh.getSpeed();
261 1937681 : myRouteLength = -veh.getPositionOnLane();
262 28042496 : } else if (reason == MSMoveReminder::NOTIFICATION_PARKING) {
263 : // notifyMove is not called while parking
264 : // @note insertion delay when resuming after parking is included
265 3870 : updateParkingStopTime();
266 : }
267 29980177 : return true;
268 : }
269 :
270 :
271 : bool
272 29904011 : MSDevice_Tripinfo::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/,
273 : MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
274 29904011 : if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
275 1864685 : myArrivalTime = MSNet::getInstance()->getCurrentTimeStep();
276 1864685 : myArrivalReason = reason;
277 1864685 : if (!MSGlobals::gUseMesoSim) {
278 1376283 : myArrivalLane = static_cast<MSVehicle&>(veh).getLane()->getID();
279 1376283 : myArrivalPosLat = static_cast<MSVehicle&>(veh).getLateralPositionOnLane();
280 : } else {
281 488402 : myArrivalLane = veh.getEdge()->getFirstAllowed(veh.getVClass(), true)->getID();
282 : }
283 : // @note vehicle may have moved past its arrivalPos during the last step
284 : // due to non-zero arrivalspeed but we consider it as arrived at the desired position
285 : // However, vaporization may happen anywhere (via TraCI)
286 1864685 : if (reason > MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED) {
287 : // vaporized
288 549 : myArrivalPos = veh.getPositionOnLane();
289 : } else {
290 1864136 : myArrivalPos = myHolder.getArrivalPos();
291 : }
292 1864685 : myArrivalSpeed = veh.getSpeed();
293 1864685 : updateParkingStopTime();
294 28039326 : } else if (reason == MSMoveReminder::NOTIFICATION_PARKING) {
295 4708 : myParkingStarted = MSNet::getInstance()->getCurrentTimeStep();
296 28034618 : } else if (reason == NOTIFICATION_JUNCTION
297 28034618 : || reason == NOTIFICATION_TELEPORT
298 12673168 : || reason == NOTIFICATION_TELEPORT_CONTINUATION) {
299 15366921 : if (MSGlobals::gUseMesoSim) {
300 2632833 : myRouteLength += myHolder.getCurrentEdge()->getLength();
301 : } else {
302 12734088 : const MSLane* lane = static_cast<MSVehicle&>(veh).getLane();
303 12734088 : if (lane != nullptr) {
304 12734064 : myRouteLength += lane->getLength();
305 : }
306 : }
307 : }
308 29904011 : return true;
309 : }
310 :
311 :
312 : void
313 1902101 : MSDevice_Tripinfo::generateOutput(OutputDevice* tripinfoOut) const {
314 1902101 : const SUMOTime timeLoss = MSGlobals::gUseMesoSim ? myMesoTimeLoss : static_cast<MSVehicle&>(myHolder).getTimeLoss();
315 1902101 : const double routeLength = myRouteLength + (myArrivalTime == NOT_ARRIVED ? myHolder.getPositionOnLane() : myArrivalPos);
316 : SUMOTime duration = 0;
317 1902101 : if (myHolder.hasDeparted()) {
318 1939243 : duration = (myArrivalTime == NOT_ARRIVED ? SIMSTEP : myArrivalTime) - myHolder.getDeparture();
319 1901857 : const SUMOTime drivingDuration = duration - myStoppingTime;
320 1901857 : const double speed = drivingDuration > 0 ? routeLength / STEPS2TIME(drivingDuration) : 0;
321 1901857 : if (myHolder.getVClass() == SVC_BICYCLE) {
322 25602 : myBikeCount++;
323 25602 : myTotalBikeRouteLength += routeLength;
324 25602 : myTotalBikeSpeed += speed;
325 25602 : myTotalBikeDuration += duration;
326 25602 : myTotalBikeWaitingTime += myWaitingTime;
327 25602 : myTotalBikeTimeLoss += timeLoss;
328 25602 : myTotalBikeDepartDelay += myHolder.getDepartDelay();
329 : } else {
330 1876255 : myVehicleCount++;
331 1876255 : myTotalRouteLength += routeLength;
332 1876255 : myTotalSpeed += speed;
333 1876255 : myTotalDuration += duration;
334 1876255 : myTotalWaitingTime += myWaitingTime;
335 1876255 : myTotalTimeLoss += timeLoss;
336 1876255 : myTotalDepartDelay += myHolder.getDepartDelay();
337 : }
338 : }
339 :
340 1902101 : myPendingOutput.erase(this);
341 1902101 : if (tripinfoOut == nullptr) {
342 1658327 : return;
343 : }
344 : // write
345 : OutputDevice& os = *tripinfoOut;
346 243774 : os.openTag("tripinfo").writeAttr("id", myHolder.getID());
347 243774 : os.writeAttr("depart", myHolder.hasDeparted() ? time2string(myHolder.getDeparture()) : "-1");
348 243774 : os.writeAttr("departLane", myDepartLane);
349 243774 : os.writeAttr("departPos", myHolder.getDepartPos());
350 243774 : if (MSGlobals::gLateralResolution > 0) {
351 26150 : os.writeAttr("departPosLat", myDepartPosLat);
352 : }
353 243774 : os.writeAttr("departSpeed", myDepartSpeed);
354 243774 : SUMOTime departDelay = myHolder.getDepartDelay();
355 243774 : const SUMOVehicleParameter& param = myHolder.getParameter();
356 243774 : if (!myHolder.hasDeparted()) {
357 : assert(param.depart <= SIMSTEP || param.departProcedure != DepartDefinition::GIVEN);
358 244 : departDelay = SIMSTEP - param.depart;
359 : }
360 243774 : os.writeAttr("departDelay", time2string(departDelay));
361 243774 : os.writeAttr("arrival", time2string(myArrivalTime));
362 243774 : os.writeAttr("arrivalLane", myArrivalLane);
363 243774 : os.writeAttr("arrivalPos", myArrivalPos);
364 243774 : if (MSGlobals::gLateralResolution > 0) {
365 26150 : os.writeAttr("arrivalPosLat", myArrivalPosLat);
366 : }
367 243774 : os.writeAttr("arrivalSpeed", myArrivalSpeed);
368 243774 : os.writeAttr("duration", time2string(duration));
369 243774 : os.writeAttr("routeLength", routeLength);
370 243774 : os.writeAttr(SUMO_ATTR_WAITINGTIME, time2string(myWaitingTime));
371 243774 : os.writeAttr(SUMO_ATTR_WAITINGCOUNT, myWaitingCount);
372 243774 : os.writeAttr(SUMO_ATTR_STOPTIME, time2string(myStoppingTime));
373 243774 : os.writeAttr(SUMO_ATTR_TIMELOSS, time2string(timeLoss));
374 243774 : os.writeAttr("rerouteNo", myHolder.getNumberReroutes());
375 487548 : os.writeAttr("devices", toString(myHolder.getDevices()));
376 243774 : os.writeAttr("vType", myHolder.getVehicleType().getID());
377 243774 : os.writeAttr("speedFactor", myHolder.getChosenSpeedFactor());
378 : std::string vaporized;
379 243774 : switch (myArrivalReason) {
380 : case MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR:
381 : vaporized = "calibrator";
382 : break;
383 : case MSMoveReminder::NOTIFICATION_VAPORIZED_GUI:
384 : vaporized = "gui";
385 : break;
386 : case MSMoveReminder::NOTIFICATION_VAPORIZED_COLLISION:
387 : vaporized = "collision";
388 : break;
389 : case MSMoveReminder::NOTIFICATION_VAPORIZED_VAPORIZER:
390 : vaporized = "vaporizer";
391 : break;
392 : case MSMoveReminder::NOTIFICATION_VAPORIZED_TRACI:
393 : vaporized = "traci";
394 : break;
395 : case MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED:
396 : vaporized = "teleport";
397 : break;
398 243371 : default:
399 243371 : if (myHolder.getEdge() == myHolder.getRoute().getLastEdge() ||
400 1632 : (param.arrivalEdge >= 0 && myHolder.getRoutePosition() >= param.arrivalEdge)) {
401 : vaporized = "";
402 : } else {
403 : vaporized = "end";
404 : }
405 : break;
406 : }
407 243774 : os.writeAttr("vaporized", vaporized);
408 : // cannot close tag because emission device output might follow
409 : }
410 :
411 :
412 : void
413 1114 : MSDevice_Tripinfo::generateOutputForUnfinished() {
414 1114 : MSNet* net = MSNet::getInstance();
415 1114 : OutputDevice* tripinfoOut = (OptionsCont::getOptions().isSet("tripinfo-output") ?
416 1965 : &OutputDevice::getDeviceByOption("tripinfo-output") : nullptr);
417 1114 : myWaitingDepartDelay = 0;
418 1114 : myUndepartedVehicleCount = 0;
419 2228 : const bool writeUndeparted = OptionsCont::getOptions().getBool("tripinfo-output.write-undeparted");
420 : const SUMOTime t = net->getCurrentTimeStep();
421 69129 : while (myPendingOutput.size() > 0) {
422 68015 : const MSDevice_Tripinfo* d = *myPendingOutput.begin();
423 68015 : const bool departed = d->myHolder.hasDeparted();
424 68015 : const bool departDelayed = d->myHolder.getParameter().depart <= t;
425 68015 : if (!departed && departDelayed) {
426 31949 : myUndepartedVehicleCount++;
427 31949 : myWaitingDepartDelay += (t - d->myHolder.getParameter().depart);
428 : }
429 68015 : if (departed || (writeUndeparted && departDelayed)) {
430 36298 : const_cast<MSDevice_Tripinfo*>(d)->updateParkingStopTime();
431 36298 : d->generateOutput(tripinfoOut);
432 36298 : if (tripinfoOut != nullptr) {
433 8048 : for (MSVehicleDevice* const dev : d->myHolder.getDevices()) {
434 5773 : if (typeid(*dev) == typeid(MSDevice_Tripinfo) || typeid(*dev) == typeid(MSDevice_Vehroutes)) {
435 : // tripinfo is special and vehroute has its own write-unfinished option
436 2947 : continue;
437 : }
438 2826 : dev->generateOutput(tripinfoOut);
439 : }
440 4550 : OutputDevice::getDeviceByOption("tripinfo-output").closeTag();
441 : }
442 : } else {
443 : myPendingOutput.erase(d);
444 : }
445 : }
446 : // unfinished persons
447 1114 : if (net->hasPersons()) {
448 646 : net->getPersonControl().eraseAll();
449 : }
450 :
451 1114 : }
452 :
453 :
454 : void
455 55558 : MSDevice_Tripinfo::addPedestrianData(double walkLength, SUMOTime walkDuration, SUMOTime walkTimeLoss) {
456 55558 : myWalkCount++;
457 55558 : myTotalWalkRouteLength += walkLength;
458 55558 : myTotalWalkDuration += walkDuration;
459 55558 : myTotalWalkTimeLoss += walkTimeLoss;
460 55558 : }
461 :
462 :
463 : void
464 7626 : MSDevice_Tripinfo::addRideTransportData(const bool isPerson, const double distance, const SUMOTime duration,
465 : const SUMOVehicleClass vClass, const std::string& line, const SUMOTime waitingTime) {
466 7626 : const int index = isPerson ? 0 : 1;
467 7626 : myRideCount[index]++;
468 7626 : if (duration > 0) {
469 7289 : myTotalRideWaitingTime[index] += waitingTime;
470 7289 : myTotalRideRouteLength[index] += distance;
471 7289 : myTotalRideDuration[index] += duration;
472 7289 : if (vClass == SVC_BICYCLE) {
473 25 : myRideBikeCount[index]++;
474 7264 : } else if (!line.empty()) {
475 6046 : if (isRailway(vClass)) {
476 847 : myRideRailCount[index]++;
477 5199 : } else if (vClass == SVC_TAXI) {
478 1941 : myRideTaxiCount[index]++;
479 : } else {
480 : // some kind of road vehicle
481 3258 : myRideBusCount[index]++;
482 : }
483 : }
484 : } else {
485 337 : myRideAbortCount[index]++;
486 : }
487 7626 : }
488 :
489 :
490 : std::string
491 3527 : MSDevice_Tripinfo::printStatistics() {
492 3527 : std::ostringstream msg;
493 : msg.setf(msg.fixed);
494 3527 : msg.precision(gPrecision);
495 3527 : if (myBikeCount == 0 || myVehicleCount > 0) {
496 3456 : msg << "Statistics (avg of " << myVehicleCount << "):\n";
497 3456 : msg << " RouteLength: " << getAvgRouteLength() << "\n"
498 3456 : << " Speed: " << getAvgTripSpeed() << "\n"
499 3456 : << " Duration: " << getAvgDuration() << "\n"
500 3456 : << " WaitingTime: " << getAvgWaitingTime() << "\n"
501 3456 : << " TimeLoss: " << getAvgTimeLoss() << "\n"
502 6912 : << " DepartDelay: " << getAvgDepartDelay() << "\n";
503 : }
504 3527 : if (myBikeCount > 0) {
505 : msg << "Bike Statistics (avg of " << myBikeCount << "):\n"
506 320 : << " RouteLength: " << getAvgBikeRouteLength() << "\n"
507 160 : << " Speed: " << getAvgBikeTripSpeed() << "\n"
508 160 : << " Duration: " << getAvgBikeDuration() << "\n"
509 160 : << " WaitingTime: " << getAvgBikeWaitingTime() << "\n"
510 160 : << " TimeLoss: " << getAvgBikeTimeLoss() << "\n"
511 320 : << " DepartDelay: " << getAvgBikeDepartDelay() << "\n";
512 160 : if (myVehicleCount > 0 && myWaitingDepartDelay >= 0) {
513 19 : msg << "Statistics (avg of " << (myVehicleCount + myBikeCount) << "):\n";
514 : }
515 : }
516 3527 : if (myWaitingDepartDelay >= 0) {
517 828 : msg << " DepartDelayWaiting: " << getAvgDepartDelayWaiting() << "\n";
518 : }
519 3527 : if (myWalkCount > 0) {
520 : msg << "Pedestrian Statistics (avg of " << myWalkCount << " walks):\n"
521 600 : << " RouteLength: " << getAvgWalkRouteLength() << "\n"
522 300 : << " Duration: " << getAvgWalkDuration() << "\n"
523 600 : << " TimeLoss: " << getAvgWalkTimeLoss() << "\n";
524 : }
525 7054 : printRideStatistics(msg, "Ride", "rides", 0);
526 7054 : printRideStatistics(msg, "Transport", "transports", 1);
527 3527 : return msg.str();
528 3527 : }
529 :
530 : void
531 7054 : MSDevice_Tripinfo::printRideStatistics(std::ostringstream& msg, const std::string& category, const std::string& modeName, const int index) {
532 7054 : if (myRideCount[index] > 0) {
533 441 : msg << category << " Statistics (avg of " << myRideCount[index] << " " << modeName << "):\n";
534 147 : msg << " WaitingTime: " << STEPS2TIME(myTotalRideWaitingTime[index] / myRideCount[index]) << "\n";
535 147 : msg << " RouteLength: " << myTotalRideRouteLength[index] / myRideCount[index] << "\n";
536 147 : msg << " Duration: " << STEPS2TIME(myTotalRideDuration[index] / myRideCount[index]) << "\n";
537 147 : if (myRideBusCount[index] > 0) {
538 15 : msg << " Bus: " << myRideBusCount[index] << "\n";
539 : }
540 147 : if (myRideRailCount[index] > 0) {
541 10 : msg << " Train: " << myRideRailCount[index] << "\n";
542 : }
543 147 : if (myRideTaxiCount[index] > 0) {
544 93 : msg << " Taxi: " << myRideTaxiCount[index] << "\n";
545 : }
546 147 : if (myRideBikeCount[index] > 0) {
547 19 : msg << " Bike: " << myRideBikeCount[index] << "\n";
548 : }
549 147 : if (myRideAbortCount[index] > 0) {
550 13 : msg << " Aborted: " << myRideAbortCount[index] << "\n";
551 : }
552 : }
553 :
554 7054 : }
555 :
556 :
557 : void
558 264 : MSDevice_Tripinfo::writeStatistics(OutputDevice& od) {
559 264 : od.setPrecision(gPrecision);
560 264 : od.openTag("vehicleTripStatistics");
561 264 : od.writeAttr("count", myVehicleCount);
562 264 : od.writeAttr("routeLength", getAvgRouteLength());
563 264 : od.writeAttr("speed", getAvgTripSpeed());
564 264 : od.writeAttr("duration", getAvgDuration());
565 264 : od.writeAttr("waitingTime", getAvgWaitingTime());
566 264 : od.writeAttr("timeLoss", getAvgTimeLoss());
567 264 : od.writeAttr("departDelay", getAvgDepartDelay());
568 264 : od.writeAttr("departDelayWaiting", getAvgDepartDelayWaiting());
569 264 : od.writeAttr("totalTravelTime", time2string(myTotalDuration));
570 264 : od.writeAttr("totalDepartDelay", time2string(TIME2STEPS(getTotalDepartDelay() + getTotalBikeDepartDelay())));
571 264 : od.closeTag();
572 264 : if (myBikeCount > 0) {
573 6 : od.openTag("bikeTripStatistics");
574 6 : od.writeAttr("count", myBikeCount);
575 6 : od.writeAttr("routeLength", getAvgBikeRouteLength());
576 6 : od.writeAttr("speed", getAvgBikeTripSpeed());
577 6 : od.writeAttr("duration", getAvgBikeDuration());
578 6 : od.writeAttr("waitingTime", getAvgBikeWaitingTime());
579 6 : od.writeAttr("timeLoss", getAvgBikeTimeLoss());
580 6 : od.writeAttr("departDelay", getAvgBikeDepartDelay());
581 6 : od.writeAttr("totalTravelTime", time2string(myTotalBikeDuration));
582 12 : od.closeTag();
583 : }
584 264 : od.openTag("pedestrianStatistics");
585 264 : od.writeAttr("number", myWalkCount);
586 264 : od.writeAttr("routeLength", getAvgWalkRouteLength());
587 264 : od.writeAttr("duration", getAvgWalkDuration());
588 264 : od.writeAttr("timeLoss", getAvgWalkTimeLoss());
589 264 : od.closeTag();
590 264 : writeRideStatistics(od, "rideStatistics", 0);
591 264 : writeRideStatistics(od, "transportStatistics", 1);
592 264 : }
593 :
594 : void
595 528 : MSDevice_Tripinfo::writeRideStatistics(OutputDevice& od, const std::string& category, const int index) {
596 528 : od.openTag(category);
597 528 : od.writeAttr("number", myRideCount[index]);
598 528 : if (myRideCount[index] > 0) {
599 2 : od.writeAttr("waitingTime", STEPS2TIME(myTotalRideWaitingTime[index] / myRideCount[index]));
600 2 : od.writeAttr("routeLength", myTotalRideRouteLength[index] / myRideCount[index]);
601 2 : od.writeAttr("duration", STEPS2TIME(myTotalRideDuration[index] / myRideCount[index]));
602 2 : od.writeAttr("bus", myRideBusCount[index]);
603 2 : od.writeAttr("train", myRideRailCount[index]);
604 2 : od.writeAttr("taxi", myRideTaxiCount[index]);
605 2 : od.writeAttr("bike", myRideBikeCount[index]);
606 2 : od.writeAttr("aborted", myRideAbortCount[index]);
607 : }
608 528 : od.closeTag();
609 528 : }
610 :
611 :
612 : double
613 3836 : MSDevice_Tripinfo::getAvgRouteLength() {
614 3836 : if (myVehicleCount > 0) {
615 3582 : return myTotalRouteLength / myVehicleCount;
616 : } else {
617 : return 0;
618 : }
619 : }
620 :
621 : double
622 3836 : MSDevice_Tripinfo::getAvgTripSpeed() {
623 3836 : if (myVehicleCount > 0) {
624 3582 : return myTotalSpeed / myVehicleCount;
625 : } else {
626 : return 0;
627 : }
628 : }
629 :
630 : double
631 3836 : MSDevice_Tripinfo::getAvgDuration() {
632 3836 : if (myVehicleCount > 0) {
633 3582 : return STEPS2TIME(myTotalDuration / myVehicleCount);
634 : } else {
635 : return 0;
636 : }
637 : }
638 :
639 : double
640 3836 : MSDevice_Tripinfo::getAvgWaitingTime() {
641 3836 : if (myVehicleCount > 0) {
642 3582 : return STEPS2TIME(myTotalWaitingTime / myVehicleCount);
643 : } else {
644 : return 0;
645 : }
646 : }
647 :
648 :
649 : double
650 3836 : MSDevice_Tripinfo::getAvgTimeLoss() {
651 3836 : if (myVehicleCount > 0) {
652 3582 : return STEPS2TIME(myTotalTimeLoss / myVehicleCount);
653 : } else {
654 : return 0;
655 : }
656 : }
657 :
658 :
659 : double
660 3836 : MSDevice_Tripinfo::getAvgDepartDelay() {
661 3836 : if (myVehicleCount > 0) {
662 3582 : return STEPS2TIME(myTotalDepartDelay / myVehicleCount);
663 : } else {
664 : return 0;
665 : }
666 : }
667 :
668 : double
669 794 : MSDevice_Tripinfo::getAvgDepartDelayWaiting() {
670 794 : if (myWaitingDepartDelay >= 0) {
671 426 : return STEPS2TIME(myWaitingDepartDelay / MAX2(1, myUndepartedVehicleCount));
672 : } else {
673 : return -1;
674 : }
675 : }
676 :
677 :
678 : double
679 380 : MSDevice_Tripinfo::getTotalDepartDelay() {
680 380 : return STEPS2TIME(myTotalDepartDelay + MAX2((SUMOTime)0, myWaitingDepartDelay));
681 : }
682 :
683 : double
684 224 : MSDevice_Tripinfo::getAvgBikeRouteLength() {
685 224 : if (myBikeCount > 0) {
686 166 : return myTotalBikeRouteLength / myBikeCount;
687 : } else {
688 : return 0;
689 : }
690 : }
691 :
692 : double
693 224 : MSDevice_Tripinfo::getAvgBikeTripSpeed() {
694 224 : if (myBikeCount > 0) {
695 166 : return myTotalBikeSpeed / myBikeCount;
696 : } else {
697 : return 0;
698 : }
699 : }
700 :
701 : double
702 224 : MSDevice_Tripinfo::getAvgBikeDuration() {
703 224 : if (myBikeCount > 0) {
704 166 : return STEPS2TIME(myTotalBikeDuration / myBikeCount);
705 : } else {
706 : return 0;
707 : }
708 : }
709 :
710 : double
711 224 : MSDevice_Tripinfo::getAvgBikeWaitingTime() {
712 224 : if (myBikeCount > 0) {
713 166 : return STEPS2TIME(myTotalBikeWaitingTime / myBikeCount);
714 : } else {
715 : return 0;
716 : }
717 : }
718 :
719 :
720 : double
721 224 : MSDevice_Tripinfo::getAvgBikeTimeLoss() {
722 224 : if (myBikeCount > 0) {
723 166 : return STEPS2TIME(myTotalBikeTimeLoss / myBikeCount);
724 : } else {
725 : return 0;
726 : }
727 : }
728 :
729 : double
730 166 : MSDevice_Tripinfo::getAvgBikeDepartDelay() {
731 166 : if (myBikeCount > 0) {
732 166 : return STEPS2TIME(myTotalBikeDepartDelay / myBikeCount);
733 : } else {
734 : return 0;
735 : }
736 : }
737 :
738 :
739 : double
740 264 : MSDevice_Tripinfo::getTotalBikeDepartDelay() {
741 264 : return STEPS2TIME(myTotalBikeDepartDelay);
742 : }
743 :
744 : double
745 622 : MSDevice_Tripinfo::getAvgWalkRouteLength() {
746 622 : if (myWalkCount > 0) {
747 306 : return myTotalWalkRouteLength / myWalkCount;
748 : } else {
749 : return 0;
750 : }
751 : }
752 :
753 : double
754 622 : MSDevice_Tripinfo::getAvgWalkDuration() {
755 622 : if (myWalkCount > 0) {
756 306 : return STEPS2TIME(myTotalWalkDuration / myWalkCount);
757 : } else {
758 : return 0;
759 : }
760 : }
761 :
762 :
763 : double
764 622 : MSDevice_Tripinfo::getAvgWalkTimeLoss() {
765 622 : if (myWalkCount > 0) {
766 306 : return STEPS2TIME(myTotalWalkTimeLoss / myWalkCount);
767 : } else {
768 : return 0;
769 : }
770 : }
771 :
772 :
773 : double
774 0 : MSDevice_Tripinfo::getAvgRideDuration() {
775 0 : if (myRideCount[0] > 0) {
776 0 : return STEPS2TIME(myTotalRideDuration[0] / myRideCount[0]);
777 : } else {
778 : return 0;
779 : }
780 : }
781 :
782 : double
783 0 : MSDevice_Tripinfo::getAvgRideWaitingTime() {
784 0 : if (myRideCount[0] > 0) {
785 0 : return STEPS2TIME(myTotalRideWaitingTime[0] / myRideCount[0]);
786 : } else {
787 : return 0;
788 : }
789 : }
790 :
791 : double
792 0 : MSDevice_Tripinfo::getAvgRideRouteLength() {
793 0 : if (myRideCount[0] > 0) {
794 0 : return myTotalRideRouteLength[0] / myRideCount[0];
795 : } else {
796 : return 0;
797 : }
798 : }
799 :
800 :
801 : std::string
802 254 : MSDevice_Tripinfo::getParameter(const std::string& key) const {
803 254 : if (key == toString(SUMO_ATTR_WAITINGTIME)) {
804 48 : return toString(STEPS2TIME(myWaitingTime));
805 206 : } else if (key == toString(SUMO_ATTR_WAITINGCOUNT)) {
806 48 : return toString(myWaitingCount);
807 158 : } else if (key == toString(SUMO_ATTR_STOPTIME)) {
808 48 : return toString(STEPS2TIME(myStoppingTime));
809 110 : } else if (key == toString(SUMO_ATTR_ARRIVALTIME)) {
810 22 : return toString(STEPS2TIME(myArrivalTime));
811 88 : } else if (key == toString(SUMO_ATTR_ARRIVALLANE)) {
812 : return toString(myArrivalLane);
813 66 : } else if (key == toString(SUMO_ATTR_ARRIVALPOS)) {
814 22 : return toString(myArrivalPos);
815 44 : } else if (key == toString(SUMO_ATTR_ARRIVALPOS_LAT)) {
816 22 : return toString(myArrivalPosLat);
817 22 : } else if (key == toString(SUMO_ATTR_ARRIVALSPEED)) {
818 22 : return toString(myArrivalSpeed);
819 : }
820 0 : throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
821 : }
822 :
823 :
824 : std::string
825 3016 : MSDevice_Tripinfo::getGlobalParameter(const std::string& prefixedKey) {
826 : std::string key = prefixedKey; // by default, assume vehicleTripStatistics;
827 3016 : const std::string err = "Parameter '" + prefixedKey + "' is not supported for device of type 'tripinfo'";
828 6032 : if (StringUtils::startsWith(key, "vehicleTripStatistics.")) {
829 1160 : key = prefixedKey.substr(22);
830 4872 : } else if (StringUtils::startsWith(key, "bikeTripStatistics.")) {
831 406 : key = prefixedKey.substr(19);
832 406 : if (key == toString(SUMO_ATTR_COUNT)) {
833 58 : return toString(myBikeCount);
834 348 : } else if (key == "routeLength") {
835 58 : return toString(getAvgBikeRouteLength());
836 290 : } else if (key == toString(SUMO_ATTR_SPEED)) {
837 58 : return toString(getAvgBikeTripSpeed());
838 232 : } else if (key == toString(SUMO_ATTR_DURATION)) {
839 58 : return toString(getAvgBikeDuration());
840 174 : } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
841 58 : return toString(getAvgBikeWaitingTime());
842 116 : } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
843 58 : return toString(getAvgBikeTimeLoss());
844 58 : } else if (key == "departDelay") {
845 0 : return toString(getAvgBikeDepartDelay());
846 58 : } else if (key == "totalTravelTime") {
847 : // avoid human readable output
848 58 : return toString(STEPS2TIME((myTotalBikeDuration)));
849 : }
850 0 : throw InvalidArgument(err);
851 :
852 4060 : } else if (StringUtils::startsWith(key, "pedestrianStatistics.")) {
853 290 : key = prefixedKey.substr(21);
854 522 : if (key == toString(SUMO_ATTR_NUMBER) || key == toString(SUMO_ATTR_COUNT)) {
855 116 : return toString(myWalkCount);
856 174 : } else if (key == "routeLength") {
857 58 : return toString(getAvgWalkRouteLength());
858 116 : } else if (key == toString(SUMO_ATTR_DURATION)) {
859 58 : return toString(getAvgWalkDuration());
860 58 : } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
861 58 : return toString(getAvgWalkTimeLoss());
862 : }
863 0 : throw InvalidArgument(err);
864 :
865 3480 : } else if (StringUtils::startsWith(key, "rideStatistics.") ||
866 2900 : StringUtils::startsWith(key, "transportStatistics.")) {
867 : int index = 0;
868 2320 : if (StringUtils::startsWith(key, "rideStatistics.")) {
869 1160 : key = prefixedKey.substr(15);
870 : } else {
871 : index = 1;
872 1160 : key = prefixedKey.substr(20);
873 : }
874 2204 : if (key == toString(SUMO_ATTR_NUMBER) || key == toString(SUMO_ATTR_COUNT)) {
875 232 : return toString(myRideCount[index]);
876 928 : } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
877 116 : return toString(STEPS2TIME(myTotalRideWaitingTime[index] / MAX2(1, myRideCount[index])));
878 812 : } else if (key == "routeLength") {
879 116 : return toString(myTotalRideRouteLength[index] / MAX2(1, myRideCount[index]));
880 696 : } else if (key == toString(SUMO_ATTR_DURATION)) {
881 116 : return toString(myTotalRideRouteLength[index] / MAX2(1, myRideCount[index]));
882 580 : } else if (key == "bus") {
883 116 : return toString(myRideBusCount[index]);
884 464 : } else if (key == "train") {
885 116 : return toString(myRideRailCount[index]);
886 348 : } else if (key == "taxi") {
887 116 : return toString(myRideTaxiCount[index]);
888 232 : } else if (key == "bike") {
889 116 : return toString(myRideBikeCount[index]);
890 116 : } else if (key == "aborted") {
891 116 : return toString(myRideAbortCount[index]);
892 : }
893 0 : throw InvalidArgument(err);
894 : }
895 : // vehicleTripStatistics
896 1160 : if (key == toString(SUMO_ATTR_COUNT)) {
897 116 : return toString(myVehicleCount);
898 1044 : } else if (key == "routeLength") {
899 116 : return toString(getAvgRouteLength());
900 928 : } else if (key == toString(SUMO_ATTR_SPEED)) {
901 116 : return toString(getAvgTripSpeed());
902 812 : } else if (key == toString(SUMO_ATTR_DURATION)) {
903 116 : return toString(getAvgDuration());
904 696 : } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
905 116 : return toString(getAvgWaitingTime());
906 580 : } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
907 116 : return toString(getAvgTimeLoss());
908 464 : } else if (key == "departDelay") {
909 116 : return toString(getAvgDepartDelay());
910 348 : } else if (key == "departDelayWaiting") {
911 116 : return toString(getAvgDepartDelayWaiting());
912 232 : } else if (key == "totalTravelTime") {
913 : // avoid human readable output
914 116 : return toString(STEPS2TIME((myTotalDuration)));
915 116 : } else if (key == "totalDepartDelay") {
916 116 : return toString(getTotalDepartDelay());
917 : }
918 0 : throw InvalidArgument(err);
919 : }
920 :
921 :
922 : void
923 396 : MSDevice_Tripinfo::saveState(OutputDevice& out) const {
924 : // always write device id to replicate stochastic assignment
925 396 : out.openTag(SUMO_TAG_DEVICE);
926 396 : out.writeAttr(SUMO_ATTR_ID, getID());
927 396 : if (myHolder.hasDeparted()) {
928 303 : std::ostringstream internals;
929 303 : internals << myDepartLane << " ";
930 303 : if (!MSGlobals::gUseMesoSim) {
931 221 : internals << myDepartPosLat << " ";
932 : }
933 303 : std::string state_arrivalLane = myArrivalLane == "" ? STATE_EMPTY_ARRIVALLANE : myArrivalLane;
934 1515 : internals << myDepartSpeed << " " << myRouteLength << " " << myWaitingTime << " " << myAmWaiting << " " << myWaitingCount << " ";
935 606 : internals << myStoppingTime << " " << myParkingStarted << " ";
936 1212 : internals << myArrivalTime << " " << state_arrivalLane << " " << myArrivalPos << " " << myArrivalPosLat << " " << myArrivalSpeed;
937 303 : out.writeAttr(SUMO_ATTR_STATE, internals.str());
938 303 : }
939 396 : out.closeTag();
940 396 : }
941 :
942 :
943 : void
944 357 : MSDevice_Tripinfo::loadState(const SUMOSAXAttributes& attrs) {
945 357 : if (attrs.hasAttribute(SUMO_ATTR_STATE)) {
946 282 : std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
947 282 : bis >> myDepartLane;
948 282 : if (!MSGlobals::gUseMesoSim) {
949 211 : bis >> myDepartPosLat;
950 : }
951 282 : bis >> myDepartSpeed >> myRouteLength >> myWaitingTime >> myAmWaiting >> myWaitingCount;
952 282 : bis >> myStoppingTime >> myParkingStarted;
953 282 : bis >> myArrivalTime >> myArrivalLane >> myArrivalPos >> myArrivalPosLat >> myArrivalSpeed;
954 282 : if (myArrivalLane == STATE_EMPTY_ARRIVALLANE) {
955 : myArrivalLane = "";
956 : }
957 282 : }
958 357 : }
959 :
960 :
961 : /****************************************************************************/
|