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