TraDemGen Logo  1.00.13
C++ Simulated Travel Demand Generation Library
Loading...
Searching...
No Matches
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
39namespace ba = boost::accumulators;
40
41// //////// Specific type definitions ///////
42typedef unsigned int NbOfRuns_T;
43
47typedef 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 //////
57const stdair::Filename_T K_TRADEMGEN_DEFAULT_LOG_FILENAME ("trademgen_generateDemand.log");
58
62const stdair::Filename_T K_TRADEMGEN_DEFAULT_INPUT_FILENAME (STDAIR_SAMPLE_DIR
63 "/demand01.csv");
64
68const stdair::Filename_T K_TRADEMGEN_DEFAULT_OUTPUT_FILENAME ("request.csv");
69
73const stdair::DemandGenerationMethod
75 stdair::DemandGenerationMethod::POI_PRO;
76
82
86const stdair::RandomSeed_T K_TRADEMGEN_DEFAULT_RANDOM_SEED =
87 stdair::DEFAULT_RANDOM_SEED;
88
93
99
104
105
109void 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.
131template<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
140int 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 /////////////////
429int 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")
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)
std::ostream & operator<<(std::ostream &os, const std::vector< T > &v)
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