Eclipse SUMO - Simulation of Urban MObility
MSDevice_Taxi.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2013-2022 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
18 // A device which controls a taxi
19 /****************************************************************************/
20 #include <config.h>
21 
30 #include <microsim/MSGlobals.h>
31 #include <microsim/MSVehicle.h>
32 #include <microsim/MSEdge.h>
33 #include <microsim/MSLane.h>
34 #include <microsim/MSStop.h>
36 
37 #include "MSDispatch.h"
38 #include "MSDispatch_Greedy.h"
41 #include "MSDispatch_TraCI.h"
42 
43 #include "MSIdling.h"
44 
45 #include "MSRoutingEngine.h"
46 #include "MSDevice_Taxi.h"
47 
48 //#define DEBUG_DISPATCH
49 
50 //#define DEBUG_COND (myHolder.isSelected())
51 #define DEBUG_COND (true)
52 
53 // ===========================================================================
54 // static member variables
55 // ===========================================================================
61 // @brief the list of available taxis
62 std::vector<MSDevice_Taxi*> MSDevice_Taxi::myFleet;
65 
66 #define TAXI_SERVICE "taxi"
67 #define TAXI_SERVICE_PREFIX "taxi:"
68 
69 // ===========================================================================
70 // method definitions
71 // ===========================================================================
72 // ---------------------------------------------------------------------------
73 // static initialisation methods
74 // ---------------------------------------------------------------------------
75 void
77  oc.addOptionSubTopic("Taxi Device");
78  insertDefaultAssignmentOptions("taxi", "Taxi Device", oc);
79 
80  oc.doRegister("device.taxi.dispatch-algorithm", new Option_String("greedy"));
81  oc.addDescription("device.taxi.dispatch-algorithm", "Taxi Device", "The dispatch algorithm [greedy|greedyClosest|greedyShared|routeExtension|traci]");
82 
83  oc.doRegister("device.taxi.dispatch-algorithm.output", new Option_FileName());
84  oc.addDescription("device.taxi.dispatch-algorithm.output", "Taxi Device", "Write information from the dispatch algorithm to FILE");
85 
86  oc.doRegister("device.taxi.dispatch-algorithm.params", new Option_String(""));
87  oc.addDescription("device.taxi.dispatch-algorithm.params", "Taxi Device", "Load dispatch algorithm parameters in format KEY1:VALUE1[,KEY2:VALUE]");
88 
89  oc.doRegister("device.taxi.dispatch-period", new Option_String("60", "TIME"));
90  oc.addDescription("device.taxi.dispatch-period", "Taxi Device", "The period between successive calls to the dispatcher");
91 
92  oc.doRegister("device.taxi.idle-algorithm", new Option_String("stop"));
93  oc.addDescription("device.taxi.idle-algorithm", "Taxi Device", "The behavior of idle taxis [stop|randomCircling]");
94 
95  oc.doRegister("device.taxi.idle-algorithm.output", new Option_FileName());
96  oc.addDescription("device.taxi.idle-algorithm.output", "Taxi Device", "Write information from the idling algorithm to FILE");
97 }
98 
99 
100 void
101 MSDevice_Taxi::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
103  if (equippedByDefaultAssignmentOptions(oc, "taxi", v, false)) {
104  // build the device
105  MSDevice_Taxi* device = new MSDevice_Taxi(v, "taxi_" + v.getID());
106  into.push_back(device);
107  myFleet.push_back(device);
108  if (v.getParameter().line == "") {
109  // automatically set the line so that persons are willing to enter
110  // (see MSStageDriving::isWaitingFor)
111  const_cast<SUMOVehicleParameter&>(v.getParameter()).line = TAXI_SERVICE;
112  }
113  if (v.getVClass() != SVC_TAXI) {
114  WRITE_WARNING("Vehicle '" + v.getID() + "' with device.taxi should have vClass taxi instead of '" + toString(v.getVClass()) + "'.");
115  }
116  const int personCapacity = v.getVehicleType().getPersonCapacity();
117  const int containerCapacity = v.getVehicleType().getContainerCapacity();
118  myMaxCapacity = MAX2(myMaxCapacity, personCapacity);
119  myMaxContainerCapacity = MAX2(myMaxContainerCapacity, containerCapacity);
120  if (personCapacity < 1 && containerCapacity < 1) {
121  WRITE_WARNINGF("Vehicle '%' with personCapacity % and containerCapacity % is not usable as taxi.", v.getID(), toString(personCapacity), toString(containerCapacity));
122  }
123  }
124 }
125 
126 
127 void
130  myDispatchPeriod = string2time(oc.getString("device.taxi.dispatch-period"));
131  // init dispatch algorithm
132  std::string algo = oc.getString("device.taxi.dispatch-algorithm");
133  Parameterised params;
134  params.setParametersStr(OptionsCont::getOptions().getString("device.taxi.dispatch-algorithm.params"), ":", ",");
135  if (algo == "greedy") {
137  } else if (algo == "greedyClosest") {
139  } else if (algo == "greedyShared") {
141  } else if (algo == "routeExtension") {
143  } else if (algo == "traci") {
145  } else {
146  throw ProcessError("Dispatch algorithm '" + algo + "' is not known");
147  }
149  // round to next multiple of myDispatchPeriod
151  const SUMOTime begin = string2time(oc.getString("begin"));
152  const SUMOTime delay = (myDispatchPeriod - ((now - begin) % myDispatchPeriod)) % myDispatchPeriod;
154 }
155 
156 bool
157 MSDevice_Taxi::isReservation(const std::set<std::string>& lines) {
158  return lines.size() == 1 && (
159  *lines.begin() == TAXI_SERVICE
160  || StringUtils::startsWith(*lines.begin(), TAXI_SERVICE_PREFIX));
161 }
162 
163 void
165  const std::set<std::string>& lines,
166  SUMOTime reservationTime,
167  SUMOTime pickupTime,
168  const MSEdge* from, double fromPos,
169  const MSEdge* to, double toPos,
170  const std::string& group) {
171  if (!isReservation(lines)) {
172  return;
173  }
174  if ((to->getPermissions() & SVC_TAXI) == 0) {
175  throw ProcessError("Cannot add taxi reservation for " + std::string(person->isPerson() ? "person" : "container")
176  + " '" + person->getID() + "' because destination edge '" + to->getID() + "'"
177  + " does not permit taxi access");
178  }
179  if ((from->getPermissions() & SVC_TAXI) == 0) {
180  throw ProcessError("Cannot add taxi reservation for " + std::string(person->isPerson() ? "person" : "container")
181  + " '" + person->getID() + "' because origin edge '" + from->getID() + "'"
182  + " does not permit taxi access");
183  }
184  if (myDispatchCommand == nullptr) {
185  initDispatch();
186  }
187  myDispatcher->addReservation(person, reservationTime, pickupTime, from, fromPos, to, toPos, group, *lines.begin(), myMaxCapacity, myMaxContainerCapacity);
188 }
189 
190 void
192  const std::set<std::string>& lines,
193  const MSEdge* from, double fromPos,
194  const MSEdge* to, double toPos,
195  const std::string& group) {
196  if (myDispatcher != nullptr && lines.size() == 1 && *lines.begin() == TAXI_SERVICE) {
197  myDispatcher->removeReservation(person, from, fromPos, to, toPos, group);
198  }
199 }
200 
201 
202 SUMOTime
204  std::vector<MSDevice_Taxi*> active;
205  for (MSDevice_Taxi* taxi : myFleet) {
206  if (taxi->getHolder().hasDeparted()) {
207  active.push_back(taxi);
208  }
209  }
210  myDispatcher->computeDispatch(currentTime, active);
211  return myDispatchPeriod;
212 }
213 
214 bool
216  return myDispatcher != nullptr && myDispatcher->hasServableReservations();
217 }
218 
219 void
221  if (myDispatcher != nullptr) {
222  delete myDispatcher;
223  myDispatcher = nullptr;
224  }
225  myDispatchCommand = nullptr;
226 }
227 
228 // ---------------------------------------------------------------------------
229 // MSDevice_Taxi-methods
230 // ---------------------------------------------------------------------------
231 MSDevice_Taxi::MSDevice_Taxi(SUMOVehicle& holder, const std::string& id) :
232  MSVehicleDevice(holder, id) {
233  std::string defaultServiceEnd = toString(1e15);
234  const std::string algo = getStringParam(holder, OptionsCont::getOptions(), "taxi.idle-algorithm", "", false);
235  if (algo == "stop") {
237  } else if (algo == "randomCircling") {
239  // make sure simulation terminates
240  defaultServiceEnd = toString(STEPS2TIME(
243  : MSNet::getInstance()->getCurrentTimeStep()) + (3600 * 8));
244  } else {
245  throw ProcessError("Idle algorithm '" + algo + "' is not known for vehicle '" + myHolder.getID() + "'");
246  }
247  myServiceEnd = string2time(getStringParam(holder, OptionsCont::getOptions(), "taxi.end", defaultServiceEnd, false));
248 }
249 
250 
252  myFleet.erase(std::find(myFleet.begin(), myFleet.end(), this));
253  // recompute myMaxCapacity
254  myMaxCapacity = 0;
256  for (MSDevice_Taxi* taxi : myFleet) {
257  myMaxCapacity = MAX2(myMaxCapacity, taxi->getHolder().getVehicleType().getPersonCapacity());
258  myMaxContainerCapacity = MAX2(myMaxContainerCapacity, taxi->getHolder().getVehicleType().getContainerCapacity());
259  }
260 }
261 
262 
265  if (myFleet.size() > 0) {
266  return &myFleet[0]->getHolder();
267  } else {
268  return nullptr;
269  }
270 }
271 
272 
273 void
275  dispatchShared({&res, &res});
276 }
277 
278 
279 void
280 MSDevice_Taxi::dispatchShared(std::vector<const Reservation*> reservations) {
281 #ifdef DEBUG_DISPATCH
282  if (DEBUG_COND) {
283  std::cout << SIMTIME << " taxi=" << myHolder.getID() << " dispatch:\n";
284  for (const Reservation* res : reservations) {
285  std::cout << " persons=" << toString(res->persons) << "\n";
286  }
287  }
288 #endif
289  ConstMSEdgeVector tmpEdges;
290  std::vector<SUMOVehicleParameter::Stop> stops;
291  double lastPos = myHolder.getPositionOnLane();
292  MSBaseVehicle* veh = dynamic_cast<MSBaseVehicle*>(&myHolder);
293  assert(veh != nullptr);
294  const MSEdge* rerouteOrigin = veh->getRerouteOrigin();
295  if (isEmpty()) {
296  // start fresh from the current edge
298  assert(!veh->hasStops());
299  tmpEdges.push_back(myHolder.getEdge());
300  if (myHolder.getEdge() != rerouteOrigin) {
301  tmpEdges.push_back(rerouteOrigin);
302  }
303  } else {
304  assert(veh->hasStops());
305  // check how often existing customers appear in the new reservations
306  std::map<const MSTransportable*, int> nOccur;
307  for (const Reservation* res : reservations) {
308  for (MSTransportable* person : res->persons) {
309  if (myCustomers.count(person) != 0) {
310  nOccur[person] += 1;
311  if (myCurrentReservations.count(res) == 0) {
312  throw ProcessError("Invalid Re-dispatch for existing customer '" + person->getID() + "' with a new reservation");
313  }
314  }
315  }
316  }
317  if (nOccur.size() == 0) {
318  // no overlap with existing customers - extend route
319  tmpEdges = myHolder.getRoute().getEdges();
320  lastPos = veh->getStops().back().pars.endPos;
321 #ifdef DEBUG_DISPATCH
322  if (DEBUG_COND) {
323  std::cout << " re-dispatch with route-extension\n";
324  }
325 #endif
326  } else if (nOccur.size() == myCustomers.size()) {
327  // redefine route (verify correct number of mentions)
328  std::set<const MSTransportable*> onBoard;
329  const std::vector<MSTransportable*>& onBoardP = myHolder.getPersons();
330  const std::vector<MSTransportable*>& onBoardC = myHolder.getContainers();
331  onBoard.insert(onBoardP.begin(), onBoardP.end());
332  onBoard.insert(onBoardC.begin(), onBoardC.end());
333  std::set<const MSTransportable*> redundantPickup;
334  for (auto item : nOccur) {
335  if (item.second == 1) {
336  // customers must already be on board
337  if (onBoard.count(item.first) == 0) {
338  throw ProcessError("Re-dispatch did not mention pickup for existing customer '" + item.first->getID() + "'");
339  }
340  } else if (item.second == 2) {
341  if (onBoard.count(item.first) == 0) {
342  // treat like a new customer
343  myCustomers.erase(item.first);
344  } else {
345  redundantPickup.insert(item.first);
346  }
347  } else {
348  throw ProcessError("Re-dispatch mentions existing customer '" + item.first->getID() + "' " + toString(item.second) + " times");
349  }
350  }
351  // remove redundancy
352  if (!redundantPickup.empty()) {
353  for (auto it = reservations.begin(); it != reservations.end();) {
354  bool isRedundant = false;
355  for (const MSTransportable* person : (*it)->persons) {
356  if (redundantPickup.count(person) != 0) {
357  isRedundant = true;
358  break;
359  }
360  }
361  if (isRedundant) {
362  for (const MSTransportable* person : (*it)->persons) {
363  redundantPickup.erase(person);
364  }
365  it = reservations.erase(it);
366  } else {
367  it++;
368  }
369  }
370  }
371  while (veh->hasStops()) {
373  }
374  tmpEdges.push_back(myHolder.getEdge());
375  if (myHolder.getEdge() != rerouteOrigin) {
376  tmpEdges.push_back(rerouteOrigin);
377  }
378 #ifdef DEBUG_DISPATCH
379  if (DEBUG_COND) {
380  std::cout << " re-dispatch from scratch\n";
381  }
382 #endif
383  } else {
384  // inconsistent re-dispatch
385  std::vector<std::string> missing;
386  for (const MSTransportable* c : myCustomers) {
387  if (nOccur.count(c) == 0) {
388  missing.push_back(c->getID());
389  }
390  }
391  throw ProcessError("Re-dispatch did mention some customers but failed to mention " + joinToStringSorting(missing, " "));
392  }
393  }
394 
396  for (const Reservation* res : reservations) {
397  myCurrentReservations.insert(res);
398  bool isPickup = false;
399  for (MSTransportable* person : res->persons) {
400  if (myCustomers.count(person) == 0) {
401  myCustomers.insert(person);
402  isPickup = true;
403  }
404  }
405  if (isPickup) {
406  prepareStop(tmpEdges, stops, lastPos, res->from, res->fromPos, "pickup " + toString(res->persons) + " (" + res->id + ")");
407  for (const MSTransportable* const transportable : res->persons) {
408  if (transportable->isPerson()) {
409  stops.back().triggered = true;
410  } else {
411  stops.back().containerTriggered = true;
412  }
413  stops.back().permitted.insert(transportable->getID());
414  }
415  //stops.back().awaitedPersons.insert(res.person->getID());
416  stops.back().parametersSet |= STOP_PERMITTED_SET;
417  if (stops.back().duration == -1) {
418  // keep dropOffDuration if the stop is dropOff and pickUp
419  stops.back().duration = TIME2STEPS(getFloatParam(myHolder, OptionsCont::getOptions(), "taxi.pickUpDuration", 0, false));
420  }
421  } else {
422  prepareStop(tmpEdges, stops, lastPos, res->to, res->toPos, "dropOff " + toString(res->persons) + " (" + res->id + ")");
423  stops.back().duration = TIME2STEPS(getFloatParam(myHolder, OptionsCont::getOptions(), "taxi.dropOffDuration", 60, false)); // pay and collect bags
424  }
425  }
426 #ifdef DEBUG_DISPATCH
427  if (DEBUG_COND) {
428  std::cout << " tmpEdges=" << toString(tmpEdges) << "\n";
429  }
430 #endif
431  if (!myHolder.replaceRouteEdges(tmpEdges, -1, 0, "taxi:prepare_dispatch", false, false, false)) {
432  throw ProcessError("Route replacement for taxi dispatch failed for vehicle '" + myHolder.getID()
433  + "' at time=" + time2string(t) + ".");
434  }
435 #ifdef DEBUG_DISPATCH
436  if (DEBUG_COND) std::cout << " replacedRoute=" << toString(tmpEdges)
437  << "\n actualRoute=" << toString(myHolder.getRoute().getEdges()) << "\n";
438 #endif
439  for (SUMOVehicleParameter::Stop& stop : stops) {
440  std::string error;
441  myHolder.addStop(stop, error);
442  if (error != "") {
443  WRITE_WARNINGF("Could not add taxi stop for vehicle '%' to %. time=% error=%.", myHolder.getID(), stop.actType, time2string(t), error)
444  }
445  }
447  // SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = myHolder.getInfluencer().getRouterTT(veh->getRNGIndex())
448  myHolder.reroute(t, "taxi:dispatch", router, false);
449 #ifdef DEBUG_DISPATCH
450  if (DEBUG_COND) {
451  std::cout << "\n finalRoute=" << toString(myHolder.getRoute().getEdges()) << " routeIndex=" << myHolder.getRoutePosition() << "\n";
452  }
453 #endif
454  myState |= PICKUP;
455 }
456 
457 
458 void
460  std::vector<SUMOVehicleParameter::Stop>& stops,
461  double& lastPos, const MSEdge* stopEdge, double stopPos,
462  const std::string& action) {
463  assert(!edges.empty());
464  if (stopPos < lastPos && stopPos + NUMERICAL_EPS >= lastPos) {
465  stopPos = lastPos;
466  }
467 
468  if (stops.empty()) {
469  // check brakeGap
470  double distToStop = stopPos - lastPos;
471  const double brakeGap = myHolder.getBrakeGap();
472  if (myHolder.getLane() != nullptr && myHolder.getLane()->isInternal()) {
473  distToStop += myHolder.getLane()->getLength();
474  }
475  if (stopEdge != edges.back()) {
476  distToStop += edges.back()->getLength();
477  if (distToStop < brakeGap) {
478  // the distance between current edge and stop edge may be small
480  ConstMSEdgeVector toFirstStop;
481  router.compute(edges.back(), stopEdge, &myHolder, SIMSTEP, toFirstStop, true);
482  for (int i = 1; i < (int)toFirstStop.size() - 1; i++) {
483  distToStop += toFirstStop[i]->getLength();
484  }
485  }
486  }
487  if (distToStop < brakeGap) {
488  // circle back to stopEdge
489  //std::cout << SIMTIME << " taxi=" << getID() << " brakeGap=" << brakeGap << " distToStop=" << distToStop << "\n";
490  edges.push_back(stopEdge);
491  }
492  }
493 
494  if (stopEdge == edges.back() && !stops.empty()) {
495  if (stopPos >= lastPos && stopPos <= stops.back().endPos) {
496  // no new stop and no adaption needed
497  stops.back().actType += "," + action;
498  return;
499  }
500  if (stopPos >= lastPos && stopPos <= lastPos + myHolder.getVehicleType().getLength()) {
501  // stop length adaption needed
502  stops.back().endPos = MIN2(lastPos + myHolder.getVehicleType().getLength(), stopEdge->getLength());
503  stops.back().actType += "," + action;
504  return;
505  }
506  }
507  if (stopEdge != edges.back() || stopPos < lastPos) {
508  edges.push_back(stopEdge);
509  }
510  lastPos = stopPos;
512  stop.lane = getStopLane(stopEdge, action)->getID();
513  stop.startPos = stopPos;
514  stop.endPos = MAX2(stopPos, MIN2(myHolder.getVehicleType().getLength(), stopEdge->getLength()));
515  stop.parking = getBoolParam(myHolder, OptionsCont::getOptions(), "taxi.parking", true, false);
516  stop.actType = action;
517  stop.index = STOP_INDEX_END;
518  stops.push_back(stop);
519 }
520 
521 
522 MSLane*
523 MSDevice_Taxi::getStopLane(const MSEdge* edge, const std::string& action) {
524  const std::vector<MSLane*>* allowedLanes = edge->allowedLanes(myHolder.getVClass());
525  if (allowedLanes == nullptr) {
526  throw ProcessError("Taxi vehicle '" + myHolder.getID() + "' cannot stop on edge '" + edge->getID() + "' (" + action + ")");
527  }
528  return allowedLanes->front();
529 }
530 
531 bool
533  return myState == EMPTY;
534 }
535 
536 
537 bool
539  return myCustomers.count(t) != 0;
540 }
541 
542 
543 bool
544 MSDevice_Taxi::notifyMove(SUMOTrafficObject& /*tObject*/, double oldPos,
545  double newPos, double /*newSpeed*/) {
547  myOccupiedDistance += (newPos - oldPos);
549  }
551  myIdleAlgorithm->idle(this);
552  }
553  if (myHolder.isStopped()) {
554  if (!myIsStopped) {
555  // limit duration of stop
556  // @note: stops are not yet added to the vehicle so we can change the loaded parameters. Stops added from a route are not affected
558  }
559  }
561  return true; // keep the device
562 }
563 
564 
565 bool
566 MSDevice_Taxi::notifyEnter(SUMOTrafficObject& /*veh*/, MSMoveReminder::Notification /*reason*/, const MSLane* /* enteredLane */) {
567  if (isEmpty() && MSNet::getInstance()->getCurrentTimeStep() < myServiceEnd) {
568  myIdleAlgorithm->idle(this);
569  }
570  return true; // keep the device
571 }
572 
573 
574 bool
575 MSDevice_Taxi::notifyLeave(SUMOTrafficObject& /*veh*/, double /*lastPos*/, MSMoveReminder::Notification /*reason*/, const MSLane* /* enteredLane */) {
576  return true; // keep the device
577 }
578 
579 void
581  myState |= OCCUPIED;
582  if (!hasFuturePickup()) {
583  myState &= ~PICKUP;
584  }
585  for (const Reservation* res : myCurrentReservations) {
586  for (const MSTransportable* cand : res->persons) {
587  if (cand == t) {
588  const_cast<Reservation*>(res)->state = Reservation::ONBOARD;
589  break;
590  }
591  }
592  }
593 }
594 
595 
596 void
599  myCustomers.erase(person);
600  if (myHolder.getPersonNumber() == 0 && myHolder.getContainerNumber() == 0) {
601  myState &= ~OCCUPIED;
602  if (myHolder.getStops().size() > 1 && (myState & PICKUP) == 0) {
603  WRITE_WARNINGF("All customers left vehicle '%' at time=% but there are % remaining stops",
604  myHolder.getID(), time2string(SIMSTEP), myHolder.getStops().size() - 1);
605  while (myHolder.getStops().size() > 1) {
607  }
608  }
609  }
610  if (isEmpty()) {
611  // cleanup
612  for (const Reservation* res : myCurrentReservations) {
614  }
615  myCurrentReservations.clear();
616  } else {
617  // check whether a single reservation has been fulfilled
618  for (auto resIt = myCurrentReservations.begin(); resIt != myCurrentReservations.end();) {
619  bool fulfilled = true;
620  for (MSTransportable* t : (*resIt)->persons) {
621  if (myCustomers.count(t) != 0) {
622  fulfilled = false;
623  break;
624  }
625  }
626  if (fulfilled) {
628  resIt = myCurrentReservations.erase(resIt);
629  } else {
630  ++resIt;
631  }
632  }
633  }
634 }
635 
636 bool
638  for (const auto& stop : myHolder.getStops()) {
639  if (stop.reached) {
640  continue;
641  }
642  if (stop.pars.permitted.size() > 0) {
643  return true;
644  }
645  }
646  return false;
647 }
648 
649 void
651  if (tripinfoOut != nullptr) {
652  tripinfoOut->openTag("taxi");
653  tripinfoOut->writeAttr("customers", toString(myCustomersServed));
654  tripinfoOut->writeAttr("occupiedDistance", toString(myOccupiedDistance));
655  tripinfoOut->writeAttr("occupiedTime", time2string(myOccupiedTime));
656  tripinfoOut->closeTag();
657  }
658 }
659 
660 std::string
661 MSDevice_Taxi::getParameter(const std::string& key) const {
662  if (key == "customers") {
663  return toString(myCustomersServed);
664  } else if (key == "occupiedDistance") {
666  } else if (key == "occupiedTime") {
668  } else if (key == "state") {
669  return toString(myState);
670  } else if (key == "currentCustomers") {
672  } else if (key == "pickUpDuration") {
673  return getStringParam(myHolder, OptionsCont::getOptions(), "taxi.pickUpDuration", "0", false);
674  } else if (key == "dropOffDuration") {
675  return getStringParam(myHolder, OptionsCont::getOptions(), "taxi.dropOffDuration", "60", false);
676  }
677  throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
678 }
679 
680 
681 void
682 MSDevice_Taxi::setParameter(const std::string& key, const std::string& value) {
683  double doubleValue;
684  try {
685  doubleValue = StringUtils::toDouble(value);
686  } catch (NumberFormatException&) {
687  throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
688  }
689  if (key == "pickUpDuration" || key == "dropOffDuration") {
690  // store as generic vehicle parameters
691  ((SUMOVehicleParameter&)myHolder.getParameter()).setParameter("device.taxi." + key, value);
692  } else {
693  UNUSED_PARAMETER(doubleValue);
694  throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
695  }
696 }
697 
698 bool
699 MSDevice_Taxi::compatibleLine(const std::string& taxiLine, const std::string& rideLine) {
700  return (taxiLine == rideLine
701  || (taxiLine == TAXI_SERVICE && StringUtils::startsWith(rideLine, "taxi:"))
702  || (rideLine == TAXI_SERVICE && StringUtils::startsWith(taxiLine, "taxi:")));
703 }
704 
705 bool
707  return compatibleLine(myHolder.getParameter().line, res->line);
708 }
709 
710 
711 /****************************************************************************/
#define TAXI_SERVICE
#define DEBUG_COND
#define TAXI_SERVICE_PREFIX
std::vector< const MSEdge * > ConstMSEdgeVector
Definition: MSEdge.h:74
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:281
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:280
SUMOTime DELTA_T
Definition: SUMOTime.cpp:37
std::string time2string(SUMOTime t)
convert SUMOTime to string
Definition: SUMOTime.cpp:68
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition: SUMOTime.cpp:45
#define STEPS2TIME(x)
Definition: SUMOTime.h:53
#define SIMSTEP
Definition: SUMOTime.h:59
#define SIMTIME
Definition: SUMOTime.h:60
#define TIME2STEPS(x)
Definition: SUMOTime.h:55
long long int SUMOTime
Definition: SUMOTime.h:32
@ SVC_TAXI
vehicle is a taxi
const int STOP_INDEX_END
const int STOP_PERMITTED_SET
@ DEPART_GIVEN
The time is given.
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:30
T MIN2(T a, T b)
Definition: StdDefs.h:74
T MAX2(T a, T b)
Definition: StdDefs.h:80
std::string joinToStringSorting(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:285
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:293
Base (microsim) event class.
Definition: Command.h:50
The base class for microscopic and mesoscopic vehicles.
Definition: MSBaseVehicle.h:51
const std::list< MSStop > & getStops() const
virtual const MSEdge * getRerouteOrigin() const
Returns the starting point for reroutes (usually the current edge)
bool hasStops() const
Returns whether the vehicle has to stop somewhere.
A device which collects info on the vehicle trip (mainly on departure and arrival)
Definition: MSDevice_Taxi.h:48
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
bool notifyLeave(SUMOTrafficObject &veh, double lastPos, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Saves arrival info.
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
bool allowsBoarding(MSTransportable *t) const
whether the given person is allowed to board this taxi
static MSDispatch * myDispatcher
the dispatch algorithm
int myCustomersServed
number of customers that were served
static int myMaxContainerCapacity
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
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
~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 bool getBoolParam(const SUMOVehicle &v, const OptionsCont &oc, std::string paramName, bool deflt, bool required)
Definition: MSDevice.cpp:201
static double getFloatParam(const SUMOVehicle &v, const OptionsCont &oc, std::string paramName, double deflt, bool required)
Definition: MSDevice.cpp:188
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:137
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:205
static std::string getStringParam(const SUMOVehicle &v, const OptionsCont &oc, std::string paramName, std::string deflt, bool required)
Definition: MSDevice.cpp:164
A dispatch algorithm that services the reservations with the shortest traveltime-to-pickup first.
A dispatch algorithm that services customers in reservation order and always sends the closest availa...
A dispatch algorithm that services customers in reservation order and always sends the closest availa...
An algorithm that performs distpach for a taxi fleet.
Definition: MSDispatch.h:102
virtual std::string removeReservation(MSTransportable *person, const MSEdge *from, double fromPos, const MSEdge *to, double toPos, std::string group)
remove person from reservation. If the whole reservation is removed, return it's id
Definition: MSDispatch.cpp:125
virtual Reservation * addReservation(MSTransportable *person, SUMOTime reservationTime, SUMOTime pickupTime, const MSEdge *from, double fromPos, const MSEdge *to, double toPos, std::string group, const std::string &line, int maxCapacity, int maxContainerCapacity)
add a new reservation
Definition: MSDispatch.cpp:61
bool hasServableReservations()
check whether there are still (servable) reservations in the system
Definition: MSDispatch.h:153
virtual void fulfilledReservation(const Reservation *res)
erase reservation from storage
Definition: MSDispatch.cpp:207
virtual void computeDispatch(SUMOTime now, const std::vector< MSDevice_Taxi * > &fleet)=0
computes dispatch and updates reservations
A road/street connecting two junctions.
Definition: MSEdge.h:77
SVCPermissions getPermissions() const
Returns the combined permissions of all lanes of this edge.
Definition: MSEdge.h:605
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:408
double getLength() const
return the length of the edge
Definition: MSEdge.h:641
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
virtual void idle(MSDevice_Taxi *taxi)=0
computes Idling and updates reservations
Representation of a lane in the micro simulation.
Definition: MSLane.h:82
double getLength() const
Returns the lane's length.
Definition: MSLane.h:541
bool isInternal() const
Definition: MSLane.cpp:2122
Notification
Definition of a vehicle state.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:174
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:318
MSEventControl * getEndOfTimestepEvents()
Returns the event control for events executed at the end of a time step.
Definition: MSNet.h:479
const ConstMSEdgeVector & getEdges() const
Definition: MSRoute.h:120
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:87
bool isPerson() const
Whether it is a person.
Abstract in-vehicle device.
SUMOVehicle & myHolder
The vehicle that stores the device.
int getPersonCapacity() const
Get this vehicle type's person capacity.
double getLength() const
Get vehicle's length [m].
int getContainerCapacity() const
Get this vehicle type's container capacity.
const std::string & getID() const
Returns the id.
Definition: Named.h:74
A storage for options typed value containers)
Definition: OptionsCont.h:89
void addDescription(const std::string &name, const std::string &subtopic, const std::string &description)
Adds a description for an option.
void doRegister(const std::string &name, Option *v)
Adds an option under the given name.
Definition: OptionsCont.cpp:75
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
void addOptionSubTopic(const std::string &topic)
Adds an option subtopic.
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:61
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:248
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
An upper class for objects with additional parameters.
Definition: Parameterised.h:41
void setParametersStr(const std::string &paramsString, const std::string kvsep="=", const std::string sep="|")
set the inner key/value map in string format "key1=value1|key2=value2|...|keyN=valueN"
const std::map< std::string, std::string > & 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 bool isStopped() const =0
Returns whether the object is at a stop.
virtual const MSVehicleType & getVehicleType() const =0
Returns the object's "vehicle" type.
virtual SUMOVehicleClass getVClass() const =0
Returns the object's access class.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle's parameter (including departure definition)
virtual const MSLane * getLane() const =0
Returns the lane the object is currently at.
virtual const MSEdge * getEdge() const =0
Returns the edge the object is currently at.
virtual double getPositionOnLane() const =0
Get the object's position along the lane.
Representation of a vehicle.
Definition: SUMOVehicle.h:60
virtual bool replaceRouteEdges(ConstMSEdgeVector &edges, double cost, double savings, const std::string &info, bool onInit=false, bool check=false, bool removeStops=true, std::string *msgReturn=nullptr)=0
Replaces the current route by the given edges.
virtual const MSRoute & getRoute() const =0
Returns the current route.
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 const std::list< MSStop > & getStops() const =0
virtual bool addStop(const SUMOVehicleParameter::Stop &stopPar, std::string &errorMsg, SUMOTime untilOffset=0, bool collision=false, ConstMSEdgeVector::const_iterator *searchStart=0)=0
Adds a stop.
virtual const std::vector< MSTransportable * > & getContainers() const =0
retrieve riding containers
virtual int getRNGIndex() const =0
virtual MSStop & getNextStop()=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 double getBrakeGap(bool delayed=false) const =0
get distance for coming to a stop (used for rerouting checks)
virtual int getRoutePosition() const =0
return index of edge within 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)
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.
bool parking
whether the vehicle is removed from the net while stopping
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)
A wrapper for a Command function.
Definition: StaticCommand.h:38
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
std::string line
Definition: MSDispatch.h:78