LCOV - code coverage report
Current view: top level - src/microsim - MSInsertionControl.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.9 % 208 189
Test Date: 2024-11-22 15:46:21 Functions: 95.7 % 23 22

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-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    MSInsertionControl.cpp
      15              : /// @author  Christian Roessel
      16              : /// @author  Daniel Krajzewicz
      17              : /// @author  Axel Wegener
      18              : /// @author  Michael Behrisch
      19              : /// @author  Jakob Erdmann
      20              : /// @author  Mirko Barthauer
      21              : /// @date    Mon, 12 Mar 2001
      22              : ///
      23              : // Inserts vehicles into the network when their departure time is reached
      24              : /****************************************************************************/
      25              : #include <config.h>
      26              : 
      27              : #include <iostream>
      28              : #include <algorithm>
      29              : #include <cassert>
      30              : #include <iterator>
      31              : #include <utils/router/IntermodalRouter.h>
      32              : #include <microsim/devices/MSDevice_Routing.h>
      33              : #include <microsim/devices/MSRoutingEngine.h>
      34              : #include "MSGlobals.h"
      35              : #include "MSVehicle.h"
      36              : #include "MSVehicleControl.h"
      37              : #include "MSLane.h"
      38              : #include "MSEdge.h"
      39              : #include "MSNet.h"
      40              : #include "MSRouteHandler.h"
      41              : #include "MSInsertionControl.h"
      42              : 
      43              : 
      44              : // ===========================================================================
      45              : // member method definitions
      46              : // ===========================================================================
      47        42995 : MSInsertionControl::MSInsertionControl(MSVehicleControl& vc,
      48              :                                        SUMOTime maxDepartDelay,
      49              :                                        bool eagerInsertionCheck,
      50              :                                        int maxVehicleNumber,
      51        42995 :                                        SUMOTime randomDepartOffset) :
      52        42995 :     myVehicleControl(vc),
      53        42995 :     myMaxDepartDelay(maxDepartDelay),
      54        42995 :     myEagerInsertionCheck(eagerInsertionCheck),
      55        42995 :     myMaxVehicleNumber(maxVehicleNumber),
      56        42995 :     myPendingEmitsUpdateTime(SUMOTime_MIN),
      57        85990 :     myFlowRNG("flow") {
      58        42995 :     myMaxRandomDepartOffset = randomDepartOffset;
      59        42995 :     RandHelper::initRandGlobal(&myFlowRNG);
      60        42995 : }
      61              : 
      62              : 
      63        40024 : MSInsertionControl::~MSInsertionControl() {
      64        42314 :     for (const Flow& f : myFlows) {
      65         2290 :         delete (f.pars);
      66              :     }
      67        80048 : }
      68              : 
      69              : 
      70              : void
      71      4957979 : MSInsertionControl::add(SUMOVehicle* veh) {
      72      4957979 :     myAllVeh.add(veh);
      73      4957979 : }
      74              : 
      75              : 
      76              : bool
      77        18810 : MSInsertionControl::addFlow(SUMOVehicleParameter* const pars, int index) {
      78        18810 :     if (myFlowIDs.count(pars->id) > 0) {
      79           34 :         return false;
      80              :     }
      81              :     const bool loadingFromState = index >= 0;
      82        18776 :     Flow flow{pars, loadingFromState ? index : 0, initScale(pars->vtypeid)};
      83        18776 :     if (!loadingFromState && pars->repetitionProbability < 0 && pars->repetitionOffset < 0) {
      84              :         // init poisson flow (but only the timing)
      85          422 :         flow.pars->incrementFlow(flow.scale, &myFlowRNG);
      86          422 :         flow.pars->repetitionsDone--;
      87              :     }
      88        18776 :     myFlows.emplace_back(flow);
      89        18776 :     myFlowIDs.insert(std::make_pair(pars->id, flow.index));
      90        18776 :     return true;
      91              : }
      92              : 
      93              : 
      94              : double
      95        18776 : MSInsertionControl::initScale(const std::string vtypeid) {
      96        18776 :     MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
      97        18776 :     if (vc.hasVTypeDistribution(vtypeid)) {
      98              :         double result = -1;
      99          796 :         const RandomDistributor<MSVehicleType*>* dist = vc.getVTypeDistribution(vtypeid);
     100         2506 :         for (const MSVehicleType* t : dist->getVals()) {
     101         1710 :             if (result == -1) {
     102          796 :                 result = t->getParameter().scale;
     103          914 :             } else if (result != t->getParameter().scale) {
     104              :                 // unequal scales in distribution
     105              :                 return -1;
     106              :             }
     107              :         }
     108          796 :         return result;
     109              :     } else {
     110              :         // rng is not used since vtypeid is not a distribution
     111        17980 :         return vc.getVType(vtypeid, nullptr, true)->getParameter().scale;
     112              :     }
     113              : }
     114              : 
     115              : 
     116              : void
     117            5 : MSInsertionControl::updateScale(const std::string vtypeid) {
     118            5 :     for (Flow& f : myFlows) {
     119            0 :         if (f.pars->vtypeid == vtypeid) {
     120            0 :             f.scale = initScale(vtypeid);
     121              :         }
     122              :     }
     123            5 : }
     124              : 
     125              : 
     126              : int
     127     91771781 : MSInsertionControl::emitVehicles(SUMOTime time) {
     128              :     // check whether any vehicles shall be emitted within this time step
     129              :     const bool havePreChecked = MSRoutingEngine::isEnabled();
     130     91771781 :     if (myPendingEmits.empty() || (havePreChecked && myEmitCandidates.empty())) {
     131              :         return 0;
     132              :     }
     133              :     int numEmitted = 0;
     134              :     // we use buffering for the refused emits to save time
     135              :     //  for this, we have two lists; one contains previously refused emits, the second
     136              :     //  will be used to append those vehicles that will not be able to depart in this
     137              :     //  time step
     138              :     MSVehicleContainer::VehicleVector refusedEmits;
     139              : 
     140              :     // go through the list of previously refused vehicles, first
     141              :     MSVehicleContainer::VehicleVector::const_iterator veh;
     142   2075364382 :     for (veh = myPendingEmits.begin(); veh != myPendingEmits.end(); veh++) {
     143   2067514980 :         if (havePreChecked && (myEmitCandidates.count(*veh) == 0)) {
     144      5683619 :             refusedEmits.push_back(*veh);
     145              :         } else {
     146   2061831361 :             numEmitted += tryInsert(time, *veh, refusedEmits);
     147              :         }
     148              :     }
     149              :     myEmitCandidates.clear();
     150      7849402 :     myPendingEmits = refusedEmits;
     151              :     return numEmitted;
     152      7849546 : }
     153              : 
     154              : 
     155              : int
     156   2061831361 : MSInsertionControl::tryInsert(SUMOTime time, SUMOVehicle* veh,
     157              :                               MSVehicleContainer::VehicleVector& refusedEmits) {
     158              :     assert(veh->getParameter().depart <= time);
     159   2061831361 :     const MSEdge& edge = *veh->getEdge();
     160   2061831361 :     if (veh->isOnRoad()) {
     161              :         return 1;
     162              :     }
     163       528048 :     if ((myMaxVehicleNumber < 0 || (int)MSNet::getInstance()->getVehicleControl().getRunningVehicleNo() < myMaxVehicleNumber)
     164   2061842126 :             && edge.insertVehicle(*veh, time, false, myEagerInsertionCheck || veh->getParameter().departProcedure == DepartDefinition::SPLIT)) {
     165              :         // Successful insertion
     166              :         return 1;
     167              :     }
     168   2058321770 :     if (myMaxDepartDelay >= 0 && time - veh->getParameter().depart > myMaxDepartDelay) {
     169              :         // remove vehicles waiting too long for departure
     170       731571 :         myVehicleControl.deleteVehicle(veh, true);
     171   2057590199 :     } else if (edge.isVaporizing()) {
     172              :         // remove vehicles if the edge shall be empty
     173        13002 :         myVehicleControl.deleteVehicle(veh, true);
     174   2057577197 :     } else if (myAbortedEmits.count(veh) > 0) {
     175              :         // remove vehicles which shall not be inserted for some reason
     176          498 :         myAbortedEmits.erase(veh);
     177          498 :         myVehicleControl.deleteVehicle(veh, true);
     178   2057576699 :     } else if ((veh->getRouteValidity(false) & (
     179              :                     MSBaseVehicle::ROUTE_START_INVALID_LANE
     180              :                     | MSBaseVehicle::ROUTE_START_INVALID_PERMISSIONS)) != 0) {
     181           46 :         myVehicleControl.deleteVehicle(veh, true);
     182              :     } else {
     183              :         // let the vehicle wait one step, we'll retry then
     184   2057576653 :         refusedEmits.push_back(veh);
     185              :     }
     186              :     edge.setLastFailedInsertionTime(time);
     187   2058321770 :     return 0;
     188              : }
     189              : 
     190              : 
     191              : void
     192     91771940 : MSInsertionControl::checkCandidates(SUMOTime time, const bool preCheck) {
     193     95178705 :     while (myAllVeh.anyWaitingBefore(time)) {
     194      3406765 :         const MSVehicleContainer::VehicleVector& top = myAllVeh.top();
     195      3406765 :         copy(top.begin(), top.end(), back_inserter(myPendingEmits));
     196      3406765 :         myAllVeh.pop();
     197              :     }
     198     91771940 :     if (preCheck) {
     199              :         MSVehicleContainer::VehicleVector::const_iterator veh;
     200    729267360 :         for (veh = myPendingEmits.begin(); veh != myPendingEmits.end(); veh++) {
     201    718866030 :             SUMOVehicle* const v = *veh;
     202    718866030 :             const MSEdge* const edge = v->getEdge();
     203    718866030 :             if (edge->insertVehicle(*v, time, true, myEagerInsertionCheck)) {
     204              :                 myEmitCandidates.insert(v);
     205              :             } else {
     206     38466863 :                 MSDevice_Routing* dev = static_cast<MSDevice_Routing*>(v->getDevice(typeid(MSDevice_Routing)));
     207              :                 if (dev != nullptr) {
     208              :                     dev->skipRouting(time);
     209              :                 }
     210              :             }
     211              :         }
     212              :     }
     213     91771902 : }
     214              : 
     215              : 
     216              : void
     217     91771947 : MSInsertionControl::determineCandidates(SUMOTime time) {
     218     91771947 :     MSVehicleControl& vehControl = MSNet::getInstance()->getVehicleControl();
     219              :     // for equidistant vehicles, up-scaling is done via repetitionOffset
     220    122017725 :     for (std::vector<Flow>::iterator i = myFlows.begin(); i != myFlows.end();) {
     221              :         MSVehicleType* vtype = nullptr;
     222     30245785 :         SUMOVehicleParameter* pars = i->pars;
     223     30245785 :         double typeScale = i->scale;
     224     30245785 :         if (typeScale < 0) {
     225              :             // must sample from distribution to determine scale value
     226            0 :             vtype = vehControl.getVType(pars->vtypeid, MSRouteHandler::getParsingRNG());
     227            0 :             typeScale = vtype->getParameter().scale;
     228              :         }
     229     30245785 :         double scale = vehControl.getScale() * typeScale;
     230     30245785 :         bool tryEmitByProb = pars->repetitionProbability > 0;
     231     34852289 :         while (scale > 0 && ((pars->repetitionProbability < 0
     232     25659956 :                               && pars->repetitionsDone < pars->repetitionNumber * scale
     233     25647254 :                               && pars->depart + pars->repetitionTotalOffset <= time)
     234     30736682 :                              || (tryEmitByProb
     235      8701429 :                                  && pars->depart <= time
     236      8693518 :                                  && pars->repetitionEnd > time
     237              :                                  // only call rand if all other conditions are met
     238      8690152 :                                  && RandHelper::rand(&myFlowRNG) < (pars->repetitionProbability * TS))
     239              :                             )) {
     240              :             tryEmitByProb = false; // only emit one per step
     241      4606511 :             SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
     242      9213022 :             newPars->id = pars->id + "." + toString(i->index);
     243      4606511 :             newPars->depart = pars->repetitionProbability > 0 ? time : pars->depart + pars->repetitionTotalOffset + computeRandomDepartOffset();
     244      4606511 :             pars->incrementFlow(scale, &myFlowRNG);
     245      4606511 :             myFlowIDs[pars->id] = i->index;
     246              :             //std::cout << SIMTIME << " flow=" << pars->id << " done=" << pars->repetitionsDone << " totalOffset=" << STEPS2TIME(pars->repetitionTotalOffset) << "\n";
     247              :             // try to build the vehicle
     248      4606511 :             if (vehControl.getVehicle(newPars->id) == nullptr) {
     249      4606511 :                 ConstMSRoutePtr const route = MSRoute::dictionary(pars->routeid);
     250      4606511 :                 if (vtype == nullptr) {
     251      4606511 :                     vtype = vehControl.getVType(pars->vtypeid, MSRouteHandler::getParsingRNG());
     252              :                 }
     253      4606511 :                 SUMOVehicle* const vehicle = vehControl.buildVehicle(newPars, route, vtype, !MSGlobals::gCheckRoutes);
     254              :                 // for equidistant vehicles, all scaling is done via repetitionOffset (to avoid artefacts, #11441)
     255              :                 // for probabilistic vehicles, we use the quota
     256      4606504 :                 int quota = pars->repetitionProbability < 0 ? 1 : vehControl.getQuota(scale);
     257       490904 :                 if (quota > 0) {
     258      4582738 :                     vehControl.addVehicle(newPars->id, vehicle);
     259      4582738 :                     if (pars->departProcedure == DepartDefinition::GIVEN || pars->departProcedure == DepartDefinition::BEGIN) {
     260      4582714 :                         add(vehicle);
     261              :                     }
     262      4582738 :                     i->index++;
     263      4639317 :                     while (--quota > 0) {
     264        56579 :                         SUMOVehicleParameter* const quotaPars = new SUMOVehicleParameter(*pars);
     265       113158 :                         quotaPars->id = pars->id + "." + toString(i->index);
     266        56579 :                         quotaPars->depart = pars->repetitionProbability > 0 ? time :
     267            0 :                                             pars->depart + pars->repetitionsDone * pars->repetitionTotalOffset + computeRandomDepartOffset();
     268        56586 :                         SUMOVehicle* const quotaVehicle = vehControl.buildVehicle(quotaPars, route, vtype, !MSGlobals::gCheckRoutes);
     269        56579 :                         vehControl.addVehicle(quotaPars->id, quotaVehicle);
     270        56579 :                         if (pars->departProcedure == DepartDefinition::GIVEN || pars->departProcedure == DepartDefinition::BEGIN) {
     271        56579 :                             add(quotaVehicle);
     272              :                         }
     273        56579 :                         pars->repetitionsDone++;
     274        56579 :                         i->index++;
     275              :                     }
     276              :                 } else {
     277        23766 :                     vehControl.deleteVehicle(vehicle, true);
     278              :                 }
     279              :             } else {
     280            0 :                 if (MSGlobals::gStateLoaded) {
     281              :                     /// @note probably obsolete since flows save their state
     282              :                     break;
     283              :                 }
     284            0 :                 throw ProcessError(TLF("Another vehicle with the id '%' exists.", newPars->id));
     285              :             }
     286              :             vtype = nullptr;
     287              :         }
     288     30245778 :         if (time >= pars->repetitionEnd ||
     289     30241216 :                 (pars->repetitionNumber != std::numeric_limits<int>::max()
     290     19578185 :                  && pars->repetitionsDone >= (int)(pars->repetitionNumber * scale + 0.5))) {
     291        16475 :             i = myFlows.erase(i);
     292        16475 :             MSRoute::checkDist(pars->routeid);
     293        16475 :             delete pars;
     294              :         } else {
     295              :             ++i;
     296              :         }
     297              :     }
     298     91771940 :     checkCandidates(time, MSRoutingEngine::isEnabled());
     299     91771902 : }
     300              : 
     301              : 
     302              : int
     303      6359339 : MSInsertionControl::getWaitingVehicleNo() const {
     304      6359339 :     return (int)myPendingEmits.size();
     305              : }
     306              : 
     307              : 
     308              : int
     309     11813459 : MSInsertionControl::getPendingFlowCount() const {
     310     11813459 :     return (int)myFlows.size();
     311              : }
     312              : 
     313              : 
     314              : void
     315          542 : MSInsertionControl::descheduleDeparture(const SUMOVehicle* veh) {
     316          542 :     myAbortedEmits.insert(veh);
     317          542 : }
     318              : 
     319              : void
     320        15085 : MSInsertionControl::retractDescheduleDeparture(const SUMOVehicle* veh) {
     321        15085 :     myAbortedEmits.erase(veh);
     322        15085 : }
     323              : 
     324              : 
     325              : void
     326         2292 : MSInsertionControl::alreadyDeparted(SUMOVehicle* veh) {
     327         2292 :     myPendingEmits.erase(std::remove(myPendingEmits.begin(), myPendingEmits.end(), veh), myPendingEmits.end());
     328         2292 :     myAllVeh.remove(veh);
     329         2292 : }
     330              : 
     331              : 
     332              : void
     333            6 : MSInsertionControl::clearPendingVehicles(const std::string& route) {
     334              :     //clear out the refused vehicle list, deleting the vehicles entirely
     335              :     MSVehicleContainer::VehicleVector::iterator veh;
     336           12 :     for (veh = myPendingEmits.begin(); veh != myPendingEmits.end();) {
     337            6 :         if ((*veh)->getRoute().getID() == route || route == "") {
     338            6 :             myVehicleControl.deleteVehicle(*veh, true);
     339            6 :             veh = myPendingEmits.erase(veh);
     340              :         } else {
     341              :             ++veh;
     342              :         }
     343              :     }
     344            6 : }
     345              : 
     346              : 
     347              : int
     348            0 : MSInsertionControl::getPendingEmits(const MSLane* lane) {
     349            0 :     if (MSNet::getInstance()->getCurrentTimeStep() != myPendingEmitsUpdateTime) {
     350              :         // updated pending emits (only once per time step)
     351              :         myPendingEmitsForLane.clear();
     352            0 :         for (const SUMOVehicle* const veh : myPendingEmits) {
     353            0 :             const MSLane* const vlane = veh->getLane();
     354            0 :             if (vlane != nullptr) {
     355            0 :                 myPendingEmitsForLane[vlane]++;
     356              :             } else {
     357              :                 // no (tentative) departLane was set, increase count for all
     358              :                 // lanes of the depart edge
     359            0 :                 for (const MSLane* const l : veh->getEdge()->getLanes()) {
     360            0 :                     myPendingEmitsForLane[l]++;
     361              :                 }
     362              :             }
     363              :         }
     364            0 :         myPendingEmitsUpdateTime = MSNet::getInstance()->getCurrentTimeStep();
     365              :     }
     366            0 :     return myPendingEmitsForLane[lane];
     367              : }
     368              : 
     369              : 
     370              : void
     371         4247 : MSInsertionControl::adaptIntermodalRouter(MSTransportableRouter& router) const {
     372              :     // fill the public transport router with pre-parsed public transport lines
     373         6132 :     for (const Flow& f : myFlows) {
     374         1885 :         if (f.pars->line != "") {
     375          511 :             ConstMSRoutePtr const route = MSRoute::dictionary(f.pars->routeid);
     376          511 :             router.getNetwork()->addSchedule(*f.pars, route == nullptr ? nullptr : &route->getStops());
     377              :         }
     378              :     }
     379         4247 : }
     380              : 
     381              : 
     382              : void
     383          425 : MSInsertionControl::saveState(OutputDevice& out) {
     384              :     // save flow states
     385          499 :     for (const Flow& flow : myFlows) {
     386           74 :         flow.pars->write(out, OptionsCont::getOptions(), SUMO_TAG_FLOWSTATE,
     387           74 :                          flow.pars->vtypeid == DEFAULT_VTYPE_ID ? "" : flow.pars->vtypeid);
     388           74 :         if (flow.pars->repetitionEnd == SUMOTime_MAX) {
     389            0 :             out.writeAttr(SUMO_ATTR_NUMBER, flow.pars->repetitionNumber);
     390              :         }
     391           74 :         if (flow.pars->repetitionProbability > 0) {
     392           14 :             out.writeAttr(SUMO_ATTR_PROB, flow.pars->repetitionProbability);
     393           60 :         } else if (flow.pars->poissonRate > 0) {
     394            1 :             out.writeAttr(SUMO_ATTR_PERIOD, "exp(" + toString(flow.pars->poissonRate) + ")");
     395            2 :             out.writeAttr(SUMO_ATTR_NEXT, STEPS2TIME(flow.pars->repetitionTotalOffset));
     396              :         } else {
     397           59 :             out.writeAttr(SUMO_ATTR_PERIOD, STEPS2TIME(flow.pars->repetitionOffset));
     398          118 :             out.writeAttr(SUMO_ATTR_NEXT, STEPS2TIME(flow.pars->repetitionTotalOffset));
     399              :         }
     400           74 :         if (flow.pars->repetitionEnd != SUMOTime_MAX) {
     401          148 :             out.writeAttr(SUMO_ATTR_END, STEPS2TIME(flow.pars->repetitionEnd));
     402              :         };
     403           74 :         out.writeAttr(SUMO_ATTR_ROUTE, flow.pars->routeid);
     404           74 :         out.writeAttr(SUMO_ATTR_DONE, flow.pars->repetitionsDone);
     405           74 :         out.writeAttr(SUMO_ATTR_INDEX, flow.index);
     406           74 :         if (flow.pars->wasSet(VEHPARS_FORCE_REROUTE)) {
     407           38 :             out.writeAttr(SUMO_ATTR_REROUTE, true);
     408              :         }
     409          148 :         out.closeTag();
     410              :     }
     411          425 : }
     412              : 
     413              : 
     414              : void
     415          177 : MSInsertionControl::clearState() {
     416          177 :     for (const Flow& f : myFlows) {
     417            0 :         delete (f.pars);
     418              :     }
     419              :     myFlows.clear();
     420              :     myFlowIDs.clear();
     421          177 :     myAllVeh.clearState();
     422              :     myPendingEmits.clear();
     423              :     myEmitCandidates.clear();
     424          177 :     myAbortedEmits.clear();
     425              :     // myPendingEmitsForLane must not be cleared since it updates itself on the next call
     426          177 : }
     427              : 
     428              : 
     429              : SUMOTime
     430      4911694 : MSInsertionControl::computeRandomDepartOffset() const {
     431      4911694 :     if (myMaxRandomDepartOffset > 0) {
     432              :         // round to the closest usable simulation step
     433           90 :         return DELTA_T * ((RandHelper::rand(myMaxRandomDepartOffset, MSRouteHandler::getParsingRNG()) + DELTA_T / 2) / DELTA_T);
     434              :     }
     435              :     return 0;
     436              : }
     437              : 
     438              : const SUMOVehicleParameter*
     439           32 : MSInsertionControl::getFlowPars(const std::string& id) const {
     440              :     if (hasFlow(id)) {
     441           32 :         for (const Flow& f : myFlows) {
     442           32 :             if (f.pars->id == id) {
     443              :                 return f.pars;
     444              :             }
     445              :         }
     446              :     }
     447              :     return nullptr;
     448              : }
     449              : 
     450              : SUMOVehicle*
     451          568 : MSInsertionControl::getLastFlowVehicle(const std::string& id) const {
     452              :     const auto it = myFlowIDs.find(id);
     453          568 :     if (it != myFlowIDs.end()) {
     454         1136 :         const std::string vehID = id + "." + toString(it->second);
     455          568 :         return MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
     456              :     }
     457              :     return nullptr;
     458              : }
     459              : 
     460              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1