Line data Source code
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 : /****************************************************************************/
14 : /// @file PollutantsInterface.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Michael Behrisch
17 : /// @date Mon, 19.08.2013
18 : ///
19 : // Interface to capsulate different emission models
20 : /****************************************************************************/
21 : #include <config.h>
22 :
23 : #include <limits>
24 : #include <cmath>
25 : #include <utils/common/MsgHandler.h>
26 : #include <utils/common/SUMOVehicleClass.h>
27 : #include <utils/common/StringUtils.h>
28 : #include <utils/common/ToString.h>
29 : #include <utils/options/OptionsCont.h>
30 : #include <foreign/PHEMlight/V5/cpp/Constants.h>
31 :
32 : #include "HelpersHBEFA.h"
33 : #include "HelpersHBEFA3.h"
34 : #include "HelpersHBEFA4.h"
35 : #include "HelpersPHEMlight.h"
36 : #include "HelpersEnergy.h"
37 : #include "HelpersMMPEVEM.h"
38 : #include "HelpersPHEMlight5.h"
39 : #include "PollutantsInterface.h"
40 :
41 :
42 : // ===========================================================================
43 : // static definitions
44 : // ===========================================================================
45 : const double PollutantsInterface::Helper::ZERO_SPEED_ACCURACY = .5;
46 : PollutantsInterface::Helper PollutantsInterface::myZeroHelper("Zero", PollutantsInterface::ZERO_EMISSIONS, PollutantsInterface::ZERO_EMISSIONS);
47 : HelpersHBEFA PollutantsInterface::myHBEFA2Helper;
48 : HelpersHBEFA3 PollutantsInterface::myHBEFA3Helper;
49 : HelpersPHEMlight PollutantsInterface::myPHEMlightHelper;
50 : HelpersEnergy PollutantsInterface::myEnergyHelper;
51 : HelpersMMPEVEM PollutantsInterface::myMMPEVEMHelper;
52 : HelpersPHEMlight5 PollutantsInterface::myPHEMlight5Helper;
53 : HelpersHBEFA4 PollutantsInterface::myHBEFA4Helper;
54 : PollutantsInterface::Helper* PollutantsInterface::myHelpers[] = {
55 : &PollutantsInterface::myZeroHelper,
56 : &PollutantsInterface::myHBEFA2Helper, &PollutantsInterface::myHBEFA3Helper,
57 : &PollutantsInterface::myPHEMlightHelper, &PollutantsInterface::myEnergyHelper,
58 : &PollutantsInterface::myMMPEVEMHelper, &PollutantsInterface::myPHEMlight5Helper,
59 : &PollutantsInterface::myHBEFA4Helper
60 : };
61 : std::vector<std::string> PollutantsInterface::myAllClassesStr;
62 :
63 :
64 : // ===========================================================================
65 : // method definitions
66 : // ===========================================================================
67 :
68 : // ---------------------------------------------------------------------------
69 : // PollutantsInterface::Emissions - methods
70 : // ---------------------------------------------------------------------------
71 :
72 102829785 : PollutantsInterface::Emissions::Emissions(double co2, double co, double hc, double f, double nox, double pmx, double elec) :
73 102829785 : CO2(co2),
74 102829785 : CO(co),
75 102829785 : HC(hc),
76 102829785 : fuel(f),
77 102829785 : NOx(nox),
78 102829785 : PMx(pmx),
79 102829785 : electricity(elec) {
80 102829785 : }
81 :
82 :
83 101387572 : void PollutantsInterface::Emissions::addScaled(const Emissions& a, const double scale) {
84 101387572 : CO2 += scale * a.CO2;
85 101387572 : CO += scale * a.CO;
86 101387572 : HC += scale * a.HC;
87 101387572 : fuel += scale * a.fuel;
88 101387572 : NOx += scale * a.NOx;
89 101387572 : PMx += scale * a.PMx;
90 101387572 : electricity += scale * a.electricity;
91 101387572 : }
92 :
93 : // ---------------------------------------------------------------------------
94 : // PollutantsInterface::Helper - methods
95 : // ---------------------------------------------------------------------------
96 :
97 456248 : PollutantsInterface::Helper::Helper(std::string name, const int baseIndex, const int defaultClass) :
98 456248 : myName(name),
99 456248 : myBaseIndex(baseIndex) {
100 456248 : if (defaultClass != -1) {
101 171093 : myEmissionClassStrings.insert("default", defaultClass);
102 342186 : myEmissionClassStrings.addAlias("unknown", defaultClass);
103 : }
104 456248 : }
105 :
106 :
107 : const
108 7841441 : std::string& PollutantsInterface::Helper::getName() const {
109 7841441 : return myName;
110 : }
111 :
112 :
113 : SUMOEmissionClass
114 1016734 : PollutantsInterface::Helper::getClassByName(const std::string& eClass, const SUMOVehicleClass vc) {
115 : UNUSED_PARAMETER(vc);
116 2027446 : myVolumetricFuel = OptionsCont::getOptions().exists("emissions.volumetric-fuel") && OptionsCont::getOptions().getBool("emissions.volumetric-fuel");
117 : if (myEmissionClassStrings.hasString(eClass)) {
118 1016734 : return myEmissionClassStrings.get(eClass);
119 : }
120 0 : return myEmissionClassStrings.get(StringUtils::to_lower_case(eClass));
121 : }
122 :
123 :
124 : const std::string
125 347744 : PollutantsInterface::Helper::getClassName(const SUMOEmissionClass c) const {
126 695488 : return myName + "/" + myEmissionClassStrings.getString(c);
127 : }
128 :
129 :
130 : bool
131 777510 : PollutantsInterface::Helper::isSilent(const SUMOEmissionClass c) {
132 777510 : return (c & (int)0xffffffff & ~HEAVY_BIT) == 0;
133 : }
134 :
135 :
136 : SUMOEmissionClass
137 0 : PollutantsInterface::Helper::getClass(const SUMOEmissionClass base, const std::string& vClass, const std::string& fuel, const std::string& eClass, const double weight) const {
138 : UNUSED_PARAMETER(vClass);
139 : UNUSED_PARAMETER(fuel);
140 : UNUSED_PARAMETER(eClass);
141 : UNUSED_PARAMETER(weight);
142 0 : return base;
143 : }
144 :
145 :
146 : std::string
147 0 : PollutantsInterface::Helper::getAmitranVehicleClass(const SUMOEmissionClass c) const {
148 : UNUSED_PARAMETER(c);
149 0 : return "Passenger";
150 : }
151 :
152 :
153 : std::string
154 0 : PollutantsInterface::Helper::getFuel(const SUMOEmissionClass c) const {
155 : UNUSED_PARAMETER(c);
156 0 : return "Gasoline";
157 : }
158 :
159 :
160 : int
161 0 : PollutantsInterface::Helper::getEuroClass(const SUMOEmissionClass c) const {
162 : UNUSED_PARAMETER(c);
163 0 : return 0;
164 : }
165 :
166 :
167 : double
168 325557 : PollutantsInterface::Helper::getWeight(const SUMOEmissionClass c) const {
169 : UNUSED_PARAMETER(c);
170 325557 : return -1.;
171 : }
172 :
173 :
174 : double
175 94220 : PollutantsInterface::Helper::compute(const SUMOEmissionClass c, const EmissionType e, const double v, const double a, const double slope, const EnergyParams* param) const {
176 : UNUSED_PARAMETER(c);
177 : UNUSED_PARAMETER(e);
178 : UNUSED_PARAMETER(v);
179 : UNUSED_PARAMETER(a);
180 : UNUSED_PARAMETER(slope);
181 : UNUSED_PARAMETER(param);
182 94220 : return 0.;
183 : }
184 :
185 :
186 : double
187 0 : PollutantsInterface::Helper::getModifiedAccel(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams* param) const {
188 : UNUSED_PARAMETER(c);
189 : UNUSED_PARAMETER(v);
190 : UNUSED_PARAMETER(slope);
191 : UNUSED_PARAMETER(param);
192 0 : return a;
193 : }
194 :
195 :
196 : double
197 366753382 : PollutantsInterface::Helper::getCoastingDecel(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams* param) const {
198 : // the interpolation for small v is basically the same as in PHEMlightdllV5::CEP::GetDecelCoast
199 366753382 : if (v < PHEMlightdllV5::Constants::SPEED_DCEL_MIN) {
200 20014635 : return v / PHEMlightdllV5::Constants::SPEED_DCEL_MIN * getCoastingDecel(c, PHEMlightdllV5::Constants::SPEED_DCEL_MIN, a, slope, param);
201 : }
202 346738747 : if (param == nullptr) {
203 4382 : param = EnergyParams::getDefault();
204 : }
205 : // the magic numbers below come from a linear interpolation with http://ts-sim-service-ba/svn/simo/trunk/projects/sumo/data/emissions/linear.py
206 346738747 : const double mass = param->getDouble(SUMO_ATTR_MASS);
207 346738747 : const double incl = param->getDouble(SUMO_ATTR_FRONTSURFACEAREA) / mass * -9.05337017 + -0.00017774;
208 346738747 : const double grad = slope == 0. ? 0. : PHEMlightdllV5::Constants::GRAVITY_CONST * sin(DEG2RAD(slope));
209 346738747 : return MIN2(0., incl * v + 0.00001066 * mass + -0.38347107 - 20.0 * incl - grad);
210 : }
211 :
212 :
213 : void
214 0 : PollutantsInterface::Helper::addAllClassesInto(std::vector<SUMOEmissionClass>& list) const {
215 0 : myEmissionClassStrings.addKeysInto(list);
216 0 : }
217 :
218 :
219 : bool
220 0 : PollutantsInterface::Helper::includesClass(const SUMOEmissionClass c) const {
221 0 : return (c >> 16) == (myBaseIndex >> 16);
222 : }
223 :
224 : // ---------------------------------------------------------------------------
225 : // PollutantsInterface - methods
226 : // ---------------------------------------------------------------------------
227 :
228 : SUMOEmissionClass
229 1016910 : PollutantsInterface::getClassByName(const std::string& eClass, const SUMOVehicleClass vc) {
230 : const std::string::size_type sep = eClass.find("/");
231 1016910 : const std::string model = eClass.substr(0, sep); // this includes the case of no separator
232 7841461 : for (int i = 0; i < 8; i++) {
233 7841441 : if (myHelpers[i]->getName() == model) {
234 1016890 : if (sep != std::string::npos) {
235 1016626 : const std::string subClass = eClass.substr(sep + 1);
236 1016626 : if (subClass == "zero") {
237 325254 : return myZeroHelper.getClassByName("default", vc);
238 : }
239 853999 : return myHelpers[i]->getClassByName(subClass, vc);
240 : }
241 528 : return myHelpers[i]->getClassByName("default", vc);
242 : }
243 : }
244 20 : if (sep == std::string::npos) {
245 20 : if (eClass == "zero") {
246 28 : return myZeroHelper.getClassByName("default", vc);
247 : }
248 18 : WRITE_WARNINGF("Emission classes should always use the model as a prefix, please recheck '%'. Starting with SUMO 1.24 this will be an error.", eClass)
249 : // default HBEFA2
250 6 : return myHBEFA2Helper.getClassByName(eClass, vc);
251 : }
252 0 : throw InvalidArgument("Unknown emission class '" + eClass + "'.");
253 : }
254 :
255 :
256 : const std::vector<SUMOEmissionClass>
257 0 : PollutantsInterface::getAllClasses() {
258 : std::vector<SUMOEmissionClass> result;
259 0 : for (int i = 0; i < 8; i++) {
260 0 : myHelpers[i]->addAllClassesInto(result);
261 : }
262 0 : return result;
263 0 : }
264 :
265 :
266 : const std::vector<std::string>&
267 0 : PollutantsInterface::getAllClassesStr() {
268 : // first check if myAllClassesStr has to be filled
269 0 : if (myAllClassesStr.empty()) {
270 : // first obtain all emissionClasses
271 : std::vector<SUMOEmissionClass> emissionClasses;
272 0 : for (int i = 0; i < 8; i++) {
273 0 : myHelpers[i]->addAllClassesInto(emissionClasses);
274 : }
275 : // now write all emissionClasses in myAllClassesStr
276 0 : for (const auto& i : emissionClasses) {
277 0 : myAllClassesStr.push_back(getName(i));
278 : }
279 0 : }
280 0 : return myAllClassesStr;
281 : }
282 :
283 : std::string
284 347744 : PollutantsInterface::getName(const SUMOEmissionClass c) {
285 347744 : return myHelpers[c >> 16]->getClassName(c);
286 : }
287 :
288 :
289 : std::string
290 0 : PollutantsInterface::getPollutantName(const EmissionType e) {
291 0 : switch (e) {
292 : case CO2:
293 0 : return "CO2";
294 : case CO:
295 0 : return "CO";
296 : case HC:
297 0 : return "HC";
298 : case FUEL:
299 0 : return "fuel";
300 : case NO_X:
301 0 : return "NOx";
302 : case PM_X:
303 0 : return "PMx";
304 : case ELEC:
305 0 : return "electricity";
306 0 : default:
307 0 : throw InvalidArgument("Unknown emission type '" + toString(e) + "'");
308 : }
309 : }
310 :
311 : bool
312 780743 : PollutantsInterface::isHeavy(const SUMOEmissionClass c) {
313 780743 : return (c & HEAVY_BIT) != 0;
314 : }
315 :
316 :
317 : bool
318 777510 : PollutantsInterface::isSilent(const SUMOEmissionClass c) {
319 777510 : return myHelpers[c >> 16]->isSilent(c);
320 : }
321 :
322 :
323 : SUMOEmissionClass
324 2 : PollutantsInterface::getClass(const SUMOEmissionClass base, const std::string& vClass,
325 : const std::string& fuel, const std::string& eClass, const double weight) {
326 2 : return myHelpers[base >> 16]->getClass(base, vClass, fuel, eClass, weight);
327 : }
328 :
329 :
330 : std::string
331 9 : PollutantsInterface::getAmitranVehicleClass(const SUMOEmissionClass c) {
332 9 : return myHelpers[c >> 16]->getAmitranVehicleClass(c);
333 : }
334 :
335 :
336 : std::string
337 1668 : PollutantsInterface::getFuel(const SUMOEmissionClass c) {
338 1668 : return myHelpers[c >> 16]->getFuel(c);
339 : }
340 :
341 :
342 : int
343 9 : PollutantsInterface::getEuroClass(const SUMOEmissionClass c) {
344 9 : return myHelpers[c >> 16]->getEuroClass(c);
345 : }
346 :
347 :
348 : double
349 325805 : PollutantsInterface::getWeight(const SUMOEmissionClass c) {
350 325805 : return myHelpers[c >> 16]->getWeight(c);
351 : }
352 :
353 :
354 : double
355 430444 : PollutantsInterface::compute(const SUMOEmissionClass c, const EmissionType e, const double v, const double a, const double slope, const EnergyParams* param) {
356 430444 : return myHelpers[c >> 16]->compute(c, e, v, a, slope, param);
357 : }
358 :
359 :
360 : PollutantsInterface::Emissions
361 101068479 : PollutantsInterface::computeAll(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams* param) {
362 101068479 : const Helper* const h = myHelpers[c >> 16];
363 303205437 : return 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),
364 303205437 : h->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),
365 101068479 : h->compute(c, ELEC, v, a, slope, param));
366 : }
367 :
368 :
369 : double
370 7482 : PollutantsInterface::computeDefault(const SUMOEmissionClass c, const EmissionType e, const double v, const double a, const double slope, const double tt, const EnergyParams* param) {
371 7482 : const Helper* const h = myHelpers[c >> 16];
372 7482 : return (h->compute(c, e, v, 0, slope, param) + h->compute(c, e, v - a, a, slope, param)) * tt / 2.;
373 : }
374 :
375 :
376 : double
377 0 : PollutantsInterface::getModifiedAccel(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams* param) {
378 0 : return myHelpers[c >> 16]->getModifiedAccel(c, v, a, slope, param);
379 : }
380 :
381 :
382 : double
383 1170803 : PollutantsInterface::getCoastingDecel(const SUMOEmissionClass c, const double v, const double a, const double slope, const EnergyParams* param) {
384 1170803 : return myHelpers[c >> 16]->getCoastingDecel(c, v, a, slope, param);
385 : }
386 :
387 :
388 : const HelpersEnergy&
389 1720 : PollutantsInterface::getEnergyHelper() {
390 1720 : return myEnergyHelper;
391 : }
392 :
393 : /****************************************************************************/
|