1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file RONet.cpp
11 /// @author Daniel Krajzewicz
12 /// @author Jakob Erdmann
13 /// @author Michael Behrisch
14 /// @date Sept 2002
15 /// @version $Id$
16 ///
17 // The router's network representation
18 /****************************************************************************/
19
20
21 // ===========================================================================
22 // included modules
23 // ===========================================================================
24 #include <config.h>
25
26 #include <algorithm>
27 #include <utils/router/RouteCostCalculator.h>
28 #include <utils/vehicle/SUMOVTypeParameter.h>
29 #include <utils/router/SUMOAbstractRouter.h>
30 #include <utils/options/OptionsCont.h>
31 #include <utils/common/UtilExceptions.h>
32 #include <utils/common/ToString.h>
33 #include <utils/common/RandHelper.h>
34 #include <utils/common/SUMOVehicleClass.h>
35 #include <utils/iodevices/OutputDevice.h>
36 #include "ROEdge.h"
37 #include "ROLane.h"
38 #include "RONode.h"
39 #include "ROPerson.h"
40 #include "RORoute.h"
41 #include "RORouteDef.h"
42 #include "ROVehicle.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*
getInstance(void)56 RONet::getInstance(void) {
57 if (myInstance != nullptr) {
58 return myInstance;
59 }
60 throw ProcessError("A network was not yet constructed.");
61 }
62
63
RONet()64 RONet::RONet()
65 : myVehicleTypes(), myDefaultVTypeMayBeDeleted(true),
66 myDefaultPedTypeMayBeDeleted(true), myDefaultBikeTypeMayBeDeleted(true),
67 myHaveActiveFlows(true),
68 myRoutesOutput(nullptr), myRouteAlternativesOutput(nullptr), myTypesOutput(nullptr),
69 myReadRouteNo(0), myDiscardedRouteNo(0), myWrittenRouteNo(0),
70 myHavePermissions(false),
71 myNumInternalEdges(0),
72 myErrorHandler(OptionsCont::getOptions().exists("ignore-errors")
73 && OptionsCont::getOptions().getBool("ignore-errors") ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
74 myKeepVTypeDist(OptionsCont::getOptions().exists("keep-vtype-distributions")
75 && OptionsCont::getOptions().getBool("keep-vtype-distributions")) {
76 if (myInstance != nullptr) {
77 throw ProcessError("A network was already constructed.");
78 }
79 SUMOVTypeParameter* type = new SUMOVTypeParameter(DEFAULT_VTYPE_ID, SVC_PASSENGER);
80 type->onlyReferenced = true;
81 myVehicleTypes.add(type->id, type);
82 SUMOVTypeParameter* defPedType = new SUMOVTypeParameter(DEFAULT_PEDTYPE_ID, SVC_PEDESTRIAN);
83 defPedType->onlyReferenced = true;
84 defPedType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
85 myVehicleTypes.add(defPedType->id, defPedType);
86 SUMOVTypeParameter* defBikeType = new SUMOVTypeParameter(DEFAULT_BIKETYPE_ID, SVC_BICYCLE);
87 defBikeType->onlyReferenced = true;
88 defBikeType->parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
89 myVehicleTypes.add(defBikeType->id, defBikeType);
90 myInstance = this;
91 }
92
93
~RONet()94 RONet::~RONet() {
95 for (RoutablesMap::iterator routables = myRoutables.begin(); routables != myRoutables.end(); ++routables) {
96 for (RORoutable* const r : routables->second) {
97 const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
98 // delete routes and the vehicle
99 if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
100 if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
101 delete veh->getRouteDefinition();
102 }
103 }
104 delete r;
105 }
106 }
107 for (const RORoutable* const r : myPTVehicles) {
108 const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
109 // delete routes and the vehicle
110 if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
111 if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
112 delete veh->getRouteDefinition();
113 }
114 }
115 delete r;
116 }
117 myRoutables.clear();
118 }
119
120
121 void
addRestriction(const std::string & id,const SUMOVehicleClass svc,const double speed)122 RONet::addRestriction(const std::string& id, const SUMOVehicleClass svc, const double speed) {
123 myRestrictions[id][svc] = speed;
124 }
125
126
127 const std::map<SUMOVehicleClass, double>*
getRestrictions(const std::string & id) const128 RONet::getRestrictions(const std::string& id) const {
129 std::map<std::string, std::map<SUMOVehicleClass, double> >::const_iterator i = myRestrictions.find(id);
130 if (i == myRestrictions.end()) {
131 return nullptr;
132 }
133 return &i->second;
134 }
135
136
137 bool
addEdge(ROEdge * edge)138 RONet::addEdge(ROEdge* edge) {
139 if (!myEdges.add(edge->getID(), edge)) {
140 WRITE_ERROR("The edge '" + edge->getID() + "' occurs at least twice.");
141 delete edge;
142 return false;
143 }
144 if (edge->isInternal()) {
145 myNumInternalEdges += 1;
146 }
147 return true;
148 }
149
150
151 bool
addDistrict(const std::string id,ROEdge * source,ROEdge * sink)152 RONet::addDistrict(const std::string id, ROEdge* source, ROEdge* sink) {
153 if (myDistricts.count(id) > 0) {
154 WRITE_ERROR("The TAZ '" + id + "' occurs at least twice.");
155 delete source;
156 delete sink;
157 return false;
158 }
159 sink->setFunction(EDGEFUNC_CONNECTOR);
160 addEdge(sink);
161 source->setFunction(EDGEFUNC_CONNECTOR);
162 addEdge(source);
163 myDistricts[id] = std::make_pair(std::vector<std::string>(), std::vector<std::string>());
164 return true;
165 }
166
167
168 bool
addDistrictEdge(const std::string tazID,const std::string edgeID,const bool isSource)169 RONet::addDistrictEdge(const std::string tazID, const std::string edgeID, const bool isSource) {
170 if (myDistricts.count(tazID) == 0) {
171 WRITE_ERROR("The TAZ '" + tazID + "' is unknown.");
172 return false;
173 }
174 ROEdge* edge = getEdge(edgeID);
175 if (edge == nullptr) {
176 WRITE_ERROR("The edge '" + edgeID + "' for TAZ '" + tazID + "' is unknown.");
177 return false;
178 }
179 if (isSource) {
180 getEdge(tazID + "-source")->addSuccessor(edge);
181 myDistricts[tazID].first.push_back(edgeID);
182 } else {
183 edge->addSuccessor(getEdge(tazID + "-sink"));
184 myDistricts[tazID].second.push_back(edgeID);
185 }
186 return true;
187 }
188
189
190 void
addNode(RONode * node)191 RONet::addNode(RONode* node) {
192 if (!myNodes.add(node->getID(), node)) {
193 WRITE_ERROR("The node '" + node->getID() + "' occurs at least twice.");
194 delete node;
195 }
196 }
197
198
199 void
addStoppingPlace(const std::string & id,const SumoXMLTag category,SUMOVehicleParameter::Stop * stop)200 RONet::addStoppingPlace(const std::string& id, const SumoXMLTag category, SUMOVehicleParameter::Stop* stop) {
201 if (!myStoppingPlaces[category == SUMO_TAG_TRAIN_STOP ? SUMO_TAG_BUS_STOP : category].add(id, stop)) {
202 WRITE_ERROR("The " + toString(category) + " '" + id + "' occurs at least twice.");
203 delete stop;
204 }
205 }
206
207
208 bool
addRouteDef(RORouteDef * def)209 RONet::addRouteDef(RORouteDef* def) {
210 return myRoutes.add(def->getID(), def);
211 }
212
213
214 void
openOutput(const OptionsCont & options)215 RONet::openOutput(const OptionsCont& options) {
216 if (options.isSet("output-file") && options.getString("output-file") != "") {
217 myRoutesOutput = &OutputDevice::getDevice(options.getString("output-file"));
218 myRoutesOutput->writeHeader<ROEdge>(SUMO_TAG_ROUTES);
219 myRoutesOutput->writeAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance").writeAttr("xsi:noNamespaceSchemaLocation", "http://sumo.dlr.de/xsd/routes_file.xsd");
220 }
221 if (options.exists("alternatives-output") && options.isSet("alternatives-output")
222 && !(options.exists("write-trips") && options.getBool("write-trips"))) {
223 myRouteAlternativesOutput = &OutputDevice::getDevice(options.getString("alternatives-output"));
224 myRouteAlternativesOutput->writeHeader<ROEdge>(SUMO_TAG_ROUTES);
225 myRouteAlternativesOutput->writeAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance").writeAttr("xsi:noNamespaceSchemaLocation", "http://sumo.dlr.de/xsd/routes_file.xsd");
226 }
227 if (options.isSet("vtype-output")) {
228 myTypesOutput = &OutputDevice::getDevice(options.getString("vtype-output"));
229 myTypesOutput->writeHeader<ROEdge>(SUMO_TAG_ROUTES);
230 myTypesOutput->writeAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance").writeAttr("xsi:noNamespaceSchemaLocation", "http://sumo.dlr.de/xsd/routes_file.xsd");
231 }
232 }
233
234
235 void
writeIntermodal(const OptionsCont & options,ROIntermodalRouter & router) const236 RONet::writeIntermodal(const OptionsCont& options, ROIntermodalRouter& router) const {
237 if (options.exists("intermodal-network-output") && options.isSet("intermodal-network-output")) {
238 OutputDevice::createDeviceByOption("intermodal-network-output", "intermodal");
239 router.writeNetwork(OutputDevice::getDevice(options.getString("intermodal-network-output")));
240 }
241 if (options.exists("intermodal-weight-output") && options.isSet("intermodal-weight-output")) {
242 OutputDevice::createDeviceByOption("intermodal-weight-output", "weights", "meandata_file.xsd");
243 OutputDevice& dev = OutputDevice::getDeviceByOption("intermodal-weight-output");
244 dev.openTag(SUMO_TAG_INTERVAL);
245 dev.writeAttr(SUMO_ATTR_ID, "intermodalweights");
246 dev.writeAttr(SUMO_ATTR_BEGIN, 0);
247 dev.writeAttr(SUMO_ATTR_END, SUMOTime_MAX);
248 router.writeWeights(dev);
249 dev.closeTag();
250 }
251 }
252
253
254 void
cleanup()255 RONet::cleanup() {
256 // end writing
257 if (myRoutesOutput != nullptr) {
258 myRoutesOutput->close();
259 }
260 // only if opened
261 if (myRouteAlternativesOutput != nullptr) {
262 myRouteAlternativesOutput->close();
263 }
264 // only if opened
265 if (myTypesOutput != nullptr) {
266 myTypesOutput->close();
267 }
268 RouteCostCalculator<RORoute, ROEdge, ROVehicle>::cleanup();
269 #ifdef HAVE_FOX
270 if (myThreadPool.size() > 0) {
271 myThreadPool.clear();
272 }
273 #endif
274 }
275
276
277
278 SUMOVTypeParameter*
getVehicleTypeSecure(const std::string & id)279 RONet::getVehicleTypeSecure(const std::string& id) {
280 // check whether the type was already known
281 SUMOVTypeParameter* type = myVehicleTypes.get(id);
282 if (id == DEFAULT_VTYPE_ID) {
283 myDefaultVTypeMayBeDeleted = false;
284 }
285 if (id == DEFAULT_PEDTYPE_ID) {
286 myDefaultPedTypeMayBeDeleted = false;
287 }
288 if (id == DEFAULT_BIKETYPE_ID) {
289 myDefaultBikeTypeMayBeDeleted = false;
290 }
291 if (type != nullptr) {
292 return type;
293 }
294 VTypeDistDictType::iterator it2 = myVTypeDistDict.find(id);
295 if (it2 != myVTypeDistDict.end()) {
296 return it2->second->get();
297 }
298 if (id == "") {
299 // ok, no vehicle type or an unknown type was given within the user input
300 // return the default type
301 myDefaultVTypeMayBeDeleted = false;
302 return myVehicleTypes.get(DEFAULT_VTYPE_ID);
303 }
304 return type;
305 }
306
307
308 bool
checkVType(const std::string & id)309 RONet::checkVType(const std::string& id) {
310 if (id == DEFAULT_VTYPE_ID) {
311 if (myDefaultVTypeMayBeDeleted) {
312 myVehicleTypes.remove(id);
313 myDefaultVTypeMayBeDeleted = false;
314 } else {
315 return false;
316 }
317 } else if (id == DEFAULT_PEDTYPE_ID) {
318 if (myDefaultPedTypeMayBeDeleted) {
319 myVehicleTypes.remove(id);
320 myDefaultPedTypeMayBeDeleted = false;
321 } else {
322 return false;
323 }
324 } else {
325 if (myVehicleTypes.get(id) != 0 || myVTypeDistDict.find(id) != myVTypeDistDict.end()) {
326 return false;
327 }
328 }
329 return true;
330 }
331
332
333 bool
addVehicleType(SUMOVTypeParameter * type)334 RONet::addVehicleType(SUMOVTypeParameter* type) {
335 if (checkVType(type->id)) {
336 myVehicleTypes.add(type->id, type);
337 } else {
338 WRITE_ERROR("The vehicle type '" + type->id + "' occurs at least twice.");
339 delete type;
340 return false;
341 }
342 return true;
343 }
344
345
346 bool
addVTypeDistribution(const std::string & id,RandomDistributor<SUMOVTypeParameter * > * vehTypeDistribution)347 RONet::addVTypeDistribution(const std::string& id, RandomDistributor<SUMOVTypeParameter*>* vehTypeDistribution) {
348 if (checkVType(id)) {
349 myVTypeDistDict[id] = vehTypeDistribution;
350 return true;
351 }
352 return false;
353 }
354
355
356 bool
addVehicle(const std::string & id,ROVehicle * veh)357 RONet::addVehicle(const std::string& id, ROVehicle* veh) {
358 if (myVehIDs.find(id) == myVehIDs.end()) {
359 myVehIDs.insert(id);
360 if (veh->isPublicTransport()) {
361 if (!veh->isPartOfFlow()) {
362 myPTVehicles.push_back(veh);
363 }
364 if (OptionsCont::getOptions().exists("ptline-routing") && !OptionsCont::getOptions().getBool("ptline-routing")) {
365 return true;
366 }
367 }
368 myRoutables[veh->getDepart()].push_back(veh);
369 return true;
370 }
371 WRITE_ERROR("Another vehicle with the id '" + id + "' exists.");
372 return false;
373 }
374
375
376 bool
addFlow(SUMOVehicleParameter * flow,const bool randomize)377 RONet::addFlow(SUMOVehicleParameter* flow, const bool randomize) {
378 if (randomize) {
379 myDepartures[flow->id].reserve(flow->repetitionNumber);
380 for (int i = 0; i < flow->repetitionNumber; ++i) {
381 myDepartures[flow->id].push_back(flow->depart + RandHelper::rand(flow->repetitionNumber * flow->repetitionOffset));
382 }
383 std::sort(myDepartures[flow->id].begin(), myDepartures[flow->id].end());
384 std::reverse(myDepartures[flow->id].begin(), myDepartures[flow->id].end());
385 }
386 return myFlows.add(flow->id, flow);
387 }
388
389
390 bool
addPerson(ROPerson * person)391 RONet::addPerson(ROPerson* person) {
392 if (myPersonIDs.count(person->getID()) == 0) {
393 myPersonIDs.insert(person->getID());
394 myRoutables[person->getDepart()].push_back(person);
395 return true;
396 }
397 WRITE_ERROR("Another person with the id '" + person->getID() + "' exists.");
398 return false;
399 }
400
401
402 void
addContainer(const SUMOTime depart,const std::string desc)403 RONet::addContainer(const SUMOTime depart, const std::string desc) {
404 myContainers.insert(std::pair<const SUMOTime, const std::string>(depart, desc));
405 }
406
407
408 void
checkFlows(SUMOTime time,MsgHandler * errorHandler)409 RONet::checkFlows(SUMOTime time, MsgHandler* errorHandler) {
410 myHaveActiveFlows = false;
411 for (const auto& i : myFlows) {
412 SUMOVehicleParameter* pars = i.second;
413 if (pars->repetitionProbability > 0) {
414 if (pars->repetitionEnd > pars->depart) {
415 myHaveActiveFlows = true;
416 }
417 const SUMOTime origDepart = pars->depart;
418 while (pars->depart < time) {
419 if (pars->repetitionEnd <= pars->depart) {
420 break;
421 }
422 // only call rand if all other conditions are met
423 if (RandHelper::rand() < (pars->repetitionProbability * TS)) {
424 SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
425 newPars->id = pars->id + "." + toString(pars->repetitionsDone);
426 newPars->depart = pars->depart;
427 for (std::vector<SUMOVehicleParameter::Stop>::iterator stop = newPars->stops.begin(); stop != newPars->stops.end(); ++stop) {
428 if (stop->until >= 0) {
429 stop->until += pars->depart - origDepart;
430 }
431 }
432 pars->repetitionsDone++;
433 // try to build the vehicle
434 SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
435 if (!myKeepVTypeDist) {
436 // fix the type id in case we used a distribution
437 newPars->vtypeid = type->id;
438 }
439 const SUMOTime stopOffset = pars->routeid[0] == '!' ? pars->depart - origDepart : pars->depart;
440 RORouteDef* route = getRouteDef(pars->routeid)->copy("!" + newPars->id, stopOffset);
441 ROVehicle* veh = new ROVehicle(*newPars, route, type, this, errorHandler);
442 addVehicle(newPars->id, veh);
443 delete newPars;
444 }
445 pars->depart += DELTA_T;
446 }
447 } else {
448 while (pars->repetitionsDone < pars->repetitionNumber) {
449 myHaveActiveFlows = true;
450 SUMOTime depart = static_cast<SUMOTime>(pars->depart + pars->repetitionsDone * pars->repetitionOffset);
451 if (myDepartures.find(pars->id) != myDepartures.end()) {
452 depart = myDepartures[pars->id].back();
453 }
454 if (depart >= time + DELTA_T) {
455 break;
456 }
457 if (myDepartures.find(pars->id) != myDepartures.end()) {
458 myDepartures[pars->id].pop_back();
459 }
460 SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
461 newPars->id = pars->id + "." + toString(pars->repetitionsDone);
462 newPars->depart = depart;
463 for (std::vector<SUMOVehicleParameter::Stop>::iterator stop = newPars->stops.begin(); stop != newPars->stops.end(); ++stop) {
464 if (stop->until >= 0) {
465 stop->until += depart - pars->depart;
466 }
467 }
468 pars->repetitionsDone++;
469 // try to build the vehicle
470 SUMOVTypeParameter* type = getVehicleTypeSecure(pars->vtypeid);
471 if (type == nullptr) {
472 type = getVehicleTypeSecure(DEFAULT_VTYPE_ID);
473 } else {
474 // fix the type id in case we used a distribution
475 newPars->vtypeid = type->id;
476 }
477 const SUMOTime stopOffset = pars->routeid[0] == '!' ? depart - pars->depart : depart;
478 RORouteDef* route = getRouteDef(pars->routeid)->copy("!" + newPars->id, stopOffset);
479 ROVehicle* veh = new ROVehicle(*newPars, route, type, this, errorHandler);
480 addVehicle(newPars->id, veh);
481 delete newPars;
482 }
483 }
484 }
485 }
486
487
488 void
createBulkRouteRequests(const RORouterProvider & provider,const SUMOTime time,const bool removeLoops)489 RONet::createBulkRouteRequests(const RORouterProvider& provider, const SUMOTime time, const bool removeLoops) {
490 std::map<const int, std::vector<RORoutable*> > bulkVehs;
491 for (RoutablesMap::const_iterator i = myRoutables.begin(); i != myRoutables.end(); ++i) {
492 if (i->first >= time) {
493 break;
494 }
495 for (RORoutable* const routable : i->second) {
496 const ROEdge* const depEdge = routable->getDepartEdge();
497 bulkVehs[depEdge->getNumericalID()].push_back(routable);
498 RORoutable* const first = bulkVehs[depEdge->getNumericalID()].front();
499 if (first->getMaxSpeed() != routable->getMaxSpeed()) {
500 WRITE_WARNING("Bulking different maximum speeds ('" + first->getID() + "' and '" + routable->getID() + "') may lead to suboptimal routes.");
501 }
502 if (first->getVClass() != routable->getVClass()) {
503 WRITE_WARNING("Bulking different vehicle classes ('" + first->getID() + "' and '" + routable->getID() + "') may lead to invalid routes.");
504 }
505 }
506 }
507 int workerIndex = 0;
508 for (std::map<const int, std::vector<RORoutable*> >::const_iterator i = bulkVehs.begin(); i != bulkVehs.end(); ++i) {
509 #ifdef HAVE_FOX
510 if (myThreadPool.size() > 0) {
511 RORoutable* const first = i->second.front();
512 myThreadPool.add(new RoutingTask(first, removeLoops, myErrorHandler), workerIndex);
513 myThreadPool.add(new BulkmodeTask(true), workerIndex);
514 for (std::vector<RORoutable*>::const_iterator j = i->second.begin() + 1; j != i->second.end(); ++j) {
515 myThreadPool.add(new RoutingTask(*j, removeLoops, myErrorHandler), workerIndex);
516 }
517 myThreadPool.add(new BulkmodeTask(false), workerIndex);
518 workerIndex++;
519 if (workerIndex == (int)myThreadPool.size()) {
520 workerIndex = 0;
521 }
522 continue;
523 }
524 #endif
525 for (std::vector<RORoutable*>::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
526 (*j)->computeRoute(provider, removeLoops, myErrorHandler);
527 provider.getVehicleRouter().setBulkMode(true);
528 }
529 provider.getVehicleRouter().setBulkMode(false);
530 }
531 }
532
533
534 SUMOTime
saveAndRemoveRoutesUntil(OptionsCont & options,const RORouterProvider & provider,SUMOTime time)535 RONet::saveAndRemoveRoutesUntil(OptionsCont& options, const RORouterProvider& provider,
536 SUMOTime time) {
537 MsgHandler* mh = (options.getBool("ignore-errors") ?
538 MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance());
539 if (myHaveActiveFlows) {
540 checkFlows(time, mh);
541 }
542 SUMOTime lastTime = -1;
543 const bool removeLoops = options.getBool("remove-loops");
544 const int maxNumThreads = options.getInt("routing-threads");
545 if (myRoutables.size() != 0) {
546 if (options.getBool("bulk-routing")) {
547 #ifdef HAVE_FOX
548 while ((int)myThreadPool.size() < maxNumThreads) {
549 new WorkerThread(myThreadPool, provider);
550 }
551 #endif
552 createBulkRouteRequests(provider, time, removeLoops);
553 } else {
554 for (RoutablesMap::const_iterator i = myRoutables.begin(); i != myRoutables.end(); ++i) {
555 if (i->first >= time) {
556 break;
557 }
558 for (RORoutable* const routable : i->second) {
559 #ifdef HAVE_FOX
560 // add task
561 if (maxNumThreads > 0) {
562 const int numThreads = (int)myThreadPool.size();
563 if (numThreads == 0) {
564 // This is the very first routing. Since at least the CHRouter needs initialization
565 // before it gets cloned, we do not do this in parallel
566 routable->computeRoute(provider, removeLoops, myErrorHandler);
567 new WorkerThread(myThreadPool, provider);
568 } else {
569 // add thread if necessary
570 if (numThreads < maxNumThreads && myThreadPool.isFull()) {
571 new WorkerThread(myThreadPool, provider);
572 }
573 myThreadPool.add(new RoutingTask(routable, removeLoops, myErrorHandler));
574 }
575 continue;
576 }
577 #endif
578 routable->computeRoute(provider, removeLoops, myErrorHandler);
579 }
580 }
581 }
582 #ifdef HAVE_FOX
583 myThreadPool.waitAll();
584 #endif
585 }
586 // write all vehicles (and additional structures)
587 while (myRoutables.size() != 0 || myContainers.size() != 0) {
588 // get the next vehicle, person or container
589 RoutablesMap::iterator routables = myRoutables.begin();
590 const SUMOTime routableTime = routables == myRoutables.end() ? SUMOTime_MAX : routables->first;
591 ContainerMap::iterator container = myContainers.begin();
592 const SUMOTime containerTime = container == myContainers.end() ? SUMOTime_MAX : container->first;
593 // check whether it shall not yet be computed
594 if (routableTime >= time && containerTime >= time) {
595 lastTime = MIN2(routableTime, containerTime);
596 break;
597 }
598 const SUMOTime minTime = MIN2(routableTime, containerTime);
599 if (routableTime == minTime) {
600 // check whether to print the output
601 if (lastTime != routableTime && lastTime != -1) {
602 // report writing progress
603 if (options.getInt("stats-period") >= 0 && ((int)routableTime % options.getInt("stats-period")) == 0) {
604 WRITE_MESSAGE("Read: " + toString(myVehIDs.size()) + ", Discarded: " + toString(myDiscardedRouteNo) + ", Written: " + toString(myWrittenRouteNo));
605 }
606 }
607 lastTime = routableTime;
608 for (const RORoutable* const r : routables->second) {
609 // ok, check whether it has been routed
610 if (r->getRoutingSuccess()) {
611 // write the route
612 r->write(*myRoutesOutput, myRouteAlternativesOutput, myTypesOutput, options);
613 myWrittenRouteNo++;
614 } else {
615 myDiscardedRouteNo++;
616 }
617 // delete routes and the vehicle
618 if (!r->isPublicTransport() || r->isPartOfFlow()) {
619 const ROVehicle* const veh = dynamic_cast<const ROVehicle*>(r);
620 if (veh != nullptr && veh->getRouteDefinition()->getID()[0] == '!') {
621 if (!myRoutes.remove(veh->getRouteDefinition()->getID())) {
622 delete veh->getRouteDefinition();
623 }
624 }
625 delete r;
626 }
627 }
628 myRoutables.erase(routables);
629 }
630 if (containerTime == minTime) {
631 myRoutesOutput->writePreformattedTag(container->second);
632 if (myRouteAlternativesOutput != nullptr) {
633 myRouteAlternativesOutput->writePreformattedTag(container->second);
634 }
635 myContainers.erase(container);
636 }
637 }
638 return lastTime;
639 }
640
641
642 bool
furtherStored()643 RONet::furtherStored() {
644 return myRoutables.size() > 0 || (myFlows.size() > 0 && myHaveActiveFlows) || myContainers.size() > 0;
645 }
646
647
648 int
getEdgeNumber() const649 RONet::getEdgeNumber() const {
650 return myEdges.size();
651 }
652
653
654 int
getInternalEdgeNumber() const655 RONet::getInternalEdgeNumber() const {
656 return myNumInternalEdges;
657 }
658
659
660 void
adaptIntermodalRouter(ROIntermodalRouter & router)661 RONet::adaptIntermodalRouter(ROIntermodalRouter& router) {
662 // add access to all parking areas
663 for (const auto& i : myInstance->myStoppingPlaces[SUMO_TAG_PARKING_AREA]) {
664 router.getNetwork()->addAccess(i.first, myInstance->getEdgeForLaneID(i.second->lane), (i.second->startPos + i.second->endPos) / 2., 0., SUMO_TAG_PARKING_AREA);
665 }
666 // add access to all public transport stops
667 for (const auto& stop : myInstance->myStoppingPlaces[SUMO_TAG_BUS_STOP]) {
668 router.getNetwork()->addAccess(stop.first, myInstance->getEdgeForLaneID(stop.second->lane), (stop.second->startPos + stop.second->endPos) / 2., 0., SUMO_TAG_BUS_STOP);
669 for (const auto& a : stop.second->accessPos) {
670 router.getNetwork()->addAccess(stop.first, myInstance->getEdgeForLaneID(std::get<0>(a)), std::get<1>(a), std::get<2>(a), SUMO_TAG_BUS_STOP);
671 }
672 }
673 // fill the public transport router with pre-parsed public transport lines
674 for (const auto& i : myInstance->myFlows) {
675 if (i.second->line != "") {
676 const RORouteDef* const route = myInstance->getRouteDef(i.second->routeid);
677 const std::vector<SUMOVehicleParameter::Stop>* addStops = nullptr;
678 if (route != nullptr && route->getFirstRoute() != nullptr) {
679 addStops = &route->getFirstRoute()->getStops();
680 }
681 router.getNetwork()->addSchedule(*i.second, addStops);
682 }
683 }
684 for (const RORoutable* const veh : myInstance->myPTVehicles) {
685 // add single vehicles with line attribute which are not part of a flow
686 // no need to add route stops here, they have been added to the vehicle before
687 router.getNetwork()->addSchedule(veh->getParameter());
688 }
689 }
690
691
692 bool
hasPermissions() const693 RONet::hasPermissions() const {
694 return myHavePermissions;
695 }
696
697
698 void
setPermissionsFound()699 RONet::setPermissionsFound() {
700 myHavePermissions = true;
701 }
702
703 const std::string
getStoppingPlaceName(const std::string & id) const704 RONet::getStoppingPlaceName(const std::string& id) const {
705 for (const auto& mapItem : myStoppingPlaces) {
706 SUMOVehicleParameter::Stop* stop = mapItem.second.get(id);
707 if (stop != nullptr) {
708 // see RONetHandler::parseStoppingPlace
709 return stop->busstop;
710 }
711 }
712 return "";
713 }
714
715 #ifdef HAVE_FOX
716 // ---------------------------------------------------------------------------
717 // RONet::RoutingTask-methods
718 // ---------------------------------------------------------------------------
719 void
run(FXWorkerThread * context)720 RONet::RoutingTask::run(FXWorkerThread* context) {
721 myRoutable->computeRoute(*static_cast<WorkerThread*>(context), myRemoveLoops, myErrorHandler);
722 }
723 #endif
724
725
726 /****************************************************************************/
727
728