LCOV - code coverage report
Current view: top level - src/tools - emissionsMap_main.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 70.0 % 140 98
Test Date: 2025-12-06 15:35:27 Functions: 100.0 % 2 2

            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    emissionsMap_main.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Michael Behrisch
      17              : /// @date    Wed, 21.08.2013
      18              : ///
      19              : // Main for an emissions map writer
      20              : /****************************************************************************/
      21              : #include <config.h>
      22              : 
      23              : #ifdef HAVE_VERSION_H
      24              : #include <version.h>
      25              : #endif
      26              : 
      27              : #include <iostream>
      28              : #include <string>
      29              : #include <ctime>
      30              : #include <memory>
      31              : #if __cplusplus >= 201703L
      32              : #if __has_include(<filesystem>)
      33              : #include <filesystem>
      34              : namespace fs = std::filesystem;
      35              : #elif __has_include(<experimental/filesystem>)
      36              : #include <experimental/filesystem>
      37              : namespace fs = std::experimental::filesystem;
      38              : #endif
      39              : #endif
      40              : #include <utils/common/MsgHandler.h>
      41              : #include <utils/common/StringUtils.h>
      42              : #include <utils/options/Option.h>
      43              : #include <utils/options/OptionsCont.h>
      44              : #include <utils/options/OptionsIO.h>
      45              : #include <utils/common/UtilExceptions.h>
      46              : #include <utils/emissions/EnergyParams.h>
      47              : #include <utils/emissions/PollutantsInterface.h>
      48              : #include <utils/common/SystemFrame.h>
      49              : #include <utils/common/ToString.h>
      50              : #include <utils/xml/XMLSubSys.h>
      51              : #include <utils/common/FileHelpers.h>
      52              : #include <utils/iodevices/OutputDevice.h>
      53              : #include "VTypesHandler.h"
      54              : 
      55              : 
      56              : // ===========================================================================
      57              : // functions
      58              : // ===========================================================================
      59          951 : void single(const OptionsCont& oc, const std::string& of, const std::string& className, SUMOEmissionClass c,
      60              :             double vMin, double vMax, double vStep,
      61              :             double aMin, double aMax, double aStep,
      62              :             double sMin, double sMax, double sStep,
      63              :             bool verbose) {
      64          951 :     if (verbose) {
      65            0 :         WRITE_MESSAGEF(TL("Writing map of '%' into '%'."), className, of);
      66              :     }
      67          951 :     std::ofstream o(of.c_str());
      68          951 :     if (!o.good()) {
      69            0 :         throw ProcessError(TLF("Could not open file '%' for writing.", of));
      70              :     }
      71              : 
      72          951 :     std::unique_ptr<EnergyParams> energyParams;
      73              :     std::map<std::string, SUMOVTypeParameter*> vTypes;
      74         1901 :     if (oc.isSet("vtype") || oc.isSet("additional-files")) {
      75            2 :         if (!oc.isSet("additional-files")) {
      76            0 :             throw ProcessError(TL("Option --vtype requires option --additional-files for loading vehicle types"));
      77              :         }
      78            2 :         if (!oc.isUsableFileList("additional-files")) {
      79            0 :             throw ProcessError();
      80              :         }
      81            3 :         for (const std::string& file : oc.getStringVector("additional-files")) {
      82            1 :             VTypesHandler typesHandler(file, vTypes);
      83            1 :             if (!XMLSubSys::runParser(typesHandler, file)) {
      84            0 :                 throw ProcessError(TLF("Loading of % failed.", file));
      85              :             }
      86            1 :         }
      87            2 :         if (!oc.isSet("vtype") && vTypes.size() != 1) {
      88            0 :             throw ProcessError(TL("Vehicle type is not unique."));
      89              :         }
      90            4 :         const auto vTypeIt = oc.isSet("vtype") ? vTypes.find(oc.getString("vtype")) : vTypes.begin();
      91            1 :         if (vTypeIt == vTypes.end()) {
      92            0 :             throw ProcessError(TLF("Vehicle type '%' is not defined.", oc.getString("vtype")));
      93              :         }
      94            2 :         if (oc.isDefault("emission-class")) {
      95            0 :             c = vTypeIt->second->emissionClass;
      96              :         }
      97            2 :         energyParams = std::unique_ptr<EnergyParams>(new EnergyParams(vTypeIt->second));
      98              :     } else {
      99         1900 :         energyParams = std::unique_ptr<EnergyParams>(new EnergyParams());
     100              :     }
     101         7608 :     for (double v = vMin; v <= vMax; v += vStep) {
     102        66570 :         for (double a = aMin; a <= aMax; a += aStep) {
     103       119826 :             for (double s = sMin; s <= sMax; s += sStep) {
     104        59913 :                 const PollutantsInterface::Emissions result = PollutantsInterface::computeAll(c, v, a, s, energyParams.get());
     105        59913 :                 o << v << ";" << a << ";" << s << ";" << "CO" << ";" << result.CO << std::endl;
     106        59913 :                 o << v << ";" << a << ";" << s << ";" << "CO2" << ";" << result.CO2 << std::endl;
     107        59913 :                 o << v << ";" << a << ";" << s << ";" << "HC" << ";" << result.HC << std::endl;
     108        59913 :                 o << v << ";" << a << ";" << s << ";" << "PMx" << ";" << result.PMx << std::endl;
     109        59913 :                 o << v << ";" << a << ";" << s << ";" << "NOx" << ";" << result.NOx << std::endl;
     110        59913 :                 o << v << ";" << a << ";" << s << ";" << "fuel" << ";" << result.fuel << std::endl;
     111        59913 :                 o << v << ";" << a << ";" << s << ";" << "electricity" << ";" << result.electricity << std::endl;
     112              :             }
     113              :         }
     114              :     }
     115          951 : }
     116              : 
     117              : 
     118              : 
     119              : 
     120              : int
     121          951 : main(int argc, char** argv) {
     122          951 :     OptionsCont& oc = OptionsCont::getOptions();
     123          951 :     oc.setApplicationDescription(TL("Builds and writes an emissions map for SUMO's emission models."));
     124         1902 :     oc.setApplicationName("emissionsMap", "Eclipse SUMO emissionsMap " VERSION_STRING);
     125              :     // add options
     126          951 :     SystemFrame::addConfigurationOptions(oc);
     127          951 :     oc.addOptionSubTopic("Input");
     128          951 :     oc.addOptionSubTopic("Processing");
     129          951 :     oc.doRegister("iterate", 'i', new Option_Bool(false));
     130         1902 :     oc.addDescription("iterate", "Processing", TL("If set, maps for all available emissions are written."));
     131              : 
     132          951 :     oc.doRegister("emission-class", 'e', new Option_String());
     133         1902 :     oc.addDescription("emission-class", "Processing", TL("Defines the name of the emission class to generate the map for."));
     134              : 
     135          951 :     oc.doRegister("additional-files", new Option_FileName());
     136         1902 :     oc.addDescription("additional-files", "Input", TL("Load emission parameters (vTypes) from FILE(s)"));
     137              : 
     138          951 :     oc.doRegister("vtype", new Option_String());
     139         1902 :     oc.addDescription("vtype", "Input", TL("Defines the vehicle type to use for emission parameters."));
     140              : 
     141          951 :     oc.doRegister("v-min", new Option_Float(0.));
     142         1902 :     oc.addDescription("v-min", "Processing", TL("Defines the minimum velocity boundary of the map to generate (in m/s)."));
     143          951 :     oc.doRegister("v-max", new Option_Float(50.));
     144         1902 :     oc.addDescription("v-max", "Processing", TL("Defines the maximum velocity boundary of the map to generate (in m/s)."));
     145          951 :     oc.doRegister("v-step", new Option_Float(2.));
     146         1902 :     oc.addDescription("v-step", "Processing", TL("Defines the velocity step size (in m/s)."));
     147          951 :     oc.doRegister("a-min", new Option_Float(-4.));
     148         1902 :     oc.addDescription("a-min", "Processing", TL("Defines the minimum acceleration boundary of the map to generate (in m/s^2)."));
     149          951 :     oc.doRegister("a-max", new Option_Float(4.));
     150         1902 :     oc.addDescription("a-max", "Processing", TL("Defines the maximum acceleration boundary of the map to generate (in m/s^2)."));
     151          951 :     oc.doRegister("a-step", new Option_Float(.5));
     152         1902 :     oc.addDescription("a-step", "Processing", TL("Defines the acceleration step size (in m/s^2)."));
     153          951 :     oc.doRegister("s-min", new Option_Float(-10.));
     154         1902 :     oc.addDescription("s-min", "Processing", TL("Defines the minimum slope boundary of the map to generate (in deg)."));
     155          951 :     oc.doRegister("s-max", new Option_Float(10.));
     156         1902 :     oc.addDescription("s-max", "Processing", TL("Defines the maximum slope boundary of the map to generate (in deg)."));
     157          951 :     oc.doRegister("s-step", new Option_Float(1.));
     158         1902 :     oc.addDescription("s-step", "Processing", TL("Defines the slope step size (in deg)."));
     159              : 
     160          951 :     oc.addOptionSubTopic("Output");
     161          951 :     oc.doRegister("output-file", 'o', new Option_String());
     162         1902 :     oc.addSynonyme("output", "output-file");
     163         1902 :     oc.addDescription("output", "Output", TL("Defines the file (or the path if --iterate was set) to write the map(s) into."));
     164              : 
     165          951 :     oc.addOptionSubTopic("Emissions");
     166          951 :     oc.doRegister("emissions.volumetric-fuel", new Option_Bool(false));
     167         1902 :     oc.addDescription("emissions.volumetric-fuel", "Emissions", TL("Return fuel consumption values in (legacy) unit l instead of mg"));
     168              : 
     169         3804 :     oc.doRegister("phemlight-path", new Option_FileName(StringVector({ "./PHEMlight/" })));
     170         1902 :     oc.addDescription("phemlight-path", "Emissions", TL("Determines where to load PHEMlight definitions from"));
     171              : 
     172          951 :     oc.doRegister("phemlight-year", new Option_Integer(0));
     173         1902 :     oc.addDescription("phemlight-year", "Emissions", TL("Enable fleet age modelling with the given reference year in PHEMlight5"));
     174              : 
     175          951 :     oc.doRegister("phemlight-temperature", new Option_Float(INVALID_DOUBLE));
     176         1902 :     oc.addDescription("phemlight-temperature", "Emissions", TL("Set ambient temperature to correct NOx emissions in PHEMlight5"));
     177              : 
     178          951 :     SystemFrame::addReportOptions(oc);
     179              : 
     180              :     // run
     181              :     int ret = 0;
     182              :     try {
     183              :         // initialise the application system (messaging, xml, options)
     184          951 :         XMLSubSys::init();
     185          951 :         OptionsIO::setArgs(argc, argv);
     186          951 :         OptionsIO::getOptions();
     187          951 :         if (oc.processMetaOptions(argc < 2)) {
     188            0 :             SystemFrame::close();
     189              :             return 0;
     190              :         }
     191              : 
     192          951 :         double vMin = oc.getFloat("v-min");
     193          951 :         double vMax = oc.getFloat("v-max");
     194          951 :         double vStep = oc.getFloat("v-step");
     195          951 :         double aMin = oc.getFloat("a-min");
     196          951 :         double aMax = oc.getFloat("a-max");
     197          951 :         double aStep = oc.getFloat("a-step");
     198          951 :         double sMin = oc.getFloat("s-min");
     199          951 :         double sMax = oc.getFloat("s-max");
     200          951 :         double sStep = oc.getFloat("s-step");
     201         1902 :         if (!oc.getBool("iterate")) {
     202         1902 :             if (!oc.isSet("emission-class")) {
     203            0 :                 throw ProcessError(TL("The emission class (-e) must be given."));
     204              :             }
     205         1902 :             if (!oc.isSet("output-file")) {
     206            0 :                 throw ProcessError(TL("The output file (-o) must be given."));
     207              :             }
     208          951 :             const SUMOEmissionClass c = PollutantsInterface::getClassByName(oc.getString("emission-class"));
     209         2853 :             single(oc, oc.getString("output-file"), oc.getString("emission-class"),
     210          951 :                    c, vMin, vMax, vStep, aMin, aMax, aStep, sMin, sMax, sStep, oc.getBool("verbose"));
     211              :         } else {
     212            0 :             if (!oc.isSet("output-file")) {
     213            0 :                 oc.set("output-file", "./");
     214              :             }
     215              : #if __cplusplus >= 201703L
     216              :             std::vector<std::string> phemPath;
     217            0 :             phemPath.push_back(OptionsCont::getOptions().getString("phemlight-path") + "/");
     218            0 :             if (getenv("PHEMLIGHT_PATH") != nullptr) {
     219            0 :                 phemPath.push_back(std::string(getenv("PHEMLIGHT_PATH")) + "/");
     220              :             }
     221            0 :             if (getenv("SUMO_HOME") != nullptr) {
     222            0 :                 phemPath.push_back(std::string(getenv("SUMO_HOME")) + "/data/emissions/PHEMlight/");
     223            0 :                 phemPath.push_back(std::string(getenv("SUMO_HOME")) + "/data/emissions/PHEMlight5/");
     224              :             }
     225            0 :             for (const std::string& p : phemPath) {
     226              :                 std::error_code ec;
     227            0 :                 for (const auto& entry : fs::directory_iterator(p, ec)) {
     228            0 :                     if (entry.path().extension() == ".veh") {
     229            0 :                         if (entry.path().parent_path().filename().string().back() == '5') {
     230            0 :                             PollutantsInterface::getClassByName("PHEMlight5/" + entry.path().filename().stem().stem().string());
     231              :                         } else {
     232            0 :                             PollutantsInterface::getClassByName("PHEMlight/" + entry.path().filename().stem().stem().string());
     233              :                         }
     234              :                     }
     235              :                 }
     236              :             }
     237              : #endif
     238            0 :             const std::vector<SUMOEmissionClass> classes = PollutantsInterface::getAllClasses();
     239            0 :             for (std::vector<SUMOEmissionClass>::const_iterator ci = classes.begin(); ci != classes.end(); ++ci) {
     240            0 :                 SUMOEmissionClass c = *ci;
     241            0 :                 single(oc, oc.getString("output-file") + PollutantsInterface::getName(c) + ".csv",
     242            0 :                        PollutantsInterface::getName(c),
     243            0 :                        c, vMin, vMax, vStep, aMin, aMax, aStep, sMin, sMax, sStep, oc.getBool("verbose"));
     244              :             }
     245            0 :         }
     246            0 :     } catch (InvalidArgument& e) {
     247            0 :         MsgHandler::getErrorInstance()->inform(e.what());
     248            0 :         MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
     249              :         ret = 1;
     250            0 :     } catch (ProcessError& e) {
     251            0 :         if (std::string(e.what()) != std::string("Process Error") && std::string(e.what()) != std::string("")) {
     252            0 :             MsgHandler::getErrorInstance()->inform(e.what());
     253              :         }
     254            0 :         MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
     255              :         ret = 1;
     256              : #ifndef _DEBUG
     257            0 :     } catch (...) {
     258            0 :         MsgHandler::getErrorInstance()->inform("Quitting (on unknown error).", false);
     259              :         ret = 1;
     260              : #endif
     261            0 :     }
     262          951 :     SystemFrame::close();
     263              :     if (ret == 0) {
     264              :         std::cout << "Success." << std::endl;
     265              :     }
     266              :     return ret;
     267         1902 : }
     268              : 
     269              : 
     270              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1