SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
od2trips_main.cpp
Go to the documentation of this file.
1 /****************************************************************************/
10 // Main for OD2TRIPS
11 /****************************************************************************/
12 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
13 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors
14 /****************************************************************************/
15 //
16 // This file is part of SUMO.
17 // SUMO is free software: you can redistribute it and/or modify
18 // it under the terms of the GNU General Public License as published by
19 // the Free Software Foundation, either version 3 of the License, or
20 // (at your option) any later version.
21 //
22 /****************************************************************************/
23 
24 
25 // ===========================================================================
26 // included modules
27 // ===========================================================================
28 #ifdef _MSC_VER
29 #include <windows_config.h>
30 #else
31 #include <config.h>
32 #endif
33 
34 #ifdef HAVE_VERSION_H
35 #include <version.h>
36 #endif
37 
38 #include <iostream>
39 #include <algorithm>
40 #include <math.h>
41 #include <cstdlib>
42 #include <string>
43 #include <xercesc/parsers/SAXParser.hpp>
44 #include <xercesc/sax2/SAX2XMLReader.hpp>
45 #include <utils/options/Option.h>
52 #include <utils/common/ToString.h>
53 #include <utils/xml/XMLSubSys.h>
57 #include <od2trips/ODMatrix.h>
59 #include <utils/common/SUMOTime.h>
66 #include <utils/common/SUMOTime.h>
67 
68 #ifdef CHECK_MEMORY_LEAKS
69 #include <foreign/nvwa/debug_new.h>
70 #endif // CHECK_MEMORY_LEAKS
71 
72 
73 // ===========================================================================
74 // functions
75 // ===========================================================================
76 void
79  oc.addCallExample("-c <CONFIGURATION>", "run with configuration file");
80 
81  // insert options sub-topics
82  SystemFrame::addConfigurationOptions(oc); // fill this subtopic, too
83  oc.addOptionSubTopic("Input");
84  oc.addOptionSubTopic("Output");
85  oc.addOptionSubTopic("Time");
86  oc.addOptionSubTopic("Processing");
87  oc.addOptionSubTopic("Defaults");
88  SystemFrame::addReportOptions(oc); // fill this subtopic, too
89 
90 
91  // register the file input options
92  oc.doRegister("net-file", 'n', new Option_FileName());
93  oc.addSynonyme("net-file", "net");
94  oc.addDescription("net-file", "Input", "Loads network (districts) from FILE");
95 
96  oc.doRegister("od-matrix-files", 'd', new Option_FileName());
97  oc.addSynonyme("od-matrix-files", "od-files");
98  oc.addSynonyme("od-matrix-files", "od");
99  oc.addDescription("od-matrix-files", "Input", "Loads O/D-files from FILE(s)");
100 
101 
102  // register the file output options
103  oc.doRegister("output-file", 'o', new Option_FileName());
104  oc.addSynonyme("output-file", "output", true);
105  oc.addDescription("output-file", "Output", "Writes trip definitions into FILE");
106 
107  oc.doRegister("ignore-vehicle-type", new Option_Bool(false));
108  oc.addSynonyme("ignore-vehicle-type", "no-vtype", true);
109  oc.addDescription("ignore-vehicle-type", "Output", "Does not save vtype information");
110 
111 
112  // register the time settings
113  oc.doRegister("begin", 'b', new Option_String("0", "TIME"));
114  oc.addDescription("begin", "Time", "Defines the begin time; Previous trips will be discarded");
115 
116  oc.doRegister("end", 'e', new Option_String(SUMOTIME_MAXSTRING, "TIME"));
117  oc.addDescription("end", "Time", "Defines the end time; Later trips will be discarded; Defaults to the maximum time that SUMO can represent");
118 
119 
120  // register the data processing options
121  oc.doRegister("scale", 's', new Option_Float(1));
122  oc.addDescription("scale", "Processing", "Scales the loaded flows by FLOAT");
123 
124  oc.doRegister("spread.uniform", new Option_Bool(false));
125  oc.addDescription("spread.uniform", "Processing", "Spreads trips uniformly over each time period");
126 
127  oc.doRegister("vtype", new Option_String(""));
128  oc.addDescription("vtype", "Processing", "Defines the name of the vehicle type to use");
129 
130  oc.doRegister("prefix", new Option_String(""));
131  oc.addDescription("prefix", "Processing", "Defines the prefix for vehicle names");
132 
133  oc.doRegister("timeline", new Option_String());
134  oc.addDescription("timeline", "Processing", "Uses STR as a timeline definition");
135 
136  oc.doRegister("timeline.day-in-hours", new Option_Bool(false));
137  oc.addDescription("timeline.day-in-hours", "Processing", "Uses STR as a 24h-timeline definition");
138 
139  oc.doRegister("dismiss-loading-errors", new Option_Bool(false)); // !!! describe, document
140  oc.addDescription("dismiss-loading-errors", "Processing", "Continue on broken input");
141 
142  oc.doRegister("no-step-log", new Option_Bool(false));
143  oc.addDescription("no-step-log", "Processing", "Disable console output of current time step");
144 
145 
146  // register defaults options
147  oc.doRegister("departlane", new Option_String("free"));
148  oc.addDescription("departlane", "Defaults", "Assigns a default depart lane");
149 
150  oc.doRegister("departpos", new Option_String());
151  oc.addDescription("departpos", "Defaults", "Assigns a default depart position");
152 
153  oc.doRegister("departspeed", new Option_String("max"));
154  oc.addDescription("departspeed", "Defaults", "Assigns a default depart speed");
155 
156  oc.doRegister("arrivallane", new Option_String());
157  oc.addDescription("arrivallane", "Defaults", "Assigns a default arrival lane");
158 
159  oc.doRegister("arrivalpos", new Option_String());
160  oc.addDescription("arrivalpos", "Defaults", "Assigns a default arrival position");
161 
162  oc.doRegister("arrivalspeed", new Option_String());
163  oc.addDescription("arrivalspeed", "Defaults", "Assigns a default arrival speed");
164 
165  // add rand options
167 }
168 
169 
171 parseTimeLine(const std::vector<std::string> &def, bool timelineDayInHours) {
172  bool interpolating = !timelineDayInHours;
173  PositionVector points;
174  SUMOReal prob = 0;
175  if (timelineDayInHours) {
176  if (def.size() != 24) {
177  throw ProcessError("Assuming 24 entries for a day timeline, but got " + toString(def.size()) + ".");
178  }
179  for (int chour = 0; chour < 24; ++chour) {
180  prob = TplConvert<char>::_2SUMOReal(def[chour].c_str());
181  points.push_back(Position((SUMOReal)(chour * 3600), prob));
182  }
183  points.push_back(Position((SUMOReal)(24 * 3600), prob));
184  } else {
185  size_t i = 0;
186  while (i < def.size()) {
187  StringTokenizer st2(def[i++], ":");
188  if (st2.size() != 2) {
189  throw ProcessError("Broken time line definition: missing a value in '" + def[i - 1] + "'.");
190  }
191  int time = TplConvert<char>::_2int(st2.next().c_str());
192  prob = TplConvert<char>::_2SUMOReal(st2.next().c_str());
193  points.push_back(Position((SUMOReal) time, prob));
194  }
195  }
196  return Distribution_Points("N/A", points, interpolating);
197 }
198 
199 
200 bool
203  bool ok = true;
204  if (!oc.isSet("net-file")) {
205  WRITE_ERROR("No net input file (-n) specified.");
206  ok = false;
207  }
208  if (!oc.isSet("od-matrix-files")) {
209  WRITE_ERROR("No input specified.");
210  ok = false;
211  }
212  if (!oc.isSet("output-file")) {
213  WRITE_ERROR("No trip table output file (-o) specified.");
214  ok = false;
215  }
216  //
217  ok &= (!oc.isSet("departlane") || SUMOVehicleParameter::departlaneValidate(oc.getString("departlane")));
218  ok &= (!oc.isSet("departpos") || SUMOVehicleParameter::departposValidate(oc.getString("departpos")));
219  ok &= (!oc.isSet("departspeed") || SUMOVehicleParameter::departspeedValidate(oc.getString("departspeed")));
220  ok &= (!oc.isSet("arrivallane") || SUMOVehicleParameter::arrivallaneValidate(oc.getString("arrivallane")));
221  ok &= (!oc.isSet("arrivalpos") || SUMOVehicleParameter::arrivalposValidate(oc.getString("arrivalpos")));
222  ok &= (!oc.isSet("arrivalspeed") || SUMOVehicleParameter::arrivalspeedValidate(oc.getString("arrivalspeed")));
223  return ok;
224 }
225 
226 
227 void
229  // check whether the user gave a net filename
230  if (!oc.isSet("net-file")) {
231  WRITE_ERROR("You must supply a network ('-n').");
232  return;
233  }
234  // get the file name and set it
235  std::string file = oc.getString("net-file");
236  if (!FileHelpers::exists(file)) {
237  throw ProcessError("Could not find network '" + file + "' to load.");
238  }
239  PROGRESS_BEGIN_MESSAGE("Loading districts from '" + file + "'");
240  // build the xml-parser and handler
241  ODDistrictHandler handler(districts, file);
242  if (!XMLSubSys::runParser(handler, file)) {
244  } else {
246  }
247 }
248 
249 
250 std::string
252  std::string line;
253  do {
254  line = lr.readLine();
255  if (line[0] != '*') {
256  return StringUtils::prune(line);
257  }
258  } while (lr.good() && lr.hasMore());
259  throw ProcessError();
260 }
261 
262 
263 SUMOTime
264 parseSingleTime(const std::string& time) {
265  if (time.find('.') == std::string::npos) {
266  throw OutOfBoundsException();
267  }
268  std::string hours = time.substr(0, time.find('.'));
269  std::string minutes = time.substr(time.find('.') + 1);
270  return (SUMOTime) TplConvert<char>::_2int(hours.c_str()) * 3600 + TplConvert<char>::_2int(minutes.c_str()) * 60;
271 }
272 
273 
274 std::pair<SUMOTime, SUMOTime>
276  std::string line = getNextNonCommentLine(lr);
277  try {
279  SUMOTime begin = parseSingleTime(st.next());
280  SUMOTime end = parseSingleTime(st.next());
281  if (begin >= end) {
282  throw ProcessError("Begin time is larger than end time.");
283  }
284  return std::make_pair(begin, end);
285  } catch (OutOfBoundsException&) {
286  throw ProcessError("Broken period definition '" + line + "'.");
287  } catch (NumberFormatException&) {
288  throw ProcessError("Broken period definition '" + line + "'.");
289  }
290 }
291 
292 
293 SUMOReal
295  std::string line = getNextNonCommentLine(lr);
296  SUMOReal factor = -1;
297  try {
298  factor = TplConvert<char>::_2SUMOReal(line.c_str()) * scale;
299  } catch (NumberFormatException&) {
300  throw ProcessError("Broken factor: '" + line + "'.");
301  }
302  return factor;
303 }
304 
305 
306 
307 void
308 readV(LineReader& lr, ODMatrix& into, SUMOReal scale,
309  std::string vehType, bool matrixHasVehType) {
310  PROGRESS_BEGIN_MESSAGE("Reading matrix '" + lr.getFileName() + "' stored as VMR");
311  // parse first defs
312  std::string line;
313  if (matrixHasVehType) {
314  line = getNextNonCommentLine(lr);
315  if (vehType == "") {
316  vehType = StringUtils::prune(line);
317  }
318  }
319 
320  // parse time
321  std::pair<SUMOTime, SUMOTime> times = readTime(lr);
322  SUMOTime begin = times.first;
323  SUMOTime end = times.second;
324 
325  // factor
326  SUMOReal factor = readFactor(lr, scale);
327 
328  // districts
329  line = getNextNonCommentLine(lr);
330  int districtNo = TplConvert<char>::_2int(StringUtils::prune(line).c_str());
331  // parse district names (normally ints)
332  std::vector<std::string> names;
333  do {
334  line = getNextNonCommentLine(lr);
336  while (st2.hasNext()) {
337  names.push_back(st2.next());
338  }
339  } while ((int) names.size() != districtNo);
340 
341  // parse the cells
342  for (std::vector<std::string>::iterator si = names.begin(); si != names.end(); ++si) {
343  std::vector<std::string>::iterator di = names.begin();
344  //
345  do {
346  line = getNextNonCommentLine(lr);
347  if (line.length() == 0) {
348  continue;
349  }
350  try {
352  while (st2.hasNext()) {
353  assert(di != names.end());
354  SUMOReal vehNumber = TplConvert<char>::_2SUMOReal(st2.next().c_str()) * factor;
355  if (vehNumber != 0) {
356  into.add(vehNumber, begin, end, *si, *di, vehType);
357  }
358  if (di == names.end()) {
359  throw ProcessError("More entries than districts found.");
360  }
361  ++di;
362  }
363  } catch (NumberFormatException&) {
364  throw ProcessError("Not numeric vehicle number in line '" + line + "'.");
365  }
366  if (!lr.hasMore()) {
367  break;
368  }
369  } while (di != names.end());
370  }
372 }
373 
374 
375 void
376 readO(LineReader& lr, ODMatrix& into, SUMOReal scale,
377  std::string vehType, bool matrixHasVehType) {
378  PROGRESS_BEGIN_MESSAGE("Reading matrix '" + lr.getFileName() + "' stored as OR");
379  // parse first defs
380  std::string line;
381  if (matrixHasVehType) {
382  line = getNextNonCommentLine(lr);
383  int type = TplConvert<char>::_2int(StringUtils::prune(line).c_str());
384  if (vehType == "") {
385  vehType = toString(type);
386  }
387  }
388 
389  // parse time
390  std::pair<SUMOTime, SUMOTime> times = readTime(lr);
391  SUMOTime begin = times.first;
392  SUMOTime end = times.second;
393 
394  // factor
395  SUMOReal factor = readFactor(lr, scale);
396 
397  // parse the cells
398  while (lr.hasMore()) {
399  line = getNextNonCommentLine(lr);
400  if (line.length() == 0) {
401  continue;
402  }
404  if (st2.size() == 0) {
405  continue;
406  }
407  try {
408  std::string sourceD = st2.next();
409  std::string destD = st2.next();
410  SUMOReal vehNumber = TplConvert<char>::_2SUMOReal(st2.next().c_str()) * factor;
411  if (vehNumber != 0) {
412  into.add(vehNumber, begin, end, sourceD, destD, vehType);
413  }
414  } catch (OutOfBoundsException&) {
415  throw ProcessError("Missing at least one information in line '" + line + "'.");
416  } catch (NumberFormatException&) {
417  throw ProcessError("Not numeric vehicle number in line '" + line + "'.");
418  }
419  }
421 }
422 
423 
424 void
426  std::vector<std::string> files = oc.getStringVector("od-files");
427  // check
428  if (files.size() == 0) {
429  throw ProcessError("No files to parse are given.");
430  }
431  // parse
432  for (std::vector<std::string>::iterator i = files.begin(); i != files.end(); ++i) {
433  LineReader lr(*i);
434  if (!lr.good()) {
435  throw ProcessError("Could not open '" + (*i) + "'.");
436  }
437  std::string type = lr.readLine();
438  // get the type only
439  if (type.find(';') != std::string::npos) {
440  type = type.substr(0, type.find(';'));
441  }
442  // parse type-dependant
443  if (type.length() > 1 && type[1] == 'V') {
444  // process ptv's 'V'-matrices
445  if (type.find('N') != std::string::npos) {
446  throw ProcessError("'" + *i + "' does not contain the needed information about the time described.");
447  }
448  readV(lr, into, oc.getFloat("scale"), oc.getString("vtype"), type.find('M') != std::string::npos);
449  } else if (type.length() > 1 && type[1] == 'O') {
450  // process ptv's 'O'-matrices
451  if (type.find('N') != std::string::npos) {
452  throw ProcessError("'" + *i + "' does not contain the needed information about the time described.");
453  }
454  readO(lr, into, oc.getFloat("scale"), oc.getString("vtype"), type.find('M') != std::string::npos);
455  } else {
456  throw ProcessError("'" + *i + "' uses an unknown matrix type '" + type + "'.");
457  }
458  }
459 }
460 
461 
462 /* -------------------------------------------------------------------------
463  * main
464  * ----------------------------------------------------------------------- */
465 int
466 main(int argc, char** argv) {
468  // give some application descriptions
469  oc.setApplicationDescription("Importer of O/D-matrices for the road traffic simulation SUMO.");
470  oc.setApplicationName("od2trips", "SUMO od2trips Version " + (std::string)VERSION_STRING);
471  int ret = 0;
472  try {
473  // initialise subsystems
474  XMLSubSys::init(false);
475  fillOptions();
476  OptionsIO::getOptions(true, argc, argv);
477  if (oc.processMetaOptions(argc < 2)) {
480  return 0;
481  }
483  if (!checkOptions()) {
484  throw ProcessError();
485  }
487  // load the districts
488  ODDistrictCont districts;
489  loadDistricts(districts, oc);
490  if (districts.size() == 0) {
491  throw ProcessError("No districts loaded...");
492  }
493  // load the matrix
494  ODMatrix matrix(districts);
495  loadMatrix(oc, matrix);
496  if (matrix.getNoLoaded() == 0) {
497  throw ProcessError("No vehicles loaded...");
498  }
499  if (MsgHandler::getErrorInstance()->wasInformed() && !oc.getBool("dismiss-loading-errors")) {
500  throw ProcessError("Loading failed...");
501  }
502  WRITE_MESSAGE(toString(matrix.getNoLoaded()) + " vehicles loaded.");
503  // apply a curve if wished
504  if (oc.isSet("timeline")) {
505  matrix.applyCurve(parseTimeLine(oc.getStringVector("timeline"), oc.getBool("timeline.day-in-hours")));
506  }
507  // write
508  if (!OutputDevice::createDeviceByOption("output-file", "trips")) {
509  throw ProcessError("No output name is given.");
510  }
511  OutputDevice& dev = OutputDevice::getDeviceByOption("output-file");
512  matrix.write(SUMOTime(string2time(oc.getString("begin")) / 1000.), SUMOTime(string2time(oc.getString("end")) / 1000.),
513  dev, oc.getBool("spread.uniform"), oc.getBool("ignore-vehicle-type"), oc.getString("prefix"), !oc.getBool("no-step-log"));
514  WRITE_MESSAGE(toString(matrix.getNoDiscarded()) + " vehicles discarded.");
515  WRITE_MESSAGE(toString(matrix.getNoWritten()) + " vehicles written.");
516  } catch (ProcessError& e) {
517  if (std::string(e.what()) != std::string("Process Error") && std::string(e.what()) != std::string("")) {
518  WRITE_ERROR(e.what());
519  }
520  MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
521  ret = 1;
522 #ifndef _DEBUG
523  } catch (...) {
524  MsgHandler::getErrorInstance()->inform("Quitting (on unknown error).", false);
525  ret = 1;
526 #endif
527  }
530  if (ret == 0) {
531  std::cout << "Success." << std::endl;
532  }
533  return ret;
534 }
535 
536 
537 
538 /****************************************************************************/
539