Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2005-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MSCalibrator.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Tue, May 2005
19 : ///
20 : // Calibrates the flow on an edge by removing an inserting vehicles
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <string>
25 : #include <algorithm>
26 : #include <cmath>
27 : #include <microsim/MSNet.h>
28 : #include <microsim/MSEdge.h>
29 : #include <microsim/MSJunction.h>
30 : #include <microsim/MSLane.h>
31 : #include <microsim/MSEventControl.h>
32 : #include <microsim/MSVehicleControl.h>
33 : #include <microsim/output/MSRouteProbe.h>
34 : #include <utils/xml/SUMOXMLDefinitions.h>
35 : #include <utils/common/ToString.h>
36 : #include <utils/common/UtilExceptions.h>
37 : #include <utils/common/StringTokenizer.h>
38 : #include <utils/xml/XMLSubSys.h>
39 : #include <utils/common/StringUtils.h>
40 : #include <utils/options/OptionsCont.h>
41 : #include <utils/vehicle/SUMOVehicleParserHelper.h>
42 : #include <utils/distribution/RandomDistributor.h>
43 : #include <utils/vehicle/SUMOVehicleParameter.h>
44 : #include "MSCalibrator.h"
45 :
46 : //#define MSCalibrator_DEBUG
47 :
48 : #define DEBUGID ""
49 : #define DEBUGCOND (getID() == DEBUGID)
50 : #define DEBUGCOND2(id) ((id) == DEBUGID)
51 :
52 : // ===========================================================================
53 : // static members
54 : // ===========================================================================
55 : std::vector<MSMoveReminder*> MSCalibrator::myLeftoverReminders;
56 : std::vector<SUMOVehicleParameter*> MSCalibrator::myLeftoverVehicleParameters;
57 : std::map<std::string, MSCalibrator*> MSCalibrator::myInstances;
58 :
59 : // ===========================================================================
60 : // CalibratorCommand method definitions
61 : // ===========================================================================
62 :
63 : SUMOTime
64 5 : MSCalibrator::CalibratorCommand::shiftTime(SUMOTime currentTime, SUMOTime execTime, SUMOTime newTime) {
65 : UNUSED_PARAMETER(currentTime);
66 : UNUSED_PARAMETER(execTime);
67 : UNUSED_PARAMETER(newTime);
68 5 : myCalibrator->myCurrentStateInterval = myCalibrator->myIntervals.begin();
69 5 : return 0;
70 : }
71 :
72 :
73 : // ===========================================================================
74 : // method definitions
75 : // ===========================================================================
76 1130 : MSCalibrator::MSCalibrator(const std::string& id,
77 : MSEdge* const edge,
78 : MSLane* const lane,
79 : MSJunction* const node,
80 : const double pos,
81 : const std::string& aXMLFilename,
82 : const std::string& outputFilename,
83 : const SUMOTime freq, const double length,
84 : const MSRouteProbe* probe,
85 : const double invalidJamThreshold,
86 : const std::string& vTypes,
87 : const bool local,
88 1130 : const bool addLaneMeanData) :
89 : MSRouteHandler(aXMLFilename, true),
90 : MSDetectorFileOutput(id, vTypes, "", (int)PersonMode::NONE), // detecting persons not yet supported
91 1130 : myEdge(edge),
92 1130 : myLane(lane),
93 1130 : myNode(node),
94 1130 : myPos(pos), myProbe(probe),
95 2260 : myMeanDataParent(id + "_dummyMeanData", 0, 0, false, false, false, false, false, false, 1, 0, 0, vTypes, "",
96 1130 : std::vector<MSEdge*>(), false),
97 1130 : myEdgeMeanData(nullptr, length, false, &myMeanDataParent),
98 : myCurrentStateInterval(myIntervals.begin()),
99 1130 : myOutput(nullptr), myFrequency(freq), myRemoved(0),
100 1130 : myInserted(0),
101 1130 : myClearedInJam(0),
102 1130 : mySpeedIsDefault(true), myDidSpeedAdaption(false), myDidInit(false),
103 1130 : myDefaultSpeed(myLane == nullptr ? (myEdge == nullptr ? 0. : myEdge->getSpeedLimit()) : myLane->getSpeedLimit()),
104 1130 : myHaveWarnedAboutClearingJam(false),
105 1130 : myAmActive(false),
106 1130 : myInvalidJamThreshold(invalidJamThreshold),
107 1130 : myAmLocal(local),
108 3390 : myHaveInvalidJam(false) {
109 1130 : if (outputFilename != "") {
110 267 : myOutput = &OutputDevice::getDevice(outputFilename);
111 267 : writeXMLDetectorProlog(*myOutput);
112 : }
113 1130 : if (aXMLFilename != "") {
114 49 : XMLSubSys::runParser(*this, aXMLFilename);
115 49 : if (!myDidInit) {
116 0 : init();
117 : }
118 : }
119 1130 : myInstances[id] = this;
120 1130 : if (addLaneMeanData && myEdge != nullptr) {
121 : // disabled for METriggeredCalibrator
122 2736 : for (MSLane* const eLane : myEdge->getLanes()) {
123 1702 : if (myLane == nullptr || myLane == eLane) {
124 : //std::cout << " cali=" << getID() << " myLane=" << Named::getIDSecure(myLane) << " checkLane=" << i << "\n";
125 1172 : MSMeanData_Net::MSLaneMeanDataValues* laneData = new MSMeanData_Net::MSLaneMeanDataValues(eLane, eLane->getLength(), true, &myMeanDataParent);
126 1172 : laneData->setDescription("meandata_calibrator_" + eLane->getID());
127 1172 : myLeftoverReminders.push_back(laneData);
128 1172 : myLaneMeanData.push_back(laneData);
129 1172 : VehicleRemover* remover = new VehicleRemover(eLane, this);
130 1172 : myLeftoverReminders.push_back(remover);
131 1172 : myVehicleRemovers.push_back(remover);
132 : }
133 : }
134 : }
135 1130 : if (node != nullptr) {
136 30 : for (const MSEdge* inEdge : myNode->getIncoming()) {
137 40 : for (MSLane* const eLane : inEdge->getLanes()) {
138 20 : VehicleRemover* remover = new VehicleRemover(eLane, this);
139 20 : myLeftoverReminders.push_back(remover);
140 20 : myVehicleRemovers.push_back(remover);
141 : }
142 : }
143 10 : if (local) {
144 20 : for (const MSEdge* outEdge : myNode->getOutgoing()) {
145 30 : for (MSLane* const eLane : outEdge->getLanes()) {
146 15 : VehicleRemover* remover = new VehicleRemover(eLane, this, true);
147 15 : myLeftoverReminders.push_back(remover);
148 15 : myVehicleRemovers.push_back(remover);
149 : }
150 : }
151 : }
152 : }
153 1130 : }
154 :
155 :
156 : void
157 1130 : MSCalibrator::init() {
158 1130 : if (myIntervals.size() > 0) {
159 374 : if (myIntervals.back().end == -1) {
160 7 : myIntervals.back().end = SUMOTime_MAX;
161 : }
162 : // calibration should happen after regular insertions have taken place
163 374 : MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(new CalibratorCommand(this));
164 : } else {
165 2268 : WRITE_WARNINGF(TL("No flow intervals in calibrator '%'."), getID());
166 : }
167 1130 : myDidInit = true;
168 1130 : }
169 :
170 :
171 2174 : MSCalibrator::~MSCalibrator() {
172 1130 : if (myCurrentStateInterval != myIntervals.end()) {
173 92 : intervalEnd();
174 : }
175 2337 : for (VehicleRemover* const remover : myVehicleRemovers) {
176 : remover->disable();
177 : }
178 : myInstances.erase(getID());
179 2174 : }
180 :
181 :
182 : MSCalibrator::AspiredState
183 123 : MSCalibrator::getCurrentStateInterval() const {
184 123 : if (myCurrentStateInterval == myIntervals.end()) {
185 0 : throw ProcessError(TLF("Calibrator '%' has no active or upcoming interval", getID()));
186 : }
187 123 : return *myCurrentStateInterval;
188 : }
189 :
190 :
191 : void
192 964 : MSCalibrator::myStartElement(int element,
193 : const SUMOSAXAttributes& attrs) {
194 964 : if (element == SUMO_TAG_FLOW) {
195 : AspiredState state;
196 : SUMOTime lastEnd = -1;
197 : SUMOTime lastBegin = -1;
198 682 : if (myIntervals.size() > 0) {
199 308 : lastEnd = myIntervals.back().end;
200 308 : lastBegin = myIntervals.back().begin;
201 308 : if (lastEnd == -1) {
202 : lastEnd = myIntervals.back().begin;
203 : }
204 : }
205 : try {
206 682 : bool ok = true;
207 682 : state.q = attrs.getOpt<double>(SUMO_ATTR_VEHSPERHOUR, nullptr, ok, -1.);
208 682 : state.v = attrs.getOpt<double>(SUMO_ATTR_SPEED, nullptr, ok, -1.);
209 682 : state.begin = attrs.getSUMOTimeReporting(SUMO_ATTR_BEGIN, getID().c_str(), ok);
210 682 : if (state.begin < lastEnd) {
211 21 : WRITE_ERRORF("Overlapping or unsorted intervals in calibrator '%' (end=%, begin2=%).", getID(), time2string(lastEnd), time2string(state.begin));
212 675 : } else if (state.begin <= lastBegin) {
213 21 : WRITE_ERRORF("Overlapping or unsorted intervals in calibrator '%' (begin=%, begin2=%).", getID(), time2string(lastBegin), time2string(state.begin));
214 : }
215 682 : state.end = attrs.getOptSUMOTimeReporting(SUMO_ATTR_END, getID().c_str(), ok, -1);
216 682 : state.vehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(element, attrs, true, true, true);
217 682 : state.vehicleParameter->parametersSet &= ~VEHPARS_CALIBRATORSPEED_SET;
218 682 : myLeftoverVehicleParameters.push_back(state.vehicleParameter);
219 : // vehicles should be inserted with max speed unless stated otherwise
220 682 : if (state.vehicleParameter->departSpeedProcedure == DepartSpeedDefinition::DEFAULT) {
221 635 : state.vehicleParameter->departSpeedProcedure = DepartSpeedDefinition::MAX;
222 : }
223 : // vehicles should be inserted on any lane unless stated otherwise
224 682 : if (state.vehicleParameter->departLaneProcedure == DepartLaneDefinition::DEFAULT) {
225 675 : if (myLane == nullptr) {
226 346 : state.vehicleParameter->departLaneProcedure = DepartLaneDefinition::ALLOWED_FREE;
227 : } else {
228 329 : state.vehicleParameter->departLaneProcedure = DepartLaneDefinition::GIVEN;
229 329 : state.vehicleParameter->departLane = myLane->getIndex();
230 : }
231 7 : } else if (myLane != nullptr && (
232 : state.vehicleParameter->departLaneProcedure != DepartLaneDefinition::GIVEN
233 0 : || state.vehicleParameter->departLane != myLane->getIndex())) {
234 0 : WRITE_WARNINGF(TL("Insertion lane may differ from calibrator lane for calibrator '%'."), getID());
235 : }
236 849 : if (state.vehicleParameter->vtypeid != DEFAULT_VTYPE_ID &&
237 167 : MSNet::getInstance()->getVehicleControl().getVType(state.vehicleParameter->vtypeid) == nullptr) {
238 0 : WRITE_ERRORF(TL("Unknown vehicle type '%' in calibrator '%'."), state.vehicleParameter->vtypeid, getID());
239 : }
240 0 : } catch (EmptyData&) {
241 0 : WRITE_ERRORF(TL("Mandatory attribute missing in definition of calibrator '%'."), getID());
242 0 : } catch (NumberFormatException&) {
243 0 : WRITE_ERRORF(TL("Non-numeric value for numeric attribute in definition of calibrator '%'."), getID());
244 0 : }
245 682 : if (state.q < 0 && state.v < 0 && state.vehicleParameter->vtypeid == DEFAULT_VTYPE_ID) {
246 0 : WRITE_ERRORF(TL("Either 'vehsPerHour', 'speed' or 'type' has to be set in flow definition of calibrator '%'."), getID());
247 : }
248 682 : if (MSGlobals::gUseMesoSim && state.q < 0 && state.vehicleParameter->vtypeid != DEFAULT_VTYPE_ID) {
249 42 : WRITE_ERRORF(TL("Type calibration is not supported in meso for calibrator '%'."), getID());
250 : }
251 682 : if (myIntervals.size() > 0 && myIntervals.back().end == -1) {
252 7 : myIntervals.back().end = state.begin;
253 : }
254 682 : myIntervals.push_back(state);
255 682 : myCurrentStateInterval = myIntervals.begin();
256 : } else {
257 282 : MSRouteHandler::myStartElement(element, attrs);
258 : }
259 964 : }
260 :
261 :
262 : void
263 2045 : MSCalibrator::myEndElement(int element) {
264 2045 : if (element == SUMO_TAG_CALIBRATOR) {
265 1130 : if (!myDidInit) {
266 1130 : init();
267 : }
268 : // ensure correct state of SUMORouteHandler::myElementStack
269 1130 : callParentEnd(element);
270 915 : } else if (element != SUMO_TAG_FLOW) {
271 233 : MSRouteHandler::myEndElement(element);
272 : }
273 2045 : }
274 :
275 :
276 : void
277 685 : MSCalibrator::intervalEnd() {
278 685 : if (myOutput != nullptr) {
279 491 : writeXMLOutput(*myOutput, myCurrentStateInterval->begin, myCurrentStateInterval->end);
280 : }
281 685 : myDidSpeedAdaption = false;
282 685 : myInserted = 0;
283 685 : myRemoved = 0;
284 685 : myClearedInJam = 0;
285 685 : myHaveWarnedAboutClearingJam = false;
286 685 : reset();
287 685 : }
288 :
289 :
290 : bool
291 618571 : MSCalibrator::isCurrentStateActive(SUMOTime time) {
292 619137 : while (myCurrentStateInterval != myIntervals.end() && myCurrentStateInterval->end <= time) {
293 : // XXX what about skipped intervals?
294 : myCurrentStateInterval++;
295 : }
296 618306 : return myCurrentStateInterval != myIntervals.end() &&
297 618571 : myCurrentStateInterval->begin <= time && myCurrentStateInterval->end > time;
298 : }
299 :
300 :
301 : int
302 576822 : MSCalibrator::totalWished() const {
303 576822 : if (myCurrentStateInterval != myIntervals.end()) {
304 576822 : const double totalHourFraction = STEPS2TIME(myCurrentStateInterval->end - myCurrentStateInterval->begin) / (double) 3600.;
305 576822 : return (int)std::floor(myCurrentStateInterval->q * totalHourFraction + 0.5); // round to closest int
306 : } else {
307 : return -1;
308 : }
309 : }
310 :
311 :
312 : double
313 0 : MSCalibrator::currentFlow() const {
314 0 : const double totalHourFraction = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - myCurrentStateInterval->begin) / (double) 3600.;
315 0 : return passed() / totalHourFraction;
316 : }
317 :
318 :
319 : double
320 0 : MSCalibrator::currentSpeed() const {
321 0 : if (myEdgeMeanData.getSamples() > 0) {
322 0 : return myEdgeMeanData.getTravelledDistance() / myEdgeMeanData.getSamples();
323 : } else {
324 : return -1;
325 : }
326 : }
327 :
328 :
329 : bool
330 518381 : MSCalibrator::removePending() {
331 518381 : if (myToRemove.size() > 0) {
332 17337 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
333 : // it is not save to remove the vehicles inside
334 : // VehicleRemover::notifyEnter so we do it here
335 34675 : for (std::set<std::string>::iterator it = myToRemove.begin(); it != myToRemove.end(); ++it) {
336 17338 : MSVehicle* vehicle = dynamic_cast<MSVehicle*>(vc.getVehicle(*it));
337 17338 : if (vehicle != nullptr) {
338 : MSLane* lane = vehicle->getMutableLane();
339 17338 : vehicle->onRemovalFromNet(MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR);
340 17338 : lane->removeVehicle(vehicle, MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR);
341 17338 : vc.scheduleVehicleRemoval(vehicle, true);
342 : } else {
343 0 : WRITE_WARNINGF(TL("Calibrator '%' could not remove vehicle '%' time=%."), getID(), *it, time2string(MSNet::getInstance()->getCurrentTimeStep()));
344 : }
345 : }
346 : myToRemove.clear();
347 17337 : return true;
348 : }
349 : return false;
350 : }
351 :
352 :
353 : SUMOTime
354 518381 : MSCalibrator::execute(SUMOTime currentTime) {
355 518381 : const bool calibrateFlow = myCurrentStateInterval->q >= 0;
356 518381 : const bool calibrateSpeed = myCurrentStateInterval->v >= 0;
357 : // get current simulation values (valid for the last simulation second)
358 761994 : myHaveInvalidJam = (calibrateFlow || calibrateSpeed) && invalidJam(myLane == 0 ? -1 : myLane->getIndex());
359 : // XXX could we miss vehicle movements if this is called less often than every DELTA_T (default) ?
360 518381 : updateMeanData();
361 518381 : const bool hadRemovals = removePending();
362 : // check whether an adaptation value exists
363 518381 : if (isCurrentStateActive(currentTime)) {
364 473021 : myAmActive = true;
365 : // all happens in isCurrentStateActive()
366 : } else {
367 45360 : myAmActive = false;
368 45360 : reset();
369 45360 : if (!mySpeedIsDefault) {
370 : // reset speed to default
371 103 : if (myLane == nullptr) {
372 51 : myEdge->setMaxSpeed(myDefaultSpeed);
373 : } else {
374 52 : myLane->setMaxSpeed(myDefaultSpeed);
375 : }
376 103 : mySpeedIsDefault = true;
377 : }
378 45360 : if (myCurrentStateInterval == myIntervals.end()) {
379 : // keep calibrator alive for gui but do not call again
380 203 : return SUMOTime_MAX - currentTime;
381 : }
382 45157 : return myFrequency;
383 : }
384 : // we are active
385 473021 : if (!myDidSpeedAdaption && calibrateSpeed) {
386 170 : if (myLane == nullptr) {
387 86 : myEdge->setMaxSpeed(myCurrentStateInterval->v);
388 : } else {
389 84 : myLane->setMaxSpeed(myCurrentStateInterval->v);
390 : }
391 170 : mySpeedIsDefault = false;
392 170 : myDidSpeedAdaption = true;
393 : }
394 :
395 473021 : const int totalWishedNum = totalWished();
396 473021 : int adaptedNum = passed() + myClearedInJam;
397 : #ifdef MSCalibrator_DEBUG
398 : if (DEBUGCOND) {
399 : std::cout << time2string(currentTime) << " " << getID()
400 : << " q=" << myCurrentStateInterval->q
401 : << " totalWished=" << totalWishedNum
402 : << " adapted=" << adaptedNum
403 : << " jam=" << myHaveInvalidJam
404 : << " entered=" << myEdgeMeanData.nVehEntered
405 : << " departed=" << myEdgeMeanData.nVehDeparted
406 : << " arrived=" << myEdgeMeanData.nVehArrived
407 : << " left=" << myEdgeMeanData.nVehLeft
408 : << " waitSecs=" << myEdgeMeanData.waitSeconds
409 : << " vaporized=" << myEdgeMeanData.nVehVaporized
410 : << "\n";
411 : }
412 : #endif
413 473021 : if (calibrateFlow && adaptedNum < totalWishedNum && !hadRemovals) {
414 : // we need to insert some vehicles
415 129439 : const double hourFraction = STEPS2TIME(currentTime - myCurrentStateInterval->begin + DELTA_T) / (double) 3600.;
416 129439 : const int wishedNum = (int)std::floor(myCurrentStateInterval->q * hourFraction + 0.5); // round to closest int
417 : // only the difference between inflow and aspiredFlow should be added, thus
418 : // we should not count vehicles vaporized from a jam here
419 : // if we have enough time left we can add missing vehicles later
420 129439 : const int relaxedInsertion = (int)std::floor(STEPS2TIME(myCurrentStateInterval->end - currentTime) / 3);
421 129439 : const int insertionSlack = MAX2(0, adaptedNum + relaxedInsertion - totalWishedNum);
422 : // increase number of vehicles
423 : #ifdef MSCalibrator_DEBUG
424 : if (DEBUGCOND) {
425 : std::cout << " wished:" << wishedNum
426 : << " slack:" << insertionSlack
427 : << " before:" << adaptedNum
428 : << "\n";
429 : }
430 : #endif
431 129439 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
432 159172 : while (wishedNum > adaptedNum + insertionSlack) {
433 103505 : SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
434 103505 : ConstMSRoutePtr route = myProbe != nullptr ? myProbe->sampleRoute() : nullptr;
435 103505 : if (route == nullptr) {
436 207010 : route = MSRoute::dictionary(pars->routeid);
437 : }
438 103505 : if (route == nullptr) {
439 0 : WRITE_WARNINGF(TL("No valid routes in calibrator '%'."), getID());
440 0 : break;
441 : }
442 103505 : if (!route->contains(myEdge)) {
443 5 : WRITE_WARNINGF(TL("Route '%' in calibrator '%' does not contain edge '%'."), route->getID(), getID(), myEdge->getID());
444 0 : break;
445 : }
446 103505 : const int routeIndex = (int)std::distance(route->begin(),
447 103505 : std::find(route->begin(), route->end(), myEdge));
448 103505 : MSVehicleType* vtype = vc.getVType(pars->vtypeid);
449 : assert(route != 0 && vtype != 0);
450 : // build the vehicle
451 103505 : const std::string newID = getNewVehicleID();
452 103505 : if (vc.getVehicle(newID) != nullptr) {
453 : // duplicate ids could come from loading state
454 7 : myInserted++;
455 7 : break;
456 : }
457 103498 : SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
458 103498 : newPars->id = newID;
459 103498 : newPars->depart = currentTime;
460 103498 : newPars->routeid = route->getID();
461 103498 : newPars->departLaneProcedure = DepartLaneDefinition::FIRST_ALLOWED; // ensure successful vehicle creation
462 : MSVehicle* vehicle;
463 : try {
464 103498 : vehicle = dynamic_cast<MSVehicle*>(vc.buildVehicle(newPars, route, vtype, true, MSVehicleControl::VehicleDefinitionSource::TRIGGER));
465 0 : } catch (const ProcessError& e) {
466 0 : if (!MSGlobals::gCheckRoutes) {
467 0 : WRITE_WARNING(e.what());
468 : vehicle = nullptr;
469 : break;
470 : } else {
471 0 : throw;
472 : }
473 0 : }
474 : #ifdef MSCalibrator_DEBUG
475 : if (DEBUGCOND) {
476 : std::cout << " resetting route pos: " << routeIndex << "\n";
477 : }
478 : #endif
479 103498 : vehicle->resetRoutePosition(routeIndex, pars->departLaneProcedure);
480 : bool success = false;
481 : try {
482 103498 : success = myEdge->insertVehicle(*vehicle, currentTime);
483 5 : } catch (const ProcessError&) {
484 5 : MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
485 5 : throw;
486 5 : }
487 103493 : if (success) {
488 29733 : if (!MSNet::getInstance()->getVehicleControl().addVehicle(vehicle->getID(), vehicle)) {
489 0 : throw ProcessError("Emission of vehicle '" + vehicle->getID() + "' in calibrator '" + getID() + "'failed!");
490 : }
491 29733 : myInserted++;
492 29733 : adaptedNum++;
493 : #ifdef MSCalibrator_DEBUG
494 : if (DEBUGCOND) {
495 : std::cout << "I ";
496 : }
497 : #endif
498 : } else {
499 : // could not insert vehicle
500 : #ifdef MSCalibrator_DEBUG
501 : if (DEBUGCOND) {
502 : std::cout << "F ";
503 : }
504 : #endif
505 73760 : MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
506 : break;
507 : }
508 : }
509 : }
510 473016 : if (myCurrentStateInterval->end <= currentTime + myFrequency) {
511 432 : intervalEnd();
512 : }
513 473016 : return myFrequency;
514 : }
515 :
516 :
517 : void
518 45884 : MSCalibrator::reset() {
519 45884 : myEdgeMeanData.reset();
520 106983 : for (MSMeanData_Net::MSLaneMeanDataValues* const val : myLaneMeanData) {
521 61099 : val->reset();
522 : }
523 45884 : }
524 :
525 :
526 : bool
527 330144 : MSCalibrator::invalidJam(int laneIndex) const {
528 330144 : if (laneIndex < 0) {
529 29074 : const int numLanes = (int)myEdge->getLanes().size();
530 86275 : for (int i = 0; i < numLanes; ++i) {
531 57457 : if (invalidJam(i)) {
532 : return true;
533 : }
534 : }
535 : return false;
536 : }
537 : assert(laneIndex < (int)myEdge->getLanes().size());
538 301070 : const MSLane* const lane = myEdge->getLanes()[laneIndex];
539 301070 : if (lane->getVehicleNumber() < 4) {
540 : // cannot reliably detect invalid jams
541 : return false;
542 : }
543 : // maxSpeed reflects the calibration target
544 210631 : const bool toSlow = lane->getMeanSpeed() < myInvalidJamThreshold * myEdge->getSpeedLimit();
545 210631 : return toSlow && remainingVehicleCapacity(laneIndex) < 1;
546 : }
547 :
548 :
549 : int
550 54111 : MSCalibrator::remainingVehicleCapacity(int laneIndex) const {
551 54111 : if (laneIndex < 0) {
552 0 : const int numLanes = (int)myEdge->getLanes().size();
553 : int result = 0;
554 0 : for (int i = 0; i < numLanes; ++i) {
555 0 : result = MAX2(result, remainingVehicleCapacity(i));
556 : }
557 0 : return result;
558 : }
559 : assert(laneIndex < (int)myEdge->getLanes().size());
560 54111 : MSLane* lane = myEdge->getLanes()[laneIndex];
561 54111 : MSVehicle* last = lane->getLastFullVehicle();
562 54111 : const SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
563 54111 : const MSVehicleType* vtype = MSNet::getInstance()->getVehicleControl().getVType(pars->vtypeid);
564 54111 : const double spacePerVehicle = vtype->getLengthWithGap() + myEdge->getSpeedLimit() * vtype->getCarFollowModel().getHeadwayTime();
565 54111 : int overallSpaceLeft = (int)ceil(lane->getLength() / spacePerVehicle) - lane->getVehicleNumber();
566 54111 : if (last != nullptr) {
567 54111 : int entrySpaceLeft = (int)(last->getPositionOnLane() / spacePerVehicle);
568 54111 : return MAX2(overallSpaceLeft, entrySpaceLeft);
569 : } else {
570 : return overallSpaceLeft;
571 : }
572 : }
573 :
574 :
575 : void
576 38670 : MSCalibrator::cleanup() {
577 78470 : while (!myInstances.empty()) {
578 1130 : delete myInstances.begin()->second;
579 : }
580 41049 : for (MSMoveReminder* rem : myLeftoverReminders) {
581 2379 : delete rem;
582 : }
583 : myLeftoverReminders.clear();
584 39352 : for (SUMOVehicleParameter* par : myLeftoverVehicleParameters) {
585 682 : delete par;
586 : }
587 : myLeftoverVehicleParameters.clear();
588 38670 : }
589 :
590 :
591 : void
592 622550 : MSCalibrator::updateMeanData() {
593 622550 : myEdgeMeanData.reset();
594 622550 : for (std::vector<MSMeanData_Net::MSLaneMeanDataValues*>::iterator it = myLaneMeanData.begin();
595 1278746 : it != myLaneMeanData.end(); ++it) {
596 656196 : (*it)->addTo(myEdgeMeanData);
597 : }
598 622550 : }
599 :
600 :
601 : bool
602 156520 : MSCalibrator::VehicleRemover::notifyEnter(SUMOTrafficObject& veh, Notification /* reason */, const MSLane* /* enteredLane */) {
603 156520 : if (myParent == nullptr) {
604 : return false;
605 : }
606 156520 : if (!myParent->vehicleApplies(veh)) {
607 : return false;
608 : }
609 151908 : if (myParent->isActive()) {
610 103801 : myParent->updateMeanData();
611 103801 : const bool calibrateFlow = myParent->myCurrentStateInterval->q >= 0;
612 103801 : const int totalWishedNum = myParent->totalWished();
613 103801 : int adaptedNum = myParent->passed() + myParent->myClearedInJam;
614 103801 : if (calibrateFlow && adaptedNum > totalWishedNum) {
615 : #ifdef MSCalibrator_DEBUG
616 : if (DEBUGCOND2(myParent->getID())) std::cout << time2string(MSNet::getInstance()->getCurrentTimeStep()) << " " << myParent->getID()
617 : << " vaporizing " << vehicle->getID() << " to reduce flow\n";
618 : #endif
619 3636 : if (myParent->scheduleRemoval(&veh)) {
620 3636 : myParent->myRemoved++;
621 : }
622 100165 : } else if (myParent->myHaveInvalidJam) {
623 : #ifdef MSCalibrator_DEBUG
624 : if (DEBUGCOND2(myParent->getID())) std::cout << time2string(MSNet::getInstance()->getCurrentTimeStep()) << " " << myParent->getID()
625 : << " vaporizing " << vehicle->getID() << " to clear jam\n";
626 : #endif
627 13714 : if (!myParent->myHaveWarnedAboutClearingJam) {
628 90 : WRITE_WARNINGF(TL("Clearing jam at calibrator '%' at time=%."), myParent->getID(), time2string(SIMSTEP));
629 30 : myParent->myHaveWarnedAboutClearingJam = true;
630 : }
631 13714 : if (myParent->scheduleRemoval(&veh)) {
632 13702 : myParent->myClearedInJam++;
633 : }
634 : }
635 103801 : const std::string typeID = myParent->myCurrentStateInterval->vehicleParameter->vtypeid;
636 103801 : if (!calibrateFlow && typeID != DEFAULT_VTYPE_ID) {
637 : // calibrate type
638 28020 : const std::string origType = veh.getParameter().vtypeid; // could by id of vTypeDistribution
639 28020 : const MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
640 28020 : const RandomDistributor<MSVehicleType*>* oldDist = vc.getVTypeDistribution(origType);
641 28020 : const RandomDistributor<MSVehicleType*>* newDist = vc.getVTypeDistribution(typeID);
642 : bool matchDistribution = false;
643 28020 : if (oldDist != nullptr && newDist != nullptr && oldDist->getVals().size() == newDist->getVals().size()) {
644 280 : auto it = std::find(oldDist->getVals().begin(), oldDist->getVals().end(), &veh.getVehicleType());
645 280 : if (it != oldDist->getVals().end()) {
646 : matchDistribution = true;
647 280 : const int distIndex = (int)(it - oldDist->getVals().begin());
648 280 : veh.replaceVehicleType(newDist->getVals()[distIndex]);
649 : }
650 : }
651 : if (!matchDistribution) {
652 27740 : MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(typeID);
653 27740 : if (vehicleType == nullptr) {
654 0 : throw ProcessError("Unknown vehicle type '" + typeID + "' in calibrator '" + myParent->getID() + "'");
655 : }
656 27740 : veh.replaceVehicleType(vehicleType);
657 : }
658 : }
659 : }
660 : return true;
661 : }
662 :
663 :
664 : bool
665 443656 : MSCalibrator::VehicleRemover::notifyLeave(SUMOTrafficObject& veh, double /* lastPos */, Notification reason, const MSLane* /* enteredLane */) {
666 443656 : if (myUndoCalibration && reason != NOTIFICATION_LANE_CHANGE) {
667 : // TODO check for distributions
668 15 : veh.replaceVehicleType(MSNet::getInstance()->getVehicleControl().getVType(veh.getParameter().vtypeid));
669 : }
670 443656 : return true;
671 : }
672 :
673 :
674 : void
675 491 : MSCalibrator::writeXMLOutput(OutputDevice& dev, SUMOTime startTime, SUMOTime stopTime) {
676 491 : updateMeanData();
677 491 : const int p = passed();
678 : // meandata will be off if vehicles are removed on the next edge instead of this one
679 491 : const int discrepancy = myEdgeMeanData.nVehEntered + myEdgeMeanData.nVehDeparted - myEdgeMeanData.nVehVaporized - myEdgeMeanData.nVehTeleported - passed();
680 : //assert(discrepancy >= 0); may go negative for lane calibrator when vehicles change lane before removal
681 502 : const std::string ds = (discrepancy > 0 ? "\" vaporizedOnNextEdge=\"" + toString(discrepancy) : "");
682 491 : const double durationSeconds = STEPS2TIME(stopTime - startTime);
683 491 : dev.openTag(SUMO_TAG_INTERVAL);
684 491 : dev.writeAttr(SUMO_ATTR_BEGIN, time2string(startTime));
685 982 : dev.writeAttr(SUMO_ATTR_END, time2string(stopTime));
686 491 : dev.writeAttr(SUMO_ATTR_ID, getID());
687 491 : dev.writeAttr("nVehContrib", p);
688 491 : dev.writeAttr("removed", myRemoved);
689 491 : dev.writeAttr("inserted", myInserted);
690 491 : dev.writeAttr("cleared", myClearedInJam);
691 982 : dev.writeAttr("flow", p * 3600.0 / durationSeconds);
692 491 : dev.writeAttr("aspiredFlow", myCurrentStateInterval->q);
693 491 : dev.writeAttr(SUMO_ATTR_SPEED, myEdgeMeanData.getSamples() != 0
694 491 : ? myEdgeMeanData.getTravelledDistance() / myEdgeMeanData.getSamples() : -1);
695 491 : dev.writeAttr("aspiredSpeed", myCurrentStateInterval->v);
696 491 : if (discrepancy > 0) {
697 22 : dev.writeAttr("vaporizedOnNextEdge", discrepancy);
698 : }
699 982 : dev.closeTag();
700 491 : }
701 :
702 : void
703 267 : MSCalibrator::writeXMLDetectorProlog(OutputDevice& dev) const {
704 534 : dev.writeXMLHeader("calibratorstats", "calibratorstats_file.xsd");
705 267 : }
706 :
707 : std::string
708 117053 : MSCalibrator::getNewVehicleID() {
709 : // avoid name clash for subsecond interval spacing
710 117053 : const double beginS = STEPS2TIME(myCurrentStateInterval->begin);
711 117053 : const int precision = beginS == int(beginS) ? 0 : 2;
712 351159 : return getID() + "." + toString(beginS, precision) + "." + toString(myInserted);
713 : }
714 :
715 : void
716 10 : MSCalibrator::setFlow(SUMOTime begin, SUMOTime end, double vehsPerHour, double speed, SUMOVehicleParameter vehicleParameter) {
717 10 : auto it = myCurrentStateInterval;
718 15 : while (it != myIntervals.end()) {
719 10 : if (it->begin > begin) {
720 0 : throw ProcessError("Cannot set flow for calibrator '" + getID() + "' with begin time=" + time2string(begin) + " in the past.");
721 10 : } else if (it->begin == begin && it->end == end) {
722 : // update current interval
723 : AspiredState& state = const_cast<AspiredState&>(*it);
724 5 : state.q = vehsPerHour;
725 5 : state.v = speed;
726 5 : state.vehicleParameter->vtypeid = vehicleParameter.vtypeid;
727 5 : state.vehicleParameter->routeid = vehicleParameter.routeid;
728 5 : state.vehicleParameter->departLane = vehicleParameter.departLane;
729 5 : state.vehicleParameter->departLaneProcedure = vehicleParameter.departLaneProcedure;
730 5 : state.vehicleParameter->departSpeed = vehicleParameter.departSpeed;
731 5 : state.vehicleParameter->departSpeedProcedure = vehicleParameter.departSpeedProcedure;
732 5 : return;
733 5 : } else if (begin < it->end) {
734 0 : throw ProcessError(TLF("Cannot set flow for calibrator '%' with overlapping interval.", getID()));
735 5 : } else if (begin >= end) {
736 0 : throw ProcessError(TLF("Cannot set flow for calibrator '%' with negative interval.", getID()));
737 : }
738 : it++;
739 : }
740 : // add interval at the end of the known intervals
741 5 : const int intervalIndex = (int)(myCurrentStateInterval - myIntervals.begin());
742 : AspiredState state;
743 5 : state.begin = begin;
744 5 : state.end = end;
745 5 : state.q = vehsPerHour;
746 5 : state.v = speed;
747 5 : state.vehicleParameter = new SUMOVehicleParameter(vehicleParameter);
748 5 : myIntervals.push_back(state);
749 : // fix iterator
750 5 : myCurrentStateInterval = myIntervals.begin() + intervalIndex;
751 : }
752 :
753 : /****************************************************************************/
|