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