Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/foreign/PHEMlight/V5/cpp/CEP.cpp
169688 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.
4
// PHEMlight module
5
// Copyright (C) 2016-2023 Technische Universitaet Graz, https://www.tugraz.at/
6
// This program and the accompanying materials are made available under the
7
// terms of the Eclipse Public License 2.0 which is available at
8
// https://www.eclipse.org/legal/epl-2.0/
9
// This Source Code may also be made available under the following Secondary
10
// Licenses when the conditions for such availability set forth in the Eclipse
11
// Public License 2.0 are satisfied: GNU General Public License, version 2
12
// or later which is available at
13
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
14
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
15
/****************************************************************************/
16
/// @file CEP.cpp
17
/// @author Martin Dippold
18
/// @author Michael Behrisch
19
/// @date July 2016
20
///
21
//
22
/****************************************************************************/
23
#include <config.h>
24
25
#include "CEP.h"
26
#include "CEPHandler.h"
27
#include "Constants.h"
28
#include "Helpers.h"
29
30
31
namespace PHEMlightdllV5 {
32
33
CEP::CEP(VEHPHEMLightJSON::VEH* Vehicle, std::vector<std::string>& headerLineFCvalues, std::vector<std::vector<double> >& matrixFCvalues, std::vector<std::string>& headerLinePollutants, std::vector<std::vector<double> >& matrixPollutants, std::vector<double>& idlingFCvalues, std::vector<double>& idlingPollutants) {
34
InitializeInstanceFields();
35
_resistanceF0 = Vehicle->getRollingResData()->getFr0();
36
_resistanceF1 = Vehicle->getRollingResData()->getFr1();
37
_resistanceF2 = Vehicle->getRollingResData()->getFr2();
38
_resistanceF3 = Vehicle->getRollingResData()->getFr3();
39
_resistanceF4 = Vehicle->getRollingResData()->getFr4();
40
_cWValue = Vehicle->getVehicleData()->getCw();
41
_crossSectionalArea = Vehicle->getVehicleData()->getA();
42
_massVehicle = Vehicle->getVehicleData()->getMass();
43
_vehicleLoading = Vehicle->getVehicleData()->getLoading();
44
_vehicleMassRot = Vehicle->getVehicleData()->getRedMassWheel();
45
setCalcType(Vehicle->getVehicleData()->getCalcType());
46
//C# TO C++ CONVERTER NOTE: The following 'switch' operated on a string variable and was converted to C++ 'if-else' logic:
47
// switch (CalcType)
48
//ORIGINAL LINE: case "Conv":
49
if (getCalcType() == "Conv") {
50
setRatedPower(Vehicle->getEngineData()->getICEData()->getPrated());
51
_engineRatedSpeed = Vehicle->getEngineData()->getICEData()->getnrated();
52
_engineIdlingSpeed = Vehicle->getEngineData()->getICEData()->getIdling();
53
}
54
//ORIGINAL LINE: case "HEV":
55
else if (getCalcType() == "HEV") {
56
// Power von beiden zusammen Rest bezogen auf ICE
57
setRatedPower(Vehicle->getEngineData()->getICEData()->getPrated() + Vehicle->getEngineData()->getEMData()->getPrated());
58
_engineRatedSpeed = Vehicle->getEngineData()->getICEData()->getnrated();
59
_engineIdlingSpeed = Vehicle->getEngineData()->getICEData()->getIdling();
60
}
61
//ORIGINAL LINE: case "BEV":
62
else if (getCalcType() == "BEV") {
63
setRatedPower(Vehicle->getEngineData()->getEMData()->getPrated());
64
_engineRatedSpeed = Vehicle->getEngineData()->getEMData()->getnrated();
65
_engineIdlingSpeed = 0;
66
}
67
68
_effectiveWheelDiameter = Vehicle->getVehicleData()->getWheelDiameter();
69
privateHeavyVehicle = Vehicle->getVehicleData()->getMassType() == Constants::HeavyVehicle;
70
setFuelType(Vehicle->getVehicleData()->getFuelType());
71
_axleRatio = Vehicle->getTransmissionData()->getAxelRatio();
72
_auxPower = Vehicle->getAuxiliariesData()->getPauxnorm();
73
74
_pNormV0 = Vehicle->getFLDData()->getP_n_max_v0() / 3.6;
75
_pNormP0 = Vehicle->getFLDData()->getP_n_max_p0();
76
_pNormV1 = Vehicle->getFLDData()->getP_n_max_v1() / 3.6;
77
_pNormP1 = Vehicle->getFLDData()->getP_n_max_p1();
78
79
// Init pollutant identifiers, unit and measures
80
std::vector<std::string> FCvaluesIdentifier;
81
std::vector<std::vector<double> > normalizedFCvaluesMeasures;
82
for (int i = 0; i < (int)headerLineFCvalues.size(); i++) {
83
FCvaluesIdentifier.push_back(headerLineFCvalues[i]);
84
normalizedFCvaluesMeasures.push_back(std::vector<double>());
85
}
86
87
// Init pollutant identifiers, unit and measures
88
std::vector<std::string> pollutantIdentifier;
89
std::vector<std::vector<double> > normalizedPollutantMeasures;
90
for (int i = 0; i < (int)headerLinePollutants.size(); i++) {
91
pollutantIdentifier.push_back(headerLinePollutants[i]);
92
normalizedPollutantMeasures.push_back(std::vector<double>());
93
}
94
95
// Assigning values for speed rotational table
96
_speedPatternRotational = std::vector<double>();
97
for (int i = 0; i < (int)Vehicle->getTransmissionData()->getTransm()["Speed"].size(); i++) {
98
_speedPatternRotational.push_back(Vehicle->getTransmissionData()->getTransm()["Speed"][i] / 3.6);
99
}
100
101
_gearTransmissionCurve = Vehicle->getTransmissionData()->getTransm()["GearRatio"];
102
_speedCurveRotational = Vehicle->getTransmissionData()->getTransm()["RotMassF"];
103
104
// Assigning values for drag table
105
_nNormTable = Vehicle->getFLDData()->getDragCurve()["n_norm"];
106
_dragNormTable = Vehicle->getFLDData()->getDragCurve()["pe_drag_norm"];
107
108
// Looping through matrix and assigning values for FC values
109
_normalizedPowerPatternFCvalues = std::vector<double>();
110
111
int headerFCCount = (int)headerLineFCvalues.size();
112
for (int i = 0; i < (int)matrixFCvalues.size(); i++) {
113
for (int j = 0; j < (int)matrixFCvalues[i].size(); j++) {
114
if ((int)matrixFCvalues[i].size() != headerFCCount + 1) {
115
return;
116
}
117
118
if (j == 0) {
119
_normalizedPowerPatternFCvalues.push_back(matrixFCvalues[i][j]);
120
}
121
else {
122
normalizedFCvaluesMeasures[j - 1].push_back(matrixFCvalues[i][j]);
123
}
124
}
125
}
126
127
_idlingValueFCvalues = std::map<std::string, double>();
128
_normedCepCurveFCvalues = std::map<std::string, std::vector<double> >();
129
130
for (int i = 0; i < (int)headerLineFCvalues.size(); i++) {
131
_normedCepCurveFCvalues.insert(std::make_pair(FCvaluesIdentifier[i], normalizedFCvaluesMeasures[i]));
132
_idlingValueFCvalues.insert(std::make_pair(FCvaluesIdentifier[i], idlingFCvalues[i]));
133
}
134
135
_normalizedPowerPatternPollutants = std::vector<double>();
136
_cepNormalizedCurvePollutants = std::map<std::string, std::vector<double> >();
137
138
int headerCount = (int)headerLinePollutants.size();
139
for (int i = 0; i < (int)matrixPollutants.size(); i++) {
140
for (int j = 0; j < (int)matrixPollutants[i].size(); j++) {
141
if ((int)matrixPollutants[i].size() != headerCount + 1) {
142
return;
143
}
144
145
if (j == 0) {
146
_normalizedPowerPatternPollutants.push_back(matrixPollutants[i][j]);
147
}
148
else {
149
normalizedPollutantMeasures[j - 1].push_back(matrixPollutants[i][j]);
150
}
151
}
152
}
153
154
_idlingValuesPollutants = std::map<std::string, double>();
155
156
for (int i = 0; i < (int)headerLinePollutants.size(); i++) {
157
_cepNormalizedCurvePollutants.insert(std::make_pair(pollutantIdentifier[i], normalizedPollutantMeasures[i]));
158
_idlingValuesPollutants.insert(std::make_pair(pollutantIdentifier[i], idlingPollutants[i]));
159
}
160
161
_FleetMix = std::map<std::string, double>();
162
_FleetMix.insert(std::make_pair(Constants::strGasoline, 0));
163
_FleetMix.insert(std::make_pair(Constants::strDiesel, 0));
164
_FleetMix.insert(std::make_pair(Constants::strCNG, 0));
165
_FleetMix.insert(std::make_pair(Constants::strLPG, 0));
166
}
167
168
const bool& CEP::getHeavyVehicle() const {
169
return privateHeavyVehicle;
170
}
171
172
const std::string& CEP::getFuelType() const {
173
return privateFuelType;
174
}
175
176
void CEP::setFuelType(const std::string& value) {
177
privateFuelType = value;
178
}
179
180
const std::string& CEP::getCalcType() const {
181
return privateCalcType;
182
}
183
184
void CEP::setCalcType(const std::string& value) {
185
privateCalcType = value;
186
}
187
188
const double& CEP::getRatedPower() const {
189
return privateRatedPower;
190
}
191
192
void CEP::setRatedPower(const double& value) {
193
privateRatedPower = value;
194
}
195
196
double CEP::CalcEngPower(double power, const double ratedPower) {
197
if (power < _normalizedPowerPatternFCvalues.front() * ratedPower) {
198
return _normalizedPowerPatternFCvalues.front() * ratedPower;
199
}
200
if (power > _normalizedPowerPatternFCvalues.back() * ratedPower) {
201
return _normalizedPowerPatternFCvalues.back() * ratedPower;
202
}
203
204
return power;
205
}
206
207
double CEP::GetEmission(const std::string& pollutant, double power, double speed, Helpers* VehicleClass, const double drivingPower, const double ratedPower) {
208
//Declaration
209
std::vector<double>* emissionCurve = nullptr;
210
std::vector<double>* powerPattern = nullptr;
211
212
// bisection search to find correct position in power pattern
213
int upperIndex;
214
int lowerIndex;
215
216
double emissionMultiplier = getHeavyVehicle() ? ratedPower : 1.;
217
if (std::abs(speed) <= Constants::ZERO_SPEED_ACCURACY) {
218
if (_cepNormalizedCurvePollutants.find(pollutant) == _cepNormalizedCurvePollutants.end() && _normedCepCurveFCvalues.find(pollutant) == _normedCepCurveFCvalues.end()) {
219
VehicleClass->setErrMsg(std::string("Emission pollutant or fuel value ") + pollutant + std::string(" not found!"));
220
return 0;
221
}
222
223
if (_normedCepCurveFCvalues.find(pollutant) != _normedCepCurveFCvalues.end()) {
224
return _idlingValueFCvalues[pollutant] * ratedPower;
225
}
226
else if (_cepNormalizedCurvePollutants.find(pollutant) != _cepNormalizedCurvePollutants.end()) {
227
return _idlingValuesPollutants[pollutant] * emissionMultiplier;
228
}
229
}
230
231
232
if (_cepNormalizedCurvePollutants.find(pollutant) == _cepNormalizedCurvePollutants.end() && _normedCepCurveFCvalues.find(pollutant) == _normedCepCurveFCvalues.end()) {
233
VehicleClass->setErrMsg(std::string("Emission pollutant or fuel value ") + pollutant + std::string(" not found!"));
234
return 0;
235
}
236
237
double normalizingPower = ratedPower;
238
if (_normedCepCurveFCvalues.find(pollutant) != _normedCepCurveFCvalues.end()) {
239
emissionCurve = &_normedCepCurveFCvalues[pollutant];
240
powerPattern = &_normalizedPowerPatternFCvalues;
241
emissionMultiplier = ratedPower;
242
}
243
else if (_cepNormalizedCurvePollutants.find(pollutant) != _cepNormalizedCurvePollutants.end()) {
244
emissionCurve = &_cepNormalizedCurvePollutants[pollutant];
245
powerPattern = &_normalizedPowerPatternPollutants;
246
if (!getHeavyVehicle()) {
247
normalizingPower = drivingPower;
248
}
249
}
250
251
if (emissionCurve == nullptr || emissionCurve->empty()) {
252
VehicleClass->setErrMsg(std::string("Empty emission curve for ") + pollutant + std::string(" found!"));
253
return 0;
254
}
255
if (emissionCurve->size() == 1) {
256
return emissionCurve->front() * emissionMultiplier;
257
}
258
259
// in case that the demanded power is smaller than the first entry (smallest) in the power pattern the first is returned (should never happen)
260
if (power <= powerPattern->front() * normalizingPower) {
261
return emissionCurve->front() * emissionMultiplier;
262
}
263
264
// if power bigger than all entries in power pattern return the last (should never happen)
265
if (power >= powerPattern->back() * normalizingPower) {
266
return emissionCurve->back() * emissionMultiplier;
267
}
268
269
FindLowerUpperInPattern(lowerIndex, upperIndex, *powerPattern, power, normalizingPower);
270
return Interpolate(power, (*powerPattern)[lowerIndex] * normalizingPower, (*powerPattern)[upperIndex] * normalizingPower, (*emissionCurve)[lowerIndex], (*emissionCurve)[upperIndex]) * emissionMultiplier;
271
}
272
273
double CEP::GetCO2Emission(double _FC, double _CO, double _HC, Helpers* VehicleClass) {
274
//Declaration
275
double fCBr, fCHC, fCCO, fCCO2;
276
277
fCBr = 0;
278
fCHC = 0;
279
fCCO = 0;
280
fCCO2 = 0;
281
282
if (getFuelType() != "Mix") {
283
if (!GetfcVals(getFuelType(), fCBr, fCHC, fCCO, fCCO2, VehicleClass)) {
284
return 0;
285
}
286
}
287
else {
288
if (!CalcfCValMix(fCBr, fCHC, fCCO, fCCO2, VehicleClass)) {
289
return 0;
290
}
291
}
292
293
return (_FC * fCBr - _CO * fCCO - _HC * fCHC) / fCCO2;
294
}
295
296
bool CEP::CalcfCValMix(double& _fCBr, double& _fCHC, double& _fCCO, double& _fCCO2, Helpers* VehicleClass) {
297
//Declaration
298
double Sum = 0;
299
double sumfCBr, sumfCHC, sumfCCO, sumfCCO2;
300
301
//Initialise
302
sumfCBr = 0;
303
sumfCHC = 0;
304
sumfCCO = 0;
305
sumfCCO2 = 0;
306
307
//calculate the sum
308
for (std::map<std::string, double>::const_iterator id = _FleetMix.begin(); id != _FleetMix.end(); ++id) {
309
Sum += _FleetMix[id->first];
310
}
311
312
//Calculate the weighted fuel factors
313
if (Sum <= 0) {
314
VehicleClass->setErrMsg("All propolsion types in the fleetshares file are not known!");
315
return false;
316
}
317
else {
318
for (std::map<std::string, double>::const_iterator id = _FleetMix.begin(); id != _FleetMix.end(); ++id) {
319
if (!GetfcVals(id->first, _fCBr, _fCHC, _fCCO, _fCCO2, VehicleClass)) {
320
return false;
321
}
322
else {
323
sumfCBr += _fCBr * _FleetMix[id->first] / Sum;
324
sumfCHC += _fCHC * _FleetMix[id->first] / Sum;
325
sumfCCO += _fCCO * _FleetMix[id->first] / Sum;
326
sumfCCO2 += _fCCO2 * _FleetMix[id->first] / Sum;
327
}
328
}
329
}
330
//Result values
331
_fCBr = sumfCBr;
332
_fCHC = sumfCHC;
333
_fCCO = sumfCCO;
334
_fCCO2 = sumfCCO2;
335
return true;
336
}
337
338
bool CEP::GetfcVals(const std::string& _fuelTypex, double& _fCBr, double& _fCHC, double& _fCCO, double& _fCCO2, Helpers* VehicleClass) {
339
_fCHC = 0.866;
340
_fCCO = 0.429;
341
_fCCO2 = 0.273;
342
343
//C# TO C++ CONVERTER NOTE: The following 'switch' operated on a string variable and was converted to C++ 'if-else' logic:
344
// switch (_fuelTypex)
345
//ORIGINAL LINE: case Constants.strGasoline:
346
if (_fuelTypex == Constants::strGasoline) {
347
_fCBr = 0.865;
348
}
349
//ORIGINAL LINE: case Constants.strDiesel:
350
else if (_fuelTypex == Constants::strDiesel) {
351
_fCBr = 0.863;
352
}
353
//ORIGINAL LINE: case Constants.strCNG:
354
else if (_fuelTypex == Constants::strCNG) {
355
_fCBr = 0.693;
356
_fCHC = 0.803;
357
}
358
//ORIGINAL LINE: case Constants.strLPG:
359
else if (_fuelTypex == Constants::strLPG) {
360
_fCBr = 0.825;
361
_fCHC = 0.825;
362
}
363
else {
364
VehicleClass->setErrMsg(std::string("The propulsion type is not known! (") + getFuelType() + std::string(")"));
365
return false;
366
}
367
return true;
368
}
369
370
double CEP::getFMot(const double speed, const double ratedPower, const double wheelRadius) {
371
if (speed < 10e-2) {
372
return 0.;
373
}
374
//Declaration
375
int upperIndex;
376
int lowerIndex;
377
378
FindLowerUpperInPattern(lowerIndex, upperIndex, _speedPatternRotational, speed);
379
double iGear = Interpolate(speed, _speedPatternRotational[lowerIndex], _speedPatternRotational[upperIndex], _gearTransmissionCurve[lowerIndex], _gearTransmissionCurve[upperIndex]);
380
381
double iTot = iGear * _axleRatio;
382
383
double n = (30 * speed * iTot) / (wheelRadius * M_PI);
384
double nNorm = (n - _engineIdlingSpeed) / (_engineRatedSpeed - _engineIdlingSpeed);
385
386
FindLowerUpperInPattern(lowerIndex, upperIndex, _nNormTable, nNorm);
387
return (-Interpolate(nNorm, _nNormTable[lowerIndex], _nNormTable[upperIndex], _dragNormTable[lowerIndex], _dragNormTable[upperIndex]) * ratedPower * 1000 / speed) / Constants::getDRIVE_TRAIN_EFFICIENCY();
388
}
389
390
double CEP::GetRotationalCoeffecient(double speed) {
391
//Declaration
392
int upperIndex;
393
int lowerIndex;
394
395
FindLowerUpperInPattern(lowerIndex, upperIndex, _speedPatternRotational, speed);
396
return Interpolate(speed, _speedPatternRotational[lowerIndex], _speedPatternRotational[upperIndex], _speedCurveRotational[lowerIndex], _speedCurveRotational[upperIndex]);
397
}
398
399
void CEP::FindLowerUpperInPattern(int& lowerIndex, int& upperIndex, const std::vector<double>& pattern, double value, double scale) {
400
lowerIndex = 0;
401
upperIndex = 0;
402
403
if (value <= pattern.front() * scale) {
404
lowerIndex = 0;
405
upperIndex = 0;
406
return;
407
}
408
409
if (value >= pattern.back() * scale) {
410
lowerIndex = (int)pattern.size() - 1;
411
upperIndex = (int)pattern.size() - 1;
412
return;
413
}
414
415
// bisection search to find correct position in power pattern
416
int middleIndex = ((int)pattern.size() - 1) / 2;
417
upperIndex = (int)pattern.size() - 1;
418
lowerIndex = 0;
419
420
while (upperIndex - lowerIndex > 1) {
421
if (pattern[middleIndex] * scale == value) {
422
lowerIndex = middleIndex;
423
upperIndex = middleIndex;
424
return;
425
}
426
else if (pattern[middleIndex] * scale < value) {
427
lowerIndex = middleIndex;
428
middleIndex = (upperIndex - lowerIndex) / 2 + lowerIndex;
429
}
430
else {
431
upperIndex = middleIndex;
432
middleIndex = (upperIndex - lowerIndex) / 2 + lowerIndex;
433
}
434
}
435
}
436
437
double CEP::Interpolate(double px, double p1, double p2, double e1, double e2) {
438
if (p2 == p1) {
439
return e1;
440
}
441
442
return e1 + (px - p1) / (p2 - p1) * (e2 - e1);
443
}
444
445
double CEP::GetPMaxNorm(double speed) {
446
// Linear function between v0 and v1, constant elsewhere
447
if (speed <= _pNormV0) {
448
return _pNormP0;
449
}
450
else if (speed >= _pNormV1) {
451
return _pNormP1;
452
}
453
else {
454
return Interpolate(speed, _pNormV0, _pNormV1, _pNormP0, _pNormP1);
455
}
456
}
457
458
void CEP::InitializeInstanceFields() {
459
_massVehicle = 0;
460
_vehicleLoading = 0;
461
_vehicleMassRot = 0;
462
_crossSectionalArea = 0;
463
_cWValue = 0;
464
_resistanceF0 = 0;
465
_resistanceF1 = 0;
466
_resistanceF2 = 0;
467
_resistanceF3 = 0;
468
_resistanceF4 = 0;
469
_axleRatio = 0;
470
_auxPower = 0;
471
_pNormV0 = 0;
472
_pNormP0 = 0;
473
_pNormV1 = 0;
474
_pNormP1 = 0;
475
_engineRatedSpeed = 0;
476
_engineIdlingSpeed = 0;
477
_effectiveWheelDiameter = 0;
478
}
479
}
480
481