Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 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 MSStopOut.cpp
15 : /// @author Jakob Erdmann
16 : /// @date Wed, 21.12.2016
17 : ///
18 : // Ouput information about planned vehicle stop
19 : /****************************************************************************/
20 : #include <config.h>
21 :
22 : #include <utils/vehicle/SUMOVehicle.h>
23 : #include <utils/options/OptionsCont.h>
24 : #include <utils/common/MsgHandler.h>
25 : #include <microsim/MSNet.h>
26 : #include <microsim/MSEdge.h>
27 : #include <microsim/MSLane.h>
28 : #include <microsim/MSStop.h>
29 : #include <microsim/MSGlobals.h>
30 : #include <microsim/MSParkingArea.h>
31 : #include <microsim/MSStoppingPlace.h>
32 : #include <microsim/MSVehicleType.h>
33 : #include <microsim/trigger/MSChargingStation.h>
34 : #include <microsim/trigger/MSOverheadWire.h>
35 : #include "MSStopOut.h"
36 :
37 :
38 : // ---------------------------------------------------------------------------
39 : // static initialisation methods
40 : // ---------------------------------------------------------------------------
41 : MSStopOut* MSStopOut::myInstance = nullptr;
42 :
43 : void
44 41446 : MSStopOut::init() {
45 82892 : if (OptionsCont::getOptions().isSet("stop-output")) {
46 1457 : myInstance = new MSStopOut(OutputDevice::getDeviceByOption("stop-output"));
47 : }
48 41446 : }
49 :
50 : void
51 41448 : MSStopOut::cleanup() {
52 41448 : delete myInstance;
53 41448 : myInstance = nullptr;
54 41448 : }
55 :
56 : // ===========================================================================
57 : // method definitions
58 : // ===========================================================================
59 1457 : MSStopOut::MSStopOut(OutputDevice& dev) :
60 1457 : myDevice(dev) {
61 1457 : }
62 :
63 2900 : MSStopOut::~MSStopOut() {}
64 :
65 :
66 : void
67 5904 : MSStopOut::stopBlocked(const SUMOVehicle* veh, SUMOTime time) {
68 : assert(veh != nullptr);
69 : if (myStopped.count(veh) == 0) {
70 170 : myStopped.emplace(veh, StopInfo(-time, -1, -1));
71 : }
72 5904 : }
73 :
74 :
75 : void
76 17 : MSStopOut::stopNotStarted(const SUMOVehicle* veh) {
77 : assert(veh != nullptr);
78 : myStopped.erase(veh);
79 17 : }
80 :
81 :
82 : void
83 6367 : MSStopOut::stopStarted(const SUMOVehicle* veh, int numPersons, int numContainers, SUMOTime time) {
84 : assert(veh != nullptr);
85 : if (myStopped.count(veh) == 0) {
86 6201 : myStopped.emplace(veh, StopInfo(0, numPersons, numContainers));
87 : } else {
88 : MSStopOut::StopInfo& info = myStopped.find(veh)->second;
89 166 : info.blockTime += time;
90 166 : info.initialNumPersons = numPersons;
91 166 : info.initialNumContainers = numContainers;
92 : }
93 6367 : }
94 :
95 :
96 : void
97 2721 : MSStopOut::loadedPersons(const SUMOVehicle* veh, int n) {
98 : // ignore triggered vehicles
99 2721 : if (veh->hasDeparted()) {
100 : if (myStopped.count(veh) == 0) {
101 0 : WRITE_WARNINGF(TL("Vehicle '%' loads persons on edge '%', time=% without starting the stop."),
102 : veh->getID(), veh->getEdge()->getID(), time2string(SIMSTEP));
103 : } else {
104 2660 : myStopped.find(veh)->second.loadedPersons += n;
105 : }
106 : }
107 2721 : }
108 :
109 :
110 : void
111 1823 : MSStopOut::unloadedPersons(const SUMOVehicle* veh, int n) {
112 : if (myStopped.count(veh) == 0) {
113 0 : WRITE_WARNINGF(TL("Vehicle '%' unloads persons on edge '%', time=% without starting the stop."),
114 : veh->getID(), veh->getEdge()->getID(), time2string(SIMSTEP));
115 : } else {
116 1823 : myStopped.find(veh)->second.unloadedPersons += n;
117 : }
118 1823 : }
119 :
120 :
121 : void
122 187 : MSStopOut::loadedContainers(const SUMOVehicle* veh, int n) {
123 : // ignore triggered vehicles
124 187 : if (veh->hasDeparted()) {
125 : if (myStopped.count(veh) == 0) {
126 0 : WRITE_WARNINGF(TL("Vehicle '%' loads container on edge '%', time=% without starting the stop."),
127 : veh->getID(), veh->getEdge()->getID(), time2string(SIMSTEP));
128 : } else {
129 173 : myStopped.find(veh)->second.loadedContainers += n;
130 : }
131 : }
132 187 : }
133 :
134 :
135 : void
136 138 : MSStopOut::unloadedContainers(const SUMOVehicle* veh, int n) {
137 : if (myStopped.count(veh) == 0) {
138 0 : WRITE_WARNINGF(TL("Vehicle '%' unloads container on edge '%', time=% without starting the stop."),
139 : veh->getID(), veh->getEdge()->getID(), time2string(SIMSTEP));
140 : } else {
141 138 : myStopped.find(veh)->second.unloadedContainers += n;
142 : }
143 138 : }
144 :
145 :
146 : void
147 6187 : MSStopOut::stopEnded(const SUMOVehicle* veh, const MSStop& stop, bool simEnd) {
148 : assert(veh != nullptr);
149 : if (myStopped.count(veh) == 0) {
150 3 : WRITE_WARNINGF(TL("Vehicle '%' ends stop on edge '%', time=% without entering the stop."),
151 : veh->getID(), veh->getEdge()->getID(), time2string(SIMSTEP));
152 1 : return;
153 : }
154 : const SUMOVehicleParameter::Stop& pars = stop.pars;
155 : const StopInfo& si = myStopped.find(veh)->second;
156 6186 : double delay = -1;
157 6186 : double arrivalDelay = -1;
158 6186 : if (pars.until >= 0 && !simEnd) {
159 1680 : delay = STEPS2TIME(SIMSTEP - pars.until);
160 : }
161 6186 : if (pars.arrival >= 0) {
162 245 : arrivalDelay = STEPS2TIME(pars.started - pars.arrival);
163 : }
164 6186 : myDevice.openTag("stopinfo");
165 6186 : myDevice.writeAttr(SUMO_ATTR_ID, veh->getID());
166 6186 : myDevice.writeAttr(SUMO_ATTR_TYPE, veh->getVehicleType().getID());
167 6186 : if (MSGlobals::gUseMesoSim) {
168 967 : myDevice.writeAttr(SUMO_ATTR_EDGE, veh->getEdge()->getID());
169 : } else {
170 5219 : myDevice.writeAttr(SUMO_ATTR_LANE, stop.lane->getID());
171 : }
172 6186 : myDevice.writeAttr(SUMO_ATTR_POSITION, veh->getPositionOnLane());
173 6186 : myDevice.writeAttr(SUMO_ATTR_PARKING, pars.parking);
174 6186 : myDevice.writeAttr(SUMO_ATTR_STARTED, time2string(pars.started));
175 6186 : myDevice.writeAttr(SUMO_ATTR_ENDED, simEnd ? "-1" : time2string(SIMSTEP));
176 6186 : if (pars.until >= 0) {
177 1680 : myDevice.writeAttr("delay", delay);
178 : }
179 6186 : if (pars.arrival >= 0) {
180 245 : myDevice.writeAttr(SUMO_ATTR_ARRIVALDELAY, arrivalDelay);
181 : }
182 6186 : if (pars.busstop != "") {
183 2536 : myDevice.writeAttr(SUMO_ATTR_BUS_STOP, pars.busstop);
184 : }
185 6186 : if (pars.containerstop != "") {
186 16 : myDevice.writeAttr(SUMO_ATTR_CONTAINER_STOP, pars.containerstop);
187 : }
188 6186 : if (pars.parkingarea != "") {
189 1923 : myDevice.writeAttr(SUMO_ATTR_PARKING_AREA, pars.parkingarea);
190 : }
191 6186 : if (pars.chargingStation != "") {
192 82 : myDevice.writeAttr(SUMO_ATTR_CHARGING_STATION, pars.chargingStation);
193 : }
194 6186 : if (pars.overheadWireSegment != "") {
195 0 : myDevice.writeAttr(SUMO_ATTR_OVERHEAD_WIRE_SEGMENT, pars.overheadWireSegment);
196 : }
197 6186 : if (pars.tripId != "") {
198 30 : myDevice.writeAttr(SUMO_ATTR_TRIP_ID, pars.tripId);
199 : }
200 6186 : if (pars.line != "") {
201 10 : myDevice.writeAttr(SUMO_ATTR_LINE, pars.line);
202 : }
203 6186 : if (pars.split != "") {
204 43 : myDevice.writeAttr(SUMO_ATTR_SPLIT, pars.split);
205 : }
206 6186 : if (MSGlobals::gUseStopEnded) {
207 30 : myDevice.writeAttr(SUMO_ATTR_USED_ENDED, pars.ended >= 0);
208 : }
209 6186 : myDevice.writeAttr("initialPersons", si.initialNumPersons);
210 6186 : myDevice.writeAttr("loadedPersons", si.loadedPersons);
211 6186 : myDevice.writeAttr("unloadedPersons", si.unloadedPersons);
212 6186 : myDevice.writeAttr("initialContainers", si.initialNumContainers);
213 6186 : myDevice.writeAttr("loadedContainers", si.loadedContainers);
214 6186 : myDevice.writeAttr("unloadedContainers", si.unloadedContainers);
215 6186 : myDevice.writeAttr("blockedDuration", time2string(si.blockTime));
216 :
217 6186 : if (stop.pars.speed > 0) {
218 68 : if (stop.waypointWithStop) {
219 12 : myDevice.writeAttr(SUMO_ATTR_STATE, "waypointStopped");
220 : } else {
221 56 : myDevice.writeAttr(SUMO_ATTR_STATE, "waypoint");
222 : }
223 6118 : } else if (stop.skipOnDemand) {
224 38 : myDevice.writeAttr(SUMO_ATTR_STATE, "skippedOnDemand");
225 : }
226 :
227 12372 : myDevice.closeTag();
228 : myStopped.erase(veh);
229 : }
230 :
231 :
232 : void
233 121 : MSStopOut::generateOutputForUnfinished() {
234 1380 : while (!myStopped.empty()) {
235 : const auto& item = *myStopped.begin();
236 1259 : const SUMOVehicle* veh = item.first;
237 : assert(veh->isStopped());
238 1259 : const MSStop& stop = veh->getNextStop();
239 : // erases item from myStopped
240 1259 : stopEnded(veh, stop, true);
241 : }
242 121 : }
243 :
244 :
245 : /****************************************************************************/
|