DiaDes  0.1
DIAgnosis of Discrete-Event System
Diagnose.cc
Go to the documentation of this file.
1 
23 #include<iostream>
24 #include<fstream>
25 #include<list>
26 #include<string>
27 #include<set>
28 #include <boost/accumulators/accumulators.hpp>
29 #include <boost/accumulators/statistics/stats.hpp>
30 #include <boost/accumulators/statistics/min.hpp>
31 #include <boost/accumulators/statistics/max.hpp>
32 #include <boost/accumulators/statistics/mean.hpp>
33 #include <boost/accumulators/statistics/variance.hpp>
34 #include <boost/date_time/posix_time/posix_time.hpp>
35 #include <utils/CmdInterface.hh>
36 #include<automata/Event.hh>
40 #include<automata/Diagnosis.hh>
41 #include<automata/History.hh>
42 #include<FaultDiagnosis.hh>
43 #include<io/xml/automata/Simulation.hh>
44 
45 
46 using std::vector;
47 using std::string;
48 using namespace boost::posix_time;
49 using namespace Diades::Automata;
50 using namespace boost::accumulators;
51 using boost::accumulators::extract::max;
52 using boost::accumulators::extract::min;
53 
54 
55 typedef enum { STATISTICS=0 , HELP =1, FAULTS = 2 } Option;
56 typedef enum { DESCOMP=0, RULES=1, XML=2, ABSTRACTION = 3, DIAGNOSER = 4} FileExtension;
57 unsigned numberOfOptions = 3;
59 
61 vector<string> options(numberOfOptions);
62 vector<bool> isSet(numberOfOptions,false);
63 
64 string description="Usage:\t diagnose --help\n\t diagnose [--statistics] [--faults evt1 evt2] file1.des_comp file2.des_comp [file3.des_comp...] sync.rules scenario.xml\n\t diagnose [--statistics] [--faults evt1 evt2] file1.des_comp scenario.xml\n\t diagnose [--statistics] [--faults evt1 evt2] file.des_comp file.abstraction scenario.xml\n\t diagnose [--statistics] [--faults evt1 evt2] file.diagnoser scenario.xml\n\n\n\t Diagnose the sequence of observations given in the scenarios. Print on the\n\t standard output the final diagnosis. Write the diagnostic history in\n\t a file 'history.archv' and the perfect diagnosis in 'perfect_history.archv'.\n\t The events listed after the --faults option are considered as faults.\n\n\t If the input models are a set of models, 'diagnose' uses a component-based\n\t algorithm. If the input model is a global one, 'diagnose' uses a global \n\t model algorithm. If the input model is a diagnoser, 'diagnose' uses a diagnoser\n\t algorithm.\n\t Options: --statistics write some statistics in a file 'output.statistics'.";
65 
67 {
68  options[STATISTICS] = "--statistics";
69  options[HELP] = "--help";
70  options[FAULTS] = "--faults";
71  fileExtensions[DESCOMP] = "des_comp";
72  fileExtensions[RULES] = "rules";
73  fileExtensions[XML] = "xml";
74  fileExtensions[ABSTRACTION] = "abstraction";
75  fileExtensions[DIAGNOSER] = "diagnoser";
76 }
77 
78 
79 
80 /************************************************************************************/
81 
82 typedef pair<time_duration,Event> EventOccurrence;
83 
85 void readParameters(int argc, char * argv[],
86  Algotype & type,
87  list<string> & modelFiles,set<Event> & faults);
88 void readScenario(const string & filename,
89  list< EventOccurrence > & simulation,
90  list< EventOccurrence > & observations);
91 void runDiagnosis(FaultDiagnosis & faultDiagnosis, const list< EventOccurrence > & observations,bool statistics);
92 
93 /************************************************************************************/
94 
95 int main(int argc, char * argv[])
96 {
99  Algotype type = Unknown;
100  list<string> modelFiles;
101  set<Event> faults;
102  readParameters(argc,argv,type,modelFiles,faults);
103  list< EventOccurrence > simulation;
104  list< EventOccurrence > observations;
105 
106  FaultDiagnosis * faultDiagnosis = 0;
107  ObservableComponent globalModel;
108  ClassicalDiagnoser diagnoser;
109  vector<const ObservableComponent *> components;
110  { verbose<VbOutput>("Loading the models..."); }
111  switch(type)
112  {
113  case Comp:
114  {
115  ParametrizedSynchronisation::ComponentVector vectorComp;
116  unsigned nbModel = modelFiles.size() - 2;
117  while(nbModel != 0)
118  {
119  ObservableComponent * component = new ObservableComponent();
120  component->importDesCompModel(modelFiles.front());
121 
122  components.push_back(component);
123  vectorComp.push_back(component);
124  modelFiles.pop_front();
125  --nbModel;
126  }
128  loadSynchronisationRules(vectorComp,modelFiles.front(),rules);
129  modelFiles.pop_front();
130  faultDiagnosis = new FaultDiagnosis(components,rules,faults);
131  break;
132  }
133  case Model:
134  {
135 
136  globalModel.importDesCompModel(modelFiles.front());
137  modelFiles.pop_front();
138  faultDiagnosis = new FaultDiagnosis(globalModel,faults);
139  break;
140  }
141  case Diagnoser:
142  {
143  std::ifstream ifs(modelFiles.front().c_str());
144  boost::archive::text_iarchive ia(ifs);
145  ia >> diagnoser;
146  string log;
147  diagnoser.sanityCheck(log);
148  modelFiles.pop_front();
149  faultDiagnosis = new FaultDiagnosis(diagnoser,faults);
150  break;
151  }
152  default:
153  {
154  cout << "ALGORITHM NOT IMPLEMENTED YET. SORRY MATE." << endl;
155  exit(1);
156  }
157  }
158  { verbose<VbOutput>("Done.\n"); }
159  { verbose<VbOutput>("Loading the scenario..."); }
160  readScenario(modelFiles.front(),simulation,observations);
161  { verbose<VbOutput>("Done.\n"); }
162  { verbose<VbOutput>("Starting the diagnosis...\n"); }
163  runDiagnosis(*faultDiagnosis,observations,isSet[STATISTICS]);
164 }
165 
166 
167 /*************************************************************************************/
168 
169 void readParameters(int argc, char * argv[],
170  Algotype & type,
171  list<string> & modelFiles,
172  set<Event> & faults)
173 {
174  if(argc < 2)
175  {
177  }
178  int index = 1;
179  string param;
180  int nbModel = 0;
181  string abstractionFile;
182  string ruleFile;
183  string xmlFile;
184  while( index < argc )
185  {
186  Option currentOption;
187  if(getOption<Option>(argv[index],options,currentOption))
188  {
189  if(isSet[currentOption])
190  {
191  printError("The option '" + options[currentOption] + "' occurs at least twice.");
192  }
193  else
194  {
195  isSet[currentOption] = true;
196  }
197  switch(currentOption)
198  {
199  case HELP:
200  {
201  if((index!=1) || (argc !=2))
202  {
203  printError("Incorrect use of option --help.");
204  }
205  else
206  {
208  }
209  break;
210  }
211  case STATISTICS:
212  {
213  ++index;
214  break;
215  }
216  case FAULTS:
217  {
218  ++index;
219  set<string> faultstring;
220  getParameterList<string>(argc,argv,options,fileExtensions,
221  index,faultstring);
222  if(faultstring.empty())
223  {
224  printError("No parameter after the option " + options[currentOption]);
225  }
226  else
227  {
228  for(const string & s : faultstring)
229  {
230  faults.insert(EventFactory::factory()->getEvent(s));
231  }
232  }
233  break;
234  }
235  default:
236  {
237  printError("Unrecognized option: " + string(argv[index]));
238  break;
239  }
240  }
241  }
242  else
243  {
244  // then it should be the name of a file
245  vector<string>::const_iterator it =
246  getFileExtension(string(argv[index]),fileExtensions.begin(),fileExtensions.end());
247 
248  if(it == fileExtensions.end())
249  {
250  printError("Unrecognized file extension in file name: " + string(argv[index]));
251  }
252 
253  // not beautiful here but i want to use a switch afterwards, so...
254  FileExtension extension = DESCOMP;
255  if(*it==fileExtensions[RULES]) { extension = RULES; }
256  if(*it==fileExtensions[XML]) { extension = XML; }
257  if(*it==fileExtensions[ABSTRACTION]) { extension = ABSTRACTION; }
258  if(*it==fileExtensions[DIAGNOSER]) { extension = DIAGNOSER; }
259  switch(extension)
260  {
261  case DIAGNOSER:
262  {
263  if(nbModel!=0)
264  {
265  printError("The Diagnose command does not accept a diagnoser and a model file at the same time.");
266  }
267  if(type == Abstract)
268  {
269  printError("The Diagnose command does not accept a diagnoser and an abstraction file at the same time.");
270  }
271  if(type == Comp)
272  {
273  printError("The Diagnose command does not accept a diagnoser and a model file at the same time.");
274  }
275  type = Diagnoser;
276  modelFiles.push_back(string(argv[index]));
277  break;
278  }
279  case DESCOMP:
280  {
281  if(type==Diagnoser)
282  {
283  printError("The Diagnose command does not accept a diagnoser and a model file at the same time.");
284  }
285  if((type==Abstract) && (nbModel==1))
286  {
287  printError("The Diagnose command does not accept several model files and an abstraction file at the same time.");
288  }
289  ++nbModel;
290  modelFiles.push_back(string(argv[index]));
291  break;
292  }
293  case ABSTRACTION:
294  {
295  if(type==Diagnoser)
296  {
297  printError("The Diagnose command does not accept a diagnoser and an abstraction file at the same time.");
298  }
299  if(nbModel>1 || (type==Comp) )
300  {
301  printError("The Diagnose command does not accept several model files and an abstraction file at the same time.");
302  }
303  abstractionFile = string(argv[index]);
304  type = Abstract;
305  break;
306  }
307  case RULES:
308  {
309  if(type==Diagnoser)
310  {
311  printError("The Diagnose command does not accept a diagnoser and an synchronisation file at the same time.");
312  }
313  if(type==Abstract)
314  {
315  printError("The Diagnose command does not accept a diagnoser and a synchronisation file at the same time.");
316 
317  }
318  if(!ruleFile.empty())
319  {
320  printError("The Diagnose command does not accept two synchronisation files at the same time.");
321  }
322  ruleFile = string(argv[index]);
323  type= Comp;
324  break;
325  }
326  case XML:
327  {
328  if(!xmlFile.empty())
329  {
330  printError("The Diagnose command does not accept two scenarios at the same time.");
331  }
332  xmlFile = string(argv[index]);
333  break;
334  }
335  }
336  ++index;
337  }
338  }
339  if(type==Unknown && nbModel !=1)
340  {
341  printError("A synchronisation file is required.");
342  }
343  if(nbModel==1 && type==Unknown)
344  {
345  type=Model;
346  }
347  if(type==Unknown)
348  {
349  printError("Sorry mate, certainly a bug but impossible to correctly interpret your command.");
350  }
351  if(type==Comp)
352  {
353  modelFiles.push_back(ruleFile);
354  }
355  if(type==Abstract)
356  {
357  modelFiles.push_back(abstractionFile);
358  }
359  if(xmlFile.empty())
360  {
361  printError("No scenario file found.");
362  }
363  modelFiles.push_back(xmlFile);
364 }
365 
366 
367 
368 
369 /***********************************************************************************/
370 
371 
372 void readScenario(const string & filename,
373  list< EventOccurrence > & simulation,
374  list< EventOccurrence > & observations)
375 {
376  back_insert_iterator< list< EventOccurrence > > simIt(simulation);
377  back_insert_iterator< list< EventOccurrence > > obsIt(observations);
378  try
379  {
380  Diades::Io::Xml::loadXmlSimulation(filename, simIt,obsIt);
381  }
382  catch(exception & e)
383  {
384  printError("The function readScenario has caught an exception when loading the file " + filename + ": \n" + e.what());
385  }
386 }
387 
388 /***********************************************************************************/
389 
390 
391 void runDiagnosis(FaultDiagnosis & faultDiagnosis, const list< EventOccurrence > & observations,
392  bool statistics)
393 {
394  // we need to store the produced Diagnosis somewhere, it will be here
395  list<Diagnosis> diagnoses;
396 
397  // let's go and start the History
398  History history;
399 
400  // let's go and start the emulated perfect History
401  History perfectHistory;
402 
403 
404 
405  // now as the observable scenario is known already, it is prerecorded in the History
406  for(const EventOccurrence & occurrence : observations)
407  {
408  history.publishObservation(history.initialTimePoint()+occurrence.first, occurrence.second);
409  perfectHistory.publishObservation(perfectHistory.initialTimePoint()+occurrence.first, occurrence.second);
410  }
411 
412  // let's publish the initial diagnosis, we suppose it is available at initial time point
413  diagnoses.push_back(Diagnosis());
414  //faultDiagnosis.getDiagnosis(diagnoses.back());
415  history.publishDiagnosis(history.initialTimePoint(),diagnoses.back());
416  perfectHistory.publishDiagnosis(perfectHistory.initialTimePoint(),diagnoses.back());
417 
418 
419  // algorithm clock, initialised at the initial time point of the history
420  time_duration algorithmClock = seconds(0);
421 
422  // for some statistics if needed
423  ofstream file;
424  accumulator_set< long, stats< tag::min, tag::max, tag::mean, tag::variance(lazy) > > stats;
425  if(statistics)
426  {
427  file.open("output.statistics");
428  }
429 
430 
431  // the described algorithms being not anytime at all, here there is only
432  // one published diagnosis after each observation. Off course,
433  // for an anytime diagnosis, several diagnosis can be published
434  // between the occurrence of two observations. That is actually the
435  // big advantage of an anytime algorithm. But to perform diagnosis
436  // publication when the diagnosis algorithm is working, it is required
437  // to implement threads that are not implemented in this version. See
438  // the work of PJ Meyer.
439  // As the result of the diagnosis algorithm presented here is
440  // always equivalent to the Samptah's diagnoser algorithm (only the duration will change)
441  // the perfect history can also be built at the same time.
442 
443  int nbObs = observations.size();
444  int currentObs = 0;
445  for(const EventOccurrence & occurrence : observations)
446  {
447  {
448  ++currentObs;
449  verbose<VbOutput>("\nObservation: %1% at time %2% (%3%/%4%).") % occurrence.second
450  % occurrence.first % currentObs % nbObs;
451  }
452  boost::posix_time::ptime initialTime(boost::posix_time::microsec_clock::local_time());
453  faultDiagnosis.diagnose(occurrence.second);
454  diagnoses.push_back(Diagnosis());
455  faultDiagnosis.getDiagnosis(diagnoses.back());
456  boost::posix_time::ptime endTime(boost::posix_time::microsec_clock::local_time());
457  time_duration algorithmicTime = endTime - initialTime;
458  if(statistics)
459  {
460  stats(algorithmicTime.total_microseconds());
461  }
475  if(algorithmClock < occurrence.first)
476  {
477  // the algorithm was sleeping
478  algorithmClock = occurrence.first + algorithmicTime;
479  }
480  else
481  {
482  // the algorithm is delayed
483  algorithmClock = algorithmClock + algorithmicTime;
484 
485  }
486 
487  // so the diagnosis provided by this algorithm for the flow from time 0 to time occurrence.first
488  // is available at time algorithmClock
489  history.publishDiagnosis(history.initialTimePoint() + algorithmClock, diagnoses.back());
490 
491  // now let us build the perfect history. The result obtained by the previous algorithm
492  // is the most accurrate so in the perfect wolrd the same result is instantaneously available
493  // at time occurrence.first
494  perfectHistory.publishDiagnosis(perfectHistory.initialTimePoint()+occurrence.first,diagnoses.back());
495  }
496 
497 
498 
499 
500  cout << endl << "Final Diagnosis:" << endl;
501  cout << diagnoses.back() << endl;
502  cout << "History saved in " << flush;
503  std::ofstream ofs1("history.archv");
504  boost::archive::text_oarchive oa1(ofs1);
505  oa1 << history;
506  cout << "history.archv" << endl;
507  cout << "Perfect history saved in " << flush;
508  std::ofstream ofs2("perfect_history.archv");
509  boost::archive::text_oarchive oa2(ofs2);
510  oa2 << perfectHistory;
511  cout << "perfect_history.archv" << endl;
512 
513  if(statistics)
514  {
515  cout << "Statistics saved in " << endl;
516  file << "/* Result are in microseconds */" << endl;
517  file << "Mean time:" << boost::accumulators::extract::mean(stats) << endl;
518  file << "Max time:" << boost::accumulators::extract::max(stats) << endl;
519  file << "Min time:" << boost::accumulators::extract::min(stats) << endl;
520  file << "Variance: " << boost::accumulators::extract::variance(stats) << endl;
521  file.close();
522  cout << "output.statistics" << endl;
523  }
524 }
void publishDiagnosis(ptime t, const Diagnosis &d)
Definition: History.hh:134
vector< string > options(numberOfOptions)
InputIterator getFileExtension(const std::basic_string< CharType, CharTraits > &fileName, InputIterator begin, InputIterator end)
Definition: StringTools.hh:57
class History
void initialiseOptions()
Definition: Diagnose.cc:66
void setVerboseLevel(Diades::Utils::VerboseLevel level)
Definition: Verbose.hh:135
vector< string > fileExtensions(numberOfFileExtensions)
vector< bool > isSet(numberOfOptions, false)
Definition: Diagnose.cc:55
Algotype
Definition: Diagnose.cc:84
FileExtension
Definition: abstract.cc:33
bool loadSynchronisationRules(const ParametrizedSynchronisation::ComponentVector &models, const string &filename, ParametrizedSynchronisation &sync)
pair< time_duration, Event > EventOccurrence
Definition: Diagnose.cc:82
string description
Definition: Diagnose.cc:64
ptime initialTimePoint() const
Definition: History.hh:146
void diagnose(const Event &obs)
An observable Component defined as a automaton.
virtual bool importDesCompModel(const string &filename)
void getDiagnosis(Diagnosis &diagnosis)
Option
Definition: abstract.cc:32
Definition: Diagnose.cc:84
void publishObservation(ptime t, const Event &e)
Definition: History.hh:121
FileExtension
Definition: Diagnose.cc:56
unsigned numberOfFileExtensions
Definition: Diagnose.cc:58
void printError(string parameter, string message)
Log log(Logger logger, const string &msg)
Definition: Log.hh:124
void runDiagnosis(FaultDiagnosis &faultDiagnosis, const list< EventOccurrence > &observations, bool statistics)
Definition: Diagnose.cc:391
void readParameters(int argc, char *argv[], Algotype &type, list< string > &modelFiles, set< Event > &faults)
Definition: Diagnose.cc:169
int main(int argc, char *argv[])
Definition: Diagnose.cc:95
Definition: Diagnose.cc:56
Option
Definition: Diagnose.cc:55
unsigned numberOfOptions
Definition: Diagnose.cc:57
void readScenario(const string &filename, list< EventOccurrence > &simulation, list< EventOccurrence > &observations)
Definition: Diagnose.cc:372
void printUsage(const po::options_description &desc)