TraDemGen Logo  1.00.7
C++ Simulated Travel Demand Generation Library
pytrademgen.cpp
Go to the documentation of this file.
1 // Boost Python
2 #include <boost/python.hpp>
3 // STL
4 #include <cassert>
5 #include <stdexcept>
6 #include <fstream>
7 #include <sstream>
8 #include <string>
9 // Boost Accumulators
10 #include <boost/accumulators/accumulators.hpp>
11 #include <boost/accumulators/statistics/stats.hpp>
12 #include <boost/accumulators/statistics/mean.hpp>
13 #include <boost/accumulators/statistics/moment.hpp>
14 #include <boost/accumulators/statistics/min.hpp>
15 #include <boost/accumulators/statistics/max.hpp>
16 #include <boost/accumulators/statistics/variance.hpp>
17 // Boost Timer (progress display)
18 #if BOOST_VERSION_MACRO >= 107200
19 #include <boost/timer/progress_display.hpp>
20 #else // BOOST_VERSION_MACRO >= 107200
21 #include <boost/progress.hpp>
22 #endif // BOOST_VERSION_MACRO >= 107200
23 // StdAir
24 #include <stdair/stdair_basic_types.hpp>
25 #include <stdair/basic/ProgressStatusSet.hpp>
26 #include <stdair/basic/DemandGenerationMethod.hpp>
27 #include <stdair/bom/EventStruct.hpp>
28 #include <stdair/bom/BookingRequestStruct.hpp>
29 //#include <stdair/bom/BomDisplay.hpp>
30 #include <stdair/service/Logger.hpp>
31 // TraDemGen
33 #include <trademgen/config/trademgen-paths.hpp>
34 
35 // Aliases for namespaces
36 namespace ba = boost::accumulators;
37 
38 // //////// Specific type definitions ///////
39 typedef unsigned int NbOfRuns_T;
40 
44 typedef ba::accumulator_set<double,
45  ba::stats<ba::tag::min, ba::tag::max,
46  ba::tag::mean (ba::immediate),
47  ba::tag::sum,
48  ba::tag::variance> > stat_acc_type;
49 
50 namespace TRADEMGEN {
51 
55  void stat_display (std::ostream& oStream, const stat_acc_type& iStatAcc) {
56 
57  // Store current formatting flags of the output stream
58  std::ios::fmtflags oldFlags = oStream.flags();
59 
60  //
61  oStream.setf (std::ios::fixed);
62 
63  //
64  oStream << "Statistics for the demand generation runs: " << std::endl;
65  oStream << " minimum = " << ba::min (iStatAcc) << std::endl;
66  oStream << " mean = " << ba::mean (iStatAcc) << std::endl;
67  oStream << " maximum = " << ba::max (iStatAcc) << std::endl;
68  oStream << " count = " << ba::count (iStatAcc) << std::endl;
69  oStream << " variance = " << ba::variance (iStatAcc) << std::endl;
70 
71  // Reset formatting flags of output stream
72  oStream.flags (oldFlags);
73  }
74 
78  struct Trademgener {
79  public:
83  std::string
84  trademgen (const NbOfRuns_T& iNbOfRuns,
85  const std::string& iDemandGenerationMethodString) {
86  std::ostringstream oStream;
87 
88  // Convert the input string into a demand generation method enumeration
89  const stdair::DemandGenerationMethod
90  iDemandGenerationMethod (iDemandGenerationMethodString);
91 
92  // Sanity check
93  if (_logOutputStream == NULL) {
94  oStream << "The log filepath is not valid." << std::endl;
95  return oStream.str();
96  }
97  assert (_logOutputStream != NULL);
98 
99  try {
100 
101  // DEBUG
102  *_logOutputStream << "Demand generation for " << iNbOfRuns << " runs, "
103  << "with the following method: "
104  << iDemandGenerationMethod << std::endl;
105 
106  if (_trademgenService == NULL) {
107  oStream << "The TraDemGen service has not been initialised, "
108  << "i.e., the init() method has not been called "
109  << "correctly on the Trademgener object. Please "
110  << "check that all the parameters are not empty and "
111  << "point to actual files.";
112  *_logOutputStream << oStream.str();
113  return oStream.str();
114  }
115  assert (_trademgenService != NULL);
116 
117  // Initialise the statistics collector/accumulator
118  stat_acc_type lStatAccumulator;
119 
120  // Retrieve the expected (mean value of the) number of events to be
121  // generated
122  const stdair::Count_T& lExpectedNbOfEventsToBeGenerated =
124 
125  // Initialise the (Boost) progress display object
126 #if BOOST_VERSION_MACRO >= 107200
127  boost::timer::progress_display
128 #else // BOOST_VERSION_MACRO >= 107200
129  boost::progress_display
130 #endif // BOOST_VERSION_MACRO >= 107200
131  lProgressDisplay (lExpectedNbOfEventsToBeGenerated * iNbOfRuns);
132 
133  for (NbOfRuns_T runIdx = 1; runIdx <= iNbOfRuns; ++runIdx) {
134  // /////////////////////////////////////////////////////
135  *_logOutputStream << "Run number: " << runIdx << std::endl;
136 
141  const stdair::Count_T& lActualNbOfEventsToBeGenerated =
142  _trademgenService->generateFirstRequests (iDemandGenerationMethod);
143 
144  // DEBUG
145  *_logOutputStream << "[" << runIdx << "] Expected: "
146  << lExpectedNbOfEventsToBeGenerated << ", actual: "
147  << lActualNbOfEventsToBeGenerated << std::endl;
148 
156  while (_trademgenService->isQueueDone() == false) {
157 
158  // Extract the next event from the event queue
159  stdair::EventStruct lEventStruct;
160  stdair::ProgressStatusSet lProgressStatusSet =
161  _trademgenService->popEvent (lEventStruct);
162 
163  // DEBUG
164  // STDAIR_LOG_DEBUG ("[" << runIdx << "] Poped event: '"
165  // << lEventStruct.describe() << "'.");
166 
167  // Extract the corresponding demand/booking request
168  const stdair::BookingRequestStruct& lPoppedRequest =
169  lEventStruct.getBookingRequest();
170 
171  // DEBUG
172  *_logOutputStream << "[" << runIdx << "] Poped booking request: '"
173  << lPoppedRequest.describe() << "'." << std::endl;
174 
175  // Dump the request into the dedicated CSV file
176  // stdair::BomDisplay::csvDisplay (output, lPoppedRequest);
177 
178  // Retrieve the corresponding demand stream key
179  const stdair::DemandGeneratorKey_T& lDemandStreamKey =
180  lPoppedRequest.getDemandGeneratorKey();
181 
182  // Assess whether more events should be generated for that
183  // demand stream
184  const bool stillHavingRequestsToBeGenerated = _trademgenService->
185  stillHavingRequestsToBeGenerated (lDemandStreamKey,
186  lProgressStatusSet,
187  iDemandGenerationMethod);
188 
189  // DEBUG
190  *_logOutputStream << lProgressStatusSet.describe() << std::endl;
191  *_logOutputStream << "=> [" << lDemandStreamKey
192  << "] is now processed. Still generate events "
193  << "for that demand stream? "
194  << stillHavingRequestsToBeGenerated << std::endl;
195 
196  // If there are still events to be generated for that demand
197  // stream, generate and add them to the event queue
198  if (stillHavingRequestsToBeGenerated == true) {
199 
200  stdair::BookingRequestPtr_T lNextRequest_ptr =
201  _trademgenService->generateNextRequest(lDemandStreamKey,
202  iDemandGenerationMethod);
203 
204  assert (lNextRequest_ptr != NULL);
205 
206  // Sanity check
207  const stdair::Duration_T lDuration =
208  lNextRequest_ptr->getRequestDateTime()
209  - lPoppedRequest.getRequestDateTime();
210  if (lDuration.total_milliseconds() < 0) {
211  *_logOutputStream << "[" << lDemandStreamKey
212  << "] The date-time of the generated event ("
213  << lNextRequest_ptr->getRequestDateTime()
214  << ") is lower than the date-time "
215  << "of the current event ("
216  << lPoppedRequest.getRequestDateTime()
217  << ")" << std::endl;
218  assert (false);
219  }
220 
221  // DEBUG
222  *_logOutputStream << "[" << lDemandStreamKey
223  << "] Added request: '"
224  << lNextRequest_ptr->describe()
225  << "'. Is queue done? "
226  << _trademgenService->isQueueDone()
227  << std::endl;
228  }
229  // DEBUG
230  *_logOutputStream << std::endl;
231 
232  // Update the progress display
233  ++lProgressDisplay;
234  }
235 
236  // Add the number of events to the statistics accumulator
237  lStatAccumulator (lActualNbOfEventsToBeGenerated);
238 
239  // Reset the service (including the event queue) for the next run
240  _trademgenService->reset();
241  }
242 
243  // DEBUG
244  *_logOutputStream << "End of the demand generation. Following are some "
245  << "statistics for the " << iNbOfRuns << " runs."
246  << std::endl;
247  std::ostringstream oStatStr;
248  stat_display (oStatStr, lStatAccumulator);
249  *_logOutputStream << oStatStr.str() << std::endl;
250 
251  // DEBUG
252  const std::string& lBOMStr = _trademgenService->csvDisplay();
253  *_logOutputStream << lBOMStr << std::endl;
254 
255  // DEBUG
256  *_logOutputStream << "TraDemGen output: "
257  << oStream.str() << std::endl;
258 
259  } catch (const stdair::RootException& eTrademgenError) {
260  oStream << "TraDemGen error: " << eTrademgenError.what() << std::endl;
261 
262  } catch (const std::exception& eStdError) {
263  oStream << "Error: " << eStdError.what() << std::endl;
264 
265  } catch (...) {
266  oStream << "Unknown error" << std::endl;
267  }
268 
269  //
270  oStream << "TraDemGen has completed the generation of the booking "
271  << "requests. See the log file for more details." << std::endl;
272 
273  return oStream.str();
274  }
275 
276  public:
278  Trademgener() : _trademgenService (NULL), _logOutputStream (NULL) {
279  }
280 
282  Trademgener (const Trademgener& iTrademgener)
283  : _trademgenService (iTrademgener._trademgenService),
284  _logOutputStream (iTrademgener._logOutputStream) {
285  }
286 
289  _trademgenService = NULL;
290  _logOutputStream = NULL;
291  }
292 
296  bool init (const std::string& iLogFilepath,
297  const stdair::RandomSeed_T& iRandomSeed, const bool isBuiltin,
298  const stdair::Filename_T& iDemandInputFilename) {
299  bool isEverythingOK = true;
300 
301  try {
302 
303  // Check that the file path given as input corresponds to an actual file
304  const bool isWriteable = (iLogFilepath.empty() == false);
305  // stdair::BasFileMgr::isWriteable (iLogFilepath);
306  if (isWriteable == false) {
307  isEverythingOK = false;
308  return isEverythingOK;
309  }
310 
311  // Set the log parameters
312  _logOutputStream = new std::ofstream;
313  assert (_logOutputStream != NULL);
314 
315  // Open and clean the log outputfile
316  _logOutputStream->open (iLogFilepath.c_str());
317  _logOutputStream->clear();
318 
319  // DEBUG
320  *_logOutputStream << "Python wrapper initialisation" << std::endl;
321  const stdair::BasLogParams lLogParams (stdair::LOG::DEBUG,
322  *_logOutputStream);
323 
324  // Initialise the context
325  _trademgenService = new TRADEMGEN_Service (lLogParams, iRandomSeed);
326  assert (_trademgenService != NULL);
327 
328  // Check wether or not a (CSV) input file should be read
329  if (isBuiltin == true) {
330  // Create a sample DemandStream object, and insert it within
331  // the BOM tree
332  _trademgenService->buildSampleBom();
333 
334  } else {
335  // Create the DemandStream objects, and insert them within
336  // the BOM tree
337  const DemandFilePath lDemandFilePath (iDemandInputFilename);
338  _trademgenService->parseAndLoad (lDemandFilePath);
339  }
340 
341  // DEBUG
342  *_logOutputStream << "Python wrapper initialised" << std::endl;
343 
344  } catch (const stdair::RootException& eTrademgenError) {
345  *_logOutputStream << "Trademgen error: " << eTrademgenError.what()
346  << std::endl;
347 
348  } catch (const std::exception& eStdError) {
349  *_logOutputStream << "Error: " << eStdError.what() << std::endl;
350 
351  } catch (...) {
352  *_logOutputStream << "Unknown error" << std::endl;
353  }
354 
355  return isEverythingOK;
356  }
357 
358  private:
360  TRADEMGEN_Service* _trademgenService;
361  std::ofstream* _logOutputStream;
362  };
363 
364 }
365 
366 // /////////////////////////////////////////////////////////////
367 BOOST_PYTHON_MODULE(pytrademgen) {
368  boost::python::class_<TRADEMGEN::Trademgener> ("Trademgener")
369  .def ("trademgen", &TRADEMGEN::Trademgener::trademgen)
370  .def ("init", &TRADEMGEN::Trademgener::init);
371 }
unsigned int NbOfRuns_T
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
unsigned int NbOfRuns_T
Definition: pytrademgen.cpp:39
BOOST_PYTHON_MODULE(pytrademgen)
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
Definition: pytrademgen.cpp:48
void stat_display(std::ostream &oStream, const stat_acc_type &iStatAcc)
Definition: pytrademgen.cpp:55
Wrapper structure around the C++ API, so as to expose a Python API.
Definition: pytrademgen.cpp:78
Trademgener(const Trademgener &iTrademgener)
bool init(const std::string &iLogFilepath, const stdair::RandomSeed_T &iRandomSeed, const bool isBuiltin, const stdair::Filename_T &iDemandInputFilename)
std::string trademgen(const NbOfRuns_T &iNbOfRuns, const std::string &iDemandGenerationMethodString)
Definition: pytrademgen.cpp:84
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