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>
35#include <utils/xml/XMLSubSys.h>
41#include "MELoop.h"
42#include "MESegment.h"
43#include "MEVehicle.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
67 // need to do it here and not in MSCalibrator because otherwise meandata is gone
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
77bool
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(TL("Clearing jam at calibrator '%' at time=%."), getID(), time2string(currentTime));
138 }
139 // remove one vehicle currently on the segment
140 if (mySegment->vaporizeAnyCar(currentTime, this)) {
142 } else {
144 // this frequenly happens for very short edges
145 WRITE_WARNINGF(TL("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;
170 while (wishedNum > adaptedNum + insertionSlack && remainingVehicleCapacity() > maximumInflow()) {
171 SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
172 const MSRoute* route = myProbe != nullptr ? myProbe->sampleRoute() : nullptr;
173 if (route == nullptr) {
174 route = MSRoute::dictionary(pars->routeid);
175 }
176 if (route == nullptr) {
177 WRITE_WARNING("No valid routes in calibrator '" + getID() + "'.");
178 break;
179 }
180 if (!route->contains(myEdge)) {
181 WRITE_WARNING("Route '" + route->getID() + "' in calibrator '" + getID() + "' does not contain edge '" + myEdge->getID() + "'.");
182 break;
183 }
184 MSVehicleType* vtype = vc.getVType(pars->vtypeid);
185 assert(route != 0 && vtype != 0);
186 // build the vehicle
187 const SUMOTime depart = mySegment->getNextInsertionTime(currentTime);
188 SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
189 newPars->id = getNewVehicleID();
190 newPars->depart = depart;
191 newPars->routeid = route->getID();
192 MEVehicle* vehicle;
193 try {
194 vehicle = static_cast<MEVehicle*>(vc.buildVehicle(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 const bool duplicate = vc.getVehicle(newPars->id) != nullptr;
205 // duplicate ids could come from loading state
206 if (duplicate) {
207 vc.deleteVehicle(vehicle, true);
208 continue;
209 }
210 vehicle->setSegment(mySegment); // needed or vehicle will not be registered (XXX why?)
211 vehicle->setEventTime(currentTime); // XXX superfluous?
212 // move vehicle forward when the route does not begin at the calibrator's edge
213 const MSEdge* myedge = &mySegment->getEdge();
214 bool atDest = false;
215 while (vehicle->getEdge() != myedge) {
216 // let the vehicle move to the next edge
217 atDest = vehicle->moveRoutePointer();
218 }
219 // insert vehicle into the net
220 if (atDest || !tryEmit(mySegment, vehicle)) {
221 //std::cout << "F ";
222 vc.deleteVehicle(vehicle, true);
223 break;
224 }
225 //std::cout << "I ";
226 myInserted++;
227 adaptedNum++;
228 }
229 }
230 //std::cout << " after:" << adaptedNum << "\n";
231 // we only remove vehicles once we really have to
232 while (totalWishedNum < adaptedNum) {
233 if (!mySegment->vaporizeAnyCar(currentTime, this)) {
234 // @bug: short edges may be jumped in a single step, giving us no chance to remove a vehicle
235 break;
236 }
237 myRemoved++;
238 adaptedNum--;
239 }
240 }
241 if (myCurrentStateInterval->end <= currentTime + myFrequency) {
242 intervalEnd();
243 }
244 //assert(!invalidJam());
245 if (invalidJam()) {
246 WRITE_WARNINGF(TL("DEBUG: Could not clear jam at calibrator '%' at time=%."), getID(), time2string(currentTime));
247 }
248 return myFrequency;
249}
250
251
252bool
254 if (mySegment->getBruttoOccupancy() == 0.) {
255 return false;
256 }
257 // maxSpeed reflects the calibration target
259 return toSlow && remainingVehicleCapacity() < maximumInflow();
260}
261
262
263int
265 const SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
268}
269
270
271void
274}
275
276
277/****************************************************************************/
long long int SUMOTime
Definition: GUI.h:36
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:266
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:265
#define TL(string)
Definition: MsgHandler.h:282
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:54
#define TIME2STEPS(x)
Definition: SUMOTime.h:56
T MAX2(T a, T b)
Definition: StdDefs.h:77
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:247
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:348
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:440
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
MESegment * getNextSegment() const
Returns the following segment on the same edge (0 if it is the last).
Definition: MESegment.h:223
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:47
double myInvalidJamThreshold
relative speed threshold for detecting and clearing invalid jam
Definition: MSCalibrator.h:340
const 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
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:1056
void setMaxSpeed(double val) const
Sets a new maximum speed for all lanes (used by TraCI and MSCalibrator)
Definition: MSEdge.cpp:1075
static bool gCheckRoutes
Definition: MSGlobals.h:88
static MELoop * gMesoNet
mesoscopic simulation infrastructure
Definition: MSGlobals.h:109
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:183
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:379
static bool dictionary(const std::string &id, const MSRoute *route)
Adds a route to the dictionary.
Definition: MSRoute.cpp:118
bool contains(const MSEdge *const edge) const
Definition: MSRoute.h:103
Writes routes of vehicles passing a certain edge.
Definition: MSRouteProbe.h:58
const MSRoute * sampleRoute(bool last=true) const
The class responsible for building and deletion of vehicles.
virtual void deleteVehicle(SUMOVehicle *v, bool discard=false)
Deletes the vehicle.
SUMOVehicle * getVehicle(const std::string &id) const
Returns the vehicle with the given id.
virtual SUMOVehicle * buildVehicle(SUMOVehicleParameter *defs, const MSRoute *route, MSVehicleType *type, const bool ignoreStopErrors, const bool fromRouteFile=true, bool addRouteStops=true)
Builds a vehicle, increases the number of built vehicles.
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.
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:59
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.