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.org/sumo
3 // Copyright (C) 2001-2022 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
106  const double jamThresh = OptionsCont::getOptions().getFloat("meso-jam-threshold");
107  while (first != nullptr) {
108  first->setSpeed(myDefaultSpeed, currentTime, jamThresh);
109  first = first->getNextSegment();
110  }
111  mySpeedIsDefault = true;
112  }
113  if (myCurrentStateInterval == myIntervals.end()) {
114  // keep calibrator alive but do not call again
115  return TIME2STEPS(86400);
116  }
117  return myFrequency;
118  }
119  const bool calibrateFlow = myCurrentStateInterval->q >= 0;
120  const bool calibrateSpeed = myCurrentStateInterval->v >= 0;
121  // we are active
122  if (!myDidSpeedAdaption && calibrateSpeed && myCurrentStateInterval->v != mySegment->getEdge().getSpeedLimit()) {
125  while (first != nullptr) {
126  first->setSpeed(myCurrentStateInterval->v, currentTime, -1);
127  first = first->getNextSegment();
128  }
129  mySpeedIsDefault = false;
130  myDidSpeedAdaption = true;
131  }
132  // clear invalid jams
133  bool hadInvalidJam = false;
134  while ((calibrateFlow || calibrateSpeed) && invalidJam()) {
135  hadInvalidJam = true;
137  WRITE_WARNINGF("Clearing jam at calibrator '%' at time=%.", getID(), time2string(currentTime));
138  }
139  // remove one vehicle currently on the segment
140  if (mySegment->vaporizeAnyCar(currentTime, this)) {
141  myClearedInJam++;
142  } else {
144  // this frequenly happens for very short edges
145  WRITE_WARNINGF("Could not clear jam at calibrator '%' at time=%.", getID(), time2string(currentTime));
146  }
147  break;
148  }
150  }
151  if (calibrateFlow) {
152  // flow calibration starts here ...
153  // compute the number of vehicles that should have passed the calibrator within the time
154  // rom begin of the interval
155  const double totalHourFraction = STEPS2TIME(myCurrentStateInterval->end - myCurrentStateInterval->begin) / (double) 3600.;
156  const int totalWishedNum = (int)std::floor(myCurrentStateInterval->q * totalHourFraction + 0.5); // round to closest int
157  int adaptedNum = passed() + myClearedInJam;
158  if (!hadInvalidJam) {
159  // only add vehicles if we do not have an invalid upstream jam to prevent spill-back
160  const double hourFraction = STEPS2TIME(currentTime - myCurrentStateInterval->begin + DELTA_T) / (double) 3600.;
161  const int wishedNum = (int)std::floor(myCurrentStateInterval->q * hourFraction + 0.5); // round to closest int
162  // only the difference between inflow and aspiredFlow should be added, thus
163  // we should not count vehicles vaporized from a jam here
164  // if we have enough time left we can add missing vehicles later
165  const int relaxedInsertion = (int)std::floor(STEPS2TIME(myCurrentStateInterval->end - currentTime) / 3);
166  const int insertionSlack = MAX2(0, adaptedNum + relaxedInsertion - totalWishedNum);
167  // increase number of vehicles
168  //std::cout << "time:" << STEPS2TIME(currentTime) << " w:" << wishedNum << " s:" << insertionSlack << " before:" << adaptedNum;
169  while (wishedNum > adaptedNum + insertionSlack && remainingVehicleCapacity() > maximumInflow()) {
170  SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
171  const MSRoute* route = myProbe != nullptr ? myProbe->sampleRoute() : nullptr;
172  if (route == nullptr) {
173  route = MSRoute::dictionary(pars->routeid);
174  }
175  if (route == nullptr) {
176  WRITE_WARNING("No valid routes in calibrator '" + getID() + "'.");
177  break;
178  }
179  if (!route->contains(myEdge)) {
180  WRITE_WARNING("Route '" + route->getID() + "' in calibrator '" + getID() + "' does not contain edge '" + myEdge->getID() + "'.");
181  break;
182  }
184  assert(route != 0 && vtype != 0);
185  // build the vehicle
186  const SUMOTime depart = mySegment->getNextInsertionTime(currentTime);
187  SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
188  newPars->id = getNewVehicleID();
189  newPars->depart = depart;
190  newPars->routeid = route->getID();
191  MEVehicle* vehicle;
192  try {
193  vehicle = static_cast<MEVehicle*>(MSNet::getInstance()->getVehicleControl().buildVehicle(
194  newPars, route, vtype, false, false));
195  } catch (const ProcessError& e) {
197  WRITE_WARNING(e.what());
198  vehicle = nullptr;
199  break;
200  } else {
201  throw e;
202  }
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 ";
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 /****************************************************************************/
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:281
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:280
SUMOTime DELTA_T
Definition: SUMOTime.cpp:37
std::string time2string(SUMOTime t)
convert SUMOTime to string
Definition: SUMOTime.cpp:68
#define STEPS2TIME(x)
Definition: SUMOTime.h:53
#define TIME2STEPS(x)
Definition: SUMOTime.h:55
long long int SUMOTime
Definition: SUMOTime.h:32
T MAX2(T a, T b)
Definition: StdDefs.h:80
MESegment * getSegmentForEdge(const MSEdge &e, double pos=0)
Get the segment for a given edge at a given position.
Definition: MELoop.cpp:314
A single mesoscopic segment (cell)
Definition: MESegment.h:49
bool initialise(MEVehicle *veh, SUMOTime time)
Inserts (emits) vehicle into the segment.
Definition: MESegment.cpp:329
double getBruttoOccupancy() const
Returns the occupany of the segment (the sum of the vehicle lengths + minGaps)
Definition: MESegment.h:251
MESegment * getNextSegment() const
Returns the following segment on the same edge (0 if it is the last).
Definition: MESegment.h:227
void prepareDetectorForWriting(MSMoveReminder &data)
Updates data of a detector for all vehicle queues.
Definition: MESegment.cpp:261
const MSEdge & getEdge() const
Returns the edge this segment belongs to.
Definition: MESegment.h:352
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:345
int remainingVehicleCapacity(const double vehLength) const
return the remaining physical space on this segment
Definition: MESegment.h:444
void addDetector(MSMoveReminder *data)
Adds a data collector for a detector to this segment.
Definition: MESegment.cpp:236
void setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh=DO_NOT_PATCH_JAM_THRESHOLD)
reset mySpeed and patch the speed of all vehicles in it. Also set/recompute myJamThreshold
Definition: MESegment.cpp:700
SUMOTime getNextInsertionTime(SUMOTime earliestEntry) const
return a time after earliestEntry at which a vehicle may be inserted at full speed
Definition: MESegment.cpp:394
bool vaporizeAnyCar(SUMOTime currentTime, const MSDetectorFileOutput *filter)
tries to remove any car from this segment
Definition: MESegment.cpp:655
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:140
void setEventTime(SUMOTime t, bool hasDelay=true)
Sets the (planned) time at which the vehicle leaves his current cell.
Definition: MEVehicle.h:209
virtual void setSegment(MESegment *s, int idx=0)
Sets the current segment the vehicle is at together with its que.
Definition: MEVehicle.h:230
const SUMOVehicleParameter & getParameter() const
Returns the vehicle's parameter (including departure definition)
const MSEdge * getEdge() const
Returns the edge the vehicle is currently at.
Calibrates the flow on a segment to a specified one.
Definition: MSCalibrator.h:48
double myInvalidJamThreshold
relative speed threshold for detecting and clearing invalid jam
Definition: MSCalibrator.h:333
const MSEdge *const myEdge
the edge on which this calibrator lies
Definition: MSCalibrator.h:280
bool mySpeedIsDefault
The information whether the speed adaption has been reset.
Definition: MSCalibrator.h:319
int myRemoved
The number of vehicles that were removed in the current interval.
Definition: MSCalibrator.h:313
const MSRouteProbe *const myProbe
the route probe to retrieve routes from
Definition: MSCalibrator.h:286
bool myAmActive
whether the calibrator was active when last checking
Definition: MSCalibrator.h:330
std::vector< AspiredState >::const_iterator myCurrentStateInterval
Iterator pointing to the current interval.
Definition: MSCalibrator.h:297
const std::string & getID() const
Definition: MSCalibrator.h:89
int myInserted
The number of vehicles that were inserted in the current interval.
Definition: MSCalibrator.h:315
bool myHaveWarnedAboutClearingJam
The default (maximum) speed on the segment.
Definition: MSCalibrator.h:327
std::vector< AspiredState > myIntervals
List of adaptation intervals.
Definition: MSCalibrator.h:295
std::string getNewVehicleID()
determine id of new vehicle from calibrator state
MSMeanData_Net::MSLaneMeanDataValues myEdgeMeanData
accumlated data for the whole edge
Definition: MSCalibrator.h:292
int myClearedInJam
The number of vehicles that were removed when clearin a jam.
Definition: MSCalibrator.h:317
double myDefaultSpeed
The default (maximum) speed on the segment.
Definition: MSCalibrator.h:325
void intervalEnd()
bool isCurrentStateActive(SUMOTime time)
SUMOTime myFrequency
The frequeny with which to check for calibration.
Definition: MSCalibrator.h:311
bool myDidSpeedAdaption
The information whether speed was adapted in the current interval.
Definition: MSCalibrator.h:321
A road/street connecting two junctions.
Definition: MSEdge.h:77
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:990
void setMaxSpeed(double val) const
Sets a new maximum speed for all lanes (used by TraCI and MSCalibrator)
Definition: MSEdge.cpp:1009
static bool gCheckRoutes
Definition: MSGlobals.h:82
static MELoop * gMesoNet
mesoscopic simulation infrastructure
Definition: MSGlobals.h:100
Representation of a lane in the micro simulation.
Definition: MSLane.h:82
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:174
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:376
static bool dictionary(const std::string &id, const MSRoute *route)
Adds a route to the dictionary.
Definition: MSRoute.cpp:113
bool contains(const MSEdge *const edge) const
Definition: MSRoute.h:99
Writes routes of vehicles passing a certain edge.
Definition: MSRouteProbe.h:58
const MSRoute * sampleRoute(bool last=true) const
virtual void deleteVehicle(SUMOVehicle *v, bool discard=false)
Deletes the vehicle.
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, const MSRoute *route, MSVehicleType *type, const bool ignoreStopErrors, const bool fromRouteFile=true)
Builds a vehicle, increases the number of built vehicles.
The car-following model and parameter.
Definition: MSVehicleType.h:62
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:58
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.