Path: blob/main/src/foreign/PHEMlight/V5/cpp/CEPHandler.cpp
169688 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.3// PHEMlight module4// Copyright (C) 2016-2023 Technische Universitaet Graz, https://www.tugraz.at/5// This program and the accompanying materials are made available under the6// terms of the Eclipse Public License 2.0 which is available at7// https://www.eclipse.org/legal/epl-2.0/8// This Source Code may also be made available under the following Secondary9// Licenses when the conditions for such availability set forth in the Eclipse10// Public License 2.0 are satisfied: GNU General Public License, version 211// or later which is available at12// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html13// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later14/****************************************************************************/15/// @file CEPHandler.cpp16/// @author Martin Dippold17/// @author Michael Behrisch18/// @date July 201619///20//21/****************************************************************************/22#include <config.h>2324#include <fstream>25#include <sstream>26#define JSON_USE_IMPLICIT_CONVERSIONS 027#include <foreign/nlohmann/json.hpp>28#include <utils/common/StringUtils.h>29#include "CEPHandler.h"30#include "CEP.h"31#include "Correction.h"32#include "Helpers.h"333435namespace PHEMlightdllV5 {3637CEPHandler::CEPHandler() {38}3940const std::map<std::string, CEP*>& CEPHandler::getCEPS() const {41return _ceps;42}4344bool CEPHandler::GetCEP(std::vector<std::string>& DataPath, Helpers* Helper, Correction* DataCor) {45if (getCEPS().find(Helper->getgClass()) == getCEPS().end()) {46if (!Load(DataPath, Helper, DataCor)) {47return false;48}49}50return true;51}5253bool CEPHandler::CalcCorrection(Correction* DataCor, Helpers* Helper, VEHPHEMLightJSON::Vehicle_Data* vehicle_Data) {54if (DataCor->getUseDet()) {55DataCor->setVehMileage(-1);56if (vehicle_Data->getMileage() > 0.) {57DataCor->setVehMileage(vehicle_Data->getMileage());58}5960if (!DataCor->IniDETfactor(Helper)) {61return false;62}63}64if (DataCor->getUseTNOx()) {65if (!DataCor->IniTNOxfactor(Helper)) {66return false;67}68}6970//Return value71return true;72}7374bool CEPHandler::Load(std::vector<std::string>& DataPath, Helpers* Helper, Correction* DataCor, bool fleetMix) {75//Deklaration76// get string identifier for PHEM emission class77std::string emissionRep = Helper->getgClass();7879// to hold everything.80std::vector<std::vector<double> > matrixFCvalues;81std::vector<std::vector<double> > matrixPollutants;82std::vector<double> idlingValuesFCvalues;83std::vector<double> idlingValuesPollutants;84std::vector<std::string> headerFCvalues;85std::vector<std::string> headerPollutants;86VEHPHEMLightJSON::VEH* Vehicle;8788if (!ReadVehicleFile(DataPath, emissionRep, Helper, fleetMix, Vehicle)) {89delete Vehicle;90return false;91}9293if (DataCor != nullptr) {94if (!CalcCorrection(DataCor, Helper, Vehicle->getVehicleData())) {95delete Vehicle;96return false;97}98}99100if (!ReadEmissionData(true, DataPath, emissionRep, Helper, fleetMix, DataCor, headerFCvalues, matrixFCvalues, idlingValuesFCvalues)) {101delete Vehicle;102return false;103}104if (!ReadEmissionData(false, DataPath, emissionRep, Helper, fleetMix, DataCor, headerPollutants, matrixPollutants, idlingValuesPollutants)) {105delete Vehicle;106return false;107}108109_ceps.insert(std::make_pair(Helper->getgClass(), new CEP(Vehicle, headerFCvalues, matrixFCvalues, headerPollutants, matrixPollutants, idlingValuesFCvalues, idlingValuesPollutants)));110delete Vehicle;111return true;112}113114double json2double(const nlohmann::json& vd, const std::string& key) {115if (vd.contains(key)) {116return vd.at(key).get<double>();117}118return 0.;119}120121bool CEPHandler::ReadVehicleFile(const std::vector<std::string>& DataPath, const std::string& emissionClass, Helpers* Helper, bool /* fleetMix */, VEHPHEMLightJSON::VEH*& Vehicle) {122std::string path = "";123Vehicle = new VEHPHEMLightJSON::VEH();124125//Open file126std::ifstream vehicleReader;127for (std::vector<std::string>::const_iterator i = DataPath.begin(); i != DataPath.end(); i++) {128vehicleReader.open(((*i) + emissionClass + ".PHEMLight.veh").c_str());129if (vehicleReader.good()) {130break;131}132}133if (!vehicleReader.good()) {134Helper->setErrMsg("File does not exist! (" + emissionClass + ".PHEMLight.veh)");135return false;136}137138//**** VEH Datei einlesen ****139nlohmann::json json;140try {141vehicleReader >> json;142} catch (...) {143Helper->setErrMsg("Error during file read! (" + emissionClass + ".PHEMLight.veh)");144return false;145}146147//*** Get the vehicle data148nlohmann::json::iterator vehDataIt = json.find("VehicleData");149if (vehDataIt == json.end()) {150Helper->setErrMsg("No VehicleData in " + emissionClass + ".PHEMLight.veh!");151return false;152}153const nlohmann::json& vd = *vehDataIt;154Vehicle->getVehicleData()->setMassType(vd.contains("MassType") ? vd.at("MassType").get<std::string>() : "LV");155Vehicle->getVehicleData()->setFuelType(vd.contains("FuelType") ? vd.at("FuelType").get<std::string>() : "D");156Vehicle->getVehicleData()->setCalcType(vd.contains("CalcType") ? vd.at("CalcType").get<std::string>() : "Conv");157Vehicle->getVehicleData()->setMass(json2double(vd, "Mass"));158Vehicle->getVehicleData()->setLoading(json2double(vd, "Loading"));159Vehicle->getVehicleData()->setRedMassWheel(json2double(vd, "RedMassWheel"));160Vehicle->getVehicleData()->setWheelDiameter(json2double(vd, "WheelDiameter"));161Vehicle->getVehicleData()->setCw(json2double(vd, "Cw"));162Vehicle->getVehicleData()->setA(json2double(vd, "A"));163Vehicle->getVehicleData()->setMileage(json2double(vd, "Mileage"));164165// Auxiliaries166nlohmann::json::iterator auxDataIt = json.find("AuxiliariesData");167if (auxDataIt == json.end() || !auxDataIt->contains("Pauxnorm")) {168Vehicle->getAuxiliariesData()->setPauxnorm(0.);169} else {170Vehicle->getAuxiliariesData()->setPauxnorm(auxDataIt->at("Pauxnorm").get<double>());171}172173// Engine Data174nlohmann::json::iterator engDataIt = json.find("EngineData");175if (engDataIt == json.end() || !engDataIt->contains("ICEData") || !engDataIt->contains("EMData")) {176Helper->setErrMsg("Incomplete EngineData in " + emissionClass + ".PHEMLight.veh!");177return false;178}179const nlohmann::json& iced = (*engDataIt)["ICEData"];180const nlohmann::json& emd = (*engDataIt)["EMData"];181Vehicle->getEngineData()->getICEData()->setPrated(json2double(iced, "Prated"));182Vehicle->getEngineData()->getICEData()->setnrated(json2double(iced, "nrated"));183Vehicle->getEngineData()->getICEData()->setIdling(json2double(iced, "Idling"));184Vehicle->getEngineData()->getEMData()->setPrated(json2double(emd, "Prated"));185Vehicle->getEngineData()->getEMData()->setnrated(json2double(emd, "nrated"));186187// Rolling resistance188nlohmann::json::iterator rrDataIt = json.find("RollingResData");189if (rrDataIt == json.end()) {190Helper->setErrMsg("No RollingResData in " + emissionClass + ".PHEMLight.veh!");191return false;192}193const nlohmann::json& rrd = *rrDataIt;194Vehicle->getRollingResData()->setFr0(json2double(rrd, "Fr0"));195Vehicle->getRollingResData()->setFr1(json2double(rrd, "Fr1"));196Vehicle->getRollingResData()->setFr2(json2double(rrd, "Fr2"));197Vehicle->getRollingResData()->setFr3(json2double(rrd, "Fr3"));198Vehicle->getRollingResData()->setFr4(json2double(rrd, "Fr4"));199200// Transmission201nlohmann::json::iterator trDataIt = json.find("TransmissionData");202if (trDataIt == json.end()) {203Helper->setErrMsg("No TransmissionData in " + emissionClass + ".PHEMLight.veh!");204return false;205}206Vehicle->getTransmissionData()->setAxelRatio(json2double(*trDataIt, "AxelRatio"));207nlohmann::json::iterator transmIt = trDataIt->find("Transm");208if (transmIt == trDataIt->end()) {209Helper->setErrMsg(std::string("Transmission ratios missing in vehicle file! Calculation stopped! (") + path + std::string(")"));210return false;211} else {212if (!transmIt->contains("Speed")) {213Helper->setErrMsg(std::string("No Speed signal in transmission data given! Calculation stopped! (") + path + std::string(")"));214return false;215}216if (!transmIt->contains("GearRatio")) {217Helper->setErrMsg(std::string("No GearRatio signal in transmission data given! Calculation stopped! (") + path + std::string(")"));218return false;219}220if (!transmIt->contains("RotMassF")) {221Helper->setErrMsg(std::string("No RotMassF signal in transmission data given! Calculation stopped! (") + path + std::string(")"));222return false;223}224}225Vehicle->getTransmissionData()->setTransm(transmIt->get<std::map<std::string, std::vector<double> > >());226227// Full load and drag228nlohmann::json::iterator fldDataIt = json.find("FLDData");229if (fldDataIt == json.end()) {230Helper->setErrMsg("No FLDData in " + emissionClass + ".PHEMLight.veh!");231return false;232}233const nlohmann::json& fld = *fldDataIt;234Vehicle->getFLDData()->setP_n_max_v0(json2double(fld, "P_n_max_v0"));235Vehicle->getFLDData()->setP_n_max_p0(json2double(fld, "P_n_max_p0"));236Vehicle->getFLDData()->setP_n_max_v1(json2double(fld, "P_n_max_v1"));237Vehicle->getFLDData()->setP_n_max_p1(json2double(fld, "P_n_max_p1"));238nlohmann::json::iterator dragIt = fldDataIt->find("DragCurve");239if (dragIt == fldDataIt->end()) {240Helper->setErrMsg(std::string("Drag curve missing in vehicle file! Calculation stopped! (") + path + std::string(")"));241return false;242} else {243if (!dragIt->contains("n_norm")) {244Helper->setErrMsg(std::string("No n_norm signal in drag curve data given! Calculation stopped! (") + path + std::string(")"));245return false;246}247if (!dragIt->contains("pe_drag_norm")) {248Helper->setErrMsg(std::string("No pe_drag_norm signal in drag curve data given! Calculation stopped! (") + path + std::string(")"));249return false;250}251}252Vehicle->getFLDData()->setDragCurve(dragIt->get<std::map<std::string, std::vector<double> > >());253254return true;255}256257bool CEPHandler::ReadEmissionData(bool readFC, const std::vector<std::string>& DataPath, const std::string& emissionClass, Helpers* Helper, bool /* fleetMix */, Correction* DataCor, std::vector<std::string>& header, std::vector<std::vector<double> >& matrix, std::vector<double>& idlingValues) {258// declare file stream259std::string line;260std::string path = "";261header = std::vector<std::string>();262matrix = std::vector<std::vector<double> >();263idlingValues = std::vector<double>();264265std::string pollutantExtension = "";266if (readFC) {267pollutantExtension += std::string("_FC");268}269270std::ifstream fileReader;271for (std::vector<std::string>::const_iterator i = DataPath.begin(); i != DataPath.end(); i++) {272fileReader.open(((*i) + emissionClass + pollutantExtension + ".csv").c_str());273if (fileReader.good()) {274break;275}276}277if (!fileReader.good()) {278Helper->setErrMsg("File does not exist! (" + emissionClass + pollutantExtension + ".csv)");279return false;280}281282// read header line for pollutant identifiers283if ((line = ReadLine(fileReader)) != "") {284const std::vector<std::string>& entries = split(line, ',');285// skip first entry "Pe"286for (int i = 1; i < (int)entries.size(); i++) {287header.push_back(entries[i]);288}289}290291// skip units292ReadLine(fileReader);293294// skip comment295ReadLine(fileReader);296297//readIdlingValues298line = ReadLine(fileReader);299300std::vector<std::string> stringIdlings = split(line, ',');301stringIdlings.erase(stringIdlings.begin());302303idlingValues = todoubleList(stringIdlings);304305while ((line = ReadLine(fileReader)) != "") {306matrix.push_back(todoubleList(split(line, ',')));307}308309//Data correction (Det & TNOx)310if (!CorrectEmissionData(DataCor, header, matrix, idlingValues)) {311Helper->setErrMsg("Error in correction calculation");312return false;313}314315//Return value316return true;317}318319bool CEPHandler::CorrectEmissionData(Correction* DataCor, std::vector<std::string>& header, std::vector<std::vector<double> >& matrix, std::vector<double>& idlingValues) {320for (int i = 0; i < (int)header.size(); i++) {321double CorF = GetDetTempCor(DataCor, header[i]);322if (CorF != 1) {323for (int j = 0; j < (int)matrix.size(); j++) {324matrix[j][i + 1] *= CorF;325}326idlingValues[i] *= CorF;327}328}329330//Return value331return true;332}333334double CEPHandler::GetDetTempCor(Correction* DataCor, const std::string& Emi) {335//Initialisation336double CorF = 1;337std::string emi = Emi;338std::transform(emi.begin(), emi.end(), emi.begin(), [](char c) { return (char)::toupper(c); });339340if (DataCor != 0) {341if (DataCor->getUseDet() && DataCor->DETFactors.count(emi) > 0) {342CorF += DataCor->DETFactors[emi] - 1;343}344if (DataCor->getUseTNOx()) {345if (emi.find("NOX") != std::string::npos) {346CorF += (DataCor->getTNOxFactor() - 1);347}348}349}350351//Return value352return CorF;353}354355const std::vector<std::string> CEPHandler::split(const std::string& s, char delim) {356std::vector<std::string> elems;357std::stringstream ss(s);358std::string item;359while (std::getline(ss, item, delim)) {360elems.push_back(item);361}362return elems;363}364365double CEPHandler::todouble(const std::string& s) {366std::stringstream ss(s);367double item;368ss >> item;369return item;370}371372std::vector<double> CEPHandler::todoubleList(const std::vector<std::string>& s) {373std::vector<double> result;374for (std::vector<std::string>::const_iterator i = s.begin(); i != s.end(); ++i) {375result.push_back(todouble(*i));376}377return result;378}379380std::string CEPHandler::ReadLine(std::ifstream& s) {381std::string line;382std::getline(s, line);383size_t lastNWChar = line.find_last_not_of(" \n\r\t");384if (lastNWChar != std::string::npos) {385line.erase(lastNWChar + 1);386}387return line;388}389390const std::string& VEHPHEMLightJSON::VEH::getType() const {391return privateType;392}393394void VEHPHEMLightJSON::VEH::setType(const std::string& value) {395privateType = value;396}397398const std::string& VEHPHEMLightJSON::VEH::getVersion() const {399return privateVersion;400}401402void VEHPHEMLightJSON::VEH::setVersion(const std::string& value) {403privateVersion = value;404}405406VEHPHEMLightJSON::Vehicle_Data* VEHPHEMLightJSON::VEH::getVehicleData() {407return &privateVehicleData;408}409410VEHPHEMLightJSON::Aux_Data* VEHPHEMLightJSON::VEH::getAuxiliariesData() {411return &privateAuxiliariesData;412}413414VEHPHEMLightJSON::Engine_Data* VEHPHEMLightJSON::VEH::getEngineData() {415return &privateEngineData;416}417418VEHPHEMLightJSON::Rollres_Data* VEHPHEMLightJSON::VEH::getRollingResData() {419return &privateRollingResData;420}421422VEHPHEMLightJSON::FullLoadDrag_Data* VEHPHEMLightJSON::VEH::getFLDData() {423return &privateFLDData;424}425426VEHPHEMLightJSON::Transmission_Data* VEHPHEMLightJSON::VEH::getTransmissionData() {427return &privateTransmissionData;428}429430const std::string& VEHPHEMLightJSON::Vehicle_Data::getMassType() const {431return privateMassType;432}433434void VEHPHEMLightJSON::Vehicle_Data::setMassType(const std::string& value) {435privateMassType = value;436}437438const std::string& VEHPHEMLightJSON::Vehicle_Data::getFuelType() const {439return privateFuelType;440}441442void VEHPHEMLightJSON::Vehicle_Data::setFuelType(const std::string& value) {443privateFuelType = value;444}445446const std::string& VEHPHEMLightJSON::Vehicle_Data::getCalcType() const {447return privateCalcType;448}449450void VEHPHEMLightJSON::Vehicle_Data::setCalcType(const std::string& value) {451privateCalcType = value;452}453454const double& VEHPHEMLightJSON::Vehicle_Data::getMass() const {455return privateMass;456}457458void VEHPHEMLightJSON::Vehicle_Data::setMass(const double& value) {459privateMass = value;460}461462const double& VEHPHEMLightJSON::Vehicle_Data::getLoading() const {463return privateLoading;464}465466void VEHPHEMLightJSON::Vehicle_Data::setLoading(const double& value) {467privateLoading = value;468}469470const double& VEHPHEMLightJSON::Vehicle_Data::getRedMassWheel() const {471return privateRedMassWheel;472}473474void VEHPHEMLightJSON::Vehicle_Data::setRedMassWheel(const double& value) {475privateRedMassWheel = value;476}477478const double& VEHPHEMLightJSON::Vehicle_Data::getWheelDiameter() const {479return privateWheelDiameter;480}481482void VEHPHEMLightJSON::Vehicle_Data::setWheelDiameter(const double& value) {483privateWheelDiameter = value;484}485486const double& VEHPHEMLightJSON::Vehicle_Data::getCw() const {487return privateCw;488}489490void VEHPHEMLightJSON::Vehicle_Data::setCw(const double& value) {491privateCw = value;492}493494const double& VEHPHEMLightJSON::Vehicle_Data::getA() const {495return privateA;496}497498void VEHPHEMLightJSON::Vehicle_Data::setA(const double& value) {499privateA = value;500}501502const double& VEHPHEMLightJSON::Vehicle_Data::getMileage() const {503return privateMileage;504}505506void VEHPHEMLightJSON::Vehicle_Data::setMileage(const double& value) {507privateMileage = value;508}509510const double& VEHPHEMLightJSON::Rollres_Data::getFr0() const {511return privateFr0;512}513514void VEHPHEMLightJSON::Rollres_Data::setFr0(const double& value) {515privateFr0 = value;516}517518const double& VEHPHEMLightJSON::Rollres_Data::getFr1() const {519return privateFr1;520}521522void VEHPHEMLightJSON::Rollres_Data::setFr1(const double& value) {523privateFr1 = value;524}525526const double& VEHPHEMLightJSON::Rollres_Data::getFr2() const {527return privateFr2;528}529530void VEHPHEMLightJSON::Rollres_Data::setFr2(const double& value) {531privateFr2 = value;532}533534const double& VEHPHEMLightJSON::Rollres_Data::getFr3() const {535return privateFr3;536}537538void VEHPHEMLightJSON::Rollres_Data::setFr3(const double& value) {539privateFr3 = value;540}541542const double& VEHPHEMLightJSON::Rollres_Data::getFr4() const {543return privateFr4;544}545546void VEHPHEMLightJSON::Rollres_Data::setFr4(const double& value) {547privateFr4 = value;548}549550VEHPHEMLightJSON::ICE_Data* VEHPHEMLightJSON::Engine_Data::getICEData() {551return &privateICEData;552}553554VEHPHEMLightJSON::EM_Data* VEHPHEMLightJSON::Engine_Data::getEMData() {555return &privateEMData;556}557558const double& VEHPHEMLightJSON::ICE_Data::getPrated() const {559return privatePrated;560}561562void VEHPHEMLightJSON::ICE_Data::setPrated(const double& value) {563privatePrated = value;564}565566const double& VEHPHEMLightJSON::ICE_Data::getnrated() const {567return privatenrated;568}569570void VEHPHEMLightJSON::ICE_Data::setnrated(const double& value) {571privatenrated = value;572}573574const double& VEHPHEMLightJSON::ICE_Data::getIdling() const {575return privateIdling;576}577578void VEHPHEMLightJSON::ICE_Data::setIdling(const double& value) {579privateIdling = value;580}581582const double& VEHPHEMLightJSON::EM_Data::getPrated() const {583return privatePrated;584}585586void VEHPHEMLightJSON::EM_Data::setPrated(const double& value) {587privatePrated = value;588}589590const double& VEHPHEMLightJSON::EM_Data::getnrated() const {591return privatenrated;592}593594void VEHPHEMLightJSON::EM_Data::setnrated(const double& value) {595privatenrated = value;596}597598const double& VEHPHEMLightJSON::Aux_Data::getPauxnorm() const {599return privatePauxnorm;600}601602void VEHPHEMLightJSON::Aux_Data::setPauxnorm(const double& value) {603privatePauxnorm = value;604}605606const double& VEHPHEMLightJSON::FullLoadDrag_Data::getP_n_max_v0() const {607return privateP_n_max_v0;608}609610void VEHPHEMLightJSON::FullLoadDrag_Data::setP_n_max_v0(const double& value) {611privateP_n_max_v0 = value;612}613614const double& VEHPHEMLightJSON::FullLoadDrag_Data::getP_n_max_p0() const {615return privateP_n_max_p0;616}617618void VEHPHEMLightJSON::FullLoadDrag_Data::setP_n_max_p0(const double& value) {619privateP_n_max_p0 = value;620}621622const double& VEHPHEMLightJSON::FullLoadDrag_Data::getP_n_max_v1() const {623return privateP_n_max_v1;624}625626void VEHPHEMLightJSON::FullLoadDrag_Data::setP_n_max_v1(const double& value) {627privateP_n_max_v1 = value;628}629630const double& VEHPHEMLightJSON::FullLoadDrag_Data::getP_n_max_p1() const {631return privateP_n_max_p1;632}633634void VEHPHEMLightJSON::FullLoadDrag_Data::setP_n_max_p1(const double& value) {635privateP_n_max_p1 = value;636}637638std::map<std::string, std::vector<double> >& VEHPHEMLightJSON::FullLoadDrag_Data::getDragCurve() {639return privateDragCurve;640}641642void VEHPHEMLightJSON::FullLoadDrag_Data::setDragCurve(const std::map<std::string, std::vector<double> >& value) {643privateDragCurve = value;644}645646VEHPHEMLightJSON::FullLoadDrag_Data::FullLoadDrag_Data() {647setDragCurve(std::map<std::string, std::vector<double> >());648}649650const double& VEHPHEMLightJSON::Transmission_Data::getAxelRatio() const {651return privateAxelRatio;652}653654void VEHPHEMLightJSON::Transmission_Data::setAxelRatio(const double& value) {655privateAxelRatio = value;656}657658std::map<std::string, std::vector<double> >& VEHPHEMLightJSON::Transmission_Data::getTransm() {659return privateTransm;660}661662void VEHPHEMLightJSON::Transmission_Data::setTransm(const std::map<std::string, std::vector<double> >& value) {663privateTransm = value;664}665666VEHPHEMLightJSON::Transmission_Data::Transmission_Data() {667setTransm(std::map<std::string, std::vector<double> >());668}669}670671672