Line data Source code
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 : /****************************************************************************/
14 : /// @file MSChargingStation.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Tamas Kurczveil
17 : /// @author Pablo Alvarez Lopez
18 : /// @author Mirko Barthauer
19 : /// @date 20-12-13
20 : ///
21 : // Charging Station for Electric vehicles
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <cassert>
26 : #include <utils/common/StringUtils.h>
27 : #include <utils/vehicle/SUMOVehicle.h>
28 : #include <microsim/MSParkingArea.h>
29 : #include <microsim/MSVehicleType.h>
30 : #include <microsim/MSStoppingPlace.h>
31 : #include <microsim/devices/MSDevice_Battery.h>
32 : #include <microsim/MSNet.h>
33 : #include "MSChargingStation.h"
34 :
35 :
36 : // ===========================================================================
37 : // member method definitions
38 : // ===========================================================================
39 :
40 12157 : MSChargingStation::MSChargingStation(const std::string& chargingStationID, MSLane& lane, double startPos, double endPos,
41 : const std::string& name, double chargingPower, double efficency, bool chargeInTransit,
42 12157 : SUMOTime chargeDelay, const std::string& chargeType, SUMOTime waitingTime) :
43 12157 : MSStoppingPlace(chargingStationID, SUMO_TAG_CHARGING_STATION, std::vector<std::string>(), lane, startPos, endPos, name),
44 24314 : myChargeInTransit(chargeInTransit), myChargeType(stringToChargeType(chargeType)) {
45 12157 : if (chargingPower < 0) {
46 0 : WRITE_WARNING(TLF("Attribute % for chargingStation with ID='%' is invalid (%).", toString(SUMO_ATTR_CHARGINGPOWER), getID(), toString(chargingPower)))
47 : } else {
48 12157 : myChargingPower = chargingPower;
49 : }
50 12157 : if (efficency < 0 || efficency > 1) {
51 6 : WRITE_WARNING(TLF("Attribute % for chargingStation with ID='%' is invalid (%).", toString(SUMO_ATTR_EFFICIENCY), getID(), toString(efficency)))
52 : } else {
53 12155 : myEfficiency = efficency;
54 : }
55 12157 : if (chargeDelay < 0) {
56 0 : WRITE_WARNING(TLF("Attribute % for chargingStation with ID='%' is invalid (%).", toString(SUMO_ATTR_CHARGEDELAY), getID(), toString(chargeDelay)))
57 : } else {
58 12157 : myChargeDelay = chargeDelay;
59 : }
60 12157 : if (waitingTime < 0) {
61 0 : WRITE_WARNING(TLF("Attribute % for chargingStation with ID='%' is invalid (%).", toString(SUMO_ATTR_WAITINGTIME), getID(), toString(waitingTime)))
62 : } else {
63 12157 : myWaitingTime = waitingTime;
64 : }
65 12157 : if (getBeginLanePosition() > getEndLanePosition()) {
66 0 : WRITE_WARNING(TLF("ChargingStation with ID='%' doesn't have a valid position (% < %).", getID(), toString(getBeginLanePosition()), toString(getEndLanePosition())));
67 : }
68 12157 : }
69 :
70 :
71 11 : MSChargingStation::MSChargingStation(const std::string& chargingStationID, const MSParkingArea* parkingArea, const std::string& name, double chargingPower,
72 11 : double efficency, bool chargeInTransit, SUMOTime chargeDelay, const std::string& chargeType, SUMOTime waitingTime) :
73 11 : MSChargingStation(chargingStationID, const_cast<MSLane&>(parkingArea->getLane()), parkingArea->getBeginLanePosition(), parkingArea->getEndLanePosition(),
74 22 : name, chargingPower, efficency, chargeInTransit, chargeDelay, chargeType, waitingTime) {
75 11 : myParkingArea = parkingArea;
76 11 : }
77 :
78 :
79 23948 : MSChargingStation::~MSChargingStation() {
80 36070 : }
81 :
82 :
83 : double
84 78563 : MSChargingStation::getChargingPower(bool usingFuel) const {
85 78563 : if (usingFuel) {
86 1968 : return myChargingPower;
87 : } else {
88 : // Convert from [Ws] to [Wh] (3600s / 1h):
89 76595 : return myChargingPower / 3600;
90 : }
91 : }
92 :
93 :
94 : double
95 78225 : MSChargingStation::getEfficency() const {
96 78225 : return myEfficiency;
97 : }
98 :
99 :
100 : bool
101 81225 : MSChargingStation::getChargeInTransit() const {
102 81225 : return myChargeInTransit;
103 : }
104 :
105 :
106 : SUMOTime
107 78423 : MSChargingStation::getChargeDelay() const {
108 78423 : return myChargeDelay;
109 : }
110 :
111 :
112 : MSChargingStation::ChargeType
113 78367 : MSChargingStation::getChargeType() const {
114 78367 : return myChargeType;
115 : }
116 :
117 :
118 : SUMOTime
119 0 : MSChargingStation::getWaitingTime() const {
120 0 : return myWaitingTime;
121 : }
122 :
123 :
124 : const MSParkingArea*
125 84836 : MSChargingStation::getParkingArea() const {
126 84836 : return myParkingArea;
127 : }
128 :
129 :
130 : void
131 511 : MSChargingStation::setChargingPower(double chargingPower) {
132 511 : myChargingPower = chargingPower;
133 511 : }
134 :
135 :
136 : void
137 511 : MSChargingStation::setEfficiency(double efficiency) {
138 511 : myEfficiency = efficiency;
139 511 : }
140 :
141 :
142 : void
143 10 : MSChargingStation::setChargeDelay(SUMOTime delay) {
144 10 : myChargeDelay = delay;
145 10 : }
146 :
147 :
148 : void
149 10 : MSChargingStation::setChargeInTransit(bool value) {
150 10 : myChargeInTransit = value;
151 10 : }
152 :
153 :
154 : void
155 80113 : MSChargingStation::setChargingVehicle(bool value) {
156 80113 : myChargingVehicle = value;
157 80113 : }
158 :
159 :
160 : bool
161 0 : MSChargingStation::vehicleIsInside(const double position) const {
162 0 : if ((position >= getBeginLanePosition()) && (position <= getEndLanePosition())) {
163 : return true;
164 : } else {
165 0 : return false;
166 : }
167 : }
168 :
169 :
170 : bool
171 0 : MSChargingStation::isCharging() const {
172 0 : return myChargingVehicle;
173 : }
174 :
175 :
176 : void
177 77981 : MSChargingStation::addChargeValueForOutput(double WCharged, MSDevice_Battery* battery) {
178 155962 : if (!OptionsCont::getOptions().isSet("chargingstations-output")) {
179 1727 : return;
180 : }
181 76254 : std::string status = "";
182 76254 : if (battery->getChargingStartTime() > myChargeDelay) {
183 75558 : if (battery->getHolder().getSpeed() < battery->getStoppingThreshold()) {
184 : status = "chargingStopped";
185 647 : } else if (myChargeInTransit) {
186 : status = "chargingInTransit";
187 : } else {
188 : status = "noCharging";
189 : }
190 : } else {
191 696 : if (myChargeInTransit) {
192 : status = "waitingChargeInTransit";
193 341 : } else if (battery->getHolder().getSpeed() < battery->getStoppingThreshold()) {
194 : status = "waitingChargeStopped";
195 : } else {
196 : status = "noWaitingCharge";
197 : }
198 : }
199 : // update total charge
200 76254 : myTotalCharge += WCharged;
201 : // create charge row and insert it in myChargeValues
202 : const std::string vehID = battery->getHolder().getID();
203 : if (myChargeValues.count(vehID) == 0) {
204 357 : myChargedVehicles.push_back(vehID);
205 : }
206 76254 : Charge C(MSNet::getInstance()->getCurrentTimeStep(), vehID, battery->getHolder().getVehicleType().getID(),
207 : status, WCharged, battery->getActualBatteryCapacity(), battery->getMaximumBatteryCapacity(),
208 228762 : myChargingPower, myEfficiency, myTotalCharge);
209 76254 : myChargeValues[vehID].push_back(C);
210 76254 : }
211 :
212 :
213 : void
214 376 : MSChargingStation::writeChargingStationOutput(OutputDevice& output) {
215 376 : int chargingSteps = 0;
216 627 : for (const auto& item : myChargeValues) {
217 251 : chargingSteps += (int)item.second.size();
218 : }
219 376 : output.openTag(SUMO_TAG_CHARGING_STATION);
220 376 : output.writeAttr(SUMO_ATTR_ID, myID);
221 376 : output.writeAttr(SUMO_ATTR_TOTALENERGYCHARGED, myTotalCharge);
222 376 : output.writeAttr(SUMO_ATTR_CHARGINGSTEPS, chargingSteps);
223 : // start writing
224 376 : if (myChargeValues.size() > 0) {
225 377 : for (const std::string& vehID : myChargedVehicles) {
226 : int iStart = 0;
227 251 : const auto& chargeSteps = myChargeValues[vehID];
228 502 : while (iStart < (int)chargeSteps.size()) {
229 251 : int iEnd = iStart + 1;
230 251 : double charged = chargeSteps[iStart].WCharged;
231 71784 : while (iEnd < (int)chargeSteps.size() && chargeSteps[iEnd].timeStep == chargeSteps[iEnd - 1].timeStep + DELTA_T) {
232 71533 : charged += chargeSteps[iEnd].WCharged;
233 71533 : iEnd++;
234 : }
235 251 : writeVehicle(output, chargeSteps, iStart, iEnd, charged);
236 : iStart = iEnd;
237 : }
238 : }
239 : }
240 : // close charging station tag
241 376 : output.closeTag();
242 376 : }
243 :
244 :
245 : void
246 49444 : MSChargingStation::writeAggregatedChargingStationOutput(OutputDevice& output, bool includeUnfinished) {
247 : std::vector<std::string> terminatedChargers;
248 54122 : for (const auto& item : myChargeValues) {
249 : const Charge& lastCharge = item.second.back();
250 : // no charge during the last time step == has stopped charging
251 4678 : bool finished = lastCharge.timeStep < SIMSTEP - DELTA_T;
252 4678 : if (finished || includeUnfinished) {
253 106 : if (finished) {
254 102 : terminatedChargers.push_back(item.first);
255 : }
256 : // aggregate values
257 106 : double charged = 0.;
258 106 : double minPower = lastCharge.chargingPower;
259 106 : double maxPower = lastCharge.chargingPower;
260 106 : double minCharge = lastCharge.WCharged;
261 106 : double maxCharge = lastCharge.WCharged;
262 106 : double minEfficiency = lastCharge.chargingEfficiency;
263 106 : double maxEfficiency = lastCharge.chargingEfficiency;
264 4576 : for (const auto& charge : item.second) {
265 4470 : charged += charge.WCharged;
266 4470 : if (charge.chargingPower < minPower) {
267 0 : minPower = charge.chargingPower;
268 : }
269 4470 : if (charge.chargingPower > maxPower) {
270 0 : maxPower = charge.chargingPower;
271 : }
272 4470 : if (charge.WCharged < minCharge) {
273 32 : minCharge = charge.WCharged;
274 : }
275 4470 : if (charge.WCharged > maxCharge) {
276 3 : maxCharge = charge.WCharged;
277 : }
278 4470 : if (charge.chargingEfficiency < minEfficiency) {
279 0 : minEfficiency = charge.chargingEfficiency;
280 : }
281 4470 : if (charge.chargingEfficiency > maxEfficiency) {
282 0 : maxEfficiency = charge.chargingEfficiency;
283 : }
284 : }
285 : // actually write the data
286 106 : output.openTag(SUMO_TAG_CHARGING_EVENT);
287 106 : output.writeAttr(SUMO_ATTR_CHARGINGSTATIONID, myID);
288 106 : output.writeAttr(SUMO_ATTR_VEHICLE, lastCharge.vehicleID);
289 106 : output.writeAttr(SUMO_ATTR_TYPE, lastCharge.vehicleType);
290 106 : output.writeAttr(SUMO_ATTR_TOTALENERGYCHARGED_VEHICLE, charged);
291 106 : output.writeAttr(SUMO_ATTR_CHARGINGBEGIN, time2string(item.second.at(0).timeStep));
292 106 : if (finished) {
293 204 : output.writeAttr(SUMO_ATTR_CHARGINGEND, time2string(lastCharge.timeStep));
294 : }
295 106 : output.writeAttr(SUMO_ATTR_ACTUALBATTERYCAPACITY, lastCharge.actualBatteryCapacity);
296 106 : output.writeAttr(SUMO_ATTR_MAXIMUMBATTERYCAPACITY, lastCharge.maxBatteryCapacity);
297 106 : output.writeAttr(SUMO_ATTR_MINPOWER, minPower);
298 106 : output.writeAttr(SUMO_ATTR_MAXPOWER, maxPower);
299 106 : output.writeAttr(SUMO_ATTR_MINCHARGE, minCharge);
300 106 : output.writeAttr(SUMO_ATTR_MAXCHARGE, maxCharge);
301 106 : output.writeAttr(SUMO_ATTR_MINEFFICIENCY, minEfficiency);
302 106 : output.writeAttr(SUMO_ATTR_MAXEFFICIENCY, maxEfficiency);
303 212 : output.closeTag();
304 : }
305 : }
306 :
307 : // clear charging data of vehicles which terminated charging
308 49546 : for (auto vehID : terminatedChargers) {
309 : myChargeValues.erase(vehID);
310 : }
311 49444 : }
312 :
313 :
314 : void
315 251 : MSChargingStation::writeVehicle(OutputDevice& out, const std::vector<Charge>& chargeSteps, int iStart, int iEnd, double charged) {
316 251 : const Charge& first = chargeSteps[iStart];
317 251 : out.openTag(SUMO_TAG_VEHICLE);
318 251 : out.writeAttr(SUMO_ATTR_ID, first.vehicleID);
319 251 : out.writeAttr(SUMO_ATTR_TYPE, first.vehicleType);
320 251 : out.writeAttr(SUMO_ATTR_TOTALENERGYCHARGED_VEHICLE, charged);
321 251 : out.writeAttr(SUMO_ATTR_CHARGINGBEGIN, time2string(first.timeStep));
322 251 : out.writeAttr(SUMO_ATTR_CHARGINGEND, time2string(chargeSteps[iEnd - 1].timeStep));
323 72035 : for (int i = iStart; i < iEnd; i++) {
324 71784 : const Charge& c = chargeSteps[i];
325 71784 : out.openTag(SUMO_TAG_STEP);
326 71784 : out.writeAttr(SUMO_ATTR_TIME, time2string(c.timeStep));
327 : // charge values
328 71784 : out.writeAttr(SUMO_ATTR_CHARGING_STATUS, c.status);
329 71784 : out.writeAttr(SUMO_ATTR_ENERGYCHARGED, c.WCharged);
330 71784 : out.writeAttr(SUMO_ATTR_PARTIALCHARGE, c.totalEnergyCharged);
331 : // charging values of charging station in this timestep
332 71784 : out.writeAttr(SUMO_ATTR_CHARGINGPOWER, c.chargingPower);
333 71784 : out.writeAttr(SUMO_ATTR_EFFICIENCY, c.chargingEfficiency);
334 : // battery status of vehicle
335 71784 : out.writeAttr(SUMO_ATTR_ACTUALBATTERYCAPACITY, c.actualBatteryCapacity);
336 71784 : out.writeAttr(SUMO_ATTR_MAXIMUMBATTERYCAPACITY, c.maxBatteryCapacity);
337 : // close tag timestep
338 143568 : out.closeTag();
339 : }
340 251 : out.closeTag();
341 251 : }
342 :
343 :
344 : /****************************************************************************/
|