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