Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
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-2025 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>
36#include <utils/xml/XMLSubSys.h>
42#include "MELoop.h"
43#include "MESegment.h"
44#include "MEVehicle.h"
46
47
48// ===========================================================================
49// method definitions
50// ===========================================================================
52 MSEdge* const edge, const double pos,
53 const std::string& aXMLFilename,
54 const std::string& outputFilename,
55 const SUMOTime freq, const double length,
56 const MSRouteProbe* probe,
57 const double invalidJamThreshold,
58 const std::string& vTypes) :
59 MSCalibrator(id, edge, nullptr, nullptr, pos, aXMLFilename, outputFilename, freq, length, probe, invalidJamThreshold, vTypes, false, false),
60 mySegment(edge == nullptr ? nullptr : MSGlobals::gMesoNet->getSegmentForEdge(*edge, pos)) {
61 myEdgeMeanData.setDescription("meandata_calibrator_" + getID());
62 if (mySegment != nullptr) {
64 }
65}
66
67
70 // need to do it here and not in MSCalibrator because otherwise meandata is gone
72 // but avoid to call it again in MSCalibrator
74 }
75 // TODO this is just commented out to work around https://github.com/eclipse/sumo/issues/7861
76 //mySegment->removeDetector(&myEdgeMeanData);
77}
78
79
80bool
82 if (s->initialise(vehicle, vehicle->getParameter().depart)) {
83 if (!MSNet::getInstance()->getVehicleControl().addVehicle(vehicle->getID(), vehicle)) {
84 throw ProcessError(TLF("Emission of vehicle '%' in calibrator '%' failed!", vehicle->getID(), getID()));
85 }
86 return true;
87 }
88 return false;
89}
90
91
94 // get current simulation values (valid for the last simulation second)
95 // XXX could we miss vehicle movements if this is called less often than every DELTA_T (default) ?
97
98 // check whether an adaptation value exists
99 if (isCurrentStateActive(currentTime)) {
100 // all happens in isCurrentStateActive()
101 myAmActive = true;
102 } else {
103 myAmActive = false;
104 myEdgeMeanData.reset(); // discard collected values
105 if (!mySpeedIsDefault) {
106 // if not, reset adaptation values
107 const double jamThresh = OptionsCont::getOptions().getFloat("meso-jam-threshold");
108 myEdge->setMaxSpeed(myDefaultSpeed, jamThresh);
109 mySpeedIsDefault = true;
110 }
111 if (myCurrentStateInterval == myIntervals.end()) {
112 // keep calibrator alive but do not call again
113 return TIME2STEPS(86400);
114 }
115 return myFrequency;
116 }
117 const bool calibrateFlow = myCurrentStateInterval->q >= 0;
118 const bool calibrateSpeed = myCurrentStateInterval->v >= 0;
119 // we are active
120 if (!myDidSpeedAdaption && calibrateSpeed && myCurrentStateInterval->v != mySegment->getEdge().getSpeedLimit()) {
122 mySpeedIsDefault = false;
123 myDidSpeedAdaption = true;
124 }
125 // clear invalid jams
126 bool hadInvalidJam = false;
127 while ((calibrateFlow || calibrateSpeed) && invalidJam()) {
128 hadInvalidJam = true;
130 WRITE_WARNINGF(TL("Clearing jam at calibrator '%' at time=%."), getID(), time2string(currentTime));
131 }
132 // remove one vehicle currently on the segment
133 if (mySegment->vaporizeAnyCar(currentTime, this)) {
135 } else {
137 // this frequenly happens for very short edges
138 WRITE_WARNINGF(TL("Could not clear jam at calibrator '%' at time=%."), getID(), time2string(currentTime));
139 }
140 break;
141 }
143 }
144 if (calibrateFlow) {
145 // flow calibration starts here ...
146 // compute the number of vehicles that should have passed the calibrator within the time
147 // rom begin of the interval
148 const double totalHourFraction = STEPS2TIME(myCurrentStateInterval->end - myCurrentStateInterval->begin) / (double) 3600.;
149 const int totalWishedNum = (int)std::floor(myCurrentStateInterval->q * totalHourFraction + 0.5); // round to closest int
150 int adaptedNum = passed() + myClearedInJam;
151 if (!hadInvalidJam) {
152 // only add vehicles if we do not have an invalid upstream jam to prevent spill-back
153 const double hourFraction = STEPS2TIME(currentTime - myCurrentStateInterval->begin + DELTA_T) / (double) 3600.;
154 const int wishedNum = (int)std::floor(myCurrentStateInterval->q * hourFraction + 0.5); // round to closest int
155 // only the difference between inflow and aspiredFlow should be added, thus
156 // we should not count vehicles vaporized from a jam here
157 // if we have enough time left we can add missing vehicles later
158 const int relaxedInsertion = (int)std::floor(STEPS2TIME(myCurrentStateInterval->end - currentTime) / 3);
159 const int insertionSlack = MAX2(0, adaptedNum + relaxedInsertion - totalWishedNum);
160 // increase number of vehicles
161 //std::cout << "time:" << STEPS2TIME(currentTime) << " w:" << wishedNum << " s:" << insertionSlack << " before:" << adaptedNum;
163 while (wishedNum > adaptedNum + insertionSlack && remainingVehicleCapacity() > maximumInflow()) {
164 SUMOVehicleParameter* pars = myCurrentStateInterval->vehicleParameter;
165 ConstMSRoutePtr route = myProbe != nullptr ? myProbe->sampleRoute() : nullptr;
166 if (route == nullptr) {
167 route = MSRoute::dictionary(pars->routeid);
168 }
169 if (route == nullptr) {
170 WRITE_WARNINGF(TL("No valid routes in calibrator '%'."), getID());
171 break;
172 }
173 if (!route->contains(myEdge)) {
174 WRITE_WARNINGF(TL("Route '%' in calibrator '%' does not contain edge '%'."), route->getID(), getID(), myEdge->getID());
175 break;
176 }
177 MSVehicleType* vtype = vc.getVType(pars->vtypeid);
178 assert(route != 0 && vtype != 0);
179 // build the vehicle
180 const SUMOTime depart = mySegment->getNextInsertionTime(currentTime);
181 SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
182 newPars->id = getNewVehicleID();
183 newPars->depart = depart;
184 newPars->routeid = route->getID();
185 MEVehicle* vehicle;
186 try {
187 vehicle = static_cast<MEVehicle*>(vc.buildVehicle(newPars, route, vtype, false, MSVehicleControl::VehicleDefinitionSource::TRIGGER));
188 std::string msg;
189 if (!vehicle->hasValidRouteStart(msg)) {
190 throw ProcessError(msg);
191 }
192 } catch (const ProcessError& e) {
194 WRITE_WARNING(e.what());
195 vehicle = nullptr;
196 break;
197 } else {
198 throw;
199 }
200 }
201 const bool duplicate = vc.getVehicle(newPars->id) != nullptr;
202 // duplicate ids could come from loading state
203 if (duplicate) {
204 vc.deleteVehicle(vehicle, true);
205 continue;
206 }
207 vehicle->setSegment(mySegment); // needed or vehicle will not be registered (XXX why?)
208 vehicle->setEventTime(currentTime); // XXX superfluous?
209 // move vehicle forward when the route does not begin at the calibrator's edge
210 const MSEdge* myedge = &mySegment->getEdge();
211 bool atDest = false;
212 while (vehicle->getEdge() != myedge) {
213 // let the vehicle move to the next edge
214 atDest = vehicle->moveRoutePointer();
215 }
216 // insert vehicle into the net
217 if (atDest || !tryEmit(mySegment, vehicle)) {
218 //std::cout << "F ";
219 vc.deleteVehicle(vehicle, true);
220 break;
221 }
222 //std::cout << "I ";
223 myInserted++;
224 adaptedNum++;
225 }
226 }
227 //std::cout << " after:" << adaptedNum << "\n";
228 // we only remove vehicles once we really have to
229 while (totalWishedNum < adaptedNum) {
230 if (!mySegment->vaporizeAnyCar(currentTime, this)) {
231 // @bug: short edges may be jumped in a single step, giving us no chance to remove a vehicle
232 break;
233 }
234 myRemoved++;
235 adaptedNum--;
236 }
237 }
238 if (myCurrentStateInterval->end <= currentTime + myFrequency) {
239 intervalEnd();
240 }
241 //assert(!invalidJam());
242 if (invalidJam()) {
243 WRITE_WARNINGF("DEBUG: Could not clear jam at calibrator '%' at time=%.", getID(), time2string(currentTime));
244 }
245 return myFrequency;
246}
247
248
249bool
251 if (mySegment->getBruttoOccupancy() == 0.) {
252 return false;
253 }
254 // maxSpeed reflects the calibration target
256 return toSlow && remainingVehicleCapacity() < maximumInflow();
257}
258
259
260int
266
267
268void
272
273
274/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define WRITE_WARNING(msg)
Definition MsgHandler.h:286
#define TL(string)
Definition MsgHandler.h:304
#define TLF(string,...)
Definition MsgHandler.h:306
std::shared_ptr< const MSRoute > ConstMSRoutePtr
Definition Route.h:32
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:91
#define STEPS2TIME(x)
Definition SUMOTime.h:55
#define TIME2STEPS(x)
Definition SUMOTime.h:57
T MAX2(T a, T b)
Definition StdDefs.h:86
A single mesoscopic segment (cell)
Definition MESegment.h:50
bool initialise(MEVehicle *veh, SUMOTime time)
Inserts (emits) vehicle into the segment.
double getBruttoOccupancy() const
Returns the occupany of the segment (the sum of the vehicle lengths + minGaps)
Definition MESegment.h:260
void addDetector(MSMoveReminder *data, int queueIndex=-1)
Adds a data collector for a detector to this segment.
const MSEdge & getEdge() const
Returns the edge this segment belongs to.
Definition MESegment.h:364
double getMeanSpeed(bool useCache) const
Returns the average speed of vehicles on the segment in meters per second. If there is no vehicle on ...
int remainingVehicleCapacity(const double vehLength) const
return the remaining physical space on this segment
Definition MESegment.h:455
SUMOTime getNextInsertionTime(SUMOTime earliestEntry) const
return a time after earliestEntry at which a vehicle may be inserted at full speed
void prepareDetectorForWriting(MSMoveReminder &data, int queueIndex=-1)
Removes a data collector for a detector from this segment.
bool vaporizeAnyCar(SUMOTime currentTime, const MSDetectorFileOutput *filter)
tries to remove any car from this segment
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.
void setEventTime(SUMOTime t, bool hasDelay=true)
Sets the (planned) time at which the vehicle leaves its current segment.
Definition MEVehicle.h:194
virtual void setSegment(MESegment *s, int idx=0)
Sets the current segment the vehicle is at together with its que.
Definition MEVehicle.h:215
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.
double myInvalidJamThreshold
relative speed threshold for detecting and clearing invalid jam
MSEdge *const myEdge
the edge on which this calibrator lies
bool mySpeedIsDefault
The information whether the speed adaption has been reset.
int myRemoved
The number of vehicles that were removed in the current interval.
const MSRouteProbe *const myProbe
the route probe to retrieve routes from
bool myAmActive
whether the calibrator was active when last checking
std::vector< AspiredState >::const_iterator myCurrentStateInterval
Iterator pointing to the current interval.
int myInserted
The number of vehicles that were inserted in the current interval.
bool myHaveWarnedAboutClearingJam
The default (maximum) speed on the segment.
std::vector< AspiredState > myIntervals
List of adaptation intervals.
std::string getNewVehicleID()
determine id of new vehicle from calibrator state
MSMeanData_Net::MSLaneMeanDataValues myEdgeMeanData
accumlated data for the whole edge
int myClearedInJam
The number of vehicles that were removed when clearin a jam.
double myDefaultSpeed
The default (maximum) speed on the segment.
bool isCurrentStateActive(SUMOTime time)
SUMOTime myFrequency
The frequeny with which to check for calibration.
bool myDidSpeedAdaption
The information whether speed was adapted in the current interval.
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:1187
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:1168
static bool gCheckRoutes
Definition MSGlobals.h:91
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:186
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition MSNet.h:392
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.
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.
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.
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.