Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
emissionsDrivingCycle_main.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2013-2026 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/****************************************************************************/
19// Main for an emissions calculator
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>
38#include <utils/xml/XMLSubSys.h>
46#include "TrajectoriesHandler.h"
47#include "VTypesHandler.h"
48
49
50// ===========================================================================
51// functions
52// ===========================================================================
53
54
55/* -------------------------------------------------------------------------
56 * main
57 * ----------------------------------------------------------------------- */
58int
59main(int argc, char** argv) {
61 oc.setApplicationDescription(TL("Computes emissions by driving a time line using SUMO's emission models."));
62 oc.setApplicationName("emissionsDrivingCycle", "Eclipse SUMO emissionsDrivingCycle " VERSION_STRING);
63
64 // add options
66 oc.addOptionSubTopic("Input");
67 oc.doRegister("timeline-file", 't', new Option_FileName());
68 oc.addSynonyme("timeline", "timeline-file");
69 oc.addDescription("timeline-file", "Input", TL("Defines the file to read the driving cycle from."));
70
71 oc.doRegister("timeline-file.skip", new Option_Integer(0));
72 oc.addSynonyme("timeline.skip", "timeline-file.skip");
73 oc.addDescription("timeline-file.skip", "Input", TL("Skips the first NUM lines."));
74
75 oc.doRegister("timeline-file.separator", new Option_String(";"));
76 oc.addSynonyme("timeline.separator", "timeline-file.separator");
77 oc.addDescription("timeline-file.separator", "Input", TL("Defines the entry separator."));
78
79 oc.doRegister("netstate-file", 'n', new Option_FileName());
80 oc.addSynonyme("netstate", "netstate-file");
81 oc.addSynonyme("amitran", "netstate-file");
82 oc.addDescription("netstate-file", "Input", TL("Defines the netstate, route and trajectory files to read the driving cycles from."));
83
84 oc.doRegister("additional-files", new Option_FileName());
85 oc.addDescription("additional-files", "Input", TL("Load emission parameters (vTypes) from FILE(s)"));
86
87 oc.doRegister("emission-class", 'e', new Option_String("HBEFA4/default"));
88 oc.addDescription("emission-class", "Input", TL("Defines for which emission class the emissions shall be generated. "));
89
90 oc.doRegister("vtype", new Option_String());
91 oc.addDescription("vtype", "Input", TL("Defines the vehicle type to use for emission parameters."));
92
93 oc.addOptionSubTopic("Processing");
94 oc.doRegister("compute-a", 'a', new Option_Bool(false));
95 oc.addDescription("compute-a", "Processing", TL("If set, the acceleration is computed instead of being read from the file. "));
96
97 oc.doRegister("compute-a.forward", new Option_Bool(false));
98 oc.addDescription("compute-a.forward", "Processing", TL("If set, the acceleration for time t is computed from v(t+1) - v(t) instead of v(t) - v(t-1). "));
99
100 oc.doRegister("compute-a.zero-correction", new Option_Bool(false));
101 oc.addDescription("compute-a.zero-correction", "Processing", TL("If set, the acceleration for time t is set to 0 if the speed is 0. "));
102
103 oc.doRegister("skip-first", 's', new Option_Bool(false));
104 oc.addDescription("skip-first", "Processing", TL("If set, the first line of the read file is skipped."));
105
106 oc.doRegister("kmh", new Option_Bool(false));
107 oc.addDescription("kmh", "Processing", TL("If set, the given speed is interpreted as being given in km/h."));
108
109 oc.doRegister("have-slope", new Option_Bool(false));
110 oc.addDescription("have-slope", "Processing", TL("If set, the fourth column is read and used as slope (in deg)."));
111
112 oc.doRegister("slope", new Option_Float(0));
113 oc.addDescription("slope", "Processing", TL("Sets a global slope (in deg) that is used if the file does not contain slope information."));
114
115 oc.addOptionSubTopic("Output");
116 oc.doRegister("output-file", 'o', new Option_String());
117 oc.addSynonyme("output", "output-file");
118 oc.addDescription("output", "Output", TL("Defines the file to write the emission cycle results into."));
119
120 oc.doRegister("output.attributes", new Option_StringVector());
121 oc.addDescription("output.attributes", "Output", TL("Defines the attributes to write."));
122
123 oc.doRegister("emission-output", new Option_FileName());
124 oc.addDescription("emission-output", "Output", TL("Save the emission values of each vehicle in XML"));
125
126 oc.doRegister("sum-output", new Option_FileName());
127 oc.addSynonyme("sum", "sum-output");
128 oc.addDescription("sum-output", "Output", TL("Save the aggregated and normed emission values of each vehicle in CSV"));
129
130 oc.addOptionSubTopic("Emissions");
131 oc.doRegister("emissions.volumetric-fuel", new Option_Bool(false));
132 oc.addDescription("emissions.volumetric-fuel", "Emissions", TL("Return fuel consumption values in (legacy) unit l instead of mg"));
133
134 oc.doRegister("phemlight-path", new Option_FileName(StringVector({ "./PHEMlight/" })));
135 oc.addDescription("phemlight-path", "Emissions", TL("Determines where to load PHEMlight definitions from"));
136
137 oc.doRegister("phemlight-year", new Option_Integer(0));
138 oc.addDescription("phemlight-year", "Emissions", TL("Enable fleet age modelling with the given reference year in PHEMlight5"));
139
140 oc.doRegister("phemlight-temperature", new Option_Float(INVALID_DOUBLE));
141 oc.addDescription("phemlight-temperature", "Emissions", TL("Set ambient temperature to correct NOx emissions in PHEMlight5"));
142
143 oc.doRegister("begin", new Option_String("0", "TIME"));
144 oc.addDescription("begin", "Processing", TL("Defines the begin time in seconds;"));
145
146 oc.doRegister("end", new Option_String("-1", "TIME"));
147 oc.addDescription("end", "Processing", TL("Defines the end time in seconds;"));
148
150 oc.doRegister("quiet", 'q', new Option_Bool(false));
151 oc.addDescription("quiet", "Report", TL("Not writing anything."));
152
153 // run
154 int ret = 0;
155 bool quiet = false;
156 try {
157 // initialise the application system (messaging, xml, options)
159 OptionsIO::setArgs(argc, argv);
161 if (oc.processMetaOptions(argc < 2)) {
163 return 0;
164 }
165
166 quiet = oc.getBool("quiet");
167 if (!oc.isSet("timeline-file") && !oc.isSet("netstate-file")) {
168 throw ProcessError(TL("Either a timeline or a netstate / amitran file must be given."));
169 }
170 if (!oc.isSet("output-file") && (oc.isSet("timeline-file") || !oc.isSet("emission-output"))) {
171 throw ProcessError(TL("The output file must be given."));
172 }
173 std::unique_ptr<std::ostream> outOwner;
174 std::ostream* out = nullptr;
175 if (oc.isSet("output-file")) {
176 outOwner.reset(new std::ofstream(oc.getString("output-file").c_str()));
177 out = outOwner.get();
178 }
179 long long int attributes = 0;
180 if (oc.isSet("output.attributes")) {
181 for (std::string attrName : oc.getStringVector("output.attributes")) {
182 if (!SUMOXMLDefinitions::Attrs.hasString(attrName)) {
183 if (attrName == "all") {
184 attributes = std::numeric_limits<long long int>::max() - 1;
185 } else {
186 WRITE_ERRORF(TL("Unknown attribute '%' to write in output."), attrName);
187 }
188 continue;
189 }
190 int attr = SUMOXMLDefinitions::Attrs.get(attrName);
191 assert(attr < 63);
192 attributes |= ((long long int)1 << attr);
193 }
194 } else {
195 attributes = ~(((long long int)1 << SUMO_ATTR_AMOUNT));
196 }
197 OutputDevice::createDeviceByOption("emission-output", "emission-export", "emission_file.xsd");
198 OutputDevice* xmlOut = nullptr;
199 if (oc.isSet("emission-output")) {
200 xmlOut = &OutputDevice::getDeviceByOption("emission-output");
201 } else if (out == nullptr) {
202 out = &std::cout;
203 }
204 std::unique_ptr<std::ostream> sumOut(nullptr);
205 if (oc.isSet("sum-output")) {
206 sumOut.reset(new std::ofstream(oc.getString("sum-output").c_str()));
207 (*sumOut) << "Vehicle,Cycle,Time,Speed,Gradient,Acceleration,FC,FCel,CO2,NOx,CO,HC,PM" << std::endl;
208 }
209
210 SUMOEmissionClass emissionClass = PollutantsInterface::getClassByName(oc.getString("emission-class"));
211 std::unique_ptr<EnergyParams> energyParams;
212 std::map<std::string, SUMOVTypeParameter*> vTypes;
213 if (oc.isSet("vtype") || oc.isSet("additional-files")) {
214 if (!oc.isSet("additional-files")) {
215 throw ProcessError(TL("Option --vtype requires option --additional-files for loading vehicle types"));
216 }
217 if (!oc.isUsableFileList("additional-files")) {
218 throw ProcessError();
219 }
220 for (const std::string& file : oc.getStringVector("additional-files")) {
221 VTypesHandler typesHandler(file, vTypes);
222 if (!XMLSubSys::runParser(typesHandler, file)) {
223 throw ProcessError(TLF("Loading of % failed.", file));
224 }
225 }
226 if (!oc.isSet("vtype") && vTypes.size() != 1) {
227 throw ProcessError(TL("Vehicle type is not unique."));
228 }
229 const auto vTypeIt = oc.isSet("vtype") ? vTypes.find(oc.getString("vtype")) : vTypes.begin();
230 if (vTypeIt == vTypes.end()) {
231 throw ProcessError(TLF("Vehicle type '%' is not defined.", oc.getString("vtype")));
232 }
233 if (oc.isDefault("emission-class")) {
234 emissionClass = vTypeIt->second->emissionClass;
235 }
236 energyParams = std::unique_ptr<EnergyParams>(new EnergyParams(vTypeIt->second));
237 } else {
238 energyParams = std::unique_ptr<EnergyParams>(new EnergyParams());
239 }
240 for (auto& vt : vTypes) {
241 delete vt.second;
242 }
243
244 const bool computeA = oc.getBool("compute-a") || oc.getBool("compute-a.forward");
245 TrajectoriesHandler handler(computeA, oc.getBool("compute-a.forward"), oc.getBool("compute-a.zero-correction"), emissionClass, energyParams.get(), attributes, oc.getFloat("slope"), out, xmlOut);
246
247 if (oc.isSet("timeline-file")) {
248 int skip = oc.getBool("skip-first") ? 1 : oc.getInt("timeline-file.skip");
249 const bool inKMH = oc.getBool("kmh");
250 const bool haveSlope = oc.getBool("have-slope");
251 double l = 0;
252 double totalA = 0;
253 double totalS = 0;
254 int time = 0;
255
256 LineReader lr(oc.getString("timeline-file"));
257 if (!lr.good()) {
258 throw ProcessError(TLF("Unreadable file '%'.", lr.getFileName()));
259 }
260 while (lr.hasMore()) {
261 std::string line = lr.readLine();
262 if (skip > 0) {
263 skip--;
264 continue;
265 }
266 StringTokenizer st(StringUtils::prune(line), oc.getString("timeline-file.separator"));
267 if (st.hasNext()) {
268 try {
269 double t = StringUtils::toDouble(st.next());
270 double v = 0;
271 if (st.hasNext()) {
272 v = StringUtils::toDouble(st.next());
273 } else {
274 v = t;
275 t = time;
276 }
277 if (inKMH) {
278 v /= 3.6;
279 }
280 double a = !computeA && st.hasNext() ? StringUtils::toDouble(st.next()) : TrajectoriesHandler::INVALID_VALUE;
281 double s = haveSlope && st.hasNext() ? StringUtils::toDouble(st.next()) : TrajectoriesHandler::INVALID_VALUE;
282 if (handler.writeEmissions(*out, "", emissionClass, energyParams.get(), attributes, t, v, a, s)) {
283 l += v;
284 totalA += a;
285 totalS += s;
286 time++;
287 }
288 } catch (EmptyData&) {
289 throw ProcessError(TLF("Missing an entry in line '%'.", line));
290 } catch (NumberFormatException&) {
291 throw ProcessError(TLF("Not numeric entry in line '%'.", line));
292 }
293 }
294 }
295 if (!quiet) {
296 std::cout << "sums" << std::endl
297 << "length:" << l << std::endl;
298 }
299 if (sumOut != nullptr) {
300 (*sumOut) << oc.getString("emission-class") << "," << lr.getFileName() << "," << time << ","
301 << (l / time * 3.6) << "," << (totalS / time) << "," << (totalA / time) << ",";
302 handler.writeNormedSums(*sumOut, "", l);
303 }
304 }
305 if (oc.isSet("netstate-file")) {
306 XMLSubSys::runParser(handler, oc.getString("netstate-file"));
307 }
308 if (!quiet) {
309 handler.writeSums(std::cout, "");
310 }
311 } catch (InvalidArgument& e) {
313 MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
314 ret = 1;
315 } catch (ProcessError& e) {
316 if (std::string(e.what()) != std::string("Process Error") && std::string(e.what()) != std::string("")) {
318 }
319 MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
320 ret = 1;
321#ifndef _DEBUG
322 } catch (...) {
323 MsgHandler::getErrorInstance()->inform("Quitting (on unknown error).", false);
324 ret = 1;
325#endif
326 }
328 if (ret == 0 && !quiet) {
329 std::cout << "Success." << std::endl;
330 }
331 return ret;
332}
333
334
335/****************************************************************************/
#define WRITE_ERRORF(...)
Definition MsgHandler.h:296
#define TL(string)
Definition MsgHandler.h:304
#define TLF(string,...)
Definition MsgHandler.h:306
std::vector< std::string > StringVector
Definition of a vector of strings.
Definition Option.h:42
int SUMOEmissionClass
@ SUMO_ATTR_AMOUNT
MSMeanData_Amitran.
const double INVALID_DOUBLE
invalid double
Definition StdDefs.h:68
An upper class for objects with additional parameters.
Retrieves a file linewise and reports the lines to a handler.
Definition LineReader.h:48
bool good() const
Returns the information whether the stream is readable.
bool readLine(LineHandler &lh)
Reads a single (the next) line from the file and reports it to the given LineHandler.
bool hasMore() const
Returns whether another line may be read (the file was not read completely)
std::string getFileName() const
Returns the name of the used file.
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
virtual void inform(std::string msg, bool addType=true)
adds a new error to the list
A storage for options typed value containers)
Definition OptionsCont.h:89
void addDescription(const std::string &name, const std::string &subtopic, const std::string &description)
Adds a description for an option.
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
void setApplicationName(const std::string &appName, const std::string &fullName)
Sets the application name.
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
void addSynonyme(const std::string &name1, const std::string &name2, bool isDeprecated=false)
Adds a synonyme for an options name (any order)
bool isDefault(const std::string &name) const
Returns the information whether the named option has still the default value.
void doRegister(const std::string &name, Option *o)
Adds an option under the given name.
void setApplicationDescription(const std::string &appDesc)
Sets the application description.
void addOptionSubTopic(const std::string &topic)
Adds an option subtopic.
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
static OptionsCont & getOptions()
Retrieves the options.
bool processMetaOptions(bool missingOptions)
Checks for help and configuration output, returns whether we should exit.
bool isUsableFileList(const std::string &name) const
Checks whether the named option is usable as a file list (with at least a single file)
static void setArgs(int argc, char **argv)
Stores the command line arguments for later parsing.
Definition OptionsIO.cpp:58
static void getOptions(const bool commandLineOnly=false)
Parses the command line arguments and loads the configuration.
Definition OptionsIO.cpp:74
Static storage of an output device and its base (abstract) implementation.
static OutputDevice & getDeviceByOption(const std::string &name)
Returns the device described by the option.
static bool createDeviceByOption(const std::string &optionName, const std::string &rootElement="", const std::string &schemaFile="", const int maximumDepth=2)
Creates the device using the output definition stored in the named option.
static SUMOEmissionClass getClassByName(const std::string &eClass, const SUMOVehicleClass vc=SVC_IGNORING)
Checks whether the string describes a known vehicle class.
static SequentialStringBijection Attrs
The names of SUMO-XML attributes for use in netbuild.
int get(const std::string &str) const
bool hasNext()
returns the information whether further substrings exist
std::string next()
returns the next substring when it exists. Otherwise the behaviour is undefined
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static std::string prune(const std::string &str)
Removes trailing and leading whitechars.
static void close()
Closes all of an applications subsystems.
static void addConfigurationOptions(OptionsCont &oc)
Adds configuration options to the given container.
static void addReportOptions(OptionsCont &oc)
Adds reporting options to the given container.
An XML-Handler for amitran and netstate trajectories.
void writeNormedSums(std::ostream &o, const std::string id, const double factor)
void writeSums(std::ostream &o, const std::string id)
static const int INVALID_VALUE
bool writeEmissions(std::ostream &o, const std::string id, const SUMOEmissionClass c, EnergyParams *params, long long int attributes, double t, double &v, double &a, double &s)
An XML-Handler for amitran and netstate trajectories.
static void init()
Initialises the xml-subsystem.
Definition XMLSubSys.cpp:56
static bool runParser(GenericSAXHandler &handler, const std::string &file, const bool isNet=false, const bool isRoute=false, const bool isExternal=false, const bool catchExceptions=true)
Runs the given handler on the given file; returns if everything's ok.
int main(int argc, char **argv)