SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MSCalibrator.cpp
Go to the documentation of this file.
1 /****************************************************************************/
8 // Calibrates the flow on an edge by removing an inserting vehicles
9 /****************************************************************************/
10 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
11 // Copyright (C) 2001-2011 DLR (http://www.dlr.de/) and contributors
12 /****************************************************************************/
13 //
14 // This program is free software; you can redistribute it and/or modify
15 // it under the terms of the GNU General Public License as published by
16 // the Free Software Foundation; either version 2 of the License, or
17 // (at your option) any later version.
18 //
19 /****************************************************************************/
20 
21 
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #ifdef _MSC_VER
26 #include <windows_config.h>
27 #else
28 #include <config.h>
29 #endif
30 
31 #include <string>
32 #include <algorithm>
33 #include <cmath>
34 #include <microsim/MSNet.h>
35 #include <microsim/MSEdge.h>
36 #include <microsim/MSLane.h>
39 #include <utils/common/ToString.h>
42 #include <utils/xml/XMLSubSys.h>
48 #include "MSCalibrator.h"
49 
50 #ifdef CHECK_MEMORY_LEAKS
51 #include <foreign/nvwa/debug_new.h>
52 #endif // CHECK_MEMORY_LEAKS
53 
54 //#define MSCalibrator_DEBUG
55 
56 // ===========================================================================
57 // static members
58 // ===========================================================================
59 std::vector<MSMoveReminder*> MSCalibrator::LeftoverReminders;
60 std::vector<SUMOVehicleParameter*> MSCalibrator::LeftoverVehicleParameters;
61 
62 // ===========================================================================
63 // method definitions
64 // ===========================================================================
65 MSCalibrator::MSCalibrator(const std::string& id,
66  MSEdge* edge, SUMOReal pos,
67  const std::string& aXMLFilename,
68  const std::string& outputFilename,
69  const SUMOTime freq) :
70  MSTrigger(id),
71  MSRouteHandler(aXMLFilename, false),
72  myEdge(edge),
73  myEdgeMeanData(0, myEdge->getLength(), false),
74  myOutput(0), myFrequency(freq), myRemoved(0),
75  myInserted(0), myClearedInJam(0),
76  mySpeedIsDefault(true), myDidSpeedAdaption(false), myDidInit(false),
77  myDefaultSpeed(myEdge->getSpeedLimit()),
78  myHaveWarnedAboutClearingJam(false) {
79  if (outputFilename != "") {
80  myOutput = &OutputDevice::getDevice(outputFilename);
81  myOutput->writeXMLHeader("calibratorstats");
82  }
83  if (aXMLFilename != "") {
84  XMLSubSys::runParser(*this, aXMLFilename);
85  if (!myDidInit) {
86  init();
87  }
88  }
89 }
90 
91 
92 void
94  if (myIntervals.size() > 0) {
95  if (myIntervals.back().end == -1) {
96  myIntervals.back().end = SUMOTime_MAX;
97  }
99  // calibration should happen after regular insertions have taken place
101  MSNet::getInstance()->getCurrentTimeStep(),
103  for (size_t i = 0; i < myEdge->getLanes().size(); ++i) {
104  MSLane* lane = myEdge->getLanes()[i];
106  LeftoverReminders.push_back(laneData);
107  myLaneMeanData.push_back(laneData);
108  VehicleRemover* remover = new VehicleRemover(lane, (int)i, this);
109  LeftoverReminders.push_back(remover);
110  myVehicleRemovers.push_back(remover);
111  }
112  } else {
113  WRITE_WARNING("No flow intervals in calibrator '" + myID + "'.");
114  }
115  myDidInit = true;
116 }
117 
118 
120  if (myCurrentStateInterval != myIntervals.end()) {
121  writeXMLOutput();
122  }
123  //mySegment->removeDetector(&myMeanData);
124  for (std::vector<VehicleRemover*>::iterator it = myVehicleRemovers.begin(); it != myVehicleRemovers.end(); ++it) {
125  (*it)->disable();
126  }
127 }
128 
129 
130 void
132  const SUMOSAXAttributes& attrs) {
133  if (element == SUMO_TAG_FLOW) {
134  AspiredState state;
135  int lastEnd = -1;
136  if (myIntervals.size() > 0) {
137  lastEnd = myIntervals.back().end;
138  if (lastEnd == -1) {
139  lastEnd = myIntervals.back().begin;
140  }
141  }
142  try {
143  bool ok = true;
144  state.q = attrs.getOpt<SUMOReal>(SUMO_ATTR_VEHSPERHOUR, 0, ok, -1.);
145  state.v = attrs.getOpt<SUMOReal>(SUMO_ATTR_SPEED, 0, ok, -1.);
146  state.begin = attrs.getSUMOTimeReporting(SUMO_ATTR_BEGIN, myID.c_str(), ok);
147  if (state.begin < lastEnd) {
148  WRITE_ERROR("Overlapping or unsorted intervals in calibrator '" + myID + "'.");
149  }
150  state.end = attrs.getOptSUMOTimeReporting(SUMO_ATTR_END, myID.c_str(), ok, -1);
153  // vehicles should be inserted with max speed unless stated otherwise
156  }
157  // vehicles should be inserted on any lane unless stated otherwise
160  }
161  if (MSNet::getInstance()->getVehicleControl().getVType(state.vehicleParameter->vtypeid) == 0) {
162  WRITE_ERROR("Unknown vehicle type '" + state.vehicleParameter->vtypeid + "' in calibrator '" + myID + "'.");
163  }
164  } catch (EmptyData) {
165  WRITE_ERROR("Mandatory attribute missing in definition of calibrator '" + myID + "'.");
166  } catch (NumberFormatException) {
167  WRITE_ERROR("Non-numeric value for numeric attribute in definition of calibrator '" + myID + "'.");
168  }
169  if (state.q < 0 && state.v < 0) {
170  WRITE_ERROR("Either 'vehsPerHour' or 'speed' has to be given in flow definition of calibrator '" + myID + "'.");
171  }
172  if (myIntervals.size() > 0 && myIntervals.back().end == -1) {
173  myIntervals.back().end = state.begin;
174  }
175  myIntervals.push_back(state);
176  } else {
177  MSRouteHandler::myStartElement(element, attrs);
178  }
179 }
180 
181 
182 void
184  if (element == SUMO_TAG_CALIBRATOR) {
185  if (!myDidInit) {
186  init();
187  }
188  } else if (element != SUMO_TAG_FLOW) {
190  }
191 }
192 
193 
194 void
196  if (myOutput != 0) {
197  updateMeanData();
198  // vehicles drive to the end of an edge by default so they count as passed
199  // but vaporized vehicles do not count
200  // if the calibrator is located on a short edge, the vehicles are
201  // vaporized on the next edge so we cannot rely on myEdgeMeanData.nVehVaporized
203  const SUMOReal durationSeconds = STEPS2TIME(myCurrentStateInterval->end - myCurrentStateInterval->begin);
204  (*myOutput) << " <interval begin=\"" << time2string(myCurrentStateInterval->begin) <<
205  "\" end=\"" << time2string(myCurrentStateInterval->end) <<
206  "\" id=\"" << myID <<
207  "\" nVehContrib=\"" << p <<
208  "\" removed=\"" << myRemoved <<
209  "\" inserted=\"" << myInserted <<
210  "\" cleared=\"" << myClearedInJam <<
211  "\" flow=\"" << p * 3600.0 / durationSeconds <<
212  "\" aspiredFlow=\"" << myCurrentStateInterval->q <<
214  "\" aspiredSpeed=\"" << myCurrentStateInterval->v <<
215  "\"/>\n";
216  }
217  myDidSpeedAdaption = false;
218  myInserted = 0;
219  myRemoved = 0;
220  myClearedInJam = 0;
222  reset();
223 }
224 
225 
226 bool
228  while (myCurrentStateInterval != myIntervals.end() && myCurrentStateInterval->end <= time) {
229  // XXX what about skipped intervals?
231  }
232  return myCurrentStateInterval != myIntervals.end() &&
233  myCurrentStateInterval->begin <= time && myCurrentStateInterval->end > time;
234 }
235 
236 
237 bool
240  /*
241  if (s->initialise(vehicle, vehicle->getParameter().depart)) {
242  vehicle->onDepart();
243  if (!MSNet::getInstance()->getVehicleControl().addVehicle(vehicle->getID(), vehicle)) {
244  throw ProcessError("Emission of vehicle '" + vehicle->getID() + "' in calibrator '" + getID() + "'failed!");
245  }
246  return true;
247  }
248  */
249  return false;
250 }
251 
252 
253 SUMOTime
255  // get current simulation values (valid for the last simulation second)
256  // XXX could we miss vehicle movements if this is called less often than every DELTA_T (default) ?
257  updateMeanData();
258  // check whether an adaptation value exists
259  if (isCurrentStateActive(currentTime)) {
260  // all happens in isCurrentStateActive()
261  } else {
262  reset();
263  if (!mySpeedIsDefault) {
264  // reset speed to default
265  for (std::vector<MSLane*>::const_iterator i = myEdge->getLanes().begin(); i != myEdge->getLanes().end(); ++i) {
266  (*i)->setMaxSpeed(myDefaultSpeed);
267  }
268  mySpeedIsDefault = true;
269  }
270  if (myCurrentStateInterval == myIntervals.end()) {
271  return 0;
272  }
273  return myFrequency;
274  }
275  // we are active
276  if (!myDidSpeedAdaption && myCurrentStateInterval->v >= 0) {
277  for (std::vector<MSLane*>::const_iterator i = myEdge->getLanes().begin(); i != myEdge->getLanes().end(); ++i) {
278  (*i)->setMaxSpeed(myCurrentStateInterval->v);
279  }
280  mySpeedIsDefault = false;
281  myDidSpeedAdaption = true;
282  }
283 
284  const bool calibrateFlow = myCurrentStateInterval->q >= 0;
285  const SUMOReal totalHourFraction = STEPS2TIME(myCurrentStateInterval->end - myCurrentStateInterval->begin) / (SUMOReal) 3600.;
286  const int totalWishedNum = (int)std::floor(myCurrentStateInterval->q * totalHourFraction + 0.5); // round to closest int
287  int adaptedNum = passed() + myClearedInJam;
288 #ifdef MSCalibrator_DEBUG
289  std::cout << time2string(currentTime) << " " << myID
290  << " q=" << myCurrentStateInterval->q
291  << " totalWished=" << totalWishedNum
292  << " adapted=" << adaptedNum
293  << " jam=" << invalidJam()
294  << " entered=" << myEdgeMeanData.nVehEntered
295  << " departed=" << myEdgeMeanData.nVehDeparted
296  << " arrived=" << myEdgeMeanData.nVehArrived
297  << " left=" << myEdgeMeanData.nVehLeft
298  << " waitSecs=" << myEdgeMeanData.waitSeconds
299  << " vaporized=" << myEdgeMeanData.nVehVaporized
300  << "\n";
301 #endif
302  if (myToRemove.size() > 0) {
303  // it is not save to remove the vehicles inside
304  // VehicleRemover::notifyEnter so we do it here
305  for (std::vector<MSVehicle*>::iterator it = myToRemove.begin(); it != myToRemove.end(); ++it) {
306  MSVehicle* vehicle = *it;
308  vehicle->getLane()->removeVehicle(vehicle);
310  }
311  myToRemove.clear();
312  } else if (calibrateFlow && adaptedNum < totalWishedNum) {
313  // we need to insert some vehicles
314  const SUMOReal hourFraction = STEPS2TIME(currentTime - myCurrentStateInterval->begin + DELTA_T) / (SUMOReal) 3600.;
315  const int wishedNum = (int)std::floor(myCurrentStateInterval->q * hourFraction + 0.5); // round to closest int
316  // only the difference between inflow and aspiredFlow should be added, thus
317  // we should not count vehicles vaporized from a jam here
318  // if we have enough time left we can add missing vehicles later
319  const int relaxedInsertion = (int)std::floor(STEPS2TIME(myCurrentStateInterval->end - currentTime) / 3);
320  const int insertionSlack = MAX2(0, adaptedNum + relaxedInsertion - totalWishedNum);
321  // increase number of vehicles
322 #ifdef MSCalibrator_DEBUG
323  std::cout
324  << " wished:" << wishedNum
325  << " slack:" << insertionSlack
326  << " before:" << adaptedNum
327  << "\n";
328 #endif
329  while (wishedNum > adaptedNum + insertionSlack) {
330  SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
331  const MSRoute* route = 0;
332  StringTokenizer st(pars->routeid);
333  while (route == 0 && st.hasNext()) {
334  route = MSRoute::dictionary(st.next());
335  }
336  if (route == 0) {
337  WRITE_WARNING("No valid routes in calibrator '" + myID + "'.");
338  break;
339  }
340  if (!route->contains(myEdge)) {
341  WRITE_WARNING("Route '" + route->getID() + "' in calibrator '" + myID + "' does not contain edge '" + myEdge->getID() + "'.");
342  break;
343  }
344  const unsigned int routeIndex = (unsigned int)std::distance(route->begin(),
345  std::find(route->begin(), route->end(), myEdge));
347  assert(route != 0 && vtype != 0);
348  // build the vehicle
349  SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
350  newPars->id = myID + "." + toString((int)STEPS2TIME(myCurrentStateInterval->begin)) + "." + toString(myInserted);
351  newPars->depart = currentTime;
352  newPars->routeid = route->getID();
354  newPars, route, vtype));
355 #ifdef MSCalibrator_DEBUG
356  std::cout << " resetting route pos: " << routeIndex << "\n";
357 #endif
358  vehicle->resetRoutePosition(routeIndex);
359  if (myEdge->insertVehicle(*vehicle, currentTime)) {
360  vehicle->onDepart();
361  if (!MSNet::getInstance()->getVehicleControl().addVehicle(vehicle->getID(), vehicle)) {
362  throw ProcessError("Emission of vehicle '" + vehicle->getID() + "' in calibrator '" + getID() + "'failed!");
363  }
364  myInserted++;
365  adaptedNum++;
366 #ifdef MSCalibrator_DEBUG
367  std::cout << "I ";
368 #endif
369  } else {
370  // could not insert vehicle
371 #ifdef MSCalibrator_DEBUG
372  std::cout << "F ";
373 #endif
375  break;
376  }
377  }
378  }
379  if (myCurrentStateInterval->end <= currentTime + myFrequency) {
380  writeXMLOutput();
381  }
382  return myFrequency;
383 }
384 
385 void
388  for (std::vector<MSMeanData_Net::MSLaneMeanDataValues*>::iterator it = myLaneMeanData.begin(); it != myLaneMeanData.end(); ++it) {
389  (*it)->reset();
390  }
391 }
392 
393 
394 bool
395 MSCalibrator::invalidJam(int laneIndex) const {
396  if (laneIndex < 0) {
397  const int numLanes = (int)myEdge->getLanes().size();
398  for (int i = 0; i < numLanes; ++i) {
399  if (invalidJam(i)) {
400  return true;
401  }
402  }
403  return false;
404  }
405  assert(laneIndex < (int)myEdge->getLanes().size());
406  MSLane* lane = myEdge->getLanes()[laneIndex];
407  unsigned int vehiclesOnEdge = 0;
408  SUMOReal meanSpeed = 0;
409  if (lane->getVehicleNumber() < 4) {
410  // cannot reliably detect invalid jams
411  return false;
412  }
413  // maxSpeed reflects the calibration target
414  const bool toSlow = lane->getMeanSpeed() < 0.5 * myEdge->getSpeedLimit();
415  return toSlow && remainingVehicleCapacity(laneIndex) < 1;
416 }
417 
418 
419 int
421  if (laneIndex < 0) {
422  const int numLanes = (int)myEdge->getLanes().size();
423  int result = 0;
424  for (int i = 0; i < numLanes; ++i) {
425  result = MAX2(result, remainingVehicleCapacity(i));
426  }
427  return result;
428  }
429  assert(laneIndex < (int)myEdge->getLanes().size());
430  MSLane* lane = myEdge->getLanes()[laneIndex];
431  MSVehicle* last = lane->getLastVehicle();
432  const SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
434  const SUMOReal spacePerVehicle = vtype->getLengthWithGap() + myEdge->getSpeedLimit() * vtype->getCarFollowModel().getHeadwayTime();
435  if (last == 0) {
436  // ensure vehicles can be inserted on short edges
437  return MAX2(1, (int)(myEdge->getLength() / spacePerVehicle));
438  } else {
439  return (int)(last->getPositionOnLane() / spacePerVehicle);
440  }
441 }
442 
443 
444 void
446  for (std::vector<MSMoveReminder*>::iterator it = LeftoverReminders.begin(); it != LeftoverReminders.end(); ++it) {
447  delete *it;
448  }
449  for (std::vector<SUMOVehicleParameter*>::iterator it = LeftoverVehicleParameters.begin();
450  it != LeftoverVehicleParameters.end(); ++it) {
451  delete *it;
452  }
453 }
454 
455 
456 void
459  for (std::vector<MSMeanData_Net::MSLaneMeanDataValues*>::iterator it = myLaneMeanData.begin();
460  it != myLaneMeanData.end(); ++it) {
461  (*it)->addTo(myEdgeMeanData);
462  }
463 }
464 
466  if (myParent == 0) {
467  return false;
468  }
470  const bool calibrateFlow = myParent->myCurrentStateInterval->q >= 0;
471  const SUMOReal totalHourFraction = STEPS2TIME(myParent->myCurrentStateInterval->end - myParent->myCurrentStateInterval->begin) / (SUMOReal) 3600.;
472  const int totalWishedNum = (int)std::floor(myParent->myCurrentStateInterval->q * totalHourFraction + 0.5); // round to closest int
473  int adaptedNum = myParent->passed() + myParent->myClearedInJam;
474  MSVehicle* vehicle = dynamic_cast<MSVehicle*>(&veh);
475  if (calibrateFlow && adaptedNum > totalWishedNum) {
476 #ifdef MSCalibrator_DEBUG
477  std::cout << " vaporizing " << vehicle->getID() << " to reduce flow\n";
478 #endif
479  myParent->scheduleRemoval(vehicle);
480  myParent->myRemoved++;
481  } else if (myParent->invalidJam(myLaneIndex)) {
482 #ifdef MSCalibrator_DEBUG
483  std::cout << " vaporizing " << vehicle->getID() << " to clear jam\n";
484 #endif
486  WRITE_WARNING("Clearing jam at calibrator '" + myParent->myID + "' at time "
487  + time2string(MSNet::getInstance()->getCurrentTimeStep()));
489  }
490  myParent->scheduleRemoval(vehicle);
492  }
493  return true;
494 }
495 
496 
497 
498 /****************************************************************************/
499