#include <config.h>
#include "CEP.h"
#include "CEPHandler.h"
#include "Constants.h"
#include "Helpers.h"
namespace PHEMlightdllV5 {
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) {
InitializeInstanceFields();
_resistanceF0 = Vehicle->getRollingResData()->getFr0();
_resistanceF1 = Vehicle->getRollingResData()->getFr1();
_resistanceF2 = Vehicle->getRollingResData()->getFr2();
_resistanceF3 = Vehicle->getRollingResData()->getFr3();
_resistanceF4 = Vehicle->getRollingResData()->getFr4();
_cWValue = Vehicle->getVehicleData()->getCw();
_crossSectionalArea = Vehicle->getVehicleData()->getA();
_massVehicle = Vehicle->getVehicleData()->getMass();
_vehicleLoading = Vehicle->getVehicleData()->getLoading();
_vehicleMassRot = Vehicle->getVehicleData()->getRedMassWheel();
setCalcType(Vehicle->getVehicleData()->getCalcType());
if (getCalcType() == "Conv") {
setRatedPower(Vehicle->getEngineData()->getICEData()->getPrated());
_engineRatedSpeed = Vehicle->getEngineData()->getICEData()->getnrated();
_engineIdlingSpeed = Vehicle->getEngineData()->getICEData()->getIdling();
}
else if (getCalcType() == "HEV") {
setRatedPower(Vehicle->getEngineData()->getICEData()->getPrated() + Vehicle->getEngineData()->getEMData()->getPrated());
_engineRatedSpeed = Vehicle->getEngineData()->getICEData()->getnrated();
_engineIdlingSpeed = Vehicle->getEngineData()->getICEData()->getIdling();
}
else if (getCalcType() == "BEV") {
setRatedPower(Vehicle->getEngineData()->getEMData()->getPrated());
_engineRatedSpeed = Vehicle->getEngineData()->getEMData()->getnrated();
_engineIdlingSpeed = 0;
}
_effectiveWheelDiameter = Vehicle->getVehicleData()->getWheelDiameter();
privateHeavyVehicle = Vehicle->getVehicleData()->getMassType() == Constants::HeavyVehicle;
setFuelType(Vehicle->getVehicleData()->getFuelType());
_axleRatio = Vehicle->getTransmissionData()->getAxelRatio();
_auxPower = Vehicle->getAuxiliariesData()->getPauxnorm();
_pNormV0 = Vehicle->getFLDData()->getP_n_max_v0() / 3.6;
_pNormP0 = Vehicle->getFLDData()->getP_n_max_p0();
_pNormV1 = Vehicle->getFLDData()->getP_n_max_v1() / 3.6;
_pNormP1 = Vehicle->getFLDData()->getP_n_max_p1();
std::vector<std::string> FCvaluesIdentifier;
std::vector<std::vector<double> > normalizedFCvaluesMeasures;
for (int i = 0; i < (int)headerLineFCvalues.size(); i++) {
FCvaluesIdentifier.push_back(headerLineFCvalues[i]);
normalizedFCvaluesMeasures.push_back(std::vector<double>());
}
std::vector<std::string> pollutantIdentifier;
std::vector<std::vector<double> > normalizedPollutantMeasures;
for (int i = 0; i < (int)headerLinePollutants.size(); i++) {
pollutantIdentifier.push_back(headerLinePollutants[i]);
normalizedPollutantMeasures.push_back(std::vector<double>());
}
_speedPatternRotational = std::vector<double>();
for (int i = 0; i < (int)Vehicle->getTransmissionData()->getTransm()["Speed"].size(); i++) {
_speedPatternRotational.push_back(Vehicle->getTransmissionData()->getTransm()["Speed"][i] / 3.6);
}
_gearTransmissionCurve = Vehicle->getTransmissionData()->getTransm()["GearRatio"];
_speedCurveRotational = Vehicle->getTransmissionData()->getTransm()["RotMassF"];
_nNormTable = Vehicle->getFLDData()->getDragCurve()["n_norm"];
_dragNormTable = Vehicle->getFLDData()->getDragCurve()["pe_drag_norm"];
_normalizedPowerPatternFCvalues = std::vector<double>();
int headerFCCount = (int)headerLineFCvalues.size();
for (int i = 0; i < (int)matrixFCvalues.size(); i++) {
for (int j = 0; j < (int)matrixFCvalues[i].size(); j++) {
if ((int)matrixFCvalues[i].size() != headerFCCount + 1) {
return;
}
if (j == 0) {
_normalizedPowerPatternFCvalues.push_back(matrixFCvalues[i][j]);
}
else {
normalizedFCvaluesMeasures[j - 1].push_back(matrixFCvalues[i][j]);
}
}
}
_idlingValueFCvalues = std::map<std::string, double>();
_normedCepCurveFCvalues = std::map<std::string, std::vector<double> >();
for (int i = 0; i < (int)headerLineFCvalues.size(); i++) {
_normedCepCurveFCvalues.insert(std::make_pair(FCvaluesIdentifier[i], normalizedFCvaluesMeasures[i]));
_idlingValueFCvalues.insert(std::make_pair(FCvaluesIdentifier[i], idlingFCvalues[i]));
}
_normalizedPowerPatternPollutants = std::vector<double>();
_cepNormalizedCurvePollutants = std::map<std::string, std::vector<double> >();
int headerCount = (int)headerLinePollutants.size();
for (int i = 0; i < (int)matrixPollutants.size(); i++) {
for (int j = 0; j < (int)matrixPollutants[i].size(); j++) {
if ((int)matrixPollutants[i].size() != headerCount + 1) {
return;
}
if (j == 0) {
_normalizedPowerPatternPollutants.push_back(matrixPollutants[i][j]);
}
else {
normalizedPollutantMeasures[j - 1].push_back(matrixPollutants[i][j]);
}
}
}
_idlingValuesPollutants = std::map<std::string, double>();
for (int i = 0; i < (int)headerLinePollutants.size(); i++) {
_cepNormalizedCurvePollutants.insert(std::make_pair(pollutantIdentifier[i], normalizedPollutantMeasures[i]));
_idlingValuesPollutants.insert(std::make_pair(pollutantIdentifier[i], idlingPollutants[i]));
}
_FleetMix = std::map<std::string, double>();
_FleetMix.insert(std::make_pair(Constants::strGasoline, 0));
_FleetMix.insert(std::make_pair(Constants::strDiesel, 0));
_FleetMix.insert(std::make_pair(Constants::strCNG, 0));
_FleetMix.insert(std::make_pair(Constants::strLPG, 0));
}
const bool& CEP::getHeavyVehicle() const {
return privateHeavyVehicle;
}
const std::string& CEP::getFuelType() const {
return privateFuelType;
}
void CEP::setFuelType(const std::string& value) {
privateFuelType = value;
}
const std::string& CEP::getCalcType() const {
return privateCalcType;
}
void CEP::setCalcType(const std::string& value) {
privateCalcType = value;
}
const double& CEP::getRatedPower() const {
return privateRatedPower;
}
void CEP::setRatedPower(const double& value) {
privateRatedPower = value;
}
double CEP::CalcEngPower(double power, const double ratedPower) {
if (power < _normalizedPowerPatternFCvalues.front() * ratedPower) {
return _normalizedPowerPatternFCvalues.front() * ratedPower;
}
if (power > _normalizedPowerPatternFCvalues.back() * ratedPower) {
return _normalizedPowerPatternFCvalues.back() * ratedPower;
}
return power;
}
double CEP::GetEmission(const std::string& pollutant, double power, double speed, Helpers* VehicleClass, const double drivingPower, const double ratedPower) {
std::vector<double>* emissionCurve = nullptr;
std::vector<double>* powerPattern = nullptr;
int upperIndex;
int lowerIndex;
double emissionMultiplier = getHeavyVehicle() ? ratedPower : 1.;
if (std::abs(speed) <= Constants::ZERO_SPEED_ACCURACY) {
if (_cepNormalizedCurvePollutants.find(pollutant) == _cepNormalizedCurvePollutants.end() && _normedCepCurveFCvalues.find(pollutant) == _normedCepCurveFCvalues.end()) {
VehicleClass->setErrMsg(std::string("Emission pollutant or fuel value ") + pollutant + std::string(" not found!"));
return 0;
}
if (_normedCepCurveFCvalues.find(pollutant) != _normedCepCurveFCvalues.end()) {
return _idlingValueFCvalues[pollutant] * ratedPower;
}
else if (_cepNormalizedCurvePollutants.find(pollutant) != _cepNormalizedCurvePollutants.end()) {
return _idlingValuesPollutants[pollutant] * emissionMultiplier;
}
}
if (_cepNormalizedCurvePollutants.find(pollutant) == _cepNormalizedCurvePollutants.end() && _normedCepCurveFCvalues.find(pollutant) == _normedCepCurveFCvalues.end()) {
VehicleClass->setErrMsg(std::string("Emission pollutant or fuel value ") + pollutant + std::string(" not found!"));
return 0;
}
double normalizingPower = ratedPower;
if (_normedCepCurveFCvalues.find(pollutant) != _normedCepCurveFCvalues.end()) {
emissionCurve = &_normedCepCurveFCvalues[pollutant];
powerPattern = &_normalizedPowerPatternFCvalues;
emissionMultiplier = ratedPower;
}
else if (_cepNormalizedCurvePollutants.find(pollutant) != _cepNormalizedCurvePollutants.end()) {
emissionCurve = &_cepNormalizedCurvePollutants[pollutant];
powerPattern = &_normalizedPowerPatternPollutants;
if (!getHeavyVehicle()) {
normalizingPower = drivingPower;
}
}
if (emissionCurve == nullptr || emissionCurve->empty()) {
VehicleClass->setErrMsg(std::string("Empty emission curve for ") + pollutant + std::string(" found!"));
return 0;
}
if (emissionCurve->size() == 1) {
return emissionCurve->front() * emissionMultiplier;
}
if (power <= powerPattern->front() * normalizingPower) {
return emissionCurve->front() * emissionMultiplier;
}
if (power >= powerPattern->back() * normalizingPower) {
return emissionCurve->back() * emissionMultiplier;
}
FindLowerUpperInPattern(lowerIndex, upperIndex, *powerPattern, power, normalizingPower);
return Interpolate(power, (*powerPattern)[lowerIndex] * normalizingPower, (*powerPattern)[upperIndex] * normalizingPower, (*emissionCurve)[lowerIndex], (*emissionCurve)[upperIndex]) * emissionMultiplier;
}
double CEP::GetCO2Emission(double _FC, double _CO, double _HC, Helpers* VehicleClass) {
double fCBr, fCHC, fCCO, fCCO2;
fCBr = 0;
fCHC = 0;
fCCO = 0;
fCCO2 = 0;
if (getFuelType() != "Mix") {
if (!GetfcVals(getFuelType(), fCBr, fCHC, fCCO, fCCO2, VehicleClass)) {
return 0;
}
}
else {
if (!CalcfCValMix(fCBr, fCHC, fCCO, fCCO2, VehicleClass)) {
return 0;
}
}
return (_FC * fCBr - _CO * fCCO - _HC * fCHC) / fCCO2;
}
bool CEP::CalcfCValMix(double& _fCBr, double& _fCHC, double& _fCCO, double& _fCCO2, Helpers* VehicleClass) {
double Sum = 0;
double sumfCBr, sumfCHC, sumfCCO, sumfCCO2;
sumfCBr = 0;
sumfCHC = 0;
sumfCCO = 0;
sumfCCO2 = 0;
for (std::map<std::string, double>::const_iterator id = _FleetMix.begin(); id != _FleetMix.end(); ++id) {
Sum += _FleetMix[id->first];
}
if (Sum <= 0) {
VehicleClass->setErrMsg("All propolsion types in the fleetshares file are not known!");
return false;
}
else {
for (std::map<std::string, double>::const_iterator id = _FleetMix.begin(); id != _FleetMix.end(); ++id) {
if (!GetfcVals(id->first, _fCBr, _fCHC, _fCCO, _fCCO2, VehicleClass)) {
return false;
}
else {
sumfCBr += _fCBr * _FleetMix[id->first] / Sum;
sumfCHC += _fCHC * _FleetMix[id->first] / Sum;
sumfCCO += _fCCO * _FleetMix[id->first] / Sum;
sumfCCO2 += _fCCO2 * _FleetMix[id->first] / Sum;
}
}
}
_fCBr = sumfCBr;
_fCHC = sumfCHC;
_fCCO = sumfCCO;
_fCCO2 = sumfCCO2;
return true;
}
bool CEP::GetfcVals(const std::string& _fuelTypex, double& _fCBr, double& _fCHC, double& _fCCO, double& _fCCO2, Helpers* VehicleClass) {
_fCHC = 0.866;
_fCCO = 0.429;
_fCCO2 = 0.273;
if (_fuelTypex == Constants::strGasoline) {
_fCBr = 0.865;
}
else if (_fuelTypex == Constants::strDiesel) {
_fCBr = 0.863;
}
else if (_fuelTypex == Constants::strCNG) {
_fCBr = 0.693;
_fCHC = 0.803;
}
else if (_fuelTypex == Constants::strLPG) {
_fCBr = 0.825;
_fCHC = 0.825;
}
else {
VehicleClass->setErrMsg(std::string("The propulsion type is not known! (") + getFuelType() + std::string(")"));
return false;
}
return true;
}
double CEP::getFMot(const double speed, const double ratedPower, const double wheelRadius) {
if (speed < 10e-2) {
return 0.;
}
int upperIndex;
int lowerIndex;
FindLowerUpperInPattern(lowerIndex, upperIndex, _speedPatternRotational, speed);
double iGear = Interpolate(speed, _speedPatternRotational[lowerIndex], _speedPatternRotational[upperIndex], _gearTransmissionCurve[lowerIndex], _gearTransmissionCurve[upperIndex]);
double iTot = iGear * _axleRatio;
double n = (30 * speed * iTot) / (wheelRadius * M_PI);
double nNorm = (n - _engineIdlingSpeed) / (_engineRatedSpeed - _engineIdlingSpeed);
FindLowerUpperInPattern(lowerIndex, upperIndex, _nNormTable, nNorm);
return (-Interpolate(nNorm, _nNormTable[lowerIndex], _nNormTable[upperIndex], _dragNormTable[lowerIndex], _dragNormTable[upperIndex]) * ratedPower * 1000 / speed) / Constants::getDRIVE_TRAIN_EFFICIENCY();
}
double CEP::GetRotationalCoeffecient(double speed) {
int upperIndex;
int lowerIndex;
FindLowerUpperInPattern(lowerIndex, upperIndex, _speedPatternRotational, speed);
return Interpolate(speed, _speedPatternRotational[lowerIndex], _speedPatternRotational[upperIndex], _speedCurveRotational[lowerIndex], _speedCurveRotational[upperIndex]);
}
void CEP::FindLowerUpperInPattern(int& lowerIndex, int& upperIndex, const std::vector<double>& pattern, double value, double scale) {
lowerIndex = 0;
upperIndex = 0;
if (value <= pattern.front() * scale) {
lowerIndex = 0;
upperIndex = 0;
return;
}
if (value >= pattern.back() * scale) {
lowerIndex = (int)pattern.size() - 1;
upperIndex = (int)pattern.size() - 1;
return;
}
int middleIndex = ((int)pattern.size() - 1) / 2;
upperIndex = (int)pattern.size() - 1;
lowerIndex = 0;
while (upperIndex - lowerIndex > 1) {
if (pattern[middleIndex] * scale == value) {
lowerIndex = middleIndex;
upperIndex = middleIndex;
return;
}
else if (pattern[middleIndex] * scale < value) {
lowerIndex = middleIndex;
middleIndex = (upperIndex - lowerIndex) / 2 + lowerIndex;
}
else {
upperIndex = middleIndex;
middleIndex = (upperIndex - lowerIndex) / 2 + lowerIndex;
}
}
}
double CEP::Interpolate(double px, double p1, double p2, double e1, double e2) {
if (p2 == p1) {
return e1;
}
return e1 + (px - p1) / (p2 - p1) * (e2 - e1);
}
double CEP::GetPMaxNorm(double speed) {
if (speed <= _pNormV0) {
return _pNormP0;
}
else if (speed >= _pNormV1) {
return _pNormP1;
}
else {
return Interpolate(speed, _pNormV0, _pNormV1, _pNormP0, _pNormP1);
}
}
void CEP::InitializeInstanceFields() {
_massVehicle = 0;
_vehicleLoading = 0;
_vehicleMassRot = 0;
_crossSectionalArea = 0;
_cWValue = 0;
_resistanceF0 = 0;
_resistanceF1 = 0;
_resistanceF2 = 0;
_resistanceF3 = 0;
_resistanceF4 = 0;
_axleRatio = 0;
_auxPower = 0;
_pNormV0 = 0;
_pNormP0 = 0;
_pNormV1 = 0;
_pNormP1 = 0;
_engineRatedSpeed = 0;
_engineIdlingSpeed = 0;
_effectiveWheelDiameter = 0;
}
}