Line data Source code
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 : /****************************************************************************/
14 : /// @file MSDevice_StationFinder.cpp
15 : /// @author Michael Behrisch
16 : /// @date 2023-05-24
17 : ///
18 : // A device which triggers rerouting to nearby charging stations
19 : /****************************************************************************/
20 : #include <config.h>
21 :
22 : #include <microsim/MSEdge.h>
23 : #include <microsim/MSNet.h>
24 : #include <microsim/MSStop.h>
25 : #include <microsim/MSVehicleControl.h>
26 : #include <microsim/output/MSDetectorControl.h>
27 : #include <utils/options/OptionsCont.h>
28 : #include <utils/emissions/PollutantsInterface.h>
29 : #include <utils/emissions/HelpersEnergy.h>
30 : #include <utils/iodevices/OutputDevice.h>
31 : #include "MSRoutingEngine.h"
32 : #include "MSDevice_Battery.h"
33 : #include "MSDevice_StationFinder.h"
34 :
35 :
36 : // ===========================================================================
37 : // method definitions
38 : // ===========================================================================
39 : // ---------------------------------------------------------------------------
40 : // static initialisation methods
41 : // ---------------------------------------------------------------------------
42 : void
43 36320 : MSDevice_StationFinder::insertOptions(OptionsCont& oc) {
44 72640 : insertDefaultAssignmentOptions("stationfinder", "Battery", oc);
45 72640 : oc.doRegister("device.stationfinder.rescueTime", new Option_String("1800", "TIME"));
46 72640 : oc.addDescription("device.stationfinder.rescueTime", "Battery", TL("Time to wait for a rescue vehicle on the road side when the battery is empty"));
47 36320 : oc.doRegister("device.stationfinder.reserveFactor", new Option_Float(1.1));
48 72640 : oc.addDescription("device.stationfinder.reserveFactor", "Battery", TL("Additional battery buffer for unexpected traffic situation when estimating the battery need"));
49 36320 : oc.doRegister("device.stationfinder.emptyThreshold", new Option_Float(5));
50 72640 : oc.addDescription("device.stationfinder.emptyThreshold", "Battery", TL("Battery percentage to go into rescue mode"));
51 72640 : oc.doRegister("device.stationfinder.radius", new Option_String("180", "TIME"));
52 72640 : oc.addDescription("device.stationfinder.radius", "Battery", TL("Search radius in travel time seconds"));
53 72640 : oc.doRegister("device.stationfinder.repeat", new Option_String("60", "TIME"));
54 72640 : oc.addDescription("device.stationfinder.repeat", "Battery", TL("When to trigger a new search if no station has been found"));
55 36320 : oc.doRegister("device.stationfinder.maxChargePower", new Option_Float(1000.));
56 72640 : oc.addDescription("device.stationfinder.maxChargePower", "Battery", TL("The maximum charging speed of the vehicle battery"));
57 72640 : oc.doRegister("device.stationfinder.chargeType", new Option_String("charging"));
58 72640 : oc.addDescription("device.stationfinder.chargeType", "Battery", TL("Type of energy transfer"));
59 72640 : oc.doRegister("device.stationfinder.waitForCharge", new Option_String("600", "TIME"));
60 72640 : oc.addDescription("device.stationfinder.waitForCharge", "Battery", TL("After this waiting time vehicle searches for a new station when the initial one is blocked"));
61 36320 : }
62 :
63 :
64 : void
65 4658946 : MSDevice_StationFinder::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
66 4658946 : OptionsCont& oc = OptionsCont::getOptions();
67 9317892 : if (equippedByDefaultAssignmentOptions(oc, "stationfinder", v, false)) {
68 16 : into.push_back(new MSDevice_StationFinder(v));
69 : }
70 4658946 : }
71 :
72 :
73 : // ---------------------------------------------------------------------------
74 : // MSDevice_StationFinder-methods
75 : // ---------------------------------------------------------------------------
76 16 : MSDevice_StationFinder::MSDevice_StationFinder(SUMOVehicle& holder)
77 16 : : MSVehicleDevice(holder, "stationfinder_" + holder.getID()),
78 16 : myBattery(nullptr), myChargingStation(nullptr) {
79 16 : OptionsCont& oc = OptionsCont::getOptions();
80 16 : myReserveFactor = getFloatParam(holder, oc, "stationfinder.reserveFactor", 1.1);
81 16 : }
82 :
83 :
84 32 : MSDevice_StationFinder::~MSDevice_StationFinder() {
85 32 : }
86 :
87 :
88 : bool
89 5956 : MSDevice_StationFinder::notifyMove(SUMOTrafficObject& /*veh*/, double /*oldPos*/, double /*newPos*/, double /*newSpeed*/) {
90 5956 : if (myChargingStation == nullptr) {
91 5552 : const SUMOTime now = SIMSTEP;
92 5552 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = MSRoutingEngine::getRouterTT(myHolder.getRNGIndex(), myHolder.getVClass());
93 5552 : const ConstMSEdgeVector& route = myHolder.getRoute().getEdges();
94 5552 : const ConstMSEdgeVector remainingRoute(route.begin() + myHolder.getRoutePosition(), route.end());
95 5552 : const double remainingTime = router.recomputeCosts(remainingRoute, &myHolder, now);
96 5552 : if (now > myHolder.getDeparture()) {
97 5552 : double expectedConsumption = myBattery->getTotalConsumption() / STEPS2TIME(now - myHolder.getDeparture()) * remainingTime;
98 5552 : if (expectedConsumption > myBattery->getActualBatteryCapacity() * myReserveFactor) {
99 4 : const MSEdge* const start = myHolder.getEdge();
100 : double minTime = std::numeric_limits<double>::max();
101 : MSChargingStation* minStation = nullptr;
102 : ConstMSEdgeVector minRoute;
103 : // TODO do some form of bulk routing here
104 24 : for (const auto& stop : MSNet::getInstance()->getStoppingPlaces(SUMO_TAG_CHARGING_STATION)) {
105 : ConstMSEdgeVector routeTo;
106 20 : const MSEdge* const csEdge = &stop.second->getLane().getEdge();
107 20 : if (router.compute(start, myHolder.getPositionOnLane(), csEdge, stop.second->getBeginLanePosition(), &myHolder, now, routeTo)) {
108 : ConstMSEdgeVector routeFrom;
109 20 : if (csEdge == route.back() || router.compute(start, &stop.second->getLane().getEdge(), &myHolder, now, routeFrom)) {
110 20 : if (csEdge != route.back()) {
111 20 : routeTo.insert(routeTo.end(), routeFrom.begin() + 1, routeFrom.end());
112 : }
113 20 : const double time = router.recomputeCosts(routeTo, &myHolder, now);
114 20 : if (time < minTime) {
115 : minTime = time;
116 4 : minStation = static_cast<MSChargingStation*>(stop.second);
117 4 : minRoute = routeTo;
118 : }
119 : }
120 : }
121 : }
122 4 : if (minStation != nullptr) {
123 4 : if (myHolder.hasStops()) {
124 0 : WRITE_WARNINGF(TL("Rerouting using station finder removes all upcoming stops for vehicle '%'."), myHolder.getID());
125 : }
126 4 : myHolder.replaceRouteEdges(minRoute, minTime, 0., getID());
127 4 : myChargingStation = minStation;
128 4 : SUMOVehicleParameter::Stop stopPar;
129 : stopPar.chargingStation = minStation->getID();
130 4 : stopPar.lane = minStation->getLane().getID();
131 4 : stopPar.endPos = minStation->getEndLanePosition();
132 4 : stopPar.duration = TIME2STEPS(expectedConsumption / minStation->getChargingPower(false) * myReserveFactor);
133 : std::string errorMsg;
134 4 : if (!myHolder.addStop(stopPar, errorMsg)) {
135 0 : WRITE_ERROR(errorMsg);
136 4 : } else if (errorMsg != "") {
137 0 : WRITE_WARNING(errorMsg);
138 : }
139 4 : }
140 : }
141 : }
142 : }
143 5956 : return true;
144 : }
145 :
146 :
147 : bool
148 0 : MSDevice_StationFinder::notifyIdle(SUMOTrafficObject& /*veh*/) {
149 0 : return true;
150 : }
151 :
152 :
153 : void
154 0 : MSDevice_StationFinder::notifyMoveInternal(const SUMOTrafficObject& /*veh*/,
155 : const double /* frontOnLane */,
156 : const double /* timeOnLane */,
157 : const double /* meanSpeedFrontOnLane */,
158 : const double /* meanSpeedVehicleOnLane */,
159 : const double /* travelledDistanceFrontOnLane */,
160 : const double /* travelledDistanceVehicleOnLane */,
161 : const double /* meanLengthOnLane */) {
162 :
163 : // called by meso (see MSMeanData_Emissions::MSLaneMeanDataValues::notifyMoveInternal)
164 0 : }
165 :
166 :
167 :
168 : void
169 16 : MSDevice_StationFinder::generateOutput(OutputDevice* tripinfoOut) const {
170 : if (tripinfoOut != nullptr) {
171 : }
172 16 : }
173 :
174 :
175 : /****************************************************************************/
|