LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDispatch.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.3 % 107 103
Test Date: 2024-11-22 15:46:21 Functions: 92.9 % 14 13

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2007-2024 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              : /****************************************************************************/
      14              : /// @file    MSDispatch.cpp
      15              : /// @author  Jakob Erdmann
      16              : /// @date    16.12.2019
      17              : ///
      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>
      25              : #include <microsim/transportables/MSTransportable.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              : 
      39              : std::string
      40          240 : Reservation::getID() const {
      41          240 :     return toString(persons);
      42              : }
      43              : 
      44              : // ===========================================================================
      45              : // MSDispatch methods
      46              : // ===========================================================================
      47              : 
      48          632 : MSDispatch::MSDispatch(const Parameterised::Map& params) :
      49              :     Parameterised(params),
      50          632 :     myOutput(nullptr),
      51          632 :     myReservationCount(0) {
      52          632 :     const std::string opt = "device.taxi.dispatch-algorithm.output";
      53          632 :     if (OptionsCont::getOptions().isSet(opt)) {
      54          240 :         OutputDevice::createDeviceByOption(opt, "DispatchInfo");
      55          120 :         myOutput = &OutputDevice::getDeviceByOption(opt);
      56              :     }
      57          632 : }
      58              : 
      59          632 : MSDispatch::~MSDispatch() {
      60         1052 :     for (auto item : myGroupReservations) {
      61          778 :         for (Reservation* res : item.second) {
      62          358 :             delete res;
      63              :         }
      64              :     }
      65              :     myGroupReservations.clear();
      66          632 : }
      67              : 
      68              : 
      69              : Reservation*
      70         2370 : MSDispatch::addReservation(MSTransportable* person,
      71              :                            SUMOTime reservationTime,
      72              :                            SUMOTime pickupTime,
      73              :                            SUMOTime earliestPickupTime,
      74              :                            const MSEdge* from, double fromPos,
      75              :                            const MSStoppingPlace* fromStop,
      76              :                            const MSEdge* to, double toPos,
      77              :                            const MSStoppingPlace* toStop,
      78              :                            std::string group,
      79              :                            const std::string& line,
      80              :                            int maxCapacity,
      81              :                            int maxContainerCapacity) {
      82              :     // no new reservation nedded if the person can be added to an existing group
      83         2370 :     if (group == "") {
      84              :         // the default empty group implies, no grouping is wanted (and
      85              :         // transportable ids are unique)
      86         2164 :         group = person->getID();
      87              :     }
      88              :     Reservation* result = nullptr;
      89              :     bool added = false;
      90              :     auto it = myGroupReservations.find(group);
      91         2370 :     if (it != myGroupReservations.end()) {
      92              :         // try to add to existing reservation
      93          141 :         for (Reservation* res : it->second) {
      94              :             if (res->persons.count(person) == 0
      95          129 :                     && res->from == from
      96          129 :                     && res->to == to
      97          129 :                     && res->fromPos == fromPos
      98          129 :                     && res->toPos == toPos) {
      99          129 :                 if (res->persons.size() > 0 && (*res->persons.begin())->isPerson() != person->isPerson()) {
     100            0 :                     WRITE_WARNINGF(TL("Mixing reservations of persons and containers with the same group is not supported for % and %"),
     101              :                                    (*res->persons.begin())->getID(), person->getID());
     102              :                 }
     103          252 :                 if ((person->isPerson() && (int)res->persons.size() >= maxCapacity) ||
     104          141 :                         (!person->isPerson() && (int)res->persons.size() >= maxContainerCapacity)) {
     105              :                     // split group to ensure that at least one taxi is capable of delivering group size.
     106           12 :                     continue;
     107              :                 }
     108              :                 res->persons.insert(person);
     109              :                 result = res;
     110              :                 added = true;
     111          117 :                 break;
     112              :             }
     113              :         }
     114              :     }
     115         2370 :     if (!added) {
     116         2253 :         Reservation* newRes = new Reservation(toString(myReservationCount++), {person}, reservationTime, pickupTime, earliestPickupTime, from, fromPos, fromStop, to, toPos, toStop, group, line);
     117         2253 :         myGroupReservations[group].push_back(newRes);
     118              :         result = newRes;
     119              :     }
     120         2370 :     myHasServableReservations = true;
     121              : #ifdef DEBUG_RESERVATION
     122              :     if (DEBUG_COND2(person)) std::cout << SIMTIME
     123              :                                            << " addReservation p=" << person->getID()
     124              :                                            << " rT=" << time2string(reservationTime)
     125              :                                            << " pT=" << time2string(pickupTime)
     126              :                                            << " from=" << from->getID() << " fromPos=" << fromPos
     127              :                                            << " to=" << to->getID() << " toPos=" << toPos
     128              :                                            << " group=" << group
     129              :                                            << " added=" << added
     130              :                                            << "\n";
     131              : #endif
     132         2370 :     return result;
     133              : }
     134              : 
     135              : 
     136              : std::string
     137           62 : MSDispatch::removeReservation(MSTransportable* person,
     138              :                               const MSEdge* from, double fromPos,
     139              :                               const MSEdge* to, double toPos,
     140              :                               std::string group) {
     141           62 :     if (group == "") {
     142              :         // the default empty group implies, no grouping is wanted (and
     143              :         // transportable ids are unique)
     144           62 :         group = person->getID();
     145              :     }
     146           62 :     std::string removedID = "";
     147              :     auto it = myGroupReservations.find(group);
     148           62 :     if (it != myGroupReservations.end()) {
     149              :         // try to add to existing reservation
     150           62 :         for (auto itRes = it->second.begin(); itRes != it->second.end(); itRes++) {
     151           62 :             Reservation* res = *itRes;
     152              :             if (res->persons.count(person) != 0
     153           62 :                     && res->from == from
     154           62 :                     && res->to == to
     155           62 :                     && res->fromPos == fromPos
     156           62 :                     && res->toPos == toPos) {
     157              :                 res->persons.erase(person);
     158           62 :                 if (res->persons.empty()) {
     159           62 :                     removedID = res->id;
     160           62 :                     fulfilledReservation(res);
     161           62 :                     it->second.erase(itRes);
     162              :                 }
     163              :                 break;
     164              :             }
     165              :         }
     166              :     }
     167              : #ifdef DEBUG_RESERVATION
     168              :     if (DEBUG_COND2(person)) std::cout << SIMTIME
     169              :                                            << " removeReservation p=" << person->getID()
     170              :                                            << " from=" << from->getID() << " fromPos=" << fromPos
     171              :                                            << " to=" << to->getID() << " toPos=" << toPos
     172              :                                            << " group=" << group
     173              :                                            << " removedID=" << removedID
     174              :                                            << "\n";
     175              : #endif
     176           62 :     return removedID;
     177              : }
     178              : 
     179              : 
     180              : Reservation*
     181          150 : MSDispatch::updateReservationFromPos(MSTransportable* person,
     182              :                                      const MSEdge* from, double fromPos,
     183              :                                      const MSEdge* to, double toPos,
     184              :                                      std::string group, double newFromPos) {
     185          150 :     if (group == "") {
     186              :         // the default empty group implies, no grouping is wanted (and
     187              :         // transportable ids are unique)
     188              :         group = person->getID();
     189              :     }
     190              :     Reservation* result = nullptr;
     191          150 :     std::string updatedID = "";
     192              :     auto it = myGroupReservations.find(group);
     193          150 :     if (it != myGroupReservations.end()) {
     194           66 :         for (auto itRes = it->second.begin(); itRes != it->second.end(); itRes++) {
     195           66 :             Reservation* res = *itRes;
     196              :             // TODO: if there is already a reservation with the newFromPos, add to this reservation
     197              :             // TODO: if there are other persons in this reservation, create a new reservation for the updated one
     198              :             if (res->persons.count(person) != 0
     199           66 :                     && res->from == from
     200           66 :                     && res->to == to
     201           66 :                     && res->fromPos == fromPos
     202           66 :                     && res->toPos == toPos) {
     203              :                 // update fromPos
     204           66 :                 res->fromPos = newFromPos;
     205              :                 result = res;
     206           66 :                 updatedID = res->id;
     207              :                 break;
     208              :             }
     209              :         }
     210              :     }
     211              : #ifdef DEBUG_RESERVATION
     212              :     if (DEBUG_COND2(person)) std::cout << SIMTIME
     213              :                                            << " updateReservationFromPos p=" << person->getID()
     214              :                                            << " from=" << from->getID() << " fromPos=" << fromPos
     215              :                                            << " to=" << to->getID() << " toPos=" << toPos
     216              :                                            << " group=" << group
     217              :                                            << " newFromPos=" << newFromPos
     218              :                                            << " updatedID=" << updatedID
     219              :                                            << "\n";
     220              : #endif
     221          150 :     return result;
     222              : }
     223              : 
     224              : 
     225              : std::vector<Reservation*>
     226         9609 : MSDispatch::getReservations() {
     227              :     std::vector<Reservation*> reservations;
     228        27839 :     for (const auto& it : myGroupReservations) {
     229        18230 :         reservations.insert(reservations.end(), it.second.begin(), it.second.end());
     230              :     }
     231         9609 :     return reservations;
     232            0 : }
     233              : 
     234              : 
     235              : std::vector<const Reservation*>
     236         2351 : MSDispatch::getRunningReservations() {
     237         2351 :     return std::vector<const Reservation*>(myRunningReservations.begin(), myRunningReservations.end());
     238              : }
     239              : 
     240              : 
     241              : void
     242         1962 : MSDispatch::servedReservation(const Reservation* res) {
     243              :     if (myRunningReservations.count(res)) {
     244              :         return; // was redispatch
     245              :     }
     246         1838 :     auto it = myGroupReservations.find(res->group);
     247         1838 :     if (it == myGroupReservations.end()) {
     248            0 :         throw ProcessError(TL("Inconsistent group reservations."));
     249              :     }
     250         1838 :     auto it2 = std::find(it->second.begin(), it->second.end(), res);
     251         1838 :     if (it2 == it->second.end()) {
     252            0 :         throw ProcessError(TL("Inconsistent group reservations (2)."));
     253              :     }
     254              :     myRunningReservations.insert(*it2);
     255         1838 :     const_cast<Reservation*>(*it2)->state = Reservation::ASSIGNED;
     256         1838 :     it->second.erase(it2);
     257         1838 :     if (it->second.empty()) {
     258              :         myGroupReservations.erase(it);
     259              :     }
     260              : }
     261              : 
     262              : 
     263              : void
     264         1877 : MSDispatch::fulfilledReservation(const Reservation* res) {
     265              :     myRunningReservations.erase(res);
     266         1877 :     delete res;
     267         1877 : }
     268              : 
     269              : 
     270              : SUMOTime
     271         1651 : MSDispatch::computePickupTime(SUMOTime t, const MSDevice_Taxi* taxi, const Reservation& res, SUMOAbstractRouter<MSEdge, SUMOVehicle>& router) {
     272              :     ConstMSEdgeVector edges;
     273         1651 :     router.compute(taxi->getHolder().getEdge(), taxi->getHolder().getPositionOnLane() - NUMERICAL_EPS,
     274         1651 :                    res.from, res.fromPos, &taxi->getHolder(), t, edges, true);
     275         3302 :     return TIME2STEPS(router.recomputeCosts(edges, &taxi->getHolder(), t));
     276         1651 : }
     277              : 
     278              : 
     279              : double
     280          398 : MSDispatch::computeDetourTime(SUMOTime t, SUMOTime viaTime, const MSDevice_Taxi* taxi,
     281              :                               const MSEdge* from, double fromPos,
     282              :                               const MSEdge* via, double viaPos,
     283              :                               const MSEdge* to, double toPos,
     284              :                               SUMOAbstractRouter<MSEdge, SUMOVehicle>& router,
     285              :                               double& timeDirect) {
     286              :     ConstMSEdgeVector edges;
     287          398 :     if (timeDirect < 0) {
     288          342 :         router.compute(from, fromPos, to, toPos, &taxi->getHolder(), t, edges, true);
     289          342 :         timeDirect = router.recomputeCostsPos(edges, &taxi->getHolder(), fromPos, toPos, t);
     290              :         edges.clear();
     291              :     }
     292              : 
     293          398 :     router.compute(from, fromPos, via, viaPos, &taxi->getHolder(), t, edges, true);
     294          398 :     const double start = STEPS2TIME(t);
     295          398 :     const double leg1 = router.recomputeCostsPos(edges, &taxi->getHolder(), fromPos, viaPos, t);
     296              : #ifdef DEBUG_DETOUR
     297              :     std::cout << "        leg1=" << toString(edges) << " startPos=" << fromPos << " toPos=" << viaPos << " time=" << leg1 << "\n";
     298              : #endif
     299          398 :     const double wait = MAX2(0.0, STEPS2TIME(viaTime) - (start + leg1));
     300              :     edges.clear();
     301          398 :     const SUMOTime timeContinue = TIME2STEPS(start + leg1 + wait);
     302          398 :     router.compute(via, viaPos, to, toPos, &taxi->getHolder(), timeContinue, edges, true);
     303          398 :     const double leg2 = router.recomputeCostsPos(edges, &taxi->getHolder(), viaPos, toPos, timeContinue);
     304          398 :     const double timeDetour = leg1 + wait + leg2;
     305              : #ifdef DEBUG_DETOUR
     306              :     std::cout << "        leg2=" << toString(edges) << " startPos=" << viaPos << " toPos=" << toPos << " time=" << leg2 << "\n";
     307              :     std::cout << "    t=" << STEPS2TIME(t) << " vt=" << STEPS2TIME(viaTime)
     308              :               << " from=" << from->getID() << " to=" << to->getID() << " via=" << via->getID()
     309              :               << " direct=" << timeDirect << " detour=" << timeDetour << " wait=" << wait << "\n";
     310              : #endif
     311          398 :     return timeDetour;
     312          398 : }
     313              : 
     314              : 
     315              : int
     316         2046 : MSDispatch::remainingCapacity(const MSDevice_Taxi* taxi, const Reservation* res) {
     317              :     assert(res->persons.size() > 0);
     318         2046 :     return ((*res->persons.begin())->isPerson()
     319         2046 :             ? taxi->getHolder().getVehicleType().getPersonCapacity()
     320          192 :             : taxi->getHolder().getVehicleType().getContainerCapacity()) - (int)res->persons.size();
     321              : }
     322              : 
     323              : 
     324              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1