Eclipse SUMO - Simulation of Urban MObility
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>
35 #include <utils/common/ToString.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 // ===========================================================================
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 
65  UNUSED_PARAMETER(currentTime);
66  UNUSED_PARAMETER(execTime);
67  UNUSED_PARAMETER(newTime);
69  return 0;
70 }
71 
72 
73 // ===========================================================================
74 // method definitions
75 // ===========================================================================
76 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  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),
101  myClearedInJam(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 
156 void
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  }
187  return *myCurrentStateInterval;
188 }
189 
190 
191 void
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);
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  }
236  if (state.vehicleParameter->vtypeid != DEFAULT_VTYPE_ID &&
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 
262 void
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 
276 void
278  if (myOutput != nullptr) {
280  }
281  myDidSpeedAdaption = false;
282  myInserted = 0;
283  myRemoved = 0;
284  myClearedInJam = 0;
286  reset();
287 }
288 
289 
290 bool
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 
301 int
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 
312 double
314  const double totalHourFraction = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - myCurrentStateInterval->begin) / (double) 3600.;
315  return passed() / totalHourFraction;
316 }
317 
318 
319 double
321  if (myEdgeMeanData.getSamples() > 0) {
323  } else {
324  return -1;
325  }
326 }
327 
328 
329 bool
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 
353 SUMOTime
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) ?
360  updateMeanData();
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 e;
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& e) {
485  throw e;
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 
517 void
521  val->reset();
522  }
523 }
524 
525 
526 bool
527 MSCalibrator::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 
549 int
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 
575 void
577  while (!myInstances.empty()) {
578  delete myInstances.begin()->second;
579  }
580  for (MSMoveReminder* rem : myLeftoverReminders) {
581  delete rem;
582  }
583  myLeftoverReminders.clear();
585  delete par;
586  }
588 }
589 
590 
591 void
594  for (std::vector<MSMeanData_Net::MSLaneMeanDataValues*>::iterator it = myLaneMeanData.begin();
595  it != myLaneMeanData.end(); ++it) {
596  (*it)->addTo(myEdgeMeanData);
597  }
598 }
599 
600 
601 bool
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)) {
620  myParent->myRemoved++;
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);
641  const RandomDistributor<MSVehicleType*>* newDist = vc.getVTypeDistribution(typeID);
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) {
652  MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(typeID);
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 
664 bool
665 MSCalibrator::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 
674 void
676  updateMeanData();
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));
686  dev.writeAttr(SUMO_ATTR_ID, getID());
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 
702 void
704  dev.writeXMLHeader("calibratorstats", "calibratorstats_file.xsd");
705 }
706 
707 std::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 
715 void
716 MSCalibrator::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;
729  state.vehicleParameter->departLaneProcedure = vehicleParameter.departLaneProcedure;
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:35
#define DEBUGCOND
#define DEBUGCOND2(id)
#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:31
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.
const int VEHPARS_CALIBRATORSPEED_SET
@ 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
Definition: MSCalibrator.h:367
OutputDevice * myOutput
The device for xml statistics.
Definition: MSCalibrator.h:330
double myInvalidJamThreshold
relative speed threshold for detecting and clearing invalid jam
Definition: MSCalibrator.h:355
double currentSpeed() const
measured speed in the current interval
MSMeanData_Net myMeanDataParent
dummy parent to retrieve vType filter
Definition: MSCalibrator.h:310
MSEdge *const myEdge
the edge on which this calibrator lies
Definition: MSCalibrator.h:300
static void cleanup()
cleanup remaining data structures
bool isActive() const
Definition: MSCalibrator.h:234
bool mySpeedIsDefault
The information whether the speed adaption has been reset.
Definition: MSCalibrator.h:341
virtual void updateMeanData()
aggregate lane values
int myRemoved
The number of vehicles that were removed in the current interval.
Definition: MSCalibrator.h:335
virtual int passed() const
Definition: MSCalibrator.h:121
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
Definition: MSCalibrator.h:308
bool myAmActive
whether the calibrator was active when last checking
Definition: MSCalibrator.h:352
std::set< std::string > myToRemove
set of vehicle ids to remove
Definition: MSCalibrator.h:327
static std::vector< MSMoveReminder * > myLeftoverReminders
Definition: MSCalibrator.h:365
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
Definition: MSCalibrator.h:361
std::vector< MSMeanData_Net::MSLaneMeanDataValues * > myLaneMeanData
data collector for the calibrator
Definition: MSCalibrator.h:312
std::vector< AspiredState >::const_iterator myCurrentStateInterval
Iterator pointing to the current interval.
Definition: MSCalibrator.h:319
double currentFlow() const
flow in the current interval in veh/h
static std::vector< SUMOVehicleParameter * > myLeftoverVehicleParameters
Definition: MSCalibrator.h:366
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.
Definition: MSCalibrator.h:337
bool myHaveWarnedAboutClearingJam
The default (maximum) speed on the segment.
Definition: MSCalibrator.h:349
std::vector< AspiredState > myIntervals
List of adaptation intervals.
Definition: MSCalibrator.h:317
const double myPos
the position on the edge where this calibrator lies
Definition: MSCalibrator.h:306
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
Definition: MSCalibrator.h:321
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
Definition: MSCalibrator.h:314
bool invalidJam(int laneIndex) const
int myClearedInJam
The number of vehicles that were removed when clearin a jam.
Definition: MSCalibrator.h:339
void writeXMLDetectorProlog(OutputDevice &dev) const
Open the XML-output.
virtual ~MSCalibrator()
double myDefaultSpeed
The default (maximum) speed on the segment.
Definition: MSCalibrator.h:347
virtual SUMOTime execute(SUMOTime currentTime)
MSLane *const myLane
the lane on which this calibrator lies (nullptr if the whole edge is covered at once)
Definition: MSCalibrator.h:302
bool scheduleRemoval(SUMOTrafficObject *veh)
try to schedule the given vehicle for removal. return true if it isn't already scheduled
Definition: MSCalibrator.h:286
bool myDidInit
The information whether init was called.
Definition: MSCalibrator.h:345
bool myAmLocal
whether the calibrator needs to undo the calibration after the edge / junction has been left
Definition: MSCalibrator.h:358
void intervalEnd()
AspiredState getCurrentStateInterval() const
bool isCurrentStateActive(SUMOTime time)
MSJunction *const myNode
the junction on which this calibrator lies (nullptr if is edge or lane specific)
Definition: MSCalibrator.h:304
SUMOTime myFrequency
The frequeny with which to check for calibration.
Definition: MSCalibrator.h:333
virtual void reset()
reset collected vehicle data
int remainingVehicleCapacity(int laneIndex) const
bool myDidSpeedAdaption
The information whether speed was adapted in the current interval.
Definition: MSCalibrator.h:343
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
void setMaxSpeed(double val, double jamThreshold=-1)
Sets a new maximum speed for all lanes (used by TraCI and MSCalibrator)
Definition: MSEdge.cpp:1125
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:168
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:1106
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:723
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
static bool gUseMesoSim
Definition: MSGlobals.h:103
static bool gCheckRoutes
Definition: MSGlobals.h:88
The base class for an intersection.
Definition: MSJunction.h:58
const ConstMSEdgeVector & getIncoming() const
Definition: MSJunction.h:108
const ConstMSEdgeVector & getOutgoing() const
Definition: MSJunction.h:114
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:2736
int getVehicleNumber() const
Returns the number of vehicles on this lane (for which this lane is responsible)
Definition: MSLane.h:448
MSVehicle * getLastFullVehicle() const
returns the last vehicle for which this lane is responsible or 0
Definition: MSLane.cpp:2549
double getLength() const
Returns the lane's length.
Definition: MSLane.h:598
int getIndex() const
Returns the lane's index.
Definition: MSLane.h:634
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:2689
double getMeanSpeed() const
Returns the mean speed on this lane.
Definition: MSLane.cpp:3339
double getTravelledDistance() const
Returns the total travelled distance.
Definition: MSMeanData.h:156
virtual double getSamples() const
Returns the number of collected sample seconds.
Definition: MSMeanData.cpp:280
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:184
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:378
MSEventControl * getEndOfTimestepEvents()
Returns the event control for events executed at the end of a time step.
Definition: MSNet.h:481
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.
Definition: MSRouteProbe.h:58
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
MSLane * getMutableLane() const
Returns the lane the vehicle is on Non const version indicates that something volatile is going on.
Definition: MSVehicle.h:592
void onRemovalFromNet(const MSMoveReminder::Notification reason)
Called when the vehicle is removed from the network.
Definition: MSVehicle.cpp:1045
double getPositionOnLane() const
Get the vehicle's position along the lane.
Definition: MSVehicle.h:377
The car-following model and parameter.
Definition: MSVehicleType.h:63
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.
Definition: OutputDevice.h:61
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:254
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.
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 parametersSet
Information for the router which parameter were set, TraCI may modify this (when changing color)
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.
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: XMLSubSys.cpp:148
Definition: json.hpp:4471
SUMOVehicleParameter * vehicleParameter
Definition: MSCalibrator.h:104