Eclipse SUMO - Simulation of Urban MObility
METriggeredCalibrator.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2001-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 /****************************************************************************/
18 // Calibrates the flow on a segment to a specified one
19 /****************************************************************************/
20 #include <config.h>
21 
22 #include <string>
23 #include <algorithm>
24 #include <cmath>
25 #include <microsim/MSGlobals.h>
26 #include <microsim/MSNet.h>
27 #include <microsim/MSEdge.h>
32 #include <utils/common/ToString.h>
35 #include <utils/xml/XMLSubSys.h>
41 #include "MELoop.h"
42 #include "MESegment.h"
43 #include "MEVehicle.h"
44 #include "METriggeredCalibrator.h"
45 
46 
47 // ===========================================================================
48 // method definitions
49 // ===========================================================================
51  const MSEdge* const edge, const double pos,
52  const std::string& aXMLFilename,
53  const std::string& outputFilename,
54  const SUMOTime freq, const double length,
55  const MSRouteProbe* probe,
56  const double invalidJamThreshold,
57  const std::string& vTypes) :
58  MSCalibrator(id, edge, (MSLane*)nullptr, pos, aXMLFilename, outputFilename, freq, length, probe, invalidJamThreshold, vTypes, false),
59  mySegment(MSGlobals::gMesoNet->getSegmentForEdge(*edge, pos)) {
60  myEdgeMeanData.setDescription("meandata_calibrator_" + getID());
62 }
63 
64 
66  if (myCurrentStateInterval != myIntervals.end()) {
67  // need to do it here and not in MSCalibrator because otherwise meandata is gone
68  intervalEnd();
69  // but avoid to call it again in MSCalibrator
71  }
72  // TODO this is just commented out to work around https://github.com/eclipse/sumo/issues/7861
73  //mySegment->removeDetector(&myEdgeMeanData);
74 }
75 
76 
77 bool
79  if (s->initialise(vehicle, vehicle->getParameter().depart)) {
80  if (!MSNet::getInstance()->getVehicleControl().addVehicle(vehicle->getID(), vehicle)) {
81  throw ProcessError("Emission of vehicle '" + vehicle->getID() + "' in calibrator '" + getID() + "'failed!");
82  }
83  return true;
84  }
85  return false;
86 }
87 
88 
91  // get current simulation values (valid for the last simulation second)
92  // XXX could we miss vehicle movements if this is called less often than every DELTA_T (default) ?
94 
95  // check whether an adaptation value exists
96  if (isCurrentStateActive(currentTime)) {
97  // all happens in isCurrentStateActive()
98  myAmActive = true;
99  } else {
100  myAmActive = false;
101  myEdgeMeanData.reset(); // discard collected values
102  if (!mySpeedIsDefault) {
103  // if not, reset adaptation values
104  const double jamThresh = OptionsCont::getOptions().getFloat("meso-jam-threshold");
105  myEdge->setMaxSpeed(myDefaultSpeed, jamThresh);
106  mySpeedIsDefault = true;
107  }
108  if (myCurrentStateInterval == myIntervals.end()) {
109  // keep calibrator alive but do not call again
110  return TIME2STEPS(86400);
111  }
112  return myFrequency;
113  }
114  const bool calibrateFlow = myCurrentStateInterval->q >= 0;
115  const bool calibrateSpeed = myCurrentStateInterval->v >= 0;
116  // we are active
117  if (!myDidSpeedAdaption && calibrateSpeed && myCurrentStateInterval->v != mySegment->getEdge().getSpeedLimit()) {
119  mySpeedIsDefault = false;
120  myDidSpeedAdaption = true;
121  }
122  // clear invalid jams
123  bool hadInvalidJam = false;
124  while ((calibrateFlow || calibrateSpeed) && invalidJam()) {
125  hadInvalidJam = true;
127  WRITE_WARNINGF(TL("Clearing jam at calibrator '%' at time=%."), getID(), time2string(currentTime));
128  }
129  // remove one vehicle currently on the segment
130  if (mySegment->vaporizeAnyCar(currentTime, this)) {
131  myClearedInJam++;
132  } else {
134  // this frequenly happens for very short edges
135  WRITE_WARNINGF(TL("Could not clear jam at calibrator '%' at time=%."), getID(), time2string(currentTime));
136  }
137  break;
138  }
140  }
141  if (calibrateFlow) {
142  // flow calibration starts here ...
143  // compute the number of vehicles that should have passed the calibrator within the time
144  // rom begin of the interval
145  const double totalHourFraction = STEPS2TIME(myCurrentStateInterval->end - myCurrentStateInterval->begin) / (double) 3600.;
146  const int totalWishedNum = (int)std::floor(myCurrentStateInterval->q * totalHourFraction + 0.5); // round to closest int
147  int adaptedNum = passed() + myClearedInJam;
148  if (!hadInvalidJam) {
149  // only add vehicles if we do not have an invalid upstream jam to prevent spill-back
150  const double hourFraction = STEPS2TIME(currentTime - myCurrentStateInterval->begin + DELTA_T) / (double) 3600.;
151  const int wishedNum = (int)std::floor(myCurrentStateInterval->q * hourFraction + 0.5); // round to closest int
152  // only the difference between inflow and aspiredFlow should be added, thus
153  // we should not count vehicles vaporized from a jam here
154  // if we have enough time left we can add missing vehicles later
155  const int relaxedInsertion = (int)std::floor(STEPS2TIME(myCurrentStateInterval->end - currentTime) / 3);
156  const int insertionSlack = MAX2(0, adaptedNum + relaxedInsertion - totalWishedNum);
157  // increase number of vehicles
158  //std::cout << "time:" << STEPS2TIME(currentTime) << " w:" << wishedNum << " s:" << insertionSlack << " before:" << adaptedNum;
160  while (wishedNum > adaptedNum + insertionSlack && remainingVehicleCapacity() > maximumInflow()) {
161  SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
162  ConstMSRoutePtr route = myProbe != nullptr ? myProbe->sampleRoute() : nullptr;
163  if (route == nullptr) {
164  route = MSRoute::dictionary(pars->routeid);
165  }
166  if (route == nullptr) {
167  WRITE_WARNINGF(TL("No valid routes in calibrator '%'."), getID());
168  break;
169  }
170  if (!route->contains(myEdge)) {
171  WRITE_WARNINGF(TL("Route '%' in calibrator '%' does not contain edge '%'."), route->getID(), getID(), myEdge->getID());
172  break;
173  }
174  MSVehicleType* vtype = vc.getVType(pars->vtypeid);
175  assert(route != 0 && vtype != 0);
176  // build the vehicle
177  const SUMOTime depart = mySegment->getNextInsertionTime(currentTime);
178  SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
179  newPars->id = getNewVehicleID();
180  newPars->depart = depart;
181  newPars->routeid = route->getID();
182  MEVehicle* vehicle;
183  try {
184  vehicle = static_cast<MEVehicle*>(vc.buildVehicle(newPars, route, vtype, false, false));
185  std::string msg;
186  if (!vehicle->hasValidRouteStart(msg)) {
187  throw ProcessError(msg);
188  }
189  } catch (const ProcessError& e) {
191  WRITE_WARNING(e.what());
192  vehicle = nullptr;
193  break;
194  } else {
195  throw e;
196  }
197  }
198  const bool duplicate = vc.getVehicle(newPars->id) != nullptr;
199  // duplicate ids could come from loading state
200  if (duplicate) {
201  vc.deleteVehicle(vehicle, true);
202  continue;
203  }
204  vehicle->setSegment(mySegment); // needed or vehicle will not be registered (XXX why?)
205  vehicle->setEventTime(currentTime); // XXX superfluous?
206  // move vehicle forward when the route does not begin at the calibrator's edge
207  const MSEdge* myedge = &mySegment->getEdge();
208  bool atDest = false;
209  while (vehicle->getEdge() != myedge) {
210  // let the vehicle move to the next edge
211  atDest = vehicle->moveRoutePointer();
212  }
213  // insert vehicle into the net
214  if (atDest || !tryEmit(mySegment, vehicle)) {
215  //std::cout << "F ";
216  vc.deleteVehicle(vehicle, true);
217  break;
218  }
219  //std::cout << "I ";
220  myInserted++;
221  adaptedNum++;
222  }
223  }
224  //std::cout << " after:" << adaptedNum << "\n";
225  // we only remove vehicles once we really have to
226  while (totalWishedNum < adaptedNum) {
227  if (!mySegment->vaporizeAnyCar(currentTime, this)) {
228  // @bug: short edges may be jumped in a single step, giving us no chance to remove a vehicle
229  break;
230  }
231  myRemoved++;
232  adaptedNum--;
233  }
234  }
235  if (myCurrentStateInterval->end <= currentTime + myFrequency) {
236  intervalEnd();
237  }
238  //assert(!invalidJam());
239  if (invalidJam()) {
240  WRITE_WARNINGF("DEBUG: Could not clear jam at calibrator '%' at time=%.", getID(), time2string(currentTime));
241  }
242  return myFrequency;
243 }
244 
245 
246 bool
248  if (mySegment->getBruttoOccupancy() == 0.) {
249  return false;
250  }
251  // maxSpeed reflects the calibration target
253  return toSlow && remainingVehicleCapacity() < maximumInflow();
254 }
255 
256 
257 int
259  const SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
262 }
263 
264 
265 void
268 }
269 
270 
271 /****************************************************************************/
long long int SUMOTime
Definition: GUI.h:35
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
#define TL(string)
Definition: MsgHandler.h:315
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 TIME2STEPS(x)
Definition: SUMOTime.h:57
T MAX2(T a, T b)
Definition: StdDefs.h:82
A single mesoscopic segment (cell)
Definition: MESegment.h:49
bool initialise(MEVehicle *veh, SUMOTime time)
Inserts (emits) vehicle into the segment.
Definition: MESegment.cpp:360
double getBruttoOccupancy() const
Returns the occupany of the segment (the sum of the vehicle lengths + minGaps)
Definition: MESegment.h:258
void addDetector(MSMoveReminder *data, int queueIndex=-1)
Adds a data collector for a detector to this segment.
Definition: MESegment.cpp:254
const MSEdge & getEdge() const
Returns the edge this segment belongs to.
Definition: MESegment.h:359
double getMeanSpeed(bool useCache) const
Returns the average speed of vehicles on the segment in meters per second. If there is no vehicle on ...
Definition: MESegment.cpp:376
int remainingVehicleCapacity(const double vehLength) const
return the remaining physical space on this segment
Definition: MESegment.h:451
SUMOTime getNextInsertionTime(SUMOTime earliestEntry) const
return a time after earliestEntry at which a vehicle may be inserted at full speed
Definition: MESegment.cpp:425
void prepareDetectorForWriting(MSMoveReminder &data, int queueIndex=-1)
Removes a data collector for a detector from this segment.
Definition: MESegment.cpp:283
bool vaporizeAnyCar(SUMOTime currentTime, const MSDetectorFileOutput *filter)
tries to remove any car from this segment
Definition: MESegment.cpp:686
void reset()
reset collected vehicle data
int maximumInflow() const
returns the maximum number of vehicles that could enter from upstream until the calibrator is activat...
SUMOTime execute(SUMOTime currentTime)
int remainingVehicleCapacity() const
returns the number of vehicles (of the current type) that still fit onto the segment
bool invalidJam() const
returns whether the segment is jammed although it should not be
METriggeredCalibrator(const std::string &id, const MSEdge *const edge, 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)
MESegment * mySegment
mesoscopic edge segment the calibrator lies on
bool tryEmit(MESegment *s, MEVehicle *vehicle)
A vehicle from the mesoscopic point of view.
Definition: MEVehicle.h:42
bool moveRoutePointer()
Update when the vehicle enters a new edge in the move step.
Definition: MEVehicle.cpp:137
void setEventTime(SUMOTime t, bool hasDelay=true)
Sets the (planned) time at which the vehicle leaves its current segment.
Definition: MEVehicle.h:188
virtual void setSegment(MESegment *s, int idx=0)
Sets the current segment the vehicle is at together with its que.
Definition: MEVehicle.h:209
const SUMOVehicleParameter & getParameter() const
Returns the vehicle's parameter (including departure definition)
const MSEdge * getEdge() const
Returns the edge the vehicle is currently at.
virtual bool hasValidRouteStart(std::string &msg)
checks wether the vehicle can depart on the first edge
Calibrates the flow on a segment to a specified one.
Definition: MSCalibrator.h:47
double myInvalidJamThreshold
relative speed threshold for detecting and clearing invalid jam
Definition: MSCalibrator.h:340
MSEdge *const myEdge
the edge on which this calibrator lies
Definition: MSCalibrator.h:287
bool mySpeedIsDefault
The information whether the speed adaption has been reset.
Definition: MSCalibrator.h:326
int myRemoved
The number of vehicles that were removed in the current interval.
Definition: MSCalibrator.h:320
const MSRouteProbe *const myProbe
the route probe to retrieve routes from
Definition: MSCalibrator.h:293
bool myAmActive
whether the calibrator was active when last checking
Definition: MSCalibrator.h:337
std::vector< AspiredState >::const_iterator myCurrentStateInterval
Iterator pointing to the current interval.
Definition: MSCalibrator.h:304
int myInserted
The number of vehicles that were inserted in the current interval.
Definition: MSCalibrator.h:322
bool myHaveWarnedAboutClearingJam
The default (maximum) speed on the segment.
Definition: MSCalibrator.h:334
std::vector< AspiredState > myIntervals
List of adaptation intervals.
Definition: MSCalibrator.h:302
std::string getNewVehicleID()
determine id of new vehicle from calibrator state
MSMeanData_Net::MSLaneMeanDataValues myEdgeMeanData
accumlated data for the whole edge
Definition: MSCalibrator.h:299
int myClearedInJam
The number of vehicles that were removed when clearin a jam.
Definition: MSCalibrator.h:324
double myDefaultSpeed
The default (maximum) speed on the segment.
Definition: MSCalibrator.h:332
void intervalEnd()
bool isCurrentStateActive(SUMOTime time)
SUMOTime myFrequency
The frequeny with which to check for calibration.
Definition: MSCalibrator.h:318
bool myDidSpeedAdaption
The information whether speed was adapted in the current interval.
Definition: MSCalibrator.h:328
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:1113
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:1094
static bool gCheckRoutes
Definition: MSGlobals.h:88
Representation of a lane in the micro simulation.
Definition: MSLane.h:84
void reset(bool afterWrite=false)
Resets values so they may be used for the next interval.
void setDescription(const std::string &description)
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:182
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:378
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.
virtual SUMOVehicle * buildVehicle(SUMOVehicleParameter *defs, ConstMSRoutePtr route, MSVehicleType *type, const bool ignoreStopErrors, const bool fromRouteFile=true, bool addRouteStops=true)
Builds a vehicle, increases the number of built 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 void deleteVehicle(SUMOVehicle *v, bool discard=false, bool wasKept=false)
Deletes the vehicle.
The car-following model and parameter.
Definition: MSVehicleType.h:63
double getLengthWithGap() const
Get vehicle's length including the minimum gap [m].
const std::string & getID() const
Returns the id.
Definition: Named.h:74
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:60
Structure representing possible vehicle parameter.
std::string vtypeid
The vehicle's type id.
std::string routeid
The vehicle's route id.
std::string id
The vehicle's id.