Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
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 2833618 : RONet::getInstance(void) {
57 2833618 : if (myInstance != nullptr) {
58 2833618 : return myInstance;
59 : }
60 0 : throw ProcessError(TL("A network was not yet constructed."));
61 : }
62 :
63 :
64 10065 : RONet::RONet() :
65 10065 : myVehicleTypes(), myDefaultVTypeMayBeDeleted(true),
66 10065 : myDefaultPedTypeMayBeDeleted(true),
67 10065 : myDefaultBikeTypeMayBeDeleted(true),
68 10065 : myDefaultTaxiTypeMayBeDeleted(true),
69 10065 : myDefaultRailTypeMayBeDeleted(true),
70 10065 : myHaveActiveFlows(true),
71 10065 : myRoutesOutput(nullptr), myRouteAlternativesOutput(nullptr), myTypesOutput(nullptr),
72 10065 : myReadRouteNo(0), myDiscardedRouteNo(0), myWrittenRouteNo(0),
73 10065 : myHavePermissions(false),
74 10065 : myNumInternalEdges(0),
75 10065 : myErrorHandler(OptionsCont::getOptions().exists("ignore-errors")
76 19684 : && OptionsCont::getOptions().getBool("ignore-errors") ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
77 10065 : myKeepVTypeDist(OptionsCont::getOptions().exists("keep-vtype-distributions")
78 19684 : && OptionsCont::getOptions().getBool("keep-vtype-distributions")),
79 10065 : myDoPTRouting(!OptionsCont::getOptions().exists("ptline-routing")
80 19224 : || OptionsCont::getOptions().getBool("ptline-routing")),
81 20130 : myHasBidiEdges(false) {
82 10065 : if (myInstance != nullptr) {
83 0 : throw ProcessError(TL("A network was already constructed."));
84 : }
85 10065 : SUMOVTypeParameter* type = new SUMOVTypeParameter(DEFAULT_VTYPE_ID, SVC_PASSENGER);
86 10065 : type->onlyReferenced = true;
87 10065 : myVehicleTypes.add(type->id, type);
88 :
89 10065 : SUMOVTypeParameter* defPedType = new SUMOVTypeParameter(DEFAULT_PEDTYPE_ID, SVC_PEDESTRIAN);
90 10065 : defPedType->onlyReferenced = true;
91 10065 : defPedType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
92 10065 : myVehicleTypes.add(defPedType->id, defPedType);
93 :
94 10065 : SUMOVTypeParameter* defBikeType = new SUMOVTypeParameter(DEFAULT_BIKETYPE_ID, SVC_BICYCLE);
95 10065 : defBikeType->onlyReferenced = true;
96 10065 : defBikeType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
97 10065 : myVehicleTypes.add(defBikeType->id, defBikeType);
98 :
99 10065 : SUMOVTypeParameter* defTaxiType = new SUMOVTypeParameter(DEFAULT_TAXITYPE_ID, SVC_TAXI);
100 10065 : defTaxiType->onlyReferenced = true;
101 10065 : defTaxiType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
102 10065 : myVehicleTypes.add(defTaxiType->id, defTaxiType);
103 :
104 10065 : SUMOVTypeParameter* defRailType = new SUMOVTypeParameter(DEFAULT_RAILTYPE_ID, SVC_RAIL);
105 10065 : defRailType->onlyReferenced = true;
106 10065 : defRailType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
107 10065 : myVehicleTypes.add(defRailType->id, defRailType);
108 :
109 10065 : myInstance = this;
110 10065 : }
111 :
112 :
113 19674 : RONet::~RONet() {
114 10255 : 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 10091 : 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 10099 : for (const auto& vTypeDist : myVTypeDistDict) {
138 88 : delete vTypeDist.second;
139 : }
140 69949 : }
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 451823 : RONet::getRestrictions(const std::string& id) const {
151 : std::map<std::string, std::map<SUMOVehicleClass, double> >::const_iterator i = myRestrictions.find(id);
152 451823 : if (i == myRestrictions.end()) {
153 : return nullptr;
154 : }
155 10 : return &i->second;
156 : }
157 :
158 :
159 : bool
160 479803 : RONet::addEdge(ROEdge* edge) {
161 479803 : 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 479791 : if (edge->isInternal()) {
167 275099 : myNumInternalEdges += 1;
168 : }
169 : return true;
170 : }
171 :
172 :
173 : bool
174 13990 : 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 13990 : if (!addEdge(sink)) {
183 : return false;
184 : }
185 : source->setFunction(SumoXMLEdgeFunc::CONNECTOR);
186 13990 : if (!addEdge(source)) {
187 : return false;
188 : }
189 : sink->setOtherTazConnector(source);
190 : source->setOtherTazConnector(sink);
191 27980 : myDistricts[id] = std::make_pair(std::vector<std::string>(), std::vector<std::string>());
192 13990 : return true;
193 : }
194 :
195 :
196 : bool
197 38211 : 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 38211 : if (edge == nullptr) {
204 0 : WRITE_ERRORF(TL("The edge '%' for TAZ '%' is unknown."), edgeID, tazID);
205 0 : return false;
206 : }
207 38211 : if (isSource) {
208 57315 : getEdge(tazID + "-source")->addSuccessor(edge);
209 19105 : myDistricts[tazID].first.push_back(edgeID);
210 : } else {
211 57318 : edge->addSuccessor(getEdge(tazID + "-sink"));
212 19106 : myDistricts[tazID].second.push_back(edgeID);
213 : }
214 : return true;
215 : }
216 :
217 :
218 : void
219 91 : RONet::addJunctionTaz(ROAbstractEdgeBuilder& eb) {
220 1432 : 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 1333 : const std::string sourceID = tazID + "-source";
227 1333 : const std::string sinkID = tazID + "-sink";
228 : // sink must be added before source
229 1333 : ROEdge* sink = eb.buildEdge(sinkID, nullptr, nullptr, 0);
230 1333 : ROEdge* source = eb.buildEdge(sourceID, nullptr, nullptr, 0);
231 : sink->setOtherTazConnector(source);
232 : source->setOtherTazConnector(sink);
233 2666 : if (!addDistrict(tazID, source, sink)) {
234 : continue;
235 : }
236 1333 : auto& district = myDistricts[tazID];
237 1333 : const RONode* junction = item.second;
238 11290 : for (const ROEdge* edge : junction->getIncoming()) {
239 9957 : if (!edge->isInternal()) {
240 2877 : const_cast<ROEdge*>(edge)->addSuccessor(sink);
241 2877 : district.second.push_back(edge->getID());
242 : }
243 : }
244 11290 : for (const ROEdge* edge : junction->getOutgoing()) {
245 9957 : if (!edge->isInternal()) {
246 2877 : source->addSuccessor(const_cast<ROEdge*>(edge));
247 2877 : district.first.push_back(edge->getID());
248 : }
249 : }
250 : }
251 91 : }
252 :
253 :
254 : void
255 9334 : RONet::setBidiEdges(const std::map<ROEdge*, std::string>& bidiMap) {
256 15624 : for (const auto& item : bidiMap) {
257 6290 : ROEdge* bidi = myEdges.get(item.second);
258 6290 : if (bidi == nullptr) {
259 0 : WRITE_ERRORF(TL("The bidi edge '%' is not known."), item.second);
260 : }
261 6290 : item.first->setBidiEdge(bidi);
262 6290 : myHasBidiEdges = true;
263 : }
264 9334 : }
265 :
266 :
267 : void
268 107483 : RONet::addNode(RONode* node) {
269 107483 : 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 107483 : }
274 :
275 :
276 : void
277 1589 : RONet::addStoppingPlace(const std::string& id, const SumoXMLTag category, SUMOVehicleParameter::Stop* stop) {
278 3058 : 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 1589 : }
283 :
284 :
285 : bool
286 139083 : RONet::addRouteDef(RORouteDef* def) {
287 139083 : return myRoutes.add(def->getID(), def);
288 : }
289 :
290 :
291 : void
292 6238 : RONet::openOutput(const OptionsCont& options) {
293 18712 : if (options.isSet("output-file") && options.getString("output-file") != "") {
294 6237 : myRoutesOutput = &OutputDevice::getDevice(options.getString("output-file"));
295 6231 : if (myRoutesOutput->isNull()) {
296 1 : myRoutesOutput = nullptr;
297 : } else {
298 6230 : myRoutesOutput->writeHeader<ROEdge>(SUMO_TAG_ROUTES);
299 18690 : 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 18516 : if (options.exists("alternatives-output") && options.isSet("alternatives-output")
303 30353 : && !(options.exists("write-trips") && options.getBool("write-trips"))) {
304 5967 : myRouteAlternativesOutput = &OutputDevice::getDevice(options.getString("alternatives-output"));
305 5967 : if (myRouteAlternativesOutput->isNull()) {
306 34 : myRouteAlternativesOutput = nullptr;
307 : } else {
308 5933 : myRouteAlternativesOutput->writeHeader<ROEdge>(SUMO_TAG_ROUTES);
309 17799 : 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 12464 : if (options.isSet("vtype-output")) {
313 18 : myTypesOutput = &OutputDevice::getDevice(options.getString("vtype-output"));
314 18 : myTypesOutput->writeHeader<ROEdge>(SUMO_TAG_ROUTES);
315 54 : myTypesOutput->writeAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance").writeAttr("xsi:noNamespaceSchemaLocation", "http://sumo.dlr.de/xsd/routes_file.xsd");
316 : }
317 6232 : }
318 :
319 :
320 : void
321 6020 : RONet::writeIntermodal(const OptionsCont& options, ROIntermodalRouter& router) const {
322 12040 : 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 12040 : 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 6020 : }
337 :
338 :
339 : void
340 6237 : RONet::cleanup() {
341 : // end writing
342 6237 : if (myRoutesOutput != nullptr) {
343 6230 : myRoutesOutput->close();
344 : }
345 : // only if opened
346 6237 : if (myRouteAlternativesOutput != nullptr) {
347 5933 : myRouteAlternativesOutput->close();
348 : }
349 : // only if opened
350 6237 : if (myTypesOutput != nullptr) {
351 18 : myTypesOutput->close();
352 : }
353 : RouteCostCalculator<RORoute, ROEdge, ROVehicle>::cleanup();
354 : #ifdef HAVE_FOX
355 6237 : if (myThreadPool.size() > 0) {
356 30 : myThreadPool.clear();
357 : }
358 : #endif
359 6237 : }
360 :
361 :
362 :
363 : SUMOVTypeParameter*
364 202015 : RONet::getVehicleTypeSecure(const std::string& id) {
365 : // check whether the type was already known
366 : SUMOVTypeParameter* type = myVehicleTypes.get(id);
367 202015 : if (id == DEFAULT_VTYPE_ID) {
368 167995 : myDefaultVTypeMayBeDeleted = false;
369 34020 : } else if (id == DEFAULT_PEDTYPE_ID) {
370 2668 : myDefaultPedTypeMayBeDeleted = false;
371 31352 : } else if (id == DEFAULT_BIKETYPE_ID) {
372 12 : myDefaultBikeTypeMayBeDeleted = false;
373 31340 : } else if (id == DEFAULT_TAXITYPE_ID) {
374 48 : myDefaultTaxiTypeMayBeDeleted = false;
375 31292 : } else if (id == DEFAULT_RAILTYPE_ID) {
376 0 : myDefaultRailTypeMayBeDeleted = false;
377 : }
378 202015 : 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 1873 : RONet::checkVType(const std::string& id) {
397 1873 : 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 1814 : } 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 1814 : } 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 1814 : } 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 1814 : } 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 1814 : 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 1829 : RONet::addVehicleType(SUMOVTypeParameter* type) {
443 1829 : if (checkVType(type->id)) {
444 1829 : 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 1829 : 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 153065 : RONet::addVehicle(const std::string& id, ROVehicle* veh) {
467 153065 : if (myVehIDs.find(id) == myVehIDs.end()) {
468 306098 : myVehIDs[id] = veh->getParameter().departProcedure == DepartDefinition::TRIGGERED ? -1 : veh->getDepartureTime();
469 :
470 153061 : 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 153025 : myRoutables[veh->getDepart()].push_back(veh);
479 153025 : 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 3522 : RONet::addFlow(SUMOVehicleParameter* flow, const bool randomize) {
505 3522 : 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 3522 : const bool added = myFlows.add(flow->id, flow);
514 3522 : if (added) {
515 3518 : myHaveActiveFlows = true;
516 : }
517 3522 : 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 18719 : RONet::checkFlows(SUMOTime time, MsgHandler* errorHandler) {
541 18719 : myHaveActiveFlows = false;
542 59829 : for (const auto& i : myFlows) {
543 41110 : SUMOVehicleParameter* const pars = i.second;
544 41110 : if (pars->line != "" && !myDoPTRouting) {
545 457 : continue;
546 : }
547 40653 : 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 40545 : SUMOTime depart = static_cast<SUMOTime>(pars->depart + pars->repetitionTotalOffset);
585 63905 : while (pars->repetitionsDone < pars->repetitionNumber && pars->repetitionEnd >= depart) {
586 34262 : myHaveActiveFlows = true;
587 34262 : depart = static_cast<SUMOTime>(pars->depart + pars->repetitionTotalOffset);
588 34262 : if (myDepartures.find(pars->id) != myDepartures.end()) {
589 110 : depart = myDepartures[pars->id].back();
590 : }
591 34262 : if (depart >= time + DELTA_T) {
592 : break;
593 : }
594 23360 : if (myDepartures.find(pars->id) != myDepartures.end()) {
595 100 : myDepartures[pars->id].pop_back();
596 : }
597 23360 : SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
598 46720 : newPars->id = pars->id + "." + toString(pars->repetitionsDone);
599 23360 : newPars->depart = depart;
600 26552 : 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 23360 : pars->incrementFlow(1);
606 : // try to build the vehicle
607 23360 : const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
608 23360 : if (type == nullptr) {
609 62 : type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
610 : } else {
611 : // fix the type id in case we used a distribution
612 23298 : newPars->vtypeid = type->id;
613 : }
614 23360 : const SUMOTime stopOffset = pars->routeid[0] == '!' ? depart - pars->depart : depart;
615 46720 : RORouteDef* route = getRouteDef(pars->routeid)->copy("!" + newPars->id, stopOffset);
616 23360 : ROVehicle* veh = new ROVehicle(*newPars, route, type, this, errorHandler);
617 23360 : addVehicle(newPars->id, veh);
618 23360 : delete newPars;
619 : }
620 : }
621 : }
622 18719 : }
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 25059 : RONet::saveAndRemoveRoutesUntil(OptionsCont& options, const RORouterProvider& provider,
677 : SUMOTime time) {
678 25059 : MsgHandler* mh = (options.getBool("ignore-errors") ?
679 25059 : MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance());
680 25059 : if (myHaveActiveFlows) {
681 18719 : checkFlows(time, mh);
682 : }
683 : SUMOTime lastTime = -1;
684 25059 : const bool removeLoops = options.getBool("remove-loops");
685 : #ifdef HAVE_FOX
686 50118 : const int maxNumThreads = options.getInt("routing-threads");
687 : #endif
688 25059 : if (myRoutables.size() != 0) {
689 30092 : 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 111391 : for (RoutablesMap::const_iterator i = myRoutables.begin(); i != myRoutables.end(); ++i) {
698 105198 : if (i->first >= time) {
699 : break;
700 : }
701 250545 : for (RORoutable* const routable : i->second) {
702 : #ifdef HAVE_FOX
703 : // add task
704 154184 : 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 153357 : routable->computeRoute(provider, removeLoops, myErrorHandler);
722 : }
723 : }
724 : }
725 : #ifdef HAVE_FOX
726 15030 : myThreadPool.waitAll();
727 : #endif
728 : }
729 49814 : const double scale = options.exists("scale-suffix") ? options.getFloat("scale") : 1;
730 : // write all vehicles (and additional structures)
731 121460 : while (myRoutables.size() != 0 || myContainers.size() != 0) {
732 : // get the next vehicle, person or container
733 : RoutablesMap::iterator routables = myRoutables.begin();
734 105254 : const SUMOTime routableTime = routables == myRoutables.end() ? SUMOTime_MAX : routables->first;
735 : ContainerMap::iterator container = myContainers.begin();
736 105254 : const SUMOTime containerTime = container == myContainers.end() ? SUMOTime_MAX : container->first;
737 : // check whether it shall not yet be computed
738 105254 : if (routableTime >= time && containerTime >= time) {
739 : lastTime = MIN2(routableTime, containerTime);
740 : break;
741 : }
742 : const SUMOTime minTime = MIN2(routableTime, containerTime);
743 96417 : if (routableTime == minTime) {
744 : // check whether to print the output
745 96369 : if (lastTime != routableTime && lastTime != -1) {
746 : // report writing progress
747 87690 : 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 250897 : for (const RORoutable* const r : routables->second) {
753 : // ok, check whether it has been routed
754 154528 : if (r->getRoutingSuccess()) {
755 : // write the route
756 151903 : int quota = getScalingQuota(scale, myWrittenRouteNo);
757 151903 : r->write(myRoutesOutput, myRouteAlternativesOutput, myTypesOutput, options, quota);
758 151903 : myWrittenRouteNo++;
759 : } else {
760 2625 : myDiscardedRouteNo++;
761 : }
762 : // we need to keep individual public transport vehicles but not the flows
763 154528 : if (!r->isPublicTransport() || r->isPartOfFlow()) {
764 : // delete routes and the vehicle
765 154528 : const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
766 154528 : if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
767 152833 : if (r->isPartOfFlow() || !myRoutes.remove(veh->getRouteDefinition()->getID())) {
768 25039 : delete veh->getRouteDefinition();
769 : }
770 : }
771 154528 : delete r;
772 : }
773 : }
774 : myRoutables.erase(routables);
775 : }
776 96417 : 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 25043 : return lastTime;
785 : }
786 :
787 :
788 : bool
789 57277 : RONet::furtherStored() {
790 57277 : return myRoutables.size() > 0 || (myFlows.size() > 0 && myHaveActiveFlows) || myContainers.size() > 0;
791 : }
792 :
793 :
794 : int
795 123 : RONet::getEdgeNumber() const {
796 123 : return myEdges.size();
797 : }
798 :
799 :
800 : int
801 1 : RONet::getInternalEdgeNumber() const {
802 1 : return myNumInternalEdges;
803 : }
804 :
805 :
806 : ROEdge*
807 6287 : RONet::getEdgeForLaneID(const std::string& laneID) const {
808 12574 : 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 1662 : for (const auto& stop : stopType.second) {
826 1396 : router.getNetwork()->addAccess(stop.first, myInstance->getEdgeForLaneID(stop.second->lane),
827 1396 : stop.second->startPos, stop.second->endPos, 0., element, false, taxiWait);
828 : // add access to all public transport stops
829 1396 : if (element == SUMO_TAG_BUS_STOP) {
830 2459 : for (const auto& a : stop.second->accessPos) {
831 1083 : 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 983 : for (const auto& i : myInstance->myFlows) {
839 473 : if (i.second->line != "") {
840 461 : const RORouteDef* const route = myInstance->getRouteDef(i.second->routeid);
841 : const std::vector<SUMOVehicleParameter::Stop>* addStops = nullptr;
842 922 : if (route != nullptr && route->getFirstRoute() != nullptr) {
843 : addStops = &route->getFirstRoute()->getStops();
844 : }
845 461 : 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 2828096 : RONet::hasPermissions() const {
866 2828096 : return myHavePermissions;
867 : }
868 :
869 :
870 : void
871 139264 : RONet::setPermissionsFound() {
872 139264 : myHavePermissions = true;
873 139264 : }
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 1092 : RONet::getStoppingPlaceName(const std::string& id) const {
887 1284 : for (const auto& mapItem : myStoppingPlaces) {
888 : SUMOVehicleParameter::Stop* stop = mapItem.second.get(id);
889 1092 : if (stop != nullptr) {
890 : // see RONetHandler::parseStoppingPlace
891 : return stop->busstop;
892 : }
893 : }
894 0 : return "";
895 : }
896 :
897 : const std::string
898 992 : RONet::getStoppingPlaceElement(const std::string& id) const {
899 1136 : for (const auto& mapItem : myStoppingPlaces) {
900 : SUMOVehicleParameter::Stop* stop = mapItem.second.get(id);
901 992 : 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 : /****************************************************************************/
|