Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSCalibrator.cpp
Go to the documentation of this file.
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/****************************************************************************/
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>
38#include <utils/xml/XMLSubSys.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// ===========================================================================
55std::vector<MSMoveReminder*> MSCalibrator::myLeftoverReminders;
56std::vector<SUMOVehicleParameter*> MSCalibrator::myLeftoverVehicleParameters;
57std::map<std::string, MSCalibrator*> MSCalibrator::myInstances;
58
59// ===========================================================================
60// CalibratorCommand method definitions
61// ===========================================================================
62
65 UNUSED_PARAMETER(currentTime);
66 UNUSED_PARAMETER(execTime);
67 UNUSED_PARAMETER(newTime);
69 return 0;
70}
71
72
73// ===========================================================================
74// method definitions
75// ===========================================================================
76MSCalibrator::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 const bool addLaneMeanData) :
89 MSRouteHandler(aXMLFilename, true),
90 MSDetectorFileOutput(id, vTypes, "", (int)PersonMode::NONE), // detecting persons not yet supported
91 myEdge(edge),
92 myLane(lane),
93 myNode(node),
94 myPos(pos), myProbe(probe),
95 myMeanDataParent(id + "_dummyMeanData", 0, 0, false, false, false, false, false, false, 1, 0, 0, vTypes, "",
96 std::vector<MSEdge*>(), false),
97 myEdgeMeanData(nullptr, length, false, &myMeanDataParent),
99 myOutput(nullptr), myFrequency(freq), myRemoved(0),
100 myInserted(0),
102 mySpeedIsDefault(true), myDidSpeedAdaption(false), myDidInit(false),
103 myDefaultSpeed(myLane == nullptr ? (myEdge == nullptr ? 0. : myEdge->getSpeedLimit()) : myLane->getSpeedLimit()),
105 myAmActive(false),
106 myInvalidJamThreshold(invalidJamThreshold),
107 myAmLocal(local),
108 myHaveInvalidJam(false) {
109 myInstances[id] = this;
110 if (outputFilename != "") {
111 myOutput = &OutputDevice::getDevice(outputFilename);
113 }
114 if (aXMLFilename != "") {
115 XMLSubSys::runParser(*this, aXMLFilename);
116 if (!myDidInit) {
117 init();
118 }
119 }
120 if (addLaneMeanData && myEdge != nullptr) {
121 // disabled for METriggeredCalibrator
122 for (MSLane* const eLane : myEdge->getLanes()) {
123 if (myLane == nullptr || myLane == eLane) {
124 //std::cout << " cali=" << getID() << " myLane=" << Named::getIDSecure(myLane) << " checkLane=" << i << "\n";
125 MSMeanData_Net::MSLaneMeanDataValues* laneData = new MSMeanData_Net::MSLaneMeanDataValues(eLane, eLane->getLength(), true, &myMeanDataParent);
126 laneData->setDescription("meandata_calibrator_" + eLane->getID());
127 myLeftoverReminders.push_back(laneData);
128 myLaneMeanData.push_back(laneData);
129 VehicleRemover* remover = new VehicleRemover(eLane, this);
130 myLeftoverReminders.push_back(remover);
131 myVehicleRemovers.push_back(remover);
132 }
133 }
134 }
135 if (node != nullptr) {
136 for (const MSEdge* inEdge : myNode->getIncoming()) {
137 for (MSLane* const eLane : inEdge->getLanes()) {
138 VehicleRemover* remover = new VehicleRemover(eLane, this);
139 myLeftoverReminders.push_back(remover);
140 myVehicleRemovers.push_back(remover);
141 }
142 }
143 if (local) {
144 for (const MSEdge* outEdge : myNode->getOutgoing()) {
145 for (MSLane* const eLane : outEdge->getLanes()) {
146 VehicleRemover* remover = new VehicleRemover(eLane, this, true);
147 myLeftoverReminders.push_back(remover);
148 myVehicleRemovers.push_back(remover);
149 }
150 }
151 }
152 }
153}
154
155
156void
158 if (myIntervals.size() > 0) {
159 if (myIntervals.back().end == -1) {
160 myIntervals.back().end = SUMOTime_MAX;
161 }
162 // calibration should happen after regular insertions have taken place
164 } else {
165 WRITE_WARNINGF(TL("No flow intervals in calibrator '%'."), getID());
166 }
167 myDidInit = true;
168}
169
170
172 if (myCurrentStateInterval != myIntervals.end()) {
173 intervalEnd();
174 }
175 for (VehicleRemover* const remover : myVehicleRemovers) {
176 remover->disable();
177 }
178 myInstances.erase(getID());
179}
180
181
184 if (myCurrentStateInterval == myIntervals.end()) {
185 throw ProcessError(TLF("Calibrator '%' has no active or upcoming interval", getID()));
186 }
188}
189
190
191void
193 const SUMOSAXAttributes& attrs) {
194 if (element == SUMO_TAG_FLOW) {
195 AspiredState state;
196 SUMOTime lastEnd = -1;
197 SUMOTime lastBegin = -1;
198 if (myIntervals.size() > 0) {
199 lastEnd = myIntervals.back().end;
200 lastBegin = myIntervals.back().begin;
201 if (lastEnd == -1) {
202 lastEnd = myIntervals.back().begin;
203 }
204 }
205 try {
206 bool ok = true;
207 state.q = attrs.getOpt<double>(SUMO_ATTR_VEHSPERHOUR, nullptr, ok, -1.);
208 state.v = attrs.getOpt<double>(SUMO_ATTR_SPEED, nullptr, ok, -1.);
209 state.begin = attrs.getSUMOTimeReporting(SUMO_ATTR_BEGIN, getID().c_str(), ok);
210 if (state.begin < lastEnd) {
211 WRITE_ERRORF("Overlapping or unsorted intervals in calibrator '%' (end=%, begin2=%).", getID(), time2string(lastEnd), time2string(state.begin));
212 } else if (state.begin <= lastBegin) {
213 WRITE_ERRORF("Overlapping or unsorted intervals in calibrator '%' (begin=%, begin2=%).", getID(), time2string(lastBegin), time2string(state.begin));
214 }
215 state.end = attrs.getOptSUMOTimeReporting(SUMO_ATTR_END, getID().c_str(), ok, -1);
216 state.vehicleParameter = SUMOVehicleParserHelper::parseVehicleAttributes(element, attrs, true, true, true);
217 state.vehicleParameter->parametersSet &= ~VEHPARS_CALIBRATORSPEED_SET;
219 // vehicles should be inserted with max speed unless stated otherwise
222 }
223 // vehicles should be inserted on any lane unless stated otherwise
225 if (myLane == nullptr) {
227 } else {
230 }
231 } else if (myLane != nullptr && (
233 || state.vehicleParameter->departLane != myLane->getIndex())) {
234 WRITE_WARNINGF(TL("Insertion lane may differ from calibrator lane for calibrator '%'."), getID());
235 }
238 WRITE_ERRORF(TL("Unknown vehicle type '%' in calibrator '%'."), state.vehicleParameter->vtypeid, getID());
239 }
240 } catch (EmptyData&) {
241 WRITE_ERRORF(TL("Mandatory attribute missing in definition of calibrator '%'."), getID());
242 } catch (NumberFormatException&) {
243 WRITE_ERRORF(TL("Non-numeric value for numeric attribute in definition of calibrator '%'."), getID());
244 }
245 if (state.q < 0 && state.v < 0 && state.vehicleParameter->vtypeid == DEFAULT_VTYPE_ID) {
246 WRITE_ERRORF(TL("Either 'vehsPerHour', 'speed' or 'type' has to be set in flow definition of calibrator '%'."), getID());
247 }
248 if (MSGlobals::gUseMesoSim && state.q < 0 && state.vehicleParameter->vtypeid != DEFAULT_VTYPE_ID) {
249 WRITE_ERRORF(TL("Type calibration is not supported in meso for calibrator '%'."), getID());
250 }
251 if (myIntervals.size() > 0 && myIntervals.back().end == -1) {
252 myIntervals.back().end = state.begin;
253 }
254 myIntervals.push_back(state);
256 } else {
257 MSRouteHandler::myStartElement(element, attrs);
258 }
259}
260
261
262void
264 if (element == SUMO_TAG_CALIBRATOR) {
265 if (!myDidInit) {
266 init();
267 }
268 // ensure correct state of SUMORouteHandler::myElementStack
269 callParentEnd(element);
270 } else if (element != SUMO_TAG_FLOW) {
272 }
273}
274
275
276void
278 if (myOutput != nullptr) {
280 }
281 myDidSpeedAdaption = false;
282 myInserted = 0;
283 myRemoved = 0;
284 myClearedInJam = 0;
286 reset();
287}
288
289
290bool
292 while (myCurrentStateInterval != myIntervals.end() && myCurrentStateInterval->end <= time) {
293 // XXX what about skipped intervals?
295 }
296 return myCurrentStateInterval != myIntervals.end() &&
297 myCurrentStateInterval->begin <= time && myCurrentStateInterval->end > time;
298}
299
300
301int
303 if (myCurrentStateInterval != myIntervals.end()) {
304 const double totalHourFraction = STEPS2TIME(myCurrentStateInterval->end - myCurrentStateInterval->begin) / (double) 3600.;
305 return (int)std::floor(myCurrentStateInterval->q * totalHourFraction + 0.5); // round to closest int
306 } else {
307 return -1;
308 }
309}
310
311
312double
314 const double totalHourFraction = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - myCurrentStateInterval->begin) / (double) 3600.;
315 return passed() / totalHourFraction;
316}
317
318
319double
321 if (myEdgeMeanData.getSamples() > 0) {
323 } else {
324 return -1;
325 }
326}
327
328
329bool
331 if (myToRemove.size() > 0) {
333 // it is not save to remove the vehicles inside
334 // VehicleRemover::notifyEnter so we do it here
335 for (std::set<std::string>::iterator it = myToRemove.begin(); it != myToRemove.end(); ++it) {
336 MSVehicle* vehicle = dynamic_cast<MSVehicle*>(vc.getVehicle(*it));
337 if (vehicle != nullptr) {
338 MSLane* lane = vehicle->getMutableLane();
341 vc.scheduleVehicleRemoval(vehicle, true);
342 } else {
343 WRITE_WARNINGF(TL("Calibrator '%' could not remove vehicle '%' time=%."), getID(), *it, time2string(MSNet::getInstance()->getCurrentTimeStep()));
344 }
345 }
346 myToRemove.clear();
347 return true;
348 }
349 return false;
350}
351
352
355 const bool calibrateFlow = myCurrentStateInterval->q >= 0;
356 const bool calibrateSpeed = myCurrentStateInterval->v >= 0;
357 // get current simulation values (valid for the last simulation second)
358 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) ?
361 const bool hadRemovals = removePending();
362 // check whether an adaptation value exists
363 if (isCurrentStateActive(currentTime)) {
364 myAmActive = true;
365 // all happens in isCurrentStateActive()
366 } else {
367 myAmActive = false;
368 reset();
369 if (!mySpeedIsDefault) {
370 // reset speed to default
371 if (myLane == nullptr) {
373 } else {
375 }
376 mySpeedIsDefault = true;
377 }
378 if (myCurrentStateInterval == myIntervals.end()) {
379 // keep calibrator alive for gui but do not call again
380 return TIME2STEPS(86400);
381 }
382 return myFrequency;
383 }
384 // we are active
385 if (!myDidSpeedAdaption && calibrateSpeed) {
386 if (myLane == nullptr) {
388 } else {
390 }
391 mySpeedIsDefault = false;
392 myDidSpeedAdaption = true;
393 }
394
395 const int totalWishedNum = totalWished();
396 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 if (calibrateFlow && adaptedNum < totalWishedNum && !hadRemovals) {
414 // we need to insert some vehicles
415 const double hourFraction = STEPS2TIME(currentTime - myCurrentStateInterval->begin + DELTA_T) / (double) 3600.;
416 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 const int relaxedInsertion = (int)std::floor(STEPS2TIME(myCurrentStateInterval->end - currentTime) / 3);
421 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
432 while (wishedNum > adaptedNum + insertionSlack) {
433 SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
434 ConstMSRoutePtr route = myProbe != nullptr ? myProbe->sampleRoute() : nullptr;
435 if (route == nullptr) {
436 route = MSRoute::dictionary(pars->routeid);
437 }
438 if (route == nullptr) {
439 WRITE_WARNINGF(TL("No valid routes in calibrator '%'."), getID());
440 break;
441 }
442 if (!route->contains(myEdge)) {
443 WRITE_WARNINGF(TL("Route '%' in calibrator '%' does not contain edge '%'."), route->getID(), getID(), myEdge->getID());
444 break;
445 }
446 const int routeIndex = (int)std::distance(route->begin(),
447 std::find(route->begin(), route->end(), myEdge));
448 MSVehicleType* vtype = vc.getVType(pars->vtypeid);
449 assert(route != 0 && vtype != 0);
450 // build the vehicle
451 const std::string newID = getNewVehicleID();
452 if (vc.getVehicle(newID) != nullptr) {
453 // duplicate ids could come from loading state
454 myInserted++;
455 break;
456 }
457 SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
458 newPars->id = newID;
459 newPars->depart = currentTime;
460 newPars->routeid = route->getID();
461 newPars->departLaneProcedure = DepartLaneDefinition::FIRST_ALLOWED; // ensure successful vehicle creation
462 MSVehicle* vehicle;
463 try {
464 vehicle = dynamic_cast<MSVehicle*>(vc.buildVehicle(newPars, route, vtype, true, MSVehicleControl::VehicleDefinitionSource::TRIGGER));
465 } catch (const ProcessError& e) {
467 WRITE_WARNING(e.what());
468 vehicle = nullptr;
469 break;
470 } else {
471 throw;
472 }
473 }
474#ifdef MSCalibrator_DEBUG
475 if (DEBUGCOND) {
476 std::cout << " resetting route pos: " << routeIndex << "\n";
477 }
478#endif
479 vehicle->resetRoutePosition(routeIndex, pars->departLaneProcedure);
480 bool success = false;
481 try {
482 success = myEdge->insertVehicle(*vehicle, currentTime);
483 } catch (const ProcessError&) {
485 throw;
486 }
487 if (success) {
488 if (!MSNet::getInstance()->getVehicleControl().addVehicle(vehicle->getID(), vehicle)) {
489 throw ProcessError("Emission of vehicle '" + vehicle->getID() + "' in calibrator '" + getID() + "'failed!");
490 }
491 myInserted++;
492 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
506 break;
507 }
508 }
509 }
510 if (myCurrentStateInterval->end <= currentTime + myFrequency) {
511 intervalEnd();
512 }
513 return myFrequency;
514}
515
516
517void
521 val->reset();
522 }
523}
524
525
526bool
527MSCalibrator::invalidJam(int laneIndex) const {
528 if (laneIndex < 0) {
529 const int numLanes = (int)myEdge->getLanes().size();
530 for (int i = 0; i < numLanes; ++i) {
531 if (invalidJam(i)) {
532 return true;
533 }
534 }
535 return false;
536 }
537 assert(laneIndex < (int)myEdge->getLanes().size());
538 const MSLane* const lane = myEdge->getLanes()[laneIndex];
539 if (lane->getVehicleNumber() < 4) {
540 // cannot reliably detect invalid jams
541 return false;
542 }
543 // maxSpeed reflects the calibration target
544 const bool toSlow = lane->getMeanSpeed() < myInvalidJamThreshold * myEdge->getSpeedLimit();
545 return toSlow && remainingVehicleCapacity(laneIndex) < 1;
546}
547
548
549int
551 if (laneIndex < 0) {
552 const int numLanes = (int)myEdge->getLanes().size();
553 int result = 0;
554 for (int i = 0; i < numLanes; ++i) {
555 result = MAX2(result, remainingVehicleCapacity(i));
556 }
557 return result;
558 }
559 assert(laneIndex < (int)myEdge->getLanes().size());
560 MSLane* lane = myEdge->getLanes()[laneIndex];
561 MSVehicle* last = lane->getLastFullVehicle();
562 const SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
564 const double spacePerVehicle = vtype->getLengthWithGap() + myEdge->getSpeedLimit() * vtype->getCarFollowModel().getHeadwayTime();
565 int overallSpaceLeft = (int)ceil(lane->getLength() / spacePerVehicle) - lane->getVehicleNumber();
566 if (last != nullptr) {
567 int entrySpaceLeft = (int)(last->getPositionOnLane() / spacePerVehicle);
568 return MAX2(overallSpaceLeft, entrySpaceLeft);
569 } else {
570 return overallSpaceLeft;
571 }
572}
573
574
575void
577 while (!myInstances.empty()) {
578 delete myInstances.begin()->second;
579 }
581 delete rem;
582 }
583 myLeftoverReminders.clear();
585 delete par;
586 }
588}
589
590
591void
594 for (std::vector<MSMeanData_Net::MSLaneMeanDataValues*>::iterator it = myLaneMeanData.begin();
595 it != myLaneMeanData.end(); ++it) {
596 (*it)->addTo(myEdgeMeanData);
597 }
598}
599
600
601bool
603 if (myParent == nullptr) {
604 return false;
605 }
606 if (!myParent->vehicleApplies(veh)) {
607 return false;
608 }
609 if (myParent->isActive()) {
611 const bool calibrateFlow = myParent->myCurrentStateInterval->q >= 0;
612 const int totalWishedNum = myParent->totalWished();
613 int adaptedNum = myParent->passed() + myParent->myClearedInJam;
614 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 if (myParent->scheduleRemoval(&veh)) {
621 }
622 } 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
628 WRITE_WARNINGF(TL("Clearing jam at calibrator '%' at time=%."), myParent->getID(), time2string(SIMSTEP));
630 }
631 if (myParent->scheduleRemoval(&veh)) {
633 }
634 }
635 const std::string typeID = myParent->myCurrentStateInterval->vehicleParameter->vtypeid;
636 if (!calibrateFlow && typeID != DEFAULT_VTYPE_ID) {
637 // calibrate type
638 const std::string origType = veh.getParameter().vtypeid; // could by id of vTypeDistribution
640 const RandomDistributor<MSVehicleType*>* oldDist = vc.getVTypeDistribution(origType);
642 bool matchDistribution = false;
643 if (oldDist != nullptr && newDist != nullptr && oldDist->getVals().size() == newDist->getVals().size()) {
644 auto it = std::find(oldDist->getVals().begin(), oldDist->getVals().end(), &veh.getVehicleType());
645 if (it != oldDist->getVals().end()) {
646 matchDistribution = true;
647 const int distIndex = (int)(it - oldDist->getVals().begin());
648 veh.replaceVehicleType(newDist->getVals()[distIndex]);
649 }
650 }
651 if (!matchDistribution) {
653 if (vehicleType == nullptr) {
654 throw ProcessError("Unknown vehicle type '" + typeID + "' in calibrator '" + myParent->getID() + "'");
655 }
656 veh.replaceVehicleType(vehicleType);
657 }
658 }
659 }
660 return true;
661}
662
663
664bool
665MSCalibrator::VehicleRemover::notifyLeave(SUMOTrafficObject& veh, double /* lastPos */, Notification reason, const MSLane* /* enteredLane */) {
666 if (myUndoCalibration && reason != NOTIFICATION_LANE_CHANGE) {
667 // TODO check for distributions
668 veh.replaceVehicleType(MSNet::getInstance()->getVehicleControl().getVType(veh.getParameter().vtypeid));
669 }
670 return true;
671}
672
673
674void
677 const int p = passed();
678 // meandata will be off if vehicles are removed on the next edge instead of this one
680 //assert(discrepancy >= 0); may go negative for lane calibrator when vehicles change lane before removal
681 const std::string ds = (discrepancy > 0 ? "\" vaporizedOnNextEdge=\"" + toString(discrepancy) : "");
682 const double durationSeconds = STEPS2TIME(stopTime - startTime);
684 dev.writeAttr(SUMO_ATTR_BEGIN, time2string(startTime));
685 dev.writeAttr(SUMO_ATTR_END, time2string(stopTime));
687 dev.writeAttr("nVehContrib", p);
688 dev.writeAttr("removed", myRemoved);
689 dev.writeAttr("inserted", myInserted);
690 dev.writeAttr("cleared", myClearedInJam);
691 dev.writeAttr("flow", p * 3600.0 / durationSeconds);
692 dev.writeAttr("aspiredFlow", myCurrentStateInterval->q);
695 dev.writeAttr("aspiredSpeed", myCurrentStateInterval->v);
696 if (discrepancy > 0) {
697 dev.writeAttr("vaporizedOnNextEdge", discrepancy);
698 }
699 dev.closeTag();
700}
701
702void
704 dev.writeXMLHeader("calibratorstats", "calibratorstats_file.xsd");
705}
706
707std::string
709 // avoid name clash for subsecond interval spacing
710 const double beginS = STEPS2TIME(myCurrentStateInterval->begin);
711 const int precision = beginS == int(beginS) ? 0 : 2;
712 return getID() + "." + toString(beginS, precision) + "." + toString(myInserted);
713}
714
715void
716MSCalibrator::setFlow(SUMOTime begin, SUMOTime end, double vehsPerHour, double speed, SUMOVehicleParameter vehicleParameter) {
717 auto it = myCurrentStateInterval;
718 while (it != myIntervals.end()) {
719 if (it->begin > begin) {
720 throw ProcessError("Cannot set flow for calibrator '" + getID() + "' with begin time=" + time2string(begin) + " in the past.");
721 } else if (it->begin == begin && it->end == end) {
722 // update current interval
723 AspiredState& state = const_cast<AspiredState&>(*it);
724 state.q = vehsPerHour;
725 state.v = speed;
726 state.vehicleParameter->vtypeid = vehicleParameter.vtypeid;
727 state.vehicleParameter->routeid = vehicleParameter.routeid;
728 state.vehicleParameter->departLane = vehicleParameter.departLane;
730 state.vehicleParameter->departSpeed = vehicleParameter.departSpeed;
732 return;
733 } else if (begin < it->end) {
734 throw ProcessError(TLF("Cannot set flow for calibrator '%' with overlapping interval.", getID()));
735 } else if (begin >= end) {
736 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 const int intervalIndex = (int)(myCurrentStateInterval - myIntervals.begin());
742 AspiredState state;
743 state.begin = begin;
744 state.end = end;
745 state.q = vehsPerHour;
746 state.v = speed;
747 state.vehicleParameter = new SUMOVehicleParameter(vehicleParameter);
748 myIntervals.push_back(state);
749 // fix iterator
750 myCurrentStateInterval = myIntervals.begin() + intervalIndex;
751}
752
753/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define DEBUGCOND(PED)
#define DEBUGCOND2(LANE)
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:296
#define WRITE_ERRORF(...)
Definition MsgHandler.h:305
#define WRITE_WARNING(msg)
Definition MsgHandler.h:295
#define TL(string)
Definition MsgHandler.h:315
#define TLF(string,...)
Definition MsgHandler.h:317
std::shared_ptr< const MSRoute > ConstMSRoutePtr
Definition Route.h:32
SUMOTime DELTA_T
Definition SUMOTime.cpp:38
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:69
#define STEPS2TIME(x)
Definition SUMOTime.h:55
#define SIMSTEP
Definition SUMOTime.h:61
#define SUMOTime_MAX
Definition SUMOTime.h:34
#define TIME2STEPS(x)
Definition SUMOTime.h:57
const std::string DEFAULT_VTYPE_ID
@ GIVEN
The lane is given.
@ ALLOWED_FREE
The least occupied lane from lanes which allow the continuation.
@ DEFAULT
No information given; use default.
@ FIRST_ALLOWED
The rightmost lane the vehicle may use.
@ MAX
The maximum safe speed is used.
@ DEFAULT
No information given; use default.
@ SUMO_TAG_INTERVAL
an aggreagated-output interval
@ SUMO_TAG_FLOW
a flow definition using from and to edges or a route
@ SUMO_TAG_CALIBRATOR
A calibrator placed over edge.
PersonMode
travel modes for persons
@ SUMO_ATTR_VEHSPERHOUR
@ SUMO_ATTR_SPEED
@ SUMO_ATTR_BEGIN
weights: time range begin
@ SUMO_ATTR_END
weights: time range end
@ SUMO_ATTR_ID
#define UNUSED_PARAMETER(x)
Definition StdDefs.h:30
T MAX2(T a, T b)
Definition StdDefs.h:82
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
void callParentEnd(int element)
signal endElement to the parent handler (special case for MSCalibrator)
void resetRoutePosition(int index, DepartLaneDefinition departLaneProcedure)
reset index of edge within route
virtual double getHeadwayTime() const
Get the driver's desired headway [s].
Definition MSCFModel.h:311
SUMOTime shiftTime(SUMOTime currentTime, SUMOTime execTime, SUMOTime newTime)
Reschedule or deschedule the command when quick-loading state.
virtual bool notifyLeave(SUMOTrafficObject &veh, double lastPos, Notification reason, const MSLane *enteredLane=nullptr)
Checks whether any calibrations need to be undone.
virtual bool notifyEnter(SUMOTrafficObject &veh, MSMoveReminder::Notification reason, const MSLane *enteredLane=nullptr)
Checks whether the reminder is activated by a vehicle entering the lane.
static std::map< std::string, MSCalibrator * > myInstances
OutputDevice * myOutput
The device for xml statistics.
double myInvalidJamThreshold
relative speed threshold for detecting and clearing invalid jam
double currentSpeed() const
measured speed in the current interval
MSMeanData_Net myMeanDataParent
dummy parent to retrieve vType filter
MSEdge *const myEdge
the edge on which this calibrator lies
static void cleanup()
cleanup remaining data structures
bool isActive() const
bool mySpeedIsDefault
The information whether the speed adaption has been reset.
virtual void updateMeanData()
aggregate lane values
int myRemoved
The number of vehicles that were removed in the current interval.
virtual int passed() const
MSCalibrator(const std::string &id, MSEdge *const edge, MSLane *const lane, MSJunction *const node, const double pos, const std::string &aXMLFilename, const std::string &outputFilename, const SUMOTime freq, const double length, const MSRouteProbe *probe, const double invalidJamThreshold, const std::string &vTypes, const bool local, const bool addLaneMeanData)
const MSRouteProbe *const myProbe
the route probe to retrieve routes from
bool myAmActive
whether the calibrator was active when last checking
std::set< std::string > myToRemove
set of vehicle ids to remove
static std::vector< MSMoveReminder * > myLeftoverReminders
void setFlow(SUMOTime begin, SUMOTime end, double vehsPerHour, double speed, SUMOVehicleParameter vehicleParameter)
bool myHaveInvalidJam
whether the calibrator has registered an invalid jam in the last execution step
std::vector< MSMeanData_Net::MSLaneMeanDataValues * > myLaneMeanData
data collector for the calibrator
std::vector< AspiredState >::const_iterator myCurrentStateInterval
Iterator pointing to the current interval.
double currentFlow() const
flow in the current interval in veh/h
static std::vector< SUMOVehicleParameter * > myLeftoverVehicleParameters
bool removePending()
remove any vehicles which are scheduled for removal. return true if removals took place
virtual void myStartElement(int element, const SUMOSAXAttributes &attrs)
Called on the opening of a tag;.
int myInserted
The number of vehicles that were inserted in the current interval.
bool myHaveWarnedAboutClearingJam
The default (maximum) speed on the segment.
std::vector< AspiredState > myIntervals
List of adaptation intervals.
const double myPos
the position on the edge where this calibrator lies
virtual void myEndElement(int element)
Called on the closing of a tag;.
int totalWished() const
number of vehicles expected to pass this interval
std::vector< VehicleRemover * > myVehicleRemovers
void writeXMLOutput(OutputDevice &dev, SUMOTime startTime, SUMOTime stopTime)
Write the generated output to the given device.
std::string getNewVehicleID()
determine id of new vehicle from calibrator state
MSMeanData_Net::MSLaneMeanDataValues myEdgeMeanData
accumlated data for the whole edge
bool invalidJam(int laneIndex) const
int myClearedInJam
The number of vehicles that were removed when clearin a jam.
void writeXMLDetectorProlog(OutputDevice &dev) const
Open the XML-output.
virtual ~MSCalibrator()
double myDefaultSpeed
The default (maximum) speed on the segment.
virtual SUMOTime execute(SUMOTime currentTime)
MSLane *const myLane
the lane on which this calibrator lies (nullptr if the whole edge is covered at once)
bool scheduleRemoval(SUMOTrafficObject *veh)
try to schedule the given vehicle for removal. return true if it isn't already scheduled
bool myDidInit
The information whether init was called.
bool myAmLocal
whether the calibrator needs to undo the calibration after the edge / junction has been left
AspiredState getCurrentStateInterval() const
bool isCurrentStateActive(SUMOTime time)
MSJunction *const myNode
the junction on which this calibrator lies (nullptr if is edge or lane specific)
SUMOTime myFrequency
The frequeny with which to check for calibration.
virtual void reset()
reset collected vehicle data
int remainingVehicleCapacity(int laneIndex) const
bool myDidSpeedAdaption
The information whether speed was adapted in the current interval.
Base of value-generating classes (detectors)
bool vehicleApplies(const SUMOTrafficObject &veh) const
Checks whether the detector measures vehicles of the given type.
A road/street connecting two junctions.
Definition MSEdge.h:77
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition MSEdge.h:168
void setMaxSpeed(double val, double jamThreshold=-1)
Sets a new maximum speed for all lanes (used by TraCI and MSCalibrator)
Definition MSEdge.cpp:1177
double getSpeedLimit() const
Returns the speed limit of the edge @caution The speed limit of the first lane is retured; should pro...
Definition MSEdge.cpp:1158
bool insertVehicle(SUMOVehicle &v, SUMOTime time, const bool checkOnly=false, const bool forceCheck=false) const
Tries to insert the given vehicle into the network.
Definition MSEdge.cpp:775
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
static bool gUseMesoSim
Definition MSGlobals.h:106
static bool gCheckRoutes
Definition MSGlobals.h:91
The base class for an intersection.
Definition MSJunction.h:58
const ConstMSEdgeVector & getOutgoing() const
Definition MSJunction.h:114
const ConstMSEdgeVector & getIncoming() const
Definition MSJunction.h:108
Representation of a lane in the micro simulation.
Definition MSLane.h:84
virtual MSVehicle * removeVehicle(MSVehicle *remVehicle, MSMoveReminder::Notification notification, bool notify=true)
Definition MSLane.cpp:2756
int getVehicleNumber() const
Returns the number of vehicles on this lane (for which this lane is responsible)
Definition MSLane.h:456
MSVehicle * getLastFullVehicle() const
returns the last vehicle for which this lane is responsible or 0
Definition MSLane.cpp:2569
double getLength() const
Returns the lane's length.
Definition MSLane.h:606
int getIndex() const
Returns the lane's index.
Definition MSLane.h:642
void setMaxSpeed(double val, bool byVSS=false, bool byTraCI=false, double jamThreshold=-1)
Sets a new maximum speed for the lane (used by TraCI and MSCalibrator)
Definition MSLane.cpp:2709
double getMeanSpeed() const
Returns the mean speed on this lane.
Definition MSLane.cpp:3359
double getTravelledDistance() const
Returns the total travelled distance.
Definition MSMeanData.h:156
virtual double getSamples() const
Returns the number of collected sample seconds.
Data structure for mean (aggregated) edge/lane values.
int nVehVaporized
The number of vehicles that left this lane via vaporization within the sample interval.
int nVehLeft
The number of vehicles that left this lane within the sample interval.
int nVehTeleported
The number of vehicles that left this lane via teleporting within the sample interval.
int nVehArrived
The number of vehicles that finished on the lane.
double waitSeconds
The number of vehicle probes with small speed.
int nVehEntered
The number of vehicles that entered this lane within the sample interval.
void reset(bool afterWrite=false)
Resets values so they may be used for the next interval.
Something on a lane to be noticed about vehicle movement.
void setDescription(const std::string &description)
Notification
Definition of a vehicle state.
@ NOTIFICATION_VAPORIZED_CALIBRATOR
The vehicle got removed by a calibrator.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:186
MSEventControl * getEndOfTimestepEvents()
Returns the event control for events executed at the end of a time step.
Definition MSNet.h:481
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition MSNet.h:378
Parser and container for routes during their loading.
virtual void myStartElement(int element, const SUMOSAXAttributes &attrs) override
Called on the opening of a tag;.
static bool dictionary(const std::string &id, ConstMSRoutePtr route)
Adds a route to the dictionary.
Definition MSRoute.cpp:109
Writes routes of vehicles passing a certain edge.
ConstMSRoutePtr sampleRoute(bool last=true) const
The class responsible for building and deletion of vehicles.
SUMOVehicle * getVehicle(const std::string &id) const
Returns the vehicle with the given id.
MSVehicleType * getVType(const std::string &id=DEFAULT_VTYPE_ID, SumoRNG *rng=nullptr, bool readOnly=false)
Returns the named vehicle type or a sample from the named distribution.
virtual SUMOVehicle * buildVehicle(SUMOVehicleParameter *defs, ConstMSRoutePtr route, MSVehicleType *type, const bool ignoreStopErrors, const VehicleDefinitionSource source=ROUTEFILE, bool addRouteStops=true)
Builds a vehicle, increases the number of built vehicles.
const RandomDistributor< MSVehicleType * > * getVTypeDistribution(const std::string &typeDistID) const
return the vehicle type distribution with the given id
void scheduleVehicleRemoval(SUMOVehicle *veh, bool checkDuplicate=false)
Removes a vehicle after it has ended.
virtual void deleteVehicle(SUMOVehicle *v, bool discard=false, bool wasKept=false)
Deletes the vehicle.
Representation of a vehicle in the micro simulation.
Definition MSVehicle.h:77
void onRemovalFromNet(const MSMoveReminder::Notification reason)
Called when the vehicle is removed from the network.
MSLane * getMutableLane() const
Returns the lane the vehicle is on Non const version indicates that something volatile is going on.
Definition MSVehicle.h:589
double getPositionOnLane() const
Get the vehicle's position along the lane.
Definition MSVehicle.h:374
The car-following model and parameter.
double getLengthWithGap() const
Get vehicle's length including the minimum gap [m].
const MSCFModel & getCarFollowModel() const
Returns the vehicle type's car following model definition (const version)
const std::string & getID() const
Returns the id.
Definition Named.h:74
Static storage of an output device and its base (abstract) implementation.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
static OutputDevice & getDevice(const std::string &name, bool usePrefix=true)
Returns the described OutputDevice.
bool writeXMLHeader(const std::string &rootElement, const std::string &schemaFile, std::map< SumoXMLAttr, std::string > attrs=std::map< SumoXMLAttr, std::string >(), bool includeConfig=true)
Writes an XML header with optional configuration.
Represents a generic random distribution.
const std::vector< T > & getVals() const
Returns the members of the distribution.
virtual void myEndElement(int element)
Called when a closing tag occurs.
Encapsulated SAX-Attributes.
T getOpt(int attr, const char *objectid, bool &ok, T defaultValue=T(), bool report=true) const
Tries to read given attribute assuming it is an int.
SUMOTime getOptSUMOTimeReporting(int attr, const char *objectid, bool &ok, SUMOTime defaultValue, bool report=true) const
Tries to read given attribute assuming it is a SUMOTime.
SUMOTime getSUMOTimeReporting(int attr, const char *objectid, bool &ok, bool report=true) const
Tries to read given attribute assuming it is a SUMOTime.
Representation of a vehicle, person, or container.
virtual const MSVehicleType & getVehicleType() const =0
Returns the object's "vehicle" type.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle's parameter (including departure definition)
virtual void replaceVehicleType(MSVehicleType *type)=0
Replaces the current vehicle type by the one given.
Structure representing possible vehicle parameter.
int departLane
(optional) The lane the vehicle shall depart from (index in edge)
double departSpeed
(optional) The initial speed of the vehicle
std::string vtypeid
The vehicle's type id.
long long int parametersSet
Information for the router which parameter were set, TraCI may modify this (when changing color)
DepartLaneDefinition departLaneProcedure
Information how the vehicle shall choose the lane to depart from.
DepartSpeedDefinition departSpeedProcedure
Information how the vehicle's initial speed shall be chosen.
std::string routeid
The vehicle's route id.
std::string id
The vehicle's id.
static SUMOVehicleParameter * parseVehicleAttributes(int element, const SUMOSAXAttributes &attrs, const bool hardFail, const bool optionalID=false, const bool skipDepart=false, const bool allowInternalRoutes=false)
Parses a vehicle's attributes.
static bool runParser(GenericSAXHandler &handler, const std::string &file, const bool isNet=false, const bool isRoute=false, const bool isExternal=false, const bool catchExceptions=true)
Runs the given handler on the given file; returns if everything's ok.
Definition json.hpp:4471
SUMOVehicleParameter * vehicleParameter