LCOV - code coverage report
Current view: top level - src/router - RONet.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.9 % 451 410
Test Date: 2024-12-21 15:45:41 Functions: 100.0 % 42 42

            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    RONet.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @date    Sept 2002
      19              : ///
      20              : // The router's network representation
      21              : /****************************************************************************/
      22              : #include <config.h>
      23              : 
      24              : #include <algorithm>
      25              : #include <utils/router/RouteCostCalculator.h>
      26              : #include <utils/vehicle/SUMOVTypeParameter.h>
      27              : #include <utils/router/SUMOAbstractRouter.h>
      28              : #include <utils/options/OptionsCont.h>
      29              : #include <utils/common/UtilExceptions.h>
      30              : #include <utils/common/ToString.h>
      31              : #include <utils/common/StringUtils.h>
      32              : #include <utils/common/RandHelper.h>
      33              : #include <utils/common/SUMOVehicleClass.h>
      34              : #include <utils/iodevices/OutputDevice.h>
      35              : #include "ROEdge.h"
      36              : #include "ROLane.h"
      37              : #include "RONode.h"
      38              : #include "ROPerson.h"
      39              : #include "RORoute.h"
      40              : #include "RORouteDef.h"
      41              : #include "ROVehicle.h"
      42              : #include "ROAbstractEdgeBuilder.h"
      43              : #include "RONet.h"
      44              : 
      45              : 
      46              : // ===========================================================================
      47              : // static member definitions
      48              : // ===========================================================================
      49              : RONet* RONet::myInstance = nullptr;
      50              : 
      51              : 
      52              : // ===========================================================================
      53              : // method definitions
      54              : // ===========================================================================
      55              : RONet*
      56      2810643 : RONet::getInstance(void) {
      57      2810643 :     if (myInstance != nullptr) {
      58      2810643 :         return myInstance;
      59              :     }
      60            0 :     throw ProcessError(TL("A network was not yet constructed."));
      61              : }
      62              : 
      63              : 
      64        10033 : RONet::RONet() :
      65        10033 :     myVehicleTypes(), myDefaultVTypeMayBeDeleted(true),
      66        10033 :     myDefaultPedTypeMayBeDeleted(true),
      67        10033 :     myDefaultBikeTypeMayBeDeleted(true),
      68        10033 :     myDefaultTaxiTypeMayBeDeleted(true),
      69        10033 :     myDefaultRailTypeMayBeDeleted(true),
      70        10033 :     myHaveActiveFlows(true),
      71        10033 :     myRoutesOutput(nullptr), myRouteAlternativesOutput(nullptr), myTypesOutput(nullptr),
      72        10033 :     myReadRouteNo(0), myDiscardedRouteNo(0), myWrittenRouteNo(0),
      73        10033 :     myHavePermissions(false),
      74        10033 :     myNumInternalEdges(0),
      75        10033 :     myErrorHandler(OptionsCont::getOptions().exists("ignore-errors")
      76        19620 :                    && OptionsCont::getOptions().getBool("ignore-errors") ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
      77        10033 :     myKeepVTypeDist(OptionsCont::getOptions().exists("keep-vtype-distributions")
      78        19620 :                     && OptionsCont::getOptions().getBool("keep-vtype-distributions")),
      79        10033 :     myDoPTRouting(!OptionsCont::getOptions().exists("ptline-routing")
      80        19167 :                   || OptionsCont::getOptions().getBool("ptline-routing")),
      81        20066 :     myHasBidiEdges(false) {
      82        10033 :     if (myInstance != nullptr) {
      83            0 :         throw ProcessError(TL("A network was already constructed."));
      84              :     }
      85        10033 :     SUMOVTypeParameter* type = new SUMOVTypeParameter(DEFAULT_VTYPE_ID, SVC_PASSENGER);
      86        10033 :     type->onlyReferenced = true;
      87        10033 :     myVehicleTypes.add(type->id, type);
      88              : 
      89        10033 :     SUMOVTypeParameter* defPedType = new SUMOVTypeParameter(DEFAULT_PEDTYPE_ID, SVC_PEDESTRIAN);
      90        10033 :     defPedType->onlyReferenced = true;
      91        10033 :     defPedType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
      92        10033 :     myVehicleTypes.add(defPedType->id, defPedType);
      93              : 
      94        10033 :     SUMOVTypeParameter* defBikeType = new SUMOVTypeParameter(DEFAULT_BIKETYPE_ID, SVC_BICYCLE);
      95        10033 :     defBikeType->onlyReferenced = true;
      96        10033 :     defBikeType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
      97        10033 :     myVehicleTypes.add(defBikeType->id, defBikeType);
      98              : 
      99        10033 :     SUMOVTypeParameter* defTaxiType = new SUMOVTypeParameter(DEFAULT_TAXITYPE_ID, SVC_TAXI);
     100        10033 :     defTaxiType->onlyReferenced = true;
     101        10033 :     defTaxiType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
     102        10033 :     myVehicleTypes.add(defTaxiType->id, defTaxiType);
     103              : 
     104        10033 :     SUMOVTypeParameter* defRailType = new SUMOVTypeParameter(DEFAULT_RAILTYPE_ID, SVC_RAIL);
     105        10033 :     defRailType->onlyReferenced = true;
     106        10033 :     defRailType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
     107        10033 :     myVehicleTypes.add(defRailType->id, defRailType);
     108              : 
     109        10033 :     myInstance = this;
     110        10033 : }
     111              : 
     112              : 
     113        19610 : RONet::~RONet() {
     114        10223 :     for (const auto& routables : myRoutables) {
     115          400 :         for (RORoutable* const r : routables.second) {
     116          200 :             const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
     117              :             // delete routes and the vehicle
     118          200 :             if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
     119          192 :                 if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
     120           76 :                     delete veh->getRouteDefinition();
     121              :                 }
     122              :             }
     123          200 :             delete r;
     124              :         }
     125              :     }
     126        10059 :     for (const RORoutable* const r : myPTVehicles) {
     127           36 :         const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
     128              :         // delete routes and the vehicle
     129           36 :         if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
     130           36 :             if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
     131            8 :                 delete veh->getRouteDefinition();
     132              :             }
     133              :         }
     134           36 :         delete r;
     135              :     }
     136              :     myRoutables.clear();
     137        10067 :     for (const auto& vTypeDist : myVTypeDistDict) {
     138           88 :         delete vTypeDist.second;
     139              :     }
     140        69725 : }
     141              : 
     142              : 
     143              : void
     144            1 : RONet::addRestriction(const std::string& id, const SUMOVehicleClass svc, const double speed) {
     145            1 :     myRestrictions[id][svc] = speed;
     146            1 : }
     147              : 
     148              : 
     149              : const std::map<SUMOVehicleClass, double>*
     150       451154 : RONet::getRestrictions(const std::string& id) const {
     151              :     std::map<std::string, std::map<SUMOVehicleClass, double> >::const_iterator i = myRestrictions.find(id);
     152       451154 :     if (i == myRestrictions.end()) {
     153              :         return nullptr;
     154              :     }
     155           10 :     return &i->second;
     156              : }
     157              : 
     158              : 
     159              : bool
     160       478868 : RONet::addEdge(ROEdge* edge) {
     161       478868 :     if (!myEdges.add(edge->getID(), edge)) {
     162           36 :         WRITE_ERRORF(TL("The edge '%' occurs at least twice."), edge->getID());
     163           12 :         delete edge;
     164           12 :         return false;
     165              :     }
     166       478856 :     if (edge->isInternal()) {
     167       274767 :         myNumInternalEdges += 1;
     168              :     }
     169              :     return true;
     170              : }
     171              : 
     172              : 
     173              : bool
     174        13857 : RONet::addDistrict(const std::string id, ROEdge* source, ROEdge* sink) {
     175              :     if (myDistricts.count(id) > 0) {
     176            0 :         WRITE_ERRORF(TL("The TAZ '%' occurs at least twice."), id);
     177            0 :         delete source;
     178            0 :         delete sink;
     179            0 :         return false;
     180              :     }
     181              :     sink->setFunction(SumoXMLEdgeFunc::CONNECTOR);
     182        13857 :     if (!addEdge(sink)) {
     183              :         return false;
     184              :     }
     185              :     source->setFunction(SumoXMLEdgeFunc::CONNECTOR);
     186        13857 :     if (!addEdge(source)) {
     187              :         return false;
     188              :     }
     189              :     sink->setOtherTazConnector(source);
     190              :     source->setOtherTazConnector(sink);
     191        27714 :     myDistricts[id] = std::make_pair(std::vector<std::string>(), std::vector<std::string>());
     192        13857 :     return true;
     193              : }
     194              : 
     195              : 
     196              : bool
     197        38097 : RONet::addDistrictEdge(const std::string tazID, const std::string edgeID, const bool isSource) {
     198              :     if (myDistricts.count(tazID) == 0) {
     199            0 :         WRITE_ERRORF(TL("The TAZ '%' is unknown."), tazID);
     200            0 :         return false;
     201              :     }
     202              :     ROEdge* edge = getEdge(edgeID);
     203        38097 :     if (edge == nullptr) {
     204            0 :         WRITE_ERRORF(TL("The edge '%' for TAZ '%' is unknown."), edgeID, tazID);
     205            0 :         return false;
     206              :     }
     207        38097 :     if (isSource) {
     208        57144 :         getEdge(tazID + "-source")->addSuccessor(edge);
     209        19048 :         myDistricts[tazID].first.push_back(edgeID);
     210              :     } else {
     211        57147 :         edge->addSuccessor(getEdge(tazID + "-sink"));
     212        19049 :         myDistricts[tazID].second.push_back(edgeID);
     213              :     }
     214              :     return true;
     215              : }
     216              : 
     217              : 
     218              : void
     219           78 : RONet::addJunctionTaz(ROAbstractEdgeBuilder& eb) {
     220         1312 :     for (auto item : myNodes) {
     221              :         const std::string tazID = item.first;
     222            8 :         if (myDistricts.count(tazID) != 0) {
     223           24 :             WRITE_WARNINGF(TL("A TAZ with id '%' already exists. Not building junction TAZ."), tazID);
     224            8 :             continue;
     225              :         }
     226         1226 :         const std::string sourceID = tazID + "-source";
     227         1226 :         const std::string sinkID = tazID + "-sink";
     228              :         // sink must be added before source
     229         1226 :         ROEdge* sink = eb.buildEdge(sinkID, nullptr, nullptr, 0);
     230         1226 :         ROEdge* source = eb.buildEdge(sourceID, nullptr, nullptr, 0);
     231              :         sink->setOtherTazConnector(source);
     232              :         source->setOtherTazConnector(sink);
     233         2452 :         if (!addDistrict(tazID, source, sink)) {
     234              :             continue;
     235              :         }
     236         1226 :         auto& district = myDistricts[tazID];
     237         1226 :         const RONode* junction = item.second;
     238        11084 :         for (const ROEdge* edge : junction->getIncoming()) {
     239         9858 :             if (!edge->isInternal()) {
     240         2778 :                 const_cast<ROEdge*>(edge)->addSuccessor(sink);
     241         2778 :                 district.second.push_back(edge->getID());
     242              :             }
     243              :         }
     244        11084 :         for (const ROEdge* edge : junction->getOutgoing()) {
     245         9858 :             if (!edge->isInternal()) {
     246         2778 :                 source->addSuccessor(const_cast<ROEdge*>(edge));
     247         2778 :                 district.first.push_back(edge->getID());
     248              :             }
     249              :         }
     250              :     }
     251           78 : }
     252              : 
     253              : 
     254              : void
     255         9302 : RONet::setBidiEdges(const std::map<ROEdge*, std::string>& bidiMap) {
     256        15746 :     for (const auto& item : bidiMap) {
     257         6444 :         ROEdge* bidi = myEdges.get(item.second);
     258         6444 :         if (bidi == nullptr) {
     259            0 :             WRITE_ERRORF(TL("The bidi edge '%' is not known."), item.second);
     260              :         }
     261         6444 :         item.first->setBidiEdge(bidi);
     262         6444 :         myHasBidiEdges = true;
     263              :     }
     264         9302 : }
     265              : 
     266              : 
     267              : void
     268       107178 : RONet::addNode(RONode* node) {
     269       107178 :     if (!myNodes.add(node->getID(), node)) {
     270            0 :         WRITE_ERRORF(TL("The node '%' occurs at least twice."), node->getID());
     271            0 :         delete node;
     272              :     }
     273       107178 : }
     274              : 
     275              : 
     276              : void
     277         1590 : RONet::addStoppingPlace(const std::string& id, const SumoXMLTag category, SUMOVehicleParameter::Stop* stop) {
     278         3060 :     if (!myStoppingPlaces[category == SUMO_TAG_TRAIN_STOP ? SUMO_TAG_BUS_STOP : category].add(id, stop)) {
     279           12 :         WRITE_ERRORF(TL("The % '%' occurs at least twice."), toString(category), id);
     280            4 :         delete stop;
     281              :     }
     282         1590 : }
     283              : 
     284              : 
     285              : bool
     286       138781 : RONet::addRouteDef(RORouteDef* def) {
     287       138781 :     return myRoutes.add(def->getID(), def);
     288              : }
     289              : 
     290              : 
     291              : void
     292         6206 : RONet::openOutput(const OptionsCont& options) {
     293        18616 :     if (options.isSet("output-file") && options.getString("output-file") != "") {
     294         6205 :         myRoutesOutput = &OutputDevice::getDevice(options.getString("output-file"));
     295         6199 :         if (myRoutesOutput->isNull()) {
     296            1 :             myRoutesOutput = nullptr;
     297              :         } else {
     298         6198 :             myRoutesOutput->writeHeader<ROEdge>(SUMO_TAG_ROUTES);
     299        18594 :             myRoutesOutput->writeAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance").writeAttr("xsi:noNamespaceSchemaLocation", "http://sumo.dlr.de/xsd/routes_file.xsd");
     300              :         }
     301              :     }
     302        18427 :     if (options.exists("alternatives-output") && options.isSet("alternatives-output")
     303        30221 :             && !(options.exists("write-trips") && options.getBool("write-trips"))) {
     304         5942 :         myRouteAlternativesOutput = &OutputDevice::getDevice(options.getString("alternatives-output"));
     305         5942 :         if (myRouteAlternativesOutput->isNull()) {
     306           34 :             myRouteAlternativesOutput = nullptr;
     307              :         } else {
     308         5908 :             myRouteAlternativesOutput->writeHeader<ROEdge>(SUMO_TAG_ROUTES);
     309        17724 :             myRouteAlternativesOutput->writeAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance").writeAttr("xsi:noNamespaceSchemaLocation", "http://sumo.dlr.de/xsd/routes_file.xsd");
     310              :         }
     311              :     }
     312        12400 :     if (options.isSet("vtype-output")) {
     313           17 :         myTypesOutput = &OutputDevice::getDevice(options.getString("vtype-output"));
     314           17 :         myTypesOutput->writeHeader<ROEdge>(SUMO_TAG_ROUTES);
     315           51 :         myTypesOutput->writeAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance").writeAttr("xsi:noNamespaceSchemaLocation", "http://sumo.dlr.de/xsd/routes_file.xsd");
     316              :     }
     317         6200 : }
     318              : 
     319              : 
     320              : void
     321         5995 : RONet::writeIntermodal(const OptionsCont& options, ROIntermodalRouter& router) const {
     322        11990 :     if (options.exists("intermodal-network-output") && options.isSet("intermodal-network-output")) {
     323           32 :         OutputDevice::createDeviceByOption("intermodal-network-output", "intermodal");
     324           32 :         router.writeNetwork(OutputDevice::getDevice(options.getString("intermodal-network-output")));
     325              :     }
     326        11990 :     if (options.exists("intermodal-weight-output") && options.isSet("intermodal-weight-output")) {
     327           16 :         OutputDevice::createDeviceByOption("intermodal-weight-output", "weights", "meandata_file.xsd");
     328            8 :         OutputDevice& dev = OutputDevice::getDeviceByOption("intermodal-weight-output");
     329            8 :         dev.openTag(SUMO_TAG_INTERVAL);
     330              :         dev.writeAttr(SUMO_ATTR_ID, "intermodalweights");
     331            8 :         dev.writeAttr(SUMO_ATTR_BEGIN, 0);
     332            8 :         dev.writeAttr(SUMO_ATTR_END, SUMOTime_MAX);
     333            8 :         router.writeWeights(dev);
     334           16 :         dev.closeTag();
     335              :     }
     336         5995 : }
     337              : 
     338              : 
     339              : void
     340         6205 : RONet::cleanup() {
     341              :     // end writing
     342         6205 :     if (myRoutesOutput != nullptr) {
     343         6198 :         myRoutesOutput->close();
     344              :     }
     345              :     // only if opened
     346         6205 :     if (myRouteAlternativesOutput != nullptr) {
     347         5908 :         myRouteAlternativesOutput->close();
     348              :     }
     349              :     // only if opened
     350         6205 :     if (myTypesOutput != nullptr) {
     351           17 :         myTypesOutput->close();
     352              :     }
     353              :     RouteCostCalculator<RORoute, ROEdge, ROVehicle>::cleanup();
     354              : #ifdef HAVE_FOX
     355         6205 :     if (myThreadPool.size() > 0) {
     356           30 :         myThreadPool.clear();
     357              :     }
     358              : #endif
     359         6205 : }
     360              : 
     361              : 
     362              : 
     363              : SUMOVTypeParameter*
     364       200832 : RONet::getVehicleTypeSecure(const std::string& id) {
     365              :     // check whether the type was already known
     366              :     SUMOVTypeParameter* type = myVehicleTypes.get(id);
     367       200832 :     if (id == DEFAULT_VTYPE_ID) {
     368       167951 :         myDefaultVTypeMayBeDeleted = false;
     369        32881 :     } else if (id == DEFAULT_PEDTYPE_ID) {
     370         2668 :         myDefaultPedTypeMayBeDeleted = false;
     371        30213 :     } else if (id == DEFAULT_BIKETYPE_ID) {
     372           12 :         myDefaultBikeTypeMayBeDeleted = false;
     373        30201 :     } else if (id == DEFAULT_TAXITYPE_ID) {
     374           48 :         myDefaultTaxiTypeMayBeDeleted = false;
     375        30153 :     } else if (id == DEFAULT_RAILTYPE_ID) {
     376            0 :         myDefaultRailTypeMayBeDeleted = false;
     377              :     }
     378       200832 :     if (type != nullptr) {
     379              :         return type;
     380              :     }
     381              :     VTypeDistDictType::iterator it2 = myVTypeDistDict.find(id);
     382         1478 :     if (it2 != myVTypeDistDict.end()) {
     383         1148 :         return it2->second->get();
     384              :     }
     385          330 :     if (id == "") {
     386              :         // ok, no vehicle type or an unknown type was given within the user input
     387              :         //  return the default type
     388            0 :         myDefaultVTypeMayBeDeleted = false;
     389              :         return myVehicleTypes.get(DEFAULT_VTYPE_ID);
     390              :     }
     391              :     return type;
     392              : }
     393              : 
     394              : 
     395              : bool
     396         1851 : RONet::checkVType(const std::string& id) {
     397         1851 :     if (id == DEFAULT_VTYPE_ID) {
     398           59 :         if (myDefaultVTypeMayBeDeleted) {
     399           59 :             myVehicleTypes.remove(id);
     400           59 :             myDefaultVTypeMayBeDeleted = false;
     401              :         } else {
     402              :             return false;
     403              :         }
     404         1792 :     } else if (id == DEFAULT_PEDTYPE_ID) {
     405            0 :         if (myDefaultPedTypeMayBeDeleted) {
     406            0 :             myVehicleTypes.remove(id);
     407            0 :             myDefaultPedTypeMayBeDeleted = false;
     408              :         } else {
     409              :             return false;
     410              :         }
     411         1792 :     } else if (id == DEFAULT_BIKETYPE_ID) {
     412            0 :         if (myDefaultBikeTypeMayBeDeleted) {
     413            0 :             myVehicleTypes.remove(id);
     414            0 :             myDefaultBikeTypeMayBeDeleted = false;
     415              :         } else {
     416              :             return false;
     417              :         }
     418         1792 :     } else if (id == DEFAULT_TAXITYPE_ID) {
     419            0 :         if (myDefaultTaxiTypeMayBeDeleted) {
     420            0 :             myVehicleTypes.remove(id);
     421            0 :             myDefaultTaxiTypeMayBeDeleted = false;
     422              :         } else {
     423              :             return false;
     424              :         }
     425         1792 :     } else if (id == DEFAULT_RAILTYPE_ID) {
     426            0 :         if (myDefaultRailTypeMayBeDeleted) {
     427            0 :             myVehicleTypes.remove(id);
     428            0 :             myDefaultRailTypeMayBeDeleted = false;
     429              :         } else {
     430              :             return false;
     431              :         }
     432              :     } else {
     433         1792 :         if (myVehicleTypes.get(id) != 0 || myVTypeDistDict.find(id) != myVTypeDistDict.end()) {
     434            0 :             return false;
     435              :         }
     436              :     }
     437              :     return true;
     438              : }
     439              : 
     440              : 
     441              : bool
     442         1807 : RONet::addVehicleType(SUMOVTypeParameter* type) {
     443         1807 :     if (checkVType(type->id)) {
     444         1807 :         myVehicleTypes.add(type->id, type);
     445              :     } else {
     446            0 :         WRITE_ERRORF(TL("The vehicle type '%' occurs at least twice."), type->id);
     447            0 :         delete type;
     448            0 :         return false;
     449              :     }
     450         1807 :     return true;
     451              : }
     452              : 
     453              : 
     454              : bool
     455           44 : RONet::addVTypeDistribution(const std::string& id, RandomDistributor<SUMOVTypeParameter*>* vehTypeDistribution) {
     456           44 :     if (checkVType(id)) {
     457           44 :         myVTypeDistDict[id] = vehTypeDistribution;
     458           44 :         return true;
     459              :     }
     460            0 :     delete vehTypeDistribution;
     461              :     return false;
     462              : }
     463              : 
     464              : 
     465              : bool
     466       152088 : RONet::addVehicle(const std::string& id, ROVehicle* veh) {
     467       152088 :     if (myVehIDs.find(id) == myVehIDs.end()) {
     468       304144 :         myVehIDs[id] = veh->getParameter().departProcedure == DepartDefinition::TRIGGERED ? -1 : veh->getDepartureTime();
     469              : 
     470       152084 :         if (veh->isPublicTransport()) {
     471           44 :             if (!veh->isPartOfFlow()) {
     472           36 :                 myPTVehicles.push_back(veh);
     473              :             }
     474           44 :             if (!myDoPTRouting) {
     475              :                 return true;
     476              :             }
     477              :         }
     478       152048 :         myRoutables[veh->getDepart()].push_back(veh);
     479       152048 :         return true;
     480              :     }
     481           12 :     WRITE_ERRORF(TL("Another vehicle with the id '%' exists."), id);
     482            4 :     delete veh;
     483              :     return false;
     484              : }
     485              : 
     486              : 
     487              : bool
     488          232 : RONet::knowsVehicle(const std::string& id) const {
     489          232 :     return myVehIDs.find(id) != myVehIDs.end();
     490              : }
     491              : 
     492              : SUMOTime
     493           20 : RONet::getDeparture(const std::string& vehID) const {
     494              :     auto it = myVehIDs.find(vehID);
     495           20 :     if (it != myVehIDs.end()) {
     496           20 :         return it->second;
     497              :     } else {
     498            0 :         throw ProcessError(TLF("Requesting departure time for unknown vehicle '%'", vehID));
     499              :     }
     500              : }
     501              : 
     502              : 
     503              : bool
     504         3430 : RONet::addFlow(SUMOVehicleParameter* flow, const bool randomize) {
     505         3430 :     if (randomize && flow->repetitionOffset >= 0) {
     506           10 :         myDepartures[flow->id].reserve(flow->repetitionNumber);
     507          110 :         for (int i = 0; i < flow->repetitionNumber; ++i) {
     508          100 :             myDepartures[flow->id].push_back(flow->depart + RandHelper::rand(flow->repetitionNumber * flow->repetitionOffset));
     509              :         }
     510           10 :         std::sort(myDepartures[flow->id].begin(), myDepartures[flow->id].end());
     511           10 :         std::reverse(myDepartures[flow->id].begin(), myDepartures[flow->id].end());
     512              :     }
     513         3430 :     const bool added = myFlows.add(flow->id, flow);
     514         3430 :     if (added) {
     515         3426 :         myHaveActiveFlows = true;
     516              :     }
     517         3430 :     return added;
     518              : }
     519              : 
     520              : 
     521              : bool
     522         1703 : RONet::addPerson(ROPerson* person) {
     523              :     if (myPersonIDs.count(person->getID()) == 0) {
     524              :         myPersonIDs.insert(person->getID());
     525         1703 :         myRoutables[person->getDepart()].push_back(person);
     526         1703 :         return true;
     527              :     }
     528            0 :     WRITE_ERRORF(TL("Another person with the id '%' exists."), person->getID());
     529            0 :     return false;
     530              : }
     531              : 
     532              : 
     533              : void
     534           56 : RONet::addContainer(const SUMOTime depart, const std::string desc) {
     535           56 :     myContainers.insert(std::pair<const SUMOTime, const std::string>(depart, desc));
     536           56 : }
     537              : 
     538              : 
     539              : void
     540        18575 : RONet::checkFlows(SUMOTime time, MsgHandler* errorHandler) {
     541        18575 :     myHaveActiveFlows = false;
     542        59197 :     for (const auto& i : myFlows) {
     543        40622 :         SUMOVehicleParameter* const pars = i.second;
     544        40622 :         if (pars->line != "" && !myDoPTRouting) {
     545          455 :             continue;
     546              :         }
     547        40167 :         if (pars->repetitionProbability > 0) {
     548          108 :             if (pars->repetitionEnd > pars->depart && pars->repetitionsDone < pars->repetitionNumber) {
     549           96 :                 myHaveActiveFlows = true;
     550              :             }
     551              :             const SUMOTime origDepart = pars->depart;
     552         1020 :             while (pars->depart < time && pars->repetitionsDone < pars->repetitionNumber) {
     553          928 :                 if (pars->repetitionEnd <= pars->depart) {
     554              :                     break;
     555              :                 }
     556              :                 // only call rand if all other conditions are met
     557          912 :                 if (RandHelper::rand() < (pars->repetitionProbability * TS)) {
     558          168 :                     SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
     559          336 :                     newPars->id = pars->id + "." + toString(pars->repetitionsDone);
     560          168 :                     newPars->depart = pars->depart;
     561          168 :                     for (std::vector<SUMOVehicleParameter::Stop>::iterator stop = newPars->stops.begin(); stop != newPars->stops.end(); ++stop) {
     562            0 :                         if (stop->until >= 0) {
     563            0 :                             stop->until += pars->depart - origDepart;
     564              :                         }
     565              :                     }
     566          168 :                     pars->repetitionsDone++;
     567              :                     // try to build the vehicle
     568          168 :                     const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
     569          168 :                     if (type == nullptr) {
     570           32 :                         type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
     571          136 :                     } else if (!myKeepVTypeDist) {
     572              :                         // fix the type id in case we used a distribution
     573          136 :                         newPars->vtypeid = type->id;
     574              :                     }
     575          168 :                     const SUMOTime stopOffset = pars->routeid[0] == '!' ? pars->depart - origDepart : pars->depart;
     576          336 :                     RORouteDef* route = getRouteDef(pars->routeid)->copy("!" + newPars->id, stopOffset);
     577          168 :                     ROVehicle* veh = new ROVehicle(*newPars, route, type, this, errorHandler);
     578          168 :                     addVehicle(newPars->id, veh);
     579          168 :                     delete newPars;
     580              :                 }
     581          912 :                 pars->depart += DELTA_T;
     582              :             }
     583              :         } else {
     584        40059 :             SUMOTime depart = static_cast<SUMOTime>(pars->depart + pars->repetitionTotalOffset);
     585        62652 :             while (pars->repetitionsDone < pars->repetitionNumber && pars->repetitionEnd >= depart) {
     586        33267 :                 myHaveActiveFlows = true;
     587        33267 :                 depart = static_cast<SUMOTime>(pars->depart + pars->repetitionTotalOffset);
     588        33267 :                 if (myDepartures.find(pars->id) != myDepartures.end()) {
     589          110 :                     depart = myDepartures[pars->id].back();
     590              :                 }
     591        33267 :                 if (depart >= time + DELTA_T) {
     592              :                     break;
     593              :                 }
     594        22593 :                 if (myDepartures.find(pars->id) != myDepartures.end()) {
     595          100 :                     myDepartures[pars->id].pop_back();
     596              :                 }
     597        22593 :                 SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
     598        45186 :                 newPars->id = pars->id + "." + toString(pars->repetitionsDone);
     599        22593 :                 newPars->depart = depart;
     600        25785 :                 for (std::vector<SUMOVehicleParameter::Stop>::iterator stop = newPars->stops.begin(); stop != newPars->stops.end(); ++stop) {
     601         3192 :                     if (stop->until >= 0) {
     602            0 :                         stop->until += depart - pars->depart;
     603              :                     }
     604              :                 }
     605        22593 :                 pars->incrementFlow(1);
     606              :                 // try to build the vehicle
     607        22593 :                 const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
     608        22593 :                 if (type == nullptr) {
     609           62 :                     type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
     610              :                 } else {
     611              :                     // fix the type id in case we used a distribution
     612        22531 :                     newPars->vtypeid = type->id;
     613              :                 }
     614        22593 :                 const SUMOTime stopOffset = pars->routeid[0] == '!' ? depart - pars->depart : depart;
     615        45186 :                 RORouteDef* route = getRouteDef(pars->routeid)->copy("!" + newPars->id, stopOffset);
     616        22593 :                 ROVehicle* veh = new ROVehicle(*newPars, route, type, this, errorHandler);
     617        22593 :                 addVehicle(newPars->id, veh);
     618        22593 :                 delete newPars;
     619              :             }
     620              :         }
     621              :     }
     622        18575 : }
     623              : 
     624              : 
     625              : void
     626           16 : RONet::createBulkRouteRequests(const RORouterProvider& provider, const SUMOTime time, const bool removeLoops) {
     627              :     std::map<const int, std::vector<RORoutable*> > bulkVehs;
     628           24 :     for (RoutablesMap::const_iterator i = myRoutables.begin(); i != myRoutables.end(); ++i) {
     629           16 :         if (i->first >= time) {
     630              :             break;
     631              :         }
     632          368 :         for (RORoutable* const routable : i->second) {
     633          360 :             const ROEdge* const depEdge = routable->getDepartEdge();
     634          360 :             bulkVehs[depEdge->getNumericalID()].push_back(routable);
     635          360 :             RORoutable* const first = bulkVehs[depEdge->getNumericalID()].front();
     636          360 :             if (first->getMaxSpeed() != routable->getMaxSpeed()) {
     637            6 :                 WRITE_WARNINGF(TL("Bulking different maximum speeds ('%' and '%') may lead to suboptimal routes."), first->getID(), routable->getID());
     638              :             }
     639          360 :             if (first->getVClass() != routable->getVClass()) {
     640            6 :                 WRITE_WARNINGF(TL("Bulking different vehicle classes ('%' and '%') may lead to invalid routes."), first->getID(), routable->getID());
     641              :             }
     642              :         }
     643              :     }
     644              : #ifdef HAVE_FOX
     645              :     int workerIndex = 0;
     646              : #endif
     647           52 :     for (std::map<const int, std::vector<RORoutable*> >::const_iterator i = bulkVehs.begin(); i != bulkVehs.end(); ++i) {
     648              : #ifdef HAVE_FOX
     649           36 :         if (myThreadPool.size() > 0) {
     650              :             bool bulk = true;
     651          132 :             for (RORoutable* const r : i->second) {
     652          120 :                 myThreadPool.add(new RoutingTask(r, removeLoops, myErrorHandler), workerIndex);
     653          120 :                 if (bulk) {
     654           12 :                     myThreadPool.add(new BulkmodeTask(true), workerIndex);
     655              :                     bulk = false;
     656              :                 }
     657              :             }
     658           12 :             myThreadPool.add(new BulkmodeTask(false), workerIndex);
     659           12 :             workerIndex++;
     660           12 :             if (workerIndex == (int)myThreadPool.size()) {
     661              :                 workerIndex = 0;
     662              :             }
     663           12 :             continue;
     664           12 :         }
     665              : #endif
     666          264 :         for (RORoutable* const r : i->second) {
     667          240 :             r->computeRoute(provider, removeLoops, myErrorHandler);
     668          240 :             provider.setBulkMode(true);
     669              :         }
     670           24 :         provider.setBulkMode(false);
     671              :     }
     672           16 : }
     673              : 
     674              : 
     675              : SUMOTime
     676        24894 : RONet::saveAndRemoveRoutesUntil(OptionsCont& options, const RORouterProvider& provider,
     677              :                                 SUMOTime time) {
     678        24894 :     MsgHandler* mh = (options.getBool("ignore-errors") ?
     679        24894 :                       MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance());
     680        24894 :     if (myHaveActiveFlows) {
     681        18575 :         checkFlows(time, mh);
     682              :     }
     683              :     SUMOTime lastTime = -1;
     684        24894 :     const bool removeLoops = options.getBool("remove-loops");
     685              : #ifdef HAVE_FOX
     686        49788 :     const int maxNumThreads = options.getInt("routing-threads");
     687              : #endif
     688        24894 :     if (myRoutables.size() != 0) {
     689        29956 :         if (options.getBool("bulk-routing")) {
     690              : #ifdef HAVE_FOX
     691           24 :             while ((int)myThreadPool.size() < maxNumThreads) {
     692            8 :                 new WorkerThread(myThreadPool, provider);
     693              :             }
     694              : #endif
     695           16 :             createBulkRouteRequests(provider, time, removeLoops);
     696              :         } else {
     697       111038 :             for (RoutablesMap::const_iterator i = myRoutables.begin(); i != myRoutables.end(); ++i) {
     698       104883 :                 if (i->first >= time) {
     699              :                     break;
     700              :                 }
     701       249283 :                 for (RORoutable* const routable : i->second) {
     702              : #ifdef HAVE_FOX
     703              :                     // add task
     704       153207 :                     if (maxNumThreads > 0) {
     705              :                         const int numThreads = (int)myThreadPool.size();
     706          827 :                         if (numThreads == 0) {
     707              :                             // This is the very first routing. Since at least the CHRouter needs initialization
     708              :                             // before it gets cloned, we do not do this in parallel
     709           24 :                             routable->computeRoute(provider, removeLoops, myErrorHandler);
     710           24 :                             new WorkerThread(myThreadPool, provider);
     711              :                         } else {
     712              :                             // add thread if necessary
     713          803 :                             if (numThreads < maxNumThreads && myThreadPool.isFull()) {
     714           18 :                                 new WorkerThread(myThreadPool, provider);
     715              :                             }
     716          803 :                             myThreadPool.add(new RoutingTask(routable, removeLoops, myErrorHandler));
     717              :                         }
     718          827 :                         continue;
     719          827 :                     }
     720              : #endif
     721       152380 :                     routable->computeRoute(provider, removeLoops, myErrorHandler);
     722              :                 }
     723              :             }
     724              :         }
     725              : #ifdef HAVE_FOX
     726        14962 :         myThreadPool.waitAll();
     727              : #endif
     728              :     }
     729        49487 :     const double scale = options.exists("scale-suffix") ? options.getFloat("scale") : 1;
     730              :     // write all vehicles (and additional structures)
     731       121010 :     while (myRoutables.size() != 0 || myContainers.size() != 0) {
     732              :         // get the next vehicle, person or container
     733              :         RoutablesMap::iterator routables = myRoutables.begin();
     734       104939 :         const SUMOTime routableTime = routables == myRoutables.end() ? SUMOTime_MAX : routables->first;
     735              :         ContainerMap::iterator container = myContainers.begin();
     736       104939 :         const SUMOTime containerTime = container == myContainers.end() ? SUMOTime_MAX : container->first;
     737              :         // check whether it shall not yet be computed
     738       104939 :         if (routableTime >= time && containerTime >= time) {
     739              :             lastTime = MIN2(routableTime, containerTime);
     740              :             break;
     741              :         }
     742              :         const SUMOTime minTime = MIN2(routableTime, containerTime);
     743        96132 :         if (routableTime == minTime) {
     744              :             // check whether to print the output
     745        96084 :             if (lastTime != routableTime && lastTime != -1) {
     746              :                 // report writing progress
     747        87443 :                 if (options.getInt("stats-period") >= 0 && ((int)routableTime % options.getInt("stats-period")) == 0) {
     748            0 :                     WRITE_MESSAGE("Read: " + toString(myVehIDs.size()) + ",  Discarded: " + toString(myDiscardedRouteNo) + ",  Written: " + toString(myWrittenRouteNo));
     749              :                 }
     750              :             }
     751              :             lastTime = routableTime;
     752       249635 :             for (const RORoutable* const r : routables->second) {
     753              :                 // ok, check whether it has been routed
     754       153551 :                 if (r->getRoutingSuccess()) {
     755              :                     // write the route
     756       151555 :                     int quota = getScalingQuota(scale, myWrittenRouteNo);
     757       151555 :                     r->write(myRoutesOutput, myRouteAlternativesOutput, myTypesOutput, options, quota);
     758       151555 :                     myWrittenRouteNo++;
     759              :                 } else {
     760         1996 :                     myDiscardedRouteNo++;
     761              :                 }
     762              :                 // we need to keep individual public transport vehicles but not the flows
     763       153551 :                 if (!r->isPublicTransport() || r->isPartOfFlow()) {
     764              :                     // delete routes and the vehicle
     765       153551 :                     const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
     766       153551 :                     if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
     767       151856 :                         if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
     768        24272 :                             delete veh->getRouteDefinition();
     769              :                         }
     770              :                     }
     771       153551 :                     delete r;
     772              :                 }
     773              :             }
     774              :             myRoutables.erase(routables);
     775              :         }
     776        96132 :         if (containerTime == minTime) {
     777           48 :             myRoutesOutput->writePreformattedTag(container->second);
     778           48 :             if (myRouteAlternativesOutput != nullptr) {
     779              :                 myRouteAlternativesOutput->writePreformattedTag(container->second);
     780              :             }
     781              :             myContainers.erase(container);
     782              :         }
     783              :     }
     784        24878 :     return lastTime;
     785              : }
     786              : 
     787              : 
     788              : bool
     789        56921 : RONet::furtherStored() {
     790        56921 :     return myRoutables.size() > 0 || (myFlows.size() > 0 && myHaveActiveFlows) || myContainers.size() > 0;
     791              : }
     792              : 
     793              : 
     794              : int
     795          122 : RONet::getEdgeNumber() const {
     796          122 :     return myEdges.size();
     797              : }
     798              : 
     799              : 
     800              : int
     801            1 : RONet::getInternalEdgeNumber() const {
     802            1 :     return myNumInternalEdges;
     803              : }
     804              : 
     805              : 
     806              : ROEdge*
     807         6299 : RONet::getEdgeForLaneID(const std::string& laneID) const {
     808        12598 :     return getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(laneID));
     809              : }
     810              : 
     811              : 
     812              : ROLane*
     813         1136 : RONet::getLane(const std::string& laneID) const {
     814         1136 :     int laneIndex = SUMOXMLDefinitions::getIndexFromLane(laneID);
     815         1136 :     return getEdgeForLaneID(laneID)->getLanes()[laneIndex];
     816              : }
     817              : 
     818              : 
     819              : void
     820          510 : RONet::adaptIntermodalRouter(ROIntermodalRouter& router) {
     821          510 :     double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
     822          776 :     for (const auto& stopType : myInstance->myStoppingPlaces) {
     823              :         // add access to all stopping places
     824          266 :         const SumoXMLTag element = stopType.first;
     825         1663 :         for (const auto& stop : stopType.second) {
     826         1397 :             router.getNetwork()->addAccess(stop.first, myInstance->getEdgeForLaneID(stop.second->lane),
     827         1397 :                                            stop.second->startPos, stop.second->endPos, 0., element, false, taxiWait);
     828              :             // add access to all public transport stops
     829         1397 :             if (element == SUMO_TAG_BUS_STOP) {
     830         2465 :                 for (const auto& a : stop.second->accessPos) {
     831         1088 :                     router.getNetwork()->addAccess(stop.first, myInstance->getEdgeForLaneID(std::get<0>(a)),
     832              :                                                    std::get<1>(a), std::get<1>(a), std::get<2>(a), SUMO_TAG_BUS_STOP, true, taxiWait);
     833              :                 }
     834              :             }
     835              :         }
     836              :     }
     837              :     // fill the public transport router with pre-parsed public transport lines
     838          981 :     for (const auto& i : myInstance->myFlows) {
     839          471 :         if (i.second->line != "") {
     840          459 :             const RORouteDef* const route = myInstance->getRouteDef(i.second->routeid);
     841              :             const std::vector<SUMOVehicleParameter::Stop>* addStops = nullptr;
     842          918 :             if (route != nullptr && route->getFirstRoute() != nullptr) {
     843              :                 addStops = &route->getFirstRoute()->getStops();
     844              :             }
     845          459 :             router.getNetwork()->addSchedule(*i.second, addStops);
     846              :         }
     847              :     }
     848          546 :     for (const RORoutable* const veh : myInstance->myPTVehicles) {
     849              :         // add single vehicles with line attribute which are not part of a flow
     850              :         // no need to add route stops here, they have been added to the vehicle before
     851           36 :         router.getNetwork()->addSchedule(veh->getParameter());
     852              :     }
     853              :     // add access to transfer from walking to taxi-use
     854          510 :     if ((router.getCarWalkTransfer() & ModeChangeOptions::TAXI_PICKUP_ANYWHERE) != 0) {
     855          728 :         for (const ROEdge* edge : ROEdge::getAllEdges()) {
     856          712 :             if ((edge->getPermissions() & SVC_PEDESTRIAN) != 0 && (edge->getPermissions() & SVC_TAXI) != 0) {
     857          288 :                 router.getNetwork()->addCarAccess(edge, SVC_TAXI, taxiWait);
     858              :             }
     859              :         }
     860              :     }
     861          510 : }
     862              : 
     863              : 
     864              : bool
     865      2805105 : RONet::hasPermissions() const {
     866      2805105 :     return myHavePermissions;
     867              : }
     868              : 
     869              : 
     870              : void
     871       139185 : RONet::setPermissionsFound() {
     872       139185 :     myHavePermissions = true;
     873       139185 : }
     874              : 
     875              : bool
     876           12 : RONet::hasLoadedEffort() const {
     877           38 :     for (const auto& item : myEdges) {
     878           35 :         if (item.second->hasStoredEffort()) {
     879              :             return true;
     880              :         }
     881              :     }
     882              :     return false;
     883              : }
     884              : 
     885              : const std::string
     886         1082 : RONet::getStoppingPlaceName(const std::string& id) const {
     887         1274 :     for (const auto& mapItem : myStoppingPlaces) {
     888              :         SUMOVehicleParameter::Stop* stop = mapItem.second.get(id);
     889         1082 :         if (stop != nullptr) {
     890              :             // see RONetHandler::parseStoppingPlace
     891              :             return stop->busstop;
     892              :         }
     893              :     }
     894            0 :     return "";
     895              : }
     896              : 
     897              : const std::string
     898          982 : RONet::getStoppingPlaceElement(const std::string& id) const {
     899         1126 :     for (const auto& mapItem : myStoppingPlaces) {
     900              :         SUMOVehicleParameter::Stop* stop = mapItem.second.get(id);
     901          982 :         if (stop != nullptr) {
     902              :             // see RONetHandler::parseStoppingPlace
     903              :             return stop->actType;
     904              :         }
     905              :     }
     906            0 :     return toString(SUMO_TAG_BUS_STOP);
     907              : }
     908              : 
     909              : 
     910              : #ifdef HAVE_FOX
     911              : // ---------------------------------------------------------------------------
     912              : // RONet::RoutingTask-methods
     913              : // ---------------------------------------------------------------------------
     914              : void
     915          923 : RONet::RoutingTask::run(MFXWorkerThread* context) {
     916          923 :     myRoutable->computeRoute(*static_cast<WorkerThread*>(context), myRemoveLoops, myErrorHandler);
     917          923 : }
     918              : #endif
     919              : 
     920              : 
     921              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1