Jpp  17.3.0
the software that should make you happy
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
JAcousticsMonitorTest.cc
Go to the documentation of this file.
1 #include <string>
2 #include <iostream>
3 #include <fstream>
4 #include <iomanip>
5 #include <map>
6 #include <locale>
7 
8 #include "TROOT.h"
9 #include "TFile.h"
10 #include "TObject.h"
11 #include "TKey.h"
12 #include "TString.h"
13 #include "TRegexp.h"
14 #include "TGraph.h"
15 #include "TF1.h"
16 #include "TH2D.h"
17 
18 #include "JGizmo/JRootObjectID.hh"
19 #include "JGizmo/JGizmoToolkit.hh"
20 #include "JTools/JRange.hh"
22 #include "JTools/JHashMap.hh"
23 #include "JLang/JLangToolkit.hh"
24 #include "JLang/JColorFacet.hh"
25 #include "JLang/JVectorize.hh"
26 
27 #include "Jeep/JParser.hh"
28 #include "Jeep/JMessage.hh"
29 #include "Jeep/JPrint.hh"
30 #include "Jeep/JColor.hh"
31 
32 #include "JROOT/JManager.hh"
33 
34 #include "JDetector/JDetector.hh"
36 
37 namespace {
38 
39  using JTOOLS::JRange;
40 
41  /**
42  * Auxilliary data structure with test criteria.
43  */
44  struct JParameters_t {
45 
46  static const char SKIPLINE = '#'; //!< skip line character
47 
48  /**
49  * Default constructor.
50  */
51  JParameters_t() :
52  working(1),
53  expected_rate(0),
54  range(JRange<double>::DEFAULT_RANGE),
55  number_of_outliers(0)
56  {}
57 
58 
59  /**
60  * Read parameters from input stream.
61  *
62  * \param input input stream
63  * \param object parameters
64  * \return input stream
65  */
66  friend inline std::istream& operator>>(std::istream& in, JParameters_t& object)
67  {
68  using namespace std;
69  return in >> object.working >> object.expected_rate >> object.range >> object.number_of_outliers;
70  }
71 
72 
73  /**
74  * Write parameters to output stream.
75  *
76  * \param output output stream
77  * \param object parameters
78  * \return output stream
79  */
80  friend inline std::ostream& operator<<(std::ostream& out, const JParameters_t& object)
81  {
82  using namespace std;
83  using namespace JPP;
84 
85  return out << setw(6) << object.working << ' '
86  << FIXED(2,6) << object.expected_rate << ' '
87  << FIXED(2,6) << object.range.getLowerLimit() << ' '
88  << FIXED(2,6) << object.range.getUpperLimit() << ' '
89  << setw(4) << object.number_of_outliers;
90  }
91 
92  int working;
93  double expected_rate;
95  int number_of_outliers;
96  };
97 
98  /*
99  * Gets list of keys in a ROOT TDirectory and stores it on a vector.
100  *
101  * \param dir The ROOT directory
102  * \param buffer Vector to store keys
103  */
104  void readDir(TDirectory* dir,
106 
107  TIter iter(dir->GetListOfKeys());
108 
109  for (TKey* key; (key = (TKey*) iter.Next()) != NULL; ) {
110 
111  if (key->IsFolder()){
112 
113  dir->cd(key->GetName());
114 
115  TDirectory *subdir = gDirectory;
116  readDir(subdir, buffer);
117 
118  dir->cd();
119 
120  } else {
121 
122  JGIZMO::JRootObjectID objectID(MAKE_STRING(dir->GetPath() << key->GetName()));
123 
124  buffer.push_back(objectID);
125  }
126  }
127  }
128 
129 }
130 
131 
132 /**
133  *
134  * Program to test:
135  * - If there is acoustic data.
136  * - If the rate recorded by each receiver is within the expected range.
137  * - If emitters and receivers are working and compares it to what is expected.
138  *
139  * Reports failure if: no acoustic data, too large number of outliers, emitter expected to work is not working,
140  * hydrophone expected to work is not working.
141  *
142  */
143 
144 int main(int argc, char **argv)
145 {
146  using namespace std;
147  using namespace JPP;
148 
149  string inputFile;
150  string parametersFile;
151  string facet;
152  string outputFile1;
153  string outputFile2;
154  string detectorFile;
155  int debug;
156  int number_of_failures = 0;
157  int run;
158 
159  try {
160 
161  JParser<> zap("Auxiliary program to apply test criteria to 2D histograms monitoring acoustic rate per emitter.");
162 
163  zap['f'] = make_field(inputFile, "output root file from JAcousticsMonitor_short");
164  zap['P'] = make_field(parametersFile, "ASCII formatted input file with test criteria (acoustic_monitor_00000XXX.txt)");
165  zap['F'] = make_field(facet, "Color facet") = get_keys(color_facets);
166  zap['d'] = make_field(debug) = 1;
167  zap['w'] = make_field(outputFile1, "output summary file");
168  zap['t'] = make_field(outputFile2, "output root file");
169  zap['a'] = make_field(detectorFile);
170  zap['r'] = make_field(run, "run number");
171  zap(argc, argv);
172  }
173  catch(const exception &error) {
174  FATAL(error.what() << endl);
175  }
176 
177  ofstream out(outputFile1.c_str());
178  out.imbue(locale(out.getloc(), color_facets[facet]->clone()));
179  out << "ACOUSTIC MONITORING \nRun: " << run << endl;
180  out << "\n(Note: red highlights are the reason for the warning)" << endl;
181 
182  // read parameters file
183 
184  typedef map<string, JParameters_t> map_type;
185 
186  map_type zmap;
187 
188  ifstream in(parametersFile.c_str());
189 
190  if (in) {
191 
192  string key;
193  JParameters_t parameters;
194 
195  for (string buffer; getline(in, buffer); ) {
196 
197  if (!buffer.empty() && buffer[0] != JParameters_t::SKIPLINE) {
198 
199  istringstream is(buffer);
200 
201  if (is >> key >> parameters) { zmap[key] = parameters; }
202  }
203  }
204 
205  in.close();
206 
207  } else {
208  FATAL("Error opening file: " << parametersFile << endl);
209  }
210 
211  // create hist for test output
212 
214 
215  try {
216  load(detectorFile, detector);
217  }
218  catch(const JException& error) {
219  FATAL(error);
220  }
221 
222  JHashMap<int, JLocation> receivers;
223 
224  for (JDetector::const_iterator i = detector.begin(); i != detector.end(); ++i) {
225 
226  receivers[i->getID()] = i->getLocation();
227  }
228 
229  const JHashCollection<int> string1(make_array(detector.begin(), detector.end(), &JModule::getString));
230  const JRange <int> floor1 (make_array(detector.begin(), detector.end(), &JModule::getFloor));
231 
232  JManager<int, TH2D> H3(new TH2D("H[%].rate-test", NULL,
233  string1.size(), - 0.5, string1.size() - 0.5,
234  floor1.getUpperLimit() + 1, - 0.5, floor1.getUpperLimit() + 0.5));
235 
236  for (Int_t i = 1; i <= H3->GetXaxis()->GetNbins(); ++i) {
237  H3->GetXaxis()->SetBinLabel(i, MAKE_CSTRING(string1.at(i-1)));
238  }
239 
240  for (Int_t i = 1; i <= H3->GetYaxis()->GetNbins(); ++i) {
241  H3->GetYaxis()->SetBinLabel(i, MAKE_CSTRING(i-1));
242  }
243 
244  // read input file
245 
246  TFile* f = TFile::Open(inputFile.c_str());
247 
248  vector<JRootObjectID> objectIDs;
249 
250  readDir(f,objectIDs);
251 
252  // check if the monitor.root file is empty
253  int no_data = 0;
254  if(objectIDs.empty()) {
255  ++number_of_failures;
256  no_data += 1;
257  out << RED << "No acoustic data." << endl;
258  out << RESET;
259  }
260 
261  // loop over expected emitters
262 
263  for (map_type::const_iterator i = zmap.begin(); i != zmap.end(); ++i) {
264 
265  if (i->first[0] == '0') { continue; } // skip receivers parameters file
266 
267  out << "\nEmitter: " << i->first << endl;
268 
269  const TRegexp regexp(i->first);
270 
271  TH2D* h3 = H3[stoi(i->first)];
272 
273  // if no data at all, all receivers out of range
274  if (no_data > 0) {
275  for (Int_t ix = 1; ix <= h3->GetXaxis()->GetNbins(); ++ix) {
276  for (Int_t iy = 1; iy <= h3->GetYaxis()->GetNbins(); ++iy) {
277  h3->Fill(ix-1, iy-1, 1.0);
278  }
279  }
280  }
281 
282  // check if data from emitter is in input file
283  for (vector<JRootObjectID>::const_iterator objectID = objectIDs.cbegin() ; objectID != objectIDs.cend() ; ++objectID) {
284 
285  const TString& objectName = objectID->getFullObjectName();
286 
287  // data from emitter is in input file
288  if (objectName.Index(regexp) != -1) {
289 
290  // check if expected status emitter changed
291  if (!i->second.working) {
292  out << (i->second.working != 0 ? RED : GREEN);
293  out << "Emitter started working." << endl;
294  out << RESET;
295  out << "(Acoustic rates not tested)" << endl;
296  }
297 
298  // if emitter expected to work, test acoustic rate
299  if (i->second.working) {
300  TObject* p = (TObject*)f->Get(objectName);
301  TH2* h2 = NULL;
302 
303  int number_of_bins = 0;
304  int number_of_outliers = 0;
305 
306  double min_rate = i->second.expected_rate * i->second.range.getLowerLimit();
307  double max_rate = i->second.expected_rate * i->second.range.getUpperLimit();
308  int outliers = i->second.number_of_outliers;
309 
310  if (h2 == NULL && dynamic_cast<TH2*>(p) != NULL) { h2 = dynamic_cast<TH2*>(p); };
311 
312  if (h2 != NULL) {
313 
314  for (Int_t ix = 1; ix <= h2->GetXaxis()->GetNbins(); ++ix) {
315  for (Int_t iy = 1; iy <= h2->GetYaxis()->GetNbins(); ++iy) {
316 
317  const Double_t z = h2->GetBinContent(ix, iy);
318  string du = to_string(h2->GetXaxis()->GetBinLabel(ix));
319  string floor = to_string(h2->GetYaxis()->GetBinLabel(iy));
320 
321  du.insert(du.begin(), 4 - du.length(), '0');
322  floor.insert(floor.begin(), 3 - floor.length(), '0');
323  const string id = du + '.' + floor;
324 
325  int working = 1;
326  if (zmap.find(id)!=zmap.end()) { working = zmap.find(id)->second.working; }
327 
328  ++number_of_bins;
329 
330  // acoustic rate out of range
331  if (z < min_rate || z > max_rate) {
332 
333  h3->Fill(ix-1, iy-1, 1.0);
334 
335  ++number_of_outliers;
336  if (working) { // receiver expected to work
337 
338  if (floor == "000" && z == 0) { // if hydrophone doesn't work
339  out << "DU " << du << ", floor " << floor << " : Acoustic rate out of range -> " << z << " Hz." << RED << " Hydrophone stopped working." << endl;
340  out << RESET;
341  ++number_of_failures;
342  } else {
343  out << "DU " << du << ", floor " << floor << " : Acoustic rate out of range -> " << z << " Hz." << endl;
344  }
345  }
346  } else if (!working) { // receiver expected to not work
347  out << "DU " << du << ", floor " << floor << " : Working again -> " << z << " Hz." << endl;
348  }
349  }
350  }
351 
352  } else { FATAL("Object at " << objectName << " is not TH2." << endl); }
353 
354  out << (number_of_outliers > outliers ? RED : GREEN) << "Number of outliers = " << number_of_outliers << "/" << number_of_bins << endl;
355  out << RESET;
356 
357  if (number_of_outliers > outliers) {
358 
359  ++number_of_failures;
360  out << (number_of_outliers > outliers ? RED : GREEN) << "Test failed." << endl;
361  out << RESET;
362  } else {
363 
364  out << (outliers >= number_of_outliers ? GREEN : RED) << "Test passed." << endl;
365  out << RESET;
366  }
367  }
368  break;
369 
370 
371  // data from emitter is not in input file
372  } else if (objectID + 1 == objectIDs.cend()) {
373 
374  // for all receivers rate out of range
375  for (Int_t ix = 1; ix <= h3->GetXaxis()->GetNbins(); ++ix) {
376  for (Int_t iy = 1; iy <= h3->GetYaxis()->GetNbins(); ++iy) {
377  h3->Fill(ix-1, iy-1, 1.0);
378  }
379  }
380 
381  // check if expected status emitter changed
382  if (i->second.working) {
383  ++number_of_failures;
384  out << (i->second.working != 0 ? RED : GREEN) << "Emitter stopped working." << endl;
385  out << RESET;
386  } else {
387  out << "Emitter is expected to not work." << endl;
388  }
389  }
390  }
391  }
392  out.close();
393 
394  TFile out2(outputFile2.c_str(), "recreate");
395 
396  out2 << H3;
397 
398  out2.Write();
399  out2.Close();
400 
401  // if number_of_failures > 0 program output needs to be reported
402  if (number_of_failures > 0) {
403  number_of_failures = 1;
404  cout << number_of_failures << endl;
405  }
406  return 0;
407 }
Utility class to parse command line options.
Definition: JParser.hh:1517
General exception.
Definition: JException.hh:23
int main(int argc, char *argv[])
Definition: Main.cc:15
General purpose class for hash map of unique keys.
Definition: JHashMap.hh:72
General purpose class for hash map of unique elements.
Detector data structure.
Definition: JDetector.hh:89
o $QUALITY_ROOT d $DEBUG!CHECK_EXIT_CODE JPlot1D f
Definition: JDataQuality.sh:76
Definition: JRoot.hh:19
*fatal Wrong number of arguments esac JCookie sh typeset Z DETECTOR typeset Z SOURCE_RUN typeset Z TARGET_RUN set_variable PARAMETERS_FILE $WORKDIR parameters
Definition: diff-Tuna.sh:38
#define MAKE_CSTRING(A)
Make C-string.
Definition: JPrint.hh:136
General purpose class for a hash collection of unique elements.
Auxiliary class to handle file name, ROOT directory and object name.
Dynamic ROOT object management.
Auxiliary data structure for floating point format specification.
Definition: JManip.hh:446
is
Definition: JDAQCHSM.chsm:167
Data structure for detector geometry and calibration.
#define MAKE_STRING(A)
Make string.
Definition: JPrint.hh:127
static const JColorFacetMap_t color_facets
Color facets.
Definition: JColorFacet.hh:332
Auxiliary class to manage set of compatible ROOT objects (e.g. histograms) using unique keys...
Definition: JManager.hh:43
I/O formatting auxiliaries.
Detector file.
Definition: JHead.hh:226
I/O coloring auxiliaries.
#define make_field(A,...)
macro to convert parameter to JParserTemplateElement object
Definition: JParser.hh:1993
const array_type< JValue_t > & make_array(const JValue_t(&array)[N])
Method to create array of values.
Definition: JVectorize.hh:54
T getUpperLimit() const
Get upper limit.
Definition: JRange.hh:213
std::istream & getline(std::istream &in, JString &object)
Read string from input stream until end of line.
Definition: JString.hh:478
Auxiliary methods to convert data members or return values of member methods of a set of objects to a...
Range of values.
Definition: JRange.hh:38
General purpose messaging.
#define FATAL(A)
Definition: JMessage.hh:67
z range($ZMAX-$ZMIN)< $MINIMAL_DZ." fi fi typeset -Z 4 STRING typeset -Z 2 FLOOR JPlot1D -f $
std::istream & operator>>(std::istream &in, JAANET::JHead &header)
Read header from input.
Definition: JHead.hh:1756
void load(const std::string &file_name, JDetector &detector)
Load detector from input file.
Auxiliary class to define a range between two values.
Utility class to parse command line options.
std::string to_string(const T &value)
Convert value to string.
std::ostream & operator<<(std::ostream &stream, const CLBCommonHeader &header)
do set_variable DETECTOR_TXT $WORKDIR detector
then fatal Wrong number of arguments fi set_variable DETECTOR $argv[1] set_variable INPUT_FILE $argv[2] eval JPrintDetector a $DETECTOR O IDENTIFIER eval JPrintDetector a $DETECTOR O SUMMARY JAcoustics sh $DETECTOR_ID source JAcousticsToolkit sh CHECK_EXIT_CODE typeset A EMITTERS get_tripods $WORKDIR tripod txt EMITTERS get_transmitters $WORKDIR transmitter txt EMITTERS for EMITTER in
Definition: JCanberra.sh:46
const array_type< JKey_t > & get_keys(const std::map< JKey_t, JValue_t, JComparator_t, JAllocator_t > &data)
Method to create array of keys of map.
Definition: JVectorize.hh:139
int debug
debug level
void readDir(TDirectory *dir, std::vector< TString > &v)