Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
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-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/****************************************************************************/
20// Helper methods for PHEMlight-based emission computation
21/****************************************************************************/
22#include <config.h>
23
24#include <limits>
25#include <cmath>
31
32#include "EnergyParams.h"
33#include "HelpersPHEMlight5.h"
34
35
36// ===========================================================================
37// method definitions
38// ===========================================================================
40 HelpersPHEMlight("PHEMlight5", PHEMLIGHT5_BASE, -1),
41 myIndex(PHEMLIGHT5_BASE) {
42}
43
44
46 for (const auto& cep : myCEPs) {
47 delete cep.second;
48 }
49}
50
51
53HelpersPHEMlight5::getClassByName(const std::string& eClass, const SUMOVehicleClass vc) {
54 if (eClass == "unknown" && !myEmissionClassStrings.hasString("unknown")) {
55 myEmissionClassStrings.addAlias("unknown", getClassByName("PC_EU4_G", vc));
56 }
57 if (eClass == "default" && !myEmissionClassStrings.hasString("default")) {
58 myEmissionClassStrings.addAlias("default", getClassByName("PC_EU4_G", vc));
59 }
61 return myEmissionClassStrings.get(eClass);
62 }
63 if (eClass.size() < 6) {
64 throw InvalidArgument("Unknown emission class '" + eClass + "'.");
65 }
67 myVolumetricFuel = oc.getBool("emissions.volumetric-fuel");
68 std::vector<std::string> phemPath;
69 phemPath.push_back(oc.getString("phemlight-path") + "/");
70 if (getenv("PHEMLIGHT_PATH") != nullptr) {
71 phemPath.push_back(std::string(getenv("PHEMLIGHT_PATH")) + "/");
72 }
73 if (getenv("SUMO_HOME") != nullptr) {
74 phemPath.push_back(std::string(getenv("SUMO_HOME")) + "/data/emissions/PHEMlight5/");
75 }
76 if (myCorrection == nullptr && (!oc.isDefault("phemlight-year") || !oc.isDefault("phemlight-temperature"))) {
78 if (!oc.isDefault("phemlight-year")) {
79 myCorrection->setYear(oc.getInt("phemlight-year"));
80 std::string err;
81 if (!myCorrection->ReadDet(err)) {
82 throw InvalidArgument("Error reading PHEMlight5 deterioration data.\n" + err);
83 }
85 }
86 if (!oc.isDefault("phemlight-temperature")) {
87 myCorrection->setAmbTemp(oc.getFloat("phemlight-temperature"));
88 std::string err;
89 if (!myCorrection->ReadTNOx(err)) {
90 throw InvalidArgument("Error reading PHEMlight5 deterioration data.\n" + err);
91 }
93 }
94 }
97 myHelper.setclass(eClass);
98 if (!myCEPHandler.GetCEP(phemPath, &myHelper, myCorrection)) {
99 throw InvalidArgument("File for PHEMlight5 emission class " + eClass + " not found.\n" + myHelper.getErrMsg());
100 }
101 PHEMlightdllV5::CEP* const currCep = myCEPHandler.getCEPS().find(myHelper.getgClass())->second;
102 int index = myIndex++;
103 if (currCep->getHeavyVehicle()) {
105 }
106 myEmissionClassStrings.insert(eClass, index);
107 myCEPs[index] = currCep;
109 return index;
110}
111
112
113std::string
115 const std::string name = myEmissionClassStrings.getString(c);
116 std::string fuel = "Gasoline";
117 if (name.find("_D_") != std::string::npos) {
118 fuel = "Diesel";
119 }
120 if (name.find("_BEV_") != std::string::npos) {
121 fuel = "Electricity";
122 }
123 if (name.find("_HEV") != std::string::npos) {
124 fuel = "Hybrid" + fuel;
125 }
126 return fuel;
127}
128
129
130double
132 return myCEPs.find(c)->second->getVehicleMass();
133}
134
135
136double
137HelpersPHEMlight5::getEmission(PHEMlightdllV5::CEP* currCep, const std::string& e, const double p, const double v, const double drivingPower, const double ratedPower) const {
138 return currCep->GetEmission(e, p, v, &myHelper, drivingPower, ratedPower);
139}
140
141
142double
143HelpersPHEMlight5::calcPower(PHEMlightdllV5::CEP* currCep, const double v, const double a, const double slope, const EnergyParams* param) const {
144 // copy of CEP::CalcPower
145 const double power = calcWheelPower(currCep, v, a, slope, param) / PHEMlightdllV5::Constants::_DRIVE_TRAIN_EFFICIENCY;
146 if (!(currCep->getCalcType() == "HEV" || currCep->getCalcType() == "BEV")) {
147 return power + param->getDoubleOptional(SUMO_ATTR_CONSTANTPOWERINTAKE, currCep->getAuxPower() * 1000.) / 1000.;
148 }
149 return power;
150}
151
152
153double
154HelpersPHEMlight5::calcWheelPower(PHEMlightdllV5::CEP* currCep, const double v, const double a, const double slope, const EnergyParams* param) const {
155 // copy of CEP::CalcWheelPower
156 const double rotFactor = currCep->GetRotationalCoeffecient(v);
157 const double mass = param->getDoubleOptional(SUMO_ATTR_MASS, currCep->getVehicleMass());
158 const double massRot = param->getDoubleOptional(SUMO_ATTR_ROTATINGMASS, currCep->getVehicleMassRot());
159 const double load = param->getDoubleOptional(SUMO_ATTR_LOADING, currCep->getVehicleLoading()) + param->getTransportableMass();
161 const double rf0 = param->getDoubleOptional(SUMO_ATTR_ROLLDRAGCOEFFICIENT, currCep->getResistanceF0());
162
163 double power = (mass + load) * PHEMlightdllV5::Constants::GRAVITY_CONST * currCep->getResistance(v, rf0) * v;
164 power += (cw * PHEMlightdllV5::Constants::AIR_DENSITY_CONST / 2) * std::pow(v, 3);
165 power += (mass * rotFactor + massRot + load) * a * v;
166 power += (mass + load) * PHEMlightdllV5::Constants::GRAVITY_CONST * slope * 0.01 * v;
167 return power / 1000.;
168}
169
170
171double
172HelpersPHEMlight5::getModifiedAccel(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams* param) const {
173 PHEMlightdllV5::CEP* currCep = myCEPs.count(c) == 0 ? nullptr : myCEPs.find(c)->second;
174 if (currCep != nullptr) {
175 if (v == 0.) {
176 return 0.;
177 }
178 // this is a copy of CEP::GetMaxAccel
179 const double rotFactor = currCep->GetRotationalCoeffecient(v);
180 const double mass = param->getDoubleOptional(SUMO_ATTR_MASS, currCep->getVehicleMass());
181 const double massRot = param->getDoubleOptional(SUMO_ATTR_ROTATINGMASS, currCep->getVehicleMassRot());
182 const double load = param->getDoubleOptional(SUMO_ATTR_LOADING, currCep->getVehicleLoading()) + param->getTransportableMass();
183 const double ratedPower = param->getDoubleOptional(SUMO_ATTR_MAXIMUMPOWER, 1000. * currCep->getRatedPower()) / 1000.;
184 const double pMaxForAcc = currCep->GetPMaxNorm(v) * ratedPower - calcPower(currCep, v, 0, slope, param);
185 const double maxAcc = (pMaxForAcc * 1000) / ((mass * rotFactor + massRot + load) * v);
186 return MIN2(a, maxAcc);
187 }
188 return a;
189}
190
191
192double
193HelpersPHEMlight5::getCoastingDecel(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams* param) const {
194 PHEMlightdllV5::CEP* const currCep = myCEPs.find(c)->second;
195 // this is a copy of CEP::GetDecelCoast with an adapted slope force calculation
198 }
199 const double rotFactor = currCep->GetRotationalCoeffecient(v);
200 const double mass = param->getDoubleOptional(SUMO_ATTR_MASS, currCep->getVehicleMass());
201 const double load = param->getDoubleOptional(SUMO_ATTR_LOADING, currCep->getVehicleLoading()) + param->getTransportableMass();
203 const double ratedPower = param->getDoubleOptional(SUMO_ATTR_MAXIMUMPOWER, 1000. * currCep->getRatedPower()) / 1000.;
204 const double wheelRadius = param->getDoubleOptional(SUMO_ATTR_WHEELRADIUS, currCep->getWheelRadius());
205 const double rf0 = param->getDoubleOptional(SUMO_ATTR_ROLLDRAGCOEFFICIENT, currCep->getResistanceF0());
206
207 const double fRoll = currCep->getResistance(v, rf0) * (mass + load) * PHEMlightdllV5::Constants::GRAVITY_CONST;
208 const double fAir = cw * PHEMlightdllV5::Constants::AIR_DENSITY_CONST * 0.5 * std::pow(v, 2);
209 const double fGrad = (mass + load) * PHEMlightdllV5::Constants::GRAVITY_CONST * sin(DEG2RAD(slope));
210
211 return -(currCep->getFMot(v, ratedPower, wheelRadius) + fRoll + fAir + fGrad) / ((mass + load) * rotFactor);
212}
213
214
215double
216HelpersPHEMlight5::compute(const SUMOEmissionClass c, const PollutantsInterface::EmissionType e, const double v, const double a, const double slope, const EnergyParams* param) const {
217 if (param != nullptr && param->isEngineOff()) {
218 return 0.;
219 }
220 const double corrSpeed = MAX2(0.0, v);
221 assert(myCEPs.count(c) == 1);
222 PHEMlightdllV5::CEP* const currCep = myCEPs.find(c)->second;
223 const double corrAcc = getModifiedAccel(c, corrSpeed, a, slope, param);
224 const bool isBEV = currCep->getFuelType() == PHEMlightdllV5::Constants::strBEV;
225 const bool isHybrid = currCep->getCalcType() == PHEMlightdllV5::Constants::strHybrid;
226 const double power_raw = calcPower(currCep, corrSpeed, corrAcc, slope, param);
227 const double ratedPower = param->getDoubleOptional(SUMO_ATTR_MAXIMUMPOWER, 1000. * currCep->getRatedPower()) / 1000.;
228 const double power = isHybrid ? calcWheelPower(currCep, corrSpeed, corrAcc, slope, param) : currCep->CalcEngPower(power_raw, ratedPower);
229
230 if (!isBEV && corrAcc < getCoastingDecel(c, corrSpeed, corrAcc, slope, param) &&
232 return 0.;
233 }
234 // TODO: this is probably only needed for non-heavy vehicles, so if execution speed becomes an issue this could be optimized out
236 switch (e) {
238 return getEmission(currCep, "CO", power, corrSpeed, drivingPower, ratedPower) / SECONDS_PER_HOUR * 1000.;
240 return currCep->GetCO2Emission(getEmission(currCep, "FC", power, corrSpeed, drivingPower, ratedPower),
241 getEmission(currCep, "CO", power, corrSpeed, drivingPower, ratedPower),
242 getEmission(currCep, "HC", power, corrSpeed, drivingPower, ratedPower), &myHelper) / SECONDS_PER_HOUR * 1000.;
244 return getEmission(currCep, "HC", power, corrSpeed, drivingPower, ratedPower) / SECONDS_PER_HOUR * 1000.;
246 return getEmission(currCep, "NOx", power, corrSpeed, drivingPower, ratedPower) / SECONDS_PER_HOUR * 1000.;
248 return getEmission(currCep, "PM", power, corrSpeed, drivingPower, ratedPower) / SECONDS_PER_HOUR * 1000.;
250 if (myVolumetricFuel && currCep->getFuelType() == PHEMlightdllV5::Constants::strDiesel) { // divide by average diesel density of 836 g/l
251 return getEmission(currCep, "FC", power, corrSpeed, drivingPower, ratedPower) / 836. / SECONDS_PER_HOUR * 1000.;
252 }
253 if (myVolumetricFuel && currCep->getFuelType() == PHEMlightdllV5::Constants::strGasoline) { // divide by average gasoline density of 742 g/l
254 return getEmission(currCep, "FC", power, corrSpeed, drivingPower, ratedPower) / 742. / SECONDS_PER_HOUR * 1000.;
255 }
256 if (isBEV) {
257 return 0.;
258 }
259 return getEmission(currCep, "FC", power, corrSpeed, drivingPower, ratedPower) / SECONDS_PER_HOUR * 1000.; // still in mg even if myVolumetricFuel is set!
260 }
262 if (isBEV) {
263 const double auxPower = param->getDoubleOptional(SUMO_ATTR_CONSTANTPOWERINTAKE, currCep->getAuxPower() * 1000.) / 1000.;
264 return (getEmission(currCep, "FC_el", power, corrSpeed, drivingPower, ratedPower) + auxPower) / SECONDS_PER_HOUR * 1000.;
265 }
266 return 0;
267 }
268 // should never get here
269 return 0.;
270}
271
272
273/****************************************************************************/
#define DEG2RAD(x)
Definition GeomHelper.h:35
const double SECONDS_PER_HOUR
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:80
T MAX2(T a, T b)
Definition StdDefs.h:86
An upper class for objects with additional parameters.
double getDoubleOptional(SumoXMLAttr attr, const double def) const
Returns the value for a given key with an optional default. SUMO_ATTR_MASS and SUMO_ATTR_FRONTSURFACE...
bool isEngineOff() const
Returns the state of the engine when the vehicle is not moving.
double getTransportableMass() const
Returns the mass of all transportables in the vehicle.
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.
double getWeight(const SUMOEmissionClass c) const
Returns a reference weight in kg described by this emission class This implementation returns the val...
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.
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)
const double & getRatedPower() const
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)
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
const std::string & getCalcType() const
double GetPMaxNorm(double speed)
double getVehicleMass() const
Definition V5/cpp/CEP.h:70
const std::string & getFuelType() const
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)
double GetCO2Emission(double _FC, double _CO, double _HC, Helpers *VehicleClass)
double CalcEngPower(double power, const double ratedPower)
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)
bool ReadDet(std::string &ErrMSG)
bool ReadTNOx(std::string &ErrMSG)
void setYear(const int &value)
void setUseTNOx(const bool &value)
void setUseDet(const bool &value)
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
const std::string & getString(const T key) const
get string
bool hasString(const std::string &str) const
check if the given string exist
void addAlias(const std::string str, const T key)
add alias to the given key
T get(const std::string &str) const
get key
void insert(const std::string str, const T key, bool checkDuplicates=true)
insert string and their associated key
static std::string to_lower_case(const std::string &str)
Transfers the content to lower case.