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