Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSDevice_Taxi.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2013-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/****************************************************************************/
18// A device which controls a taxi
19/****************************************************************************/
20#include <config.h>
21
32#include <microsim/MSGlobals.h>
33#include <microsim/MSVehicle.h>
34#include <microsim/MSEdge.h>
35#include <microsim/MSLane.h>
36#include <microsim/MSStop.h>
39
40#include "MSDispatch.h"
41#include "MSDispatch_Greedy.h"
44#include "MSDispatch_TraCI.h"
45
46#include "MSIdling.h"
47
48#include "MSRoutingEngine.h"
49#include "MSDevice_Routing.h"
50#include "MSDevice_Taxi.h"
51
52//#define DEBUG_DISPATCH
53//#define DEBUG_CANCEL
54
55//#define DEBUG_COND (myHolder.isSelected())
56#define DEBUG_COND (true)
57
58// ===========================================================================
59// static member variables
60// ===========================================================================
66// @brief the list of available taxis
67std::vector<MSDevice_Taxi*> MSDevice_Taxi::myFleet;
70std::map<SUMOVehicleClass, std::string> MSDevice_Taxi::myTaxiTypes;
72std::map<std::string, MSDevice_Taxi*> MSDevice_Taxi::myStateLoadedCustomers;
73std::map<std::string, MSDevice_Taxi*> MSDevice_Taxi::myStateLoadedReservations;
74
75#define TAXI_SERVICE "taxi"
76#define TAXI_SERVICE_PREFIX "taxi:"
77#define SWAP_THRESHOLD 5
78
79// ===========================================================================
80// method definitions
81// ===========================================================================
82// ---------------------------------------------------------------------------
83// static initialisation methods
84// ---------------------------------------------------------------------------
85void
87 oc.addOptionSubTopic("Taxi Device");
88 insertDefaultAssignmentOptions("taxi", "Taxi Device", oc);
89
90 oc.doRegister("device.taxi.dispatch-algorithm", new Option_String("greedy"));
91 oc.addDescription("device.taxi.dispatch-algorithm", "Taxi Device", TL("The dispatch algorithm [greedy|greedyClosest|greedyShared|routeExtension|traci]"));
92
93 oc.doRegister("device.taxi.dispatch-algorithm.output", new Option_FileName());
94 oc.addDescription("device.taxi.dispatch-algorithm.output", "Taxi Device", TL("Write information from the dispatch algorithm to FILE"));
95
96 oc.doRegister("device.taxi.dispatch-algorithm.params", new Option_String(""));
97 oc.addDescription("device.taxi.dispatch-algorithm.params", "Taxi Device", TL("Load dispatch algorithm parameters in format KEY1:VALUE1[,KEY2:VALUE]"));
98
99 oc.doRegister("device.taxi.dispatch-period", new Option_String("60", "TIME"));
100 oc.addDescription("device.taxi.dispatch-period", "Taxi Device", TL("The period between successive calls to the dispatcher"));
101
102 oc.doRegister("device.taxi.dispatch-keep-unreachable", new Option_String("3600", "TIME"));
103 oc.addDescription("device.taxi.dispatch-keep-unreachable", "Taxi Device", TL("The time before aborting unreachable reservations"));
104
105 oc.doRegister("device.taxi.idle-algorithm", new Option_String("stop"));
106 oc.addDescription("device.taxi.idle-algorithm", "Taxi Device", TL("The behavior of idle taxis [stop|randomCircling|taxistand]"));
107
108 oc.doRegister("device.taxi.idle-algorithm.output", new Option_FileName());
109 oc.addDescription("device.taxi.idle-algorithm.output", "Taxi Device", TL("Write information from the idling algorithm to FILE"));
110
111 oc.doRegister("device.taxi.vclasses", new Option_StringVector({"taxi"}));
112 oc.addSynonyme("device.taxi.vclasses", "taxi.vclasses");
113 oc.addDescription("device.taxi.vclasses", "Taxi Device", TL("Network permissions that can be accessed by taxis"));
114}
115
116
117void
118MSDevice_Taxi::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
120 if (equippedByDefaultAssignmentOptions(oc, "taxi", v, false)) {
121 // build the device
122 MSDevice_Taxi* device = new MSDevice_Taxi(v, "taxi_" + v.getID());
123 into.push_back(device);
124 myFleet.push_back(device);
125 if (v.getParameter().line == "") {
126 // automatically set the line so that persons are willing to enter
127 // (see MSStageDriving::isWaitingFor)
128 const_cast<SUMOVehicleParameter&>(v.getParameter()).line = TAXI_SERVICE;
129 }
130 const int personCapacity = v.getVehicleType().getPersonCapacity();
131 const int containerCapacity = v.getVehicleType().getContainerCapacity();
132 myMaxCapacity = MAX2(myMaxCapacity, personCapacity);
134 if (myTaxiTypes[v.getVClass()] == "") {
136 }
137 if ((gTaxiClasses & v.getVClass()) == 0) {
138 gTaxiClasses |= v.getVClass();
140 }
141 if (personCapacity < 1 && containerCapacity < 1) {
142 WRITE_WARNINGF(TL("Vehicle '%' with personCapacity % and containerCapacity % is not usable as taxi."), v.getID(), toString(personCapacity), toString(containerCapacity));
143 }
144 }
145}
146
151
152void
155 myDispatchPeriod = string2time(oc.getString("device.taxi.dispatch-period"));
156 // init dispatch algorithm
157 std::string algo = oc.getString("device.taxi.dispatch-algorithm");
158 Parameterised params;
159 params.setParametersStr(OptionsCont::getOptions().getString("device.taxi.dispatch-algorithm.params"), ":", ",");
160 if (algo == "greedy") {
162 } else if (algo == "greedyClosest") {
164 } else if (algo == "greedyShared") {
166 } else if (algo == "routeExtension") {
168 } else if (algo == "traci") {
170 } else {
171 throw ProcessError(TLF("Dispatch algorithm '%' is not known", algo));
172 }
174 // round to next multiple of myDispatchPeriod
175 if (next < 0) {
177 const SUMOTime begin = string2time(oc.getString("begin"));
178 const SUMOTime delay = (myDispatchPeriod - ((now - begin) % myDispatchPeriod)) % myDispatchPeriod;
179 next = now + delay;
180 }
181 myNextDispatchTime = next;
183}
184
185bool
186MSDevice_Taxi::isReservation(const std::set<std::string>& lines) {
187 return lines.size() == 1 && (
188 *lines.begin() == TAXI_SERVICE
189 || StringUtils::startsWith(*lines.begin(), TAXI_SERVICE_PREFIX));
190}
191
192void
194 const std::set<std::string>& lines,
195 SUMOTime reservationTime,
196 SUMOTime pickupTime,
197 SUMOTime earliestPickupTime,
198 const MSEdge* from, double fromPos,
199 const MSStoppingPlace* fromStop,
200 const MSEdge* to, double toPos,
201 const MSStoppingPlace* toStop,
202 const std::string& group) {
203 if (!isReservation(lines)) {
204 return;
205 }
206 if ((to->getPermissions() & gTaxiClasses) == 0) {
207 throw ProcessError("Cannot add taxi reservation for " + std::string(person->isPerson() ? "person" : "container")
208 + " '" + person->getID() + "' because destination edge '" + to->getID() + "'"
209 + " does not permit taxi access");
210 }
211 if ((from->getPermissions() & gTaxiClasses) == 0) {
212 throw ProcessError("Cannot add taxi reservation for " + std::string(person->isPerson() ? "person" : "container")
213 + " '" + person->getID() + "' because origin edge '" + from->getID() + "'"
214 + " does not permit taxi access");
215 }
216 if (myDispatchCommand == nullptr) {
217 initDispatch();
218 }
219 if (fromStop != nullptr && &fromStop->getLane().getEdge() == from) {
220 // pickup position should be at the stop-endPos
221 fromPos = fromStop->getEndLanePosition();
222 }
223 Reservation* res = myDispatcher->addReservation(person, reservationTime, pickupTime, earliestPickupTime, from, fromPos, fromStop, to, toPos, toStop, group, *lines.begin(), myMaxCapacity, myMaxContainerCapacity);
224 if (myStateLoadedCustomers.size() > 0) {
225 auto it = myStateLoadedCustomers.find(person->getID());
226 if (it != myStateLoadedCustomers.end()) {
227 //std::cout << SIMTIME << " loadedServed p=" << person->getID() << " res=" << res->getID() << " taxi=" << it->second->getID() << "\n";
228 myDispatcher->servedReservation(res, it->second);
229 }
230 }
231}
232
233void
235 const std::set<std::string>& lines,
236 const MSEdge* from, double fromPos,
237 const MSEdge* to, double toPos,
238 const std::string& group) {
239 if (myDispatcher != nullptr && lines.size() == 1 && *lines.begin() == TAXI_SERVICE) {
240 myDispatcher->removeReservation(person, from, fromPos, to, toPos, group);
241 }
242}
243
244void
246 const std::set<std::string>& lines,
247 const MSEdge* from, double fromPos,
248 const MSEdge* to, double toPos,
249 const std::string& group, double newFromPos) {
250 if (myDispatcher != nullptr && lines.size() == 1 && *lines.begin() == TAXI_SERVICE) {
251 myDispatcher->updateReservationFromPos(person, from, fromPos, to, toPos, group, newFromPos);
252 }
253}
254
255
258 std::vector<MSDevice_Taxi*> active;
259 for (MSDevice_Taxi* taxi : myFleet) {
260 if (taxi->getHolder().hasDeparted()) {
261 active.push_back(taxi);
262 }
263 }
264 myDispatcher->computeDispatch(currentTime, active);
265 myNextDispatchTime = currentTime + myDispatchPeriod;
266 return myDispatchPeriod;
267}
268
269bool
273
274void
276 if (myDispatcher != nullptr) {
277 delete myDispatcher;
278 myDispatcher = nullptr;
279 }
280 myDispatchCommand = nullptr;
281 myTaxiTypes.clear();
282}
283
284
285void
287 for (MSDevice_Taxi* taxi : myFleet) {
288 // disable taskSwap
289 taxi->myState = EMPTY;
290 }
291}
292
293
294const std::map<SUMOVehicleClass, std::string>&
296 const int numClasses = std::bitset<64>(gTaxiClasses).count();
297 if ((int)myTaxiTypes.size() < numClasses) {
298 for (const std::string& vClassName : OptionsCont::getOptions().getStringVector("device.taxi.vclasses")) {
300 if (myTaxiTypes[svc] == "") {
301 switch(svc) {
302 // @see MSVehicleControl::initDefaultTypes()
303 case SVC_TAXI:
305 break;
306 case SVC_RAIL:
308 break;
309 case SVC_BICYCLE:
311 break;
312 case SVC_PASSENGER:
314 break;
315 default: {
316 const std::string typeID = "DEFAULT_" + StringUtils::to_upper_case(vClassName) + "TYPE";
318 if (!vc.hasVType(typeID)) {
319 SUMOVTypeParameter tp(typeID, svc);
321 vc.addVType(t);
322 }
323 myTaxiTypes[svc] = typeID;;
324 }
325 }
326 }
327 }
328 }
329 return myTaxiTypes;
330}
331
332
333// ---------------------------------------------------------------------------
334// MSDevice_Taxi-methods
335// ---------------------------------------------------------------------------
336MSDevice_Taxi::MSDevice_Taxi(SUMOVehicle& holder, const std::string& id) :
337 MSVehicleDevice(holder, id) {
338 std::string defaultServiceEnd = toString(1e15);
339 const std::string algo = holder.getStringParam("device.taxi.idle-algorithm");
340 if (algo == "stop") {
342 } else if (algo == "randomCircling") {
344 // make sure simulation terminates
345 defaultServiceEnd = toString(STEPS2TIME(
348 : MSNet::getInstance()->getCurrentTimeStep()) + (3600 * 8));
349 } else if (algo == "taxistand") {
350 const std::string rerouterID = holder.getStringParam("device.taxi.stands-rerouter");
351 if (rerouterID.empty()) {
352 throw ProcessError("Idle algorithm '" + algo + "' requires a rerouter id to be defined using device param 'stands-rerouter' for vehicle '" + myHolder.getID() + "'");
353 }
354 if (MSTriggeredRerouter::getInstances().count(rerouterID) == 0) {
355 throw ProcessError("Unknown rerouter '" + rerouterID + "' when loading taxi stands for vehicle '" + myHolder.getID() + "'");
356 }
357 MSTriggeredRerouter* rerouter = MSTriggeredRerouter::getInstances().find(rerouterID)->second;
358 myIdleAlgorithm = new MSIdling_TaxiStand(rerouter);
359 } else {
360 throw ProcessError("Idle algorithm '" + algo + "' is not known for vehicle '" + myHolder.getID() + "'");
361 }
362 myServiceEnd = string2time(holder.getStringParam("device.taxi.end", false, defaultServiceEnd));
364}
365
366
368 myFleet.erase(std::find(myFleet.begin(), myFleet.end(), this));
369 // recompute myMaxCapacity
370 myMaxCapacity = 0;
372 for (MSDevice_Taxi* taxi : myFleet) {
373 myMaxCapacity = MAX2(myMaxCapacity, taxi->getHolder().getVehicleType().getPersonCapacity());
374 myMaxContainerCapacity = MAX2(myMaxContainerCapacity, taxi->getHolder().getVehicleType().getContainerCapacity());
375 }
376 delete myIdleAlgorithm;
377}
378
379
380bool
382 return myFleet.size() > 0;;
383}
384
385
386void
388 dispatchShared({&res, &res});
389}
390
391
392void
393MSDevice_Taxi::dispatchShared(std::vector<const Reservation*> reservations) {
394#ifdef DEBUG_DISPATCH
395 if (DEBUG_COND) {
396 std::cout << SIMTIME << " taxi=" << myHolder.getID() << " dispatch:\n";
397 for (const Reservation* res : reservations) {
398 std::cout << " res=" << res->getID();
399 std::cout << " persons=" << toString(res->persons) << "\n";
400 }
401 }
402#endif
403 myLastDispatch = reservations;
404 ConstMSEdgeVector tmpEdges;
405 StopParVector stops;
406 double lastPos = myHolder.getPositionOnLane();
407 const MSEdge* rerouteOrigin = *myHolder.getRerouteOrigin();
408 if (isEmpty()) {
409 // start fresh from the current edge
411 // parking stop must be ended normally
413 stop.duration = 0;
414 lastPos = stop.pars.endPos;
416 stop.triggered = false;
417 stop.containerTriggered = false;
418 stop.joinTriggered = false;
420 }
421 // prevent unauthorized/premature entry
422 const_cast<SUMOVehicleParameter::Stop&>(stop.pars).permitted.insert("");
423 while (myHolder.getStops().size() > 1) {
425 }
426 } else {
427 while (myHolder.hasStops()) {
428 // in meso there might be more than 1 stop at this point
430 }
431 assert(!myHolder.hasStops());
432 }
433 tmpEdges.push_back(myHolder.getEdge());
434 if (myHolder.getEdge() != rerouteOrigin) {
435 tmpEdges.push_back(rerouteOrigin);
436 }
437 } else {
438 assert(myHolder.hasStops());
439 // check how often existing customers appear in the new reservations
440 std::map<const MSTransportable*, int> nOccur;
441 for (const Reservation* res : reservations) {
442 for (const MSTransportable* person : res->persons) {
443 if (myCustomers.count(person) != 0) {
444 nOccur[person] += 1;
445 if (myCurrentReservations.count(res) == 0) {
446 throw ProcessError(TLF("Invalid Re-dispatch for existing customer '%' with a new reservation", person->getID()));
447 }
448 }
449 }
450 }
451#ifdef DEBUG_DISPATCH
452 if (DEBUG_COND) {
453 for (auto item : nOccur) {
454 std::cout << " previousCustomer=" << item.first->getID() << " occurs=" << item.second << "\n";
455 }
456 }
457#endif
458 if (nOccur.size() == 0) {
459 // no overlap with existing customers - extend route
460 tmpEdges = myHolder.getRoute().getEdges();
461 lastPos = myHolder.getStops().back().pars.endPos;
462#ifdef DEBUG_DISPATCH
463 if (DEBUG_COND) {
464 std::cout << " re-dispatch with route-extension\n";
465 }
466#endif
467 } else if (nOccur.size() == myCustomers.size()) {
468 // redefine route (verify correct number of mentions)
469 std::set<const MSTransportable*> onBoard;
470 const std::vector<MSTransportable*>& onBoardP = myHolder.getPersons();
471 const std::vector<MSTransportable*>& onBoardC = myHolder.getContainers();
472 onBoard.insert(onBoardP.begin(), onBoardP.end());
473 onBoard.insert(onBoardC.begin(), onBoardC.end());
474 std::set<const MSTransportable*> redundantPickup;
475 for (auto item : nOccur) {
476 if (item.second == 1) {
477 // customers must already be on board
478 if (onBoard.count(item.first) == 0) {
479 throw ProcessError(TLF("Re-dispatch did not mention pickup for existing customer '%'", item.first->getID()));
480 }
481 } else if (item.second == 2) {
482 if (onBoard.count(item.first) == 0) {
483 // treat like a new customer
484 // TODO: need to be checked
485 myCustomers.erase(item.first);
486 } else {
487 redundantPickup.insert(item.first);
488 }
489 } else {
490 throw ProcessError("Re-dispatch mentions existing customer '" + item.first->getID() + "' " + toString(item.second) + " times");
491 }
492 }
493 // remove redundancy
494 if (!redundantPickup.empty()) {
495 for (auto it = reservations.begin(); it != reservations.end();) {
496 bool isRedundant = false;
497 for (const MSTransportable* person : (*it)->persons) {
498 if (redundantPickup.count(person) != 0) {
499 isRedundant = true;
500 break;
501 }
502 }
503 if (isRedundant) {
504 for (const MSTransportable* person : (*it)->persons) {
505 redundantPickup.erase(person);
506 }
507 it = reservations.erase(it);
508 } else {
509 it++;
510 }
511 }
512 }
513 while (myHolder.hasStops()) {
515 }
516 tmpEdges.push_back(myHolder.getEdge());
517 if (myHolder.getEdge() != rerouteOrigin) {
518 tmpEdges.push_back(rerouteOrigin);
519 }
520#ifdef DEBUG_DISPATCH
521 if (DEBUG_COND) {
522 std::cout << " re-dispatch from scratch\n";
523 }
524#endif
525 } else {
526 // inconsistent re-dispatch
527 std::vector<std::string> missing;
528 for (const MSTransportable* c : myCustomers) {
529 if (nOccur.count(c) == 0) {
530 missing.push_back(c->getID());
531 }
532 }
533 throw ProcessError("Re-dispatch did mention some customers but failed to mention " + joinToStringSorting(missing, " "));
534 }
535 }
536
538 bool hasPickup = false;
539 for (const Reservation* res : reservations) {
540 myCurrentReservations.insert(res);
541 bool isPickup = false;
542 for (const MSTransportable* person : res->persons) {
543 if (myCustomers.count(person) == 0) {
544 myCustomers.insert(person);
545 isPickup = true;
546 hasPickup = true;
547 }
548 }
549 if (isPickup) {
550 prepareStop(tmpEdges, stops, lastPos, res->from, res->fromPos, res->fromStop, "pickup " + toString(res->persons) + " (" + res->id + ")", res, isPickup);
551 for (const MSTransportable* const transportable : res->persons) {
552 if (transportable->isPerson()) {
553 stops.back().triggered = true;
554 } else {
555 stops.back().containerTriggered = true;
556 }
557 stops.back().permitted.insert(transportable->getID());
558 stops.back().parametersSet |= STOP_PERMITTED_SET | STOP_TRIGGER_SET;
559 }
560 // proof this lines: Is needed for pre-booking?
561 std::set<const MSTransportable*> persons = res->persons;
562 for (auto itr = persons.begin(); itr != persons.end(); itr++) {
563 stops.back().awaitedPersons.insert((*itr)->getID());
564 }
565
566 if (stops.back().duration == -1) {
567 // keep dropOffDuration if the stop is dropOff and pickUp
568 stops.back().duration = TIME2STEPS(myHolder.getFloatParam("device.taxi.pickUpDuration", false, 0));
569 }
570 } else {
571 prepareStop(tmpEdges, stops, lastPos, res->to, res->toPos, res->toStop, "dropOff " + toString(res->persons) + " (" + res->id + ")", res, isPickup);
572 stops.back().duration = TIME2STEPS(myHolder.getFloatParam("device.taxi.dropOffDuration", false, 60)); // pay and collect bags
573 }
574 stops.back().parametersSet |= STOP_DURATION_SET | STOP_PARKING_SET;
575 }
576#ifdef DEBUG_DISPATCH
577 if (DEBUG_COND) {
578 std::cout << " tmpEdges=" << toString(tmpEdges) << "\n";
579 }
580#endif
581 if (!myHolder.replaceRouteEdges(tmpEdges, -1, 0, "taxi:prepare_dispatch", false, false, false)) {
582 throw ProcessError("Route replacement for taxi dispatch failed for vehicle '" + myHolder.getID()
583 + "' at time=" + time2string(t) + ".");
584 }
585#ifdef DEBUG_DISPATCH
586 if (DEBUG_COND) std::cout << " replacedRoute=" << toString(tmpEdges)
587 << "\n actualRoute=" << toString(myHolder.getRoute().getEdges()) << "\n";
588#endif
589 for (SUMOVehicleParameter::Stop& stop : stops) {
590 std::string error;
591 if (!myHolder.addStop(stop, error)) {
592 WRITE_WARNINGF(TL("Could not add taxi stop for %, desc=% time=% error=%"), myHolder.getID(), stop.actType, time2string(t), error)
593 }
594 }
596 // SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = myHolder.getInfluencer().getRouterTT(veh->getRNGIndex())
597 myHolder.reroute(t, "taxi:dispatch", router, false);
598#ifdef DEBUG_DISPATCH
599 if (DEBUG_COND) {
600 std::cout << "\n finalRoute=" << toString(myHolder.getRoute().getEdges()) << " routeIndex=" << myHolder.getRoutePosition() << "\n";
601 }
602#endif
603 if (hasPickup) {
604 myState |= PICKUP;
605 }
606}
607
608
609void
611 // check if taxi has stopped
612 if (myHolder.getNextStopParameter() == nullptr) {
613 return;
614 }
615 // find customers of the current stop
616 std::set<const MSTransportable*> customersToBeRemoved;
617 std::set<const MSTransportable*> onBoard;
618 onBoard.insert(myHolder.getPersons().begin(), myHolder.getPersons().end());
619 onBoard.insert(myHolder.getContainers().begin(), myHolder.getContainers().end());
620 for (std::string tID : myHolder.getNextStopParameter()->permitted) {
621 for (auto t : myCustomers) {
622 if (t->getID() == tID && onBoard.count(t) == 0) {
623 customersToBeRemoved.insert(t);
624 }
625 }
626 }
627 if (!customersToBeRemoved.empty()) {
628 WRITE_WARNINGF(TL("Taxi '%' aborts waiting for customers: % at time=%."),
629 myHolder.getID(), toString(customersToBeRemoved), time2string(SIMSTEP));
630 }
631 for (auto t : customersToBeRemoved) {
633 }
634}
635
636
637bool
639#ifdef DEBUG_CANCEL
640 if (DEBUG_COND) {
641 std::cout << SIMTIME << " taxi=" << myHolder.getID() << " cancelCustomer " << t->getID() << "\n";
642 }
643#endif
644
645 // is the given transportable a customer of the reservations?
646 if (myCustomers.count(t) == 0) {
647 return false;
648 }
649 myCustomers.erase(t);
650 // check whether a single reservation has been fulfilled or another customer is part of the reservation
651 for (auto resIt = myCurrentReservations.begin(); resIt != myCurrentReservations.end();) {
652 bool fulfilled = false;
653 if ((*resIt)->persons.size() == 1 && (*resIt)->persons.count(t) != 0) {
654 // the reservation contains only the customer
655 fulfilled = true;
656 }
657 if (fulfilled) {
658 const Reservation* res = *resIt;
659 // remove reservation from the current dispatch
660 for (auto it = myLastDispatch.begin(); it != myLastDispatch.end();) {
661 if (*it == res) {
662 it = myLastDispatch.erase(it);
663 } else {
664 ++it;
665 }
666 }
667 // remove reservation from the served reservations
668 resIt = myCurrentReservations.erase(resIt);
669 // delete the reservation
671 } else {
672 ++resIt;
673 }
674 }
675 myState &= ~PICKUP; // remove state PICKUP
676 for (const Reservation* res : myCurrentReservations) {
677 // if there is another pickup in the dispatch left, add the state PICKUP
678 if (std::count(myLastDispatch.begin(), myLastDispatch.end(), res) == 2) {
679 myState |= PICKUP; // add state PICKUP
680 }
681 }
682 // we also have to clean reservations from myLastDispatch where the customers arrived in the meantime
683 for (auto it = myLastDispatch.begin(); it != myLastDispatch.end();) {
684 if (myCurrentReservations.count(*it) == 0) {
685 it = myLastDispatch.erase(it);
686 } else {
687 ++it;
688 }
689 }
690 // if there are reservations left, go on with the dispatch
691 // in meso, wait for the next dispatch cycle to avoid updating stops in this stage
694 }
695 return true;
696}
697
698
699void
701 myCustomers.insert(t);
702 MSBaseVehicle& veh = dynamic_cast<MSBaseVehicle&>(myHolder);
703 for (const MSStop& stop : veh.getStops()) {
704 SUMOVehicleParameter::Stop& pars = const_cast<SUMOVehicleParameter::Stop&>(stop.pars);
705 //std::cout << " sE=" << (*stop.edge)->getID() << " sStart=" << pars.startPos << " sEnd=" << pars.endPos << " rFrom=" <<
706 // res->from->getID() << " rTo=" << res->to->getID() << " rFromPos=" << res->fromPos << " resToPos=" << res->toPos << "\n";
707 if (*stop.edge == res->from
708 && pars.startPos <= res->fromPos
709 && pars.endPos >= res->fromPos) {
710 pars.awaitedPersons.insert(t->getID());
711 pars.permitted.insert(t->getID());
712 pars.actType += " +" + t->getID();
713 } else if (*stop.edge == res->to
714 && pars.startPos <= res->toPos
715 && pars.endPos >= res->toPos) {
716 pars.actType += " +" + t->getID();
717 break;
718 }
719 }
720}
721
722
723void
725 StopParVector& stops,
726 double& lastPos, const MSEdge* stopEdge, double stopPos,
727 const MSStoppingPlace* stopPlace,
728 const std::string& action, const Reservation* res, const bool isPickup) {
729 assert(!edges.empty());
730 if (stopPlace != nullptr && &stopPlace->getLane().getEdge() == stopEdge) {
731 stopPos = stopPlace->getEndLanePosition();
732 }
733 if (stopPos < lastPos && stopPos + NUMERICAL_EPS >= lastPos) {
734 stopPos = lastPos;
735 }
736 bool addedEdge = false;
737
738 if (stops.empty()) {
739 // check brakeGap
740 double distToStop = stopPos - lastPos;
741 const double brakeGap = myHolder.getBrakeGap();
742 if (myHolder.getLane() != nullptr && myHolder.getLane()->isInternal()) {
743 distToStop += myHolder.getLane()->getLength();
744 }
745 if (stopEdge != edges.back()) {
746 distToStop += edges.back()->getLength();
747 if (distToStop < brakeGap) {
748 // the distance between current edge and stop edge may be small
750 ConstMSEdgeVector toFirstStop;
751 router.compute(edges.back(), stopEdge, &myHolder, SIMSTEP, toFirstStop, true);
752 for (int i = 1; i < (int)toFirstStop.size() - 1; i++) {
753 distToStop += toFirstStop[i]->getLength();
754 }
755 }
756 }
757 if (distToStop < brakeGap) {
758 // circle back to stopEdge
759 //std::cout << SIMTIME << " taxi=" << getID() << " brakeGap=" << brakeGap << " distToStop=" << distToStop << "\n";
760 edges.push_back(stopEdge);
761 addedEdge = true;
762 }
763 }
764
765 if (stopEdge == edges.back() && !stops.empty()) {
766 if (stopPos >= lastPos && stopPos <= stops.back().endPos) {
767 // no new stop and no adaption needed
768 stops.back().actType += "," + action;
769 return;
770 }
771 if (stopPos >= lastPos && stopPos <= lastPos + myHolder.getVehicleType().getLength()) {
772 // stop length adaption needed
773 stops.back().endPos = MIN2(lastPos + myHolder.getVehicleType().getLength(), stopEdge->getLength());
774 stops.back().actType += "," + action;
775 return;
776 }
777 }
778 if (!addedEdge && (stopEdge != edges.back() || stopPos < lastPos)) {
779 //std::cout << SIMTIME << " stopPos=" << stopPos << " lastPos=" << lastPos << "\n";
780 edges.push_back(stopEdge);
781 }
782 lastPos = stopPos;
784 stop.lane = getStopLane(stopEdge, action)->getID();
785 if (stopPlace != nullptr && &stopPlace->getLane().getEdge() == stopEdge) {
786 stop.startPos = stopPlace->getBeginLanePosition();
787 stop.endPos = stopPlace->getEndLanePosition();
788 const SumoXMLTag tag = stopPlace->getElement();
789 if (tag == SUMO_TAG_BUS_STOP || tag == SUMO_TAG_TRAIN_STOP) {
790 stop.busstop = stopPlace->getID();
791 } else if (tag == SUMO_TAG_PARKING_AREA) {
792 stop.parkingarea = stopPlace->getID();
793 } else if (tag == SUMO_TAG_CONTAINER_STOP) {
794 stop.containerstop = stopPlace->getID();
795 }
796 } else {
797 stop.startPos = stopPos;
798 stop.endPos = MAX2(stopPos, MIN2(myHolder.getVehicleType().getLength(), stopEdge->getLength()));
800 }
801 stop.parking = SUMOVehicleParameter::parseParkingType(myHolder.getStringParam("device.taxi.parking", false, "true"));
802 stop.actType = action;
803 stop.index = STOP_INDEX_END;
804 // In case of prebooking if person is not there/ comes to late for pickup set maximum waiting time:
805 SUMOTime earliestPickupTime = res->earliestPickupTime;
806 if (isPickup && earliestPickupTime >= 0) {
807 stop.waitUntil = earliestPickupTime;
808 // TODO: replace hard coded extension with parameter
809 stop.extension = static_cast<SUMOTime>(3 * 60 * 1000); // 3mins
810 }
811 stops.push_back(stop);
812}
813
814
815MSLane*
816MSDevice_Taxi::getStopLane(const MSEdge* edge, const std::string& action) {
817 const std::vector<MSLane*>* allowedLanes = edge->allowedLanes(myHolder.getVClass());
818 if (allowedLanes == nullptr) {
819 throw ProcessError("Taxi vehicle '" + myHolder.getID() + "' cannot stop on edge '" + edge->getID() + "' (" + action + ")");
820 }
821 return allowedLanes->front();
822}
823
824bool
826 return myState == EMPTY;
827}
828
829
830bool
832 return myCustomers.count(t) != 0;
833}
834
835
836void
837MSDevice_Taxi::updateMove(const SUMOTime traveltime, const double travelledDist) {
839 myOccupiedDistance += travelledDist;
840 myOccupiedTime += traveltime;
841 }
842 if (isEmpty()) {
843 if (MSNet::getInstance()->getCurrentTimeStep() < myServiceEnd) {
844 myIdleAlgorithm->idle(this);
845 if (myRoutingDevice != nullptr) {
846 // prevent rerouting during idling (#11079)
848 }
849 } else if (!myReachedServiceEnd) {
850 WRITE_WARNINGF(TL("Taxi '%' reaches scheduled end of service at time=%."), myHolder.getID(), time2string(SIMSTEP));
851 myReachedServiceEnd = true;
852 }
853 } else if (myRoutingDevice != nullptr) {
855 }
857 // limit duration of stop (but only for idling-related stops)
859 }
860#ifdef DEBUG_DISPATCH
862 std::cout << SIMTIME << " updateMove veh=" << myHolder.getID() << " myIsStopped=" << myIsStopped << " myHolderStopped=" << myHolder.isStopped() << " myState=" << myState << "\n";
863 }
864#endif
866}
867
868
869bool
871 double newPos, double /*newSpeed*/) {
872 updateMove(DELTA_T, newPos - oldPos);
873 return true; // keep the device
874}
875
876
877void
879 const double /* frontOnLane */,
880 const double timeOnLane,
881 const double /* meanSpeedFrontOnLane */,
882 const double /* meanSpeedVehicleOnLane */,
883 const double travelledDistanceFrontOnLane,
884 const double /* travelledDistanceVehicleOnLane */,
885 const double /* meanLengthOnLane */) {
886 updateMove(TIME2STEPS(timeOnLane), travelledDistanceFrontOnLane);
887}
888
889
890bool
892 if (isEmpty() && MSNet::getInstance()->getCurrentTimeStep() < myServiceEnd) {
893 myIdleAlgorithm->idle(this);
894 }
895 return true; // keep the device
896}
897
898
899void
901 myState |= OCCUPIED;
902 if (!hasFuturePickup()) {
903 myState &= ~PICKUP;
904 }
905 for (const Reservation* res : myCurrentReservations) {
906 for (const MSTransportable* cand : res->persons) {
907 if (cand == t) {
908 const_cast<Reservation*>(res)->state = Reservation::ONBOARD;
909 break;
910 }
911 }
912 }
913}
914
915
916void
919 myCustomers.erase(person);
921 myState &= ~OCCUPIED;
922 if (myHolder.getStops().size() > 1 && (myState & PICKUP) == 0) {
923 WRITE_WARNINGF(TL("All customers left vehicle '%' at time=% but there are % remaining stops"),
925 while (myHolder.getStops().size() > 1) {
927 }
928 }
929 }
930 if (isEmpty()) {
931 // cleanup
932 for (const Reservation* res : myCurrentReservations) {
934 }
935 myCurrentReservations.clear();
937 if (isEmpty()) {
938 if (MSGlobals::gUseMesoSim && MSNet::getInstance()->getCurrentTimeStep() < myServiceEnd) {
939 myIdleAlgorithm->idle(this);
940 }
941 }
942 } else {
943 // check whether a single reservation has been fulfilled
944 for (auto resIt = myCurrentReservations.begin(); resIt != myCurrentReservations.end();) {
945 bool fulfilled = true;
946 for (const MSTransportable* t : (*resIt)->persons) {
947 if (myCustomers.count(t) != 0) {
948 fulfilled = false;
949 break;
950 }
951 }
952 if (fulfilled) {
954 resIt = myCurrentReservations.erase(resIt);
955 } else {
956 ++resIt;
957 }
958 }
959 }
960}
961
962
963void
965 const std::string swapGroup = myHolder.getStringParam("device.taxi.swapGroup", false, "");
966 if (swapGroup != "") {
968 const double stopTime = myHolder.isStopped() ? MAX2(0.0, STEPS2TIME(myHolder.getNextStop().duration)) : 0;
969 double maxSaving = 0;
970 MSDevice_Taxi* bestSwap = nullptr;
971 for (MSDevice_Taxi* taxi : myFleet) {
972 if (taxi->getHolder().hasDeparted() && taxi->getState() == PICKUP
973 && taxi->getHolder().getStringParam("device.taxi.swapGroup", false, "") == swapGroup) {
974 SUMOVehicle& veh = taxi->getHolder();
975 const MSStop& stop = veh.getNextStop();
976 ConstMSEdgeVector toPickup(veh.getCurrentRouteEdge(), stop.edge + 1);
977 const double cost = router.recomputeCostsPos(toPickup, &veh, veh.getPositionOnLane(), stop.pars.endPos, SIMSTEP);
978 ConstMSEdgeVector toPickup2;
979 router.compute(myHolder.getEdge(), myHolder.getPositionOnLane(), *stop.edge, stop.pars.endPos, &myHolder, SIMSTEP, toPickup2, true);
980 if (!toPickup2.empty()) {
981 const double cost2 = router.recomputeCostsPos(toPickup2, &myHolder, myHolder.getPositionOnLane(), stop.pars.endPos, SIMSTEP);
982 const double saving = cost - cost2 - stopTime;
983 //std::cout << SIMTIME << " taxi=" << getID() << " other=" << veh.getID() << " cost=" << cost << " cost2=" << cost2 << " stopTime=" << stopTime << " saving=" << saving << " route1=" << toString(toPickup) << " route2=" << toString(toPickup2) << "\n";
984 if (saving > maxSaving) {
985 maxSaving = saving;
986 bestSwap = taxi;
987 }
988 }
989 }
990 }
991 if (maxSaving > SWAP_THRESHOLD) {
992#ifdef DEBUG_DISPATCH
993 if (DEBUG_COND) {
994 std::cout << SIMTIME << " taxi=" << myHolder.getID() << " swapWith=" << bestSwap->getHolder().getID() << " saving=" << maxSaving << " lastDispatch=";
995 for (const Reservation* res : bestSwap->myLastDispatch) {
996 std::cout << toString(res->persons) << "; ";
997 }
998 std::cout << "\n";
999 }
1000#endif
1001 dispatchShared(bestSwap->myLastDispatch);
1002 bestSwap->myCurrentReservations.clear();
1003 bestSwap->myCustomers.clear();
1004 bestSwap->myState = EMPTY;
1005 while (bestSwap->getHolder().hasStops()) {
1006 bestSwap->getHolder().abortNextStop();
1007 }
1008 for (const Reservation* res : myCurrentReservations) {
1009 myDispatcher->swappedRunning(res, this);
1010 }
1011 }
1012 }
1013}
1014
1015
1016bool
1018 for (const auto& stop : myHolder.getStops()) {
1019 if (stop.reached) {
1020 continue;
1021 }
1022 if (stop.pars.permitted.size() > 0) {
1023 return true;
1024 }
1025 }
1026 return false;
1027}
1028
1029void
1031 if (tripinfoOut != nullptr) {
1032 tripinfoOut->openTag("taxi");
1033 tripinfoOut->writeAttr("customers", toString(myCustomersServed));
1034 tripinfoOut->writeAttr("occupiedDistance", toString(myOccupiedDistance));
1035 tripinfoOut->writeAttr("occupiedTime", time2string(myOccupiedTime));
1036 tripinfoOut->closeTag();
1037 }
1038}
1039
1040std::string
1041MSDevice_Taxi::getParameter(const std::string& key) const {
1042 if (key == "customers") {
1044 } else if (key == "occupiedDistance") {
1046 } else if (key == "occupiedTime") {
1048 } else if (key == "state") {
1049 return toString(myState);
1050 } else if (key == "currentCustomers") {
1052 } else if (key == "pickUpDuration") {
1053 return myHolder.getStringParam("device.taxi.pickUpDuration", false, "0");
1054 } else if (key == "dropOffDuration") {
1055 return myHolder.getStringParam("device.taxi.dropOffDuration", false, "60");
1056 }
1057 throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
1058}
1059
1060
1061void
1062MSDevice_Taxi::setParameter(const std::string& key, const std::string& value) {
1063 double doubleValue;
1064 try {
1065 doubleValue = StringUtils::toDouble(value);
1066 } catch (NumberFormatException&) {
1067 throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
1068 }
1069 if (key == "pickUpDuration" || key == "dropOffDuration") {
1070 // store as generic vehicle parameters
1071 ((SUMOVehicleParameter&)myHolder.getParameter()).setParameter("device.taxi." + key, value);
1072 } else {
1073 UNUSED_PARAMETER(doubleValue);
1074 throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
1075 }
1076}
1077
1078
1079void
1083 std::ostringstream internals;
1084 internals << myState
1085 << " " << myCustomersServed
1086 << " " << myOccupiedDistance
1087 << " " << myOccupiedTime;
1088 out.writeAttr(SUMO_ATTR_STATE, internals.str());
1089 if (myCustomers.size() > 0) {
1091 }
1092 if (myCurrentReservations.size() > 0) {
1094 }
1095 out.closeTag();
1096}
1097
1098
1099void
1101 bool ok = true;
1102 std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
1103 bis >> myState;
1104 bis >> myCustomersServed;
1105 bis >> myOccupiedDistance;
1106 bis >> myOccupiedTime;
1107 if (attrs.hasAttribute(SUMO_ATTR_CUSTOMERS)) {
1108 for (const std::string& id : attrs.get<std::vector<std::string> >(SUMO_ATTR_CUSTOMERS, getID().c_str(), ok)) {
1109 myStateLoadedCustomers[id] = this;
1110 }
1111 }
1113 for (const std::string& id : attrs.get<std::vector<std::string> >(SUMO_ATTR_RESERVATIONS, getID().c_str(), ok)) {
1114 myStateLoadedReservations[id] = this;
1115 }
1116 }
1117}
1118
1119
1120void
1122 if (myStateLoadedCustomers.size() > 0) {
1123 MSNet* net = MSNet::getInstance();
1124 MSTransportableControl* pc = net->hasPersons() ? &net->getPersonControl() : nullptr;
1125 MSTransportableControl* cc = net->hasContainers() ? &net->getContainerControl() : nullptr;
1126 for (auto item : myStateLoadedCustomers) {
1127 MSTransportable* t = nullptr;
1128 if (pc != nullptr) {
1129 t = pc->get(item.first);
1130 }
1131 if (t == nullptr && cc != nullptr) {
1132 t = cc->get(item.first);
1133 }
1134 if (t == nullptr) {
1135 WRITE_ERRORF("Could not find taxi customer '%'. Ensure state contains transportables", item.first);
1136 } else {
1137 item.second->myCustomers.insert(t);
1138 }
1139 }
1140 }
1141 if (myStateLoadedReservations.size() > 0) {
1142 assert(myDispatcher != nullptr);
1143 std::map<std::string, const Reservation*> resLookup;
1144 for (const Reservation* res : myDispatcher->getReservations()) {
1145 resLookup[res->getID()] = res;
1146 }
1147 for (const Reservation* res : myDispatcher->getRunningReservations()) {
1148 resLookup[res->getID()] = res;
1149 }
1150 for (auto item : myStateLoadedReservations) {
1151 auto it = resLookup.find(item.first);
1152 if (it == resLookup.end()) {
1153 WRITE_ERRORF("Could not find taxi reservation '%'.", item.first);
1154 } else {
1155 item.second->myCurrentReservations.insert(it->second);
1156 }
1157 }
1158 }
1159 myStateLoadedCustomers.clear();
1161}
1162
1163
1164bool
1165MSDevice_Taxi::compatibleLine(const std::string& taxiLine, const std::string& rideLine) {
1166 return ((taxiLine == rideLine && StringUtils::startsWith(rideLine, "taxi") && StringUtils::startsWith(taxiLine, "taxi"))
1167 || (taxiLine == TAXI_SERVICE && StringUtils::startsWith(rideLine, "taxi:"))
1168 || (rideLine == TAXI_SERVICE && StringUtils::startsWith(taxiLine, "taxi:")));
1169}
1170
1171bool
1175
1176
1177/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define TAXI_SERVICE
#define SWAP_THRESHOLD
#define TAXI_SERVICE_PREFIX
std::vector< const MSEdge * > ConstMSEdgeVector
Definition MSEdge.h:74
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define WRITE_ERRORF(...)
Definition MsgHandler.h:296
#define TL(string)
Definition MsgHandler.h:304
#define TLF(string,...)
Definition MsgHandler.h:306
SUMOTime DELTA_T
Definition SUMOTime.cpp:38
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition SUMOTime.cpp:46
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:91
#define STEPS2TIME(x)
Definition SUMOTime.h:58
#define SIMSTEP
Definition SUMOTime.h:64
#define SIMTIME
Definition SUMOTime.h:65
#define TIME2STEPS(x)
Definition SUMOTime.h:60
SVCPermissions parseVehicleClasses(const std::string &allowedS)
Parses the given definition of allowed vehicle classes into the given containers Deprecated classes g...
const std::string DEFAULT_TAXITYPE_ID
const std::string DEFAULT_RAILTYPE_ID
const std::string DEFAULT_VTYPE_ID
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_RAIL
vehicle is a not electrified rail
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
@ SVC_BICYCLE
vehicle is a bicycle
@ SVC_TAXI
vehicle is a taxi
const std::string DEFAULT_BIKETYPE_ID
const int STOP_DURATION_SET
const int STOP_INDEX_END
const int STOP_PARKING_SET
std::vector< SUMOVehicleParameter::Stop > StopParVector
const int STOP_PERMITTED_SET
const int STOP_START_SET
const int STOP_TRIGGER_SET
const int STOP_END_SET
@ GIVEN
The time is given.
SumoXMLTag
Numbers representing SUMO-XML - element names.
@ SUMO_TAG_DEVICE
@ SUMO_TAG_CONTAINER_STOP
A container stop.
@ SUMO_TAG_BUS_STOP
A bus stop.
@ SUMO_TAG_PARKING_AREA
A parking area.
@ SUMO_TAG_TRAIN_STOP
A train stop (alias for bus stop)
@ SUMO_ATTR_CUSTOMERS
@ SUMO_ATTR_ID
@ SUMO_ATTR_RESERVATIONS
@ SUMO_ATTR_STATE
The state of a link.
int gTaxiClasses
Definition StdDefs.cpp:38
T MIN2(T a, T b)
Definition StdDefs.h:80
T MAX2(T a, T b)
Definition StdDefs.h:86
std::string joinToStringSorting(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition ToString.h:329
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:49
std::string joinNamedToStringSorting(const std::set< T * > &ns, const T_BETWEEN &between)
Definition ToString.h:337
Base (microsim) event class.
Definition Command.h:50
The base class for microscopic and mesoscopic vehicles.
const std::list< MSStop > & getStops() const
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)
void prepareStop(ConstMSEdgeVector &edges, StopParVector &stops, double &lastPos, const MSEdge *stopEdge, double stopPos, const MSStoppingPlace *stopPlace, const std::string &action, const Reservation *res, const bool isPickup)
prepare stop for the given action
void addCustomer(const MSTransportable *t, const Reservation *res)
add person after extending reservation
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)
static void updateReservationFromPos(MSTransportable *person, const std::set< std::string > &lines, const MSEdge *from, double fromPos, const MSEdge *to, double toPos, const std::string &group, double newFromPos)
update reservation's fromPos due to pre-booking
bool cancelCustomer(const MSTransportable *t)
remove person from reservations
void generateOutput(OutputDevice *tripinfoOut) const
Called on writing tripinfo output.
static int myMaxCapacity
void dispatchShared(std::vector< const Reservation * > reservations)
service the given reservations
static void addReservation(MSTransportable *person, const std::set< std::string > &lines, SUMOTime reservationTime, SUMOTime pickupTime, SUMOTime earliestPickupTime, const MSEdge *from, double fromPos, const MSStoppingPlace *fromStop, const MSEdge *to, double toPos, const MSStoppingPlace *toStop, const std::string &group)
add new reservation
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
void cancelCurrentCustomers()
remove the persons the taxi is currently waiting for from reservations
std::vector< const Reservation * > myLastDispatch
the last dispatch order
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
static std::map< std::string, MSDevice_Taxi * > myStateLoadedCustomers
ids of customers loaded from state
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
static SUMOTime myNextDispatchTime
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 bool hasFleet()
returns whether taxis have been loaded
static void allCustomersErased()
signal the end of the simulation and the removal of all customers
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
static const std::map< SUMOVehicleClass, std::string > & getTaxiTypes()
return all types that are known to carry a taxi device (or the default type if no devices are initial...
static SUMOTime getNextDispatchTime()
void saveState(OutputDevice &out) const
Saves the state of the device.
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 finalizeLoadState()
call during state loading after all transportables are loaded
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
void loadState(const SUMOSAXAttributes &attrs)
Loads the state of the device from the given description.
SUMOTime myOccupiedTime
time spent driving with customers
bool myReachedServiceEnd
whether the taxi has reached its schedule service end
~MSDevice_Taxi()
Destructor.
static std::map< std::string, MSDevice_Taxi * > myStateLoadedReservations
ids of reservations loaded from state
static std::map< SUMOVehicleClass, std::string > myTaxiTypes
storing only one type per vClass
MSLane * getStopLane(const MSEdge *edge, const std::string &action)
determine stopping lane for taxi
void checkTaskSwap()
optionally swap tasks when a taxi becomes idle
static void initDispatch(SUMOTime next=-1)
initialize the dispatch algorithm
std::string getParameter(const std::string &key) const
try to retrieve the given parameter from this device. Throw exception for unsupported key
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:157
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:200
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:114
void swappedRunning(const Reservation *res, MSDevice_Taxi *taxi)
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 its id
virtual Reservation * updateReservationFromPos(MSTransportable *person, const MSEdge *from, double fromPos, const MSEdge *to, double toPos, std::string group, double newFromPos)
update fromPos of the person's reservation. TODO: if there is already a reservation with the newFromP...
std::vector< Reservation * > getReservations()
retrieve all reservations
virtual std::vector< const Reservation * > getRunningReservations()
retrieve all reservations that were already dispatched and are still active
virtual SUMOAbstractRouter< MSEdge, SUMOVehicle > & getRouter() const
virtual Reservation * addReservation(MSTransportable *person, SUMOTime reservationTime, SUMOTime pickupTime, SUMOTime earliestPickupTime, const MSEdge *from, double fromPos, const MSStoppingPlace *fromStop, const MSEdge *to, double toPos, const MSStoppingPlace *tostop, std::string group, const std::string &line, int maxCapacity, int maxContainerCapacity)
add a new reservation
bool hasServableReservations()
check whether there are still (servable) reservations in the system
Definition MSDispatch.h:176
virtual void fulfilledReservation(const Reservation *res)
erase reservation from storage
virtual void computeDispatch(SUMOTime now, const std::vector< MSDevice_Taxi * > &fleet)=0
computes dispatch and updates reservations
void servedReservation(const Reservation *res, MSDevice_Taxi *taxi)
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:658
const std::vector< MSLane * > * allowedLanes(const MSEdge &destination, SUMOVehicleClass vclass=SVC_IGNORING, bool ignoreTransientPermissions=false) const
Get the allowed lanes to reach the destination-edge.
Definition MSEdge.cpp:480
double getLength() const
return the length of the edge
Definition MSEdge.h:694
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
static bool gUseMesoSim
Definition MSGlobals.h:106
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:617
bool isInternal() const
Definition MSLane.cpp:2641
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:775
Notification
Definition of a vehicle state.
The simulated network and simulation perfomer.
Definition MSNet.h:89
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:199
MSEventControl * getEndOfTimestepEvents()
Returns the event control for events executed at the end of a time step.
Definition MSNet.h:495
virtual MSTransportableControl & getContainerControl()
Returns the container control.
Definition MSNet.cpp:1283
void resetIntermodalRouter() const
force reconstruction of intermodal network
Definition MSNet.cpp:1685
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:334
bool hasContainers() const
Returns whether containers are simulated.
Definition MSNet.h:425
bool hasPersons() const
Returns whether persons are simulated.
Definition MSNet.h:409
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition MSNet.h:392
virtual MSTransportableControl & getPersonControl()
Returns the person control.
Definition MSNet.cpp:1274
const ConstMSEdgeVector & getEdges() const
Definition MSRoute.h:128
static MSVehicleRouter & getRouterTT(const int rngIndex, SUMOVehicleClass svc, const Prohibitions &prohibited={})
return the vehicle router instance
bool triggered
whether an arriving person lets the vehicle continue
Definition MSStop.h:69
bool containerTriggered
whether an arriving container lets the vehicle continue
Definition MSStop.h:71
bool joinTriggered
whether coupling another vehicle (train) the vehicle continue
Definition MSStop.h:73
MSRouteIterator edge
The edge in the route to stop at.
Definition MSStop.h:48
SUMOTime endBoarding
the maximum time at which persons may board this vehicle
Definition MSStop.h:85
SUMOTime duration
The stopping duration.
Definition MSStop.h:67
const SUMOVehicleParameter::Stop pars
The stop parameter.
Definition MSStop.h:65
A lane area vehicles can halt at.
double getBeginLanePosition() const
Returns the begin position of this stop.
SumoXMLTag getElement() const
return the type of this stopping place
double getEndLanePosition() const
Returns the end position of this stop.
const MSLane & getLane() const
Returns the lane this stop is located at.
MSTransportable * get(const std::string &id) const
Returns the named transportable, if existing.
bool isPerson() const override
Whether it is a person.
Reroutes traffic objects passing an edge.
static const std::map< std::string, MSTriggeredRerouter * > & getInstances()
return all rerouter instances
The class responsible for building and deletion of vehicles.
bool hasVType(const std::string &id) const
Asks for existence of a vehicle type.
bool addVType(MSVehicleType *vehType)
Adds a vehicle type.
Abstract in-vehicle device.
SUMOVehicle & myHolder
The vehicle that stores the device.
SUMOVehicle & getHolder() const
Returns the vehicle that holds this device.
The car-following model and parameter.
int getPersonCapacity() const
Get this vehicle type's person capacity.
const std::string & getID() const
Returns the name of the vehicle type.
static MSVehicleType * build(SUMOVTypeParameter &from, const std::string &fileName="")
Builds the microsim vehicle type described by the given parameter.
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.
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
void addSynonyme(const std::string &name1, const std::string &name2, bool isDeprecated=false)
Adds a synonyme for an options name (any order)
void doRegister(const std::string &name, Option *o)
Adds an option under the given name.
void addOptionSubTopic(const std::string &topic)
Adds an option subtopic.
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
static OptionsCont & getOptions()
Retrieves the options.
Static storage of an output device and its base (abstract) implementation.
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const ATTR_TYPE &attr, const T &val, const bool isNull=false)
writes a named attribute
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.
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...
double recomputeCostsPos(const std::vector< const E * > &edges, const V *const v, double fromPos, double toPos, SUMOTime msTime, double *lengthp=nullptr) const
Encapsulated SAX-Attributes.
virtual std::string getString(int id, bool *isPresent=nullptr) const =0
Returns the string-value of the named (by its enum-value) attribute.
T get(int attr, const char *objectid, bool &ok, bool report=true) const
Tries to read given attribute assuming it is an int.
virtual bool hasAttribute(int id) const =0
Returns the information whether the named (by its enum-value) attribute is within the current list.
Representation of a vehicle, person, or container.
virtual const MSVehicleType & getVehicleType() const =0
Returns the object's "vehicle" type.
std::string getStringParam(const std::string &paramName, const bool required=false, const std::string &deflt="") const
Retrieve a string parameter for the traffic object.
virtual const MSLane * getLane() const =0
Returns the lane the object is currently at.
virtual int getRNGIndex() const =0
virtual MSDevice * getDevice(const std::type_info &type) const =0
Returns a device of the given type if it exists or nullptr if not.
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
double getFloatParam(const std::string &paramName, const bool required=false, const double deflt=INVALID_DOUBLE, bool checkDist=true) const
Retrieve a floating point parameter for the traffic object.
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.
Structure representing possible vehicle parameter.
Representation of a vehicle.
Definition SUMOVehicle.h:63
virtual ConstMSEdgeVector::const_iterator getRerouteOrigin() const =0
Returns the starting point for reroutes (usually the current edge)
virtual bool reroute(SUMOTime t, const std::string &info, SUMOAbstractRouter< MSEdge, SUMOVehicle > &router, const bool onInit=false, const bool withTaz=false, const bool silent=false, const MSEdge *sink=nullptr)=0
Performs a rerouting using the given router.
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 bool isStopped() const =0
Returns whether the vehicle is at a stop and waiting for a person or container to continue.
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 getPersonNumber() const =0
Returns the number of persons.
virtual void unregisterWaiting()=0
mark vehicle as active
virtual bool isStoppedTriggered() const =0
Returns whether the vehicle is at a stop and waiting for a person or container to continue.
virtual const std::vector< MSTransportable * > & getPersons() const =0
retrieve riding persons
virtual int getContainerNumber() const =0
Returns the number of containers.
virtual const MSStop & getNextStop() const =0
virtual MSStop & getNextStopMutable()=0
virtual double getBrakeGap(bool delayed=false) const =0
get distance for coming to a stop (used for rerouting checks)
virtual bool isStoppedParking() const =0
Returns whether the vehicle is at a stop and parking.
virtual const ConstMSEdgeVector::const_iterator & getCurrentRouteEdge() const =0
Returns an iterator pointing to the current edge in this vehicles route.
virtual const SUMOVehicleParameter::Stop * getNextStopParameter() const =0
Returns parameters of the next stop or nullptr.
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.
SUMOTime extension
The maximum time extension for boarding / loading.
std::string parkingarea
(Optional) parking area if one is assigned to the stop
double startPos
The stopping position start.
std::set< std::string > permitted
IDs of persons or containers that may board/load at this stop.
int parametersSet
Information for the output which parameter were set.
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.
SUMOTime waitUntil
The earliest pickup time for a taxi stop.
std::set< std::string > awaitedPersons
IDs of persons the vehicle has to wait for until departing.
std::string busstop
(Optional) bus stop if one is assigned to the stop
std::string containerstop
(Optional) container stop if one is assigned to the stop
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.
static std::string to_upper_case(const std::string &str)
Transfers the content to upper case.
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.
#define UNUSED_PARAMETER(x)
#define DEBUG_COND
const MSEdge * to
Definition MSDispatch.h:84
double fromPos
Definition MSDispatch.h:82
std::string line
Definition MSDispatch.h:88
const MSEdge * from
Definition MSDispatch.h:81
SUMOTime earliestPickupTime
Definition MSDispatch.h:80
double toPos
Definition MSDispatch.h:85