Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2009-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file 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 39784 : MSDevice_Tripinfo::insertOptions(OptionsCont& oc) {
87 39784 : oc.addOptionSubTopic("Tripinfo Device");
88 79568 : insertDefaultAssignmentOptions("tripinfo", "Tripinfo Device", oc);
89 39784 : }
90 :
91 :
92 : void
93 5371080 : MSDevice_Tripinfo::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
94 5371080 : OptionsCont& oc = OptionsCont::getOptions();
95 10480349 : const bool enableByOutputOption = oc.isSet("tripinfo-output") || oc.getBool("duration-log.statistics");
96 10742160 : if (equippedByDefaultAssignmentOptions(oc, "tripinfo", v, enableByOutputOption)) {
97 2123702 : MSDevice_Tripinfo* device = new MSDevice_Tripinfo(v, "tripinfo_" + v.getID());
98 2123702 : into.push_back(device);
99 : myPendingOutput.insert(device);
100 : }
101 5371080 : }
102 :
103 :
104 : // ---------------------------------------------------------------------------
105 : // MSDevice_Tripinfo-methods
106 : // ---------------------------------------------------------------------------
107 2123702 : MSDevice_Tripinfo::MSDevice_Tripinfo(SUMOVehicle& holder, const std::string& id) :
108 : MSVehicleDevice(holder, id),
109 0 : myDepartLane(""),
110 2123702 : myDepartSpeed(-1),
111 2123702 : myDepartPosLat(0),
112 2123702 : myWaitingTime(0),
113 2123702 : myAmWaiting(false),
114 2123702 : myWaitingCount(0),
115 2123702 : myStoppingTime(0),
116 2123702 : myParkingStarted(-1),
117 2123702 : myArrivalTime(NOT_ARRIVED),
118 2123702 : myArrivalLane(""),
119 2123702 : myArrivalPos(-1),
120 2123702 : myArrivalPosLat(0.),
121 2123702 : myArrivalSpeed(-1),
122 2123702 : myArrivalReason(MSMoveReminder::NOTIFICATION_ARRIVED),
123 2123702 : myMesoTimeLoss(0),
124 2123702 : myRouteLength(0.) {
125 2123702 : }
126 :
127 :
128 4247354 : MSDevice_Tripinfo::~MSDevice_Tripinfo() {
129 : // ensure clean up for vaporized vehicles which do not generate output
130 2123677 : myPendingOutput.erase(this);
131 4247354 : }
132 :
133 : void
134 38670 : MSDevice_Tripinfo::cleanup() {
135 38670 : myVehicleCount = 0;
136 38670 : myTotalRouteLength = 0;
137 38670 : myTotalSpeed = 0;
138 38670 : myTotalDuration = 0;
139 38670 : myTotalWaitingTime = 0;
140 38670 : myTotalTimeLoss = 0;
141 38670 : myTotalDepartDelay = 0;
142 38670 : myWaitingDepartDelay = -1;
143 :
144 38670 : myBikeCount = 0;
145 38670 : myTotalBikeRouteLength = 0;
146 38670 : myTotalBikeSpeed = 0;
147 38670 : myTotalBikeDuration = 0;
148 38670 : myTotalBikeWaitingTime = 0;
149 38670 : myTotalBikeTimeLoss = 0;
150 38670 : myTotalBikeDepartDelay = 0;
151 :
152 38670 : myWalkCount = 0;
153 38670 : myTotalWalkRouteLength = 0;
154 38670 : myTotalWalkDuration = 0;
155 38670 : myTotalWalkTimeLoss = 0;
156 :
157 38670 : myRideCount = {0, 0};
158 38670 : myRideBusCount = {0, 0};
159 38670 : myRideRailCount = {0, 0};
160 38670 : myRideTaxiCount = {0, 0};
161 38670 : myRideBikeCount = {0, 0};
162 38670 : myRideAbortCount = {0, 0};
163 38670 : myTotalRideWaitingTime = {0, 0};
164 38670 : myTotalRideRouteLength = {0., 0.};
165 38670 : myTotalRideDuration = {0, 0};
166 38670 : }
167 :
168 : bool
169 3518 : MSDevice_Tripinfo::notifyIdle(SUMOTrafficObject& veh) {
170 3518 : if (veh.isVehicle()) {
171 3518 : myWaitingTime += DELTA_T;
172 3518 : if (!myAmWaiting) {
173 130 : myWaitingCount++;
174 130 : myAmWaiting = true;
175 : }
176 : }
177 3518 : return true;
178 : }
179 :
180 :
181 : bool
182 336642236 : MSDevice_Tripinfo::notifyMove(SUMOTrafficObject& veh, double /*oldPos*/,
183 : double /*newPos*/, double newSpeed) {
184 336642236 : if (veh.isStopped()) {
185 1931365 : if (newSpeed <= SUMO_const_haltingSpeed) {
186 1931181 : myStoppingTime += DELTA_T;
187 : }
188 334710871 : } else if (newSpeed <= SUMO_const_haltingSpeed && lowAcceleration(veh)) {
189 50316363 : myWaitingTime += DELTA_T;
190 50316363 : if (!myAmWaiting) {
191 2516933 : myWaitingCount++;
192 2516933 : myAmWaiting = true;
193 : }
194 : } else {
195 284394508 : myAmWaiting = false;
196 : }
197 336642236 : return true;
198 : }
199 :
200 :
201 : bool
202 50317220 : MSDevice_Tripinfo::lowAcceleration(const SUMOTrafficObject& veh) {
203 50317220 : if (MSGlobals::gUseMesoSim) {
204 : // acceleration is not modelled
205 : return false;
206 : } else {
207 50317220 : const MSVehicle& v = dynamic_cast<const MSVehicle&>(veh);
208 50317220 : return v.getAcceleration() <= v.accelThresholdForWaiting();
209 : }
210 : }
211 :
212 :
213 : void
214 13247778 : 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 13247778 : const double vmax = veh.getEdge()->getVehicleMaxSpeed(&veh);
225 13247778 : if (vmax > 0) {
226 16141221 : myMesoTimeLoss += TIME2STEPS(timeOnLane * (vmax - meanSpeedVehicleOnLane) / vmax);
227 : }
228 13247778 : myWaitingTime += veh.getWaitingTime();
229 13247778 : }
230 :
231 :
232 : void
233 1594678 : MSDevice_Tripinfo::updateParkingStopTime() {
234 1594678 : if (myParkingStarted >= 0) {
235 3843 : myStoppingTime += (MSNet::getInstance()->getCurrentTimeStep() - myParkingStarted);
236 3843 : myParkingStarted = -1;
237 : }
238 1594678 : }
239 :
240 : bool
241 27155168 : MSDevice_Tripinfo::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
242 27155168 : if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
243 1624168 : if (!MSGlobals::gUseMesoSim) {
244 1262873 : myDepartLane = static_cast<MSVehicle&>(veh).getLane()->getID();
245 1262873 : myDepartPosLat = static_cast<MSVehicle&>(veh).getLateralPositionOnLane();
246 : } else {
247 361295 : myDepartLane = veh.getEdge()->getFirstAllowed(veh.getVClass(), true)->getID();
248 : }
249 1624168 : myDepartSpeed = veh.getSpeed();
250 1624168 : myRouteLength = -veh.getPositionOnLane();
251 25531000 : } else if (reason == MSMoveReminder::NOTIFICATION_PARKING) {
252 : // notifyMove is not called while parking
253 : // @note insertion delay when resuming after parking is included
254 3288 : updateParkingStopTime();
255 : }
256 27155168 : return true;
257 : }
258 :
259 :
260 : bool
261 27084689 : MSDevice_Tripinfo::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/,
262 : MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
263 27084689 : if (reason >= MSMoveReminder::NOTIFICATION_ARRIVED) {
264 1557931 : myArrivalTime = MSNet::getInstance()->getCurrentTimeStep();
265 1557931 : myArrivalReason = reason;
266 1557931 : if (!MSGlobals::gUseMesoSim) {
267 1201867 : myArrivalLane = static_cast<MSVehicle&>(veh).getLane()->getID();
268 1201867 : myArrivalPosLat = static_cast<MSVehicle&>(veh).getLateralPositionOnLane();
269 : } else {
270 356064 : myArrivalLane = veh.getEdge()->getFirstAllowed(veh.getVClass(), true)->getID();
271 : }
272 : // @note vehicle may have moved past its arrivalPos during the last step
273 : // due to non-zero arrivalspeed but we consider it as arrived at the desired position
274 : // However, vaporization may happen anywhere (via TraCI)
275 1557931 : if (reason > MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED) {
276 : // vaporized
277 546 : myArrivalPos = veh.getPositionOnLane();
278 : } else {
279 1557385 : myArrivalPos = myHolder.getArrivalPos();
280 : }
281 1557931 : myArrivalSpeed = veh.getSpeed();
282 1557931 : updateParkingStopTime();
283 25526758 : } else if (reason == MSMoveReminder::NOTIFICATION_PARKING) {
284 3996 : myParkingStarted = MSNet::getInstance()->getCurrentTimeStep();
285 25522762 : } else if (reason == NOTIFICATION_JUNCTION
286 25522762 : || reason == NOTIFICATION_TELEPORT
287 12344779 : || reason == NOTIFICATION_TELEPORT_CONTINUATION) {
288 13183289 : if (MSGlobals::gUseMesoSim) {
289 1346644 : myRouteLength += myHolder.getEdge()->getLength();
290 : } else {
291 11836645 : const MSLane* lane = static_cast<MSVehicle&>(veh).getLane();
292 11836645 : if (lane != nullptr) {
293 11836621 : myRouteLength += lane->getLength();
294 : }
295 : }
296 : }
297 27084689 : return true;
298 : }
299 :
300 :
301 : void
302 1591214 : MSDevice_Tripinfo::generateOutput(OutputDevice* tripinfoOut) const {
303 1591214 : const SUMOTime timeLoss = MSGlobals::gUseMesoSim ? myMesoTimeLoss : static_cast<MSVehicle&>(myHolder).getTimeLoss();
304 1591214 : const double routeLength = myRouteLength + (myArrivalTime == NOT_ARRIVED ? myHolder.getPositionOnLane() : myArrivalPos);
305 : SUMOTime duration = 0;
306 1591214 : if (myHolder.hasDeparted()) {
307 1624223 : duration = (myArrivalTime == NOT_ARRIVED ? SIMSTEP : myArrivalTime) - myHolder.getDeparture();
308 1590970 : if (myHolder.getVClass() == SVC_BICYCLE) {
309 25127 : myBikeCount++;
310 25127 : myTotalBikeRouteLength += routeLength;
311 25127 : myTotalBikeSpeed += routeLength / STEPS2TIME(duration);
312 25127 : myTotalBikeDuration += duration;
313 25127 : myTotalBikeWaitingTime += myWaitingTime;
314 25127 : myTotalBikeTimeLoss += timeLoss;
315 25127 : myTotalBikeDepartDelay += myHolder.getDepartDelay();
316 : } else {
317 1565843 : myVehicleCount++;
318 1565843 : myTotalRouteLength += routeLength;
319 1565843 : myTotalSpeed += routeLength / STEPS2TIME(duration);
320 1565843 : myTotalDuration += duration;
321 1565843 : myTotalWaitingTime += myWaitingTime;
322 1565843 : myTotalTimeLoss += timeLoss;
323 1565843 : myTotalDepartDelay += myHolder.getDepartDelay();
324 : }
325 : }
326 :
327 1591214 : myPendingOutput.erase(this);
328 1591214 : if (tripinfoOut == nullptr) {
329 1356592 : return;
330 : }
331 : // write
332 : OutputDevice& os = *tripinfoOut;
333 469244 : os.openTag("tripinfo").writeAttr("id", myHolder.getID());
334 469244 : os.writeAttr("depart", myHolder.hasDeparted() ? time2string(myHolder.getDeparture()) : "-1");
335 234622 : os.writeAttr("departLane", myDepartLane);
336 234622 : os.writeAttr("departPos", myHolder.getDepartPos());
337 234622 : if (MSGlobals::gLateralResolution > 0) {
338 49992 : os.writeAttr("departPosLat", myDepartPosLat);
339 : }
340 234622 : os.writeAttr("departSpeed", myDepartSpeed);
341 234622 : SUMOTime departDelay = myHolder.getDepartDelay();
342 234622 : const SUMOVehicleParameter& param = myHolder.getParameter();
343 234622 : if (!myHolder.hasDeparted()) {
344 : assert(param.depart <= SIMSTEP || param.departProcedure != DepartDefinition::GIVEN);
345 244 : departDelay = SIMSTEP - param.depart;
346 : }
347 469244 : os.writeAttr("departDelay", time2string(departDelay));
348 469244 : os.writeAttr("arrival", time2string(myArrivalTime));
349 234622 : os.writeAttr("arrivalLane", myArrivalLane);
350 234622 : os.writeAttr("arrivalPos", myArrivalPos);
351 234622 : if (MSGlobals::gLateralResolution > 0) {
352 49992 : os.writeAttr("arrivalPosLat", myArrivalPosLat);
353 : }
354 234622 : os.writeAttr("arrivalSpeed", myArrivalSpeed);
355 469244 : os.writeAttr("duration", time2string(duration));
356 234622 : os.writeAttr("routeLength", routeLength);
357 234622 : os.writeAttr(SUMO_ATTR_WAITINGTIME, time2string(myWaitingTime));
358 234622 : os.writeAttr(SUMO_ATTR_WAITINGCOUNT, myWaitingCount);
359 234622 : os.writeAttr(SUMO_ATTR_STOPTIME, time2string(myStoppingTime));
360 234622 : os.writeAttr(SUMO_ATTR_TIMELOSS, time2string(timeLoss));
361 234622 : os.writeAttr("rerouteNo", myHolder.getNumberReroutes());
362 703866 : os.writeAttr("devices", toString(myHolder.getDevices()));
363 234622 : os.writeAttr("vType", myHolder.getVehicleType().getID());
364 469244 : os.writeAttr("speedFactor", myHolder.getChosenSpeedFactor());
365 : std::string vaporized;
366 234622 : switch (myArrivalReason) {
367 : case MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR:
368 : vaporized = "calibrator";
369 : break;
370 : case MSMoveReminder::NOTIFICATION_VAPORIZED_GUI:
371 : vaporized = "gui";
372 : break;
373 : case MSMoveReminder::NOTIFICATION_VAPORIZED_COLLISION:
374 : vaporized = "collision";
375 : break;
376 : case MSMoveReminder::NOTIFICATION_VAPORIZED_VAPORIZER:
377 : vaporized = "vaporizer";
378 : break;
379 : case MSMoveReminder::NOTIFICATION_VAPORIZED_TRACI:
380 : vaporized = "traci";
381 : break;
382 : case MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED:
383 : vaporized = "teleport";
384 : break;
385 234239 : default:
386 234239 : if (myHolder.getEdge() == myHolder.getRoute().getLastEdge() ||
387 1499 : (param.arrivalEdge >= 0 && myHolder.getRoutePosition() >= param.arrivalEdge)) {
388 : vaporized = "";
389 : } else {
390 : vaporized = "end";
391 : }
392 : break;
393 : }
394 469244 : os.writeAttr("vaporized", vaporized);
395 : // cannot close tag because emission device output might follow
396 : }
397 :
398 :
399 : void
400 911 : MSDevice_Tripinfo::generateOutputForUnfinished() {
401 911 : MSNet* net = MSNet::getInstance();
402 911 : OutputDevice* tripinfoOut = (OptionsCont::getOptions().isSet("tripinfo-output") ?
403 1567 : &OutputDevice::getDeviceByOption("tripinfo-output") : nullptr);
404 911 : myWaitingDepartDelay = 0;
405 911 : myUndepartedVehicleCount = 0;
406 1822 : const bool writeUndeparted = OptionsCont::getOptions().getBool("tripinfo-output.write-undeparted");
407 : const SUMOTime t = net->getCurrentTimeStep();
408 66089 : while (myPendingOutput.size() > 0) {
409 65178 : const MSDevice_Tripinfo* d = *myPendingOutput.begin();
410 65178 : const bool departed = d->myHolder.hasDeparted();
411 65178 : const bool departDelayed = d->myHolder.getParameter().depart <= t;
412 65178 : if (!departed && departDelayed) {
413 31951 : myUndepartedVehicleCount++;
414 31951 : myWaitingDepartDelay += (t - d->myHolder.getParameter().depart);
415 : }
416 65178 : if (departed || (writeUndeparted && departDelayed)) {
417 33459 : const_cast<MSDevice_Tripinfo*>(d)->updateParkingStopTime();
418 33459 : d->generateOutput(tripinfoOut);
419 33459 : if (tripinfoOut != nullptr) {
420 6568 : for (MSVehicleDevice* const dev : d->myHolder.getDevices()) {
421 4599 : if (typeid(*dev) == typeid(MSDevice_Tripinfo) || typeid(*dev) == typeid(MSDevice_Vehroutes)) {
422 : // tripinfo is special and vehroute has its own write-unfinished option
423 2423 : continue;
424 : }
425 2176 : dev->generateOutput(tripinfoOut);
426 : }
427 3938 : OutputDevice::getDeviceByOption("tripinfo-output").closeTag();
428 : }
429 : } else {
430 : myPendingOutput.erase(d);
431 : }
432 : }
433 : // unfinished persons
434 911 : if (net->hasPersons()) {
435 551 : MSTransportableControl& pc = net->getPersonControl();
436 767 : while (pc.loadedBegin() != pc.loadedEnd()) {
437 216 : pc.erase(pc.loadedBegin()->second);
438 : }
439 : }
440 :
441 911 : }
442 :
443 :
444 : void
445 55168 : MSDevice_Tripinfo::addPedestrianData(double walkLength, SUMOTime walkDuration, SUMOTime walkTimeLoss) {
446 55168 : myWalkCount++;
447 55168 : myTotalWalkRouteLength += walkLength;
448 55168 : myTotalWalkDuration += walkDuration;
449 55168 : myTotalWalkTimeLoss += walkTimeLoss;
450 55168 : }
451 :
452 :
453 : void
454 6928 : MSDevice_Tripinfo::addRideTransportData(const bool isPerson, const double distance, const SUMOTime duration,
455 : const SUMOVehicleClass vClass, const std::string& line, const SUMOTime waitingTime) {
456 6928 : const int index = isPerson ? 0 : 1;
457 6928 : myRideCount[index]++;
458 6928 : if (duration > 0) {
459 6663 : myTotalRideWaitingTime[index] += waitingTime;
460 6663 : myTotalRideRouteLength[index] += distance;
461 6663 : myTotalRideDuration[index] += duration;
462 6663 : if (vClass == SVC_BICYCLE) {
463 13 : myRideBikeCount[index]++;
464 6650 : } else if (!line.empty()) {
465 5441 : if (isRailway(vClass)) {
466 817 : myRideRailCount[index]++;
467 4624 : } else if (vClass == SVC_TAXI) {
468 1444 : myRideTaxiCount[index]++;
469 : } else {
470 : // some kind of road vehicle
471 3180 : myRideBusCount[index]++;
472 : }
473 : }
474 : } else {
475 265 : myRideAbortCount[index]++;
476 : }
477 6928 : }
478 :
479 :
480 : std::string
481 2911 : MSDevice_Tripinfo::printStatistics() {
482 2911 : std::ostringstream msg;
483 : msg.setf(msg.fixed);
484 2911 : msg.precision(gPrecision);
485 2911 : if (myBikeCount == 0 || myVehicleCount > 0) {
486 2845 : msg << "Statistics (avg of " << myVehicleCount << "):\n";
487 2845 : msg << " RouteLength: " << getAvgRouteLength() << "\n"
488 2845 : << " Speed: " << getAvgTripSpeed() << "\n"
489 2845 : << " Duration: " << getAvgDuration() << "\n"
490 2845 : << " WaitingTime: " << getAvgWaitingTime() << "\n"
491 2845 : << " TimeLoss: " << getAvgTimeLoss() << "\n"
492 5690 : << " DepartDelay: " << getAvgDepartDelay() << "\n";
493 : }
494 2911 : if (myBikeCount > 0) {
495 : msg << "Bike Statistics (avg of " << myBikeCount << "):\n"
496 302 : << " RouteLength: " << getAvgBikeRouteLength() << "\n"
497 151 : << " Speed: " << getAvgBikeTripSpeed() << "\n"
498 151 : << " Duration: " << getAvgBikeDuration() << "\n"
499 151 : << " WaitingTime: " << getAvgBikeWaitingTime() << "\n"
500 151 : << " TimeLoss: " << getAvgBikeTimeLoss() << "\n"
501 302 : << " DepartDelay: " << getAvgBikeDepartDelay() << "\n";
502 151 : if (myVehicleCount > 0 && myWaitingDepartDelay >= 0) {
503 19 : msg << "Statistics (avg of " << (myVehicleCount + myBikeCount) << "):\n";
504 : }
505 : }
506 2911 : if (myWaitingDepartDelay >= 0) {
507 686 : msg << " DepartDelayWaiting: " << getAvgDepartDelayWaiting() << "\n";
508 : }
509 2911 : if (myWalkCount > 0) {
510 : msg << "Pedestrian Statistics (avg of " << myWalkCount << " walks):\n"
511 566 : << " RouteLength: " << getAvgWalkRouteLength() << "\n"
512 283 : << " Duration: " << getAvgWalkDuration() << "\n"
513 566 : << " TimeLoss: " << getAvgWalkTimeLoss() << "\n";
514 : }
515 5822 : printRideStatistics(msg, "Ride", "rides", 0);
516 5822 : printRideStatistics(msg, "Transport", "transports", 1);
517 2911 : return msg.str();
518 2911 : }
519 :
520 : void
521 5822 : MSDevice_Tripinfo::printRideStatistics(std::ostringstream& msg, const std::string& category, const std::string& modeName, const int index) {
522 5822 : if (myRideCount[index] > 0) {
523 336 : msg << category << " Statistics (avg of " << myRideCount[index] << " " << modeName << "):\n";
524 112 : msg << " WaitingTime: " << STEPS2TIME(myTotalRideWaitingTime[index] / myRideCount[index]) << "\n";
525 112 : msg << " RouteLength: " << myTotalRideRouteLength[index] / myRideCount[index] << "\n";
526 112 : msg << " Duration: " << STEPS2TIME(myTotalRideDuration[index] / myRideCount[index]) << "\n";
527 112 : if (myRideBusCount[index] > 0) {
528 15 : msg << " Bus: " << myRideBusCount[index] << "\n";
529 : }
530 112 : if (myRideRailCount[index] > 0) {
531 9 : msg << " Train: " << myRideRailCount[index] << "\n";
532 : }
533 112 : if (myRideTaxiCount[index] > 0) {
534 66 : msg << " Taxi: " << myRideTaxiCount[index] << "\n";
535 : }
536 112 : if (myRideBikeCount[index] > 0) {
537 13 : msg << " Bike: " << myRideBikeCount[index] << "\n";
538 : }
539 112 : if (myRideAbortCount[index] > 0) {
540 11 : msg << " Aborted: " << myRideAbortCount[index] << "\n";
541 : }
542 : }
543 :
544 5822 : }
545 :
546 :
547 : void
548 264 : MSDevice_Tripinfo::writeStatistics(OutputDevice& od) {
549 264 : od.setPrecision(gPrecision);
550 264 : od.openTag("vehicleTripStatistics");
551 264 : od.writeAttr("count", myVehicleCount);
552 264 : od.writeAttr("routeLength", getAvgRouteLength());
553 264 : od.writeAttr("speed", getAvgTripSpeed());
554 264 : od.writeAttr("duration", getAvgDuration());
555 264 : od.writeAttr("waitingTime", getAvgWaitingTime());
556 264 : od.writeAttr("timeLoss", getAvgTimeLoss());
557 264 : od.writeAttr("departDelay", getAvgDepartDelay());
558 264 : od.writeAttr("departDelayWaiting", getAvgDepartDelayWaiting());
559 528 : od.writeAttr("totalTravelTime", time2string(myTotalDuration));
560 528 : od.writeAttr("totalDepartDelay", time2string(TIME2STEPS(getTotalDepartDelay() + getTotalBikeDepartDelay())));
561 264 : od.closeTag();
562 264 : if (myBikeCount > 0) {
563 6 : od.openTag("bikeTripStatistics");
564 6 : od.writeAttr("count", myBikeCount);
565 6 : od.writeAttr("routeLength", getAvgBikeRouteLength());
566 6 : od.writeAttr("speed", getAvgBikeTripSpeed());
567 6 : od.writeAttr("duration", getAvgBikeDuration());
568 6 : od.writeAttr("waitingTime", getAvgBikeWaitingTime());
569 6 : od.writeAttr("timeLoss", getAvgBikeTimeLoss());
570 6 : od.writeAttr("departDelay", getAvgBikeDepartDelay());
571 12 : od.writeAttr("totalTravelTime", time2string(myTotalBikeDuration));
572 12 : od.closeTag();
573 : }
574 264 : od.openTag("pedestrianStatistics");
575 264 : od.writeAttr("number", myWalkCount);
576 264 : od.writeAttr("routeLength", getAvgWalkRouteLength());
577 264 : od.writeAttr("duration", getAvgWalkDuration());
578 264 : od.writeAttr("timeLoss", getAvgWalkTimeLoss());
579 264 : od.closeTag();
580 264 : writeRideStatistics(od, "rideStatistics", 0);
581 264 : writeRideStatistics(od, "transportStatistics", 1);
582 264 : }
583 :
584 : void
585 528 : MSDevice_Tripinfo::writeRideStatistics(OutputDevice& od, const std::string& category, const int index) {
586 528 : od.openTag(category);
587 1056 : od.writeAttr("number", myRideCount[index]);
588 528 : if (myRideCount[index] > 0) {
589 4 : od.writeAttr("waitingTime", STEPS2TIME(myTotalRideWaitingTime[index] / myRideCount[index]));
590 4 : od.writeAttr("routeLength", myTotalRideRouteLength[index] / myRideCount[index]);
591 4 : od.writeAttr("duration", STEPS2TIME(myTotalRideDuration[index] / myRideCount[index]));
592 4 : od.writeAttr("bus", myRideBusCount[index]);
593 4 : od.writeAttr("train", myRideRailCount[index]);
594 4 : od.writeAttr("taxi", myRideTaxiCount[index]);
595 4 : od.writeAttr("bike", myRideBikeCount[index]);
596 4 : od.writeAttr("aborted", myRideAbortCount[index]);
597 : }
598 528 : od.closeTag();
599 528 : }
600 :
601 :
602 : double
603 3233 : MSDevice_Tripinfo::getAvgRouteLength() {
604 3233 : if (myVehicleCount > 0) {
605 3003 : return myTotalRouteLength / myVehicleCount;
606 : } else {
607 : return 0;
608 : }
609 : }
610 :
611 : double
612 3233 : MSDevice_Tripinfo::getAvgTripSpeed() {
613 3233 : if (myVehicleCount > 0) {
614 3003 : return myTotalSpeed / myVehicleCount;
615 : } else {
616 : return 0;
617 : }
618 : }
619 :
620 : double
621 3233 : MSDevice_Tripinfo::getAvgDuration() {
622 3233 : if (myVehicleCount > 0) {
623 3003 : return STEPS2TIME(myTotalDuration / myVehicleCount);
624 : } else {
625 : return 0;
626 : }
627 : }
628 :
629 : double
630 3233 : MSDevice_Tripinfo::getAvgWaitingTime() {
631 3233 : if (myVehicleCount > 0) {
632 3003 : return STEPS2TIME(myTotalWaitingTime / myVehicleCount);
633 : } else {
634 : return 0;
635 : }
636 : }
637 :
638 :
639 : double
640 3233 : MSDevice_Tripinfo::getAvgTimeLoss() {
641 3233 : if (myVehicleCount > 0) {
642 3003 : return STEPS2TIME(myTotalTimeLoss / myVehicleCount);
643 : } else {
644 : return 0;
645 : }
646 : }
647 :
648 :
649 : double
650 3233 : MSDevice_Tripinfo::getAvgDepartDelay() {
651 3233 : if (myVehicleCount > 0) {
652 3003 : return STEPS2TIME(myTotalDepartDelay / myVehicleCount);
653 : } else {
654 : return 0;
655 : }
656 : }
657 :
658 : double
659 731 : MSDevice_Tripinfo::getAvgDepartDelayWaiting() {
660 731 : if (myWaitingDepartDelay >= 0) {
661 355 : return STEPS2TIME(myWaitingDepartDelay / MAX2(1, myUndepartedVehicleCount));
662 : } else {
663 : return -1;
664 : }
665 : }
666 :
667 :
668 : double
669 652 : MSDevice_Tripinfo::getTotalDepartDelay() {
670 652 : return STEPS2TIME(myTotalDepartDelay + MAX2((SUMOTime)0, myWaitingDepartDelay));
671 : }
672 :
673 : double
674 219 : MSDevice_Tripinfo::getAvgBikeRouteLength() {
675 219 : if (myBikeCount > 0) {
676 157 : return myTotalBikeRouteLength / myBikeCount;
677 : } else {
678 : return 0;
679 : }
680 : }
681 :
682 : double
683 219 : MSDevice_Tripinfo::getAvgBikeTripSpeed() {
684 219 : if (myBikeCount > 0) {
685 157 : return myTotalBikeSpeed / myBikeCount;
686 : } else {
687 : return 0;
688 : }
689 : }
690 :
691 : double
692 219 : MSDevice_Tripinfo::getAvgBikeDuration() {
693 219 : if (myBikeCount > 0) {
694 157 : return STEPS2TIME(myTotalBikeDuration / myBikeCount);
695 : } else {
696 : return 0;
697 : }
698 : }
699 :
700 : double
701 219 : MSDevice_Tripinfo::getAvgBikeWaitingTime() {
702 219 : if (myBikeCount > 0) {
703 157 : return STEPS2TIME(myTotalBikeWaitingTime / myBikeCount);
704 : } else {
705 : return 0;
706 : }
707 : }
708 :
709 :
710 : double
711 219 : MSDevice_Tripinfo::getAvgBikeTimeLoss() {
712 219 : if (myBikeCount > 0) {
713 157 : return STEPS2TIME(myTotalBikeTimeLoss / myBikeCount);
714 : } else {
715 : return 0;
716 : }
717 : }
718 :
719 : double
720 157 : MSDevice_Tripinfo::getAvgBikeDepartDelay() {
721 157 : if (myBikeCount > 0) {
722 157 : return STEPS2TIME(myTotalBikeDepartDelay / myBikeCount);
723 : } else {
724 : return 0;
725 : }
726 : }
727 :
728 :
729 : double
730 528 : MSDevice_Tripinfo::getTotalBikeDepartDelay() {
731 528 : return STEPS2TIME(myTotalBikeDepartDelay);
732 : }
733 :
734 : double
735 609 : MSDevice_Tripinfo::getAvgWalkRouteLength() {
736 609 : if (myWalkCount > 0) {
737 289 : return myTotalWalkRouteLength / myWalkCount;
738 : } else {
739 : return 0;
740 : }
741 : }
742 :
743 : double
744 609 : MSDevice_Tripinfo::getAvgWalkDuration() {
745 609 : if (myWalkCount > 0) {
746 289 : return STEPS2TIME(myTotalWalkDuration / myWalkCount);
747 : } else {
748 : return 0;
749 : }
750 : }
751 :
752 :
753 : double
754 609 : MSDevice_Tripinfo::getAvgWalkTimeLoss() {
755 609 : if (myWalkCount > 0) {
756 289 : return STEPS2TIME(myTotalWalkTimeLoss / myWalkCount);
757 : } else {
758 : return 0;
759 : }
760 : }
761 :
762 :
763 : double
764 0 : MSDevice_Tripinfo::getAvgRideDuration() {
765 0 : if (myRideCount[0] > 0) {
766 0 : return STEPS2TIME(myTotalRideDuration[0] / myRideCount[0]);
767 : } else {
768 : return 0;
769 : }
770 : }
771 :
772 : double
773 0 : MSDevice_Tripinfo::getAvgRideWaitingTime() {
774 0 : if (myRideCount[0] > 0) {
775 0 : return STEPS2TIME(myTotalRideWaitingTime[0] / myRideCount[0]);
776 : } else {
777 : return 0;
778 : }
779 : }
780 :
781 : double
782 0 : MSDevice_Tripinfo::getAvgRideRouteLength() {
783 0 : if (myRideCount[0] > 0) {
784 0 : return myTotalRideRouteLength[0] / myRideCount[0];
785 : } else {
786 : return 0;
787 : }
788 : }
789 :
790 :
791 : std::string
792 266 : MSDevice_Tripinfo::getParameter(const std::string& key) const {
793 266 : if (key == toString(SUMO_ATTR_WAITINGTIME)) {
794 52 : return toString(STEPS2TIME(myWaitingTime));
795 214 : } else if (key == toString(SUMO_ATTR_WAITINGCOUNT)) {
796 52 : return toString(myWaitingCount);
797 162 : } else if (key == toString(SUMO_ATTR_STOPTIME)) {
798 52 : return toString(STEPS2TIME(myStoppingTime));
799 110 : } else if (key == toString(SUMO_ATTR_ARRIVALTIME)) {
800 22 : return toString(STEPS2TIME(myArrivalTime));
801 88 : } else if (key == toString(SUMO_ATTR_ARRIVALLANE)) {
802 22 : return toString(myArrivalLane);
803 66 : } else if (key == toString(SUMO_ATTR_ARRIVALPOS)) {
804 22 : return toString(myArrivalPos);
805 44 : } else if (key == toString(SUMO_ATTR_ARRIVALPOS_LAT)) {
806 22 : return toString(myArrivalPosLat);
807 22 : } else if (key == toString(SUMO_ATTR_ARRIVALSPEED)) {
808 22 : return toString(myArrivalSpeed);
809 : }
810 0 : throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
811 : }
812 :
813 :
814 : std::string
815 3224 : MSDevice_Tripinfo::getGlobalParameter(const std::string& prefixedKey) {
816 : std::string key = prefixedKey; // by default, assume vehicleTripStatistics;
817 3224 : const std::string err = "Parameter '" + prefixedKey + "' is not supported for device of type 'tripinfo'";
818 6448 : if (StringUtils::startsWith(key, "vehicleTripStatistics.")) {
819 1240 : key = prefixedKey.substr(22);
820 5208 : } else if (StringUtils::startsWith(key, "bikeTripStatistics.")) {
821 434 : key = prefixedKey.substr(19);
822 434 : if (key == toString(SUMO_ATTR_COUNT)) {
823 62 : return toString(myBikeCount);
824 372 : } else if (key == "routeLength") {
825 62 : return toString(getAvgBikeRouteLength());
826 310 : } else if (key == toString(SUMO_ATTR_SPEED)) {
827 62 : return toString(getAvgBikeTripSpeed());
828 248 : } else if (key == toString(SUMO_ATTR_DURATION)) {
829 62 : return toString(getAvgBikeDuration());
830 186 : } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
831 62 : return toString(getAvgBikeWaitingTime());
832 124 : } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
833 62 : return toString(getAvgBikeTimeLoss());
834 62 : } else if (key == "departDelay") {
835 0 : return toString(getAvgBikeDepartDelay());
836 62 : } else if (key == "totalTravelTime") {
837 : // avoid human readable output
838 62 : return toString(STEPS2TIME((myTotalBikeDuration)));
839 : }
840 0 : throw InvalidArgument(err);
841 :
842 4340 : } else if (StringUtils::startsWith(key, "pedestrianStatistics.")) {
843 310 : key = prefixedKey.substr(21);
844 558 : if (key == toString(SUMO_ATTR_NUMBER) || key == toString(SUMO_ATTR_COUNT)) {
845 124 : return toString(myWalkCount);
846 186 : } else if (key == "routeLength") {
847 62 : return toString(getAvgWalkRouteLength());
848 124 : } else if (key == toString(SUMO_ATTR_DURATION)) {
849 62 : return toString(getAvgWalkDuration());
850 62 : } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
851 62 : return toString(getAvgWalkTimeLoss());
852 : }
853 0 : throw InvalidArgument(err);
854 :
855 3720 : } else if (StringUtils::startsWith(key, "rideStatistics.") ||
856 3100 : StringUtils::startsWith(key, "transportStatistics.")) {
857 : int index = 0;
858 2480 : if (StringUtils::startsWith(key, "rideStatistics.")) {
859 1240 : key = prefixedKey.substr(15);
860 : } else {
861 : index = 1;
862 1240 : key = prefixedKey.substr(20);
863 : }
864 2356 : if (key == toString(SUMO_ATTR_NUMBER) || key == toString(SUMO_ATTR_COUNT)) {
865 248 : return toString(myRideCount[index]);
866 992 : } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
867 124 : return toString(STEPS2TIME(myTotalRideWaitingTime[index] / MAX2(1, myRideCount[index])));
868 868 : } else if (key == "routeLength") {
869 124 : return toString(myTotalRideRouteLength[index] / MAX2(1, myRideCount[index]));
870 744 : } else if (key == toString(SUMO_ATTR_DURATION)) {
871 124 : return toString(myTotalRideRouteLength[index] / MAX2(1, myRideCount[index]));
872 620 : } else if (key == "bus") {
873 124 : return toString(myRideBusCount[index]);
874 496 : } else if (key == "train") {
875 124 : return toString(myRideRailCount[index]);
876 372 : } else if (key == "taxi") {
877 124 : return toString(myRideTaxiCount[index]);
878 248 : } else if (key == "bike") {
879 124 : return toString(myRideBikeCount[index]);
880 124 : } else if (key == "aborted") {
881 124 : return toString(myRideAbortCount[index]);
882 : }
883 0 : throw InvalidArgument(err);
884 : }
885 : // vehicleTripStatistics
886 1240 : if (key == toString(SUMO_ATTR_COUNT)) {
887 124 : return toString(myVehicleCount);
888 1116 : } else if (key == "routeLength") {
889 124 : return toString(getAvgRouteLength());
890 992 : } else if (key == toString(SUMO_ATTR_SPEED)) {
891 124 : return toString(getAvgTripSpeed());
892 868 : } else if (key == toString(SUMO_ATTR_DURATION)) {
893 124 : return toString(getAvgDuration());
894 744 : } else if (key == toString(SUMO_ATTR_WAITINGTIME)) {
895 124 : return toString(getAvgWaitingTime());
896 620 : } else if (key == toString(SUMO_ATTR_TIMELOSS)) {
897 124 : return toString(getAvgTimeLoss());
898 496 : } else if (key == "departDelay") {
899 124 : return toString(getAvgDepartDelay());
900 372 : } else if (key == "departDelayWaiting") {
901 124 : return toString(getAvgDepartDelayWaiting());
902 248 : } else if (key == "totalTravelTime") {
903 : // avoid human readable output
904 124 : return toString(STEPS2TIME((myTotalDuration)));
905 124 : } else if (key == "totalDepartDelay") {
906 124 : return toString(getTotalDepartDelay());
907 : }
908 0 : throw InvalidArgument(err);
909 : }
910 :
911 :
912 : void
913 198 : MSDevice_Tripinfo::saveState(OutputDevice& out) const {
914 : // always write device id to replicate stochastic assignment
915 198 : out.openTag(SUMO_TAG_DEVICE);
916 198 : out.writeAttr(SUMO_ATTR_ID, getID());
917 198 : if (myHolder.hasDeparted()) {
918 123 : std::ostringstream internals;
919 123 : internals << myDepartLane << " ";
920 123 : if (!MSGlobals::gUseMesoSim) {
921 78 : internals << myDepartPosLat << " ";
922 : }
923 123 : std::string state_arrivalLane = myArrivalLane == "" ? STATE_EMPTY_ARRIVALLANE : myArrivalLane;
924 615 : internals << myDepartSpeed << " " << myRouteLength << " " << myWaitingTime << " " << myAmWaiting << " " << myWaitingCount << " ";
925 246 : internals << myStoppingTime << " " << myParkingStarted << " ";
926 492 : internals << myArrivalTime << " " << state_arrivalLane << " " << myArrivalPos << " " << myArrivalPosLat << " " << myArrivalSpeed;
927 246 : out.writeAttr(SUMO_ATTR_STATE, internals.str());
928 123 : }
929 198 : out.closeTag();
930 198 : }
931 :
932 :
933 : void
934 148 : MSDevice_Tripinfo::loadState(const SUMOSAXAttributes& attrs) {
935 148 : if (attrs.hasAttribute(SUMO_ATTR_STATE)) {
936 103 : std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
937 103 : bis >> myDepartLane;
938 103 : if (!MSGlobals::gUseMesoSim) {
939 69 : bis >> myDepartPosLat;
940 : }
941 103 : bis >> myDepartSpeed >> myRouteLength >> myWaitingTime >> myAmWaiting >> myWaitingCount;
942 103 : bis >> myStoppingTime >> myParkingStarted;
943 103 : bis >> myArrivalTime >> myArrivalLane >> myArrivalPos >> myArrivalPosLat >> myArrivalSpeed;
944 103 : if (myArrivalLane == STATE_EMPTY_ARRIVALLANE) {
945 : myArrivalLane = "";
946 : }
947 103 : }
948 148 : }
949 :
950 :
951 : /****************************************************************************/
|