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 5037611 : RONet::getInstance(void) {
57 5037611 : if (myInstance != nullptr) {
58 5037611 : return myInstance;
59 : }
60 0 : throw ProcessError(TL("A network was not yet constructed."));
61 : }
62 :
63 :
64 4250 : RONet::RONet() :
65 4250 : myVehicleTypes(), myDefaultVTypeMayBeDeleted(true),
66 4250 : myDefaultPedTypeMayBeDeleted(true),
67 4250 : myDefaultBikeTypeMayBeDeleted(true),
68 4250 : myDefaultTaxiTypeMayBeDeleted(true),
69 4250 : myDefaultRailTypeMayBeDeleted(true),
70 4250 : myHaveActiveFlows(true),
71 4250 : myRoutesOutput(nullptr), myRouteAlternativesOutput(nullptr), myTypesOutput(nullptr),
72 4250 : myReadRouteNo(0), myDiscardedRouteNo(0), myWrittenRouteNo(0),
73 4250 : myHavePermissions(false),
74 4250 : myHaveParamRestrictions(false),
75 4250 : myNumInternalEdges(0),
76 4250 : myErrorHandler(OptionsCont::getOptions().exists("ignore-errors")
77 8053 : && OptionsCont::getOptions().getBool("ignore-errors") ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
78 4250 : myKeepVTypeDist(OptionsCont::getOptions().exists("keep-vtype-distributions")
79 8053 : && OptionsCont::getOptions().getBool("keep-vtype-distributions")),
80 4250 : myDoPTRouting(!OptionsCont::getOptions().exists("ptline-routing")
81 7593 : || OptionsCont::getOptions().getBool("ptline-routing")),
82 4250 : myKeepFlows(OptionsCont::getOptions().exists("keep-flows")
83 7593 : && OptionsCont::getOptions().getBool("keep-flows")),
84 8500 : myHasBidiEdges(false) {
85 4250 : if (myInstance != nullptr) {
86 0 : throw ProcessError(TL("A network was already constructed."));
87 : }
88 4250 : SUMOVTypeParameter* type = new SUMOVTypeParameter(DEFAULT_VTYPE_ID, SVC_PASSENGER);
89 4250 : type->onlyReferenced = true;
90 4250 : myVehicleTypes.add(type->id, type);
91 :
92 4250 : SUMOVTypeParameter* defPedType = new SUMOVTypeParameter(DEFAULT_PEDTYPE_ID, SVC_PEDESTRIAN);
93 4250 : defPedType->onlyReferenced = true;
94 4250 : defPedType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
95 4250 : myVehicleTypes.add(defPedType->id, defPedType);
96 :
97 4250 : SUMOVTypeParameter* defBikeType = new SUMOVTypeParameter(DEFAULT_BIKETYPE_ID, SVC_BICYCLE);
98 4250 : defBikeType->onlyReferenced = true;
99 4250 : defBikeType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
100 4250 : myVehicleTypes.add(defBikeType->id, defBikeType);
101 :
102 4250 : SUMOVTypeParameter* defTaxiType = new SUMOVTypeParameter(DEFAULT_TAXITYPE_ID, SVC_TAXI);
103 4250 : defTaxiType->onlyReferenced = true;
104 4250 : defTaxiType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
105 4250 : myVehicleTypes.add(defTaxiType->id, defTaxiType);
106 :
107 4250 : SUMOVTypeParameter* defRailType = new SUMOVTypeParameter(DEFAULT_RAILTYPE_ID, SVC_RAIL);
108 4250 : defRailType->onlyReferenced = true;
109 4250 : defRailType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
110 4250 : myVehicleTypes.add(defRailType->id, defRailType);
111 :
112 4250 : myInstance = this;
113 4250 : }
114 :
115 :
116 8043 : RONet::~RONet() {
117 4453 : for (const auto& routables : myRoutables) {
118 426 : for (RORoutable* const r : routables.second) {
119 213 : const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
120 : // delete routes and the vehicle
121 213 : if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
122 204 : if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
123 76 : delete veh->getRouteDefinition();
124 : }
125 : }
126 213 : delete r;
127 : }
128 : }
129 4276 : for (const RORoutable* const r : myPTVehicles) {
130 36 : const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
131 : // delete routes and the vehicle
132 36 : if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
133 36 : if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
134 8 : delete veh->getRouteDefinition();
135 : }
136 : }
137 36 : delete r;
138 : }
139 : myRoutables.clear();
140 4284 : for (const auto& vTypeDist : myVTypeDistDict) {
141 88 : delete vTypeDist.second;
142 : }
143 29243 : }
144 :
145 :
146 : void
147 17 : RONet::addSpeedRestriction(const std::string& id, const SUMOVehicleClass svc, const double speed) {
148 17 : mySpeedRestrictions[id][svc] = speed;
149 17 : }
150 :
151 :
152 : double
153 1286 : RONet::getPreference(const std::string& routingType, const SUMOVTypeParameter& pars) const {
154 1286 : if (gRoutingPreferences) {
155 1286 : auto it = myVTypePreferences.find(pars.id);
156 1286 : if (it != myVTypePreferences.end()) {
157 : auto it2 = it->second.find(routingType);
158 86 : if (it2 != it->second.end()) {
159 22 : return it2->second;
160 : }
161 : }
162 : auto it3 = myVClassPreferences.find(pars.vehicleClass);
163 1264 : if (it3 != myVClassPreferences.end()) {
164 : auto it4 = it3->second.find(routingType);
165 176 : if (it4 != it3->second.end()) {
166 47 : return it4->second;
167 : }
168 : }
169 : // fallback to generel preferences
170 1217 : it = myVTypePreferences.find("");
171 1217 : if (it != myVTypePreferences.end()) {
172 : auto it2 = it->second.find(routingType);
173 774 : if (it2 != it->second.end()) {
174 140 : return it2->second;
175 : }
176 : }
177 : }
178 : return 1;
179 : }
180 :
181 :
182 : void
183 24 : RONet::addPreference(const std::string& routingType, SUMOVehicleClass svc, double prio) {
184 24 : myVClassPreferences[svc][routingType] = prio;
185 24 : gRoutingPreferences = true;
186 24 : }
187 :
188 :
189 : void
190 32 : RONet::addPreference(const std::string& routingType, std::string vType, double prio) {
191 32 : myVTypePreferences[vType][routingType] = prio;
192 32 : gRoutingPreferences = true;
193 32 : }
194 :
195 :
196 :
197 : const std::map<SUMOVehicleClass, double>*
198 66 : RONet::getRestrictions(const std::string& id) const {
199 : std::map<std::string, std::map<SUMOVehicleClass, double> >::const_iterator i = mySpeedRestrictions.find(id);
200 66 : if (i == mySpeedRestrictions.end()) {
201 : return nullptr;
202 : }
203 26 : return &i->second;
204 : }
205 :
206 :
207 : bool
208 327249 : RONet::addEdge(ROEdge* edge) {
209 327249 : if (!myEdges.add(edge->getID(), edge)) {
210 36 : WRITE_ERRORF(TL("The edge '%' occurs at least twice."), edge->getID());
211 12 : delete edge;
212 12 : return false;
213 : }
214 327237 : if (edge->isInternal()) {
215 159922 : myNumInternalEdges += 1;
216 : }
217 : return true;
218 : }
219 :
220 :
221 : bool
222 1816 : RONet::addDistrict(const std::string id, ROEdge* source, ROEdge* sink) {
223 : if (myDistricts.count(id) > 0) {
224 0 : WRITE_ERRORF(TL("The TAZ '%' occurs at least twice."), id);
225 0 : delete source;
226 0 : delete sink;
227 0 : return false;
228 : }
229 : sink->setFunction(SumoXMLEdgeFunc::CONNECTOR);
230 1816 : if (!addEdge(sink)) {
231 : return false;
232 : }
233 : source->setFunction(SumoXMLEdgeFunc::CONNECTOR);
234 1816 : if (!addEdge(source)) {
235 : return false;
236 : }
237 : sink->setOtherTazConnector(source);
238 : source->setOtherTazConnector(sink);
239 3632 : myDistricts[id] = std::make_pair(std::vector<std::string>(), std::vector<std::string>());
240 1816 : return true;
241 : }
242 :
243 :
244 : bool
245 1379 : RONet::addDistrictEdge(const std::string tazID, const std::string edgeID, const bool isSource) {
246 : if (myDistricts.count(tazID) == 0) {
247 0 : WRITE_ERRORF(TL("The TAZ '%' is unknown."), tazID);
248 0 : return false;
249 : }
250 : ROEdge* edge = getEdge(edgeID);
251 1379 : if (edge == nullptr) {
252 0 : WRITE_ERRORF(TL("The edge '%' for TAZ '%' is unknown."), edgeID, tazID);
253 0 : return false;
254 : }
255 1379 : if (isSource) {
256 2067 : getEdge(tazID + "-source")->addSuccessor(edge);
257 689 : myDistricts[tazID].first.push_back(edgeID);
258 : } else {
259 2070 : edge->addSuccessor(getEdge(tazID + "-sink"));
260 690 : myDistricts[tazID].second.push_back(edgeID);
261 : }
262 : return true;
263 : }
264 :
265 :
266 : void
267 101 : RONet::addJunctionTaz(ROAbstractEdgeBuilder& eb) {
268 1544 : for (auto item : myNodes) {
269 : const std::string tazID = item.first;
270 8 : if (myDistricts.count(tazID) != 0) {
271 24 : WRITE_WARNINGF(TL("A TAZ with id '%' already exists. Not building junction TAZ."), tazID);
272 8 : continue;
273 : }
274 1435 : const std::string sourceID = tazID + "-source";
275 1435 : const std::string sinkID = tazID + "-sink";
276 : // sink must be added before source
277 2870 : ROEdge* sink = eb.buildEdge(sinkID, nullptr, nullptr, 0, "", "");
278 2870 : ROEdge* source = eb.buildEdge(sourceID, nullptr, nullptr, 0, "", "");
279 : sink->setOtherTazConnector(source);
280 : source->setOtherTazConnector(sink);
281 2870 : if (!addDistrict(tazID, source, sink)) {
282 : continue;
283 : }
284 1435 : auto& district = myDistricts[tazID];
285 1435 : const RONode* junction = item.second;
286 12452 : for (const ROEdge* edge : junction->getIncoming()) {
287 11017 : if (!edge->isInternal()) {
288 3129 : const_cast<ROEdge*>(edge)->addSuccessor(sink);
289 3129 : district.second.push_back(edge->getID());
290 : }
291 : }
292 12452 : for (const ROEdge* edge : junction->getOutgoing()) {
293 11017 : if (!edge->isInternal()) {
294 3129 : source->addSuccessor(const_cast<ROEdge*>(edge));
295 3129 : district.first.push_back(edge->getID());
296 : }
297 : }
298 : }
299 101 : }
300 :
301 :
302 : void
303 3519 : RONet::setBidiEdges(const std::map<ROEdge*, std::string>& bidiMap) {
304 15603 : for (const auto& item : bidiMap) {
305 12084 : ROEdge* bidi = myEdges.get(item.second);
306 12084 : if (bidi == nullptr) {
307 0 : WRITE_ERRORF(TL("The bidi edge '%' is not known."), item.second);
308 : }
309 12084 : item.first->setBidiEdge(bidi);
310 12084 : myHasBidiEdges = true;
311 : }
312 3519 : }
313 :
314 :
315 : void
316 73204 : RONet::addNode(RONode* node) {
317 73204 : if (!myNodes.add(node->getID(), node)) {
318 0 : WRITE_ERRORF(TL("The node '%' occurs at least twice."), node->getID());
319 0 : delete node;
320 : }
321 73204 : }
322 :
323 :
324 : void
325 1968 : RONet::addStoppingPlace(const std::string& id, const SumoXMLTag category, SUMOVehicleParameter::Stop* stop) {
326 3816 : if (!myStoppingPlaces[category == SUMO_TAG_TRAIN_STOP ? SUMO_TAG_BUS_STOP : category].add(id, stop)) {
327 12 : WRITE_ERRORF(TL("The % '%' occurs at least twice."), toString(category), id);
328 4 : delete stop;
329 : }
330 1968 : }
331 :
332 :
333 : bool
334 280945 : RONet::addRouteDef(RORouteDef* def) {
335 280945 : return myRoutes.add(def->getID(), def);
336 : }
337 :
338 :
339 : void
340 2820 : RONet::openOutput(const OptionsCont& options) {
341 8458 : if (options.isSet("output-file") && options.getString("output-file") != "") {
342 2819 : myRoutesOutput = &OutputDevice::getDevice(options.getString("output-file"));
343 2813 : if (myRoutesOutput->isNull()) {
344 1 : myRoutesOutput = nullptr;
345 : } else {
346 5624 : myRoutesOutput->writeXMLHeader("routes", "routes_file.xsd");
347 : }
348 : }
349 8262 : if (options.exists("alternatives-output") && options.isSet("alternatives-output")
350 13154 : && !(options.exists("write-trips") && options.getBool("write-trips"))) {
351 2440 : myRouteAlternativesOutput = &OutputDevice::getDevice(options.getString("alternatives-output"));
352 2440 : if (myRouteAlternativesOutput->isNull()) {
353 132 : myRouteAlternativesOutput = nullptr;
354 : } else {
355 4616 : myRouteAlternativesOutput->writeXMLHeader("routes", "routes_file.xsd");
356 : }
357 : }
358 5628 : if (options.isSet("vtype-output")) {
359 32 : myTypesOutput = &OutputDevice::getDevice(options.getString("vtype-output"));
360 64 : myTypesOutput->writeXMLHeader("routes", "routes_file.xsd");
361 : }
362 2814 : }
363 :
364 :
365 : void
366 2602 : RONet::writeIntermodal(const OptionsCont& options, ROIntermodalRouter& router) const {
367 5204 : if (options.exists("intermodal-network-output") && options.isSet("intermodal-network-output")) {
368 32 : OutputDevice::createDeviceByOption("intermodal-network-output", "intermodal");
369 32 : router.writeNetwork(OutputDevice::getDevice(options.getString("intermodal-network-output")));
370 : }
371 5204 : if (options.exists("intermodal-weight-output") && options.isSet("intermodal-weight-output")) {
372 16 : OutputDevice::createDeviceByOption("intermodal-weight-output", "weights", "meandata_file.xsd");
373 8 : OutputDevice& dev = OutputDevice::getDeviceByOption("intermodal-weight-output");
374 8 : dev.openTag(SUMO_TAG_INTERVAL);
375 8 : dev.writeAttr(SUMO_ATTR_ID, "intermodalweights");
376 8 : dev.writeAttr(SUMO_ATTR_BEGIN, 0);
377 8 : dev.writeAttr(SUMO_ATTR_END, SUMOTime_MAX);
378 8 : router.writeWeights(dev);
379 16 : dev.closeTag();
380 : }
381 2602 : }
382 :
383 :
384 : void
385 2819 : RONet::cleanup() {
386 : // end writing
387 2819 : if (myRoutesOutput != nullptr) {
388 2812 : myRoutesOutput->close();
389 : }
390 : // only if opened
391 2819 : if (myRouteAlternativesOutput != nullptr) {
392 2308 : myRouteAlternativesOutput->close();
393 : }
394 : // only if opened
395 2819 : if (myTypesOutput != nullptr) {
396 32 : myTypesOutput->close();
397 : }
398 : RouteCostCalculator<RORoute, ROEdge, ROVehicle>::cleanup();
399 : #ifdef HAVE_FOX
400 2819 : if (myThreadPool.size() > 0) {
401 30 : myThreadPool.clear();
402 : }
403 : #endif
404 2819 : }
405 :
406 :
407 :
408 : SUMOVTypeParameter*
409 495733 : RONet::getVehicleTypeSecure(const std::string& id) {
410 : // check whether the type was already known
411 : SUMOVTypeParameter* type = myVehicleTypes.get(id);
412 495733 : if (id == DEFAULT_VTYPE_ID) {
413 455100 : myDefaultVTypeMayBeDeleted = false;
414 40633 : } else if (id == DEFAULT_PEDTYPE_ID) {
415 5324 : myDefaultPedTypeMayBeDeleted = false;
416 35309 : } else if (id == DEFAULT_BIKETYPE_ID) {
417 54 : myDefaultBikeTypeMayBeDeleted = false;
418 35255 : } else if (id == DEFAULT_TAXITYPE_ID) {
419 93 : myDefaultTaxiTypeMayBeDeleted = false;
420 35162 : } else if (id == DEFAULT_RAILTYPE_ID) {
421 0 : myDefaultRailTypeMayBeDeleted = false;
422 : }
423 495733 : if (type != nullptr) {
424 : return type;
425 : }
426 : VTypeDistDictType::iterator it2 = myVTypeDistDict.find(id);
427 1478 : if (it2 != myVTypeDistDict.end()) {
428 1148 : return it2->second->get();
429 : }
430 330 : if (id == "") {
431 : // ok, no vehicle type or an unknown type was given within the user input
432 : // return the default type
433 0 : myDefaultVTypeMayBeDeleted = false;
434 : return myVehicleTypes.get(DEFAULT_VTYPE_ID);
435 : }
436 : return type;
437 : }
438 :
439 :
440 : bool
441 2102 : RONet::checkVType(const std::string& id) {
442 2102 : if (id == DEFAULT_VTYPE_ID) {
443 65 : if (myDefaultVTypeMayBeDeleted) {
444 65 : myVehicleTypes.remove(id);
445 65 : myDefaultVTypeMayBeDeleted = false;
446 : } else {
447 : return false;
448 : }
449 2037 : } else if (id == DEFAULT_PEDTYPE_ID) {
450 0 : if (myDefaultPedTypeMayBeDeleted) {
451 0 : myVehicleTypes.remove(id);
452 0 : myDefaultPedTypeMayBeDeleted = false;
453 : } else {
454 : return false;
455 : }
456 2037 : } else if (id == DEFAULT_BIKETYPE_ID) {
457 0 : if (myDefaultBikeTypeMayBeDeleted) {
458 0 : myVehicleTypes.remove(id);
459 0 : myDefaultBikeTypeMayBeDeleted = false;
460 : } else {
461 : return false;
462 : }
463 2037 : } else if (id == DEFAULT_TAXITYPE_ID) {
464 0 : if (myDefaultTaxiTypeMayBeDeleted) {
465 0 : myVehicleTypes.remove(id);
466 0 : myDefaultTaxiTypeMayBeDeleted = false;
467 : } else {
468 : return false;
469 : }
470 2037 : } else if (id == DEFAULT_RAILTYPE_ID) {
471 0 : if (myDefaultRailTypeMayBeDeleted) {
472 0 : myVehicleTypes.remove(id);
473 0 : myDefaultRailTypeMayBeDeleted = false;
474 : } else {
475 : return false;
476 : }
477 : } else {
478 2037 : if (myVehicleTypes.get(id) != 0 || myVTypeDistDict.find(id) != myVTypeDistDict.end()) {
479 0 : return false;
480 : }
481 : }
482 : return true;
483 : }
484 :
485 :
486 : bool
487 2058 : RONet::addVehicleType(SUMOVTypeParameter* type) {
488 2058 : if (checkVType(type->id)) {
489 2058 : myVehicleTypes.add(type->id, type);
490 : } else {
491 0 : WRITE_ERRORF(TL("The vehicle type '%' occurs at least twice."), type->id);
492 0 : delete type;
493 0 : return false;
494 : }
495 2058 : return true;
496 : }
497 :
498 :
499 : bool
500 44 : RONet::addVTypeDistribution(const std::string& id, RandomDistributor<SUMOVTypeParameter*>* vehTypeDistribution) {
501 44 : if (checkVType(id)) {
502 44 : myVTypeDistDict[id] = vehTypeDistribution;
503 44 : return true;
504 : }
505 0 : delete vehTypeDistribution;
506 : return false;
507 : }
508 :
509 :
510 : bool
511 296877 : RONet::addVehicle(const std::string& id, ROVehicle* veh) {
512 296877 : if (myVehIDs.find(id) == myVehIDs.end()) {
513 593714 : myVehIDs[id] = veh->getParameter().departProcedure == DepartDefinition::TRIGGERED ? -1 : veh->getDepartureTime();
514 :
515 296873 : if (veh->isPublicTransport()) {
516 44 : if (!veh->isPartOfFlow()) {
517 36 : myPTVehicles.push_back(veh);
518 : }
519 44 : if (!myDoPTRouting) {
520 : return true;
521 : }
522 : }
523 296837 : myRoutables[veh->getDepart()].push_back(veh);
524 296837 : return true;
525 : }
526 12 : WRITE_ERRORF(TL("Another vehicle with the id '%' exists."), id);
527 4 : delete veh;
528 : return false;
529 : }
530 :
531 :
532 : bool
533 256 : RONet::knowsVehicle(const std::string& id) const {
534 256 : return myVehIDs.find(id) != myVehIDs.end();
535 : }
536 :
537 : SUMOTime
538 28 : RONet::getDeparture(const std::string& vehID) const {
539 : auto it = myVehIDs.find(vehID);
540 28 : if (it != myVehIDs.end()) {
541 28 : return it->second;
542 : } else {
543 0 : throw ProcessError(TLF("Requesting departure time for unknown vehicle '%'", vehID));
544 : }
545 : }
546 :
547 :
548 : bool
549 2550 : RONet::addFlow(SUMOVehicleParameter* flow, const bool randomize) {
550 2550 : if (randomize && flow->repetitionOffset >= 0) {
551 10 : myDepartures[flow->id].reserve(flow->repetitionNumber);
552 110 : for (int i = 0; i < flow->repetitionNumber; ++i) {
553 100 : myDepartures[flow->id].push_back(flow->depart + RandHelper::rand(flow->repetitionNumber * flow->repetitionOffset));
554 : }
555 10 : std::sort(myDepartures[flow->id].begin(), myDepartures[flow->id].end());
556 10 : std::reverse(myDepartures[flow->id].begin(), myDepartures[flow->id].end());
557 : }
558 2550 : const bool added = myFlows.add(flow->id, flow);
559 2550 : if (added) {
560 2546 : myHaveActiveFlows = true;
561 : }
562 2550 : return added;
563 : }
564 :
565 :
566 : bool
567 3338 : RONet::addPerson(ROPerson* person) {
568 : if (myPersonIDs.count(person->getID()) == 0) {
569 : myPersonIDs.insert(person->getID());
570 3338 : myRoutables[person->getDepart()].push_back(person);
571 3338 : return true;
572 : }
573 0 : WRITE_ERRORF(TL("Another person with the id '%' exists."), person->getID());
574 0 : return false;
575 : }
576 :
577 :
578 : void
579 56 : RONet::addContainer(const SUMOTime depart, const std::string desc) {
580 56 : myContainers.insert(std::pair<const SUMOTime, const std::string>(depart, desc));
581 56 : }
582 :
583 :
584 : void
585 13246 : RONet::checkFlows(SUMOTime time, MsgHandler* errorHandler) {
586 13246 : myHaveActiveFlows = false;
587 51178 : for (const auto& i : myFlows) {
588 37932 : SUMOVehicleParameter* const pars = i.second;
589 37932 : if (pars->line != "" && !myDoPTRouting) {
590 737 : continue;
591 : }
592 37195 : if (myKeepFlows) {
593 796 : if (pars->repetitionsDone < pars->repetitionNumber) {
594 : // each each flow only once
595 790 : pars->repetitionsDone = pars->repetitionNumber;
596 790 : const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
597 790 : if (type == nullptr) {
598 0 : type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
599 : } else {
600 : auto dist = getVTypeDistribution(pars->vtypeid);
601 0 : if (dist != nullptr) {
602 0 : WRITE_WARNINGF("Keeping flow '%' with a vTypeDistribution can lead to invalid routes if the distribution contains different vClasses", pars->id);
603 : }
604 : }
605 1580 : RORouteDef* route = getRouteDef(pars->routeid)->copy(pars->routeid, pars->depart);
606 790 : ROVehicle* veh = new ROVehicle(*pars, route, type, this, errorHandler);
607 790 : addVehicle(pars->id, veh);
608 : }
609 36399 : } else if (pars->repetitionProbability > 0) {
610 108 : if (pars->repetitionEnd > pars->depart && pars->repetitionsDone < pars->repetitionNumber) {
611 96 : myHaveActiveFlows = true;
612 : }
613 : const SUMOTime origDepart = pars->depart;
614 1020 : while (pars->depart < time && pars->repetitionsDone < pars->repetitionNumber) {
615 928 : if (pars->repetitionEnd <= pars->depart) {
616 : break;
617 : }
618 : // only call rand if all other conditions are met
619 912 : if (RandHelper::rand() < (pars->repetitionProbability * TS)) {
620 168 : SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
621 336 : newPars->id = pars->id + "." + toString(pars->repetitionsDone);
622 168 : newPars->depart = pars->depart;
623 168 : for (StopParVector::iterator stop = newPars->stops.begin(); stop != newPars->stops.end(); ++stop) {
624 0 : if (stop->until >= 0) {
625 0 : stop->until += pars->depart - origDepart;
626 : }
627 : }
628 168 : pars->repetitionsDone++;
629 : // try to build the vehicle
630 168 : const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
631 168 : if (type == nullptr) {
632 32 : type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
633 136 : } else if (!myKeepVTypeDist) {
634 : // fix the type id in case we used a distribution
635 136 : newPars->vtypeid = type->id;
636 : }
637 168 : const SUMOTime stopOffset = pars->routeid[0] == '!' ? pars->depart - origDepart : pars->depart;
638 336 : RORouteDef* route = getRouteDef(pars->routeid)->copy("!" + newPars->id, stopOffset);
639 168 : ROVehicle* veh = new ROVehicle(*newPars, route, type, this, errorHandler);
640 168 : addVehicle(newPars->id, veh);
641 168 : delete newPars;
642 : }
643 912 : pars->depart += DELTA_T;
644 : }
645 : } else {
646 36291 : SUMOTime depart = static_cast<SUMOTime>(pars->depart + pars->repetitionTotalOffset);
647 54019 : while (pars->repetitionsDone < pars->repetitionNumber && pars->repetitionEnd >= depart) {
648 28450 : myHaveActiveFlows = true;
649 28450 : depart = static_cast<SUMOTime>(pars->depart + pars->repetitionTotalOffset);
650 28450 : if (myDepartures.find(pars->id) != myDepartures.end()) {
651 110 : depart = myDepartures[pars->id].back();
652 : }
653 28450 : if (depart >= time + DELTA_T) {
654 : break;
655 : }
656 17728 : if (myDepartures.find(pars->id) != myDepartures.end()) {
657 100 : myDepartures[pars->id].pop_back();
658 : }
659 17728 : SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
660 35456 : newPars->id = pars->id + "." + toString(pars->repetitionsDone);
661 17728 : newPars->depart = depart;
662 17848 : for (StopParVector::iterator stop = newPars->stops.begin(); stop != newPars->stops.end(); ++stop) {
663 120 : if (stop->until >= 0) {
664 0 : stop->until += depart - pars->depart;
665 : }
666 : }
667 17728 : pars->incrementFlow(1);
668 : // try to build the vehicle
669 17728 : const SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
670 17728 : if (type == nullptr) {
671 62 : type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
672 17666 : } else if (!myKeepVTypeDist) {
673 : // fix the type id in case we used a distribution
674 17626 : newPars->vtypeid = type->id;
675 : }
676 17728 : const SUMOTime stopOffset = pars->routeid[0] == '!' ? depart - pars->depart : depart;
677 35456 : RORouteDef* route = getRouteDef(pars->routeid)->copy("!" + newPars->id, stopOffset);
678 17728 : ROVehicle* veh = new ROVehicle(*newPars, route, type, this, errorHandler);
679 17728 : addVehicle(newPars->id, veh);
680 17728 : delete newPars;
681 : }
682 : }
683 : }
684 13246 : }
685 :
686 :
687 : void
688 56 : RONet::createBulkRouteRequests(const RORouterProvider& provider, const SUMOTime time, const bool removeLoops) {
689 : std::map<const int, std::vector<RORoutable*> > bulkVehs;
690 : int numBulked = 0;
691 84 : for (RoutablesMap::const_iterator i = myRoutables.begin(); i != myRoutables.end(); ++i) {
692 56 : if (i->first >= time) {
693 : break;
694 : }
695 539 : for (RORoutable* const routable : i->second) {
696 511 : const ROEdge* const depEdge = routable->getDepartEdge();
697 511 : bulkVehs[depEdge->getNumericalID()].push_back(routable);
698 511 : RORoutable* const first = bulkVehs[depEdge->getNumericalID()].front();
699 511 : numBulked++;
700 511 : if (first->getMaxSpeed() != routable->getMaxSpeed()) {
701 6 : WRITE_WARNINGF(TL("Bulking different maximum speeds ('%' and '%') may lead to suboptimal routes."), first->getID(), routable->getID());
702 : }
703 511 : if (first->getVClass() != routable->getVClass()) {
704 6 : WRITE_WARNINGF(TL("Bulking different vehicle classes ('%' and '%') may lead to invalid routes."), first->getID(), routable->getID());
705 : }
706 : }
707 : }
708 : #ifdef HAVE_FOX
709 : int workerIndex = 0;
710 : #endif
711 56 : if ((int)bulkVehs.size() < numBulked) {
712 56 : WRITE_MESSAGE(TLF("Using bulk-mode for % entities from % origins", numBulked, bulkVehs.size()));
713 : }
714 157 : for (std::map<const int, std::vector<RORoutable*> >::const_iterator i = bulkVehs.begin(); i != bulkVehs.end(); ++i) {
715 : #ifdef HAVE_FOX
716 101 : if (myThreadPool.size() > 0) {
717 : bool bulk = true;
718 132 : for (RORoutable* const r : i->second) {
719 120 : myThreadPool.add(new RoutingTask(r, removeLoops, myErrorHandler), workerIndex);
720 120 : if (bulk) {
721 12 : myThreadPool.add(new BulkmodeTask(true), workerIndex);
722 : bulk = false;
723 : }
724 : }
725 12 : myThreadPool.add(new BulkmodeTask(false), workerIndex);
726 12 : workerIndex++;
727 12 : if (workerIndex == (int)myThreadPool.size()) {
728 : workerIndex = 0;
729 : }
730 12 : continue;
731 12 : }
732 : #endif
733 480 : for (RORoutable* const r : i->second) {
734 391 : r->computeRoute(provider, removeLoops, myErrorHandler);
735 391 : provider.setBulkMode(true);
736 : }
737 89 : provider.setBulkMode(false);
738 : }
739 56 : }
740 :
741 :
742 : SUMOTime
743 19236 : RONet::saveAndRemoveRoutesUntil(OptionsCont& options, const RORouterProvider& provider,
744 : SUMOTime time) {
745 19236 : MsgHandler* mh = (options.getBool("ignore-errors") ?
746 19236 : MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance());
747 19236 : if (myHaveActiveFlows) {
748 13246 : checkFlows(time, mh);
749 : }
750 : SUMOTime lastTime = -1;
751 19236 : const bool removeLoops = options.getBool("remove-loops");
752 : #ifdef HAVE_FOX
753 38472 : const int maxNumThreads = options.getInt("routing-threads");
754 : #endif
755 19236 : if (myRoutables.size() != 0) {
756 18446 : if (options.getBool("bulk-routing")) {
757 : #ifdef HAVE_FOX
758 64 : while ((int)myThreadPool.size() < maxNumThreads) {
759 8 : new WorkerThread(myThreadPool, provider);
760 : }
761 : #endif
762 56 : createBulkRouteRequests(provider, time, removeLoops);
763 : } else {
764 250973 : for (RoutablesMap::const_iterator i = myRoutables.begin(); i != myRoutables.end(); ++i) {
765 248228 : if (i->first >= time) {
766 : break;
767 : }
768 541273 : for (RORoutable* const routable : i->second) {
769 : #ifdef HAVE_FOX
770 : // add task
771 299467 : if (maxNumThreads > 0) {
772 : const int numThreads = (int)myThreadPool.size();
773 827 : if (numThreads == 0) {
774 : // This is the very first routing. Since at least the CHRouter needs initialization
775 : // before it gets cloned, we do not do this in parallel
776 24 : routable->computeRoute(provider, removeLoops, myErrorHandler);
777 24 : new WorkerThread(myThreadPool, provider);
778 : } else {
779 : // add thread if necessary
780 803 : if (numThreads < maxNumThreads && myThreadPool.isFull()) {
781 18 : new WorkerThread(myThreadPool, provider);
782 : }
783 803 : myThreadPool.add(new RoutingTask(routable, removeLoops, myErrorHandler));
784 : }
785 827 : continue;
786 827 : }
787 : #endif
788 298640 : routable->computeRoute(provider, removeLoops, myErrorHandler);
789 : }
790 : }
791 : }
792 : #ifdef HAVE_FOX
793 9207 : myThreadPool.waitAll();
794 : #endif
795 : }
796 38168 : const double scale = options.exists("scale-suffix") ? options.getFloat("scale") : 1;
797 : // write all vehicles (and additional structures)
798 261102 : while (myRoutables.size() != 0 || myContainers.size() != 0) {
799 : // get the next vehicle, person or container
800 : RoutablesMap::iterator routables = myRoutables.begin();
801 248324 : const SUMOTime routableTime = routables == myRoutables.end() ? SUMOTime_MAX : routables->first;
802 : ContainerMap::iterator container = myContainers.begin();
803 248324 : const SUMOTime containerTime = container == myContainers.end() ? SUMOTime_MAX : container->first;
804 : // check whether it shall not yet be computed
805 248324 : if (routableTime >= time && containerTime >= time) {
806 : lastTime = MIN2(routableTime, containerTime);
807 : break;
808 : }
809 : const SUMOTime minTime = MIN2(routableTime, containerTime);
810 241882 : if (routableTime == minTime) {
811 : // check whether to print the output
812 241834 : if (lastTime != routableTime && lastTime != -1) {
813 : // report writing progress
814 235666 : if (options.getInt("stats-period") >= 0 && ((int)routableTime % options.getInt("stats-period")) == 0) {
815 0 : WRITE_MESSAGE("Read: " + toString(myVehIDs.size()) + ", Discarded: " + toString(myDiscardedRouteNo) + ", Written: " + toString(myWrittenRouteNo));
816 : }
817 : }
818 : lastTime = routableTime;
819 541796 : for (const RORoutable* const r : routables->second) {
820 : // ok, check whether it has been routed
821 299962 : if (r->getRoutingSuccess()) {
822 : // write the route
823 280773 : int quota = getScalingQuota(scale, myWrittenRouteNo);
824 280773 : r->write(myRoutesOutput, myRouteAlternativesOutput, myTypesOutput, options, quota);
825 280773 : myWrittenRouteNo++;
826 : } else {
827 19189 : myDiscardedRouteNo++;
828 : }
829 : // we need to keep individual public transport vehicles but not the flows
830 299962 : if (!r->isPublicTransport() || r->isPartOfFlow()) {
831 : // delete routes and the vehicle
832 299962 : const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
833 299962 : if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
834 296633 : if (r->isPartOfFlow() || !myRoutes.remove(veh->getRouteDefinition()->getID())) {
835 19877 : delete veh->getRouteDefinition();
836 : }
837 : }
838 299962 : delete r;
839 : }
840 : }
841 : myRoutables.erase(routables);
842 : }
843 241882 : if (containerTime == minTime) {
844 48 : myRoutesOutput->writePreformattedTag(container->second);
845 48 : if (myRouteAlternativesOutput != nullptr) {
846 : myRouteAlternativesOutput->writePreformattedTag(container->second);
847 : }
848 : myContainers.erase(container);
849 : }
850 : }
851 19220 : return lastTime;
852 : }
853 :
854 :
855 : bool
856 41199 : RONet::furtherStored() {
857 41199 : return myRoutables.size() > 0 || (myFlows.size() > 0 && myHaveActiveFlows) || myContainers.size() > 0;
858 : }
859 :
860 :
861 : int
862 123 : RONet::getEdgeNumber() const {
863 123 : return myEdges.size();
864 : }
865 :
866 :
867 : int
868 1 : RONet::getInternalEdgeNumber() const {
869 1 : return myNumInternalEdges;
870 : }
871 :
872 :
873 : ROEdge*
874 9031 : RONet::getEdgeForLaneID(const std::string& laneID) const {
875 18062 : return getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(laneID));
876 : }
877 :
878 :
879 : ROLane*
880 1136 : RONet::getLane(const std::string& laneID) const {
881 1136 : int laneIndex = SUMOXMLDefinitions::getIndexFromLane(laneID);
882 1136 : return getEdgeForLaneID(laneID)->getLanes()[laneIndex];
883 : }
884 :
885 :
886 : void
887 593 : RONet::adaptIntermodalRouter(ROIntermodalRouter& router) {
888 593 : double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
889 880 : for (const auto& stopType : myInstance->myStoppingPlaces) {
890 : // add access to all stopping places
891 287 : const SumoXMLTag element = stopType.first;
892 2062 : for (const auto& stop : stopType.second) {
893 1775 : router.getNetwork()->addAccess(stop.first, myInstance->getEdgeForLaneID(stop.second->lane),
894 1775 : stop.second->startPos, stop.second->endPos, 0., element, false, taxiWait);
895 : // add access to all public transport stops
896 1775 : if (element == SUMO_TAG_BUS_STOP) {
897 3831 : for (const auto& a : stop.second->accessPos) {
898 2076 : router.getNetwork()->addAccess(stop.first, myInstance->getEdgeForLaneID(std::get<0>(a)),
899 : std::get<1>(a), std::get<1>(a), std::get<2>(a), SUMO_TAG_BUS_STOP, true, taxiWait);
900 : }
901 : }
902 : }
903 : }
904 : // fill the public transport router with pre-parsed public transport lines
905 1346 : for (const auto& i : myInstance->myFlows) {
906 753 : if (i.second->line != "") {
907 741 : const RORouteDef* const route = myInstance->getRouteDef(i.second->routeid);
908 : const StopParVector* addStops = nullptr;
909 1482 : if (route != nullptr && route->getFirstRoute() != nullptr) {
910 : addStops = &route->getFirstRoute()->getStops();
911 : }
912 741 : router.getNetwork()->addSchedule(*i.second, addStops);
913 : }
914 : }
915 629 : for (const RORoutable* const veh : myInstance->myPTVehicles) {
916 : // add single vehicles with line attribute which are not part of a flow
917 : // no need to add route stops here, they have been added to the vehicle before
918 36 : router.getNetwork()->addSchedule(veh->getParameter());
919 : }
920 : // add access to transfer from walking to taxi-use
921 593 : if ((router.getCarWalkTransfer() & ModeChangeOptions::TAXI_PICKUP_ANYWHERE) != 0) {
922 81723 : for (const ROEdge* edge : ROEdge::getAllEdges()) {
923 81142 : if (!edge->isTazConnector() && (edge->getPermissions() & SVC_PEDESTRIAN) != 0 && (edge->getPermissions() & SVC_TAXI) != 0) {
924 22470 : router.getNetwork()->addCarAccess(edge, SVC_TAXI, taxiWait);
925 : }
926 : }
927 : }
928 593 : }
929 :
930 :
931 : bool
932 4186459 : RONet::hasPermissions() const {
933 4186459 : return myHavePermissions;
934 : }
935 :
936 :
937 : void
938 252972 : RONet::setPermissionsFound() {
939 252972 : myHavePermissions = true;
940 252972 : }
941 :
942 : bool
943 12 : RONet::hasLoadedEffort() const {
944 38 : for (const auto& item : myEdges) {
945 35 : if (item.second->hasStoredEffort()) {
946 : return true;
947 : }
948 : }
949 : return false;
950 : }
951 :
952 : const std::string
953 1591 : RONet::getStoppingPlaceName(const std::string& id) const {
954 1783 : for (const auto& mapItem : myStoppingPlaces) {
955 : SUMOVehicleParameter::Stop* stop = mapItem.second.get(id);
956 1591 : if (stop != nullptr) {
957 : // see RONetHandler::parseStoppingPlace
958 : return stop->busstop;
959 : }
960 : }
961 0 : return "";
962 : }
963 :
964 : const std::string
965 1471 : RONet::getStoppingPlaceElement(const std::string& id) const {
966 1615 : for (const auto& mapItem : myStoppingPlaces) {
967 : SUMOVehicleParameter::Stop* stop = mapItem.second.get(id);
968 1471 : if (stop != nullptr) {
969 : // see RONetHandler::parseStoppingPlace
970 : return stop->actType;
971 : }
972 : }
973 0 : return toString(SUMO_TAG_BUS_STOP);
974 : }
975 :
976 :
977 : #ifdef HAVE_FOX
978 : // ---------------------------------------------------------------------------
979 : // RONet::RoutingTask-methods
980 : // ---------------------------------------------------------------------------
981 : void
982 923 : RONet::RoutingTask::run(MFXWorkerThread* context) {
983 923 : myRoutable->computeRoute(*static_cast<WorkerThread*>(context), myRemoveLoops, myErrorHandler);
984 923 : }
985 : #endif
986 :
987 :
988 : /****************************************************************************/
|