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