Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/tools/emissionsDrivingCycle_main.cpp
169665 views
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 emissionsDrivingCycle_main.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Michael Behrisch
17
/// @date Wed, 21.08.2013
18
///
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>
31
#include <utils/common/MsgHandler.h>
32
#include <utils/options/Option.h>
33
#include <utils/options/OptionsCont.h>
34
#include <utils/options/OptionsIO.h>
35
#include <utils/common/UtilExceptions.h>
36
#include <utils/common/SystemFrame.h>
37
#include <utils/common/ToString.h>
38
#include <utils/xml/XMLSubSys.h>
39
#include <utils/common/FileHelpers.h>
40
#include <utils/common/StringTokenizer.h>
41
#include <utils/common/StringUtils.h>
42
#include <utils/emissions/PollutantsInterface.h>
43
#include <utils/emissions/EnergyParams.h>
44
#include <utils/iodevices/OutputDevice.h>
45
#include <utils/importio/LineReader.h>
46
#include "TrajectoriesHandler.h"
47
#include "VTypesHandler.h"
48
49
50
// ===========================================================================
51
// functions
52
// ===========================================================================
53
54
55
/* -------------------------------------------------------------------------
56
* main
57
* ----------------------------------------------------------------------- */
58
int
59
main(int argc, char** argv) {
60
OptionsCont& oc = OptionsCont::getOptions();
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
65
SystemFrame::addConfigurationOptions(oc);
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
149
SystemFrame::addReportOptions(oc);
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)
158
XMLSubSys::init();
159
OptionsIO::setArgs(argc, argv);
160
OptionsIO::getOptions();
161
if (oc.processMetaOptions(argc < 2)) {
162
SystemFrame::close();
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::ostream* out = nullptr;
174
if (oc.isSet("output-file")) {
175
out = new std::ofstream(oc.getString("output-file").c_str());
176
}
177
long long int attributes = 0;
178
if (oc.isSet("output.attributes")) {
179
for (std::string attrName : oc.getStringVector("output.attributes")) {
180
if (!SUMOXMLDefinitions::Attrs.hasString(attrName)) {
181
if (attrName == "all") {
182
attributes = std::numeric_limits<long long int>::max() - 1;
183
} else {
184
WRITE_ERRORF(TL("Unknown attribute '%' to write in output."), attrName);
185
}
186
continue;
187
}
188
int attr = SUMOXMLDefinitions::Attrs.get(attrName);
189
assert(attr < 63);
190
attributes |= ((long long int)1 << attr);
191
}
192
} else {
193
attributes = ~(((long long int)1 << SUMO_ATTR_AMOUNT));
194
}
195
OutputDevice::createDeviceByOption("emission-output", "emission-export", "emission_file.xsd");
196
OutputDevice* xmlOut = nullptr;
197
if (oc.isSet("emission-output")) {
198
xmlOut = &OutputDevice::getDeviceByOption("emission-output");
199
} else if (out == nullptr) {
200
out = &std::cout;
201
}
202
std::ostream* sumOut = nullptr;
203
if (oc.isSet("sum-output")) {
204
sumOut = new std::ofstream(oc.getString("sum-output").c_str());
205
(*sumOut) << "Vehicle,Cycle,Time,Speed,Gradient,Acceleration,FC,FCel,CO2,NOx,CO,HC,PM" << std::endl;
206
}
207
208
SUMOEmissionClass emissionClass = PollutantsInterface::getClassByName(oc.getString("emission-class"));
209
std::unique_ptr<EnergyParams> energyParams;
210
std::map<std::string, SUMOVTypeParameter*> vTypes;
211
if (oc.isSet("vtype") || oc.isSet("additional-files")) {
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 (const std::string& 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 (!oc.isSet("vtype") && vTypes.size() != 1) {
225
throw ProcessError(TL("Vehicle type is not unique."));
226
}
227
const auto vTypeIt = oc.isSet("vtype") ? vTypes.find(oc.getString("vtype")) : vTypes.begin();
228
if (vTypeIt == vTypes.end()) {
229
throw ProcessError(TLF("Vehicle type '%' is not defined.", oc.getString("vtype")));
230
}
231
if (oc.isDefault("emission-class")) {
232
emissionClass = vTypeIt->second->emissionClass;
233
}
234
energyParams = std::unique_ptr<EnergyParams>(new EnergyParams(vTypeIt->second));
235
} else {
236
energyParams = std::unique_ptr<EnergyParams>(new EnergyParams());
237
}
238
239
const bool computeA = oc.getBool("compute-a") || oc.getBool("compute-a.forward");
240
TrajectoriesHandler handler(computeA, oc.getBool("compute-a.forward"), oc.getBool("compute-a.zero-correction"), emissionClass, energyParams.get(), attributes, oc.getFloat("slope"), out, xmlOut);
241
242
if (oc.isSet("timeline-file")) {
243
int skip = oc.getBool("skip-first") ? 1 : oc.getInt("timeline-file.skip");
244
const bool inKMH = oc.getBool("kmh");
245
const bool haveSlope = oc.getBool("have-slope");
246
double l = 0;
247
double totalA = 0;
248
double totalS = 0;
249
int time = 0;
250
251
LineReader lr(oc.getString("timeline-file"));
252
if (!lr.good()) {
253
throw ProcessError(TLF("Unreadable file '%'.", lr.getFileName()));
254
}
255
while (lr.hasMore()) {
256
std::string line = lr.readLine();
257
if (skip > 0) {
258
skip--;
259
continue;
260
}
261
StringTokenizer st(StringUtils::prune(line), oc.getString("timeline-file.separator"));
262
if (st.hasNext()) {
263
try {
264
double t = StringUtils::toDouble(st.next());
265
double v = 0;
266
if (st.hasNext()) {
267
v = StringUtils::toDouble(st.next());
268
} else {
269
v = t;
270
t = time;
271
}
272
if (inKMH) {
273
v /= 3.6;
274
}
275
double a = !computeA && st.hasNext() ? StringUtils::toDouble(st.next()) : TrajectoriesHandler::INVALID_VALUE;
276
double s = haveSlope && st.hasNext() ? StringUtils::toDouble(st.next()) : TrajectoriesHandler::INVALID_VALUE;
277
if (handler.writeEmissions(*out, "", emissionClass, energyParams.get(), attributes, t, v, a, s)) {
278
l += v;
279
totalA += a;
280
totalS += s;
281
time++;
282
}
283
} catch (EmptyData&) {
284
throw ProcessError(TLF("Missing an entry in line '%'.", line));
285
} catch (NumberFormatException&) {
286
throw ProcessError(TLF("Not numeric entry in line '%'.", line));
287
}
288
}
289
}
290
if (!quiet) {
291
std::cout << "sums" << std::endl
292
<< "length:" << l << std::endl;
293
}
294
if (sumOut != nullptr) {
295
(*sumOut) << oc.getString("emission-class") << "," << lr.getFileName() << "," << time << ","
296
<< (l / time * 3.6) << "," << (totalS / time) << "," << (totalA / time) << ",";
297
handler.writeNormedSums(*sumOut, "", l);
298
}
299
}
300
if (oc.isSet("netstate-file")) {
301
XMLSubSys::runParser(handler, oc.getString("netstate-file"));
302
}
303
if (!quiet) {
304
handler.writeSums(std::cout, "");
305
}
306
delete sumOut;
307
if (out != &std::cout) {
308
delete out;
309
}
310
} catch (InvalidArgument& e) {
311
MsgHandler::getErrorInstance()->inform(e.what());
312
MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
313
ret = 1;
314
} catch (ProcessError& e) {
315
if (std::string(e.what()) != std::string("Process Error") && std::string(e.what()) != std::string("")) {
316
MsgHandler::getErrorInstance()->inform(e.what());
317
}
318
MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
319
ret = 1;
320
#ifndef _DEBUG
321
} catch (...) {
322
MsgHandler::getErrorInstance()->inform("Quitting (on unknown error).", false);
323
ret = 1;
324
#endif
325
}
326
SystemFrame::close();
327
if (ret == 0 && !quiet) {
328
std::cout << "Success." << std::endl;
329
}
330
return ret;
331
}
332
333
334
/****************************************************************************/
335
336