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