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