]> git.uio.no Git - u/mrichter/AliRoot.git/blob - STEER/AliSurveyObj.cxx
Cleanup. Comments added.
[u/mrichter/AliRoot.git] / STEER / AliSurveyObj.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /////////////////////////////////////////////////////////////////////
17 //                                                                 //
18 //  class AliSurveyObj                                             //
19 //  Retrieve and Convert survey data into ROOT Objects             //
20 //                                                                 //
21 /////////////////////////////////////////////////////////////////////
22
23 #include "AliSurveyObj.h"
24
25 //ROOT includes
26 #include "TROOT.h"
27 #include "Riostream.h"
28 #include "TObjArray.h"
29 #include "TGrid.h"
30 #include "TFile.h"
31 #include "TObjString.h"
32
33 //AliROOT includes
34 #include "AliLog.h"
35
36 ClassImp(AliSurveyObj)
37   
38 //_____________________________________________________________________________
39 AliSurveyObj::AliSurveyObj():
40   TObject(),
41   fTitle(""),
42   fDate(""),
43   fDetector(""),
44   fURL("http://edms.cern.ch/"),
45   fReportNr(-1),
46   fVersion(-1),
47   fObs(""),
48   fCoordSys(""),
49   fUnits(""),
50   fNrColumns(-1),
51   fColNames(""),
52   fIsValid(kFALSE),
53   fGridUser(""),
54   fDataPoints(new TObjArray(1))
55 {
56   // constructor
57   fDataPoints->SetOwner(kTRUE);
58 }
59
60
61 //_____________________________________________________________________________
62 AliSurveyObj::~AliSurveyObj() {
63   //destructor
64   if (fDataPoints) {
65     for (Int_t i = 0; i < fDataPoints->GetEntries(); ++i) delete fDataPoints->At(i);
66     fDataPoints->Delete();
67     fDataPoints = 0;
68   }
69 }
70
71
72 //_____________________________________________________________________________
73 AliSurveyObj::AliSurveyObj(const AliSurveyObj& surveyObj):
74   TObject(),
75   fTitle(surveyObj.fTitle),
76   fDate(surveyObj.fDate),
77   fDetector(surveyObj.fDetector),
78   fURL(surveyObj.fURL),
79   fReportNr(surveyObj.fReportNr),
80   fVersion(surveyObj.fVersion),
81   fObs(surveyObj.fObs),
82   fCoordSys(surveyObj.fCoordSys),
83   fUnits(surveyObj.fUnits),
84   fNrColumns(surveyObj.fNrColumns),
85   fColNames(surveyObj.fColNames),
86   fIsValid(surveyObj.fIsValid),
87   fGridUser(surveyObj.fGridUser),
88   fDataPoints(new TObjArray(1))
89 {
90   // copy constructor
91   TObject *curr = surveyObj.fDataPoints->First();
92   while (curr != 0) {
93     fDataPoints->Add(curr);
94     curr = surveyObj.fDataPoints->After(curr);
95   }
96 }
97
98 //_____________________________________________________________________________
99 AliSurveyObj& AliSurveyObj::operator=(const AliSurveyObj& surveyObj)
100 {
101   // assignment operator
102   if (this != &surveyObj) {
103     fTitle = surveyObj.fTitle;
104     fDate = surveyObj.fDate;
105     fDetector = surveyObj.fDetector;
106     fURL = surveyObj.fURL;
107     fReportNr = surveyObj.fReportNr;
108     fVersion = surveyObj.fVersion;
109     fObs = surveyObj.fObs;
110     fCoordSys = surveyObj.fCoordSys;
111     fUnits = surveyObj.fUnits;
112     fNrColumns = surveyObj.fNrColumns;
113     fColNames = surveyObj.fColNames;
114     fIsValid = surveyObj.fIsValid;
115     fGridUser = surveyObj.fGridUser;
116     TObject *curr = surveyObj.fDataPoints->First();
117     while (curr != 0) {
118       fDataPoints->Add(curr);
119       curr = surveyObj.fDataPoints->After(curr);
120     }
121   }
122   return *this;
123 }
124
125
126 //_____________________________________________________________________________
127 void AliSurveyObj::AddPoint(AliSurveyPoint* point) {
128   // Adds a point to the TObjArray which containst the list of points
129   fDataPoints->Add(point);
130   return;
131 }
132
133
134 //_____________________________________________________________________________
135 Bool_t AliSurveyObj::Connect(const char *gridUrl, const char *user) {
136   // Connects to the grid
137
138   // If the same "Grid" is alreay active, skip connection
139   if (!gGrid || gridUrl != gGrid->GridUrl() ||
140       (( user != "" ) && ( user != gGrid->GetUser() )) ) {
141     // connection to the Grid
142     AliInfo("\nConnecting to the Grid...");
143     if (gGrid) {
144       AliInfo(Form("gGrid = %x; GridUrl = %s; gGrid->GridUrl() = %s", 
145                    gGrid, gridUrl, gGrid->GridUrl()));
146       AliInfo(Form("User = %s; gGrid->GetUser() = %s",
147                    user, gGrid->GetUser()));
148     }
149     TGrid::Connect(gridUrl,user);
150   }
151         
152   if(!gGrid) {
153     AliError("Connection failed!");
154     return kFALSE;
155   }
156   return kTRUE;
157 }
158
159
160 //_____________________________________________________________________________
161 Bool_t AliSurveyObj::OpenFile(TString openString) {
162   // Opens the file and reads it to a buffer
163   TString storage = "alien://alice.cern.ch";
164
165   Printf("TFile::Open string: \n -> \"%s\"\n", openString.Data());
166
167   if (openString.BeginsWith("alien://"))
168     if (!Connect(storage.Data(), fGridUser.Data())) {
169       AliError(Form("Error connecting to GRID"));
170       return kFALSE;
171     }
172
173   TFile *file = TFile::Open(openString.Data(), "READ");
174   if ( !file ) {
175     AliError(Form("Error opening file \"%s\"", openString.Data()));
176     return kFALSE;
177   }
178
179   Int_t size = file->GetSize();
180
181   char *buf = new Char_t[size + 1];
182   memset(buf, '\0', size + 1);
183
184   file->Seek(0);  
185   if ( file->ReadBuffer(buf, size) ) {
186     AliError("Error reading file contents to buffer!");
187     return kFALSE;
188   }
189   Printf("%d bytes read!\n", file->GetBytesRead());
190   
191   ParseBuffer(buf);
192
193   file->Close();
194   delete[] buf;
195   return kTRUE;
196 }
197
198
199
200 //_____________________________________________________________________________
201 Bool_t AliSurveyObj::Fill(TString detector, Int_t year, Int_t reportNumber,
202                          Int_t reportVersion, TString username) {
203   // Fills the object from a file in the default storage location in AliEn
204
205   TString baseFolder = "/alice/data/Reference/";
206   TString validDetectors = "ACORDE,BABYFRAME,BACKFRAME,EMCAL,FMD,HMPID,ITS,L3 MAGNET,MUON,MUON ABSORBERS,MUON DIPOLE,PHOS,PMD,SPACEFRAME,SUPERSTRUCTURE,T0,TOF,TPC,TRD,V0,ZDC";
207   TString GRPDetectors = "BABYFRAME,BACKFRAME,L3 MAGNET,SPACEFRAME,MUON DIPOLE,MUON ABSORBERS";
208   TString MUONDetectors = "MUON,SUPERSTRUCTURE";
209
210   detector.ToUpper();
211   
212   // Check if <detector> is valid
213   TObjArray *dets = validDetectors.Tokenize(',');
214   if (!dets->FindObject(detector)) {
215     AliError(Form("Detector '%s' is not a valid detector/structure!", detector.Data()));
216     return kFALSE;
217   }
218   dets->Delete();
219   dets = 0;
220
221   // Some "detectors" don't have a folder of their own
222   dets = GRPDetectors.Tokenize(',');
223   if (dets->FindObject(detector)) detector = "GRP";
224   dets->Delete();
225   dets = 0;
226
227   dets = MUONDetectors.Tokenize(',');
228   if (dets->FindObject(detector)) detector = "MUON";
229   dets->Delete();
230   dets = 0;
231
232   // Check if <year>, <reportNumber> and <reportVersion> are valid (roughly)
233   if ((year < 1950) || (reportNumber < 1) || (reportVersion < 1)) {
234     AliError("Invalid parameter values for AliSurveyObj::Fill. (Year, Report Number or Report Version)");
235     return kFALSE;
236   }
237
238   // Finally composes the full string
239   TString fullOpenString = "alien://" + baseFolder + detector + "/RawSurvey/";
240   fullOpenString += Form("%d/%d_v%d.txt?filetype=raw", year, reportNumber, reportVersion);
241
242   // Set the GRID username variable to connect to the GRID
243   fGridUser = username;
244
245   return OpenFile(fullOpenString);
246 }
247
248
249 //_____________________________________________________________________________
250 Bool_t AliSurveyObj::FillFromLocalFile(const Char_t* filename) {
251   // Fills the object from a file in a local filesystem
252
253   TString fullOpenString = "file://" + TString(filename) + "?filetype=raw";
254
255   return OpenFile(fullOpenString);
256 }
257
258
259 //_____________________________________________________________________________
260 TString &AliSurveyObj::Sanitize(TString str) {
261   // Cleans up a line of new line and carriage return characters.
262   // (Specially usefull for files created in Windows.)
263
264   str.Remove(TString::kTrailing, '\r');
265   str.Remove(TString::kTrailing, '\n');
266   str.Remove(TString::kTrailing, '\r');
267   if (!str.IsAscii()) {
268     AliWarning("Warning: Non-ASCII characters!\n");
269     str = "";
270   }
271   return str.Remove(TString::kBoth, ' ');
272 }
273
274
275 //_____________________________________________________________________________
276 Bool_t AliSurveyObj::ParseBuffer(const Char_t* buf) {
277   // Parses a character buffer assuming the format defined with the TS/SU
278   // http://aliceinfo/Offline/Activities/Alignment/SurveyInformation.html
279
280   // If the object is already filled clean it up
281   if (fIsValid) Reset();
282
283   // Copy the buffer to a TString to use Tokenize
284   TString buffer = TString(buf);
285   TObjArray *lines = buffer.Tokenize('\n');
286   TObjArray *dataLine = NULL; // Used to Tokenize each point/line read
287   TObjArray *colLine = NULL; // Used to Tokenize the column names
288
289   // Some local variables declarations and initializations
290   const Int_t kFieldCheck = 10;
291   Bool_t check[kFieldCheck];
292   TString tmp_name = "";
293   Float_t tmp_x = 0.0, tmp_y = 0.0, tmp_z = 0.0;
294   Float_t tmp_precX = 0.0, tmp_precY = 0.0, tmp_precZ = 0.0;
295   Char_t tmp_type = '\0';
296   Bool_t tmp_targ = kTRUE;
297   AliSurveyPoint *dp = 0;
298   for (Int_t i = 0; i < kFieldCheck; ++i) check[i] = kFALSE;
299
300   Int_t nrLines = lines->GetEntries();
301   Printf("Lines in file: %d\n", nrLines); 
302
303   // The main cycle, the buffer is parsed a line at a time
304   TString currLine = "", nextLine = "";
305   for (Int_t i = 0; i < nrLines; ++i) {
306
307     // Get the next line
308     currLine = ((TObjString *)(lines->At(i)))->GetString().Data();
309     nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : "");
310     currLine = Sanitize(currLine);
311     nextLine = Sanitize(nextLine);
312     // Printf("\n%d: \"\"%s\"\"\"\n", i + 1, currLine.Data());
313     
314     // Skip empty line
315     if (0 == currLine.Length()) Printf("Info: Empty line skipped\n\n");
316
317     // The line contains a keyword
318     else if (currLine.BeginsWith(">") && !nextLine.BeginsWith(">")) {
319       currLine.Remove(TString::kLeading, '>');
320       currLine.Remove(TString::kTrailing, ':');
321       currLine.Remove(TString::kBoth, ' ');
322       nextLine.Remove(TString::kBoth, ' ');
323       // Printf(" -> Field: \"%s\"\n", currLine.Data());
324       
325       if (currLine.BeginsWith("Title", TString::kIgnoreCase)) {
326         // Report Title
327         fTitle = nextLine;
328         ++i;
329       } else if (currLine.BeginsWith("Date", TString::kIgnoreCase)) {
330         // Report(measurement) Date
331         fDate = nextLine;
332         ++i;
333       } else if (currLine.BeginsWith("Subdetector", TString::kIgnoreCase)) {
334         // Subdetector or structure
335         fDetector = nextLine;
336         ++i;
337       } else if (currLine.BeginsWith("Report URL", TString::kIgnoreCase)) {
338         // Report URL in EDMS
339         if (nextLine.BeginsWith("http://edms.cern.ch/document/", TString::kIgnoreCase) ||
340             nextLine.BeginsWith("https://edms.cern.ch/document/", TString::kIgnoreCase)) {
341           fURL = nextLine;
342           nextLine.Remove(TString::kTrailing, '/');
343           nextLine = nextLine(nextLine.Last('/') + 1, nextLine.Length() - nextLine.Last('/') + 1);
344           
345           Int_t sscanf_tmp = 0;
346           if (1 != sscanf(nextLine.Data(), "%d", &sscanf_tmp)) {
347             AliError("Survey text file sintax error! (incorrectly formated Report URL)");
348             lines->Delete();
349             return kFALSE;
350           }
351           fReportNr = nextLine.Atoi();
352           //Printf(" $$ %d $$\n", fReportNr);
353           ++i;
354         } else { 
355           // URL incorrectly formated
356           AliError("Survey text file sintax error! (incorrectly formated Report URL)");
357           return kFALSE;
358         }
359       } else if (currLine.BeginsWith("Version", TString::kIgnoreCase)) {
360         // Report version
361         if (!nextLine.IsDigit()) {
362           lines->Delete();
363           AliError("Survey text file sintax error! (incorrectly formated Report Version)");
364           return kFALSE;
365         }
366         fVersion = nextLine.Atoi();
367         ++i;
368       } else if (currLine.BeginsWith("General Observations", TString::kIgnoreCase)) {
369         // Observations
370         fObs = "";
371         // Can be more than 1 line. Loop until another keyword is found
372         while (('>' != nextLine[0]) && (nextLine.Length() > 0) && (i < nrLines)) {      
373           fObs += (0 == fObs.Length()) ? nextLine : " / " + nextLine;
374           ++i;
375           nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : "");
376           nextLine = Sanitize(nextLine);
377         }
378       } else if (currLine.BeginsWith("Coordinate System", TString::kIgnoreCase)) {
379         // Coordinate System
380         fCoordSys = nextLine;
381         ++i;
382       } else if (currLine.BeginsWith("Units", TString::kIgnoreCase)) {
383         // Measurement Unit
384         fUnits = nextLine;
385         ++i;
386       } else if (currLine.BeginsWith("Nr Columns", TString::kIgnoreCase)) {
387         // Number of columns in the "Data" section
388         if (!nextLine.IsDigit()) {
389           lines->Delete();
390           AliError("Survey text file sintax error! (incorrectly formated Number of Columns)");
391           return kFALSE;
392         }
393         fNrColumns = nextLine.Atoi();
394         ++i;
395       } else if (currLine.BeginsWith("Column Names", TString::kIgnoreCase)) {
396         // Column names separated by commas
397         fColNames = nextLine;
398         colLine = nextLine.Tokenize(',');
399         if (colLine->GetEntries() != fNrColumns) {
400           AliError("Survey text file sintax error! (Declared number of Columns doesn't match number of column names)");
401           colLine->Delete();
402           lines->Delete();
403           return kFALSE;
404         }
405         ++i;
406       } else if (currLine.BeginsWith("Data", TString::kIgnoreCase)) {
407         // Data section!
408         while ((nextLine.Length() > 0) && ('>' != nextLine[0])) {
409
410           // Printf("Data LINE: \"%s\": %d\n", nextLine.Data(), nextLine.Length());
411
412           // What is the separator used between fields?
413           // The allowed are: comma (','), tab ('\t'), and space (' ')
414           if (fNrColumns == nextLine.CountChar(',') + 1) dataLine = nextLine.Tokenize(',');
415           else if (fNrColumns == nextLine.CountChar('\t') + 1) dataLine = nextLine.Tokenize('\t');
416           else if (fNrColumns == nextLine.CountChar(' ') + 1) dataLine = nextLine.Tokenize(' ');
417           else {
418             // Error (No separator was found!)
419             AliError("Survey text file syntax error! Error processing data line!");
420             lines->Delete();
421             return kFALSE;
422           }
423           
424           if (dataLine->GetEntries() != fNrColumns) {
425             // The number of columns doesn't match the number specified in the header
426             AliError("Survey text file sintax error! (Number of entries in line is different from declared Number of Columns)");
427             dataLine->Delete();
428             lines->Delete();
429             return kFALSE;
430           }
431
432           // Reset the bits used to check if all the required fields are present
433           for (Int_t t = 0; t < kFieldCheck; ++t) check[t] = 0;
434
435           // Process the data line using the column names as index
436           for (Int_t j = 0; j < dataLine->GetEntries(); ++j) {
437             TString cn = ((TObjString *)(colLine->At(j)))->GetString();
438             TString value = ((TObjString *)(dataLine->At(j)))->GetString();
439             if (cn.BeginsWith("Point Name", TString::kIgnoreCase)) {
440               tmp_name = value;
441               check[0] = kTRUE;
442             } else if (cn.BeginsWith("X", TString::kIgnoreCase)) {
443               tmp_x = value.Atof();
444               check[1] = kTRUE;
445             } else if (cn.BeginsWith("Y", TString::kIgnoreCase)) {
446               tmp_y = value.Atof();
447               check[2] = kTRUE;
448             } else if (cn.BeginsWith("Z", TString::kIgnoreCase)) {
449               tmp_z = value.Atof();
450               check[3] = kTRUE;
451             } else if (cn.BeginsWith("Precision", TString::kIgnoreCase)) {
452               TString tmpCN = cn(0, cn.First('('));
453               Int_t precLength = TString("Precision").Length();
454               //Printf(" ====== %d ======= %d ====== \n", precLength, tmpCN.Length());
455               //Printf(" ====== %s ======= \n", tmpCN.Data());
456               if (precLength == tmpCN.Length()) {
457                 tmp_precX = tmp_precY = tmp_precZ = value.Atof();
458                 check[6] = kTRUE;
459               } else {
460                 TString axis = cn(precLength, tmpCN.Length() - precLength);
461                 if (axis.Contains('X', TString::kIgnoreCase)) {
462                   tmp_precX = value.Atof();
463                   check[7] = kTRUE;
464                 } else if (axis.Contains('Y', TString::kIgnoreCase)) {
465                   tmp_precY = value.Atof();
466                   check[8] = kTRUE;
467                 } else if (axis.Contains('Z', TString::kIgnoreCase)) {
468                   tmp_precZ = value.Atof();
469                   check[9] = kTRUE;
470                 } else {
471                   AliError("Survey text file sintax error! (Precision column name invalid)");
472                   dataLine->Delete();
473                   lines->Delete();
474                   return kFALSE;
475                 }
476               }
477             } else if (cn.BeginsWith("Point Type", TString::kIgnoreCase)) {
478               tmp_type = value.Data()[0];
479               check[4] = kTRUE;
480             } else if (cn.BeginsWith("Target Used", TString::kIgnoreCase)) {
481               tmp_targ = (value.Data()[0] == 'Y') ? kTRUE : kFALSE;
482               check[5] = kTRUE;
483             }
484
485             //Printf("--> %s\n", ((TObjString *)(dataLine->At(j)))->GetString().Data());
486           }
487
488           // Check if all the mandatory fields exist
489           Bool_t res = kTRUE, precInd = kTRUE;
490
491           // Target
492           if (kFALSE == check[5]) {
493             tmp_targ = kTRUE;
494             check[5] = kTRUE;
495           }
496           
497           // Individual axis precisions
498           for (Int_t t = 7; t < 10; ++t) precInd &= check[t];
499           if ((kFALSE == check[6]) && (kTRUE == precInd)) check[6] = kTRUE;
500
501           for (Int_t t = 0; t < kFieldCheck - 3; ++t) {
502             //Printf("RES(%d): %d\n", t, check[t]);
503             res &= check[t];
504           }
505           if (kTRUE == res) {
506             dp = new AliSurveyPoint(tmp_name, tmp_x, tmp_y, tmp_z, tmp_precX, tmp_precY, tmp_precZ, tmp_type, tmp_targ);
507             dp->PrintPoint();
508             AddPoint(dp);
509           } else {
510             AliError("Parsing error processing data line!");
511             dataLine->Delete();
512             lines->Delete();
513             return kFALSE;
514           }
515           
516           dataLine->Delete();
517           dataLine = NULL;
518           ++i;
519           nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : "");
520           nextLine = Sanitize(nextLine);
521         }
522       }
523     } else {
524       AliError("Survey text file sintax error!");
525       lines->Delete();
526       return kFALSE;
527     }
528   }
529   lines->Delete();
530   fIsValid = kTRUE;
531   return kTRUE;
532 }
533
534 //_____________________________________________________________________________
535 void AliSurveyObj::Reset() {
536   // Resets the AliSurveyObj to a clean object.
537   // Used if the same object is filled more than once
538   
539   if (fDataPoints) {
540     for (Int_t i = 0; i < fDataPoints->GetEntries(); ++i) delete fDataPoints->At(i);
541     fDataPoints->Delete();
542     fDataPoints = 0;
543   }
544   fTitle = "";
545   fDate = "";
546   fDetector = "";
547   fURL = "http://edms.cern.ch/";
548   fReportNr = -1;
549   fVersion = -1;
550   fObs = "";
551   fCoordSys = "";
552   fUnits = "";
553   fNrColumns = -1;
554   fColNames = "";
555   fIsValid = kFALSE;
556   fDataPoints = new TObjArray(1);
557   fDataPoints->SetOwner(kTRUE);
558   return;
559 }
560