Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSDispatch.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2007-2025 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// An algorithm that performs dispatch for the taxi device
19/****************************************************************************/
20#include <config.h>
21
22#include <limits>
23#include <microsim/MSNet.h>
24#include <microsim/MSEdge.h>
26#include "MSRoutingEngine.h"
27#include "MSDispatch.h"
28
29//#define DEBUG_RESERVATION
30//#define DEBUG_DETOUR
31//#define DEBUG_COND2(obj) (obj->getID() == "p0")
32#define DEBUG_COND2(obj) (true)
33
34
35// ===========================================================================
36// Reservation methods
37// ===========================================================================
38
39std::string
41 return toString(persons);
42}
43
44// ===========================================================================
45// MSDispatch methods
46// ===========================================================================
47
49 Parameterised(params),
50 myOutput(nullptr),
51 myReservationCount(0) {
52 const std::string opt = "device.taxi.dispatch-algorithm.output";
53 if (OptionsCont::getOptions().isSet(opt)) {
54 OutputDevice::createDeviceByOption(opt, "DispatchInfo");
56 }
57 myKeepUnreachableResTime = string2time(OptionsCont::getOptions().getString("device.taxi.dispatch-keep-unreachable"));
58}
59
61 for (auto item : myGroupReservations) {
62 for (Reservation* res : item.second) {
63 delete res;
64 }
65 }
66 myGroupReservations.clear();
67}
68
69
72 SUMOTime reservationTime,
73 SUMOTime pickupTime,
74 SUMOTime earliestPickupTime,
75 const MSEdge* from, double fromPos,
76 const MSStoppingPlace* fromStop,
77 const MSEdge* to, double toPos,
78 const MSStoppingPlace* toStop,
79 std::string group,
80 const std::string& line,
81 int maxCapacity,
82 int maxContainerCapacity) {
83 // no new reservation nedded if the person can be added to an existing group
84 if (group == "") {
85 // the default empty group implies, no grouping is wanted (and
86 // transportable ids are unique)
87 group = person->getID();
88 }
89 Reservation* result = nullptr;
90 bool added = false;
91 auto it = myGroupReservations.find(group);
92 if (it != myGroupReservations.end()) {
93 // try to add to existing reservation
94 for (Reservation* res : it->second) {
95 if (res->persons.count(person) == 0
96 && res->from == from
97 && res->to == to
98 && res->fromPos == fromPos
99 && res->toPos == toPos) {
100 if (res->persons.size() > 0 && (*res->persons.begin())->isPerson() != person->isPerson()) {
101 WRITE_WARNINGF(TL("Mixing reservations of persons and containers with the same group is not supported for % and %"),
102 (*res->persons.begin())->getID(), person->getID());
103 }
104 if ((person->isPerson() && (int)res->persons.size() >= maxCapacity) ||
105 (!person->isPerson() && (int)res->persons.size() >= maxContainerCapacity)) {
106 // split group to ensure that at least one taxi is capable of delivering group size.
107 continue;
108 }
109 res->persons.insert(person);
110 result = res;
111 added = true;
112 break;
113 }
114 }
115 }
116 if (!added) {
117 Reservation* newRes = new Reservation(toString(myReservationCount++), {person}, reservationTime, pickupTime, earliestPickupTime, from, fromPos, fromStop, to, toPos, toStop, group, line);
118 myGroupReservations[group].push_back(newRes);
119 result = newRes;
120 }
122#ifdef DEBUG_RESERVATION
123 if (DEBUG_COND2(person)) std::cout << SIMTIME
124 << " addReservation p=" << person->getID()
125 << " rT=" << time2string(reservationTime)
126 << " pT=" << time2string(pickupTime)
127 << " from=" << from->getID() << " fromPos=" << fromPos
128 << " to=" << to->getID() << " toPos=" << toPos
129 << " group=" << group
130 << " added=" << added
131 << "\n";
132#endif
133 return result;
134}
135
136
137std::string
139 const MSEdge* from, double fromPos,
140 const MSEdge* to, double toPos,
141 std::string group) {
142 if (group == "") {
143 // the default empty group implies, no grouping is wanted (and
144 // transportable ids are unique)
145 group = person->getID();
146 }
147 std::string removedID = "";
148 auto it = myGroupReservations.find(group);
149 if (it != myGroupReservations.end()) {
150 for (auto itRes = it->second.begin(); itRes != it->second.end(); itRes++) {
151 Reservation* res = *itRes;
152 if (res->persons.count(person) != 0
153 && res->from == from
154 && res->to == to
155 && res->fromPos == fromPos
156 && res->toPos == toPos) {
157 res->persons.erase(person);
158 if (res->persons.empty()) {
159 removedID = res->id;
160 it->second.erase(itRes);
161 // cleans up MSDispatch_Greedy
163 if (it->second.empty()) {
164 myGroupReservations.erase(it);
165 }
166 }
167 break;
168 }
169 }
170 } else {
171 auto it2 = myRunningReservations.find(group);
172 if (it2 != myRunningReservations.end()) {
173 for (auto item : it2->second) {
174 const Reservation* res = item.first;
175 if (res->persons.count(person) != 0
176 && res->from == from
177 && res->to == to
178 && res->fromPos == fromPos
179 && res->toPos == toPos) {
180 MSDevice_Taxi* taxi = item.second;
181 taxi->cancelCustomer(person);
182 if (res->persons.empty()) {
183 removedID = res->id;
184 }
185 break;
186 }
187 }
188 }
189 }
191#ifdef DEBUG_RESERVATION
192 if (DEBUG_COND2(person)) std::cout << SIMTIME
193 << " removeReservation p=" << person->getID()
194 << " from=" << from->getID() << " fromPos=" << fromPos
195 << " to=" << to->getID() << " toPos=" << toPos
196 << " group=" << group
197 << " removedID=" << removedID
198 << " hasServable=" << myHasServableReservations
199 << "\n";
200#endif
201 return removedID;
202}
203
204
207 const MSEdge* from, double fromPos,
208 const MSEdge* to, double toPos,
209 std::string group, double newFromPos) {
210 if (group == "") {
211 // the default empty group implies, no grouping is wanted (and
212 // transportable ids are unique)
213 group = person->getID();
214 }
215 Reservation* result = nullptr;
216 std::string updatedID = "";
217 auto it = myGroupReservations.find(group);
218 if (it != myGroupReservations.end()) {
219 for (auto itRes = it->second.begin(); itRes != it->second.end(); itRes++) {
220 Reservation* res = *itRes;
221 // TODO: if there is already a reservation with the newFromPos, add to this reservation
222 // TODO: if there are other persons in this reservation, create a new reservation for the updated one
223 if (res->persons.count(person) != 0
224 && res->from == from
225 && res->to == to
226 && res->fromPos == fromPos
227 && res->toPos == toPos) {
228 // update fromPos
229 res->fromPos = newFromPos;
230 result = res;
231 updatedID = res->id;
232 break;
233 }
234 }
235 }
236#ifdef DEBUG_RESERVATION
237 if (DEBUG_COND2(person)) std::cout << SIMTIME
238 << " updateReservationFromPos p=" << person->getID()
239 << " from=" << from->getID() << " fromPos=" << fromPos
240 << " to=" << to->getID() << " toPos=" << toPos
241 << " group=" << group
242 << " newFromPos=" << newFromPos
243 << " updatedID=" << updatedID
244 << "\n";
245#endif
246 return result;
247}
248
249
250std::vector<Reservation*>
252 std::vector<Reservation*> reservations;
253 for (const auto& it : myGroupReservations) {
254 reservations.insert(reservations.end(), it.second.begin(), it.second.end());
255 }
256 return reservations;
257}
258
259
260std::vector<const Reservation*>
262 std::vector<const Reservation*> result;
263 for (auto item : myRunningReservations) {
264 for (auto item2 : item.second) {
265 result.push_back(item2.first);
266 }
267 }
268 return result;
269}
270
271
272void
274 auto itR = myRunningReservations.find(res->group);
275 if (itR != myRunningReservations.end() && itR->second.count(res) != 0) {
276 return; // was redispatch
277 }
278 auto it = myGroupReservations.find(res->group);
279 if (it == myGroupReservations.end()) {
280 throw ProcessError(TL("Inconsistent group reservations."));
281 }
282 auto it2 = std::find(it->second.begin(), it->second.end(), res);
283 if (it2 == it->second.end()) {
284 throw ProcessError(TL("Inconsistent group reservations (2)."));
285 }
286 myRunningReservations[res->group][res] = taxi;
287 const_cast<Reservation*>(*it2)->state = Reservation::ASSIGNED;
288 it->second.erase(it2);
289 if (it->second.empty()) {
290 myGroupReservations.erase(it);
291 }
292}
293
294
295void
297 myRunningReservations[res->group].erase(res);
298 if (myRunningReservations[res->group].empty()) {
299 myRunningReservations.erase(res->group);
300 }
301 delete res;
302}
303
304
307 ConstMSEdgeVector edges;
308 router.compute(taxi->getHolder().getEdge(), taxi->getHolder().getPositionOnLane() - NUMERICAL_EPS,
309 res.from, res.fromPos, &taxi->getHolder(), t, edges, true);
310 if (edges.empty()) {
311 return SUMOTime_MAX;
312 } else {
313 return TIME2STEPS(router.recomputeCosts(edges, &taxi->getHolder(), t));
314 }
315}
316
317
318bool
320 ConstMSEdgeVector edges;
321 router.compute(res.from, res.fromPos, res.to, res.toPos, &taxi->getHolder(), t, edges, true);
322 return !edges.empty();
323}
324
325
326double
328 const MSEdge* from, double fromPos,
329 const MSEdge* via, double viaPos,
330 const MSEdge* to, double toPos,
332 double& timeDirect) {
333 ConstMSEdgeVector edges;
334 if (timeDirect < 0) {
335 router.compute(from, fromPos, to, toPos, &taxi->getHolder(), t, edges, true);
336 timeDirect = router.recomputeCostsPos(edges, &taxi->getHolder(), fromPos, toPos, t);
337 edges.clear();
338 }
339
340 router.compute(from, fromPos, via, viaPos, &taxi->getHolder(), t, edges, true);
341 const double start = STEPS2TIME(t);
342 const double leg1 = router.recomputeCostsPos(edges, &taxi->getHolder(), fromPos, viaPos, t);
343#ifdef DEBUG_DETOUR
344 std::cout << " leg1=" << toString(edges) << " startPos=" << fromPos << " toPos=" << viaPos << " time=" << leg1 << "\n";
345#endif
346 const double wait = MAX2(0.0, STEPS2TIME(viaTime) - (start + leg1));
347 edges.clear();
348 const SUMOTime timeContinue = TIME2STEPS(start + leg1 + wait);
349 router.compute(via, viaPos, to, toPos, &taxi->getHolder(), timeContinue, edges, true);
350 const double leg2 = router.recomputeCostsPos(edges, &taxi->getHolder(), viaPos, toPos, timeContinue);
351 const double timeDetour = leg1 + wait + leg2;
352#ifdef DEBUG_DETOUR
353 std::cout << " leg2=" << toString(edges) << " startPos=" << viaPos << " toPos=" << toPos << " time=" << leg2 << "\n";
354 std::cout << " t=" << STEPS2TIME(t) << " vt=" << STEPS2TIME(viaTime)
355 << " from=" << from->getID() << " to=" << to->getID() << " via=" << via->getID()
356 << " direct=" << timeDirect << " detour=" << timeDetour << " wait=" << wait << "\n";
357#endif
358 return timeDetour;
359}
360
361
362int
364 assert(res->persons.size() > 0);
365 return ((*res->persons.begin())->isPerson()
367 : taxi->getHolder().getVehicleType().getContainerCapacity()) - (int)res->persons.size();
368}
369
370
371/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define DEBUG_COND2(obj)
Definition MESegment.cpp:54
std::vector< const MSEdge * > ConstMSEdgeVector
Definition MSEdge.h:74
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define TL(string)
Definition MsgHandler.h:304
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:55
#define SUMOTime_MAX
Definition SUMOTime.h:34
#define SIMTIME
Definition SUMOTime.h:62
#define TIME2STEPS(x)
Definition SUMOTime.h:57
T MAX2(T a, T b)
Definition StdDefs.h:86
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
A device which collects info on the vehicle trip (mainly on departure and arrival)
bool cancelCustomer(const MSTransportable *t)
remove person from reservations
OutputDevice * myOutput
optional file output for dispatch information
Definition MSDispatch.h:206
bool isReachable(SUMOTime t, const MSDevice_Taxi *taxi, const Reservation &res, SUMOAbstractRouter< MSEdge, SUMOVehicle > &router)
compute whether the reservation is servable
int remainingCapacity(const MSDevice_Taxi *taxi, const Reservation *res)
whether the given taxi has sufficient capacity to serve the reservation
static SUMOTime computePickupTime(SUMOTime t, const MSDevice_Taxi *taxi, const Reservation &res, SUMOAbstractRouter< MSEdge, SUMOVehicle > &router)
compute time to pick up the given reservation
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
bool myHasServableReservations
whether the last call to computeDispatch has left servable reservations
Definition MSDispatch.h:194
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::map< std::string, std::vector< Reservation * > > myGroupReservations
Definition MSDispatch.h:213
std::vector< Reservation * > getReservations()
retrieve all reservations
virtual std::vector< const Reservation * > getRunningReservations()
retrieve all reservations that were already dispatched and are still active
SUMOTime myKeepUnreachableResTime
the duration before canceling unreachable reservations
Definition MSDispatch.h:211
static double computeDetourTime(SUMOTime t, SUMOTime viaTime, const MSDevice_Taxi *taxi, const MSEdge *from, double fromPos, const MSEdge *via, double viaPos, const MSEdge *to, double toPos, SUMOAbstractRouter< MSEdge, SUMOVehicle > &router, double &timeDirect)
compute directTime and detourTime
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
int myReservationCount
Definition MSDispatch.h:208
virtual void fulfilledReservation(const Reservation *res)
erase reservation from storage
MSDispatch(const Parameterised::Map &params)
Constructor;.
std::map< std::string, std::map< const Reservation *, MSDevice_Taxi * > > myRunningReservations
Definition MSDispatch.h:203
virtual ~MSDispatch()
Destructor.
void servedReservation(const Reservation *res, MSDevice_Taxi *taxi)
A road/street connecting two junctions.
Definition MSEdge.h:77
A lane area vehicles can halt at.
bool isPerson() const
Whether it is a person.
SUMOVehicle & getHolder() const
Returns the vehicle that holds this device.
int getPersonCapacity() const
Get this vehicle type's person capacity.
int getContainerCapacity() const
Get this vehicle type's container capacity.
const std::string & getID() const
Returns the id.
Definition Named.h:74
static OptionsCont & getOptions()
Retrieves the options.
static bool createDeviceByOption(const std::string &optionName, const std::string &rootElement="", const std::string &schemaFile="")
Creates the device using the output definition stored in the named option.
static OutputDevice & getDeviceByOption(const std::string &name)
Returns the device described by the option.
An upper class for objects with additional parameters.
std::map< std::string, std::string > Map
parameters 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...
virtual double recomputeCosts(const std::vector< const E * > &edges, const V *const v, SUMOTime msTime, double *lengthp=nullptr) const
double recomputeCostsPos(const std::vector< const E * > &edges, const V *const v, double fromPos, double toPos, SUMOTime msTime, double *lengthp=nullptr) const
virtual const MSVehicleType & getVehicleType() const =0
Returns the object's "vehicle" type.
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.
std::string id
Definition MSDispatch.h:76
const MSEdge * to
Definition MSDispatch.h:84
std::string getID() const
debug identification
double fromPos
Definition MSDispatch.h:82
const MSEdge * from
Definition MSDispatch.h:81
std::string group
Definition MSDispatch.h:87
ReservationState state
Definition MSDispatch.h:90
std::set< const MSTransportable * > persons
Definition MSDispatch.h:77
double toPos
Definition MSDispatch.h:85