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