Eclipse SUMO - Simulation of Urban MObility
MSDevice_ElecHybrid.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2002-2020 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 /****************************************************************************/
19 // A device ElecHybrid ===description here===
20 /****************************************************************************/
21 #include <config.h>
22 
27 #include <utils/common/SUMOTime.h>
29 #include <microsim/MSNet.h>
30 #include <microsim/MSLane.h>
31 #include <microsim/MSEdge.h>
32 #include <microsim/MSVehicle.h>
33 #include <microsim/MSGlobals.h>
34 #include <microsim/MSEdgeControl.h>
35 #include <mesosim/MEVehicle.h>
36 #include "MSDevice_Tripinfo.h"
37 #include "MSDevice_ElecHybrid.h"
38 
39 //due to strncmp
40 #include <string.h>
41 
42 //due to clock()
43 #include <ctime>
44 
45 // ===========================================================================
46 // method definitions
47 // ===========================================================================
48 // ---------------------------------------------------------------------------
49 // static initialisation methods
50 // ---------------------------------------------------------------------------
51 void
53  oc.addOptionSubTopic("ElecHybrid Device");
54  insertDefaultAssignmentOptions("elechybrid", "ElecHybrid Device", oc);
55 }
56 
57 
58 void
59 MSDevice_ElecHybrid::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
60  // Check if vehicle should get an 'elecHybrid' device.
62  if (equippedByDefaultAssignmentOptions(oc, "elechybrid", v, false)) {
63  // Yes, build the device.
64  // Fetch the battery capacity (if present) from the vehicle descriptor.
65  const SUMOVTypeParameter& typeParams = v.getVehicleType().getParameter();
66  const SUMOVehicleParameter& vehicleParams = v.getParameter();
67  double actualBatteryCapacity = 0;
68  std::string attrName = toString(SUMO_ATTR_ACTUALBATTERYCAPACITY);
69  if (vehicleParams.knowsParameter(attrName)) {
70  const std::string abc = vehicleParams.getParameter(attrName, "-1");
71  try {
72  actualBatteryCapacity = StringUtils::toDouble(abc);
73  } catch (...) {
74  WRITE_WARNING("Invalid value '" + abc + "'for vehicle parameter '" + attrName + "'. Using the default of " + std::to_string(actualBatteryCapacity));
75  }
76  } else {
77  if (typeParams.knowsParameter(attrName)) {
78  const std::string abc = typeParams.getParameter(attrName, "-1");
79  try {
80  actualBatteryCapacity = StringUtils::toDouble(abc);
81  WRITE_WARNING("Vehicle '" + v.getID() + "' does not provide vehicle parameter '" + attrName + "'. Using the vehicle type value of " + std::to_string(actualBatteryCapacity));
82  } catch (...) {
83  WRITE_WARNING("Invalid value '" + abc + "'for vehicle type parameter '" + attrName + "'. Using the default of " + std::to_string(actualBatteryCapacity));
84  }
85  } else {
86  WRITE_WARNING("Vehicle '" + v.getID() + "' does not provide vehicle or vehicle type parameter '" + attrName + "'. Using the default of " + std::to_string(actualBatteryCapacity));
87  }
88  }
89 
90  // obtain maximumBatteryCapacity
91  double maximumBatteryCapacity = 0;
93  if (typeParams.knowsParameter(attrName)) {
94  const std::string mbc = typeParams.getParameter(attrName, "-1");
95  try {
96  maximumBatteryCapacity = StringUtils::toDouble(mbc);
97  } catch (...) {
98  WRITE_WARNING("Invalid value '" + mbc + "'for vType parameter '" + attrName + "'");
99  }
100  } else {
101  WRITE_WARNING("Vehicle '" + v.getID() + "' is missing the vType parameter '" + attrName + "'. Using the default of " + std::to_string(maximumBatteryCapacity));
102  }
103 
104  // obtain overheadWireChargingPower
105  double overheadWireChargingPower = 0;
107  if (typeParams.knowsParameter(attrName)) {
108  const std::string ocp = typeParams.getParameter(attrName, "-1");
109  try {
110  overheadWireChargingPower = StringUtils::toDouble(ocp);
111  } catch (...) {
112  WRITE_WARNING("Invalid value '" + ocp + "'for vType parameter '" + attrName + "'");
113  }
114  } else {
115  WRITE_WARNING("Vehicle '" + v.getID() + "' is missing the vType parameter '" + attrName + "'. Using the default of " + std::to_string(overheadWireChargingPower));
116  }
117 
118  // get custom vType parameter using SUMOXMLDefinitions.cpp/.h
120  // const SUMOVTypeParameter& typeParams = v.getVehicleType().getParameter();
121  std::map<int, double> param;
132 
133  param[SUMO_ATTR_MAXIMUMPOWER] = typeParams.getDouble(toString(SUMO_ATTR_MAXIMUMPOWER), 100000.);
134 
135  // elecHybrid constructor
136  MSDevice_ElecHybrid* device = new MSDevice_ElecHybrid(v, "elecHybrid_" + v.getID(),
137  actualBatteryCapacity, maximumBatteryCapacity, overheadWireChargingPower, param);
138 
139  // Add device to vehicle
140  into.push_back(device);
141  }
142 }
143 
144 
145 // ---------------------------------------------------------------------------
146 // MSDevice_ElecHybrid-methods
147 // ---------------------------------------------------------------------------
149  const double actualBatteryCapacity, const double maximumBatteryCapacity, const double overheadWireChargingPower, const std::map<int, double>& param) :
150  MSVehicleDevice(holder, id),
151  myActualBatteryCapacity(0), // [actualBatteryCapacity <= maximumBatteryCapacity]
152  myMaximumBatteryCapacity(0), // [maximumBatteryCapacity >= 0]t
153  myOverheadWireChargingPower(0),
154  myParam(param),
155  myLastAngle(NAN),
156  myConsum(0),
157  myBatteryDischargedLogic(false),
158  myCharging(false), // Initially vehicle don't charge
159  myEnergyCharged(0), // Initially the energy charged is zero
160  myCircuitCurrent(NAN), // Initially the current is unknown
161  myCircuitVoltage(NAN), // Initially the voltage is unknown as well
162  myMaxBatteryPower(NAN), // Initial maximum of the the battery energy during the simulation is unknown
163  myMinBatteryPower(NAN), // Initial minimum of the the battery energy during the simulation is unknown
164  myTotalPowerConsumed(0), // No energy spent yet
165  myTotalPowerRegenerated(0), // No energy regenerated
166  myTotalPowerWasted(0), // No energy wated on resistors
167  mySOCMin(0.005), // Minimum SOC of the battery
168  mySOCMax(0.980), // Maximum SOC of the battery
169  myActOverheadWireSegment(nullptr), // Initially the vehicle isn't under any overhead wire segment
170  myPreviousOverheadWireSegment(nullptr), // Initially the vehicle wasn't under any overhead wire segment
171  veh_elem(nullptr),
172  veh_pos_tail_elem(nullptr),
173  pos_veh_node(nullptr) {
174  if (maximumBatteryCapacity < 0) {
175  WRITE_WARNING("ElecHybrid builder: Vehicle '" + getID() + "' doesn't have a valid value for parameter " + toString(SUMO_ATTR_MAXIMUMBATTERYCAPACITY) + " (" + toString(maximumBatteryCapacity) + ").")
176  } else {
177  myMaximumBatteryCapacity = maximumBatteryCapacity;
178  }
179 
180  if (actualBatteryCapacity > maximumBatteryCapacity) {
181  WRITE_WARNING("ElecHybrid builder: Vehicle '" + getID() + "' has a " + toString(SUMO_ATTR_ACTUALBATTERYCAPACITY) + " (" + toString(actualBatteryCapacity) + ") greater than it's " + toString(SUMO_ATTR_MAXIMUMBATTERYCAPACITY) + " (" + toString(maximumBatteryCapacity) + "). A max battery capacity value will be asigned");
183  } else {
184  myActualBatteryCapacity = actualBatteryCapacity;
185  }
186 
187  if (overheadWireChargingPower < 0) {
188  WRITE_WARNING("ElecHybrid builder: Vehicle '" + getID() + "' doesn't have a valid value for parameter " + toString(SUMO_ATTR_OVERHEADWIRECHARGINGPOWER) + " (" + toString(overheadWireChargingPower) + ").")
189  } else {
190  myOverheadWireChargingPower = overheadWireChargingPower;
191  }
192 
204 }
205 
207 }
208 
209 bool
210 MSDevice_ElecHybrid::notifyMove(SUMOTrafficObject& tObject, double /* oldPos */, double /* newPos */, double /* newSpeed */) {
211  if (!tObject.isVehicle()) {
212  return false;
213  }
214  SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
215  // Do not compute the current consumption here anymore:
216  // myConsum is (non-systematically, we agree) set in MSVehicle so that the vehicle `vNext` value can
217  // be influenced by the maximum traction power of the vehicle (i.e. installing a 80 kWh powertrain will
218  // limit the acceleration regardless of the acceleration specified in vehicleType params, in case that
219  // the vehicleType acceleration is too high).
220  //
221  // myParam[SUMO_ATTR_ANGLE] = myLastAngle == std::numeric_limits<double>::infinity() ? 0. : GeomHelper::angleDiff(myLastAngle, veh.getAngle());
222  // myConsum = PollutantsInterface::getEnergyHelper().compute(0, PollutantsInterface::ELEC, veh.getSpeed(), veh.getAcceleration(), veh.getSlope(), &myParam);
223  assert(!ISNAN(myConsum));
224 
225  // is battery pack discharged (from previous timestep)
228  } else {
229  myBatteryDischargedLogic = false;
230  }
231 
232  /* If baterry is discharged we will force the vehicle to slowly come to
233  a halt (freewheel motion). It could still happen that some energy will
234  be recovered in later steps due to regenerative braking. */
235  if (isBatteryDischarged()) {
236  std::vector<std::pair<SUMOTime, double> > speedTimeLine;
240  double accel = acceleration(veh, 0, veh.getSpeed()); // or use veh.getAcceleration() method???
241  const double nextSpeed = MAX2(0., veh.getSpeed() + ACCEL2SPEED(accel));
242  speedTimeLine.push_back(
243  std::make_pair(
244  MSNet::getInstance()->getCurrentTimeStep(),
245  veh.getSpeed()));
246  speedTimeLine.push_back(
247  std::make_pair(
248  MSNet::getInstance()->getCurrentTimeStep() + DELTA_T,
249  nextSpeed));
250 
251  static_cast<MSVehicle*>(&veh)->getInfluencer().setSpeedTimeLine(speedTimeLine);
252  }
253 
254  /* Check if there is an overhead wire either over the lane where the vehicle is or over a
255  neighbouring lanes. This check has to be performed at every simulation step as the
256  overhead wires for trolleybuses will typically end at a bus stop that is located somewhere
257  in the middle of the lane. */
258  std::string overheadWireSegmentID = MSNet::getInstance()->getStoppingPlaceID(veh.getLane(), veh.getPositionOnLane(), SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
259 
260  //check overhead line on the left neighbouring lane
261  if (overheadWireSegmentID == "" && veh.getEdge()->leftLane(veh.getLane()) != nullptr) {
263  }
264  //check overhead line on the right neighbouring lane
265  if (overheadWireSegmentID == "" && veh.getEdge()->rightLane(veh.getLane()) != nullptr) {
267  }
268 
269  /* Store the amount of power that could not be recuperated. */
270  double powerWasted = 0.0;
271  /* If vehicle has access to an overhead wire (including the installation on neighbouring lanes) */
272  if (overheadWireSegmentID != "") {
273  /* Update the actual overhead wire segment of this device */
275  static_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(overheadWireSegmentID, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
276  /* Store the traction substation of the actual overhead wire segment */
278 
279  /* Disable charging from previous (not the actual) overhead wire segment.
280  REASON:
281  If there is no gap between two different overhead wire segments that are
282  places on the same lane, the vehicle switches from the one segment to another
283  in one timestep. */
285  if (myPreviousOverheadWireSegment != nullptr) {
286  /* Remove the vehicle from the list of vehicles powered by the previous segment. */
289  if (ts != nullptr) {
291  ts->eraseVehicle(this);
292  }
293  }
294  /* Add the vehicle reference to the current segment. */
296  if (actualSubstation != nullptr) {
297  actualSubstation->increaseElecHybridCount();
298  actualSubstation->addVehicle(this);
299  }
300  }
301 
302  /* Do we simulate the behaviour of the overhead wire electric circuit? */
304 #ifdef HAVE_EIGEN
306  /* Circuit update due to vehicle movement:
307  Delete vehicle resistor element, vehicle resistor nodes and vehicle resistor
308  tails in the circuit used in the previous timestep. */
310 
311  /* Add the vehicle to the circuit in case that there is a substation that provides
312  power to it. */
313  if (actualSubstation != nullptr) {
314  /* Add a resistor (current source in the future?) representing trolleybus
315  vehicle to the circuit.
316  pos/neg_veh_node elements
317  [0] .... vehicle_resistor
318  [1] .... leading resistor
319  [2] .... tail resistor pos/neg_tail_vehID
320  */
321 
322  // pos_veh_node and veh_elem shoud be NULL
323  if (pos_veh_node != nullptr || veh_elem != nullptr) {
324  WRITE_WARNING("pos_veh_node or neg_veh_node or veh_elem is not NULL (and they shoud be at the beginning of adding elecHybrid to the circuit)");
325  }
326 
327  // create pos and veh_elem
329  pos_veh_node = owc->addNode("pos_" + veh.getID());
330  assert(pos_veh_node != nullptr);
332  veh_elem = owc->addElement("resistance_" + veh.getID(), 10,
333  pos_veh_node, owc->getNode("negNode_ground"),
334  Element::ElementType::CURRENT_SOURCE_traction_wire);
335 
336  // Connect vehicle to an existing overhead wire segment = add elecHybridVehicle to the myActOverheadWireSegment circuit
337  // Find pos resistor element of the actual overhead line section and their end nodes
338  Element* element_pos = owc->getElement("pos_" + myActOverheadWireSegment->getID());
339  Node* node_pos = element_pos->getNegNode();
340  double resistance = element_pos->getResistance();
341 
342  /* Find the right position of the vehicle at the overhead line.
343  We start the while loop at the end of the actual overhead line section and go against the direction of vehicle movement.
344  The decision rule is based on the resistance value:
345  * from the vehicle position to the end of lane,
346  * sum of resistance of elements (going from the end of ovehead line section in the contrary direction).
347  */
348  // while (resistance < (veh.getLane()->getLength() - veh.getPositionOnLane())*WIRE_RESISTIVITY) {
349  // Immprovement: the relative complementary position of the vehicle on the vehicle's lane to the segment's lane (may be neigboring or the same as the vehicle's one)
350  double relativeComplementaryPosOnSegment =
352  (veh.getPositionOnLane() / veh.getLane()->getLength()));
353  while (resistance < relativeComplementaryPosOnSegment * WIRE_RESISTIVITY) {
354  node_pos = element_pos->getPosNode();
355  element_pos = node_pos->getElements()->at(2);
356  resistance += element_pos->getResistance();
357  if (strncmp(element_pos->getName().c_str(), "pos_tail_", 9) != 0) {
358  WRITE_WARNING("splitting element is not 'pos_tail_XXX'")
359  }
360  }
361 
362  node_pos = element_pos->getPosNode();
363  //resistance of vehicle tail nodes
364  resistance -= relativeComplementaryPosOnSegment * WIRE_RESISTIVITY;
365 
366  /* dividing element_pos
367  before: |node_pos|---------------------------------------------|element_pos|----
368  after: |node_pos|----|veh_pos_tail_elem|----|pos_veh_node|----|element_pos|----
369  */
370  element_pos->setPosNode(pos_veh_node);
371  node_pos->eraseElement(element_pos);
372  pos_veh_node->addElement(element_pos);
373 
374  veh_pos_tail_elem = owc->addElement("pos_tail_" + veh.getID(),
375  resistance, node_pos, pos_veh_node, Element::ElementType::RESISTOR_traction_wire);
376 
377  if (element_pos->getResistance() - resistance < 0) {
378  WRITE_WARNING("The resistivity of overhead wire segment connected to vehicle " + veh.getID() + " is < 0. Set to 1e-6.");
379  }
380 
381  element_pos->setResistance(element_pos->getResistance() - resistance);
382 
383 
384  // Set the power requirement to the consumption + charging power.
385  // RICE_TODO: The charging power id different when moving and when not
386  // RICE_TODO: The maximum battery capacity is not the upper charging limit, we need something like "charging_SOC_upper_bound" configurable, e.g. 0.9
389  } else {
391  }
392 
393  // No recuperation to overheadwire (only to the batterypack)
394  // RICE_TODO: This is an oversimplification, allow recuperation to the circuit, if possible.
395  if (veh_elem->getPowerWanted() < 0) {
396  powerWasted = veh_elem->getPowerWanted();
398  }
399 
400  double voltage = myCircuitVoltage;
404  if (voltage < 10 || voltage > 1500 || ISNAN(voltage)) {
405  voltage = actualSubstation->getSubstationVoltage();
406  }
407  // Initial value of current for the solver
408  double current = -(veh_elem->getPowerWanted() / voltage);
409  veh_elem->setCurrent(current);
410 
411  // Set the device as charging
412  myCharging = true;
413 
414  // And register the call to solver at the end of the simulation step
415  actualSubstation->addSolvingCirucitToEndOfTimestepEvents();
416  } else {
417  /*
418  No substation on this wire ...
419  */
420 
421  // Energy flowing to/from the battery pack [Wh] has to completely cover vehicle consumption.
423  // Update Battery charge
425  // No substation is connected to this segmenr and the charging output is therefore zero.
427  }
428 #else
429  WRITE_ERROR("Overhead wire solver is on, but the Eigen library has not been compiled in!")
430 #endif
431  } else {
432  /*
433  Faster approximaion without circuit solving at every simulation step.
434  */
435 
436  // First check that there is a traction substation connected to the overhead wire
437  double voltage = 0.0;
438  if (actualSubstation != nullptr) {
439  voltage = actualSubstation->getSubstationVoltage();
440  }
441 
442  // At this point the volate can be (a) NAN if the substation voltage was not specified,
443  // (b) 0 if no substation powers the current segment or if someone put its power to zero,
444  // (c) >0 if the substation can provide energy to the circuit.
445  if (voltage > 0.0) {
446  // There is a power source connected to this segment.
447  // Set the simplified power requirement to the consumption + charging power.
448  // RICE_TODO: The charging power id different when moving and when not
449  // RICE_TODO: The maximum battery capacity is not the upper charging limit, we need something like "charging_SOC_upper_bound" configurable, e.g. 0.9
450  double powerWanted = WATTHR2WATT(myConsum);
452  // Additional `myOverheadWireChargingPower` due to charging of battery pack
453  powerWanted += myOverheadWireChargingPower;
454  }
455 
456  // No recuperation to overhead wire (only to the batterypack)
457  // RICE_TODO: This is an oversimplification, allow recuperation to the circuit, if possible.
458  if (powerWanted < 0.0) {
459  powerWasted = -powerWanted;
460  powerWanted = 0.0;
461  }
462 
463  // Set the actual current and voltage of the global circuit
464  // RICE_TODO: Process the traction stataion current limiting here as well.
465  myCircuitCurrent = powerWanted / voltage;
466  myCircuitVoltage = voltage;
467 
468  // Calulate energy flowing to/from the battery in this step [Wh]
469  myEnergyCharged = WATT2WATTHR(powerWanted) - myConsum;
470  // Update battery charge
472  // Add the energy provided by the overhead wire segment to the output of the segment
474  } else {
475  /*
476  Overhead wire without a connected substation
477  */
478  // Energy for the powertrain is provided by the battery pack
480  // Update battery charge
482  // No energy was provided by the overhead wire segment
484  }
485  }
486  assert(myActOverheadWireSegment != nullptr);
488  } else {
489  /*
490  No overhead wires, no charging.
491  */
492 
493  // Disable charing flag
494  myCharging = false;
495 
496  // Invalidate the circuit voltage and current
497  myCircuitCurrent = NAN;
498  myCircuitVoltage = NAN;
499 
500  // Additional bookkeeping in case that the circuit solver is used
502 #ifdef HAVE_EIGEN
503  /*
504  Delete vehicle resistor element, vehicle resistor nodes and vehicle resistor tails
505  in the previous circuit (i.e. the circuit used in the previous timestep)
506  */
508 #else
509  WRITE_ERROR("Overhead wire solver is on, but the Eigen library has not been compiled in!")
510 #endif
511  }
512 
513  // Vehicle is not under an overhead wire
514  myActOverheadWireSegment = nullptr;
515 
516  // Remove the vehicle from overhead wire if it was under it in the previous step.
517  // This has to be called afer deleteVehicleFromCircuit() as the file uses myPreviousOverheadWire.
518  if (myPreviousOverheadWireSegment != nullptr) {
521  if (ts != nullptr) {
523  ts->eraseVehicle(this);
524  }
526  }
527 
528  // Energy for the powertrain is provided by the battery pack
530  // Update battery charge
532  }
533 
534  // Update the statistical values
537  }
540  }
541  if (myConsum > 0.0) {
543  } else {
545  }
546  myTotalPowerWasted += powerWasted;
547 
548  myLastAngle = veh.getAngle();
549  return true; // keep the device
550 }
551 
552 // Note: This is called solely in the mesoscopic mode to mimic the `notifyMove()` reminder
553 void
555  const SUMOTrafficObject& tObject,
556  const double frontOnLane,
557  const double timeOnLane,
558  const double meanSpeedFrontOnLane,
559  const double meanSpeedVehicleOnLane,
560  const double travelledDistanceFrontOnLane,
561  const double travelledDistanceVehicleOnLane,
562  const double meanLengthOnLane) {
563  UNUSED_PARAMETER(tObject);
564  UNUSED_PARAMETER(frontOnLane);
565  UNUSED_PARAMETER(timeOnLane);
566  UNUSED_PARAMETER(meanSpeedFrontOnLane);
567  UNUSED_PARAMETER(meanSpeedVehicleOnLane);
568  UNUSED_PARAMETER(travelledDistanceFrontOnLane);
569  UNUSED_PARAMETER(travelledDistanceVehicleOnLane);
570  UNUSED_PARAMETER(meanLengthOnLane);
571 }
572 
573 void
575  if (myPreviousOverheadWireSegment != nullptr) {
577  //check if all pointers to vehicle elements and nodes are not nullptr
578  if (veh_elem == nullptr || veh_pos_tail_elem == nullptr || pos_veh_node == nullptr) {
579  WRITE_ERROR("During deleting vehicle '" + veh.getID() + "' from circuit some init previous Nodes or Elements was not assigned.");
580  }
581  //check if pos_veh_node has 3 elements - they shoud be: veh_elem, veh_pos_tail_elem and an overhead line resistor element "ahead" of vehicle.
582  if (pos_veh_node->getElements()->size() != 3) {
583  WRITE_ERROR("During deleting vehicle '" + veh.getID() + "' from circuit the size of element-vector of pNode or nNode was not 3. It should be 3 by Jakub's opinion.");
584  }
585  //delete vehicle resistor element "veh_elem" in the previous circuit,
588  delete veh_elem;
589  veh_elem = nullptr;
590 
591  //eraising of tail elements (the element connected to the veh_node is afterthen only the ahead overhead line resistor element)
593 
594  if (pos_veh_node->getElements()->size() != 1) {
595  WRITE_ERROR("During deleting vehicle '" + veh.getID() + "' from circuit the size of element-vector of pNode or nNode was not 1. It should be 1 by Jakub's opinion.");
596  }
597 
598  // add the resistance value of veh_tail element to the resistance value of the ahead overhead line element
599  pos_veh_node->getElements()->front()->setResistance(pos_veh_node->getElements()->front()->getResistance() + veh_pos_tail_elem->getResistance());
600  //set PosNode of the ahead overhead line element to the posNode value of tail element
601  Element* aux = pos_veh_node->getElements()->front();
602  //set node = 3 operations
604  aux->getPosNode()->eraseElement(aux);
606 
607  // erase tail element from its PosNode
609  // delete veh_pos_tail_elem
611  delete veh_pos_tail_elem;
612  veh_pos_tail_elem = nullptr;
613 
614  //erase pos_veh_node
616  //modify id of other elements (the id of erasing element shoud be the greatest)
617  int lastId = myPreviousOverheadWireSegment->getCircuit()->getLastId() - 1;
618  if (pos_veh_node->getId() != lastId) {
619  Node* node_last = myPreviousOverheadWireSegment->getCircuit()->getNode(lastId);
620  if (node_last != nullptr) {
621  node_last->setId(pos_veh_node->getId());
622  } else {
624  if (elem_last != nullptr) {
625  elem_last->setId(pos_veh_node->getId());
626  } else {
627  WRITE_ERROR("The element or node with the last Id was not found in the circuit!");
628  }
629  }
630  }
632  delete pos_veh_node;
633  pos_veh_node = nullptr;
634  }
635  }
636 }
637 
638 bool
640  SUMOTrafficObject& tObject,
641  MSMoveReminder::Notification /* reason */,
642  const MSLane* /* enteredLane */) {
643  if (!tObject.isVehicle()) {
644  return false;
645  }
646 #ifdef ELECHYBRID_MESOSCOPIC_DEBUG
647  SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
648  std::cout << "device '" << getID() << "' notifyEnter: reason=" << reason << " currentEdge=" << veh.getEdge()->getID() << "\n";
649 #endif
650 
651  return true; // keep the device
652 }
653 
654 bool
656  SUMOTrafficObject& tObject,
657  double /*lastPos*/,
659  const MSLane* /* enteredLane */) {
660  if (!tObject.isVehicle()) {
661  return false;
662  }
663  SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
664 #ifdef ELECHYBRID_MESOSCOPIC_DEBUG
665  SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
666  std::cout << "device '" << getID() << "' notifyLeave: reason=" << reason << " currentEdge=" << veh.getEdge()->getID() << "\n";
667  SUMOVehicle* sumoVehicle = *veh;
669  MEVehicle& v = dynamic_cast<MEVehicle&>(veh);
670  std::cout << "***************** MESO - notifyLeave*** START ****************** '" << v.getID() << "' \n";
671  //TODO the second argument of getStoptime should change
672  std::cout << "getSpeed: '" << v.getSpeed() << "' | getAverageSpeed: '" << v.getAverageSpeed() << "' | getStoptime: '" << v.getStoptime(v.getSegment(), 0) << "' \n";
673  std::cout << "getStopEdges: '" << "' | getLastEntryTime: '" << v.getLastEntryTime() << "' | getBlockTimeSeconds: '" << v.getBlockTimeSeconds() << "' \n";
674  std::cout << "getWaitingTime: '" << v.getWaitingTime() << "' | getAccumulatedWaitingTime: '" << v.getAccumulatedWaitingTime() << "' | getLastEntryTimeSeconds: '" << v.getLastEntryTimeSeconds() << "' \n";
675  std::cout << "***************** MESO - notifyLeave*** END ****************** '" << v.getID() << "' \n";
676  }
677 #endif
678 
679  // RICE_CHECK: Are MSMoveReminders really sorted so that we can do `<`?
681  return true;
682  }
683 
685 #ifdef HAVE_EIGEN
686  // ------- *** ------- delete vehicle resistor element, vehicle resistor nodes and vehicle resistor tails in the previous circuit (circuit used in the previous timestep)------- *** -------
689  //TODORICE is MSDevice_ElecHybrid* erased from MSTractionSubstation?
690 #else
691  UNUSED_PARAMETER(veh);
692  WRITE_ERROR("Overhead wire solver is on, but the Eigen library has not been compiled in!")
693 #endif
694  }
695  // disable charging vehicle from overhead wire and segment and traction station
696  if (myPreviousOverheadWireSegment != nullptr) {
699  if (prevSubstation != nullptr) {
700  prevSubstation->decreaseElecHybridCount();
701  prevSubstation->eraseVehicle(this);
702  }
704  }
705  return true;
706 }
707 
708 void
710  const SumoXMLAttr paramKey,
711  const double lower,
712  const double upper) {
713  if (myParam.find(paramKey) == myParam.end() ||
714  myParam.find(paramKey)->second < lower ||
715  myParam.find(paramKey)->second > upper) {
716  WRITE_WARNING("ElecHybrid builder: Vehicle '" + getID() + "' doesn't have a valid value for parameter " + toString(paramKey) + " (" + toString(myParam[paramKey]) + ").");
718  }
719 }
720 
721 
722 void
724  if (tripinfoOut != nullptr) {
725  // Write the summary elecHybrid information into tripinfo output
726  tripinfoOut->openTag("elechybrid");
727  tripinfoOut->writeAttr("maxBatteryCharge", myMaxBatteryPower);
728  tripinfoOut->writeAttr("minBatteryCharge", myMinBatteryPower);
729  tripinfoOut->writeAttr("totalEnergyConsumed", myTotalPowerConsumed);
730  tripinfoOut->writeAttr("totalEnergyRegenerated", myTotalPowerRegenerated);
731  tripinfoOut->writeAttr("totalEnergyWasted", myTotalPowerWasted);
732  tripinfoOut->closeTag();
733  }
734 }
735 
736 
737 double
740 }
741 
742 
743 double
746 }
747 
748 std::string
749 MSDevice_ElecHybrid::getParameter(const std::string& key) const {
752  } else if (key == toString(SUMO_ATTR_ENERGYCONSUMED)) {
753  return toString(myConsum);
754  } else if (key == toString(SUMO_ATTR_ENERGYCHARGED)) {
755  return toString(myEnergyCharged);
756  } else if (key == toString(SUMO_ATTR_MAXIMUMBATTERYCAPACITY)) {
758  } else if (key == toString(SUMO_ATTR_OVERHEADWIREID)) {
759  return getOverheadWireSegmentID();
760  } else if (key == toString(SUMO_ATTR_SUBSTATIONID)) {
761  return getTractionSubstationID();
762  } else if (key == toString(SUMO_ATTR_VEHICLEMASS)) {
763  return toString(myParam.find(SUMO_ATTR_VEHICLEMASS)->second);
764  }
765  throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
766 }
767 
768 
769 double
770 MSDevice_ElecHybrid::getParameterDouble(const std::string& key) const {
771  if (key == toString(SUMO_ATTR_MAXIMUMPOWER)) {
772  return (myParam.find(SUMO_ATTR_MAXIMUMPOWER)->second);
773  }
774  throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
775 }
776 
777 
778 double
780  return myConsum;
781 }
782 
783 void
784 MSDevice_ElecHybrid::setConsum(const double consumption) {
786 }
787 
788 double
790  return myEnergyCharged;
791 }
792 
793 void
795  myEnergyCharged = energyCharged;
796 }
797 
798 double
801 #ifdef HAVE_EIGEN
803  if (owc != nullptr) {
804  return owc->alphaBest ;
805  }
806 #else
807  WRITE_ERROR("Overhead wire solver is on, but the Eigen library has not been compiled in!")
808 #endif
809  }
810  return NAN;
811 }
812 
813 double
815  if (veh_elem != nullptr) {
816  return veh_elem->getPowerWanted();
817  }
818  return NAN;
819 }
820 
821 double
823  return myCircuitCurrent;
824 }
825 
826 void
828  myCircuitCurrent = current;
829 }
830 
831 double
833  return myCircuitVoltage;
834 }
835 
836 void
838  myCircuitVoltage = voltage;
839 }
840 
841 std::string
843  if (myActOverheadWireSegment != nullptr) {
845  } else {
846  return "";
847  }
848 }
849 
850 std::string
852  if (myActOverheadWireSegment != nullptr) {
854  if (ts != nullptr) {
855  return ts->getID();
856  }
857  }
858  return "";
859 }
860 
861 bool
864 }
865 
866 void
867 MSDevice_ElecHybrid::setActualBatteryCapacity(const double actualBatteryCapacity) {
868  if (actualBatteryCapacity < 0.0) {
870  } else if (actualBatteryCapacity > myMaximumBatteryCapacity) {
872  } else {
873  myActualBatteryCapacity = actualBatteryCapacity;
874  }
875 }
876 
877 void
878 MSDevice_ElecHybrid::setParameter(const std::string& key, const std::string& value) {
879  double doubleValue;
880  try {
881  doubleValue = StringUtils::toDouble(value);
882  } catch (NumberFormatException&) {
883  throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
884  }
886  myActualBatteryCapacity = doubleValue;
887  } else if (key == toString(SUMO_ATTR_MAXIMUMBATTERYCAPACITY)) {
888  myMaximumBatteryCapacity = doubleValue;
889  } else if (key == toString(SUMO_ATTR_OVERHEADWIRECHARGINGPOWER)) {
890  myOverheadWireChargingPower = doubleValue;
891  } else if (key == toString(SUMO_ATTR_VEHICLEMASS)) {
892  myParam[SUMO_ATTR_VEHICLEMASS] = doubleValue;
893  } else {
894  throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
895  }
896 }
897 
898 double
899 MSDevice_ElecHybrid::acceleration(SUMOVehicle& veh, double power, double oldSpeed) {
902 }
903 
904 double
905 MSDevice_ElecHybrid::consumption(SUMOVehicle& veh, double a, double newSpeed) {
908 }
909 
910 
911 /****************************************************************************/
#define WATT2WATTHR(_x)
#define WATTHR2WATT(_x)
const double WIRE_RESISTIVITY
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:284
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:276
SUMOTime DELTA_T
Definition: SUMOTime.cpp:37
#define ACCEL2SPEED(x)
Definition: SUMOTime.h:49
#define TS
Definition: SUMOTime.h:40
@ SUMO_TAG_OVERHEAD_WIRE_SEGMENT
An overhead wire segment.
SumoXMLAttr
Numbers representing SUMO-XML - attributes.
@ SUMO_ATTR_MAXIMUMPOWER
Maximum Power.
@ SUMO_ATTR_ENERGYCONSUMED
Energy consumed.
@ SUMO_ATTR_SUBSTATIONID
id of a traction substation substation
@ SUMO_ATTR_MAXIMUMBATTERYCAPACITY
Maxium battery capacity.
@ SUMO_ATTR_ROLLDRAGCOEFFICIENT
Roll Drag coefficient.
@ SUMO_ATTR_CONSTANTPOWERINTAKE
Constant Power Intake.
@ SUMO_ATTR_RECUPERATIONEFFICIENCY_BY_DECELERATION
Recuperation efficiency (by deceleration)
@ SUMO_ATTR_RECUPERATIONEFFICIENCY
Recuperation efficiency (constant)
@ SUMO_ATTR_AIRDRAGCOEFFICIENT
Air drag coefficient.
@ SUMO_ATTR_ANGLE
@ SUMO_ATTR_ACTUALBATTERYCAPACITY
@ SUMO_ATTR_VEHICLEMASS
Vehicle mass.
@ SUMO_ATTR_RADIALDRAGCOEFFICIENT
Radial drag coefficient.
@ SUMO_ATTR_ENERGYCHARGED
tgotal of Energy charged
@ SUMO_ATTR_OVERHEADWIREID
@ SUMO_ATTR_PROPULSIONEFFICIENCY
Propulsion efficiency.
@ SUMO_ATTR_INTERNALMOMENTOFINERTIA
Internal moment of inertia.
@ SUMO_ATTR_FRONTSURFACEAREA
Front surface area.
@ SUMO_ATTR_OVERHEADWIRECHARGINGPOWER
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:29
T ISNAN(T a)
Definition: StdDefs.h:114
T MAX2(T a, T b)
Definition: StdDefs.h:79
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:44
Element * addElement(string name, double value, Node *pNode, Node *nNode, Element::ElementType et)
Definition: Circuit.cpp:659
void eraseNode(Node *node)
Definition: Circuit.cpp:62
int getLastId()
Definition: Circuit.h:173
Node * getNode(string name)
Definition: Circuit.cpp:98
Element * getVoltageSource(int id)
Definition: Circuit.cpp:145
Element * getElement(string name)
Definition: Circuit.cpp:117
double alphaBest
Best alpha scaling value.
Definition: Circuit.h:69
Node * addNode(string name)
Definition: Circuit.cpp:41
void descreaseLastId()
Definition: Circuit.h:178
void eraseElement(Element *element)
Definition: Circuit.cpp:693
void setId(int id)
Definition: Element.cpp:127
double getResistance()
Definition: Element.cpp:93
void setCurrent(double current)
Definition: Element.cpp:57
double getPowerWanted()
Definition: Element.cpp:96
string getName()
Definition: Element.cpp:116
Node * getNegNode()
Definition: Element.cpp:109
void setPosNode(Node *node)
Definition: Element.cpp:120
Node * getPosNode()
Definition: Element.cpp:106
void setResistance(double resistance)
Definition: Element.cpp:60
void setPowerWanted(double powerWanted)
Definition: Element.cpp:67
static double angleDiff(const double angle1, const double angle2)
Returns the difference of the second angle to the first angle in radiants.
Definition: GeomHelper.cpp:179
Helper methods for energy-based electricity consumption computation based on the battery device.
Definition: HelpersEnergy.h:40
double compute(const SUMOEmissionClass c, const PollutantsInterface::EmissionType e, const double v, const double a, const double slope, const std::map< int, double > *param) const
Computes the emitted pollutant amount using the given speed and acceleration.
double acceleration(const SUMOEmissionClass c, const PollutantsInterface::EmissionType e, const double v, const double P, const double slope, const std::map< int, double > *param) const
Computes the achievable acceleration using the given speed and amount of consumed electric power.
double getDefaultParam(int paramKey) const
Definition: HelpersEnergy.h:74
A vehicle from the mesoscopic point of view.
Definition: MEVehicle.h:42
double getLastEntryTimeSeconds() const
Returns the entry time for the current segment.
Definition: MEVehicle.h:316
double getBlockTimeSeconds() const
Returns the time at which the vehicle was blocked on the current segment.
Definition: MEVehicle.h:321
double getAverageSpeed() const
Returns the vehicle's estimated average speed on the segment assuming no further delays.
Definition: MEVehicle.cpp:117
SUMOTime getAccumulatedWaitingTime() const
Returns the duration for which the vehicle was blocked.
Definition: MEVehicle.h:294
SUMOTime getLastEntryTime() const
Returns the time the vehicle entered the current segment.
Definition: MEVehicle.h:261
MESegment * getSegment() const
Returns the current segment the vehicle is on.
Definition: MEVehicle.h:237
SUMOTime getWaitingTime() const
Returns the duration for which the vehicle was blocked.
Definition: MEVehicle.h:284
double getSpeed() const
Returns the vehicle's estimated speed assuming no delays.
Definition: MEVehicle.cpp:107
A device which collects info on the vehicle trip (mainly on departure and arrival)
void setEnergyCharged(double energyCharged)
bool myCharging
Parameter, Flag: Vehicle is charging (by default is false)
void setCurrentFromOverheadWire(double current)
double myMaximumBatteryCapacity
Parameter, The total vehicles's Battery Capacity in Wh, [myMaximumBatteryCapacity >= 0].
std::map< int, double > myParam
Parameter collection.
double getCircuitAlpha() const
MSOverheadWire * myPreviousOverheadWireSegment
Parameter, Pointer to the act overhead wire segment in previous step (by default is nullptr),...
static void buildVehicleDevices(SUMOVehicle &v, std::vector< MSVehicleDevice * > &into)
Build devices for the given vehicle, if needed.
void deleteVehicleFromCircuit(SUMOVehicle &veh)
double getVoltageOfOverheadWire() const
Get actual voltage on the overhead wire segment.
double myEnergyCharged
Energy flowing into (+) or from (-) the battery pack in the given timestep.
bool notifyLeave(SUMOTrafficObject &tObject, double lastPos, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Saves arrival info.
double mySOCMax
Maximal SOC of the battery pack, battery will not be charged above this level. (But the buffer may st...
double getMaximumBatteryCapacity() const
Get the total vehicle's Battery Capacity in kWh.
double consumption(SUMOVehicle &veh, double a, double newSpeed)
double getParameterDouble(const std::string &key) const
void setConsum(const double consumption)
bool isBatteryDischarged() const
Get consum.
void generateOutput(OutputDevice *tripinfoOut) const
Called on writing tripinfo output.
double myConsum
Parameter, Vehicle consumption during a time step (by default is 0.)
void setActualBatteryCapacity(const double actualBatteryCapacity)
Set actual vehicle's Battery Capacity in kWh.
std::string getParameter(const std::string &key) const
try to retrieve the given parameter from this device. Throw exception for unsupported key
double acceleration(SUMOVehicle &veh, double power, double oldSpeed)
double myLastAngle
Parameter, Vehicle's last angle.
double getCurrentFromOverheadWire() const
Get actual current in the overhead wire segment.
bool myBatteryDischargedLogic
Parameter, Flag: Battery of Vehicle is fully discharged (by default is false)
const std::string deviceName() const
return the name for this type of device
bool notifyMove(SUMOTrafficObject &tObject, double oldPos, double newPos, double newSpeed)
Checks for waiting steps when the vehicle moves.
void checkParam(const SumoXMLAttr paramKey, const double lower=0., const double upper=std::numeric_limits< double >::infinity())
double myOverheadWireChargingPower
Parameter, overhead wire charging power to battery, if the battery SoC is not full (in Watt)
void setVoltageOfOverheadWire(double voltage)
double myTotalPowerWasted
Energy that could not be stored back to the battery or traction station and was wasted on resistors....
static void insertOptions(OptionsCont &oc)
Inserts MSDevice_ElecHybrid-options.
MSOverheadWire * myActOverheadWireSegment
Parameter, Pointer to the actual overhead wire segment in which vehicle is placed (by default is null...
double myActualBatteryCapacity
Parameter, The actual vehicles's Battery Capacity in Wh, [myActualBatteryCapacity <= myMaximumBattery...
double getEnergyCharged() const
Get charged energy.
std::string getTractionSubstationID() const
Get actual traction substationn ID.
virtual void notifyMoveInternal(const SUMOTrafficObject &tObject, const double frontOnLane, const double timeOnLane, const double meanSpeedFrontOnLane, const double meanSpeedVehicleOnLane, const double travelledDistanceFrontOnLane, const double travelledDistanceVehicleOnLane, const double meanLengthOnLane)
Internal notification about the vehicle moves.
bool notifyEnter(SUMOTrafficObject &tObject, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Saves departure info on insertion.
MSDevice_ElecHybrid(SUMOVehicle &holder, const std::string &id, const double actualBatteryCapacity, const double maximumBatteryCapacity, const double overheadWireChargingPower, const std::map< int, double > &param)
Constructor.
double getActualBatteryCapacity() const
Get the actual vehicle's Battery Capacity in kWh.
double getConsum() const
Get consum.
double myCircuitCurrent
Parameter, Current wanted at overhead wire in next timestep.
std::string getOverheadWireSegmentID() const
Get actual overhead wire segment ID.
void setParameter(const std::string &key, const std::string &value)
try to set the given parameter for this device. Throw exception for unsupported key
static void insertDefaultAssignmentOptions(const std::string &deviceName, const std::string &optionsTopic, OptionsCont &oc, const bool isPerson=false)
Adds common command options that allow to assign devices to vehicles.
Definition: MSDevice.cpp:134
static bool equippedByDefaultAssignmentOptions(const OptionsCont &oc, const std::string &deviceName, DEVICEHOLDER &v, bool outputOptionSet, const bool isPerson=false)
Determines whether a vehicle should get a certain device.
Definition: MSDevice.h:204
MSLane * leftLane(const MSLane *const lane) const
Returns the lane left to the one given, 0 if the given lane is leftmost.
Definition: MSEdge.cpp:341
MSLane * rightLane(const MSLane *const lane) const
Returns the lane right to the one given, 0 if the given lane is rightmost.
Definition: MSEdge.cpp:347
static bool gUseMesoSim
Definition: MSGlobals.h:88
static bool gOverheadWireSolver
Definition: MSGlobals.h:103
Representation of a lane in the micro simulation.
Definition: MSLane.h:82
double getLength() const
Returns the lane's length.
Definition: MSLane.h:539
Notification
Definition of a vehicle state.
@ NOTIFICATION_TELEPORT
The vehicle is being teleported.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:171
std::string getStoppingPlaceID(const MSLane *lane, const double pos, const SumoXMLTag category) const
Returns the stop of the given category close to the given position.
Definition: MSNet.cpp:1107
MSStoppingPlace * getStoppingPlace(const std::string &id, const SumoXMLTag category) const
Returns the named stopping place of the given category.
Definition: MSNet.cpp:1098
Definition of overhead wire segment.
Circuit * getCircuit() const
void addChargeValueForOutput(double WCharged, MSDevice_ElecHybrid *elecHybrid, bool ischarging=1)
add charge value for output
MSTractionSubstation * getTractionSubstation() const
void eraseVehicle(SUMOVehicle &veh)
void addVehicle(SUMOVehicle &veh)
const MSLane & getLane() const
Returns the lane this stop is located at.
void eraseVehicle(MSDevice_ElecHybrid *elecHybrid)
double getSubstationVoltage() const
void addSolvingCirucitToEndOfTimestepEvents()
void addVehicle(MSDevice_ElecHybrid *elecHybrid)
Abstract in-vehicle device.
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:77
const SUMOVTypeParameter & getParameter() const
const std::string & getID() const
Returns the id.
Definition: Named.h:73
Definition: Node.h:31
vector< Element * > * getElements()
Definition: Node.cpp:99
int getId()
Definition: Node.cpp:75
void addElement(Element *element)
Definition: Node.cpp:42
void eraseElement(Element *element)
Definition: Node.cpp:46
void setId(int id)
Definition: Node.cpp:79
A storage for options typed value containers)
Definition: OptionsCont.h:89
void addOptionSubTopic(const std::string &topic)
Adds an option subtopic.
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:60
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:239
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
double getDouble(const std::string &key, const double defaultValue) const
Returns the value for a given key converted to a double.
const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
bool knowsParameter(const std::string &key) const
Returns whether the parameter is known.
static const HelpersEnergy & getEnergyHelper()
get energy helper
Representation of a vehicle, person, or container.
virtual bool isVehicle() const
Whether it is a vehicle.
virtual double getSlope() const =0
Returns the slope of the road at object's position in degrees.
virtual double getSpeed() const =0
Returns the object's current speed.
virtual const MSVehicleType & getVehicleType() const =0
Returns the object's "vehicle" type.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle's parameter (including departure definition)
virtual const MSLane * getLane() const =0
Returns the lane the object is currently at.
virtual const MSEdge * getEdge() const =0
Returns the edge the object is currently at.
virtual double getPositionOnLane() const =0
Get the object's position along the lane.
Structure representing possible vehicle parameter.
Representation of a vehicle.
Definition: SUMOVehicle.h:58
virtual double getAngle() const =0
Get the vehicle's angle.
Structure representing possible vehicle parameter.
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter