Eclipse SUMO - Simulation of Urban MObility
MSDevice_Taxi.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3// Copyright (C) 2013-2022 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/****************************************************************************/
18// A device which controls a taxi
19/****************************************************************************/
20#include <config.h>
21
30#include <microsim/MSGlobals.h>
31#include <microsim/MSVehicle.h>
32#include <microsim/MSEdge.h>
33#include <microsim/MSLane.h>
34#include <microsim/MSStop.h>
36
37#include "MSDispatch.h"
38#include "MSDispatch_Greedy.h"
41#include "MSDispatch_TraCI.h"
42
43#include "MSIdling.h"
44
45#include "MSRoutingEngine.h"
46#include "MSDevice_Routing.h"
47#include "MSDevice_Taxi.h"
48
49//#define DEBUG_DISPATCH
50
51//#define DEBUG_COND (myHolder.isSelected())
52#define DEBUG_COND (true)
53
54// ===========================================================================
55// static member variables
56// ===========================================================================
62// @brief the list of available taxis
63std::vector<MSDevice_Taxi*> MSDevice_Taxi::myFleet;
66
67#define TAXI_SERVICE "taxi"
68#define TAXI_SERVICE_PREFIX "taxi:"
69
70// ===========================================================================
71// method definitions
72// ===========================================================================
73// ---------------------------------------------------------------------------
74// static initialisation methods
75// ---------------------------------------------------------------------------
76void
78 oc.addOptionSubTopic("Taxi Device");
79 insertDefaultAssignmentOptions("taxi", "Taxi Device", oc);
80
81 oc.doRegister("device.taxi.dispatch-algorithm", new Option_String("greedy"));
82 oc.addDescription("device.taxi.dispatch-algorithm", "Taxi Device", "The dispatch algorithm [greedy|greedyClosest|greedyShared|routeExtension|traci]");
83
84 oc.doRegister("device.taxi.dispatch-algorithm.output", new Option_FileName());
85 oc.addDescription("device.taxi.dispatch-algorithm.output", "Taxi Device", "Write information from the dispatch algorithm to FILE");
86
87 oc.doRegister("device.taxi.dispatch-algorithm.params", new Option_String(""));
88 oc.addDescription("device.taxi.dispatch-algorithm.params", "Taxi Device", "Load dispatch algorithm parameters in format KEY1:VALUE1[,KEY2:VALUE]");
89
90 oc.doRegister("device.taxi.dispatch-period", new Option_String("60", "TIME"));
91 oc.addDescription("device.taxi.dispatch-period", "Taxi Device", "The period between successive calls to the dispatcher");
92
93 oc.doRegister("device.taxi.idle-algorithm", new Option_String("stop"));
94 oc.addDescription("device.taxi.idle-algorithm", "Taxi Device", "The behavior of idle taxis [stop|randomCircling]");
95
96 oc.doRegister("device.taxi.idle-algorithm.output", new Option_FileName());
97 oc.addDescription("device.taxi.idle-algorithm.output", "Taxi Device", "Write information from the idling algorithm to FILE");
98}
99
100
101void
102MSDevice_Taxi::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
104 if (equippedByDefaultAssignmentOptions(oc, "taxi", v, false)) {
105 // build the device
106 MSDevice_Taxi* device = new MSDevice_Taxi(v, "taxi_" + v.getID());
107 into.push_back(device);
108 myFleet.push_back(device);
109 if (v.getParameter().line == "") {
110 // automatically set the line so that persons are willing to enter
111 // (see MSStageDriving::isWaitingFor)
112 const_cast<SUMOVehicleParameter&>(v.getParameter()).line = TAXI_SERVICE;
113 }
114 if (v.getVClass() != SVC_TAXI) {
115 WRITE_WARNING("Vehicle '" + v.getID() + "' with device.taxi should have vClass taxi instead of '" + toString(v.getVClass()) + "'.");
116 }
117 const int personCapacity = v.getVehicleType().getPersonCapacity();
118 const int containerCapacity = v.getVehicleType().getContainerCapacity();
119 myMaxCapacity = MAX2(myMaxCapacity, personCapacity);
121 if (personCapacity < 1 && containerCapacity < 1) {
122 WRITE_WARNINGF(TL("Vehicle '%' with personCapacity % and containerCapacity % is not usable as taxi."), v.getID(), toString(personCapacity), toString(containerCapacity));
123 }
124 }
125}
126
127
128void
131 myDispatchPeriod = string2time(oc.getString("device.taxi.dispatch-period"));
132 // init dispatch algorithm
133 std::string algo = oc.getString("device.taxi.dispatch-algorithm");
134 Parameterised params;
135 params.setParametersStr(OptionsCont::getOptions().getString("device.taxi.dispatch-algorithm.params"), ":", ",");
136 if (algo == "greedy") {
138 } else if (algo == "greedyClosest") {
140 } else if (algo == "greedyShared") {
142 } else if (algo == "routeExtension") {
144 } else if (algo == "traci") {
146 } else {
147 throw ProcessError("Dispatch algorithm '" + algo + "' is not known");
148 }
150 // round to next multiple of myDispatchPeriod
152 const SUMOTime begin = string2time(oc.getString("begin"));
153 const SUMOTime delay = (myDispatchPeriod - ((now - begin) % myDispatchPeriod)) % myDispatchPeriod;
155}
156
157bool
158MSDevice_Taxi::isReservation(const std::set<std::string>& lines) {
159 return lines.size() == 1 && (
160 *lines.begin() == TAXI_SERVICE
161 || StringUtils::startsWith(*lines.begin(), TAXI_SERVICE_PREFIX));
162}
163
164void
166 const std::set<std::string>& lines,
167 SUMOTime reservationTime,
168 SUMOTime pickupTime,
169 const MSEdge* from, double fromPos,
170 const MSEdge* to, double toPos,
171 const std::string& group) {
172 if (!isReservation(lines)) {
173 return;
174 }
175 if ((to->getPermissions() & SVC_TAXI) == 0) {
176 throw ProcessError("Cannot add taxi reservation for " + std::string(person->isPerson() ? "person" : "container")
177 + " '" + person->getID() + "' because destination edge '" + to->getID() + "'"
178 + " does not permit taxi access");
179 }
180 if ((from->getPermissions() & SVC_TAXI) == 0) {
181 throw ProcessError("Cannot add taxi reservation for " + std::string(person->isPerson() ? "person" : "container")
182 + " '" + person->getID() + "' because origin edge '" + from->getID() + "'"
183 + " does not permit taxi access");
184 }
185 if (myDispatchCommand == nullptr) {
186 initDispatch();
187 }
188 myDispatcher->addReservation(person, reservationTime, pickupTime, from, fromPos, to, toPos, group, *lines.begin(), myMaxCapacity, myMaxContainerCapacity);
189}
190
191void
193 const std::set<std::string>& lines,
194 const MSEdge* from, double fromPos,
195 const MSEdge* to, double toPos,
196 const std::string& group) {
197 if (myDispatcher != nullptr && lines.size() == 1 && *lines.begin() == TAXI_SERVICE) {
198 myDispatcher->removeReservation(person, from, fromPos, to, toPos, group);
199 }
200}
201
202
205 std::vector<MSDevice_Taxi*> active;
206 for (MSDevice_Taxi* taxi : myFleet) {
207 if (taxi->getHolder().hasDeparted()) {
208 active.push_back(taxi);
209 }
210 }
211 myDispatcher->computeDispatch(currentTime, active);
212 return myDispatchPeriod;
213}
214
215bool
217 return myDispatcher != nullptr && myDispatcher->hasServableReservations();
218}
219
220void
222 if (myDispatcher != nullptr) {
223 delete myDispatcher;
224 myDispatcher = nullptr;
225 }
226 myDispatchCommand = nullptr;
227}
228
229// ---------------------------------------------------------------------------
230// MSDevice_Taxi-methods
231// ---------------------------------------------------------------------------
232MSDevice_Taxi::MSDevice_Taxi(SUMOVehicle& holder, const std::string& id) :
233 MSVehicleDevice(holder, id) {
234 std::string defaultServiceEnd = toString(1e15);
235 const std::string algo = getStringParam(holder, OptionsCont::getOptions(), "taxi.idle-algorithm", "", false);
236 if (algo == "stop") {
238 } else if (algo == "randomCircling") {
240 // make sure simulation terminates
241 defaultServiceEnd = toString(STEPS2TIME(
244 : MSNet::getInstance()->getCurrentTimeStep()) + (3600 * 8));
245 } else {
246 throw ProcessError("Idle algorithm '" + algo + "' is not known for vehicle '" + myHolder.getID() + "'");
247 }
248 myServiceEnd = string2time(getStringParam(holder, OptionsCont::getOptions(), "taxi.end", defaultServiceEnd, false));
250}
251
252
254 myFleet.erase(std::find(myFleet.begin(), myFleet.end(), this));
255 // recompute myMaxCapacity
256 myMaxCapacity = 0;
258 for (MSDevice_Taxi* taxi : myFleet) {
259 myMaxCapacity = MAX2(myMaxCapacity, taxi->getHolder().getVehicleType().getPersonCapacity());
260 myMaxContainerCapacity = MAX2(myMaxContainerCapacity, taxi->getHolder().getVehicleType().getContainerCapacity());
261 }
262 delete myIdleAlgorithm;
263}
264
265
268 if (myFleet.size() > 0) {
269 return &myFleet[0]->getHolder();
270 } else {
271 return nullptr;
272 }
273}
274
275
276void
278 dispatchShared({&res, &res});
279}
280
281
282void
283MSDevice_Taxi::dispatchShared(std::vector<const Reservation*> reservations) {
284#ifdef DEBUG_DISPATCH
285 if (DEBUG_COND) {
286 std::cout << SIMTIME << " taxi=" << myHolder.getID() << " dispatch:\n";
287 for (const Reservation* res : reservations) {
288 std::cout << " persons=" << toString(res->persons) << "\n";
289 }
290 }
291#endif
292 ConstMSEdgeVector tmpEdges;
293 std::vector<SUMOVehicleParameter::Stop> stops;
294 double lastPos = myHolder.getPositionOnLane();
295 const MSEdge* rerouteOrigin = myHolder.getRerouteOrigin();
296 if (isEmpty()) {
297 // start fresh from the current edge
299 assert(!myHolder.hasStops());
300 tmpEdges.push_back(myHolder.getEdge());
301 if (myHolder.getEdge() != rerouteOrigin) {
302 tmpEdges.push_back(rerouteOrigin);
303 }
304 } else {
305 assert(myHolder.hasStops());
306 // check how often existing customers appear in the new reservations
307 std::map<const MSTransportable*, int> nOccur;
308 for (const Reservation* res : reservations) {
309 for (MSTransportable* person : res->persons) {
310 if (myCustomers.count(person) != 0) {
311 nOccur[person] += 1;
312 if (myCurrentReservations.count(res) == 0) {
313 throw ProcessError("Invalid Re-dispatch for existing customer '" + person->getID() + "' with a new reservation");
314 }
315 }
316 }
317 }
318#ifdef DEBUG_DISPATCH
319 if (DEBUG_COND) {
320 for (auto item : nOccur) {
321 std::cout << " previousCustomer=" << item.first->getID() << " occurs=" << item.second << "\n";
322 }
323 }
324#endif
325 if (nOccur.size() == 0) {
326 // no overlap with existing customers - extend route
327 tmpEdges = myHolder.getRoute().getEdges();
328 lastPos = myHolder.getStops().back().pars.endPos;
329#ifdef DEBUG_DISPATCH
330 if (DEBUG_COND) {
331 std::cout << " re-dispatch with route-extension\n";
332 }
333#endif
334 } else if (nOccur.size() == myCustomers.size()) {
335 // redefine route (verify correct number of mentions)
336 std::set<const MSTransportable*> onBoard;
337 const std::vector<MSTransportable*>& onBoardP = myHolder.getPersons();
338 const std::vector<MSTransportable*>& onBoardC = myHolder.getContainers();
339 onBoard.insert(onBoardP.begin(), onBoardP.end());
340 onBoard.insert(onBoardC.begin(), onBoardC.end());
341 std::set<const MSTransportable*> redundantPickup;
342 for (auto item : nOccur) {
343 if (item.second == 1) {
344 // customers must already be on board
345 if (onBoard.count(item.first) == 0) {
346 throw ProcessError("Re-dispatch did not mention pickup for existing customer '" + item.first->getID() + "'");
347 }
348 } else if (item.second == 2) {
349 if (onBoard.count(item.first) == 0) {
350 // treat like a new customer
351 myCustomers.erase(item.first);
352 } else {
353 redundantPickup.insert(item.first);
354 }
355 } else {
356 throw ProcessError("Re-dispatch mentions existing customer '" + item.first->getID() + "' " + toString(item.second) + " times");
357 }
358 }
359 // remove redundancy
360 if (!redundantPickup.empty()) {
361 for (auto it = reservations.begin(); it != reservations.end();) {
362 bool isRedundant = false;
363 for (const MSTransportable* person : (*it)->persons) {
364 if (redundantPickup.count(person) != 0) {
365 isRedundant = true;
366 break;
367 }
368 }
369 if (isRedundant) {
370 for (const MSTransportable* person : (*it)->persons) {
371 redundantPickup.erase(person);
372 }
373 it = reservations.erase(it);
374 } else {
375 it++;
376 }
377 }
378 }
379 while (myHolder.hasStops()) {
381 }
382 tmpEdges.push_back(myHolder.getEdge());
383 if (myHolder.getEdge() != rerouteOrigin) {
384 tmpEdges.push_back(rerouteOrigin);
385 }
386#ifdef DEBUG_DISPATCH
387 if (DEBUG_COND) {
388 std::cout << " re-dispatch from scratch\n";
389 }
390#endif
391 } else {
392 // inconsistent re-dispatch
393 std::vector<std::string> missing;
394 for (const MSTransportable* c : myCustomers) {
395 if (nOccur.count(c) == 0) {
396 missing.push_back(c->getID());
397 }
398 }
399 throw ProcessError("Re-dispatch did mention some customers but failed to mention " + joinToStringSorting(missing, " "));
400 }
401 }
402
404 bool hasPickup = false;
405 for (const Reservation* res : reservations) {
406 myCurrentReservations.insert(res);
407 bool isPickup = false;
408 for (MSTransportable* person : res->persons) {
409 if (myCustomers.count(person) == 0) {
410 myCustomers.insert(person);
411 isPickup = true;
412 hasPickup = true;
413 }
414 }
415 if (isPickup) {
416 prepareStop(tmpEdges, stops, lastPos, res->from, res->fromPos, "pickup " + toString(res->persons) + " (" + res->id + ")");
417 for (const MSTransportable* const transportable : res->persons) {
418 if (transportable->isPerson()) {
419 stops.back().triggered = true;
420 } else {
421 stops.back().containerTriggered = true;
422 }
423 stops.back().permitted.insert(transportable->getID());
424 }
425 //stops.back().awaitedPersons.insert(res.person->getID());
426 stops.back().parametersSet |= STOP_PERMITTED_SET;
427 if (stops.back().duration == -1) {
428 // keep dropOffDuration if the stop is dropOff and pickUp
429 stops.back().duration = TIME2STEPS(getFloatParam(myHolder, OptionsCont::getOptions(), "taxi.pickUpDuration", 0, false));
430 }
431 } else {
432 prepareStop(tmpEdges, stops, lastPos, res->to, res->toPos, "dropOff " + toString(res->persons) + " (" + res->id + ")");
433 stops.back().duration = TIME2STEPS(getFloatParam(myHolder, OptionsCont::getOptions(), "taxi.dropOffDuration", 60, false)); // pay and collect bags
434 }
435 }
436#ifdef DEBUG_DISPATCH
437 if (DEBUG_COND) {
438 std::cout << " tmpEdges=" << toString(tmpEdges) << "\n";
439 }
440#endif
441 if (!myHolder.replaceRouteEdges(tmpEdges, -1, 0, "taxi:prepare_dispatch", false, false, false)) {
442 throw ProcessError("Route replacement for taxi dispatch failed for vehicle '" + myHolder.getID()
443 + "' at time=" + time2string(t) + ".");
444 }
445#ifdef DEBUG_DISPATCH
446 if (DEBUG_COND) std::cout << " replacedRoute=" << toString(tmpEdges)
447 << "\n actualRoute=" << toString(myHolder.getRoute().getEdges()) << "\n";
448#endif
449 for (SUMOVehicleParameter::Stop& stop : stops) {
450 std::string error;
451 myHolder.addStop(stop, error);
452 if (error != "") {
453 WRITE_WARNINGF(TL("Could not add taxi stop for vehicle '%' to %. time=% error=%."), myHolder.getID(), stop.actType, time2string(t), error)
454 }
455 }
457 // SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = myHolder.getInfluencer().getRouterTT(veh->getRNGIndex())
458 myHolder.reroute(t, "taxi:dispatch", router, false);
459#ifdef DEBUG_DISPATCH
460 if (DEBUG_COND) {
461 std::cout << "\n finalRoute=" << toString(myHolder.getRoute().getEdges()) << " routeIndex=" << myHolder.getRoutePosition() << "\n";
462 }
463#endif
464 if (hasPickup) {
465 myState |= PICKUP;
466 }
467}
468
469
470void
472 std::vector<SUMOVehicleParameter::Stop>& stops,
473 double& lastPos, const MSEdge* stopEdge, double stopPos,
474 const std::string& action) {
475 assert(!edges.empty());
476 if (stopPos < lastPos && stopPos + NUMERICAL_EPS >= lastPos) {
477 stopPos = lastPos;
478 }
479
480 if (stops.empty()) {
481 // check brakeGap
482 double distToStop = stopPos - lastPos;
483 const double brakeGap = myHolder.getBrakeGap();
484 if (myHolder.getLane() != nullptr && myHolder.getLane()->isInternal()) {
485 distToStop += myHolder.getLane()->getLength();
486 }
487 if (stopEdge != edges.back()) {
488 distToStop += edges.back()->getLength();
489 if (distToStop < brakeGap) {
490 // the distance between current edge and stop edge may be small
492 ConstMSEdgeVector toFirstStop;
493 router.compute(edges.back(), stopEdge, &myHolder, SIMSTEP, toFirstStop, true);
494 for (int i = 1; i < (int)toFirstStop.size() - 1; i++) {
495 distToStop += toFirstStop[i]->getLength();
496 }
497 }
498 }
499 if (distToStop < brakeGap) {
500 // circle back to stopEdge
501 //std::cout << SIMTIME << " taxi=" << getID() << " brakeGap=" << brakeGap << " distToStop=" << distToStop << "\n";
502 edges.push_back(stopEdge);
503 }
504 }
505
506 if (stopEdge == edges.back() && !stops.empty()) {
507 if (stopPos >= lastPos && stopPos <= stops.back().endPos) {
508 // no new stop and no adaption needed
509 stops.back().actType += "," + action;
510 return;
511 }
512 if (stopPos >= lastPos && stopPos <= lastPos + myHolder.getVehicleType().getLength()) {
513 // stop length adaption needed
514 stops.back().endPos = MIN2(lastPos + myHolder.getVehicleType().getLength(), stopEdge->getLength());
515 stops.back().actType += "," + action;
516 return;
517 }
518 }
519 if (stopEdge != edges.back() || stopPos < lastPos) {
520 edges.push_back(stopEdge);
521 }
522 lastPos = stopPos;
524 stop.lane = getStopLane(stopEdge, action)->getID();
525 stop.startPos = stopPos;
526 stop.endPos = MAX2(stopPos, MIN2(myHolder.getVehicleType().getLength(), stopEdge->getLength()));
528 stop.actType = action;
529 stop.index = STOP_INDEX_END;
530 stops.push_back(stop);
531}
532
533
534MSLane*
535MSDevice_Taxi::getStopLane(const MSEdge* edge, const std::string& action) {
536 const std::vector<MSLane*>* allowedLanes = edge->allowedLanes(myHolder.getVClass());
537 if (allowedLanes == nullptr) {
538 throw ProcessError("Taxi vehicle '" + myHolder.getID() + "' cannot stop on edge '" + edge->getID() + "' (" + action + ")");
539 }
540 return allowedLanes->front();
541}
542
543bool
545 return myState == EMPTY;
546}
547
548
549bool
551 return myCustomers.count(t) != 0;
552}
553
554
555void
556MSDevice_Taxi::updateMove(const SUMOTime traveltime, const double travelledDist) {
558 myOccupiedDistance += travelledDist;
559 myOccupiedTime += traveltime;
560 }
561 if (isEmpty()) {
562 if (MSNet::getInstance()->getCurrentTimeStep() < myServiceEnd) {
563 myIdleAlgorithm->idle(this);
564 if (myRoutingDevice != nullptr) {
565 // prevent rerouting during idling (#11079)
567 }
568 } else if (!myReachedServiceEnd) {
569 WRITE_WARNINGF(TL("Taxi '%' reaches scheduled end of service at time=%."), myHolder.getID(), time2string(SIMSTEP));
570 myReachedServiceEnd = true;
571 }
572 } else if (myRoutingDevice != nullptr) {
574 }
575 if (myHolder.isStopped()) {
576 if (!myIsStopped) {
577 // limit duration of stop
578 // @note: stops are not yet added to the vehicle so we can change the loaded parameters. Stops added from a route are not affected
580 }
581 }
582#ifdef DEBUG_DISPATCH
584 std::cout << SIMTIME << " updateMove veh=" << myHolder.getID() << " myIsStopped=" << myIsStopped << " myHolderStopped=" << myHolder.isStopped() << " myState=" << myState << "\n";
585 }
586#endif
588}
589
590
591bool
593 double newPos, double /*newSpeed*/) {
594 updateMove(DELTA_T, newPos - oldPos);
595 return true; // keep the device
596}
597
598
599void
601 const double /* frontOnLane */,
602 const double timeOnLane,
603 const double /* meanSpeedFrontOnLane */,
604 const double /* meanSpeedVehicleOnLane */,
605 const double travelledDistanceFrontOnLane,
606 const double /* travelledDistanceVehicleOnLane */,
607 const double /* meanLengthOnLane */) {
608 updateMove(TIME2STEPS(timeOnLane), travelledDistanceFrontOnLane);
609}
610
611
612bool
614 if (isEmpty() && MSNet::getInstance()->getCurrentTimeStep() < myServiceEnd) {
615 myIdleAlgorithm->idle(this);
616 }
617 return true; // keep the device
618}
619
620
621void
623 myState |= OCCUPIED;
624 if (!hasFuturePickup()) {
625 myState &= ~PICKUP;
626 }
627 for (const Reservation* res : myCurrentReservations) {
628 for (const MSTransportable* cand : res->persons) {
629 if (cand == t) {
630 const_cast<Reservation*>(res)->state = Reservation::ONBOARD;
631 break;
632 }
633 }
634 }
635}
636
637
638void
641 myCustomers.erase(person);
643 myState &= ~OCCUPIED;
644 if (myHolder.getStops().size() > 1 && (myState & PICKUP) == 0) {
645 WRITE_WARNINGF(TL("All customers left vehicle '%' at time=% but there are % remaining stops"),
647 while (myHolder.getStops().size() > 1) {
649 }
650 }
651 }
652 if (isEmpty()) {
653 // cleanup
654 for (const Reservation* res : myCurrentReservations) {
656 }
657 myCurrentReservations.clear();
658 if (MSGlobals::gUseMesoSim && MSNet::getInstance()->getCurrentTimeStep() < myServiceEnd) {
659 myIdleAlgorithm->idle(this);
660 }
661 } else {
662 // check whether a single reservation has been fulfilled
663 for (auto resIt = myCurrentReservations.begin(); resIt != myCurrentReservations.end();) {
664 bool fulfilled = true;
665 for (MSTransportable* t : (*resIt)->persons) {
666 if (myCustomers.count(t) != 0) {
667 fulfilled = false;
668 break;
669 }
670 }
671 if (fulfilled) {
673 resIt = myCurrentReservations.erase(resIt);
674 } else {
675 ++resIt;
676 }
677 }
678 }
679}
680
681
682bool
684 for (const auto& stop : myHolder.getStops()) {
685 if (stop.reached) {
686 continue;
687 }
688 if (stop.pars.permitted.size() > 0) {
689 return true;
690 }
691 }
692 return false;
693}
694
695void
697 if (tripinfoOut != nullptr) {
698 tripinfoOut->openTag("taxi");
699 tripinfoOut->writeAttr("customers", toString(myCustomersServed));
700 tripinfoOut->writeAttr("occupiedDistance", toString(myOccupiedDistance));
701 tripinfoOut->writeAttr("occupiedTime", time2string(myOccupiedTime));
702 tripinfoOut->closeTag();
703 }
704}
705
706std::string
707MSDevice_Taxi::getParameter(const std::string& key) const {
708 if (key == "customers") {
710 } else if (key == "occupiedDistance") {
712 } else if (key == "occupiedTime") {
714 } else if (key == "state") {
715 return toString(myState);
716 } else if (key == "currentCustomers") {
718 } else if (key == "pickUpDuration") {
719 return getStringParam(myHolder, OptionsCont::getOptions(), "taxi.pickUpDuration", "0", false);
720 } else if (key == "dropOffDuration") {
721 return getStringParam(myHolder, OptionsCont::getOptions(), "taxi.dropOffDuration", "60", false);
722 }
723 throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
724}
725
726
727void
728MSDevice_Taxi::setParameter(const std::string& key, const std::string& value) {
729 double doubleValue;
730 try {
731 doubleValue = StringUtils::toDouble(value);
732 } catch (NumberFormatException&) {
733 throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
734 }
735 if (key == "pickUpDuration" || key == "dropOffDuration") {
736 // store as generic vehicle parameters
737 ((SUMOVehicleParameter&)myHolder.getParameter()).setParameter("device.taxi." + key, value);
738 } else {
739 UNUSED_PARAMETER(doubleValue);
740 throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
741 }
742}
743
744bool
745MSDevice_Taxi::compatibleLine(const std::string& taxiLine, const std::string& rideLine) {
746 return (taxiLine == rideLine
747 || (taxiLine == TAXI_SERVICE && StringUtils::startsWith(rideLine, "taxi:"))
748 || (rideLine == TAXI_SERVICE && StringUtils::startsWith(taxiLine, "taxi:")));
749}
750
751bool
754}
755
756
757/****************************************************************************/
long long int SUMOTime
Definition: GUI.h:36
#define TAXI_SERVICE
#define DEBUG_COND
#define TAXI_SERVICE_PREFIX
std::vector< const MSEdge * > ConstMSEdgeVector
Definition: MSEdge.h:74
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:266
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:265
#define TL(string)
Definition: MsgHandler.h:282
SUMOTime DELTA_T
Definition: SUMOTime.cpp:37
std::string time2string(SUMOTime t)
convert SUMOTime to string
Definition: SUMOTime.cpp:68
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition: SUMOTime.cpp:45
#define STEPS2TIME(x)
Definition: SUMOTime.h:54
#define SIMSTEP
Definition: SUMOTime.h:60
#define SIMTIME
Definition: SUMOTime.h:61
#define TIME2STEPS(x)
Definition: SUMOTime.h:56
@ SVC_TAXI
vehicle is a taxi
const int STOP_INDEX_END
const int STOP_PERMITTED_SET
@ GIVEN
The time is given.
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:30
T MIN2(T a, T b)
Definition: StdDefs.h:71
T MAX2(T a, T b)
Definition: StdDefs.h:77
std::string joinToStringSorting(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:298
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
std::string joinNamedToStringSorting(const std::set< T * > &ns, const T_BETWEEN &between)
Definition: ToString.h:306
Base (microsim) event class.
Definition: Command.h:50
A device that performs vehicle rerouting based on current edge speeds.
void setActive(bool active)
A device which collects info on the vehicle trip (mainly on departure and arrival)
Definition: MSDevice_Taxi.h:49
static void initDispatch()
initialize the dispatch algorithm
static Command * myDispatchCommand
The repeated call to the dispatcher.
void customerArrived(const MSTransportable *person)
called by MSDevice_Transportable upon unloading a person
static SUMOTime triggerDispatch(SUMOTime currentTime)
period command to trigger the dispatch algorithm
void dispatch(const Reservation &res)
service the given reservation
std::set< const MSTransportable * > myCustomers
the customer of the current reservation
SUMOTime myServiceEnd
the time at which the taxi service ends (end the vehicle may leave the simulation)
void generateOutput(OutputDevice *tripinfoOut) const
Called on writing tripinfo output.
static int myMaxCapacity
void dispatchShared(std::vector< const Reservation * > reservations)
service the given reservations
MSIdling * myIdleAlgorithm
algorithm for controlling idle behavior
std::set< const Reservation * > myCurrentReservations
reservations currently being served
bool notifyMove(SUMOTrafficObject &veh, double oldPos, double newPos, double newSpeed)
Checks for waiting steps when the vehicle moves.
bool hasFuturePickup()
whether the taxi has another pickup scheduled
static MSDispatch * myDispatcher
the dispatch algorithm
int myCustomersServed
number of customers that were served
void updateMove(const SUMOTime traveltime, const double travelledDist)
void notifyMoveInternal(const SUMOTrafficObject &veh, const double frontOnLane, const double timeOnLane, const double meanSpeedFrontOnLane, const double meanSpeedVehicleOnLane, const double travelledDistanceFrontOnLane, const double travelledDistanceVehicleOnLane, const double meanLengthOnLane)
Internal notification about the vehicle moves, see MSMoveReminder::notifyMoveInternal()
static int myMaxContainerCapacity
MSDevice_Routing * myRoutingDevice
routing device (if the vehicle has one)
bool isEmpty()
whether the taxi is empty
const std::string deviceName() const
return the name for this type of device
static std::vector< MSDevice_Taxi * > myFleet
static void removeReservation(MSTransportable *person, const std::set< std::string > &lines, const MSEdge *from, double fromPos, const MSEdge *to, double toPos, const std::string &group)
retract reservation
static SUMOTime myDispatchPeriod
the time between successive calls to the dispatcher
bool notifyEnter(SUMOTrafficObject &veh, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Saves departure info on insertion.
static void cleanup()
resets counters
static bool isReservation(const std::set< std::string > &lines)
whether the given lines description is a taxi call
double myOccupiedDistance
distance driven with customers
MSDevice_Taxi(SUMOVehicle &holder, const std::string &id)
Constructor.
static void addReservation(MSTransportable *person, const std::set< std::string > &lines, SUMOTime reservationTime, SUMOTime pickupTime, const MSEdge *from, double fromPos, const MSEdge *to, double toPos, const std::string &group)
add new reservation
bool allowsBoarding(const MSTransportable *t) const
whether the given person is allowed to board this taxi
static bool hasServableReservations()
check whether there are still (servable) reservations in the system
void prepareStop(ConstMSEdgeVector &edges, std::vector< SUMOVehicleParameter::Stop > &stops, double &lastPos, const MSEdge *stopEdge, double stopPos, const std::string &action)
prepare stop for the given action
static SUMOVehicle * getTaxi()
returns a taxi if any exist or nullptr
void customerEntered(const MSTransportable *t)
called by MSDevice_Transportable upon loading a person
bool compatibleLine(const Reservation *res)
whether the given reservation is compatible with the taxi line
static void buildVehicleDevices(SUMOVehicle &v, std::vector< MSVehicleDevice * > &into)
Build devices for the given vehicle, if needed.
static void insertOptions(OptionsCont &oc)
Inserts MSDevice_Taxi-options.
bool myIsStopped
whether the vehicle is currently stopped
void setParameter(const std::string &key, const std::string &value)
try to set the given parameter for this device. Throw exception for unsupported key
SUMOTime myOccupiedTime
time spent driving with customers
bool myReachedServiceEnd
whether the taxi has reached it's schedule service end
~MSDevice_Taxi()
Destructor.
MSLane * getStopLane(const MSEdge *edge, const std::string &action)
determine stopping lane for taxi
std::string getParameter(const std::string &key) const
try to retrieve the given parameter from this device. Throw exception for unsupported key
static double getFloatParam(const SUMOVehicle &v, const OptionsCont &oc, std::string paramName, double deflt, bool required)
Definition: MSDevice.cpp:195
static void insertDefaultAssignmentOptions(const std::string &deviceName, const std::string &optionsTopic, OptionsCont &oc, const bool isPerson=false)
Adds common command options that allow to assign devices to vehicles.
Definition: MSDevice.cpp:144
static bool equippedByDefaultAssignmentOptions(const OptionsCont &oc, const std::string &deviceName, DEVICEHOLDER &v, bool outputOptionSet, const bool isPerson=false)
Determines whether a vehicle should get a certain device.
Definition: MSDevice.h:202
static std::string getStringParam(const SUMOVehicle &v, const OptionsCont &oc, std::string paramName, std::string deflt, bool required)
Definition: MSDevice.cpp:171
A dispatch algorithm that services the reservations with the shortest traveltime-to-pickup first.
A dispatch algorithm that services customers in reservation order and always sends the closest availa...
A dispatch algorithm that services customers in reservation order and always sends the closest availa...
An algorithm that performs distpach for a taxi fleet.
Definition: MSDispatch.h:102
virtual std::string removeReservation(MSTransportable *person, const MSEdge *from, double fromPos, const MSEdge *to, double toPos, std::string group)
remove person from reservation. If the whole reservation is removed, return it's id
Definition: MSDispatch.cpp:125
virtual Reservation * addReservation(MSTransportable *person, SUMOTime reservationTime, SUMOTime pickupTime, const MSEdge *from, double fromPos, const MSEdge *to, double toPos, std::string group, const std::string &line, int maxCapacity, int maxContainerCapacity)
add a new reservation
Definition: MSDispatch.cpp:61
bool hasServableReservations()
check whether there are still (servable) reservations in the system
Definition: MSDispatch.h:153
virtual void fulfilledReservation(const Reservation *res)
erase reservation from storage
Definition: MSDispatch.cpp:207
virtual void computeDispatch(SUMOTime now, const std::vector< MSDevice_Taxi * > &fleet)=0
computes dispatch and updates reservations
A road/street connecting two junctions.
Definition: MSEdge.h:77
SVCPermissions getPermissions() const
Returns the combined permissions of all lanes of this edge.
Definition: MSEdge.h:622
const std::vector< MSLane * > * allowedLanes(const MSEdge &destination, SUMOVehicleClass vclass=SVC_IGNORING) const
Get the allowed lanes to reach the destination-edge.
Definition: MSEdge.cpp:439
double getLength() const
return the length of the edge
Definition: MSEdge.h:658
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
static bool gUseMesoSim
Definition: MSGlobals.h:103
virtual void idle(MSDevice_Taxi *taxi)=0
computes Idling and updates reservations
Representation of a lane in the micro simulation.
Definition: MSLane.h:84
double getLength() const
Returns the lane's length.
Definition: MSLane.h:575
bool isInternal() const
Definition: MSLane.cpp:2330
Notification
Definition of a vehicle state.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:183
MSEventControl * getEndOfTimestepEvents()
Returns the event control for events executed at the end of a time step.
Definition: MSNet.h:482
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:321
const ConstMSEdgeVector & getEdges() const
Definition: MSRoute.h:124
static SUMOAbstractRouter< MSEdge, SUMOVehicle > & getRouterTT(const int rngIndex, SUMOVehicleClass svc, const MSEdgeVector &prohibited=MSEdgeVector())
return the router instance
SUMOTime endBoarding
the maximum time at which persons may board this vehicle
Definition: MSStop.h:85
bool isPerson() const
Whether it is a person.
Abstract in-vehicle device.
SUMOVehicle & myHolder
The vehicle that stores the device.
int getPersonCapacity() const
Get this vehicle type's person capacity.
double getLength() const
Get vehicle's length [m].
int getContainerCapacity() const
Get this vehicle type's container capacity.
const std::string & getID() const
Returns the id.
Definition: Named.h:74
A storage for options typed value containers)
Definition: OptionsCont.h:89
void addDescription(const std::string &name, const std::string &subtopic, const std::string &description)
Adds a description for an option.
void doRegister(const std::string &name, Option *v)
Adds an option under the given name.
Definition: OptionsCont.cpp:76
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
void addOptionSubTopic(const std::string &topic)
Adds an option subtopic.
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:59
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:61
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:251
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
An upper class for objects with additional parameters.
Definition: Parameterised.h:41
void setParametersStr(const std::string &paramsString, const std::string kvsep="=", const std::string sep="|")
set the inner key/value map in string format "key1=value1|key2=value2|...|keyN=valueN"
const Parameterised::Map & getParametersMap() const
Returns the inner key/value map.
virtual bool compute(const E *from, const E *to, const V *const vehicle, SUMOTime msTime, std::vector< const E * > &into, bool silent=false)=0
Builds the route between the given edges using the minimum effort at the given time The definition of...
Representation of a vehicle, person, or container.
virtual const MSVehicleType & getVehicleType() const =0
Returns the object's "vehicle" type.
virtual const MSLane * getLane() const =0
Returns the lane the object is currently at.
virtual bool isStopped() const =0
Returns whether the object is at a stop.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle's parameter (including departure definition)
virtual SUMOVehicleClass getVClass() const =0
Returns the object's access class.
virtual int getRoutePosition() const =0
return index of edge within route
virtual const MSEdge * getEdge() const =0
Returns the edge the object is currently at.
virtual double getPositionOnLane() const =0
Get the object's position along the lane.
Representation of a vehicle.
Definition: SUMOVehicle.h:60
virtual bool replaceRouteEdges(ConstMSEdgeVector &edges, double cost, double savings, const std::string &info, bool onInit=false, bool check=false, bool removeStops=true, std::string *msgReturn=nullptr)=0
Replaces the current route by the given edges.
virtual const std::vector< MSTransportable * > & getContainers() const =0
retrieve riding containers
virtual const MSEdge * getRerouteOrigin() const =0
Returns the starting point for reroutes (usually the current edge)
virtual void reroute(SUMOTime t, const std::string &info, SUMOAbstractRouter< MSEdge, SUMOVehicle > &router, const bool onInit=false, const bool withTaz=false, const bool silent=false)=0
Performs a rerouting using the given router.
virtual bool hasStops() const =0
Returns whether the vehicle has to stop somewhere.
virtual bool addStop(const SUMOVehicleParameter::Stop &stopPar, std::string &errorMsg, SUMOTime untilOffset=0, ConstMSEdgeVector::const_iterator *searchStart=0)=0
Adds a stop.
virtual const std::list< MSStop > & getStops() const =0
virtual int getRNGIndex() const =0
virtual int getPersonNumber() const =0
Returns the number of persons.
virtual const std::vector< MSTransportable * > & getPersons() const =0
retrieve riding persons
virtual int getContainerNumber() const =0
Returns the number of containers.
virtual MSVehicleDevice * getDevice(const std::type_info &type) const =0
Returns a device of the given type if it exists or 0.
virtual double getBrakeGap(bool delayed=false) const =0
get distance for coming to a stop (used for rerouting checks)
virtual MSStop & getNextStop()=0
virtual const MSRoute & getRoute() const =0
Returns the current route.
virtual bool abortNextStop(int nextStopIndex=0)=0
deletes the next stop at the given index if it exists
Definition of vehicle stop (position and duration)
ParkingType parking
whether the vehicle is removed from the net while stopping
std::string lane
The lane to stop at.
double startPos
The stopping position start.
int index
at which position in the stops list
std::string actType
act Type (only used by Persons) (used by NETEDIT)
double endPos
The stopping position end.
Structure representing possible vehicle parameter.
DepartDefinition departProcedure
Information how the vehicle shall choose the depart time.
std::string line
The vehicle's line (mainly for public transport)
static ParkingType parseParkingType(const std::string &value)
parses parking type value
A wrapper for a Command function.
Definition: StaticCommand.h:38
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
std::string line
Definition: MSDispatch.h:78