Path: blob/main/src/utils/emissions/PollutantsInterface.cpp
169678 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2013-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file PollutantsInterface.cpp14/// @author Daniel Krajzewicz15/// @author Michael Behrisch16/// @date Mon, 19.08.201317///18// Interface to capsulate different emission models19/****************************************************************************/20#include <config.h>2122#include <limits>23#include <cmath>24#include <utils/common/MsgHandler.h>25#include <utils/common/SUMOVehicleClass.h>26#include <utils/common/StringUtils.h>27#include <utils/common/ToString.h>28#include <utils/options/OptionsCont.h>29#include <foreign/PHEMlight/V5/cpp/Constants.h>3031#include "HelpersHBEFA.h"32#include "HelpersHBEFA3.h"33#include "HelpersHBEFA4.h"34#include "HelpersPHEMlight.h"35#include "HelpersEnergy.h"36#include "HelpersMMPEVEM.h"37#include "HelpersPHEMlight5.h"38#include "PollutantsInterface.h"394041// ===========================================================================42// static definitions43// ===========================================================================44const double PollutantsInterface::Helper::ZERO_SPEED_ACCURACY = .5;45PollutantsInterface::Helper PollutantsInterface::myZeroHelper("Zero", PollutantsInterface::ZERO_EMISSIONS, PollutantsInterface::ZERO_EMISSIONS);46HelpersHBEFA PollutantsInterface::myHBEFA2Helper;47HelpersHBEFA3 PollutantsInterface::myHBEFA3Helper;48HelpersPHEMlight PollutantsInterface::myPHEMlightHelper;49HelpersEnergy PollutantsInterface::myEnergyHelper;50HelpersMMPEVEM PollutantsInterface::myMMPEVEMHelper;51HelpersPHEMlight5 PollutantsInterface::myPHEMlight5Helper;52HelpersHBEFA4 PollutantsInterface::myHBEFA4Helper;53PollutantsInterface::Helper* PollutantsInterface::myHelpers[] = {54&PollutantsInterface::myZeroHelper,55&PollutantsInterface::myHBEFA2Helper, &PollutantsInterface::myHBEFA3Helper,56&PollutantsInterface::myPHEMlightHelper, &PollutantsInterface::myEnergyHelper,57&PollutantsInterface::myMMPEVEMHelper, &PollutantsInterface::myPHEMlight5Helper,58&PollutantsInterface::myHBEFA4Helper59};60std::vector<std::string> PollutantsInterface::myAllClassesStr;616263// ===========================================================================64// method definitions65// ===========================================================================6667// ---------------------------------------------------------------------------68// PollutantsInterface::Emissions - methods69// ---------------------------------------------------------------------------7071PollutantsInterface::Emissions::Emissions(double co2, double co, double hc, double f, double nox, double pmx, double elec) :72CO2(co2),73CO(co),74HC(hc),75fuel(f),76NOx(nox),77PMx(pmx),78electricity(elec) {79}808182void PollutantsInterface::Emissions::addScaled(const Emissions& a, const double scale) {83CO2 += scale * a.CO2;84CO += scale * a.CO;85HC += scale * a.HC;86fuel += scale * a.fuel;87NOx += scale * a.NOx;88PMx += scale * a.PMx;89electricity += scale * a.electricity;90}9192// ---------------------------------------------------------------------------93// PollutantsInterface::Helper - methods94// ---------------------------------------------------------------------------9596PollutantsInterface::Helper::Helper(std::string name, const int baseIndex, const int defaultClass) :97myName(name),98myBaseIndex(baseIndex) {99if (defaultClass != -1) {100myEmissionClassStrings.insert("default", defaultClass);101myEmissionClassStrings.addAlias("unknown", defaultClass);102}103}104105106const107std::string& PollutantsInterface::Helper::getName() const {108return myName;109}110111112SUMOEmissionClass113PollutantsInterface::Helper::getClassByName(const std::string& eClass, const SUMOVehicleClass vc) {114UNUSED_PARAMETER(vc);115myVolumetricFuel = OptionsCont::getOptions().exists("emissions.volumetric-fuel") && OptionsCont::getOptions().getBool("emissions.volumetric-fuel");116if (myEmissionClassStrings.hasString(eClass)) {117return myEmissionClassStrings.get(eClass);118}119return myEmissionClassStrings.get(StringUtils::to_lower_case(eClass));120}121122123const std::string124PollutantsInterface::Helper::getClassName(const SUMOEmissionClass c) const {125return myName + "/" + myEmissionClassStrings.getString(c);126}127128129bool130PollutantsInterface::Helper::isSilent(const SUMOEmissionClass c) {131return (c & (int)0xffffffff & ~HEAVY_BIT) == 0;132}133134135SUMOEmissionClass136PollutantsInterface::Helper::getClass(const SUMOEmissionClass base, const std::string& vClass, const std::string& fuel, const std::string& eClass, const double weight) const {137UNUSED_PARAMETER(vClass);138UNUSED_PARAMETER(fuel);139UNUSED_PARAMETER(eClass);140UNUSED_PARAMETER(weight);141return base;142}143144145std::string146PollutantsInterface::Helper::getAmitranVehicleClass(const SUMOEmissionClass c) const {147UNUSED_PARAMETER(c);148return "Passenger";149}150151152std::string153PollutantsInterface::Helper::getFuel(const SUMOEmissionClass c) const {154UNUSED_PARAMETER(c);155return "Gasoline";156}157158159int160PollutantsInterface::Helper::getEuroClass(const SUMOEmissionClass c) const {161UNUSED_PARAMETER(c);162return 0;163}164165166double167PollutantsInterface::Helper::getWeight(const SUMOEmissionClass c) const {168UNUSED_PARAMETER(c);169return -1.;170}171172173double174PollutantsInterface::Helper::compute(const SUMOEmissionClass c, const EmissionType e, const double v, const double a, const double slope, const EnergyParams* param) const {175UNUSED_PARAMETER(c);176UNUSED_PARAMETER(e);177UNUSED_PARAMETER(v);178UNUSED_PARAMETER(a);179UNUSED_PARAMETER(slope);180UNUSED_PARAMETER(param);181return 0.;182}183184185double186PollutantsInterface::Helper::getModifiedAccel(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams* param) const {187UNUSED_PARAMETER(c);188UNUSED_PARAMETER(v);189UNUSED_PARAMETER(slope);190UNUSED_PARAMETER(param);191return a;192}193194195double196PollutantsInterface::Helper::getCoastingDecel(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams* param) const {197// the interpolation for small v is basically the same as in PHEMlightdllV5::CEP::GetDecelCoast198if (v < PHEMlightdllV5::Constants::SPEED_DCEL_MIN) {199return v / PHEMlightdllV5::Constants::SPEED_DCEL_MIN * getCoastingDecel(c, PHEMlightdllV5::Constants::SPEED_DCEL_MIN, a, slope, param);200}201if (param == nullptr) {202param = EnergyParams::getDefault();203}204// the magic numbers below come from a linear interpolation with http://ts-sim-service-ba/svn/simo/trunk/projects/sumo/data/emissions/linear.py205const double mass = param->getDouble(SUMO_ATTR_MASS);206const double incl = param->getDouble(SUMO_ATTR_FRONTSURFACEAREA) / mass * -9.05337017 + -0.00017774;207const double grad = slope == 0. ? 0. : PHEMlightdllV5::Constants::GRAVITY_CONST * sin(DEG2RAD(slope));208return MIN2(0., incl * v + 0.00001066 * mass + -0.38347107 - 20.0 * incl - grad);209}210211212void213PollutantsInterface::Helper::addAllClassesInto(std::vector<SUMOEmissionClass>& list) const {214myEmissionClassStrings.addKeysInto(list);215}216217218bool219PollutantsInterface::Helper::includesClass(const SUMOEmissionClass c) const {220return (c >> 16) == (myBaseIndex >> 16);221}222223// ---------------------------------------------------------------------------224// PollutantsInterface - methods225// ---------------------------------------------------------------------------226227SUMOEmissionClass228PollutantsInterface::getClassByName(const std::string& eClass, const SUMOVehicleClass vc) {229const std::string::size_type sep = eClass.find("/");230const std::string model = eClass.substr(0, sep); // this includes the case of no separator231for (int i = 0; i < 8; i++) {232if (myHelpers[i]->getName() == model) {233if (sep != std::string::npos) {234const std::string subClass = eClass.substr(sep + 1);235if (subClass == "zero") {236return myZeroHelper.getClassByName("default", vc);237}238return myHelpers[i]->getClassByName(subClass, vc);239}240return myHelpers[i]->getClassByName("default", vc);241}242}243if (sep == std::string::npos) {244if (eClass == "zero") {245return myZeroHelper.getClassByName("default", vc);246}247WRITE_WARNINGF("Emission classes should always use the model as a prefix, please recheck '%'. Starting with SUMO 1.24 this will be an error.", eClass)248// default HBEFA2249return myHBEFA2Helper.getClassByName(eClass, vc);250}251throw InvalidArgument("Unknown emission class '" + eClass + "'.");252}253254255const std::vector<SUMOEmissionClass>256PollutantsInterface::getAllClasses() {257std::vector<SUMOEmissionClass> result;258for (int i = 0; i < 8; i++) {259myHelpers[i]->addAllClassesInto(result);260}261return result;262}263264265const std::vector<std::string>&266PollutantsInterface::getAllClassesStr() {267// first check if myAllClassesStr has to be filled268if (myAllClassesStr.empty()) {269// first obtain all emissionClasses270std::vector<SUMOEmissionClass> emissionClasses;271for (int i = 0; i < 8; i++) {272myHelpers[i]->addAllClassesInto(emissionClasses);273}274// now write all emissionClasses in myAllClassesStr275for (const auto& i : emissionClasses) {276myAllClassesStr.push_back(getName(i));277}278}279return myAllClassesStr;280}281282std::string283PollutantsInterface::getName(const SUMOEmissionClass c) {284return myHelpers[c >> 16]->getClassName(c);285}286287288std::string289PollutantsInterface::getPollutantName(const EmissionType e) {290switch (e) {291case CO2:292return "CO2";293case CO:294return "CO";295case HC:296return "HC";297case FUEL:298return "fuel";299case NO_X:300return "NOx";301case PM_X:302return "PMx";303case ELEC:304return "electricity";305default:306throw InvalidArgument("Unknown emission type '" + toString(e) + "'");307}308}309310bool311PollutantsInterface::isHeavy(const SUMOEmissionClass c) {312return (c & HEAVY_BIT) != 0;313}314315316bool317PollutantsInterface::isSilent(const SUMOEmissionClass c) {318return myHelpers[c >> 16]->isSilent(c);319}320321322SUMOEmissionClass323PollutantsInterface::getClass(const SUMOEmissionClass base, const std::string& vClass,324const std::string& fuel, const std::string& eClass, const double weight) {325return myHelpers[base >> 16]->getClass(base, vClass, fuel, eClass, weight);326}327328329std::string330PollutantsInterface::getAmitranVehicleClass(const SUMOEmissionClass c) {331return myHelpers[c >> 16]->getAmitranVehicleClass(c);332}333334335std::string336PollutantsInterface::getFuel(const SUMOEmissionClass c) {337return myHelpers[c >> 16]->getFuel(c);338}339340341int342PollutantsInterface::getEuroClass(const SUMOEmissionClass c) {343return myHelpers[c >> 16]->getEuroClass(c);344}345346347double348PollutantsInterface::getWeight(const SUMOEmissionClass c) {349return myHelpers[c >> 16]->getWeight(c);350}351352353double354PollutantsInterface::compute(const SUMOEmissionClass c, const EmissionType e, const double v, const double a, const double slope, const EnergyParams* param) {355return myHelpers[c >> 16]->compute(c, e, v, a, slope, param);356}357358359PollutantsInterface::Emissions360PollutantsInterface::computeAll(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams* param) {361const Helper* const h = myHelpers[c >> 16];362return Emissions(h->compute(c, CO2, v, a, slope, param), h->compute(c, CO, v, a, slope, param), h->compute(c, HC, v, a, slope, param),363h->compute(c, FUEL, v, a, slope, param), h->compute(c, NO_X, v, a, slope, param), h->compute(c, PM_X, v, a, slope, param),364h->compute(c, ELEC, v, a, slope, param));365}366367368double369PollutantsInterface::computeDefault(const SUMOEmissionClass c, const EmissionType e, const double v, const double a, const double slope, const double tt, const EnergyParams* param) {370const Helper* const h = myHelpers[c >> 16];371return (h->compute(c, e, v, 0, slope, param) + h->compute(c, e, v - a, a, slope, param)) * tt / 2.;372}373374375double376PollutantsInterface::getModifiedAccel(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams* param) {377return myHelpers[c >> 16]->getModifiedAccel(c, v, a, slope, param);378}379380381double382PollutantsInterface::getCoastingDecel(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams* param) {383return myHelpers[c >> 16]->getCoastingDecel(c, v, a, slope, param);384}385386387const HelpersEnergy&388PollutantsInterface::getEnergyHelper() {389return myEnergyHelper;390}391392/****************************************************************************/393394395