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-2023 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
31#include <microsim/MSGlobals.h>
32#include <microsim/MSVehicle.h>
33#include <microsim/MSEdge.h>
34#include <microsim/MSLane.h>
35#include <microsim/MSStop.h>
38
39#include "MSDispatch.h"
40#include "MSDispatch_Greedy.h"
43#include "MSDispatch_TraCI.h"
44
45#include "MSIdling.h"
46
47#include "MSRoutingEngine.h"
48#include "MSDevice_Routing.h"
49#include "MSDevice_Taxi.h"
50
51//#define DEBUG_DISPATCH
52
53//#define DEBUG_COND (myHolder.isSelected())
54#define DEBUG_COND (true)
55
56// ===========================================================================
57// static member variables
58// ===========================================================================
64// @brief the list of available taxis
65std::vector<MSDevice_Taxi*> MSDevice_Taxi::myFleet;
68
69#define TAXI_SERVICE "taxi"
70#define TAXI_SERVICE_PREFIX "taxi:"
71
72// ===========================================================================
73// method definitions
74// ===========================================================================
75// ---------------------------------------------------------------------------
76// static initialisation methods
77// ---------------------------------------------------------------------------
78void
80 oc.addOptionSubTopic("Taxi Device");
81 insertDefaultAssignmentOptions("taxi", "Taxi Device", oc);
82
83 oc.doRegister("device.taxi.dispatch-algorithm", new Option_String("greedy"));
84 oc.addDescription("device.taxi.dispatch-algorithm", "Taxi Device", TL("The dispatch algorithm [greedy|greedyClosest|greedyShared|routeExtension|traci]"));
85
86 oc.doRegister("device.taxi.dispatch-algorithm.output", new Option_FileName());
87 oc.addDescription("device.taxi.dispatch-algorithm.output", "Taxi Device", TL("Write information from the dispatch algorithm to FILE"));
88
89 oc.doRegister("device.taxi.dispatch-algorithm.params", new Option_String(""));
90 oc.addDescription("device.taxi.dispatch-algorithm.params", "Taxi Device", TL("Load dispatch algorithm parameters in format KEY1:VALUE1[,KEY2:VALUE]"));
91
92 oc.doRegister("device.taxi.dispatch-period", new Option_String("60", "TIME"));
93 oc.addDescription("device.taxi.dispatch-period", "Taxi Device", TL("The period between successive calls to the dispatcher"));
94
95 oc.doRegister("device.taxi.idle-algorithm", new Option_String("stop"));
96 oc.addDescription("device.taxi.idle-algorithm", "Taxi Device", TL("The behavior of idle taxis [stop|randomCircling]"));
97
98 oc.doRegister("device.taxi.idle-algorithm.output", new Option_FileName());
99 oc.addDescription("device.taxi.idle-algorithm.output", "Taxi Device", TL("Write information from the idling algorithm to FILE"));
100}
101
102
103void
104MSDevice_Taxi::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
106 if (equippedByDefaultAssignmentOptions(oc, "taxi", v, false)) {
107 // build the device
108 MSDevice_Taxi* device = new MSDevice_Taxi(v, "taxi_" + v.getID());
109 into.push_back(device);
110 myFleet.push_back(device);
111 if (v.getParameter().line == "") {
112 // automatically set the line so that persons are willing to enter
113 // (see MSStageDriving::isWaitingFor)
114 const_cast<SUMOVehicleParameter&>(v.getParameter()).line = TAXI_SERVICE;
115 }
116 if (v.getVClass() != SVC_TAXI) {
117 WRITE_WARNINGF(TL("Vehicle '%' with device.taxi should have vClass taxi instead of '%'."), v.getID(), toString(v.getVClass()));
118 }
119 const int personCapacity = v.getVehicleType().getPersonCapacity();
120 const int containerCapacity = v.getVehicleType().getContainerCapacity();
121 myMaxCapacity = MAX2(myMaxCapacity, personCapacity);
123 if (personCapacity < 1 && containerCapacity < 1) {
124 WRITE_WARNINGF(TL("Vehicle '%' with personCapacity % and containerCapacity % is not usable as taxi."), v.getID(), toString(personCapacity), toString(containerCapacity));
125 }
126 }
127}
128
129
130void
133 myDispatchPeriod = string2time(oc.getString("device.taxi.dispatch-period"));
134 // init dispatch algorithm
135 std::string algo = oc.getString("device.taxi.dispatch-algorithm");
136 Parameterised params;
137 params.setParametersStr(OptionsCont::getOptions().getString("device.taxi.dispatch-algorithm.params"), ":", ",");
138 if (algo == "greedy") {
140 } else if (algo == "greedyClosest") {
142 } else if (algo == "greedyShared") {
144 } else if (algo == "routeExtension") {
146 } else if (algo == "traci") {
148 } else {
149 throw ProcessError(TLF("Dispatch algorithm '%' is not known", algo));
150 }
152 // round to next multiple of myDispatchPeriod
154 const SUMOTime begin = string2time(oc.getString("begin"));
155 const SUMOTime delay = (myDispatchPeriod - ((now - begin) % myDispatchPeriod)) % myDispatchPeriod;
157}
158
159bool
160MSDevice_Taxi::isReservation(const std::set<std::string>& lines) {
161 return lines.size() == 1 && (
162 *lines.begin() == TAXI_SERVICE
163 || StringUtils::startsWith(*lines.begin(), TAXI_SERVICE_PREFIX));
164}
165
166void
168 const std::set<std::string>& lines,
169 SUMOTime reservationTime,
170 SUMOTime pickupTime,
171 const MSEdge* from, double fromPos,
172 const MSEdge* to, double toPos,
173 const std::string& group) {
174 if (!isReservation(lines)) {
175 return;
176 }
177 if ((to->getPermissions() & SVC_TAXI) == 0) {
178 throw ProcessError("Cannot add taxi reservation for " + std::string(person->isPerson() ? "person" : "container")
179 + " '" + person->getID() + "' because destination edge '" + to->getID() + "'"
180 + " does not permit taxi access");
181 }
182 if ((from->getPermissions() & SVC_TAXI) == 0) {
183 throw ProcessError("Cannot add taxi reservation for " + std::string(person->isPerson() ? "person" : "container")
184 + " '" + person->getID() + "' because origin edge '" + from->getID() + "'"
185 + " does not permit taxi access");
186 }
187 if (myDispatchCommand == nullptr) {
188 initDispatch();
189 }
190 myDispatcher->addReservation(person, reservationTime, pickupTime, from, fromPos, to, toPos, group, *lines.begin(), myMaxCapacity, myMaxContainerCapacity);
191}
192
193void
195 const std::set<std::string>& lines,
196 const MSEdge* from, double fromPos,
197 const MSEdge* to, double toPos,
198 const std::string& group) {
199 if (myDispatcher != nullptr && lines.size() == 1 && *lines.begin() == TAXI_SERVICE) {
200 myDispatcher->removeReservation(person, from, fromPos, to, toPos, group);
201 }
202}
203
204
207 std::vector<MSDevice_Taxi*> active;
208 for (MSDevice_Taxi* taxi : myFleet) {
209 if (taxi->getHolder().hasDeparted()) {
210 active.push_back(taxi);
211 }
212 }
213 myDispatcher->computeDispatch(currentTime, active);
214 return myDispatchPeriod;
215}
216
217bool
221
222void
224 if (myDispatcher != nullptr) {
225 delete myDispatcher;
226 myDispatcher = nullptr;
227 }
228 myDispatchCommand = nullptr;
229}
230
231// ---------------------------------------------------------------------------
232// MSDevice_Taxi-methods
233// ---------------------------------------------------------------------------
234MSDevice_Taxi::MSDevice_Taxi(SUMOVehicle& holder, const std::string& id) :
235 MSVehicleDevice(holder, id) {
236 std::string defaultServiceEnd = toString(1e15);
237 const std::string algo = getStringParam(holder, OptionsCont::getOptions(), "taxi.idle-algorithm", "", false);
238 if (algo == "stop") {
240 } else if (algo == "randomCircling") {
242 // make sure simulation terminates
243 defaultServiceEnd = toString(STEPS2TIME(
246 : MSNet::getInstance()->getCurrentTimeStep()) + (3600 * 8));
247 } else if (algo == "taxistand") {
248 const std::string rerouterID = getStringParam(holder, OptionsCont::getOptions(), "taxi.stands-rerouter", "", false);
249 if (rerouterID.empty()) {
250 throw ProcessError("Idle algorithm '" + algo + "' requires a rerouter id to be defined using device param 'stands-rerouter' for vehicle '" + myHolder.getID() + "'");
251 }
252 if (MSTriggeredRerouter::getInstances().count(rerouterID) == 0) {
253 throw ProcessError("Unknown rerouter '" + rerouterID + "' when loading taxi stands for vehicle '" + myHolder.getID() + "'");
254 }
255 MSTriggeredRerouter* rerouter = MSTriggeredRerouter::getInstances().find(rerouterID)->second;
256 myIdleAlgorithm = new MSIdling_TaxiStand(rerouter);
257 } else {
258 throw ProcessError("Idle algorithm '" + algo + "' is not known for vehicle '" + myHolder.getID() + "'");
259 }
260 myServiceEnd = string2time(getStringParam(holder, OptionsCont::getOptions(), "taxi.end", defaultServiceEnd, false));
262}
263
264
266 myFleet.erase(std::find(myFleet.begin(), myFleet.end(), this));
267 // recompute myMaxCapacity
268 myMaxCapacity = 0;
270 for (MSDevice_Taxi* taxi : myFleet) {
271 myMaxCapacity = MAX2(myMaxCapacity, taxi->getHolder().getVehicleType().getPersonCapacity());
272 myMaxContainerCapacity = MAX2(myMaxContainerCapacity, taxi->getHolder().getVehicleType().getContainerCapacity());
273 }
274 delete myIdleAlgorithm;
275}
276
277
280 if (myFleet.size() > 0) {
281 return &myFleet[0]->getHolder();
282 } else {
283 return nullptr;
284 }
285}
286
287
288void
290 dispatchShared({&res, &res});
291}
292
293
294void
295MSDevice_Taxi::dispatchShared(std::vector<const Reservation*> reservations) {
296#ifdef DEBUG_DISPATCH
297 if (DEBUG_COND) {
298 std::cout << SIMTIME << " taxi=" << myHolder.getID() << " dispatch:\n";
299 for (const Reservation* res : reservations) {
300 std::cout << " persons=" << toString(res->persons) << "\n";
301 }
302 }
303#endif
304 ConstMSEdgeVector tmpEdges;
305 std::vector<SUMOVehicleParameter::Stop> stops;
306 double lastPos = myHolder.getPositionOnLane();
307 const MSEdge* rerouteOrigin = *myHolder.getRerouteOrigin();
308 if (isEmpty()) {
309 // start fresh from the current edge
310 while (myHolder.hasStops()) {
311 // in meso there might be more than 1 stop at this point
313 }
314 assert(!myHolder.hasStops());
315 tmpEdges.push_back(myHolder.getEdge());
316 if (myHolder.getEdge() != rerouteOrigin) {
317 tmpEdges.push_back(rerouteOrigin);
318 }
319 } else {
320 assert(myHolder.hasStops());
321 // check how often existing customers appear in the new reservations
322 std::map<const MSTransportable*, int> nOccur;
323 for (const Reservation* res : reservations) {
324 for (MSTransportable* person : res->persons) {
325 if (myCustomers.count(person) != 0) {
326 nOccur[person] += 1;
327 if (myCurrentReservations.count(res) == 0) {
328 throw ProcessError(TLF("Invalid Re-dispatch for existing customer '%' with a new reservation", person->getID()));
329 }
330 }
331 }
332 }
333#ifdef DEBUG_DISPATCH
334 if (DEBUG_COND) {
335 for (auto item : nOccur) {
336 std::cout << " previousCustomer=" << item.first->getID() << " occurs=" << item.second << "\n";
337 }
338 }
339#endif
340 if (nOccur.size() == 0) {
341 // no overlap with existing customers - extend route
342 tmpEdges = myHolder.getRoute().getEdges();
343 lastPos = myHolder.getStops().back().pars.endPos;
344#ifdef DEBUG_DISPATCH
345 if (DEBUG_COND) {
346 std::cout << " re-dispatch with route-extension\n";
347 }
348#endif
349 } else if (nOccur.size() == myCustomers.size()) {
350 // redefine route (verify correct number of mentions)
351 std::set<const MSTransportable*> onBoard;
352 const std::vector<MSTransportable*>& onBoardP = myHolder.getPersons();
353 const std::vector<MSTransportable*>& onBoardC = myHolder.getContainers();
354 onBoard.insert(onBoardP.begin(), onBoardP.end());
355 onBoard.insert(onBoardC.begin(), onBoardC.end());
356 std::set<const MSTransportable*> redundantPickup;
357 for (auto item : nOccur) {
358 if (item.second == 1) {
359 // customers must already be on board
360 if (onBoard.count(item.first) == 0) {
361 throw ProcessError(TLF("Re-dispatch did not mention pickup for existing customer '%'", item.first->getID()));
362 }
363 } else if (item.second == 2) {
364 if (onBoard.count(item.first) == 0) {
365 // treat like a new customer
366 myCustomers.erase(item.first);
367 } else {
368 redundantPickup.insert(item.first);
369 }
370 } else {
371 throw ProcessError("Re-dispatch mentions existing customer '" + item.first->getID() + "' " + toString(item.second) + " times");
372 }
373 }
374 // remove redundancy
375 if (!redundantPickup.empty()) {
376 for (auto it = reservations.begin(); it != reservations.end();) {
377 bool isRedundant = false;
378 for (const MSTransportable* person : (*it)->persons) {
379 if (redundantPickup.count(person) != 0) {
380 isRedundant = true;
381 break;
382 }
383 }
384 if (isRedundant) {
385 for (const MSTransportable* person : (*it)->persons) {
386 redundantPickup.erase(person);
387 }
388 it = reservations.erase(it);
389 } else {
390 it++;
391 }
392 }
393 }
394 while (myHolder.hasStops()) {
396 }
397 tmpEdges.push_back(myHolder.getEdge());
398 if (myHolder.getEdge() != rerouteOrigin) {
399 tmpEdges.push_back(rerouteOrigin);
400 }
401#ifdef DEBUG_DISPATCH
402 if (DEBUG_COND) {
403 std::cout << " re-dispatch from scratch\n";
404 }
405#endif
406 } else {
407 // inconsistent re-dispatch
408 std::vector<std::string> missing;
409 for (const MSTransportable* c : myCustomers) {
410 if (nOccur.count(c) == 0) {
411 missing.push_back(c->getID());
412 }
413 }
414 throw ProcessError("Re-dispatch did mention some customers but failed to mention " + joinToStringSorting(missing, " "));
415 }
416 }
417
419 bool hasPickup = false;
420 for (const Reservation* res : reservations) {
421 myCurrentReservations.insert(res);
422 bool isPickup = false;
423 for (MSTransportable* person : res->persons) {
424 if (myCustomers.count(person) == 0) {
425 myCustomers.insert(person);
426 isPickup = true;
427 hasPickup = true;
428 }
429 }
430 if (isPickup) {
431 prepareStop(tmpEdges, stops, lastPos, res->from, res->fromPos, "pickup " + toString(res->persons) + " (" + res->id + ")");
432 for (const MSTransportable* const transportable : res->persons) {
433 if (transportable->isPerson()) {
434 stops.back().triggered = true;
435 } else {
436 stops.back().containerTriggered = true;
437 }
438 stops.back().permitted.insert(transportable->getID());
439 }
440 //stops.back().awaitedPersons.insert(res.person->getID());
441 stops.back().parametersSet |= STOP_PERMITTED_SET;
442 if (stops.back().duration == -1) {
443 // keep dropOffDuration if the stop is dropOff and pickUp
444 stops.back().duration = TIME2STEPS(getFloatParam(myHolder, OptionsCont::getOptions(), "taxi.pickUpDuration", 0, false));
445 }
446 } else {
447 prepareStop(tmpEdges, stops, lastPos, res->to, res->toPos, "dropOff " + toString(res->persons) + " (" + res->id + ")");
448 stops.back().duration = TIME2STEPS(getFloatParam(myHolder, OptionsCont::getOptions(), "taxi.dropOffDuration", 60, false)); // pay and collect bags
449 }
450 }
451#ifdef DEBUG_DISPATCH
452 if (DEBUG_COND) {
453 std::cout << " tmpEdges=" << toString(tmpEdges) << "\n";
454 }
455#endif
456 if (!myHolder.replaceRouteEdges(tmpEdges, -1, 0, "taxi:prepare_dispatch", false, false, false)) {
457 throw ProcessError("Route replacement for taxi dispatch failed for vehicle '" + myHolder.getID()
458 + "' at time=" + time2string(t) + ".");
459 }
460#ifdef DEBUG_DISPATCH
461 if (DEBUG_COND) std::cout << " replacedRoute=" << toString(tmpEdges)
462 << "\n actualRoute=" << toString(myHolder.getRoute().getEdges()) << "\n";
463#endif
464 for (SUMOVehicleParameter::Stop& stop : stops) {
465 std::string error;
466 myHolder.addStop(stop, error);
467 if (error != "") {
468 WRITE_WARNINGF(TL("Could not add taxi stop for vehicle '%' to %. time=% error=%."), myHolder.getID(), stop.actType, time2string(t), error)
469 }
470 }
472 // SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = myHolder.getInfluencer().getRouterTT(veh->getRNGIndex())
473 myHolder.reroute(t, "taxi:dispatch", router, false);
474#ifdef DEBUG_DISPATCH
475 if (DEBUG_COND) {
476 std::cout << "\n finalRoute=" << toString(myHolder.getRoute().getEdges()) << " routeIndex=" << myHolder.getRoutePosition() << "\n";
477 }
478#endif
479 if (hasPickup) {
480 myState |= PICKUP;
481 }
482}
483
484
485void
487 std::vector<SUMOVehicleParameter::Stop>& stops,
488 double& lastPos, const MSEdge* stopEdge, double stopPos,
489 const std::string& action) {
490 assert(!edges.empty());
491 if (stopPos < lastPos && stopPos + NUMERICAL_EPS >= lastPos) {
492 stopPos = lastPos;
493 }
494
495 if (stops.empty()) {
496 // check brakeGap
497 double distToStop = stopPos - lastPos;
498 const double brakeGap = myHolder.getBrakeGap();
499 if (myHolder.getLane() != nullptr && myHolder.getLane()->isInternal()) {
500 distToStop += myHolder.getLane()->getLength();
501 }
502 if (stopEdge != edges.back()) {
503 distToStop += edges.back()->getLength();
504 if (distToStop < brakeGap) {
505 // the distance between current edge and stop edge may be small
507 ConstMSEdgeVector toFirstStop;
508 router.compute(edges.back(), stopEdge, &myHolder, SIMSTEP, toFirstStop, true);
509 for (int i = 1; i < (int)toFirstStop.size() - 1; i++) {
510 distToStop += toFirstStop[i]->getLength();
511 }
512 }
513 }
514 if (distToStop < brakeGap) {
515 // circle back to stopEdge
516 //std::cout << SIMTIME << " taxi=" << getID() << " brakeGap=" << brakeGap << " distToStop=" << distToStop << "\n";
517 edges.push_back(stopEdge);
518 }
519 }
520
521 if (stopEdge == edges.back() && !stops.empty()) {
522 if (stopPos >= lastPos && stopPos <= stops.back().endPos) {
523 // no new stop and no adaption needed
524 stops.back().actType += "," + action;
525 return;
526 }
527 if (stopPos >= lastPos && stopPos <= lastPos + myHolder.getVehicleType().getLength()) {
528 // stop length adaption needed
529 stops.back().endPos = MIN2(lastPos + myHolder.getVehicleType().getLength(), stopEdge->getLength());
530 stops.back().actType += "," + action;
531 return;
532 }
533 }
534 if (stopEdge != edges.back() || stopPos < lastPos) {
535 edges.push_back(stopEdge);
536 }
537 lastPos = stopPos;
539 stop.lane = getStopLane(stopEdge, action)->getID();
540 stop.startPos = stopPos;
541 stop.endPos = MAX2(stopPos, MIN2(myHolder.getVehicleType().getLength(), stopEdge->getLength()));
543 stop.actType = action;
544 stop.index = STOP_INDEX_END;
545 stops.push_back(stop);
546}
547
548
549MSLane*
550MSDevice_Taxi::getStopLane(const MSEdge* edge, const std::string& action) {
551 const std::vector<MSLane*>* allowedLanes = edge->allowedLanes(myHolder.getVClass());
552 if (allowedLanes == nullptr) {
553 throw ProcessError("Taxi vehicle '" + myHolder.getID() + "' cannot stop on edge '" + edge->getID() + "' (" + action + ")");
554 }
555 return allowedLanes->front();
556}
557
558bool
560 return myState == EMPTY;
561}
562
563
564bool
566 return myCustomers.count(t) != 0;
567}
568
569
570void
571MSDevice_Taxi::updateMove(const SUMOTime traveltime, const double travelledDist) {
573 myOccupiedDistance += travelledDist;
574 myOccupiedTime += traveltime;
575 }
576 if (isEmpty()) {
577 if (MSNet::getInstance()->getCurrentTimeStep() < myServiceEnd) {
578 myIdleAlgorithm->idle(this);
579 if (myRoutingDevice != nullptr) {
580 // prevent rerouting during idling (#11079)
582 }
583 } else if (!myReachedServiceEnd) {
584 WRITE_WARNINGF(TL("Taxi '%' reaches scheduled end of service at time=%."), myHolder.getID(), time2string(SIMSTEP));
585 myReachedServiceEnd = true;
586 }
587 } else if (myRoutingDevice != nullptr) {
589 }
590 if (myHolder.isStopped()) {
591 if (!myIsStopped) {
592 // limit duration of stop
593 // @note: stops are not yet added to the vehicle so we can change the loaded parameters. Stops added from a route are not affected
595 }
596 }
597#ifdef DEBUG_DISPATCH
599 std::cout << SIMTIME << " updateMove veh=" << myHolder.getID() << " myIsStopped=" << myIsStopped << " myHolderStopped=" << myHolder.isStopped() << " myState=" << myState << "\n";
600 }
601#endif
603}
604
605
606bool
608 double newPos, double /*newSpeed*/) {
609 updateMove(DELTA_T, newPos - oldPos);
610 return true; // keep the device
611}
612
613
614void
616 const double /* frontOnLane */,
617 const double timeOnLane,
618 const double /* meanSpeedFrontOnLane */,
619 const double /* meanSpeedVehicleOnLane */,
620 const double travelledDistanceFrontOnLane,
621 const double /* travelledDistanceVehicleOnLane */,
622 const double /* meanLengthOnLane */) {
623 updateMove(TIME2STEPS(timeOnLane), travelledDistanceFrontOnLane);
624}
625
626
627bool
629 if (isEmpty() && MSNet::getInstance()->getCurrentTimeStep() < myServiceEnd) {
630 myIdleAlgorithm->idle(this);
631 }
632 return true; // keep the device
633}
634
635
636void
638 myState |= OCCUPIED;
639 if (!hasFuturePickup()) {
640 myState &= ~PICKUP;
641 }
642 for (const Reservation* res : myCurrentReservations) {
643 for (const MSTransportable* cand : res->persons) {
644 if (cand == t) {
645 const_cast<Reservation*>(res)->state = Reservation::ONBOARD;
646 break;
647 }
648 }
649 }
650}
651
652
653void
656 myCustomers.erase(person);
658 myState &= ~OCCUPIED;
659 if (myHolder.getStops().size() > 1 && (myState & PICKUP) == 0) {
660 WRITE_WARNINGF(TL("All customers left vehicle '%' at time=% but there are % remaining stops"),
662 while (myHolder.getStops().size() > 1) {
664 }
665 }
666 }
667 if (isEmpty()) {
668 // cleanup
669 for (const Reservation* res : myCurrentReservations) {
671 }
672 myCurrentReservations.clear();
674 myIdleAlgorithm->idle(this);
675 }
676 } else {
677 // check whether a single reservation has been fulfilled
678 for (auto resIt = myCurrentReservations.begin(); resIt != myCurrentReservations.end();) {
679 bool fulfilled = true;
680 for (MSTransportable* t : (*resIt)->persons) {
681 if (myCustomers.count(t) != 0) {
682 fulfilled = false;
683 break;
684 }
685 }
686 if (fulfilled) {
688 resIt = myCurrentReservations.erase(resIt);
689 } else {
690 ++resIt;
691 }
692 }
693 }
694}
695
696
697bool
699 for (const auto& stop : myHolder.getStops()) {
700 if (stop.reached) {
701 continue;
702 }
703 if (stop.pars.permitted.size() > 0) {
704 return true;
705 }
706 }
707 return false;
708}
709
710void
712 if (tripinfoOut != nullptr) {
713 tripinfoOut->openTag("taxi");
714 tripinfoOut->writeAttr("customers", toString(myCustomersServed));
715 tripinfoOut->writeAttr("occupiedDistance", toString(myOccupiedDistance));
716 tripinfoOut->writeAttr("occupiedTime", time2string(myOccupiedTime));
717 tripinfoOut->closeTag();
718 }
719}
720
721std::string
722MSDevice_Taxi::getParameter(const std::string& key) const {
723 if (key == "customers") {
725 } else if (key == "occupiedDistance") {
727 } else if (key == "occupiedTime") {
729 } else if (key == "state") {
730 return toString(myState);
731 } else if (key == "currentCustomers") {
733 } else if (key == "pickUpDuration") {
734 return getStringParam(myHolder, OptionsCont::getOptions(), "taxi.pickUpDuration", "0", false);
735 } else if (key == "dropOffDuration") {
736 return getStringParam(myHolder, OptionsCont::getOptions(), "taxi.dropOffDuration", "60", false);
737 }
738 throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
739}
740
741
742void
743MSDevice_Taxi::setParameter(const std::string& key, const std::string& value) {
744 double doubleValue;
745 try {
746 doubleValue = StringUtils::toDouble(value);
747 } catch (NumberFormatException&) {
748 throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
749 }
750 if (key == "pickUpDuration" || key == "dropOffDuration") {
751 // store as generic vehicle parameters
752 ((SUMOVehicleParameter&)myHolder.getParameter()).setParameter("device.taxi." + key, value);
753 } else {
754 UNUSED_PARAMETER(doubleValue);
755 throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
756 }
757}
758
759bool
760MSDevice_Taxi::compatibleLine(const std::string& taxiLine, const std::string& rideLine) {
761 return (taxiLine == rideLine
762 || (taxiLine == TAXI_SERVICE && StringUtils::startsWith(rideLine, "taxi:"))
763 || (rideLine == TAXI_SERVICE && StringUtils::startsWith(taxiLine, "taxi:")));
764}
765
766bool
770
771
772/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define TAXI_SERVICE
#define TAXI_SERVICE_PREFIX
std::vector< const MSEdge * > ConstMSEdgeVector
Definition MSEdge.h:74
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:271
#define TL(string)
Definition MsgHandler.h:287
#define TLF(string,...)
Definition MsgHandler.h:288
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:69
#define STEPS2TIME(x)
Definition SUMOTime.h:55
#define SIMSTEP
Definition SUMOTime.h:61
#define SIMTIME
Definition SUMOTime.h:62
#define TIME2STEPS(x)
Definition SUMOTime.h:57
@ 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:76
T MAX2(T a, T b)
Definition StdDefs.h:82
std::string joinToStringSorting(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition ToString.h:299
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:307
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)
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=false)
Definition MSDevice.cpp:199
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:148
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=false)
Definition MSDevice.cpp:175
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
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
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
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:593
bool isInternal() const
Definition MSLane.cpp:2456
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:483
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:322
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.
Reroutes vehicles passing an edge.
static const std::map< std::string, MSTriggeredRerouter * > & getInstances()
return all rerouter instances
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.
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
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.
static OptionsCont & getOptions()
Retrieves the options.
Static storage of an output device and its base (abstract) implementation.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
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.
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:62
virtual ConstMSEdgeVector::const_iterator getRerouteOrigin() const =0
Returns the starting point for reroutes (usually the current edge)
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 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.
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 DEBUG_COND
std::string line
Definition MSDispatch.h:78