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