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