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