Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netload/NLBuilder.cpp
193874 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 NLBuilder.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @date Mon, 9 Jul 2001
19
///
20
// The main interface for loading a microsim
21
/****************************************************************************/
22
#include <config.h>
23
24
#include <iostream>
25
#include <vector>
26
#include <string>
27
#include <map>
28
29
#include <utils/common/MsgHandler.h>
30
#include <utils/common/StringTokenizer.h>
31
#include <utils/common/SystemFrame.h>
32
#include <utils/options/Option.h>
33
#include <utils/options/OptionsCont.h>
34
#include <utils/options/OptionsIO.h>
35
#include <utils/common/StringUtils.h>
36
#include <utils/common/FileHelpers.h>
37
#include <utils/common/SysUtils.h>
38
#include <utils/common/ToString.h>
39
#include <utils/vehicle/SUMORouteLoaderControl.h>
40
#include <utils/vehicle/SUMORouteLoader.h>
41
#include <utils/xml/XMLSubSys.h>
42
#ifdef HAVE_FOX
43
#include <utils/foxtools/MsgHandlerSynchronized.h>
44
#endif
45
#include <libsumo/Helper.h>
46
#include <mesosim/MEVehicleControl.h>
47
#include <mesosim/METypeHandler.h>
48
#include <microsim/MSVehicleControl.h>
49
#include <microsim/MSVehicleTransfer.h>
50
#include <microsim/MSNet.h>
51
#include <microsim/devices/MSDevice.h>
52
#include <microsim/devices/MSDevice_ToC.h>
53
#include <microsim/devices/MSDevice_BTreceiver.h>
54
#include <microsim/devices/MSDevice_FCDReplay.h>
55
#include <microsim/MSEdgeControl.h>
56
#include <microsim/MSGlobals.h>
57
#include <microsim/output/MSDetectorControl.h>
58
#include <microsim/MSFrame.h>
59
#include <microsim/MSEdgeWeightsStorage.h>
60
#include <microsim/MSStateHandler.h>
61
#include <microsim/MSDriverState.h>
62
#include <microsim/trigger/MSTriggeredRerouter.h>
63
#include <traci-server/TraCIServer.h>
64
65
#include "NLHandler.h"
66
#include "NLNetShapeHandler.h"
67
#include "NLEdgeControlBuilder.h"
68
#include "NLJunctionControlBuilder.h"
69
#include "NLDetectorBuilder.h"
70
#include "NLTriggerBuilder.h"
71
#include "NLBuilder.h"
72
73
74
// ===========================================================================
75
// method definitions
76
// ===========================================================================
77
// ---------------------------------------------------------------------------
78
// NLBuilder::EdgeFloatTimeLineRetriever_EdgeWeight - methods
79
// ---------------------------------------------------------------------------
80
void
81
NLBuilder::EdgeFloatTimeLineRetriever_EdgeEffort::addEdgeWeight(const std::string& id,
82
double value, double begTime, double endTime) const {
83
MSEdge* edge = MSEdge::dictionary(id);
84
if (edge != nullptr) {
85
myNet.getWeightsStorage().addEffort(edge, begTime, endTime, value);
86
} else {
87
WRITE_ERRORF(TL("Trying to set the effort for the unknown edge '%'."), id);
88
}
89
}
90
91
92
// ---------------------------------------------------------------------------
93
// NLBuilder::EdgeFloatTimeLineRetriever_EdgeTravelTime - methods
94
// ---------------------------------------------------------------------------
95
void
96
NLBuilder::EdgeFloatTimeLineRetriever_EdgeTravelTime::addEdgeWeight(const std::string& id,
97
double value, double begTime, double endTime) const {
98
MSEdge* edge = MSEdge::dictionary(id);
99
if (edge != nullptr) {
100
myNet.getWeightsStorage().addTravelTime(edge, begTime, endTime, value);
101
} else {
102
WRITE_ERRORF(TL("Trying to set the travel time for the unknown edge '%'."), id);
103
}
104
}
105
106
107
// ---------------------------------------------------------------------------
108
// NLBuilder - methods
109
// ---------------------------------------------------------------------------
110
NLBuilder::NLBuilder(OptionsCont& oc,
111
MSNet& net,
112
NLEdgeControlBuilder& eb,
113
NLJunctionControlBuilder& jb,
114
NLDetectorBuilder& db,
115
NLHandler& xmlHandler)
116
: myOptions(oc), myEdgeBuilder(eb), myJunctionBuilder(jb),
117
myDetectorBuilder(db),
118
myNet(net), myXMLHandler(xmlHandler) {}
119
120
121
NLBuilder::~NLBuilder() {}
122
123
124
bool
125
NLBuilder::build() {
126
// try to build the net
127
if (!load("net-file", true)) {
128
return false;
129
}
130
if (myXMLHandler.networkVersion() == MMVersion(0, 0)) {
131
throw ProcessError(TL("Invalid network, no network version declared."));
132
}
133
// check whether the loaded net agrees with the simulation options
134
if ((myOptions.getBool("no-internal-links") || myOptions.getBool("mesosim")) && myXMLHandler.haveSeenInternalEdge() && myXMLHandler.haveSeenDefaultLength()) {
135
WRITE_WARNING(TL("Network contains internal links which are ignored. Vehicles will 'jump' across junctions and thus underestimate route lengths and travel times."));
136
}
137
buildNet();
138
if (myOptions.isSet("alternative-net-file")) {
139
for (std::string fname : myOptions.getStringVector("alternative-net-file")) {
140
const long before = PROGRESS_BEGIN_TIME_MESSAGE("Loading alternative net from '" + fname + "'");
141
NLNetShapeHandler nsh(fname, myNet);
142
if (!XMLSubSys::runParser(nsh, fname, true)) {
143
WRITE_MESSAGE("Loading of alternative net failed.");
144
return false;
145
}
146
nsh.sortInternalShapes();
147
PROGRESS_TIME_MESSAGE(before);
148
}
149
}
150
// @note on loading order constraints:
151
// - additional-files before route-files and state-files due to referencing
152
// - additional-files before weight-files since the latter might contain intermodal edge data and the intermodal net depends on the stops and public transport from the additionals
153
154
bool stateBeginMismatch = false;
155
if (myOptions.isSet("load-state")) {
156
// first, load only the time
157
const SUMOTime stateTime = MSStateHandler::MSStateTimeHandler::getTime(myOptions.getString("load-state"));
158
if (myOptions.isDefault("begin")) {
159
myOptions.set("begin", time2string(stateTime));
160
if (TraCIServer::getInstance() != nullptr) {
161
TraCIServer::getInstance()->stateLoaded(stateTime);
162
}
163
} else {
164
if (stateTime != string2time(myOptions.getString("begin"))) {
165
WRITE_WARNINGF(TL("State was written at a different time=% than the begin time %!"), time2string(stateTime), myOptions.getString("begin"));
166
stateBeginMismatch = true;
167
}
168
}
169
myNet.setCurrentTimeStep(string2time(myOptions.getString("begin")));
170
}
171
172
if (myOptions.getBool("junction-taz")) {
173
// create a TAZ for every junction
174
const MSJunctionControl& junctions = myNet.getJunctionControl();
175
for (auto it = junctions.begin(); it != junctions.end(); it++) {
176
const std::string sinkID = it->first + "-sink";
177
const std::string sourceID = it->first + "-source";
178
if (MSEdge::dictionary(sinkID) == nullptr && MSEdge::dictionary(sourceID) == nullptr) {
179
// sink must be built and added before source
180
MSEdge* sink = myEdgeBuilder.buildEdge(sinkID, SumoXMLEdgeFunc::CONNECTOR, "", "", "", -1, 0);
181
MSEdge* source = myEdgeBuilder.buildEdge(sourceID, SumoXMLEdgeFunc::CONNECTOR, "", "", "", -1, 0);
182
sink->setOtherTazConnector(source);
183
source->setOtherTazConnector(sink);
184
MSEdge::dictionary(sinkID, sink);
185
MSEdge::dictionary(sourceID, source);
186
sink->initialize(new std::vector<MSLane*>());
187
source->initialize(new std::vector<MSLane*>());
188
const MSJunction* junction = it->second;
189
for (const MSEdge* edge : junction->getIncoming()) {
190
if (!edge->isInternal()) {
191
const_cast<MSEdge*>(edge)->addSuccessor(sink);
192
}
193
}
194
for (const MSEdge* edge : junction->getOutgoing()) {
195
if (!edge->isInternal()) {
196
source->addSuccessor(const_cast<MSEdge*>(edge));
197
}
198
}
199
} else {
200
WRITE_WARNINGF(TL("A TAZ with id '%' already exists. Not building junction TAZ."), it->first)
201
}
202
}
203
}
204
// load meso edge types
205
bool haveSeenMesoEdgeType = false;
206
if (MSGlobals::gUseMesoSim) {
207
if (myOptions.isSet("additional-files")) {
208
haveSeenMesoEdgeType = loadMesoEdgeTypes("additional-files");
209
}
210
// meso segment building must be delayed until meso edge types have been read from additional files
211
myNet.getEdgeControl().buildMesoSegments();
212
}
213
// load additional net elements (sources, detectors, ...)
214
if (myOptions.isSet("additional-files")) {
215
if (!load("additional-files")) {
216
return false;
217
}
218
// load shapes with separate handler
219
NLShapeHandler sh("", myNet.getShapeContainer());
220
if (!ShapeHandler::loadFiles(myOptions.getStringVector("additional-files"), sh)) {
221
return false;
222
}
223
if (myXMLHandler.haveSeenAdditionalSpeedRestrictions()) {
224
myNet.getEdgeControl().setAdditionalRestrictions();
225
}
226
MSTriggeredRerouter::checkParkingRerouteConsistency();
227
}
228
if (MSGlobals::gUseMesoSim) {
229
if (haveSeenMesoEdgeType || myXMLHandler.haveSeenTLSParams()) {
230
for (MSTrafficLightLogic* tll : myNet.getTLSControl().getAllLogics()) {
231
tll->initMesoTLSPenalties();
232
}
233
}
234
}
235
// init tls after all detectors have been loaded
236
myJunctionBuilder.postLoadInitialization();
237
// declare meandata set by options
238
buildDefaultMeanData("edgedata-output", "DEFAULT_EDGEDATA", false);
239
buildDefaultMeanData("lanedata-output", "DEFAULT_LANEDATA", true);
240
241
if (stateBeginMismatch && myNet.getVehicleControl().getLoadedVehicleNo() > 0) {
242
throw ProcessError(TL("Loading vehicles ahead of a state file is not supported. Correct --begin option or load vehicles with option --route-files"));
243
}
244
245
// load weights if wished
246
if (myOptions.isSet("weight-files")) {
247
if (!myOptions.isUsableFileList("weight-files")) {
248
return false;
249
}
250
// build and prepare the weights handler
251
std::vector<SAXWeightsHandler::ToRetrieveDefinition*> retrieverDefs;
252
// travel time, first (always used)
253
EdgeFloatTimeLineRetriever_EdgeTravelTime ttRetriever(myNet);
254
retrieverDefs.push_back(new SAXWeightsHandler::ToRetrieveDefinition("traveltime", true, ttRetriever));
255
// the measure to use, then
256
EdgeFloatTimeLineRetriever_EdgeEffort eRetriever(myNet);
257
std::string measure = myOptions.getString("weight-attribute");
258
if (!myOptions.isDefault("weight-attribute")) {
259
if (measure == "CO" || measure == "CO2" || measure == "HC" || measure == "PMx" || measure == "NOx" || measure == "fuel" || measure == "electricity") {
260
measure += "_perVeh";
261
}
262
retrieverDefs.push_back(new SAXWeightsHandler::ToRetrieveDefinition(measure, true, eRetriever));
263
}
264
// set up handler
265
SAXWeightsHandler handler(retrieverDefs, "");
266
// start parsing; for each file in the list
267
std::vector<std::string> files = myOptions.getStringVector("weight-files");
268
for (std::vector<std::string>::iterator i = files.begin(); i != files.end(); ++i) {
269
// report about loading when wished
270
WRITE_MESSAGEF(TL("Loading weights from '%'..."), *i);
271
// parse the file
272
if (!XMLSubSys::runParser(handler, *i)) {
273
return false;
274
}
275
}
276
}
277
// load the previous state if wished
278
if (myOptions.isSet("load-state")) {
279
const std::string& f = myOptions.getString("load-state");
280
long before = PROGRESS_BEGIN_TIME_MESSAGE(TLF("Loading state from '%'", f));
281
MSStateHandler h(f, string2time(myOptions.getString("load-state.offset")));
282
XMLSubSys::runParser(h, f);
283
if (MsgHandler::getErrorInstance()->wasInformed()) {
284
return false;
285
}
286
PROGRESS_TIME_MESSAGE(before);
287
}
288
// routes from FCD files
289
MSDevice_FCDReplay::init();
290
// load routes
291
if (myOptions.isSet("route-files")) {
292
if (string2time(myOptions.getString("route-steps")) <= 0) {
293
// incremental loading is disabled. Load route files fully
294
if (!load("route-files")) {
295
return false;
296
}
297
} else {
298
// message must come after additional-files have been loaded (but buildRouteLoaderControl was called earlier)
299
for (std::string file : myOptions.getStringVector("route-files")) {
300
WRITE_MESSAGE(TLF("Loading route-files incrementally from '%'", file));
301
}
302
}
303
}
304
// optionally switch off traffic lights
305
if (myOptions.getBool("tls.all-off")) {
306
myNet.getTLSControl().switchOffAll();
307
}
308
WRITE_MESSAGE(TL("Loading done."));
309
return true;
310
}
311
312
313
MSNet*
314
NLBuilder::init(const bool isLibsumo) {
315
OptionsCont& oc = OptionsCont::getOptions();
316
oc.clear();
317
MSFrame::fillOptions();
318
OptionsIO::getOptions();
319
if (oc.processMetaOptions(OptionsIO::getArgC() < 2)) {
320
SystemFrame::close();
321
return nullptr;
322
}
323
SystemFrame::checkOptions(oc);
324
std::string validation = oc.getString("xml-validation");
325
std::string routeValidation = oc.getString("xml-validation.routes");
326
if (isLibsumo) {
327
if (oc.isDefault("xml-validation")) {
328
validation = "never";
329
}
330
if (oc.isDefault("xml-validation.routes")) {
331
routeValidation = "never";
332
}
333
}
334
XMLSubSys::setValidation(validation, oc.getString("xml-validation.net"), routeValidation);
335
if (!MSFrame::checkOptions()) {
336
throw ProcessError();
337
}
338
#ifdef HAVE_FOX
339
if (oc.getInt("threads") > 1) {
340
// make the output aware of threading
341
MsgHandler::setFactory(&MsgHandlerSynchronized::create);
342
}
343
#endif
344
MsgHandler::initOutputOptions();
345
initRandomness();
346
MSFrame::setMSGlobals(oc);
347
MSVehicleControl* vc = nullptr;
348
if (MSGlobals::gUseMesoSim) {
349
vc = new MEVehicleControl();
350
} else {
351
vc = new MSVehicleControl();
352
}
353
MSNet* net = new MSNet(vc, new MSEventControl(), new MSEventControl(), new MSEventControl());
354
// need to init TraCI-Server before loading routes to catch VehicleState::BUILT
355
TraCIServer::openSocket(std::map<int, TraCIServer::CmdExecutor>());
356
if (isLibsumo) {
357
libsumo::Helper::registerStateListener();
358
}
359
360
NLEdgeControlBuilder eb;
361
NLDetectorBuilder db(*net);
362
NLJunctionControlBuilder jb(*net, db);
363
NLTriggerBuilder tb;
364
NLHandler handler("", *net, db, tb, eb, jb);
365
tb.setHandler(&handler);
366
NLBuilder builder(oc, *net, eb, jb, db, handler);
367
MsgHandler::getErrorInstance()->clear();
368
MsgHandler::getWarningInstance()->clear();
369
MsgHandler::getMessageInstance()->clear();
370
if (builder.build()) {
371
// preload the routes especially for TraCI
372
net->loadRoutes();
373
return net;
374
}
375
delete net;
376
throw ProcessError();
377
}
378
379
380
void
381
NLBuilder::initRandomness() {
382
RandHelper::initRandGlobal();
383
RandHelper::initRandGlobal(MSRouteHandler::getParsingRNG());
384
RandHelper::initRandGlobal(MSDevice::getEquipmentRNG());
385
RandHelper::initRandGlobal(OUProcess::getRNG());
386
RandHelper::initRandGlobal(MSDevice_ToC::getResponseTimeRNG());
387
RandHelper::initRandGlobal(MSDevice_BTreceiver::getRecognitionRNG());
388
MSLane::initRNGs(OptionsCont::getOptions());
389
}
390
391
392
void
393
NLBuilder::buildNet() {
394
MSEdgeControl* edges = nullptr;
395
MSJunctionControl* junctions = nullptr;
396
SUMORouteLoaderControl* routeLoaders = nullptr;
397
MSTLLogicControl* tlc = nullptr;
398
std::vector<SUMOTime> stateDumpTimes;
399
std::vector<std::string> stateDumpFiles;
400
try {
401
MSFrame::buildStreams(); // ensure streams are ready for output during building
402
edges = myEdgeBuilder.build(myXMLHandler.networkVersion());
403
junctions = myJunctionBuilder.build();
404
junctions->postloadInitContainer();
405
for (MSEdge* e : edges->getEdges()) {
406
e->postLoadInitLaneChanger();
407
}
408
routeLoaders = buildRouteLoaderControl(myOptions);
409
tlc = myJunctionBuilder.buildTLLogics();
410
for (std::string timeStr : myOptions.getStringVector("save-state.times")) {
411
stateDumpTimes.push_back(string2time(timeStr));
412
}
413
if (myOptions.isSet("save-state.files")) {
414
stateDumpFiles = myOptions.getStringVector("save-state.files");
415
if (stateDumpFiles.size() != stateDumpTimes.size()) {
416
throw ProcessError(TL("Wrong number of state file names!"));
417
}
418
} else {
419
const std::string prefix = myOptions.getString("save-state.prefix");
420
const std::string suffix = myOptions.getString("save-state.suffix");
421
for (std::vector<SUMOTime>::iterator i = stateDumpTimes.begin(); i != stateDumpTimes.end(); ++i) {
422
std::string timeStamp = time2string(*i);
423
std::replace(timeStamp.begin(), timeStamp.end(), ':', '-');
424
stateDumpFiles.push_back(prefix + "_" + timeStamp + suffix);
425
}
426
}
427
} catch (ProcessError&) {
428
MSEdge::clear();
429
MSLane::clear();
430
delete edges;
431
delete junctions;
432
delete routeLoaders;
433
delete tlc;
434
throw;
435
}
436
// if anthing goes wrong after this point, the net is responsible for cleaning up
437
myNet.closeBuilding(myOptions, edges, junctions, routeLoaders, tlc, stateDumpTimes, stateDumpFiles,
438
myXMLHandler.haveSeenInternalEdge(),
439
myXMLHandler.hasJunctionHigherSpeeds(),
440
myXMLHandler.networkVersion());
441
}
442
443
444
bool
445
NLBuilder::load(const std::string& mmlWhat, const bool isNet) {
446
if (!myOptions.isUsableFileList(mmlWhat)) {
447
return false;
448
}
449
std::vector<std::string> files = myOptions.getStringVector(mmlWhat);
450
for (std::vector<std::string>::const_iterator fileIt = files.begin(); fileIt != files.end(); ++fileIt) {
451
const long before = PROGRESS_BEGIN_TIME_MESSAGE(TLF("Loading % from '%'", mmlWhat, *fileIt));
452
if (!XMLSubSys::runParser(myXMLHandler, *fileIt, isNet)) {
453
WRITE_MESSAGEF(TL("Loading of % failed."), mmlWhat);
454
return false;
455
}
456
PROGRESS_TIME_MESSAGE(before);
457
}
458
return true;
459
}
460
461
462
bool
463
NLBuilder::loadMesoEdgeTypes(const std::string& mmlWhat) {
464
if (!myOptions.isUsableFileList(mmlWhat)) {
465
return false;
466
}
467
METypeHandler meTypeHandler("", myNet);
468
for (const std::string& file : myOptions.getStringVector(mmlWhat)) {
469
if (!XMLSubSys::runParser(meTypeHandler, file)) {
470
continue;
471
}
472
}
473
return meTypeHandler.haveSeenMesoEdgeType();
474
}
475
476
477
SUMORouteLoaderControl*
478
NLBuilder::buildRouteLoaderControl(const OptionsCont& oc) {
479
// build the loaders
480
SUMORouteLoaderControl* loaders = new SUMORouteLoaderControl(string2time(oc.getString("route-steps")));
481
// check whether a list is existing
482
if (oc.isSet("route-files") && string2time(oc.getString("route-steps")) > 0) {
483
std::vector<std::string> files = oc.getStringVector("route-files");
484
for (std::vector<std::string>::const_iterator fileIt = files.begin(); fileIt != files.end(); ++fileIt) {
485
if (!FileHelpers::isReadable(*fileIt)) {
486
throw ProcessError(TLF("The route file '%' is not accessible.", *fileIt));
487
}
488
}
489
// open files for reading
490
for (std::vector<std::string>::const_iterator fileIt = files.begin(); fileIt != files.end(); ++fileIt) {
491
loaders->add(new SUMORouteLoader(new MSRouteHandler(*fileIt, false)));
492
}
493
}
494
return loaders;
495
}
496
497
498
void
499
NLBuilder::buildDefaultMeanData(const std::string& optionName, const std::string& id, bool useLanes) {
500
if (OptionsCont::getOptions().isSet(optionName)) {
501
if (useLanes && MSGlobals::gUseMesoSim && !OptionsCont::getOptions().getBool("meso-lane-queue")) {
502
WRITE_WARNING(TL("LaneData requested for mesoscopic simulation but --meso-lane-queue is not active. Falling back to edgeData."));
503
useLanes = false;
504
}
505
try {
506
SUMOTime begin = string2time(OptionsCont::getOptions().getString("begin"));
507
myDetectorBuilder.createEdgeLaneMeanData(id, -1, begin, -1, "traffic", useLanes, false, false,
508
false, false, false, 100000, 0, SUMO_const_haltingSpeed, "", "", std::vector<MSEdge*>(), AggregateType::NO,
509
OptionsCont::getOptions().getString(optionName));
510
} catch (InvalidArgument& e) {
511
WRITE_ERROR(e.what());
512
} catch (IOError& e) {
513
WRITE_ERROR(e.what());
514
}
515
}
516
}
517
518
/****************************************************************************/
519
520