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