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  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, nullptr, nullptr, pos, aXMLFilename, outputFilename, freq, length, probe, invalidJamThreshold, vTypes, false, false),
59  mySegment(edge == nullptr ? nullptr : MSGlobals::gMesoNet->getSegmentForEdge(*edge, pos)) {
60  myEdgeMeanData.setDescription("meandata_calibrator_" + getID());
61  if (mySegment != nullptr) {
63  }
64 }
65 
66 
68  if (myCurrentStateInterval != myIntervals.end()) {
69  // need to do it here and not in MSCalibrator because otherwise meandata is gone
70  intervalEnd();
71  // but avoid to call it again in MSCalibrator
73  }
74  // TODO this is just commented out to work around https://github.com/eclipse/sumo/issues/7861
75  //mySegment->removeDetector(&myEdgeMeanData);
76 }
77 
78 
79 bool
81  if (s->initialise(vehicle, vehicle->getParameter().depart)) {
82  if (!MSNet::getInstance()->getVehicleControl().addVehicle(vehicle->getID(), vehicle)) {
83  throw ProcessError("Emission of vehicle '" + vehicle->getID() + "' in calibrator '" + getID() + "'failed!");
84  }
85  return true;
86  }
87  return false;
88 }
89 
90 
93  // get current simulation values (valid for the last simulation second)
94  // XXX could we miss vehicle movements if this is called less often than every DELTA_T (default) ?
96 
97  // check whether an adaptation value exists
98  if (isCurrentStateActive(currentTime)) {
99  // all happens in isCurrentStateActive()
100  myAmActive = true;
101  } else {
102  myAmActive = false;
103  myEdgeMeanData.reset(); // discard collected values
104  if (!mySpeedIsDefault) {
105  // if not, reset adaptation values
106  const double jamThresh = OptionsCont::getOptions().getFloat("meso-jam-threshold");
107  myEdge->setMaxSpeed(myDefaultSpeed, jamThresh);
108  mySpeedIsDefault = true;
109  }
110  if (myCurrentStateInterval == myIntervals.end()) {
111  // keep calibrator alive but do not call again
112  return TIME2STEPS(86400);
113  }
114  return myFrequency;
115  }
116  const bool calibrateFlow = myCurrentStateInterval->q >= 0;
117  const bool calibrateSpeed = myCurrentStateInterval->v >= 0;
118  // we are active
119  if (!myDidSpeedAdaption && calibrateSpeed && myCurrentStateInterval->v != mySegment->getEdge().getSpeedLimit()) {
121  mySpeedIsDefault = false;
122  myDidSpeedAdaption = true;
123  }
124  // clear invalid jams
125  bool hadInvalidJam = false;
126  while ((calibrateFlow || calibrateSpeed) && invalidJam()) {
127  hadInvalidJam = true;
129  WRITE_WARNINGF(TL("Clearing jam at calibrator '%' at time=%."), getID(), time2string(currentTime));
130  }
131  // remove one vehicle currently on the segment
132  if (mySegment->vaporizeAnyCar(currentTime, this)) {
133  myClearedInJam++;
134  } else {
136  // this frequenly happens for very short edges
137  WRITE_WARNINGF(TL("Could not clear jam at calibrator '%' at time=%."), getID(), time2string(currentTime));
138  }
139  break;
140  }
142  }
143  if (calibrateFlow) {
144  // flow calibration starts here ...
145  // compute the number of vehicles that should have passed the calibrator within the time
146  // rom begin of the interval
147  const double totalHourFraction = STEPS2TIME(myCurrentStateInterval->end - myCurrentStateInterval->begin) / (double) 3600.;
148  const int totalWishedNum = (int)std::floor(myCurrentStateInterval->q * totalHourFraction + 0.5); // round to closest int
149  int adaptedNum = passed() + myClearedInJam;
150  if (!hadInvalidJam) {
151  // only add vehicles if we do not have an invalid upstream jam to prevent spill-back
152  const double hourFraction = STEPS2TIME(currentTime - myCurrentStateInterval->begin + DELTA_T) / (double) 3600.;
153  const int wishedNum = (int)std::floor(myCurrentStateInterval->q * hourFraction + 0.5); // round to closest int
154  // only the difference between inflow and aspiredFlow should be added, thus
155  // we should not count vehicles vaporized from a jam here
156  // if we have enough time left we can add missing vehicles later
157  const int relaxedInsertion = (int)std::floor(STEPS2TIME(myCurrentStateInterval->end - currentTime) / 3);
158  const int insertionSlack = MAX2(0, adaptedNum + relaxedInsertion - totalWishedNum);
159  // increase number of vehicles
160  //std::cout << "time:" << STEPS2TIME(currentTime) << " w:" << wishedNum << " s:" << insertionSlack << " before:" << adaptedNum;
162  while (wishedNum > adaptedNum + insertionSlack && remainingVehicleCapacity() > maximumInflow()) {
163  SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
164  ConstMSRoutePtr route = myProbe != nullptr ? myProbe->sampleRoute() : nullptr;
165  if (route == nullptr) {
166  route = MSRoute::dictionary(pars->routeid);
167  }
168  if (route == nullptr) {
169  WRITE_WARNINGF(TL("No valid routes in calibrator '%'."), getID());
170  break;
171  }
172  if (!route->contains(myEdge)) {
173  WRITE_WARNINGF(TL("Route '%' in calibrator '%' does not contain edge '%'."), route->getID(), getID(), myEdge->getID());
174  break;
175  }
176  MSVehicleType* vtype = vc.getVType(pars->vtypeid);
177  assert(route != 0 && vtype != 0);
178  // build the vehicle
179  const SUMOTime depart = mySegment->getNextInsertionTime(currentTime);
180  SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
181  newPars->id = getNewVehicleID();
182  newPars->depart = depart;
183  newPars->routeid = route->getID();
184  MEVehicle* vehicle;
185  try {
186  vehicle = static_cast<MEVehicle*>(vc.buildVehicle(newPars, route, vtype, false, MSVehicleControl::VehicleDefinitionSource::TRIGGER));
187  std::string msg;
188  if (!vehicle->hasValidRouteStart(msg)) {
189  throw ProcessError(msg);
190  }
191  } catch (const ProcessError& e) {
193  WRITE_WARNING(e.what());
194  vehicle = nullptr;
195  break;
196  } else {
197  throw e;
198  }
199  }
200  const bool duplicate = vc.getVehicle(newPars->id) != nullptr;
201  // duplicate ids could come from loading state
202  if (duplicate) {
203  vc.deleteVehicle(vehicle, true);
204  continue;
205  }
206  vehicle->setSegment(mySegment); // needed or vehicle will not be registered (XXX why?)
207  vehicle->setEventTime(currentTime); // XXX superfluous?
208  // move vehicle forward when the route does not begin at the calibrator's edge
209  const MSEdge* myedge = &mySegment->getEdge();
210  bool atDest = false;
211  while (vehicle->getEdge() != myedge) {
212  // let the vehicle move to the next edge
213  atDest = vehicle->moveRoutePointer();
214  }
215  // insert vehicle into the net
216  if (atDest || !tryEmit(mySegment, vehicle)) {
217  //std::cout << "F ";
218  vc.deleteVehicle(vehicle, true);
219  break;
220  }
221  //std::cout << "I ";
222  myInserted++;
223  adaptedNum++;
224  }
225  }
226  //std::cout << " after:" << adaptedNum << "\n";
227  // we only remove vehicles once we really have to
228  while (totalWishedNum < adaptedNum) {
229  if (!mySegment->vaporizeAnyCar(currentTime, this)) {
230  // @bug: short edges may be jumped in a single step, giving us no chance to remove a vehicle
231  break;
232  }
233  myRemoved++;
234  adaptedNum--;
235  }
236  }
237  if (myCurrentStateInterval->end <= currentTime + myFrequency) {
238  intervalEnd();
239  }
240  //assert(!invalidJam());
241  if (invalidJam()) {
242  WRITE_WARNINGF("DEBUG: Could not clear jam at calibrator '%' at time=%.", getID(), time2string(currentTime));
243  }
244  return myFrequency;
245 }
246 
247 
248 bool
250  if (mySegment->getBruttoOccupancy() == 0.) {
251  return false;
252  }
253  // maxSpeed reflects the calibration target
255  return toSlow && remainingVehicleCapacity() < maximumInflow();
256 }
257 
258 
259 int
261  const SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
264 }
265 
266 
267 void
270 }
271 
272 
273 /****************************************************************************/
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:688
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
MESegment * mySegment
mesoscopic edge segment the calibrator lies on
bool tryEmit(MESegment *s, MEVehicle *vehicle)
METriggeredCalibrator(const std::string &id, 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)
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:156
void setEventTime(SUMOTime t, bool hasDelay=true)
Sets the (planned) time at which the vehicle leaves its current segment.
Definition: MEVehicle.h:190
virtual void setSegment(MESegment *s, int idx=0)
Sets the current segment the vehicle is at together with its que.
Definition: MEVehicle.h:211
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:355
MSEdge *const myEdge
the edge on which this calibrator lies
Definition: MSCalibrator.h:300
bool mySpeedIsDefault
The information whether the speed adaption has been reset.
Definition: MSCalibrator.h:341
int myRemoved
The number of vehicles that were removed in the current interval.
Definition: MSCalibrator.h:335
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::vector< AspiredState >::const_iterator myCurrentStateInterval
Iterator pointing to the current interval.
Definition: MSCalibrator.h:319
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
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
int myClearedInJam
The number of vehicles that were removed when clearin a jam.
Definition: MSCalibrator.h:339
double myDefaultSpeed
The default (maximum) speed on the segment.
Definition: MSCalibrator.h:347
void intervalEnd()
bool isCurrentStateActive(SUMOTime time)
SUMOTime myFrequency
The frequeny with which to check for calibration.
Definition: MSCalibrator.h:333
bool myDidSpeedAdaption
The information whether speed was adapted in the current interval.
Definition: MSCalibrator.h:343
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
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
static bool gCheckRoutes
Definition: MSGlobals.h:88
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:184
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.
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.
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.