TraDemGen Logo  1.00.7
C++ Simulated Travel Demand Generation Library
trademgen_generateDemand.cpp
Go to the documentation of this file.
1 // //////////////////////////////////////////////////////////////////////
2 // Import section
3 // //////////////////////////////////////////////////////////////////////
4 // STL
5 #include <cassert>
6 #include <sstream>
7 #include <fstream>
8 #include <vector>
9 #include <list>
10 #include <string>
11 // //// Boost (Extended STL) ////
12 // Boost Tokeniser
13 #include <boost/tokenizer.hpp>
14 // Boost Program Options
15 #include <boost/program_options.hpp>
16 // Boost Accumulators
17 #include <boost/accumulators/accumulators.hpp>
18 #include <boost/accumulators/statistics.hpp>
19 // Boost Timer (progress display)
20 #if BOOST_VERSION_MACRO >= 107200
21 #include <boost/timer/progress_display.hpp>
22 #else // if BOOST_VERSION_MACRO >= 107200
23 #include <boost/progress.hpp>
24 #endif // ifBOOST_VERSION_MACRO >= 107200
25 // StdAir
26 #include <stdair/stdair_basic_types.hpp>
27 #include <stdair/basic/BasConst_General.hpp>
28 #include <stdair/basic/ProgressStatusSet.hpp>
29 #include <stdair/basic/DemandGenerationMethod.hpp>
30 #include <stdair/bom/EventStruct.hpp>
31 #include <stdair/bom/BookingRequestStruct.hpp>
32 #include <stdair/bom/BomDisplay.hpp>
33 #include <stdair/service/Logger.hpp>
34 // TraDemGen
36 #include <trademgen/config/trademgen-paths.hpp>
37 
38 // Aliases for namespaces
39 namespace ba = boost::accumulators;
40 
41 // //////// Specific type definitions ///////
42 typedef unsigned int NbOfRuns_T;
43 
47 typedef ba::accumulator_set<double,
48  ba::stats<ba::tag::min, ba::tag::max,
49  ba::tag::mean (ba::immediate),
50  ba::tag::sum,
51  ba::tag::variance> > stat_acc_type;
52 
53 // //////// Constants //////
57 const stdair::Filename_T K_TRADEMGEN_DEFAULT_LOG_FILENAME ("trademgen_generateDemand.log");
58 
62 const stdair::Filename_T K_TRADEMGEN_DEFAULT_INPUT_FILENAME (STDAIR_SAMPLE_DIR
63  "/demand01.csv");
64 
68 const stdair::Filename_T K_TRADEMGEN_DEFAULT_OUTPUT_FILENAME ("request.csv");
69 
73 const stdair::DemandGenerationMethod
75  stdair::DemandGenerationMethod::POI_PRO;
76 
82 
86 const stdair::RandomSeed_T K_TRADEMGEN_DEFAULT_RANDOM_SEED =
87  stdair::DEFAULT_RANDOM_SEED;
88 
93 
99 
104 
105 
109 void stat_display (std::ostream& oStream, const stat_acc_type& iStatAcc) {
110 
111  // Store current formatting flags of the output stream
112  std::ios::fmtflags oldFlags = oStream.flags();
113 
114  //
115  oStream.setf (std::ios::fixed);
116 
117  //
118  oStream << "Statistics for the demand generation runs: " << std::endl;
119  oStream << " minimum = " << ba::min (iStatAcc) << std::endl;
120  oStream << " mean = " << ba::mean (iStatAcc) << std::endl;
121  oStream << " maximum = " << ba::max (iStatAcc) << std::endl;
122  oStream << " count = " << ba::count (iStatAcc) << std::endl;
123  oStream << " variance = " << ba::variance (iStatAcc) << std::endl;
124 
125  // Reset formatting flags of output stream
126  oStream.flags (oldFlags);
127 }
128 
129 // ///////// Parsing of Options & Configuration /////////
130 // A helper function to simplify the main part.
131 template<class T> std::ostream& operator<< (std::ostream& os,
132  const std::vector<T>& v) {
133  std::copy (v.begin(), v.end(), std::ostream_iterator<T> (std::cout, " "));
134  return os;
135 }
136 
140 int readConfiguration (int argc, char* argv[], bool& ioIsBuiltin,
141  stdair::RandomSeed_T& ioRandomSeed,
142  NbOfRuns_T& ioRandomRuns,
143  stdair::Filename_T& ioInputFilename,
144  stdair::Filename_T& ioOutputFilename,
145  stdair::Filename_T& ioLogFilename,
146  stdair::DemandGenerationMethod& ioDemandGenerationMethod) {
147 
148  // Demand generation method as a single char (e.g., 'P' or 'S').
149  char lDemandGenerationMethodChar;
150 
151  // Default for the built-in input
153 
154  // Declare a group of options that will be allowed only on command line
155  boost::program_options::options_description generic ("Generic options");
156  generic.add_options()
157  ("prefix", "print installation prefix")
158  ("version,v", "print version string")
159  ("help,h", "produce help message");
160 
161  // Declare a group of options that will be allowed both on command
162  // line and in config file
163  boost::program_options::options_description config ("Configuration");
164  config.add_options()
165  ("builtin,b",
166  "The sample BOM tree can be either built-in or parsed from an input file. That latter must then be given with the -i/--input option")
167  ("seed,s",
168  boost::program_options::value<stdair::RandomSeed_T>(&ioRandomSeed)->default_value(K_TRADEMGEN_DEFAULT_RANDOM_SEED),
169  "Seed for the random generation")
170  ("draws,d",
171  boost::program_options::value<NbOfRuns_T>(&ioRandomRuns)->default_value(K_TRADEMGEN_DEFAULT_RANDOM_DRAWS),
172  "Number of runs for the demand generations")
173  ("demandgeneration,G",
174  boost::program_options::value< char >(&lDemandGenerationMethodChar)->default_value(K_TRADEMGEN_DEFAULT_DEMAND_GENERATION_METHOD_CHAR),
175  "Method used to generate the demand (i.e., the booking requests): Poisson Process (P) or Order Statistics (S)")
176  ("input,i",
177  boost::program_options::value< std::string >(&ioInputFilename)->default_value(K_TRADEMGEN_DEFAULT_INPUT_FILENAME),
178  "(CSV) input file for the demand distributions")
179  ("output,o",
180  boost::program_options::value< std::string >(&ioOutputFilename)->default_value(K_TRADEMGEN_DEFAULT_OUTPUT_FILENAME),
181  "(CSV) output file for the generated requests")
182  ("log,l",
183  boost::program_options::value< std::string >(&ioLogFilename)->default_value(K_TRADEMGEN_DEFAULT_LOG_FILENAME),
184  "Filepath for the logs")
185  ;
186 
187  // Hidden options, will be allowed both on command line and
188  // in config file, but will not be shown to the user.
189  boost::program_options::options_description hidden ("Hidden options");
190  hidden.add_options()
191  ("copyright",
192  boost::program_options::value< std::vector<std::string> >(),
193  "Show the copyright (license)");
194 
195  boost::program_options::options_description cmdline_options;
196  cmdline_options.add(generic).add(config).add(hidden);
197 
198  boost::program_options::options_description config_file_options;
199  config_file_options.add(config).add(hidden);
200 
201  boost::program_options::options_description visible ("Allowed options");
202  visible.add(generic).add(config);
203 
204  boost::program_options::positional_options_description p;
205  p.add ("copyright", -1);
206 
207  boost::program_options::variables_map vm;
208  boost::program_options::
209  store (boost::program_options::command_line_parser (argc, argv).
210  options (cmdline_options).positional(p).run(), vm);
211 
212  std::ifstream ifs ("trademgen.cfg");
213  boost::program_options::store (parse_config_file (ifs, config_file_options),
214  vm);
215  boost::program_options::notify (vm);
216 
217  if (vm.count ("help")) {
218  std::cout << visible << std::endl;
220  }
221 
222  if (vm.count ("version")) {
223  std::cout << PACKAGE_NAME << ", version " << PACKAGE_VERSION << std::endl;
225  }
226 
227  if (vm.count ("prefix")) {
228  std::cout << "Installation prefix: " << PREFIXDIR << std::endl;
230  }
231 
232  if (vm.count ("builtin")) {
233  ioIsBuiltin = true;
234  }
235  const std::string isBuiltinStr = (ioIsBuiltin == true)?"yes":"no";
236  std::cout << "The BOM should be built-in? " << isBuiltinStr << std::endl;
237 
238  if (ioIsBuiltin == false) {
239 
240  // The BOM tree should be built from parsing a demand input file
241  if (vm.count ("input")) {
242  ioInputFilename = vm["input"].as< std::string >();
243  std::cout << "Input filename is: " << ioInputFilename << std::endl;
244 
245  } else {
246  // The built-in option is not selected. However, no demand input file
247  // is specified
248  std::cerr << "Either one among the -b/--builtin and -i/--input "
249  << "options must be specified" << std::endl;
250  }
251  }
252 
253  if (vm.count ("output")) {
254  ioOutputFilename = vm["output"].as< std::string >();
255  std::cout << "Output filename is: " << ioOutputFilename << std::endl;
256  }
257 
258  if (vm.count ("log")) {
259  ioLogFilename = vm["log"].as< std::string >();
260  std::cout << "Log filename is: " << ioLogFilename << std::endl;
261  }
262 
263  if (vm.count ("demandgeneration")) {
264  ioDemandGenerationMethod =
265  stdair::DemandGenerationMethod (lDemandGenerationMethodChar);
266  std::cout << "Date-time request generation method is: "
267  << ioDemandGenerationMethod.describe() << std::endl;
268  }
269 
270  //
271  std::cout << "The random generation seed is: " << ioRandomSeed << std::endl;
272 
273  //
274  std::cout << "The number of runs is: " << ioRandomRuns << std::endl;
275 
276  return 0;
277 }
278 
279 // /////////////////////////////////////////////////////////////////////////
281  const stdair::Filename_T& iOutputFilename,
282  const NbOfRuns_T& iNbOfRuns,
283  const stdair::DemandGenerationMethod& iDemandGenerationMethod) {
284 
285  // Open and clean the .csv output file
286  std::ofstream output;
287  output.open (iOutputFilename.c_str());
288  output.clear();
289 
290  // Initialise the statistics collector/accumulator
291  stat_acc_type lStatAccumulator;
292 
293  // Retrieve the expected (mean value of the) number of events to be
294  // generated
295  const stdair::Count_T& lExpectedNbOfEventsToBeGenerated =
297 
298  // Initialise the (Boost) progress display object
299 #if BOOST_VERSION_MACRO >= 107200
300  boost::timer::progress_display
301 #else // if BOOST_VERSION_MACRO >= 107200
302  boost::progress_display
303 #endif // if BOOST_VERSION_MACRO >= 107200
304  lProgressDisplay (lExpectedNbOfEventsToBeGenerated
305  * iNbOfRuns);
306 
307  for (NbOfRuns_T runIdx = 1; runIdx <= iNbOfRuns; ++runIdx) {
308  // /////////////////////////////////////////////////////
309  output << "Run number: " << runIdx << std::endl;
310 
315  const stdair::Count_T& lActualNbOfEventsToBeGenerated =
316  ioTrademgenService.generateFirstRequests (iDemandGenerationMethod);
317 
318  // DEBUG
319  STDAIR_LOG_DEBUG ("[" << runIdx << "] Expected: "
320  << lExpectedNbOfEventsToBeGenerated << ", actual: "
321  << lActualNbOfEventsToBeGenerated);
322 
330  while (ioTrademgenService.isQueueDone() == false) {
331 
332  // Extract the next event from the event queue
333  stdair::EventStruct lEventStruct;
334  stdair::ProgressStatusSet lProgressStatusSet =
335  ioTrademgenService.popEvent (lEventStruct);
336 
337  // DEBUG
338  // STDAIR_LOG_DEBUG ("[" << runIdx << "] Poped event: '"
339  // << lEventStruct.describe() << "'.");
340 
341  // Extract the corresponding demand/booking request
342  const stdair::BookingRequestStruct& lPoppedRequest =
343  lEventStruct.getBookingRequest();
344 
345  // DEBUG
346  STDAIR_LOG_DEBUG ("[" << runIdx << "] Poped booking request: '"
347  << lPoppedRequest.describe() << "'.");
348 
349  // Dump the request into the dedicated CSV file
350  // stdair::BomDisplay::csvDisplay (output, lPoppedRequest);
351 
352  // Retrieve the corresponding demand stream key
353  const stdair::DemandGeneratorKey_T& lDemandStreamKey =
354  lPoppedRequest.getDemandGeneratorKey();
355 
356  // Assess whether more events should be generated for that demand stream
357  const bool stillHavingRequestsToBeGenerated = ioTrademgenService.
358  stillHavingRequestsToBeGenerated (lDemandStreamKey,
359  lProgressStatusSet,
360  iDemandGenerationMethod);
361 
362  // DEBUG
363  STDAIR_LOG_DEBUG (lProgressStatusSet.describe());
364  STDAIR_LOG_DEBUG ("=> [" << lDemandStreamKey << "] is now processed. "
365  << "Still generate events for that demand stream? "
366  << stillHavingRequestsToBeGenerated);
367 
368  // If there are still events to be generated for that demand stream,
369  // generate and add them to the event queue
370  if (stillHavingRequestsToBeGenerated == true) {
371 
372  stdair::BookingRequestPtr_T lNextRequest_ptr =
373  ioTrademgenService.generateNextRequest (lDemandStreamKey,
374  iDemandGenerationMethod);
375 
376  assert (lNextRequest_ptr != NULL);
377 
378  // Sanity check
379  const stdair::Duration_T lDuration =
380  lNextRequest_ptr->getRequestDateTime()
381  - lPoppedRequest.getRequestDateTime();
382  if (lDuration.total_milliseconds() < 0) {
383  STDAIR_LOG_ERROR ("[" << lDemandStreamKey
384  << "] The date-time of the generated event ("
385  << lNextRequest_ptr->getRequestDateTime()
386  << ") is lower than the date-time "
387  << "of the current event ("
388  << lPoppedRequest.getRequestDateTime() << ")");
389  assert (false);
390  }
391 
392  // DEBUG
393  STDAIR_LOG_DEBUG ("[" << lDemandStreamKey << "] Added request: '"
394  << lNextRequest_ptr->describe()
395  << "'. Is queue done? "
396  << ioTrademgenService.isQueueDone());
397  }
398  // DEBUG
399  STDAIR_LOG_DEBUG ("");
400 
401  // Update the progress display
402  ++lProgressDisplay;
403  }
404 
405  // Add the number of events to the statistics accumulator
406  lStatAccumulator (lActualNbOfEventsToBeGenerated);
407 
408  // Reset the service (including the event queue) for the next run
409  ioTrademgenService.reset();
410  }
411 
412  // DEBUG
413  STDAIR_LOG_DEBUG ("End of the demand generation. Following are some "
414  "statistics for the " << iNbOfRuns << " runs.");
415  std::ostringstream oStatStr;
416  stat_display (oStatStr, lStatAccumulator);
417  STDAIR_LOG_DEBUG (oStatStr.str());
418 
419  // DEBUG
420  const std::string& lBOMStr = ioTrademgenService.csvDisplay();
421  STDAIR_LOG_DEBUG (lBOMStr);
422 
423  // Close the output file
424  output.close();
425 }
426 
427 
428 // /////////////// M A I N /////////////////
429 int main (int argc, char* argv[]) {
430 
431  // State whether the BOM tree should be built-in or parsed from an input file
432  bool isBuiltin;
433 
434  // Random generation seed
435  stdair::RandomSeed_T lRandomSeed;
436 
437  // Number of random draws to be generated (best if greater than 100)
438  NbOfRuns_T lNbOfRuns;
439 
440  // Input file name
441  stdair::Filename_T lInputFilename;
442 
443  // Output file name
444  stdair::Filename_T lOutputFilename;
445 
446  // Output log File
447  stdair::Filename_T lLogFilename;
448 
449  // Demand generation method.
450  stdair::DemandGenerationMethod
451  lDemandGenerationMethod (K_TRADEMGEN_DEFAULT_DEMAND_GENERATION_METHOD);
452 
453  // Call the command-line option parser
454  const int lOptionParserStatus =
455  readConfiguration (argc, argv, isBuiltin, lRandomSeed, lNbOfRuns,
456  lInputFilename, lOutputFilename, lLogFilename,
457  lDemandGenerationMethod);
458 
459  if (lOptionParserStatus == K_TRADEMGEN_EARLY_RETURN_STATUS) {
460  return 0;
461  }
462 
463  // Set the log parameters
464  std::ofstream logOutputFile;
465  // Open and clean the log outputfile
466  logOutputFile.open (lLogFilename.c_str());
467  logOutputFile.clear();
468 
469  // Set up the log parameters
470  const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG, logOutputFile);
471 
472  // Initialise the TraDemGen service object
473  TRADEMGEN::TRADEMGEN_Service trademgenService (lLogParams, lRandomSeed);
474 
475  // Check wether or not a (CSV) input file should be read
476  if (isBuiltin == true) {
477  // Create a sample DemandStream object, and insert it within the BOM tree
478  trademgenService.buildSampleBom();
479 
480  } else {
481  // Create the DemandStream objects, and insert them within the BOM tree
482  const TRADEMGEN::DemandFilePath lDemandFilePath (lInputFilename);
483  trademgenService.parseAndLoad (lDemandFilePath);
484  }
485 
486  // Calculate the expected number of events to be generated.
487  generateDemand (trademgenService, lOutputFilename, lNbOfRuns,
488  lDemandGenerationMethod);
489 
490  // Close the Log outputFile
491  logOutputFile.close();
492 
493  /*
494  \note: as that program is not intended to be run on a server in
495  production, it is better not to catch the exceptions. When it
496  happens (that an exception is throwned), that way we get the
497  call stack.
498  */
499 
500  return 0;
501 }
int main(int argc, char *argv[])
void generateDemand(TRADEMGEN::TRADEMGEN_Service &ioTrademgenService, const stdair::Filename_T &iOutputFilename, const NbOfRuns_T &iNbOfRuns, const stdair::DemandGenerationMethod &iDemandGenerationMethod)
void stat_display(std::ostream &oStream, const stat_acc_type &iStatAcc)
unsigned int NbOfRuns_T
const stdair::Filename_T K_TRADEMGEN_DEFAULT_INPUT_FILENAME(STDAIR_SAMPLE_DIR "/demand01.csv")
std::ostream & operator<<(std::ostream &os, const std::vector< T > &v)
const stdair::RandomSeed_T K_TRADEMGEN_DEFAULT_RANDOM_SEED
const NbOfRuns_T K_TRADEMGEN_DEFAULT_RANDOM_DRAWS
int readConfiguration(int argc, char *argv[], bool &ioIsBuiltin, stdair::RandomSeed_T &ioRandomSeed, NbOfRuns_T &ioRandomRuns, stdair::Filename_T &ioInputFilename, stdair::Filename_T &ioOutputFilename, stdair::Filename_T &ioLogFilename, stdair::DemandGenerationMethod &ioDemandGenerationMethod)
const stdair::DemandGenerationMethod K_TRADEMGEN_DEFAULT_DEMAND_GENERATION_METHOD
const stdair::Filename_T K_TRADEMGEN_DEFAULT_OUTPUT_FILENAME("request.csv")
const char K_TRADEMGEN_DEFAULT_DEMAND_GENERATION_METHOD_CHAR
const int K_TRADEMGEN_EARLY_RETURN_STATUS
const stdair::Filename_T K_TRADEMGEN_DEFAULT_LOG_FILENAME("trademgen_generateDemand.log")
ba::accumulator_set< double, ba::stats< ba::tag::min, ba::tag::max, ba::tag::mean(ba::immediate), ba::tag::sum, ba::tag::variance > > stat_acc_type
const bool K_TRADEMGEN_DEFAULT_BUILT_IN_INPUT
class holding the services related to Travel Demand Generation.
void parseAndLoad(const DemandFilePath &)
stdair::ProgressStatusSet popEvent(stdair::EventStruct &) const
const stdair::Count_T & getExpectedTotalNumberOfRequestsToBeGenerated() const
stdair::Count_T generateFirstRequests(const stdair::DemandGenerationMethod &) const
stdair::BookingRequestPtr_T generateNextRequest(const stdair::DemandStreamKeyStr_T &, const stdair::DemandGenerationMethod &) const