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-2023 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 oc.setApplicationDescription(TL("Computes emissions by driving a time line using SUMO's emission models."));
63 oc.setApplicationName("emissionsDrivingCycle", "Eclipse SUMO emissionsDrivingCycle Version " VERSION_STRING);
64
65 // add options
67 oc.addOptionSubTopic("Input");
68 oc.doRegister("timeline-file", 't', new Option_FileName());
69 oc.addSynonyme("timeline", "timeline-file");
70 oc.addDescription("timeline-file", "Input", TL("Defines the file to read the driving cycle from."));
71
72 oc.doRegister("timeline-file.skip", new Option_Integer(0));
73 oc.addSynonyme("timeline.skip", "timeline-file.skip");
74 oc.addDescription("timeline-file.skip", "Input", TL("Skips the first NUM lines."));
75
76 oc.doRegister("timeline-file.separator", new Option_String(";"));
77 oc.addSynonyme("timeline.separator", "timeline-file.separator");
78 oc.addDescription("timeline-file.separator", "Input", TL("Defines the entry separator."));
79
80 oc.doRegister("netstate-file", 'n', new Option_FileName());
81 oc.addSynonyme("netstate", "netstate-file");
82 oc.addSynonyme("amitran", "netstate-file");
83 oc.addDescription("netstate-file", "Input", TL("Defines the netstate, route and trajectory files to read the driving cycles from."));
84
85 oc.doRegister("additional-files", new Option_FileName());
86 oc.addDescription("additional-files", "Input", TL("Load emission parameters (vTypes) from FILE(s)"));
87
88 oc.doRegister("emission-class", 'e', new Option_String("unknown"));
89 oc.addDescription("emission-class", "Input", TL("Defines for which emission class the emissions shall be generated. "));
90
91 oc.doRegister("vtype", new Option_String());
92 oc.addDescription("vtype", "Input", TL("Defines the vehicle type to use for emission parameters."));
93
94 oc.addOptionSubTopic("Processing");
95 oc.doRegister("compute-a", 'a', new Option_Bool(false));
96 oc.addDescription("compute-a", "Processing", TL("If set, the acceleration is computed instead of being read from the file. "));
97
98 oc.doRegister("compute-a.forward", new Option_Bool(false));
99 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). "));
100
101 oc.doRegister("compute-a.zero-correction", new Option_Bool(false));
102 oc.addDescription("compute-a.zero-correction", "Processing", TL("If set, the acceleration for time t is set to 0 if the speed is 0. "));
103
104 oc.doRegister("skip-first", 's', new Option_Bool(false));
105 oc.addDescription("skip-first", "Processing", TL("If set, the first line of the read file is skipped."));
106
107 oc.doRegister("kmh", new Option_Bool(false));
108 oc.addDescription("kmh", "Processing", TL("If set, the given speed is interpreted as being given in km/h."));
109
110 oc.doRegister("have-slope", new Option_Bool(false));
111 oc.addDescription("have-slope", "Processing", TL("If set, the fourth column is read and used as slope (in deg)."));
112
113 oc.doRegister("slope", new Option_Float(0));
114 oc.addDescription("slope", "Processing", TL("Sets a global slope (in deg) that is used if the file does not contain slope information."));
115
116 oc.addOptionSubTopic("Output");
117 oc.doRegister("output-file", 'o', new Option_String());
118 oc.addSynonyme("output", "output-file");
119 oc.addDescription("output", "Output", TL("Defines the file to write the emission cycle results into."));
120
121 oc.doRegister("output.attributes", new Option_StringVector());
122 oc.addDescription("output.attributes", "Output", TL("Defines the attributes to write."));
123
124 oc.doRegister("emission-output", new Option_FileName());
125 oc.addDescription("emission-output", "Output", TL("Save the emission values of each vehicle in XML"));
126
127 oc.doRegister("sum-output", new Option_FileName());
128 oc.addSynonyme("sum", "sum-output");
129 oc.addDescription("sum-output", "Output", TL("Save the aggregated and normed emission values of each vehicle in CSV"));
130
131 oc.addOptionSubTopic("Emissions");
132 oc.doRegister("emissions.volumetric-fuel", new Option_Bool(false));
133 oc.addDescription("emissions.volumetric-fuel", "Emissions", TL("Return fuel consumption values in (legacy) unit l instead of mg"));
134
135 oc.doRegister("phemlight-path", new Option_FileName(StringVector({ "./PHEMlight/" })));
136 oc.addDescription("phemlight-path", "Emissions", TL("Determines where to load PHEMlight definitions from"));
137
138 oc.doRegister("phemlight-year", new Option_Integer(0));
139 oc.addDescription("phemlight-year", "Emissions", TL("Enable fleet age modelling with the given reference year in PHEMlight5"));
140
141 oc.doRegister("phemlight-temperature", new Option_Float(INVALID_DOUBLE));
142 oc.addDescription("phemlight-temperature", "Emissions", TL("Set ambient temperature to correct NOx emissions in PHEMlight5"));
143
144 oc.doRegister("begin", new Option_String("0", "TIME"));
145 oc.addDescription("begin", "Processing", TL("Defines the begin time in seconds;"));
146
147 oc.doRegister("end", new Option_String("-1", "TIME"));
148 oc.addDescription("end", "Processing", TL("Defines the end time in seconds;"));
149
151 oc.doRegister("quiet", 'q', new Option_Bool(false));
152 oc.addDescription("quiet", "Report", TL("Not writing anything."));
153
154 // run
155 int ret = 0;
156 bool quiet = false;
157 try {
158 // initialise the application system (messaging, xml, options)
160 OptionsIO::setArgs(argc, argv);
162 if (oc.processMetaOptions(argc < 2)) {
164 return 0;
165 }
166
167 quiet = oc.getBool("quiet");
168 if (!oc.isSet("timeline-file") && !oc.isSet("netstate-file")) {
169 throw ProcessError(TL("Either a timeline or a netstate / amitran file must be given."));
170 }
171 if (!oc.isSet("output-file") && (oc.isSet("timeline-file") || !oc.isSet("emission-output"))) {
172 throw ProcessError(TL("The output file must be given."));
173 }
174 std::ostream* out = nullptr;
175 if (oc.isSet("output-file")) {
176 out = new std::ofstream(oc.getString("output-file").c_str());
177 }
178 long long int attributes = 0;
179 if (oc.isSet("output.attributes")) {
180 for (std::string attrName : oc.getStringVector("output.attributes")) {
181 if (!SUMOXMLDefinitions::Attrs.hasString(attrName)) {
182 if (attrName == "all") {
183 attributes = std::numeric_limits<long long int>::max() - 1;
184 } else {
185 WRITE_ERRORF(TL("Unknown attribute '%' to write in output."), attrName);
186 }
187 continue;
188 }
189 int attr = SUMOXMLDefinitions::Attrs.get(attrName);
190 assert(attr < 63);
191 attributes |= ((long long int)1 << attr);
192 }
193 } else {
194 attributes = ~(((long long int)1 << SUMO_ATTR_AMOUNT));
195 }
196 OutputDevice::createDeviceByOption("emission-output", "emission-export", "emission_file.xsd");
197 OutputDevice* xmlOut = nullptr;
198 if (oc.isSet("emission-output")) {
199 xmlOut = &OutputDevice::getDeviceByOption("emission-output");
200 } else if (out == nullptr) {
201 out = &std::cout;
202 }
203 std::ostream* sumOut = nullptr;
204 if (oc.isSet("sum-output")) {
205 sumOut = new std::ofstream(oc.getString("sum-output").c_str());
206 (*sumOut) << "Vehicle,Cycle,Time,Speed,Gradient,Acceleration,FC,FCel,CO2,NOx,CO,HC,PM" << std::endl;
207 }
208
209 EnergyParams energyParams;
210 std::map<std::string, SUMOVTypeParameter*> vTypes;
211 if (oc.isSet("vtype")) {
212 if (!oc.isSet("additional-files")) {
213 throw ProcessError(TL("Option --vtype requires option --additional-files for loading vehicle types"));
214 }
215 if (!oc.isUsableFileList("additional-files")) {
216 throw ProcessError();
217 }
218 for (auto file : oc.getStringVector("additional-files")) {
219 VTypesHandler typesHandler(file, vTypes);
220 if (!XMLSubSys::runParser(typesHandler, file)) {
221 throw ProcessError(TLF("Loading of % failed.", file));
222 }
223 }
224 if (vTypes.count(oc.getString("vtype")) == 0) {
225 throw ProcessError(TLF("Vehicle type '%' is not defined", oc.getString("vtype")));
226 }
227 energyParams = EnergyParams(vTypes[oc.getString("vtype")]);
228 }
229
230 const SUMOEmissionClass defaultClass = PollutantsInterface::getClassByName(oc.getString("emission-class"));
231 const bool computeA = oc.getBool("compute-a") || oc.getBool("compute-a.forward");
232 TrajectoriesHandler handler(computeA, oc.getBool("compute-a.forward"), oc.getBool("compute-a.zero-correction"), defaultClass, &energyParams, attributes, oc.getFloat("slope"), out, xmlOut);
233
234 if (oc.isSet("timeline-file")) {
235 int skip = oc.getBool("skip-first") ? 1 : oc.getInt("timeline-file.skip");
236 const bool inKMH = oc.getBool("kmh");
237 const bool haveSlope = oc.getBool("have-slope");
238 double l = 0;
239 double totalA = 0;
240 double totalS = 0;
241 int time = 0;
242
243 LineReader lr(oc.getString("timeline-file"));
244 if (!lr.good()) {
245 throw ProcessError(TLF("Unreadable file '%'.", lr.getFileName()));
246 }
247 while (lr.hasMore()) {
248 std::string line = lr.readLine();
249 if (skip > 0) {
250 skip--;
251 continue;
252 }
253 StringTokenizer st(StringUtils::prune(line), oc.getString("timeline-file.separator"));
254 if (st.hasNext()) {
255 try {
256 double t = StringUtils::toDouble(st.next());
257 double v = 0;
258 if (st.hasNext()) {
259 v = StringUtils::toDouble(st.next());
260 } else {
261 v = t;
262 t = time;
263 }
264 if (inKMH) {
265 v /= 3.6;
266 }
267 double a = !computeA && st.hasNext() ? StringUtils::toDouble(st.next()) : TrajectoriesHandler::INVALID_VALUE;
268 double s = haveSlope && st.hasNext() ? StringUtils::toDouble(st.next()) : TrajectoriesHandler::INVALID_VALUE;
269 if (handler.writeEmissions(*out, "", defaultClass, &energyParams, attributes, t, v, a, s)) {
270 l += v;
271 totalA += a;
272 totalS += s;
273 time++;
274 }
275 } catch (EmptyData&) {
276 throw ProcessError(TLF("Missing an entry in line '%'.", line));
277 } catch (NumberFormatException&) {
278 throw ProcessError(TLF("Not numeric entry in line '%'.", line));
279 }
280 }
281 }
282 if (!quiet) {
283 std::cout << "sums" << std::endl
284 << "length:" << l << std::endl;
285 }
286 if (sumOut != nullptr) {
287 (*sumOut) << oc.getString("emission-class") << "," << lr.getFileName() << "," << time << ","
288 << (l / time * 3.6) << "," << (totalS / time) << "," << (totalA / time) << ",";
289 handler.writeNormedSums(*sumOut, "", l);
290 }
291 }
292 if (oc.isSet("netstate-file")) {
293 XMLSubSys::runParser(handler, oc.getString("netstate-file"));
294 }
295 if (!quiet) {
296 handler.writeSums(std::cout, "");
297 }
298 delete sumOut;
299 if (out != &std::cout) {
300 delete out;
301 }
302 } catch (InvalidArgument& e) {
304 MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
305 ret = 1;
306 } catch (ProcessError& e) {
307 if (std::string(e.what()) != std::string("Process Error") && std::string(e.what()) != std::string("")) {
309 }
310 MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
311 ret = 1;
312#ifndef _DEBUG
313 } catch (...) {
314 MsgHandler::getErrorInstance()->inform("Quitting (on unknown error).", false);
315 ret = 1;
316#endif
317 }
319 if (ret == 0 && !quiet) {
320 std::cout << "Success." << std::endl;
321 }
322 return ret;
323}
324
325
326/****************************************************************************/
#define WRITE_ERRORF(...)
Definition MsgHandler.h:280
#define TL(string)
Definition MsgHandler.h:287
#define TLF(string,...)
Definition MsgHandler.h:288
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:64
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)
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 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.
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:55
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)