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