Eclipse SUMO - Simulation of Urban MObility
HelpersPHEMlight5.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2013-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 /****************************************************************************/
20 // Helper methods for PHEMlight-based emission computation
21 /****************************************************************************/
22 #include <config.h>
23 
24 #include <limits>
25 #include <cmath>
30 
31 #include "EnergyParams.h"
32 #include "HelpersPHEMlight5.h"
33 
34 
35 // ===========================================================================
36 // method definitions
37 // ===========================================================================
39  HelpersPHEMlight("PHEMlight5", PHEMLIGHT5_BASE, -1),
40  myIndex(PHEMLIGHT5_BASE) {
41 }
42 
43 
45  for (const auto& cep : myCEPs) {
46  delete cep.second;
47  }
48 }
49 
50 
52 HelpersPHEMlight5::getClassByName(const std::string& eClass, const SUMOVehicleClass vc) {
53  if (eClass == "unknown" && !myEmissionClassStrings.hasString("unknown")) {
54  myEmissionClassStrings.addAlias("unknown", getClassByName("PC_EU4_G", vc));
55  }
56  if (eClass == "default" && !myEmissionClassStrings.hasString("default")) {
57  myEmissionClassStrings.addAlias("default", getClassByName("PC_EU4_G", vc));
58  }
59  if (myEmissionClassStrings.hasString(eClass)) {
60  return myEmissionClassStrings.get(eClass);
61  }
62  if (eClass.size() < 6) {
63  throw InvalidArgument("Unknown emission class '" + eClass + "'.");
64  }
66  myVolumetricFuel = oc.getBool("emissions.volumetric-fuel");
67  std::vector<std::string> phemPath;
68  phemPath.push_back(oc.getString("phemlight-path") + "/");
69  if (getenv("PHEMLIGHT_PATH") != nullptr) {
70  phemPath.push_back(std::string(getenv("PHEMLIGHT_PATH")) + "/");
71  }
72  if (getenv("SUMO_HOME") != nullptr) {
73  phemPath.push_back(std::string(getenv("SUMO_HOME")) + "/data/emissions/PHEMlight5/");
74  }
75  if (myCorrection == nullptr && (!oc.isDefault("phemlight-year") || !oc.isDefault("phemlight-temperature"))) {
77  if (!oc.isDefault("phemlight-year")) {
78  myCorrection->setYear(oc.getInt("phemlight-year"));
79  std::string err;
80  if (!myCorrection->ReadDet(err)) {
81  throw InvalidArgument("Error reading PHEMlight5 deterioration data.\n" + err);
82  }
83  myCorrection->setUseDet(true);
84  }
85  if (!oc.isDefault("phemlight-temperature")) {
86  myCorrection->setAmbTemp(oc.getFloat("phemlight-temperature"));
87  std::string err;
88  if (!myCorrection->ReadTNOx(err)) {
89  throw InvalidArgument("Error reading PHEMlight5 deterioration data.\n" + err);
90  }
91  myCorrection->setUseTNOx(true);
92  }
93  }
95  myHelper.setPHEMDataV("V5");
96  myHelper.setclass(eClass);
97  if (!myCEPHandler.GetCEP(phemPath, &myHelper, myCorrection)) {
98  throw InvalidArgument("File for PHEMlight5 emission class " + eClass + " not found.\n" + myHelper.getErrMsg());
99  }
100  PHEMlightdllV5::CEP* const currCep = myCEPHandler.getCEPS().find(myHelper.getgClass())->second;
101  int index = myIndex++;
102  if (currCep->getHeavyVehicle()) {
104  }
105  myEmissionClassStrings.insert(eClass, index);
106  myCEPs[index] = currCep;
108  return index;
109 }
110 
111 
112 std::string
114  const std::string name = myEmissionClassStrings.getString(c);
115  std::string fuel = "Gasoline";
116  if (name.find("_D_") != std::string::npos) {
117  fuel = "Diesel";
118  }
119  if (name.find("_BEV_") != std::string::npos) {
120  fuel = "Electricity";
121  }
122  if (name.find("_HEV") != std::string::npos) {
123  fuel = "Hybrid" + fuel;
124  }
125  return fuel;
126 }
127 
128 
129 double
130 HelpersPHEMlight5::getEmission(PHEMlightdllV5::CEP* currCep, const std::string& e, const double p, const double v, const double drivingPower, const double ratedPower) const {
131  return currCep->GetEmission(e, p, v, &myHelper, drivingPower, ratedPower);
132 }
133 
134 
135 double
136 HelpersPHEMlight5::calcPower(PHEMlightdllV5::CEP* currCep, const double v, const double a, const double slope, const EnergyParams* param) const {
137  // copy of CEP::CalcPower
138  const double power = calcWheelPower(currCep, v, a, slope, param) / PHEMlightdllV5::Constants::_DRIVE_TRAIN_EFFICIENCY;
139  if (!(currCep->getCalcType() == "HEV" || currCep->getCalcType() == "BEV")) {
140  return power + param->getDoubleOptional(SUMO_ATTR_CONSTANTPOWERINTAKE, currCep->getAuxPower() * 1000.) / 1000.;
141  }
142  return power;
143 }
144 
145 
146 double
147 HelpersPHEMlight5::calcWheelPower(PHEMlightdllV5::CEP* currCep, const double v, const double a, const double slope, const EnergyParams* param) const {
148  // copy of CEP::CalcWheelPower
149  const double rotFactor = currCep->GetRotationalCoeffecient(v);
150  const double mass = param->getDoubleOptional(SUMO_ATTR_MASS, currCep->getVehicleMass());
151  const double massRot = param->getDoubleOptional(SUMO_ATTR_ROTATINGMASS, currCep->getVehicleMassRot());
152  const double load = param->getDoubleOptional(SUMO_ATTR_LOADING, currCep->getVehicleLoading());
154  const double rf0 = param->getDoubleOptional(SUMO_ATTR_ROLLDRAGCOEFFICIENT, currCep->getResistanceF0());
155 
156  double power = (mass + load) * PHEMlightdllV5::Constants::GRAVITY_CONST * currCep->getResistance(v, rf0) * v;
157  power += (cw * PHEMlightdllV5::Constants::AIR_DENSITY_CONST / 2) * std::pow(v, 3);
158  power += (mass * rotFactor + massRot + load) * a * v;
159  power += (mass + load) * PHEMlightdllV5::Constants::GRAVITY_CONST * slope * 0.01 * v;
160  return power / 1000.;
161 }
162 
163 
164 double
165 HelpersPHEMlight5::getModifiedAccel(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams* param) const {
166  PHEMlightdllV5::CEP* currCep = myCEPs.count(c) == 0 ? nullptr : myCEPs.find(c)->second;
167  if (currCep != nullptr) {
168  if (v == 0.) {
169  return 0.;
170  }
171  // this is a copy of CEP::GetMaxAccel
172  const double rotFactor = currCep->GetRotationalCoeffecient(v);
173  const double mass = param->getDoubleOptional(SUMO_ATTR_MASS, currCep->getVehicleMass());
174  const double massRot = param->getDoubleOptional(SUMO_ATTR_ROTATINGMASS, currCep->getVehicleMassRot());
175  const double load = param->getDoubleOptional(SUMO_ATTR_LOADING, currCep->getVehicleLoading());
176  const double ratedPower = param->getDoubleOptional(SUMO_ATTR_MAXIMUMPOWER, currCep->getRatedPower());
177  const double pMaxForAcc = currCep->GetPMaxNorm(v) * ratedPower - calcPower(currCep, v, 0, slope, param);
178  const double maxAcc = (pMaxForAcc * 1000) / ((mass * rotFactor + massRot + load) * v);
179  return MIN2(a, maxAcc);
180  }
181  return a;
182 }
183 
184 
185 double
186 HelpersPHEMlight5::getCoastingDecel(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams* param) const {
187  PHEMlightdllV5::CEP* const currCep = myCEPs.find(c)->second;
188  // this is a copy of CEP::GetDecelCoast
191  }
192  const double rotFactor = currCep->GetRotationalCoeffecient(v);
193  const double mass = param->getDoubleOptional(SUMO_ATTR_MASS, currCep->getVehicleMass());
194  const double load = param->getDoubleOptional(SUMO_ATTR_LOADING, currCep->getVehicleLoading());
196  const double ratedPower = param->getDoubleOptional(SUMO_ATTR_MAXIMUMPOWER, currCep->getRatedPower());
197  const double wheelRadius = param->getDoubleOptional(SUMO_ATTR_WHEELRADIUS, currCep->getWheelRadius());
198  const double rf0 = param->getDoubleOptional(SUMO_ATTR_ROLLDRAGCOEFFICIENT, currCep->getResistanceF0());
199 
200  const double fRoll = currCep->getResistance(v, rf0) * (mass + load) * PHEMlightdllV5::Constants::GRAVITY_CONST;
201  const double fAir = cw * PHEMlightdllV5::Constants::AIR_DENSITY_CONST * 0.5 * std::pow(v, 2);
202  const double fGrad = (mass + load) * PHEMlightdllV5::Constants::GRAVITY_CONST * slope / 100;
203 
204  return -(currCep->getFMot(v, ratedPower, wheelRadius) + fRoll + fAir + fGrad) / ((mass + load) * rotFactor);
205 }
206 
207 
208 double
209 HelpersPHEMlight5::compute(const SUMOEmissionClass c, const PollutantsInterface::EmissionType e, const double v, const double a, const double slope, const EnergyParams* param) const {
210  if (param != nullptr && param->isEngineOff()) {
211  return 0.;
212  }
213  const double corrSpeed = MAX2(0.0, v);
214  assert(myCEPs.count(c) == 1);
215  PHEMlightdllV5::CEP* const currCep = myCEPs.find(c)->second;
216  const double corrAcc = getModifiedAccel(c, corrSpeed, a, slope, param);
217  const bool isBEV = currCep->getFuelType() == PHEMlightdllV5::Constants::strBEV;
218  const bool isHybrid = currCep->getCalcType() == PHEMlightdllV5::Constants::strHybrid;
219  const double power_raw = calcPower(currCep, corrSpeed, corrAcc, slope, param);
220  const double ratedPower = param->getDoubleOptional(SUMO_ATTR_MAXIMUMPOWER, currCep->getRatedPower());
221  const double power = isHybrid ? calcWheelPower(currCep, corrSpeed, corrAcc, slope, param) : currCep->CalcEngPower(power_raw, ratedPower);
222 
223  if (!isBEV && corrAcc < getCoastingDecel(c, corrSpeed, corrAcc, slope, param) &&
225  return 0.;
226  }
227  // TODO: this is probably only needed for non-heavy vehicles, so if execution speed becomes an issue this could be optimized out
229  switch (e) {
231  return getEmission(currCep, "CO", power, corrSpeed, drivingPower, ratedPower) / SECONDS_PER_HOUR * 1000.;
233  return currCep->GetCO2Emission(getEmission(currCep, "FC", power, corrSpeed, drivingPower, ratedPower),
234  getEmission(currCep, "CO", power, corrSpeed, drivingPower, ratedPower),
235  getEmission(currCep, "HC", power, corrSpeed, drivingPower, ratedPower), &myHelper) / SECONDS_PER_HOUR * 1000.;
237  return getEmission(currCep, "HC", power, corrSpeed, drivingPower, ratedPower) / SECONDS_PER_HOUR * 1000.;
239  return getEmission(currCep, "NOx", power, corrSpeed, drivingPower, ratedPower) / SECONDS_PER_HOUR * 1000.;
241  return getEmission(currCep, "PM", power, corrSpeed, drivingPower, ratedPower) / SECONDS_PER_HOUR * 1000.;
243  if (myVolumetricFuel && currCep->getFuelType() == PHEMlightdllV5::Constants::strDiesel) { // divide by average diesel density of 836 g/l
244  return getEmission(currCep, "FC", power, corrSpeed, drivingPower, ratedPower) / 836. / SECONDS_PER_HOUR * 1000.;
245  }
246  if (myVolumetricFuel && currCep->getFuelType() == PHEMlightdllV5::Constants::strGasoline) { // divide by average gasoline density of 742 g/l
247  return getEmission(currCep, "FC", power, corrSpeed, drivingPower, ratedPower) / 742. / SECONDS_PER_HOUR * 1000.;
248  }
249  if (isBEV) {
250  return 0.;
251  }
252  return getEmission(currCep, "FC", power, corrSpeed, drivingPower, ratedPower) / SECONDS_PER_HOUR * 1000.; // still in mg even if myVolumetricFuel is set!
253  }
255  if (isBEV) {
256  const double auxPower = param->getDoubleOptional(SUMO_ATTR_CONSTANTPOWERINTAKE, currCep->getAuxPower() * 1000.) / 1000.;
257  return (getEmission(currCep, "FC_el", power, corrSpeed, drivingPower, ratedPower) + auxPower) / SECONDS_PER_HOUR * 1000.;
258  }
259  return 0;
260  }
261  // should never get here
262  return 0.;
263 }
264 
265 
266 /****************************************************************************/
const double SECONDS_PER_HOUR
Definition: PHEMConstants.h:27
int SUMOEmissionClass
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SUMO_ATTR_MAXIMUMPOWER
Maximum Power.
@ SUMO_ATTR_MASS
@ SUMO_ATTR_ROLLDRAGCOEFFICIENT
Roll Drag coefficient.
@ SUMO_ATTR_CONSTANTPOWERINTAKE
Constant Power Intake.
@ SUMO_ATTR_LOADING
additional mass loaded on the vehicle
@ SUMO_ATTR_WHEELRADIUS
@ SUMO_ATTR_AIRDRAGCOEFFICIENT
Air drag coefficient.
@ SUMO_ATTR_ROTATINGMASS
Mass equivalent of rotating elements.
@ SUMO_ATTR_FRONTSURFACEAREA
Front surface area.
T MIN2(T a, T b)
Definition: StdDefs.h:76
T MAX2(T a, T b)
Definition: StdDefs.h:82
An upper class for objects with additional parameters.
Definition: EnergyParams.h:43
double getDoubleOptional(SumoXMLAttr attr, const double def) const
bool isEngineOff() const
Returns the state of the engine when the vehicle is not moving.
int myIndex
the index of the next class
double getModifiedAccel(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams *param) const
Returns the adapted acceleration value, useful for comparing with external PHEMlight references.
double calcWheelPower(PHEMlightdllV5::CEP *currCep, const double v, const double a, const double slope, const EnergyParams *param) const
Returns the power without auxiliaries.
HelpersPHEMlight5()
Constructor.
double calcPower(PHEMlightdllV5::CEP *currCep, const double v, const double a, const double slope, const EnergyParams *param) const
Returns the total power needed.
virtual double getCoastingDecel(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams *param) const
Returns the maximum deceleration value (as a negative number), which can still be considered as non-b...
std::string getFuel(const SUMOEmissionClass c) const
Returns the fuel type described by this emission class as described in the Amitran interface (Gasolin...
double compute(const SUMOEmissionClass c, const PollutantsInterface::EmissionType e, const double v, const double a, const double slope, const EnergyParams *param) const
Returns the amount of emitted pollutant given the vehicle type and state (in mg/s or in ml/s for fuel...
double getEmission(PHEMlightdllV5::CEP *currCep, const std::string &e, const double p, const double v, const double drivingPower, const double ratedPower) const
Returns the amount of emitted pollutant given the vehicle type and state (in mg/s or in ml/s for fuel...
PHEMlightdllV5::CEPHandler myCEPHandler
std::map< SUMOEmissionClass, PHEMlightdllV5::CEP * > myCEPs
PHEMlightdllV5::Correction * myCorrection
SUMOEmissionClass getClassByName(const std::string &eClass, const SUMOVehicleClass vc)
Checks whether the string describes a known vehicle class.
virtual ~HelpersPHEMlight5()
Destructor.
PHEMlightdllV5::Helpers myHelper
Helper methods for PHEMlight-based emission computation.
A storage for options typed value containers)
Definition: OptionsCont.h:89
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool isDefault(const std::string &name) const
Returns the information whether the named option has still the default value.
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:60
const std::map< std::string, CEP * > & getCEPS() const
bool GetCEP(std::vector< std::string > &DataPath, Helpers *Helper, Correction *DataCor)
double getWheelRadius() const
Definition: V5/cpp/CEP.h:85
double getVehicleMassRot() const
Definition: V5/cpp/CEP.h:76
double GetRotationalCoeffecient(double speed)
Definition: V5/cpp/CEP.cpp:390
const double & getRatedPower() const
Definition: V5/cpp/CEP.cpp:188
double getCWValue() const
Definition: V5/cpp/CEP.h:82
double getResistanceF0() const
Definition: V5/cpp/CEP.h:88
double getFMot(const double speed, const double ratedPower, const double wheelRadius)
Definition: V5/cpp/CEP.cpp:370
double getVehicleLoading() const
Definition: V5/cpp/CEP.h:73
double getResistance(const double speed, const double f0) const
Definition: V5/cpp/CEP.h:91
double getCrossSectionalArea() const
Definition: V5/cpp/CEP.h:79
const bool & getHeavyVehicle() const
Definition: V5/cpp/CEP.cpp:168
const std::string & getCalcType() const
Definition: V5/cpp/CEP.cpp:180
double GetPMaxNorm(double speed)
Definition: V5/cpp/CEP.cpp:445
double getVehicleMass() const
Definition: V5/cpp/CEP.h:70
const std::string & getFuelType() const
Definition: V5/cpp/CEP.cpp:172
double getAuxPower() const
Definition: V5/cpp/CEP.h:67
double GetEmission(const std::string &pollutant, double power, double speed, Helpers *VehicleClass, const double drivingPower, const double ratedPower)
Definition: V5/cpp/CEP.cpp:207
double GetCO2Emission(double _FC, double _CO, double _HC, Helpers *VehicleClass)
Definition: V5/cpp/CEP.cpp:273
double CalcEngPower(double power, const double ratedPower)
Definition: V5/cpp/CEP.cpp:196
static const std::string strBEV
static const double NORMALIZING_ACCELARATION
static const double NORMALIZING_SPEED
static const double SPEED_DCEL_MIN
static const double ZERO_SPEED_ACCURACY
static const double AIR_DENSITY_CONST
static const std::string strHybrid
static const std::string strGasoline
static const std::string strDiesel
static const double GRAVITY_CONST
static double _DRIVE_TRAIN_EFFICIENCY
void setAmbTemp(const double &value)
Definition: Correction.cpp:286
bool ReadDet(std::string &ErrMSG)
Definition: Correction.cpp:86
bool ReadTNOx(std::string &ErrMSG)
Definition: Correction.cpp:298
void setYear(const int &value)
Definition: Correction.cpp:74
void setUseTNOx(const bool &value)
Definition: Correction.cpp:270
void setUseDet(const bool &value)
Definition: Correction.cpp:50
void setPHEMDataV(const std::string &value)
bool setclass(const std::string &VEH)
const std::string & getgClass() const
void setCommentPrefix(const std::string &value)
const std::string & getErrMsg() const
bool myVolumetricFuel
return fuel consumption in l instead of mg
StringBijection< SUMOEmissionClass > myEmissionClassStrings
Mapping between emission class names and integer representations.
EmissionType
Enumerating all emission types, including fuel.
static const int HEAVY_BIT
the bit to set for denoting heavy vehicles
bool hasString(const std::string &str) const
const std::string & getString(const T key) const
void addAlias(const std::string str, const T key)
T get(const std::string &str) const
void insert(const std::string str, const T key, bool checkDuplicates=true)
static std::string to_lower_case(const std::string &str)
Transfers the content to lower case.
Definition: StringUtils.cpp:79