Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 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 5944790 : RONet::getInstance(void) {
57 5944790 : if (myInstance != nullptr) {
58 5944790 : return myInstance;
59 : }
60 0 : throw ProcessError(TL("A network was not yet constructed."));
61 : }
62 :
63 :
64 5032 : RONet::RONet() :
65 5032 : myVehicleTypes(), myDefaultVTypeMayBeDeleted(true),
66 5032 : myDefaultPedTypeMayBeDeleted(true),
67 5032 : myDefaultBikeTypeMayBeDeleted(true),
68 5032 : myDefaultTaxiTypeMayBeDeleted(true),
69 5032 : myDefaultRailTypeMayBeDeleted(true),
70 5032 : myHaveActiveFlows(true),
71 5032 : myRoutesOutput(nullptr), myRouteAlternativesOutput(nullptr), myTypesOutput(nullptr),
72 5032 : myReadRouteNo(0), myDiscardedRouteNo(0), myWrittenRouteNo(0),
73 5032 : myHavePermissions(false),
74 5032 : myHaveParamRestrictions(false),
75 5032 : myNumInternalEdges(0),
76 5032 : myErrorHandler(OptionsCont::getOptions().exists("ignore-errors")
77 9617 : && OptionsCont::getOptions().getBool("ignore-errors") ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
78 5032 : myKeepVTypeDist(OptionsCont::getOptions().exists("keep-vtype-distributions")
79 9617 : && OptionsCont::getOptions().getBool("keep-vtype-distributions")),
80 5032 : myDoPTRouting(!OptionsCont::getOptions().exists("ptline-routing")
81 9147 : || OptionsCont::getOptions().getBool("ptline-routing")),
82 5032 : myKeepFlows(OptionsCont::getOptions().exists("keep-flows")
83 9147 : && OptionsCont::getOptions().getBool("keep-flows")),
84 5032 : myHasBidiEdges(false),
85 18294 : myMaxTraveltime(OptionsCont::getOptions().exists("max-traveltime") ? STEPS2TIME(string2time(OptionsCont::getOptions().getString("max-traveltime"))) : -1) {
86 5032 : if (myInstance != nullptr) {
87 0 : throw ProcessError(TL("A network was already constructed."));
88 : }
89 5032 : SUMOVTypeParameter* type = new SUMOVTypeParameter(DEFAULT_VTYPE_ID, SVC_PASSENGER);
90 5032 : type->onlyReferenced = true;
91 5032 : myVehicleTypes.add(type->id, type);
92 :
93 5032 : SUMOVTypeParameter* defPedType = new SUMOVTypeParameter(DEFAULT_PEDTYPE_ID, SVC_PEDESTRIAN);
94 5032 : defPedType->onlyReferenced = true;
95 5032 : defPedType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
96 5032 : myVehicleTypes.add(defPedType->id, defPedType);
97 :
98 5032 : SUMOVTypeParameter* defBikeType = new SUMOVTypeParameter(DEFAULT_BIKETYPE_ID, SVC_BICYCLE);
99 5032 : defBikeType->onlyReferenced = true;
100 5032 : defBikeType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
101 5032 : myVehicleTypes.add(defBikeType->id, defBikeType);
102 :
103 5032 : SUMOVTypeParameter* defTaxiType = new SUMOVTypeParameter(DEFAULT_TAXITYPE_ID, SVC_TAXI);
104 5032 : defTaxiType->onlyReferenced = true;
105 5032 : defTaxiType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
106 5032 : myVehicleTypes.add(defTaxiType->id, defTaxiType);
107 :
108 5032 : SUMOVTypeParameter* defRailType = new SUMOVTypeParameter(DEFAULT_RAILTYPE_ID, SVC_RAIL);
109 5032 : defRailType->onlyReferenced = true;
110 5032 : defRailType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
111 5032 : myVehicleTypes.add(defRailType->id, defRailType);
112 :
113 5032 : myInstance = this;
114 5032 : }
115 :
116 :
117 9607 : RONet::~RONet() {
118 5280 : for (const auto& routables : myRoutables) {
119 516 : for (RORoutable* const r : routables.second) {
120 258 : const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
121 : // delete routes and the vehicle
122 258 : if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
123 248 : if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
124 95 : delete veh->getRouteDefinition();
125 : }
126 : }
127 258 : delete r;
128 : }
129 : }
130 5067 : for (const RORoutable* const r : myPTVehicles) {
131 45 : const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
132 : // delete routes and the vehicle
133 45 : if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
134 45 : if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
135 10 : delete veh->getRouteDefinition();
136 : }
137 : }
138 45 : delete r;
139 : }
140 : myRoutables.clear();
141 5127 : for (const auto& vTypeDist : myVTypeDistDict) {
142 210 : delete vTypeDist.second;
143 : }
144 34717 : }
145 :
146 :
147 : void
148 21 : RONet::addSpeedRestriction(const std::string& id, const SUMOVehicleClass svc, const double speed) {
149 21 : mySpeedRestrictions[id][svc] = speed;
150 21 : }
151 :
152 :
153 : double
154 1680 : RONet::getPreference(const std::string& routingType, const SUMOVTypeParameter& pars) const {
155 1680 : if (gRoutingPreferences) {
156 1680 : auto it = myVTypePreferences.find(pars.id);
157 1680 : if (it != myVTypePreferences.end()) {
158 : auto it2 = it->second.find(routingType);
159 114 : if (it2 != it->second.end()) {
160 30 : return it2->second;
161 : }
162 : }
163 : auto it3 = myVClassPreferences.find(pars.vehicleClass);
164 1650 : if (it3 != myVClassPreferences.end()) {
165 : auto it4 = it3->second.find(routingType);
166 228 : if (it4 != it3->second.end()) {
167 60 : return it4->second;
168 : }
169 : }
170 : // fallback to generel preferences
171 1590 : it = myVTypePreferences.find("");
172 1590 : if (it != myVTypePreferences.end()) {
173 : auto it2 = it->second.find(routingType);
174 1011 : if (it2 != it->second.end()) {
175 180 : return it2->second;
176 : }
177 : }
178 : }
179 : return 1;
180 : }
181 :
182 :
183 : void
184 30 : RONet::addPreference(const std::string& routingType, SUMOVehicleClass svc, double prio) {
185 30 : myVClassPreferences[svc][routingType] = prio;
186 30 : gRoutingPreferences = true;
187 30 : }
188 :
189 :
190 : void
191 40 : RONet::addPreference(const std::string& routingType, std::string vType, double prio) {
192 40 : myVTypePreferences[vType][routingType] = prio;
193 40 : gRoutingPreferences = true;
194 40 : }
195 :
196 :
197 :
198 : const std::map<SUMOVehicleClass, double>*
199 80 : RONet::getRestrictions(const std::string& id) const {
200 : std::map<std::string, std::map<SUMOVehicleClass, double> >::const_iterator i = mySpeedRestrictions.find(id);
201 80 : if (i == mySpeedRestrictions.end()) {
202 : return nullptr;
203 : }
204 30 : return &i->second;
205 : }
206 :
207 :
208 : bool
209 349987 : RONet::addEdge(ROEdge* edge) {
210 349987 : if (!myEdges.add(edge->getID(), edge)) {
211 36 : WRITE_ERRORF(TL("The edge '%' occurs at least twice."), edge->getID());
212 12 : delete edge;
213 12 : return false;
214 : }
215 349975 : if (edge->isInternal()) {
216 170699 : myNumInternalEdges += 1;
217 : }
218 : return true;
219 : }
220 :
221 :
222 : bool
223 2184 : RONet::addDistrict(const std::string id, ROEdge* source, ROEdge* sink) {
224 : if (myDistricts.count(id) > 0) {
225 0 : WRITE_ERRORF(TL("The TAZ '%' occurs at least twice."), id);
226 0 : delete source;
227 0 : delete sink;
228 0 : return false;
229 : }
230 : sink->setFunction(SumoXMLEdgeFunc::CONNECTOR);
231 2184 : if (!addEdge(sink)) {
232 : return false;
233 : }
234 : source->setFunction(SumoXMLEdgeFunc::CONNECTOR);
235 2184 : if (!addEdge(source)) {
236 : return false;
237 : }
238 : sink->setOtherTazConnector(source);
239 : source->setOtherTazConnector(sink);
240 4368 : myDistricts[id] = std::make_pair(std::vector<std::string>(), std::vector<std::string>());
241 2184 : return true;
242 : }
243 :
244 :
245 : bool
246 1510 : RONet::addDistrictEdge(const std::string tazID, const std::string edgeID, const bool isSource) {
247 : if (myDistricts.count(tazID) == 0) {
248 0 : WRITE_ERRORF(TL("The TAZ '%' is unknown."), tazID);
249 0 : return false;
250 : }
251 : ROEdge* edge = getEdge(edgeID);
252 1510 : if (edge == nullptr) {
253 0 : WRITE_ERRORF(TL("The edge '%' for TAZ '%' is unknown."), edgeID, tazID);
254 0 : return false;
255 : }
256 1510 : if (isSource) {
257 2265 : getEdge(tazID + "-source")->addSuccessor(edge);
258 755 : myDistricts[tazID].first.push_back(edgeID);
259 : } else {
260 2265 : edge->addSuccessor(getEdge(tazID + "-sink"));
261 755 : myDistricts[tazID].second.push_back(edgeID);
262 : }
263 : return true;
264 : }
265 :
266 :
267 : void
268 121 : RONet::addJunctionTaz(ROAbstractEdgeBuilder& eb) {
269 1888 : for (auto item : myNodes) {
270 : const std::string tazID = item.first;
271 10 : if (myDistricts.count(tazID) != 0) {
272 30 : WRITE_WARNINGF(TL("A TAZ with id '%' already exists. Not building junction TAZ."), tazID);
273 10 : continue;
274 : }
275 1757 : const std::string sourceID = tazID + "-source";
276 1757 : const std::string sinkID = tazID + "-sink";
277 : // sink must be added before source
278 3514 : ROEdge* sink = eb.buildEdge(sinkID, nullptr, nullptr, 0, "", "");
279 3514 : ROEdge* source = eb.buildEdge(sourceID, nullptr, nullptr, 0, "", "");
280 : sink->setOtherTazConnector(source);
281 : source->setOtherTazConnector(sink);
282 3514 : if (!addDistrict(tazID, source, sink)) {
283 : continue;
284 : }
285 1757 : auto& district = myDistricts[tazID];
286 1757 : const RONode* junction = item.second;
287 15478 : for (const ROEdge* edge : junction->getIncoming()) {
288 13721 : if (!edge->isInternal()) {
289 3864 : const_cast<ROEdge*>(edge)->addSuccessor(sink);
290 3864 : district.second.push_back(edge->getID());
291 : }
292 : }
293 15478 : for (const ROEdge* edge : junction->getOutgoing()) {
294 13721 : if (!edge->isInternal()) {
295 3864 : source->addSuccessor(const_cast<ROEdge*>(edge));
296 3864 : district.first.push_back(edge->getID());
297 : }
298 : }
299 : }
300 121 : }
301 :
302 :
303 : void
304 4298 : RONet::setBidiEdges(const std::map<ROEdge*, std::string>& bidiMap) {
305 17256 : for (const auto& item : bidiMap) {
306 12958 : ROEdge* bidi = myEdges.get(item.second);
307 12958 : if (bidi == nullptr) {
308 0 : WRITE_ERRORF(TL("The bidi edge '%' is not known."), item.second);
309 : }
310 12958 : item.first->setBidiEdge(bidi);
311 12958 : myHasBidiEdges = true;
312 : }
313 4298 : }
314 :
315 :
316 : void
317 81043 : RONet::addNode(RONode* node) {
318 81043 : if (!myNodes.add(node->getID(), node)) {
319 0 : WRITE_ERRORF(TL("The node '%' occurs at least twice."), node->getID());
320 0 : delete node;
321 : }
322 81043 : }
323 :
324 :
325 : void
326 2335 : RONet::addStoppingPlace(const std::string& id, const SumoXMLTag category, SUMOVehicleParameter::Stop* stop) {
327 4260 : if (!myStoppingPlaces[category == SUMO_TAG_TRAIN_STOP ? SUMO_TAG_BUS_STOP : category].add(id, stop)) {
328 15 : WRITE_ERRORF(TL("The % '%' occurs at least twice."), toString(category), id);
329 5 : delete stop;
330 : }
331 2335 : }
332 :
333 :
334 : bool
335 285042 : RONet::addRouteDef(RORouteDef* def) {
336 285042 : return myRoutes.add(def->getID(), def);
337 : }
338 :
339 :
340 : void
341 3484 : RONet::openOutput(const OptionsCont& options) {
342 10450 : if (options.isSet("output-file") && options.getString("output-file") != "") {
343 3483 : myRoutesOutput = &OutputDevice::getDevice(options.getString("output-file"));
344 3476 : if (myRoutesOutput->isNull()) {
345 1 : myRoutesOutput = nullptr;
346 : } else {
347 6950 : myRoutesOutput->writeXMLHeader("routes", "routes_file.xsd");
348 : }
349 : }
350 10241 : if (options.exists("alternatives-output") && options.isSet("alternatives-output")
351 16408 : && !(options.exists("write-trips") && options.getBool("write-trips"))) {
352 3072 : myRouteAlternativesOutput = &OutputDevice::getDevice(options.getString("alternatives-output"));
353 3072 : if (myRouteAlternativesOutput->isNull()) {
354 180 : myRouteAlternativesOutput = nullptr;
355 : } else {
356 5784 : myRouteAlternativesOutput->writeXMLHeader("routes", "routes_file.xsd");
357 : }
358 : }
359 6954 : if (options.isSet("vtype-output")) {
360 34 : myTypesOutput = &OutputDevice::getDevice(options.getString("vtype-output"));
361 68 : myTypesOutput->writeXMLHeader("routes", "routes_file.xsd");
362 : }
363 3477 : }
364 :
365 :
366 : void
367 3247 : RONet::writeIntermodal(const OptionsCont& options, ROIntermodalRouter& router) const {
368 6494 : if (options.exists("intermodal-network-output") && options.isSet("intermodal-network-output")) {
369 40 : OutputDevice::createDeviceByOption("intermodal-network-output", "intermodal");
370 40 : router.writeNetwork(OutputDevice::getDevice(options.getString("intermodal-network-output")));
371 : }
372 6494 : if (options.exists("intermodal-weight-output") && options.isSet("intermodal-weight-output")) {
373 20 : OutputDevice::createDeviceByOption("intermodal-weight-output", "weights", "meandata_file.xsd");
374 10 : OutputDevice& dev = OutputDevice::getDeviceByOption("intermodal-weight-output");
375 10 : dev.openTag(SUMO_TAG_INTERVAL);
376 10 : dev.writeAttr(SUMO_ATTR_ID, "intermodalweights");
377 10 : dev.writeAttr(SUMO_ATTR_BEGIN, 0);
378 10 : dev.writeAttr(SUMO_ATTR_END, SUMOTime_MAX);
379 10 : router.writeWeights(dev);
380 20 : dev.closeTag();
381 : }
382 3247 : }
383 :
384 :
385 : void
386 3483 : RONet::cleanup() {
387 : // end writing
388 3483 : if (myRoutesOutput != nullptr) {
389 3475 : myRoutesOutput->close();
390 : }
391 : // only if opened
392 3483 : if (myRouteAlternativesOutput != nullptr) {
393 2892 : myRouteAlternativesOutput->close();
394 : }
395 : // only if opened
396 3483 : if (myTypesOutput != nullptr) {
397 34 : myTypesOutput->close();
398 : }
399 : RouteCostCalculator<RORoute, ROEdge, ROVehicle>::cleanup();
400 : #ifdef HAVE_FOX
401 3483 : if (myThreadPool.size() > 0) {
402 242 : myThreadPool.clear();
403 : }
404 : #endif
405 3483 : }
406 :
407 :
408 :
409 : SUMOVTypeParameter*
410 506403 : RONet::getVehicleTypeSecure(const std::string& id) {
411 : // check whether the type was already known
412 : SUMOVTypeParameter* type = myVehicleTypes.get(id);
413 506403 : if (id == DEFAULT_VTYPE_ID) {
414 461359 : myDefaultVTypeMayBeDeleted = false;
415 45044 : } else if (id == DEFAULT_PEDTYPE_ID) {
416 6293 : myDefaultPedTypeMayBeDeleted = false;
417 38751 : } else if (id == DEFAULT_BIKETYPE_ID) {
418 69 : myDefaultBikeTypeMayBeDeleted = false;
419 38682 : } else if (id == DEFAULT_TAXITYPE_ID) {
420 105 : myDefaultTaxiTypeMayBeDeleted = false;
421 38577 : } else if (id == DEFAULT_RAILTYPE_ID) {
422 0 : myDefaultRailTypeMayBeDeleted = false;
423 : }
424 506403 : if (type != nullptr) {
425 : return type;
426 : }
427 : VTypeDistDictType::iterator it2 = myVTypeDistDict.find(id);
428 3074 : if (it2 != myVTypeDistDict.end()) {
429 2665 : return it2->second->get();
430 : }
431 409 : if (id == "") {
432 : // ok, no vehicle type or an unknown type was given within the user input
433 : // return the default type
434 0 : myDefaultVTypeMayBeDeleted = false;
435 : return myVehicleTypes.get(DEFAULT_VTYPE_ID);
436 : }
437 : return type;
438 : }
439 :
440 :
441 : bool
442 2701 : RONet::checkVType(const std::string& id) {
443 2701 : if (id == DEFAULT_VTYPE_ID) {
444 81 : if (myDefaultVTypeMayBeDeleted) {
445 81 : myVehicleTypes.remove(id);
446 81 : myDefaultVTypeMayBeDeleted = false;
447 : } else {
448 : return false;
449 : }
450 2620 : } else if (id == DEFAULT_PEDTYPE_ID) {
451 0 : if (myDefaultPedTypeMayBeDeleted) {
452 0 : myVehicleTypes.remove(id);
453 0 : myDefaultPedTypeMayBeDeleted = false;
454 : } else {
455 : return false;
456 : }
457 2620 : } else if (id == DEFAULT_BIKETYPE_ID) {
458 0 : if (myDefaultBikeTypeMayBeDeleted) {
459 0 : myVehicleTypes.remove(id);
460 0 : myDefaultBikeTypeMayBeDeleted = false;
461 : } else {
462 : return false;
463 : }
464 2620 : } else if (id == DEFAULT_TAXITYPE_ID) {
465 0 : if (myDefaultTaxiTypeMayBeDeleted) {
466 0 : myVehicleTypes.remove(id);
467 0 : myDefaultTaxiTypeMayBeDeleted = false;
468 : } else {
469 : return false;
470 : }
471 2620 : } else if (id == DEFAULT_RAILTYPE_ID) {
472 0 : if (myDefaultRailTypeMayBeDeleted) {
473 0 : myVehicleTypes.remove(id);
474 0 : myDefaultRailTypeMayBeDeleted = false;
475 : } else {
476 : return false;
477 : }
478 : } else {
479 2620 : if (myVehicleTypes.get(id) != 0 || myVTypeDistDict.find(id) != myVTypeDistDict.end()) {
480 0 : return false;
481 : }
482 : }
483 : return true;
484 : }
485 :
486 :
487 : bool
488 2596 : RONet::addVehicleType(SUMOVTypeParameter* type) {
489 2596 : if (checkVType(type->id)) {
490 2596 : myVehicleTypes.add(type->id, type);
491 : } else {
492 0 : WRITE_ERRORF(TL("The vehicle type '%' occurs at least twice."), type->id);
493 0 : delete type;
494 0 : return false;
495 : }
496 2596 : return true;
497 : }
498 :
499 :
500 : bool
501 105 : RONet::addVTypeDistribution(const std::string& id, RandomDistributor<SUMOVTypeParameter*>* vehTypeDistribution) {
502 105 : if (checkVType(id)) {
503 105 : myVTypeDistDict[id] = vehTypeDistribution;
504 105 : return true;
505 : }
506 0 : delete vehTypeDistribution;
507 : return false;
508 : }
509 :
510 :
511 : bool
512 303139 : RONet::addVehicle(const std::string& id, ROVehicle* veh) {
513 303139 : if (myVehIDs.find(id) == myVehIDs.end()) {
514 606230 : myVehIDs[id] = veh->getParameter().departProcedure == DepartDefinition::TRIGGERED ? -1 : veh->getDepartureTime();
515 :
516 303134 : if (veh->isPublicTransport()) {
517 55 : if (!veh->isPartOfFlow()) {
518 45 : myPTVehicles.push_back(veh);
519 : }
520 55 : if (!myDoPTRouting) {
521 : return true;
522 : }
523 : }
524 303089 : myRoutables[veh->getDepart()].push_back(veh);
525 303089 : return true;
526 : }
527 15 : WRITE_ERRORF(TL("Another vehicle with the id '%' exists."), id);
528 5 : delete veh;
529 : return false;
530 : }
531 :
532 :
533 : bool
534 318 : RONet::knowsVehicle(const std::string& id) const {
535 318 : return myVehIDs.find(id) != myVehIDs.end();
536 : }
537 :
538 :
539 : bool
540 20 : RONet::knowsVType(const std::string& id) const {
541 20 : return myVehicleTypes.get(id) != nullptr || myVTypeDistDict.find(id) != myVTypeDistDict.end();
542 : }
543 :
544 :
545 : SUMOTime
546 35 : RONet::getDeparture(const std::string& vehID) const {
547 : auto it = myVehIDs.find(vehID);
548 35 : if (it != myVehIDs.end()) {
549 35 : return it->second;
550 : } else {
551 0 : throw ProcessError(TLF("Requesting departure time for unknown vehicle '%'", vehID));
552 : }
553 : }
554 :
555 :
556 : bool
557 2797 : RONet::addFlow(SUMOVehicleParameter* flow, const bool randomize) {
558 2797 : if (randomize && flow->repetitionOffset >= 0) {
559 12 : myDepartures[flow->id].reserve(flow->repetitionNumber);
560 132 : for (int i = 0; i < flow->repetitionNumber; ++i) {
561 120 : myDepartures[flow->id].push_back(flow->depart + RandHelper::rand(flow->repetitionNumber * flow->repetitionOffset));
562 : }
563 12 : std::sort(myDepartures[flow->id].begin(), myDepartures[flow->id].end());
564 12 : std::reverse(myDepartures[flow->id].begin(), myDepartures[flow->id].end());
565 2785 : } else if (flow->repetitionOffset < 0) {
566 : // init poisson flow (but only the timing)
567 354 : flow->incrementFlow(1);
568 354 : flow->repetitionsDone--;
569 : }
570 2797 : const bool added = myFlows.add(flow->id, flow);
571 2797 : if (added) {
572 2792 : myHaveActiveFlows = true;
573 : }
574 2797 : return added;
575 : }
576 :
577 :
578 : bool
579 3862 : RONet::addPerson(ROPerson* person) {
580 : if (myPersonIDs.count(person->getID()) == 0) {
581 : myPersonIDs.insert(person->getID());
582 3862 : myRoutables[person->getDepart()].push_back(person);
583 3862 : return true;
584 : }
585 0 : WRITE_ERRORF(TL("Another person with the id '%' exists."), person->getID());
586 0 : return false;
587 : }
588 :
589 :
590 : void
591 70 : RONet::addContainer(const SUMOTime depart, const std::string desc) {
592 70 : myContainers.insert(std::pair<const SUMOTime, const std::string>(depart, desc));
593 70 : }
594 :
595 :
596 : void
597 16514 : RONet::checkFlows(SUMOTime time, MsgHandler* errorHandler) {
598 16514 : myHaveActiveFlows = false;
599 63353 : for (const auto& i : myFlows) {
600 46839 : SUMOVehicleParameter* const pars = i.second;
601 46839 : if (pars->line != "" && !myDoPTRouting) {
602 842 : continue;
603 : }
604 45997 : if (myKeepFlows) {
605 798 : if (pars->repetitionsDone < pars->repetitionNumber) {
606 : // each each flow only once
607 792 : pars->repetitionsDone = pars->repetitionNumber;
608 792 : const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
609 792 : if (type == nullptr) {
610 0 : type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
611 : } else {
612 : auto dist = getVTypeDistribution(pars->vtypeid);
613 0 : if (dist != nullptr) {
614 0 : WRITE_WARNINGF("Keeping flow '%' with a vTypeDistribution can lead to invalid routes if the distribution contains different vClasses", pars->id);
615 : }
616 : }
617 1584 : RORouteDef* route = getRouteDef(pars->routeid)->copy(pars->routeid, pars->depart);
618 792 : ROVehicle* veh = new ROVehicle(*pars, route, type, this, errorHandler);
619 792 : addVehicle(pars->id, veh);
620 : }
621 45199 : } else if (pars->repetitionProbability > 0) {
622 135 : if (pars->repetitionEnd > pars->depart && pars->repetitionsDone < pars->repetitionNumber) {
623 120 : myHaveActiveFlows = true;
624 : }
625 : const SUMOTime origDepart = pars->depart;
626 1275 : while (pars->depart < time && pars->repetitionsDone < pars->repetitionNumber) {
627 1160 : if (pars->repetitionEnd <= pars->depart) {
628 : break;
629 : }
630 : // only call rand if all other conditions are met
631 1140 : if (RandHelper::rand() < (pars->repetitionProbability * TS)) {
632 210 : SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
633 420 : newPars->id = pars->id + "." + toString(pars->repetitionsDone);
634 210 : newPars->depart = pars->depart;
635 210 : for (StopParVector::iterator stop = newPars->stops.begin(); stop != newPars->stops.end(); ++stop) {
636 0 : if (stop->until >= 0) {
637 0 : stop->until += pars->depart - origDepart;
638 : }
639 : }
640 210 : pars->repetitionsDone++;
641 : // try to build the vehicle
642 210 : const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
643 210 : if (type == nullptr) {
644 40 : type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
645 170 : } else if (!myKeepVTypeDist) {
646 : // fix the type id in case we used a distribution
647 170 : newPars->vtypeid = type->id;
648 : }
649 210 : const SUMOTime stopOffset = pars->routeid[0] == '!' ? pars->depart - origDepart : pars->depart;
650 420 : RORouteDef* route = getRouteDef(pars->routeid)->copy("!" + newPars->id, stopOffset);
651 210 : ROVehicle* veh = new ROVehicle(*newPars, route, type, this, errorHandler);
652 210 : addVehicle(newPars->id, veh);
653 210 : delete newPars;
654 : }
655 1140 : pars->depart += DELTA_T;
656 : }
657 : } else {
658 45064 : SUMOTime depart = static_cast<SUMOTime>(pars->depart + pars->repetitionTotalOffset);
659 65206 : while (pars->repetitionsDone < pars->repetitionNumber && pars->repetitionEnd >= depart) {
660 33456 : myHaveActiveFlows = true;
661 33456 : depart = static_cast<SUMOTime>(pars->depart + pars->repetitionTotalOffset);
662 33456 : if (myDepartures.find(pars->id) != myDepartures.end()) {
663 132 : depart = myDepartures[pars->id].back();
664 : }
665 33456 : if (depart >= time + DELTA_T) {
666 : break;
667 : }
668 20142 : if (myDepartures.find(pars->id) != myDepartures.end()) {
669 120 : myDepartures[pars->id].pop_back();
670 : }
671 20142 : SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
672 40284 : newPars->id = pars->id + "." + toString(pars->repetitionsDone);
673 20142 : newPars->depart = depart;
674 20342 : for (StopParVector::iterator stop = newPars->stops.begin(); stop != newPars->stops.end(); ++stop) {
675 200 : if (stop->until >= 0) {
676 50 : stop->until += depart - pars->depart;
677 : }
678 200 : if (stop->arrival >= 0) {
679 50 : stop->arrival += depart - pars->depart;
680 : }
681 : }
682 20142 : pars->incrementFlow(1);
683 : // try to build the vehicle
684 20142 : const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
685 20142 : if (type == nullptr) {
686 75 : type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
687 20067 : } else if (!myKeepVTypeDist) {
688 : // fix the type id in case we used a distribution
689 20017 : newPars->vtypeid = type->id;
690 : }
691 20142 : const SUMOTime stopOffset = pars->routeid[0] == '!' ? depart - pars->depart : depart;
692 40284 : RORouteDef* route = getRouteDef(pars->routeid)->copy("!" + newPars->id, stopOffset);
693 20142 : ROVehicle* veh = new ROVehicle(*newPars, route, type, this, errorHandler);
694 20142 : addVehicle(newPars->id, veh);
695 20142 : delete newPars;
696 : }
697 : }
698 : }
699 16514 : }
700 :
701 :
702 : void
703 86 : RONet::createBulkRouteRequests(const RORouterProvider& provider, const SUMOTime time, const bool removeLoops) {
704 : std::map<const int, std::vector<RORoutable*> > bulkVehs;
705 : int numBulked = 0;
706 129 : for (RoutablesMap::const_iterator i = myRoutables.begin(); i != myRoutables.end(); ++i) {
707 86 : if (i->first >= time) {
708 : break;
709 : }
710 785 : for (RORoutable* const routable : i->second) {
711 742 : const ROEdge* const depEdge = routable->getDepartEdge();
712 742 : bulkVehs[depEdge->getNumericalID()].push_back(routable);
713 742 : RORoutable* const first = bulkVehs[depEdge->getNumericalID()].front();
714 742 : numBulked++;
715 742 : if (first->getMaxSpeed() != routable->getMaxSpeed()) {
716 9 : WRITE_WARNINGF(TL("Bulking different maximum speeds ('%' and '%') may lead to suboptimal routes."), first->getID(), routable->getID());
717 : }
718 742 : if (first->getVClass() != routable->getVClass()) {
719 9 : WRITE_WARNINGF(TL("Bulking different vehicle classes ('%' and '%') may lead to invalid routes."), first->getID(), routable->getID());
720 : }
721 : }
722 : }
723 : #ifdef HAVE_FOX
724 : int workerIndex = 0;
725 : #endif
726 86 : if ((int)bulkVehs.size() < numBulked) {
727 84 : WRITE_MESSAGE(TLF("Using bulk-mode for % entities from % origins", numBulked, bulkVehs.size()));
728 : }
729 257 : for (std::map<const int, std::vector<RORoutable*> >::const_iterator i = bulkVehs.begin(); i != bulkVehs.end(); ++i) {
730 : #ifdef HAVE_FOX
731 171 : if (myThreadPool.size() > 0) {
732 : bool bulk = true;
733 198 : for (RORoutable* const r : i->second) {
734 180 : myThreadPool.add(new RoutingTask(r, removeLoops, myErrorHandler), workerIndex);
735 180 : if (bulk) {
736 18 : myThreadPool.add(new BulkmodeTask(true), workerIndex);
737 : bulk = false;
738 : }
739 : }
740 18 : myThreadPool.add(new BulkmodeTask(false), workerIndex);
741 18 : workerIndex++;
742 18 : if (workerIndex == (int)myThreadPool.size()) {
743 : workerIndex = 0;
744 : }
745 18 : continue;
746 18 : }
747 : #endif
748 715 : for (RORoutable* const r : i->second) {
749 562 : r->computeRoute(provider, removeLoops, myErrorHandler);
750 562 : provider.setBulkMode(true);
751 : }
752 153 : provider.setBulkMode(false);
753 : }
754 86 : }
755 :
756 :
757 : SUMOTime
758 23641 : RONet::saveAndRemoveRoutesUntil(OptionsCont& options, const RORouterProvider& provider,
759 : SUMOTime time) {
760 23641 : MsgHandler* mh = (options.getBool("ignore-errors") ?
761 23641 : MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance());
762 23641 : if (myHaveActiveFlows) {
763 16514 : checkFlows(time, mh);
764 : }
765 : SUMOTime lastTime = -1;
766 23641 : const bool removeLoops = options.getBool("remove-loops");
767 : #ifdef HAVE_FOX
768 47282 : const int maxNumThreads = options.getInt("routing-threads");
769 : #endif
770 23641 : if (myRoutables.size() != 0) {
771 22212 : if (options.getBool("bulk-routing")) {
772 : #ifdef HAVE_FOX
773 98 : while ((int)myThreadPool.size() < maxNumThreads) {
774 12 : new WorkerThread(myThreadPool, provider);
775 : }
776 : #endif
777 86 : createBulkRouteRequests(provider, time, removeLoops);
778 : } else {
779 257622 : for (RoutablesMap::const_iterator i = myRoutables.begin(); i != myRoutables.end(); ++i) {
780 254248 : if (i->first >= time) {
781 : break;
782 : }
783 552573 : for (RORoutable* const routable : i->second) {
784 : #ifdef HAVE_FOX
785 : // add task
786 305971 : if (maxNumThreads > 0) {
787 : const int numThreads = (int)myThreadPool.size();
788 179945 : if (numThreads == 0) {
789 : // This is the very first routing. Since at least the CHRouter needs initialization
790 : // before it gets cloned, we do not do this in parallel
791 231 : routable->computeRoute(provider, removeLoops, myErrorHandler);
792 231 : new WorkerThread(myThreadPool, provider);
793 : } else {
794 : // add thread if necessary
795 179714 : if (numThreads < maxNumThreads && myThreadPool.isFull()) {
796 1202 : new WorkerThread(myThreadPool, provider);
797 : }
798 179714 : myThreadPool.add(new RoutingTask(routable, removeLoops, myErrorHandler));
799 : }
800 179945 : continue;
801 179945 : }
802 : #endif
803 126026 : routable->computeRoute(provider, removeLoops, myErrorHandler);
804 : }
805 : }
806 : }
807 : #ifdef HAVE_FOX
808 11086 : myThreadPool.waitAll();
809 : #endif
810 : }
811 46970 : const double scale = options.exists("scale-suffix") ? options.getFloat("scale") : 1;
812 : // write all vehicles (and additional structures)
813 270326 : while (myRoutables.size() != 0 || myContainers.size() != 0) {
814 : // get the next vehicle, person or container
815 : RoutablesMap::iterator routables = myRoutables.begin();
816 254384 : const SUMOTime routableTime = routables == myRoutables.end() ? SUMOTime_MAX : routables->first;
817 : ContainerMap::iterator container = myContainers.begin();
818 254384 : const SUMOTime containerTime = container == myContainers.end() ? SUMOTime_MAX : container->first;
819 : // check whether it shall not yet be computed
820 254384 : if (routableTime >= time && containerTime >= time) {
821 : lastTime = MIN2(routableTime, containerTime);
822 : break;
823 : }
824 : const SUMOTime minTime = MIN2(routableTime, containerTime);
825 246705 : if (routableTime == minTime) {
826 : // check whether to print the output
827 246645 : if (lastTime != routableTime && lastTime != -1) {
828 : // report writing progress
829 239358 : if (options.getInt("stats-period") >= 0 && ((int)routableTime % options.getInt("stats-period")) == 0) {
830 0 : WRITE_MESSAGE("Read: " + toString(myVehIDs.size()) + ", Discarded: " + toString(myDiscardedRouteNo) + ", Written: " + toString(myWrittenRouteNo));
831 : }
832 : }
833 : lastTime = routableTime;
834 553338 : for (const RORoutable* const r : routables->second) {
835 : // ok, check whether it has been routed
836 306693 : if (r->getRoutingSuccess()) {
837 : // write the route
838 287251 : int quota = getScalingQuota(scale, myWrittenRouteNo);
839 287251 : r->write(myRoutesOutput, myRouteAlternativesOutput, myTypesOutput, options, quota);
840 287251 : myWrittenRouteNo++;
841 : } else {
842 19442 : myDiscardedRouteNo++;
843 : }
844 : // we need to keep individual public transport vehicles but not the flows
845 306693 : if (!r->isPublicTransport() || r->isPartOfFlow()) {
846 : // delete routes and the vehicle
847 306693 : const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
848 306693 : if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
849 302841 : if (r->isPartOfFlow() || !myRoutes.remove(veh->getRouteDefinition()->getID())) {
850 22642 : delete veh->getRouteDefinition();
851 : }
852 : }
853 306693 : delete r;
854 : }
855 : }
856 : myRoutables.erase(routables);
857 : }
858 246705 : if (containerTime == minTime) {
859 60 : myRoutesOutput->writePreformattedTag(container->second);
860 60 : if (myRouteAlternativesOutput != nullptr) {
861 : myRouteAlternativesOutput->writePreformattedTag(container->second);
862 : }
863 : myContainers.erase(container);
864 : }
865 : }
866 23621 : return lastTime;
867 : }
868 :
869 :
870 : bool
871 50897 : RONet::furtherStored() {
872 50897 : return myRoutables.size() > 0 || (myFlows.size() > 0 && myHaveActiveFlows) || myContainers.size() > 0;
873 : }
874 :
875 :
876 : int
877 123 : RONet::getEdgeNumber() const {
878 123 : return myEdges.size();
879 : }
880 :
881 :
882 : int
883 1 : RONet::getInternalEdgeNumber() const {
884 1 : return myNumInternalEdges;
885 : }
886 :
887 :
888 : ROEdge*
889 10292 : RONet::getEdgeForLaneID(const std::string& laneID) const {
890 20584 : return getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(laneID));
891 : }
892 :
893 :
894 : ROLane*
895 1425 : RONet::getLane(const std::string& laneID) const {
896 1425 : int laneIndex = SUMOXMLDefinitions::getIndexFromLane(laneID);
897 1425 : return getEdgeForLaneID(laneID)->getLanes()[laneIndex];
898 : }
899 :
900 :
901 : void
902 893 : RONet::adaptIntermodalRouter(ROIntermodalRouter& router) {
903 893 : double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
904 1252 : for (const auto& stopType : myInstance->myStoppingPlaces) {
905 : // add access to all stopping places
906 359 : const SumoXMLTag element = stopType.first;
907 2453 : for (const auto& stop : stopType.second) {
908 2094 : router.getNetwork()->addAccess(stop.first, myInstance->getEdgeForLaneID(stop.second->lane),
909 2094 : stop.second->startPos, stop.second->endPos, 0., element, false, taxiWait);
910 : // add access to all public transport stops
911 2094 : if (element == SUMO_TAG_BUS_STOP) {
912 4288 : for (const auto& a : stop.second->accessPos) {
913 2219 : router.getNetwork()->addAccess(stop.first, myInstance->getEdgeForLaneID(std::get<0>(a)),
914 : std::get<1>(a), std::get<1>(a), std::get<2>(a), SUMO_TAG_BUS_STOP, true, taxiWait);
915 : }
916 : }
917 : }
918 : }
919 : // fill the public transport router with pre-parsed public transport lines
920 2459 : for (const auto& i : myInstance->myFlows) {
921 1566 : if (i.second->line != "") {
922 847 : const RORouteDef* const route = myInstance->getRouteDef(i.second->routeid);
923 : const StopParVector* addStops = nullptr;
924 2541 : if (route != nullptr && route->getFirstRoute() != nullptr) {
925 847 : addStops = &route->getFirstRoute()->getStops();
926 : }
927 847 : router.getNetwork()->addSchedule(*i.second, addStops);
928 : }
929 : }
930 938 : for (const RORoutable* const veh : myInstance->myPTVehicles) {
931 : // add single vehicles with line attribute which are not part of a flow
932 : // no need to add route stops here, they have been added to the vehicle before
933 45 : router.getNetwork()->addSchedule(veh->getParameter());
934 : }
935 : // add access to transfer from walking to taxi-use
936 893 : if ((router.getCarWalkTransfer() & ModeChangeOptions::TAXI_PICKUP_ANYWHERE) != 0) {
937 230143 : for (const ROEdge* edge : ROEdge::getAllEdges()) {
938 229265 : if (!edge->isTazConnector() && (edge->getPermissions() & SVC_PEDESTRIAN) != 0 && (edge->getPermissions() & SVC_TAXI) != 0) {
939 40257 : router.getNetwork()->addCarAccess(edge, SVC_TAXI, taxiWait);
940 : }
941 : }
942 : }
943 893 : }
944 :
945 :
946 : bool
947 4186489 : RONet::hasPermissions() const {
948 4186489 : return myHavePermissions;
949 : }
950 :
951 :
952 : void
953 259711 : RONet::setPermissionsFound() {
954 259711 : myHavePermissions = true;
955 259711 : }
956 :
957 : bool
958 12 : RONet::hasLoadedEffort() const {
959 38 : for (const auto& item : myEdges) {
960 35 : if (item.second->hasStoredEffort()) {
961 : return true;
962 : }
963 : }
964 : return false;
965 : }
966 :
967 : const std::string
968 1787 : RONet::getStoppingPlaceName(const std::string& id) const {
969 2027 : for (const auto& mapItem : myStoppingPlaces) {
970 : SUMOVehicleParameter::Stop* stop = mapItem.second.get(id);
971 1787 : if (stop != nullptr) {
972 : // see RONetHandler::parseStoppingPlace
973 : return stop->busstop;
974 : }
975 : }
976 0 : return "";
977 : }
978 :
979 : const std::string
980 1647 : RONet::getStoppingPlaceElement(const std::string& id) const {
981 1827 : for (const auto& mapItem : myStoppingPlaces) {
982 : SUMOVehicleParameter::Stop* stop = mapItem.second.get(id);
983 1647 : if (stop != nullptr) {
984 : // see RONetHandler::parseStoppingPlace
985 : return stop->actType;
986 : }
987 : }
988 0 : return toString(SUMO_TAG_BUS_STOP);
989 : }
990 :
991 :
992 : void
993 5 : RONet::addProhibition(const ROEdge* edge, const RouterProhibition& prohibition) {
994 : if (myProhibitions.count(edge) != 0) {
995 0 : throw ProcessError(TLF("Already loaded prohibition for edge '%'. (Only one prohibition per edge is supported)", edge->getID()));
996 : }
997 5 : myProhibitions[edge] = prohibition;
998 5 : myHavePermissions = true;
999 5 : }
1000 :
1001 :
1002 : void
1003 5 : RONet::addLaneProhibition(const ROLane* lane, const RouterProhibition& prohibition) {
1004 : if (myLaneProhibitions.count(lane) != 0) {
1005 0 : throw ProcessError(TLF("Already loaded prohibition for lane '%'. (Only one prohibition per lane is supported)", lane->getID()));
1006 : }
1007 : assert(prohibition.end > prohibition.begin);
1008 5 : myLaneProhibitions[lane] = prohibition;
1009 5 : myLaneProhibitionTimes[prohibition.begin].insert(lane);
1010 5 : myHavePermissions = true;
1011 5 : }
1012 :
1013 :
1014 : void
1015 30 : RONet::updateLaneProhibitions(SUMOTime begin) {
1016 30 : const double beginS = STEPS2TIME(begin);
1017 36 : while (myLaneProhibitionTimes.size() > 0 && myLaneProhibitionTimes.begin()->first <= beginS) {
1018 : const double t = myLaneProhibitionTimes.begin()->first;
1019 12 : for (const ROLane* const lane : myLaneProhibitionTimes.begin()->second) {
1020 : const SVCPermissions orig = lane->getPermissions();
1021 : assert(myLaneProhibitions.count(lane) != 0);
1022 6 : RouterProhibition& rp = myLaneProhibitions[lane];
1023 6 : const_cast<ROLane*>(lane)->setPermissions(rp.permissions);
1024 6 : lane->getEdge().resetSuccessors();
1025 6 : for (ROEdge* pred : lane->getEdge().getPredecessors()) {
1026 0 : pred->resetSuccessors();
1027 : }
1028 6 : if (t == rp.begin) {
1029 : // schedule restoration of original permissions. This works
1030 : // without a stack because there is at most one prohibition per lane
1031 3 : myLaneProhibitionTimes[rp.end].insert(lane);
1032 3 : rp.permissions = orig;
1033 : }
1034 : }
1035 : myLaneProhibitionTimes.erase(myLaneProhibitionTimes.begin());
1036 : }
1037 30 : }
1038 :
1039 :
1040 : #ifdef HAVE_FOX
1041 : // ---------------------------------------------------------------------------
1042 : // RONet::RoutingTask-methods
1043 : // ---------------------------------------------------------------------------
1044 : void
1045 179894 : RONet::RoutingTask::run(MFXWorkerThread* context) {
1046 179894 : myRoutable->computeRoute(*static_cast<WorkerThread*>(context), myRemoveLoops, myErrorHandler);
1047 179894 : }
1048 : #endif
1049 :
1050 :
1051 : /****************************************************************************/
|