Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2007-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 MSRoutingEngine.cpp
15 : /// @author Michael Behrisch
16 : /// @author Daniel Krajzewicz
17 : /// @author Laura Bieker
18 : /// @author Christoph Sommer
19 : /// @author Jakob Erdmann
20 : /// @date Tue, 04 Dec 2007
21 : ///
22 : // A device that performs vehicle rerouting based on current edge speeds
23 : /****************************************************************************/
24 : #include <config.h>
25 :
26 : #include "MSRoutingEngine.h"
27 : #include <microsim/MSNet.h>
28 : #include <microsim/MSLane.h>
29 : #include <microsim/MSJunction.h>
30 : #include <microsim/MSEdge.h>
31 : #include <microsim/MSEdgeControl.h>
32 : #include <microsim/MSEventControl.h>
33 : #include <microsim/MSGlobals.h>
34 : #include <microsim/MSVehicleControl.h>
35 : #include <microsim/MSVehicleType.h>
36 : #include <microsim/MSVehicle.h>
37 : #include <microsim/MSRoute.h>
38 : #include <microsim/MSEdgeWeightsStorage.h>
39 : #include <mesosim/MEVehicle.h>
40 : #include <libsumo/TraCIConstants.h>
41 : #include <utils/vehicle/SUMOVehicleParameter.h>
42 : #include <set>
43 : #include <microsim/MSInsertionControl.h>
44 : #include <microsim/transportables/MSTransportable.h>
45 : #include <microsim/devices/MSDevice_Taxi.h>
46 : #include <utils/options/OptionsCont.h>
47 : #include <utils/common/WrappingCommand.h>
48 : #include <utils/common/StaticCommand.h>
49 : #include <utils/common/StringUtils.h>
50 : #include <utils/xml/SUMOSAXAttributes.h>
51 : #include <utils/router/DijkstraRouter.h>
52 : #include <utils/router/AStarRouter.h>
53 : #include <utils/router/CHRouter.h>
54 : #include <utils/router/CHRouterWrapper.h>
55 : #include <utils/vehicle/SUMOVehicleParserHelper.h>
56 : #include <utils/router/CCHGraph.h>
57 : #include <utils/router/CCHMetricFamily.h>
58 : #include <utils/router/CCHRouter.h>
59 : #pragma GCC diagnostic push
60 : #pragma GCC diagnostic ignored "-Wunused-parameter"
61 : #include <routingkit/customizable_contraction_hierarchy.h>
62 : #pragma GCC diagnostic pop
63 :
64 : //#define DEBUG_SEPARATE_TURNS
65 : #define DEBUG_COND(obj) (obj->isSelected())
66 :
67 : // ===========================================================================
68 : // static member variables
69 : // ===========================================================================
70 : std::vector<double> MSRoutingEngine::myEdgeSpeeds;
71 : std::vector<double> MSRoutingEngine::myEdgeBikeSpeeds;
72 : std::vector<MSRoutingEngine::TimeAndCount> MSRoutingEngine::myEdgeTravelTimes;
73 : std::vector<std::vector<double> > MSRoutingEngine::myPastEdgeSpeeds;
74 : std::vector<std::vector<double> > MSRoutingEngine::myPastEdgeBikeSpeeds;
75 : Command* MSRoutingEngine::myEdgeWeightSettingCommand = nullptr;
76 : double MSRoutingEngine::myAdaptationWeight(0);
77 : int MSRoutingEngine::myAdaptationSteps;
78 : int MSRoutingEngine::myAdaptationStepsIndex = 0;
79 : SUMOTime MSRoutingEngine::myAdaptationInterval = -1;
80 : SUMOTime MSRoutingEngine::myLastAdaptation = -1;
81 : bool MSRoutingEngine::myWithTaz;
82 : bool MSRoutingEngine::myBikeSpeeds;
83 : MSRouterProvider* MSRoutingEngine::myRouterProvider = nullptr;
84 : std::map<std::pair<const MSEdge*, const MSEdge*>, ConstMSRoutePtr> MSRoutingEngine::myCachedRoutes;
85 : double MSRoutingEngine::myPriorityFactor(0);
86 : double MSRoutingEngine::myMinEdgePriority(std::numeric_limits<double>::max());
87 : double MSRoutingEngine::myEdgePriorityRange(0);
88 : bool MSRoutingEngine::myDynamicRandomness(false);
89 : bool MSRoutingEngine::myHaveExtras(false);
90 :
91 : SUMOAbstractRouter<MSEdge, SUMOVehicle>::Operation MSRoutingEngine::myEffortFunc = &MSRoutingEngine::getEffort;
92 : #ifdef HAVE_FOX
93 : FXMutex MSRoutingEngine::myRouteCacheMutex;
94 : #endif
95 : MSCCHGraph* MSRoutingEngine::myCCHGraph = nullptr;
96 : MSCCHMetricFamily* MSRoutingEngine::myCCHLive = nullptr;
97 : MSCCHMetricFamily* MSRoutingEngine::myCCHFreeflow = nullptr;
98 :
99 :
100 : // ===========================================================================
101 : // method definitions
102 : // ===========================================================================
103 : void
104 1413745 : MSRoutingEngine::initWeightUpdate(SUMOTime lastAdaptation) {
105 1413745 : if (myAdaptationInterval == -1) {
106 8397 : myEdgeWeightSettingCommand = nullptr;
107 8397 : myLastAdaptation = lastAdaptation;
108 8397 : const OptionsCont& oc = OptionsCont::getOptions();
109 8397 : myWithTaz = oc.getBool("device.rerouting.with-taz");
110 8397 : myAdaptationInterval = string2time(oc.getString("device.rerouting.adaptation-interval"));
111 8397 : myAdaptationWeight = oc.getFloat("device.rerouting.adaptation-weight");
112 8397 : const SUMOTime period = string2time(oc.getString("device.rerouting.period"));
113 8397 : if (myAdaptationWeight < 1. && myAdaptationInterval > 0) {
114 : SUMOTime nextAdaptation = -1;
115 8323 : if (lastAdaptation >= 0) {
116 5 : nextAdaptation = lastAdaptation + myAdaptationInterval;
117 : }
118 8323 : myEdgeWeightSettingCommand = new StaticCommand<MSRoutingEngine>(&MSRoutingEngine::adaptEdgeEfforts);
119 8323 : MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(myEdgeWeightSettingCommand, nextAdaptation);
120 8397 : } else if (period > 0) {
121 0 : WRITE_WARNING(TL("Rerouting is useless if the edge weights do not get updated!"));
122 : }
123 16794 : OutputDevice::createDeviceByOption("device.rerouting.output", "weights", "meandata_file.xsd");
124 : }
125 1413745 : }
126 :
127 :
128 : void
129 89178868 : MSRoutingEngine::initEdgeWeights(SUMOVehicleClass svc, SUMOTime lastAdaption, int index) {
130 89178868 : const OptionsCont& oc = OptionsCont::getOptions();
131 89202184 : if (myAdaptationWeight == 0 || !oc.isDefault("device.rerouting.adaptation-steps")) {
132 89155552 : myAdaptationSteps = oc.getInt("device.rerouting.adaptation-steps");
133 : }
134 89178868 : if (myBikeSpeeds && svc == SVC_BICYCLE) {
135 336 : _initEdgeWeights(myEdgeBikeSpeeds, myPastEdgeBikeSpeeds);
136 : } else {
137 89178532 : _initEdgeWeights(myEdgeSpeeds, myPastEdgeSpeeds);
138 : }
139 89178868 : if (lastAdaption >= 0) {
140 186 : myLastAdaptation = lastAdaption;
141 : }
142 89178868 : if (index >= 0 && myAdaptationSteps > 0) {
143 : assert(index < myAdaptationSteps);
144 186 : myAdaptationStepsIndex = index;
145 : }
146 89178868 : }
147 :
148 :
149 : void
150 42187 : MSRoutingEngine::initWeightConstants(const OptionsCont& oc) {
151 84374 : if (oc.getFloat("weights.priority-factor") != 0) {
152 40 : myPriorityFactor = oc.getFloat("weights.priority-factor");
153 40 : if (myPriorityFactor < 0) {
154 0 : throw ProcessError(TL("weights.priority-factor cannot be negative."));
155 : }
156 40 : myMinEdgePriority = std::numeric_limits<double>::max();
157 : double maxEdgePriority = -std::numeric_limits<double>::max();
158 416 : for (const MSEdge* const edge : MSNet::getInstance()->getEdgeControl().getEdges()) {
159 376 : maxEdgePriority = MAX2(maxEdgePriority, (double)edge->getPriority());
160 632 : myMinEdgePriority = MIN2(myMinEdgePriority, (double)edge->getPriority());
161 : }
162 40 : myEdgePriorityRange = maxEdgePriority - myMinEdgePriority;
163 40 : if (myEdgePriorityRange == 0) {
164 0 : WRITE_WARNING(TL("Option weights.priority-factor does not take effect because all edges have the same priority"));
165 0 : myPriorityFactor = 0;
166 : }
167 : }
168 42187 : myDynamicRandomness = oc.getBool("weights.random-factor.dynamic");
169 42187 : myHaveExtras = gRoutingPreferences || myPriorityFactor != 0 || gWeightsRandomFactor != 1;
170 42187 : }
171 :
172 :
173 : void
174 89178868 : MSRoutingEngine::_initEdgeWeights(std::vector<double>& edgeSpeeds, std::vector<std::vector<double> >& pastEdgeSpeeds) {
175 89178868 : if (edgeSpeeds.empty()) {
176 8310 : const OptionsCont& oc = OptionsCont::getOptions();
177 8310 : const bool useLoaded = oc.getBool("device.rerouting.init-with-loaded-weights");
178 8310 : const double currentSecond = SIMTIME;
179 813125 : for (const MSEdge* const edge : MSNet::getInstance()->getEdgeControl().getEdges()) {
180 1609630 : while (edge->getNumericalID() >= (int)edgeSpeeds.size()) {
181 804815 : edgeSpeeds.push_back(0);
182 804815 : if (myAdaptationSteps > 0) {
183 804037 : pastEdgeSpeeds.push_back(std::vector<double>());
184 : }
185 806695 : if (MSGlobals::gWeightsSeparateTurns && edgeSpeeds == myEdgeSpeeds) {
186 1880 : myEdgeTravelTimes.push_back(TimeAndCount(0, 0));
187 : }
188 : }
189 804815 : if (useLoaded) {
190 124 : edgeSpeeds[edge->getNumericalID()] = edge->getLength() / MSNet::getTravelTime(edge, nullptr, currentSecond);
191 : } else {
192 804691 : edgeSpeeds[edge->getNumericalID()] = edge->getMeanSpeed();
193 : }
194 804815 : if (myAdaptationSteps > 0) {
195 804037 : pastEdgeSpeeds[edge->getNumericalID()] = std::vector<double>(myAdaptationSteps, edgeSpeeds[edge->getNumericalID()]);
196 : }
197 : }
198 8310 : myLastAdaptation = MSNet::getInstance()->getCurrentTimeStep();
199 : }
200 89178868 : }
201 :
202 :
203 : double
204 254099594 : MSRoutingEngine::getEffort(const MSEdge* const e, const SUMOVehicle* const v, double) {
205 : const int id = e->getNumericalID();
206 254099594 : if (id < (int)myEdgeSpeeds.size()) {
207 246244873 : return MAX2(e->getLength() / MAX2(myEdgeSpeeds[id], NUMERICAL_EPS), e->getMinimumTravelTime(v));
208 : }
209 7931638 : return e->getMinimumTravelTime(v);
210 : }
211 :
212 :
213 : double
214 3680 : MSRoutingEngine::getEffortBike(const MSEdge* const e, const SUMOVehicle* const v, double) {
215 : const int id = e->getNumericalID();
216 3680 : if (id < (int)myEdgeBikeSpeeds.size()) {
217 3666 : return MAX2(e->getLength() / MAX2(myEdgeBikeSpeeds[id], NUMERICAL_EPS), e->getMinimumTravelTime(v));
218 : }
219 14 : return e->getMinimumTravelTime(v);
220 : }
221 :
222 :
223 : double
224 126692 : MSRoutingEngine::getEffortExtra(const MSEdge* const e, const SUMOVehicle* const v, double t) {
225 6371 : double effort = (!myBikeSpeeds || v == nullptr || v->getVClass() != SVC_BICYCLE
226 131175 : ? getEffort(e, v, t)
227 1888 : : getEffortBike(e, v, t));
228 126692 : applyExtras(e, v, SIMSTEP, effort);
229 126692 : return effort;
230 : }
231 :
232 :
233 : double
234 4240 : MSRoutingEngine::getAssumedSpeed(const MSEdge* edge, const SUMOVehicle* veh) {
235 4240 : return edge->getLength() / myEffortFunc(edge, veh, 0);
236 : }
237 :
238 :
239 : SUMOTime
240 86900952 : MSRoutingEngine::adaptEdgeEfforts(SUMOTime currentTime) {
241 86900952 : initEdgeWeights(SVC_PASSENGER);
242 86900952 : if (myBikeSpeeds) {
243 256 : initEdgeWeights(SVC_BICYCLE);
244 : }
245 86900952 : if (MSNet::getInstance()->getVehicleControl().getDepartedVehicleNo() == 0) {
246 72517504 : return myAdaptationInterval;
247 : }
248 : {
249 : #ifdef HAVE_FOX
250 : FXMutexLock lock(myRouteCacheMutex);
251 : #endif
252 : myCachedRoutes.clear();
253 : }
254 14383448 : const MSEdgeVector& edges = MSNet::getInstance()->getEdgeControl().getEdges();
255 14383448 : const double newWeightFactor = (double)(1. - myAdaptationWeight);
256 : bool cchEdgeMoved = false;
257 847510865 : for (const MSEdge* const e : edges) {
258 8744922 : if (e->isDelayed()) {
259 : const int id = e->getNumericalID();
260 202223506 : double currSpeed = e->getMeanSpeed();
261 202223506 : if (MSGlobals::gWeightsSeparateTurns > 0 && e->getNumSuccessors() > 1) {
262 194890 : currSpeed = patchSpeedForTurns(e, currSpeed);
263 : }
264 : #ifdef DEBUG_SEPARATE_TURNS
265 : if (DEBUG_COND(e->getLanes()[0])) {
266 : std::cout << SIMTIME << " edge=" << e->getID()
267 : << " meanSpeed=" << e->getMeanSpeed()
268 : << " currSpeed=" << currSpeed
269 : << " oldestSpeed=" << myPastEdgeSpeeds[id][myAdaptationStepsIndex]
270 : << " oldAvg=" << myEdgeSpeeds[id]
271 : << "\n";
272 : }
273 : #endif
274 202223506 : const double oldSmoothedSpeed = myEdgeSpeeds[id];
275 202223506 : if (myAdaptationSteps > 0) {
276 : // moving average
277 202152032 : myEdgeSpeeds[id] += (currSpeed - myPastEdgeSpeeds[id][myAdaptationStepsIndex]) / myAdaptationSteps;
278 202152032 : myPastEdgeSpeeds[id][myAdaptationStepsIndex] = currSpeed;
279 202152032 : if (myBikeSpeeds) {
280 0 : const double currBikeSpeed = e->getMeanSpeedBike();
281 0 : myEdgeBikeSpeeds[id] += (currBikeSpeed - myPastEdgeBikeSpeeds[id][myAdaptationStepsIndex]) / myAdaptationSteps;
282 0 : myPastEdgeBikeSpeeds[id][myAdaptationStepsIndex] = currBikeSpeed;
283 : }
284 : } else {
285 : // exponential moving average
286 71474 : if (currSpeed != myEdgeSpeeds[id]) {
287 27754 : myEdgeSpeeds[id] = myEdgeSpeeds[id] * myAdaptationWeight + currSpeed * newWeightFactor;
288 : }
289 71474 : if (myBikeSpeeds) {
290 1454 : const double currBikeSpeed = e->getMeanSpeedBike();
291 1454 : if (currBikeSpeed != myEdgeBikeSpeeds[id]) {
292 902 : myEdgeBikeSpeeds[id] = myEdgeBikeSpeeds[id] * myAdaptationWeight + currBikeSpeed * newWeightFactor;
293 : }
294 : }
295 : }
296 : // sparse CCH re-customization: remember which edges actually
297 : // moved; the update deadband is applied at the customize barrier
298 202223506 : if (myCCHLive != nullptr && myEdgeSpeeds[id] != oldSmoothedSpeed) {
299 1115388 : myCCHLive->markDirty(e);
300 : cchEdgeMoved = true;
301 : }
302 : }
303 : }
304 14383448 : if (myAdaptationSteps > 0) {
305 14361336 : myAdaptationStepsIndex = (myAdaptationStepsIndex + 1) % myAdaptationSteps;
306 : }
307 14383448 : myLastAdaptation = currentTime;
308 : // The device's CCH customization barrier: re-customize the metrics from
309 : // the freshly updated speed tables and publish (double-buffered). Runs
310 : // on the main thread after the speed update; no worker query is in
311 : // flight at this point. The family skips quiet barriers and runs that
312 : // never route (see CCHMetricFamily::atBarrier: measured on Lausanne, the
313 : // unconditional per-tick customize was 80% of meso wall time at
314 : // adaptation-interval 2, and ran even with rerouting probability 0).
315 14383448 : if (myCCHLive != nullptr) {
316 287654 : myCCHLive->atBarrier(STEPS2TIME(currentTime), cchEdgeMoved);
317 : }
318 28766896 : if (OptionsCont::getOptions().isSet("device.rerouting.output")) {
319 13568 : OutputDevice& dev = OutputDevice::getDeviceByOption("device.rerouting.output");
320 13568 : dev.openTag(SUMO_TAG_INTERVAL);
321 13568 : dev.writeAttr(SUMO_ATTR_ID, "device.rerouting");
322 13568 : dev.writeAttr(SUMO_ATTR_BEGIN, STEPS2TIME(currentTime));
323 13568 : dev.writeAttr(SUMO_ATTR_END, STEPS2TIME(currentTime + myAdaptationInterval));
324 162963 : for (const MSEdge* e : edges) {
325 149395 : dev.openTag(SUMO_TAG_EDGE);
326 149395 : dev.writeAttr(SUMO_ATTR_ID, e->getID());
327 149395 : dev.writeAttr("traveltime", myEffortFunc(e, nullptr, STEPS2TIME(currentTime)));
328 149395 : if (myBikeSpeeds) {
329 : // @note edge-priority is not included here
330 1792 : dev.writeAttr("traveltimeBike", getEffortBike(e, nullptr, STEPS2TIME(currentTime)));
331 : }
332 298790 : dev.closeTag();
333 : }
334 27136 : dev.closeTag();
335 : }
336 14383448 : return myAdaptationInterval;
337 : }
338 :
339 :
340 : MSCCHGraph*
341 427 : MSRoutingEngine::ensureCCHGraph() {
342 427 : if (myCCHGraph == nullptr) {
343 302 : myCCHGraph = new MSCCHGraph(MSEdge::getAllEdges()); // union topology; class masks prime at first fill
344 : }
345 427 : return myCCHGraph;
346 : }
347 :
348 :
349 : void
350 229 : MSRoutingEngine::initCCH() {
351 229 : if (myCCHLive != nullptr) {
352 0 : return; // device-side state built once (the graph alone may already
353 : // exist for MSNet's free-flow router)
354 : }
355 : // One LIVE metric per vehicle TYPE known when routing starts (see
356 : // utils/router/CCHMetricFamily.h for the keying and buffer semantics).
357 : // All types share ONE CCH topology (the union); route files stream, so
358 : // types appearing later register through the family's wanted list and
359 : // get their metric at the next customization barrier.
360 229 : ensureCCHGraph();
361 229 : const OptionsCont& oc = OptionsCont::getOptions();
362 229 : myCCHLive = new MSCCHMetricFamily(
363 : myCCHGraph, myEffortFunc, &MSRoutingEngine::getEffort,
364 : oc.getFloat("device.rerouting.cch-update-threshold.factor"),
365 458 : STEPS2TIME(string2time(oc.getString("device.rerouting.cch-update-threshold.constant"))),
366 : &MSRoutingEngine::buildCCHRefVehicle,
367 916 : oc.getInt("device.rerouting.cch-ensemble"));
368 : std::vector<std::string> vtypeIDs;
369 229 : MSNet::getInstance()->getVehicleControl().insertVTypeIDs(vtypeIDs);
370 1678 : for (const std::string& id : vtypeIDs) {
371 1449 : const MSVehicleType* vt = MSNet::getInstance()->getVehicleControl().getVType(id, nullptr, true);
372 1449 : if (vt != nullptr && !vt->isVehicleSpecific()) {
373 1449 : myCCHLive->seedKey(vt);
374 : }
375 : }
376 : // publish initial metrics so the first queries succeed
377 229 : myCCHLive->customize(STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()));
378 229 : }
379 :
380 :
381 : SUMOVehicle*
382 1543 : MSRoutingEngine::buildCCHRefVehicle(const MSVehicleType* type, int slot) {
383 : // The effort-reference vehicle: constructed DIRECTLY (what buildVehicle
384 : // does minus initVehicle), so it is never counted in the vehicle
385 : // statistics, never given devices and never inserted -- it exists only
386 : // so every metric fill evaluates the same reference. The mean speed
387 : // factor makes it deterministic (the findRoute precedent) and the fixed
388 : // id makes the frozen weights.random-factor realization reproducible
389 : // (the random seed is a hash of the id).
390 1543 : SUMOVehicleParameter* pars = new SUMOVehicleParameter();
391 : // slot 0 keeps the historical id (and with it the frozen random-factor
392 : // realization); ensemble slots differ only in the id, which seeds their
393 : // own realization -- see CCHMetricFamily::RefVehicleFactory
394 3086 : pars->id = "cchRef:" + type->getID() + (slot == 0 ? "" : ":" + toString(slot));
395 : const MSEdge* refEdge = nullptr;
396 132724 : for (const MSEdge* e : MSEdge::getAllEdges()) {
397 132724 : if (!e->isInternal() && !e->isTazConnector()) {
398 : refEdge = e;
399 : break;
400 : }
401 : }
402 3086 : ConstMSRoutePtr route = std::make_shared<MSRoute>(pars->id, ConstMSEdgeVector({refEdge}), false, nullptr, StopParVector());
403 1543 : if (MSGlobals::gUseMesoSim) {
404 : return new MEVehicle(pars, route, const_cast<MSVehicleType*>(type),
405 3 : type->getSpeedFactor().getParameter(0));
406 : }
407 : return new MSVehicle(pars, route, const_cast<MSVehicleType*>(type),
408 4626 : type->getSpeedFactor().getParameter(0));
409 : }
410 :
411 :
412 : void
413 1416 : MSRoutingEngine::invalidateCCHEdge(const MSEdge* e) {
414 1416 : if (myCCHGraph == nullptr) {
415 : return;
416 : }
417 : // the primed connection masks reflect the OLD successor lists; the next
418 : // fill of either family re-primes from the live ones. Safe to do right
419 : // here: masks are only read at fill time, and every fill runs on the
420 : // main thread (the device barrier, the free-flow repair) -- never on a
421 : // query thread.
422 : myCCHGraph->invalidateClassMasks();
423 43 : if (myCCHFreeflow != nullptr) {
424 : myCCHFreeflow->flagPermissionsStale();
425 : }
426 43 : if (myCCHLive != nullptr) {
427 20 : myCCHLive->invalidateEdge(e);
428 : }
429 : }
430 :
431 :
432 : const RoutingKit::CustomizableContractionHierarchyMetric*
433 58836 : MSRoutingEngine::getPublishedCCHMetric(SUMOVehicleClass /* vClass */, SUMOTime /* time */, const SUMOVehicle* veh) {
434 : // the published metrics always track the live speeds; the query time
435 : // only matters for duarouter's per-weight-period metrics. Lookup is by
436 : // vehicle TYPE (the metric's exactness key); a vehicle-specific type
437 : // (TraCI-modified singular copy) routes on the exact fallback rather
438 : // than on another type's metric.
439 58836 : if (veh == nullptr || myCCHLive == nullptr) {
440 : return nullptr;
441 : }
442 58836 : const MSVehicleType* type = &veh->getVehicleType();
443 58836 : if (type->isVehicleSpecific()) {
444 : return nullptr;
445 : }
446 58836 : return myCCHLive->published(type, veh->getID());
447 : }
448 :
449 :
450 : const RoutingKit::CustomizableContractionHierarchyMetric*
451 16418 : MSRoutingEngine::getFreeflowCCHMetric(SUMOVehicleClass /* vClass */, SUMOTime /* time */, const SUMOVehicle* veh) {
452 : // MAIN-THREAD ONLY (see header): MSNet's routers serve TraCI, triggers
453 : // and the GUI, never the rerouting worker threads, so the family's lazy
454 : // creation and stale repair may run synchronously right here.
455 16418 : if (veh == nullptr) {
456 : return nullptr;
457 : }
458 : // Everything MSNet::getTravelTime reads ahead of the free-flow layer is
459 : // per-vehicle and cannot live in a shared metric -> exact fallback:
460 : // individual TraCI edge weights, global TraCI edge weights, a routing
461 : // mode other than DEFAULT (the AGGREGATED modes belong to the device
462 : // metrics; the transient-permission modes already fall back inside
463 : // CCHRouter::compute).
464 16418 : if (veh->getRoutingMode() != libsumo::ROUTING_MODE_DEFAULT
465 16418 : || !MSNet::getInstance()->getWeightsStorage().empty()) {
466 0 : return nullptr;
467 : }
468 16418 : const MSVehicle* const msVeh = dynamic_cast<const MSVehicle*>(veh);
469 16418 : if (msVeh != nullptr && !msVeh->getWeightsStorage().empty()) {
470 : return nullptr;
471 : }
472 16418 : const MSVehicleType* type = &veh->getVehicleType();
473 16418 : if (type->isVehicleSpecific()) {
474 : return nullptr;
475 : }
476 16418 : if (myCCHFreeflow == nullptr) {
477 : // free-flow efforts are static: a STATIC family with a single weight
478 : // period, lazily customized per type on first query
479 91 : myCCHFreeflow = new MSCCHMetricFamily(
480 91 : ensureCCHGraph(), &MSNet::getTravelTime, 0, SUMOTime_MAX,
481 182 : &MSRoutingEngine::buildCCHRefVehicle, nullptr);
482 : }
483 16418 : return myCCHFreeflow->get(type, type->getVehicleClass(),
484 16418 : MSNet::getInstance()->getCurrentTimeStep(), veh);
485 : }
486 :
487 :
488 : double
489 194890 : MSRoutingEngine::patchSpeedForTurns(const MSEdge* edge, double currSpeed) {
490 : const double length = edge->getLength();
491 : double maxSpeed = 0;
492 840432 : for (const auto& pair : edge->getViaSuccessors()) {
493 645542 : if (pair.second == nullptr) {
494 63678 : continue;
495 : }
496 581864 : TimeAndCount& tc = myEdgeTravelTimes[pair.second->getNumericalID()];
497 581864 : if (tc.second > 0) {
498 69261 : const double avgSpeed = length / STEPS2TIME(tc.first / tc.second);
499 : maxSpeed = MAX2(avgSpeed, maxSpeed);
500 : }
501 : }
502 194890 : if (maxSpeed > 0) {
503 : // perform correction
504 44133 : const double correctedSpeed = MSGlobals::gWeightsSeparateTurns * maxSpeed + (1 - MSGlobals::gWeightsSeparateTurns) * currSpeed;
505 197740 : for (const auto& pair : edge->getViaSuccessors()) {
506 153607 : if (pair.second == nullptr) {
507 15453 : continue;
508 : }
509 : const int iid = pair.second->getNumericalID();
510 138154 : TimeAndCount& tc = myEdgeTravelTimes[iid];
511 138154 : if (tc.second > 0) {
512 69261 : const double avgSpeed = length / STEPS2TIME(tc.first / tc.second);
513 69261 : if (avgSpeed < correctedSpeed) {
514 26911 : double internalTT = pair.second->getLength() / pair.second->getSpeedLimit();
515 26911 : internalTT += (length / avgSpeed - length / correctedSpeed) * MSGlobals::gWeightsSeparateTurns;
516 26911 : const double origInternalSpeed = myEdgeSpeeds[iid];
517 26911 : const double newInternalSpeed = pair.second->getLength() / internalTT;
518 26911 : const double origCurrSpeed = myPastEdgeSpeeds[iid][myAdaptationStepsIndex];
519 :
520 26911 : myEdgeSpeeds[iid] = newInternalSpeed;
521 : // to ensure myEdgeSpeed reverts to the speed limit
522 : // when there are no updates, we also have to patch
523 : // myPastEdgeSpeeds with a virtual value that is consistent
524 : // with the updated speed
525 : // note: internal edges were handled before the normal ones
526 26911 : const double virtualSpeed = (newInternalSpeed - (origInternalSpeed - origCurrSpeed / myAdaptationSteps)) * myAdaptationSteps;
527 26911 : myPastEdgeSpeeds[iid][myAdaptationStepsIndex] = virtualSpeed;
528 :
529 : #ifdef DEBUG_SEPARATE_TURNS
530 : if (DEBUG_COND(pair.second->getLanes()[0])) {
531 : std::cout << SIMTIME << " edge=" << edge->getID() << " to=" << pair.first->getID() << " via=" << pair.second->getID()
532 : << " origSpeed=" << currSpeed
533 : << " maxSpeed=" << maxSpeed
534 : << " correctedSpeed=" << correctedSpeed
535 : << " avgSpeed=" << avgSpeed
536 : << " internalTT=" << internalTT
537 : << " internalSpeed=" << origInternalSpeed
538 : << " newInternalSpeed=" << newInternalSpeed
539 : << " virtualSpeed=" << virtualSpeed
540 : << "\n";
541 : }
542 : #endif
543 : }
544 69261 : if (myAdaptationStepsIndex == 0) {
545 738 : tc.first = 0;
546 738 : tc.second = 0;
547 : }
548 : }
549 : }
550 : return correctedSpeed;
551 : }
552 : return currSpeed;
553 : }
554 :
555 :
556 : ConstMSRoutePtr
557 465910 : MSRoutingEngine::getCachedRoute(const std::pair<const MSEdge*, const MSEdge*>& key) {
558 : #ifdef HAVE_FOX
559 : // worker threads insert into the cache concurrently (RoutingTask::run)
560 : FXMutexLock lock(myRouteCacheMutex);
561 : #endif
562 : auto routeIt = myCachedRoutes.find(key);
563 465910 : if (routeIt != myCachedRoutes.end()) {
564 : return routeIt->second;
565 : }
566 : return nullptr;
567 : }
568 :
569 :
570 : void
571 8147 : MSRoutingEngine::initRouter(SUMOVehicle* vehicle) {
572 8147 : OptionsCont& oc = OptionsCont::getOptions();
573 8147 : const std::string routingAlgorithm = oc.getString("routing-algorithm");
574 8147 : const bool hasPermissions = MSNet::getInstance()->hasPermissions();
575 8147 : myBikeSpeeds = oc.getBool("device.rerouting.bike-speeds");
576 8147 : myEffortFunc = ((myHaveExtras || myBikeSpeeds) ? &MSRoutingEngine::getEffortExtra : &MSRoutingEngine::getEffort);
577 :
578 : SUMOAbstractRouter<MSEdge, SUMOVehicle>* router = nullptr;
579 8147 : if (routingAlgorithm == "dijkstra") {
580 7616 : router = new DijkstraRouter<MSEdge, SUMOVehicle>(MSEdge::getAllEdges(), true, myEffortFunc, nullptr, false, nullptr, true);
581 531 : } else if (routingAlgorithm == "astar") {
582 : typedef AStarRouter<MSEdge, SUMOVehicle, MSMapMatcher> AStar;
583 : std::shared_ptr<const AStar::LookupTable> lookup = nullptr;
584 568 : if (oc.isSet("astar.all-distances")) {
585 0 : lookup = std::make_shared<const AStar::FLT>(oc.getString("astar.all-distances"), (int)MSEdge::getAllEdges().size());
586 568 : } else if (oc.isSet("astar.landmark-distances") && vehicle != nullptr) {
587 35 : const double speedFactor = vehicle->getChosenSpeedFactor();
588 : // we need an exemplary vehicle with speedFactor 1
589 35 : vehicle->setChosenSpeedFactor(1);
590 : CHRouterWrapper<MSEdge, SUMOVehicle> chrouter(
591 35 : MSEdge::getAllEdges(), true, &MSNet::getTravelTime,
592 105 : string2time(oc.getString("begin")), string2time(oc.getString("end")), SUMOTime_MAX, hasPermissions, 1);
593 35 : lookup = std::make_shared<const AStar::LMLT>(oc.getString("astar.landmark-distances"), MSEdge::getAllEdges(), &chrouter,
594 70 : nullptr, vehicle, "", oc.getInt("device.rerouting.threads"), MSNet::getInstance()->getMapMatcher());
595 35 : vehicle->setChosenSpeedFactor(speedFactor);
596 35 : }
597 852 : router = new AStar(MSEdge::getAllEdges(), true, myEffortFunc, lookup, true);
598 247 : } else if (routingAlgorithm == "CH" && !hasPermissions) {
599 0 : const SUMOTime weightPeriod = myAdaptationInterval > 0 ? myAdaptationInterval : SUMOTime_MAX;
600 : router = new CHRouter<MSEdge, SUMOVehicle>(
601 0 : MSEdge::getAllEdges(), true, myEffortFunc, vehicle == nullptr ? SVC_PASSENGER : vehicle->getVClass(), weightPeriod, true, false);
602 247 : } else if (routingAlgorithm == "CHWrapper" || routingAlgorithm == "CH") {
603 : // use CHWrapper instead of CH if the net has permissions
604 18 : const SUMOTime weightPeriod = myAdaptationInterval > 0 ? myAdaptationInterval : SUMOTime_MAX;
605 : router = new CHRouterWrapper<MSEdge, SUMOVehicle>(
606 18 : MSEdge::getAllEdges(), true, myEffortFunc,
607 54 : string2time(oc.getString("begin")), string2time(oc.getString("end")), weightPeriod, hasPermissions, oc.getInt("device.rerouting.threads"));
608 229 : } else if (routingAlgorithm == "CCH") {
609 : // CCH metrics are keyed by vehicle TYPE and filled with a reference
610 : // vehicle of the type (customizeCCH), mirroring duarouter's
611 : // RODUACCHMetrics: type/class-specific routing preferences, the
612 : // bicycle speed table, the type's maximum speed and the static
613 : // priority multiplier are captured exactly per metric.
614 : // weights.random-factor freezes one realization per metric -- the
615 : // same approximation CHRouterWrapper makes when building its
616 : // hierarchies; exact per-vehicle randomization remains the domain of
617 : // dijkstra and astar.
618 229 : initCCH(); // build the immutable topology + publish an initial metric (once)
619 : // embedded fallback for non-passenger / prohibited / unreachable queries
620 : SUMOAbstractRouter<MSEdge, SUMOVehicle>* fallback =
621 229 : new AStarRouter<MSEdge, SUMOVehicle, MSMapMatcher>(MSEdge::getAllEdges(), true, myEffortFunc, nullptr, true);
622 : router = new CCHRouter<MSEdge, SUMOVehicle, MSCCHGraph>(
623 229 : myCCHGraph, &MSRoutingEngine::getPublishedCCHMetric, myEffortFunc, true, fallback);
624 : } else {
625 0 : throw ProcessError(TLF("Unknown routing algorithm '%'!", routingAlgorithm));
626 : }
627 :
628 : RailwayRouter<MSEdge, SUMOVehicle>* railRouter = nullptr;
629 8147 : if (MSNet::getInstance()->hasBidiEdges()) {
630 580 : railRouter = new RailwayRouter<MSEdge, SUMOVehicle>(MSEdge::getAllEdges(), true, myEffortFunc, nullptr, false, true, false,
631 : oc.getFloat("railway.max-train-length"),
632 1160 : oc.getFloat("weights.reversal-penalty"));
633 : }
634 9071 : const int carWalk = SUMOVehicleParserHelper::parseCarWalkTransfer(oc, MSDevice_Taxi::hasFleet() || MSNet::getInstance()->getInsertionControl().hasTaxiFlow());
635 8147 : const double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
636 8147 : MSTransportableRouter* transRouter = new MSTransportableRouter(MSNet::adaptIntermodalRouter, carWalk, taxiWait, routingAlgorithm, 0);
637 8147 : myRouterProvider = new MSRouterProvider(router, nullptr, transRouter, railRouter);
638 : #ifndef THREAD_POOL
639 : #ifdef HAVE_FOX
640 8147 : MFXWorkerThread::Pool& threadPool = MSNet::getInstance()->getEdgeControl().getThreadPool();
641 8147 : if (threadPool.size() > 0) {
642 : const std::vector<MFXWorkerThread*>& threads = threadPool.getWorkers();
643 1135 : if (static_cast<MSEdgeControl::WorkerThread*>(threads.front())->setRouterProvider(myRouterProvider)) {
644 4462 : for (std::vector<MFXWorkerThread*>::const_iterator t = threads.begin() + 1; t != threads.end(); ++t) {
645 3327 : static_cast<MSEdgeControl::WorkerThread*>(*t)->setRouterProvider(myRouterProvider->clone());
646 : }
647 : }
648 : }
649 : #endif
650 : #endif
651 8147 : }
652 :
653 :
654 : void
655 2272151 : MSRoutingEngine::reroute(SUMOVehicle& vehicle, const SUMOTime currentTime, const std::string& info,
656 : const bool onInit, const bool silent, const Prohibitions& prohibited) {
657 2272151 : if (myRouterProvider == nullptr) {
658 7699 : initRouter(&vehicle);
659 : }
660 2272151 : auto& router = myRouterProvider->getVehicleRouter(vehicle.getVClass());
661 : #ifndef THREAD_POOL
662 : #ifdef HAVE_FOX
663 2272151 : MFXWorkerThread::Pool& threadPool = MSNet::getInstance()->getEdgeControl().getThreadPool();
664 2272151 : if (threadPool.size() > 0) {
665 171961 : threadPool.add(new RoutingTask(vehicle, currentTime, info, onInit, silent, prohibited));
666 171961 : return;
667 : }
668 : #endif
669 : #endif
670 2100190 : if (!prohibited.empty()) {
671 4 : router.prohibit(prohibited);
672 : }
673 : try {
674 2100190 : vehicle.reroute(currentTime, info, router, onInit, myWithTaz, silent);
675 109 : } catch (ProcessError&) {
676 109 : if (!silent) {
677 109 : if (!prohibited.empty()) {
678 0 : router.prohibit(Prohibitions());
679 : }
680 109 : throw;
681 : }
682 109 : }
683 2100081 : if (!prohibited.empty()) {
684 8 : router.prohibit(Prohibitions());
685 : }
686 : }
687 :
688 :
689 : void
690 136 : MSRoutingEngine::reroute(MSTransportable& t, const SUMOTime currentTime, const std::string& info,
691 : const bool onInit, const bool silent, const Prohibitions& prohibited) {
692 136 : MSTransportableRouter& router = getIntermodalRouterTT(t.getRNGIndex(), prohibited);
693 : #ifndef THREAD_POOL
694 : #ifdef HAVE_FOX
695 136 : MFXWorkerThread::Pool& threadPool = MSNet::getInstance()->getEdgeControl().getThreadPool();
696 136 : if (threadPool.size() > 0) {
697 : // threadPool.add(new RoutingTask(t, currentTime, info, onInit, silent, prohibited));
698 : return;
699 : }
700 : #endif
701 : #endif
702 118 : if (!prohibited.empty()) {
703 0 : router.prohibit(prohibited);
704 : }
705 : try {
706 118 : t.reroute(currentTime, info, router, onInit, myWithTaz, silent);
707 0 : } catch (ProcessError&) {
708 0 : if (!silent) {
709 0 : if (!prohibited.empty()) {
710 0 : router.prohibit(Prohibitions());
711 : }
712 0 : throw;
713 : }
714 0 : }
715 118 : if (!prohibited.empty()) {
716 0 : router.prohibit(Prohibitions());
717 : }
718 : }
719 :
720 :
721 : void
722 9 : MSRoutingEngine::setEdgeTravelTime(const MSEdge* const edge, const double travelTime) {
723 9 : myEdgeSpeeds[edge->getNumericalID()] = edge->getLength() / travelTime;
724 9 : }
725 :
726 : void
727 13518 : MSRoutingEngine::addEdgeTravelTime(const MSEdge& edge, const SUMOTime travelTime) {
728 13518 : TimeAndCount& tc = myEdgeTravelTimes[edge.getNumericalID()];
729 13518 : tc.first += travelTime;
730 13518 : tc.second += 1;
731 13518 : }
732 :
733 :
734 : MSVehicleRouter&
735 633538 : MSRoutingEngine::getRouterTT(const int rngIndex, SUMOVehicleClass svc, const Prohibitions& prohibited) {
736 633538 : if (myRouterProvider == nullptr) {
737 186 : initWeightUpdate();
738 186 : initEdgeWeights(svc);
739 186 : initRouter();
740 : }
741 : #ifndef THREAD_POOL
742 : #ifdef HAVE_FOX
743 633538 : MFXWorkerThread::Pool& threadPool = MSNet::getInstance()->getEdgeControl().getThreadPool();
744 633538 : if (threadPool.size() > 0) {
745 33930 : auto& router = static_cast<MSEdgeControl::WorkerThread*>(threadPool.getWorkers()[rngIndex % MSGlobals::gNumThreads])->getRouter(svc);
746 33930 : router.prohibit(prohibited);
747 33930 : return router;
748 : }
749 : #else
750 : UNUSED_PARAMETER(rngIndex);
751 : #endif
752 : #endif
753 1199216 : myRouterProvider->getVehicleRouter(svc).prohibit(prohibited);
754 599608 : return myRouterProvider->getVehicleRouter(svc);
755 : }
756 :
757 :
758 : MSTransportableRouter&
759 4651 : MSRoutingEngine::getIntermodalRouterTT(const int rngIndex, const Prohibitions& prohibited) {
760 4651 : if (myRouterProvider == nullptr) {
761 262 : initWeightUpdate();
762 262 : initEdgeWeights(SVC_PEDESTRIAN);
763 262 : initRouter();
764 : }
765 : #ifndef THREAD_POOL
766 : #ifdef HAVE_FOX
767 4651 : MFXWorkerThread::Pool& threadPool = MSNet::getInstance()->getEdgeControl().getThreadPool();
768 4651 : if (threadPool.size() > 0) {
769 4533 : auto& router = static_cast<MSEdgeControl::WorkerThread*>(threadPool.getWorkers()[rngIndex % MSGlobals::gNumThreads])->getIntermodalRouter();
770 4533 : router.prohibit(prohibited);
771 4533 : return router;
772 : }
773 : #else
774 : UNUSED_PARAMETER(rngIndex);
775 : #endif
776 : #endif
777 118 : myRouterProvider->getIntermodalRouter().prohibit(prohibited);
778 118 : return myRouterProvider->getIntermodalRouter();
779 : }
780 :
781 :
782 : void
783 85961 : MSRoutingEngine::cleanupCCH() {
784 : // free the CCH state so a subsequent load (libsumo / GUI reload) rebuilds
785 : // it against the new network; the router clones referencing it were
786 : // deleted together with the worker threads / router provider.
787 : // Deleting the metric families' owned ref vehicles dereferences their
788 : // MSVehicleType*, so this must run BEFORE MSNet deletes its
789 : // MSVehicleControl (see the call in ~MSNet); the nullptr checks below
790 : // make a second call from cleanup() a safe no-op.
791 85961 : delete myCCHLive;
792 85961 : myCCHLive = nullptr;
793 85961 : delete myCCHFreeflow;
794 85961 : myCCHFreeflow = nullptr;
795 85961 : delete myCCHGraph;
796 85961 : myCCHGraph = nullptr;
797 85961 : }
798 :
799 :
800 : void
801 43126 : MSRoutingEngine::cleanup() {
802 43126 : myAdaptationInterval = -1; // responsible for triggering initEdgeWeights
803 : myPastEdgeSpeeds.clear();
804 : myEdgeSpeeds.clear();
805 : myEdgeTravelTimes.clear();
806 : myPastEdgeBikeSpeeds.clear();
807 : myEdgeBikeSpeeds.clear();
808 : // @todo recheck. calling release crashes in parallel routing
809 : //for (auto& item : myCachedRoutes) {
810 : // item.second->release();
811 : //}
812 : {
813 : #ifdef HAVE_FOX
814 : FXMutexLock lock(myRouteCacheMutex);
815 : #endif
816 : myCachedRoutes.clear();
817 : }
818 43126 : myAdaptationStepsIndex = 0;
819 43126 : cleanupCCH();
820 : #ifdef HAVE_FOX
821 43126 : if (MSGlobals::gNumThreads > 1) {
822 : // router deletion is done in thread destructor
823 4561 : myRouterProvider = nullptr;
824 4561 : return;
825 : }
826 : #endif
827 38565 : delete myRouterProvider;
828 38565 : myRouterProvider = nullptr;
829 : }
830 :
831 :
832 : void
833 535 : MSRoutingEngine::saveState(OutputDevice& out) {
834 535 : if (myEdgeSpeeds.size() == 0) {
835 : return;
836 : }
837 116 : out.openTag(SUMO_TAG_ROUTINGENGINE);
838 116 : out.writeAttr(SUMO_ATTR_LAST, myLastAdaptation);
839 116 : out.writeAttr(SUMO_ATTR_INDEX, myAdaptationStepsIndex);
840 116 : const MSEdgeVector& edges = MSNet::getInstance()->getEdgeControl().getEdges();
841 9390 : for (const MSEdge* const e : edges) {
842 0 : if (e->isDelayed()) {
843 : const int id = e->getNumericalID();
844 1434 : out.openTag(SUMO_TAG_EDGE);
845 1434 : out.writeAttr(SUMO_ATTR_ID, e->getID());
846 1434 : out.writeAttr(SUMO_ATTR_SPEED, myEdgeSpeeds[id]);
847 1434 : if (myAdaptationSteps > 0) {
848 1434 : out.writeAttr(SUMO_ATTR_PASTSPEED, myPastEdgeSpeeds[id]);
849 : }
850 1434 : if (myBikeSpeeds) {
851 0 : out.writeAttr(SUMO_ATTR_BIKESPEED, myEdgeBikeSpeeds[id]);
852 0 : if (myAdaptationSteps > 0) {
853 0 : out.writeAttr(SUMO_ATTR_PASTBIKESPEED, myPastEdgeBikeSpeeds[id]);
854 : }
855 : }
856 2868 : out.closeTag();
857 : }
858 : }
859 232 : out.closeTag();
860 : }
861 :
862 :
863 : void
864 1818 : MSRoutingEngine::loadState(const SUMOSAXAttributes& attrs) {
865 3636 : const MSEdge* const e = MSEdge::dictionary(attrs.getString(SUMO_ATTR_ID));
866 : e->markDelayed();
867 : const int id = e->getNumericalID();
868 : bool checkedSteps = false;
869 : bool checkedBikeSpeeds = false;
870 1818 : bool ok = true;
871 1818 : if ((int)myEdgeSpeeds.size() > id) {
872 1818 : myEdgeSpeeds[id] = attrs.get<double>(SUMO_ATTR_SPEED, nullptr, ok);
873 1818 : if (myBikeSpeeds) {
874 0 : if (attrs.hasAttribute(SUMO_ATTR_BIKESPEED)) {
875 0 : myEdgeBikeSpeeds[id] = attrs.get<double>(SUMO_ATTR_BIKESPEED, nullptr, ok);
876 : } else if (!checkedBikeSpeeds) {
877 : checkedBikeSpeeds = true;
878 0 : WRITE_WARNING("Bike speeds missing in loaded state");
879 : }
880 : }
881 1818 : if (myAdaptationSteps > 0) {
882 1818 : const std::vector<double> speeds = attrs.getOpt<std::vector<double> >(SUMO_ATTR_PASTSPEED, nullptr, ok);
883 1818 : if ((int)speeds.size() == myAdaptationSteps) {
884 1818 : myPastEdgeSpeeds[id] = speeds;
885 1818 : if (myBikeSpeeds && attrs.hasAttribute(SUMO_ATTR_PASTBIKESPEED)) {
886 0 : myPastEdgeBikeSpeeds[id] = attrs.getOpt<std::vector<double> >(SUMO_ATTR_PASTBIKESPEED, nullptr, ok);
887 : }
888 : } else if (!checkedSteps) {
889 : checkedSteps = true;
890 0 : WRITE_WARNING("Number of adaptation speeds in loaded state doesn't match option --device.rerouting.adaptation-steps");
891 : }
892 1818 : }
893 : }
894 1818 : }
895 :
896 :
897 : #ifdef HAVE_FOX
898 : void
899 420310354 : MSRoutingEngine::waitForAll() {
900 : #ifndef THREAD_POOL
901 420310354 : MFXWorkerThread::Pool& threadPool = MSNet::getInstance()->getEdgeControl().getThreadPool();
902 420310354 : if (threadPool.size() > 0) {
903 241062860 : threadPool.waitAll();
904 : }
905 : #endif
906 420310329 : }
907 :
908 :
909 : // ---------------------------------------------------------------------------
910 : // MSRoutingEngine::RoutingTask-methods
911 : // ---------------------------------------------------------------------------
912 : void
913 171961 : MSRoutingEngine::RoutingTask::run(MFXWorkerThread* context) {
914 171961 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = static_cast<MSEdgeControl::WorkerThread*>(context)->getRouter(myVehicle.getVClass());
915 171961 : if (!myProhibited.empty()) {
916 2 : router.prohibit(myProhibited);
917 : }
918 : try {
919 171961 : myVehicle.reroute(myTime, myInfo, router, myOnInit, myWithTaz, mySilent);
920 25 : } catch (ProcessError&) {
921 25 : if (!mySilent) {
922 25 : if (!myProhibited.empty()) {
923 0 : router.prohibit(Prohibitions());
924 : }
925 25 : throw;
926 : }
927 25 : }
928 171936 : if (!myProhibited.empty()) {
929 4 : router.prohibit(Prohibitions());
930 : }
931 171936 : const MSEdge* source = *myVehicle.getRoute().begin();
932 171936 : const MSEdge* dest = myVehicle.getRoute().getLastEdge();
933 171936 : if (source->isTazConnector() && dest->isTazConnector()) {
934 4 : const std::pair<const MSEdge*, const MSEdge*> key = std::make_pair(source, dest);
935 : FXMutexLock lock(myRouteCacheMutex);
936 4 : if (MSRoutingEngine::myCachedRoutes.find(key) == MSRoutingEngine::myCachedRoutes.end()) {
937 6 : MSRoutingEngine::myCachedRoutes[key] = myVehicle.getRoutePtr();
938 : }
939 : }
940 171936 : }
941 :
942 :
943 : #endif
944 :
945 :
946 : /****************************************************************************/
|