]>
Commit | Line | Data |
---|---|---|
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 "TObjArray.h" | |
27 | #include "TGrid.h" | |
28 | #include "TGridResult.h" | |
29 | #include "TFile.h" | |
30 | #include "TObjString.h" | |
31 | ||
32 | //AliROOT includes | |
33 | #include "AliLog.h" | |
34 | #include "AliSurveyPoint.h" | |
35 | ||
36 | ClassImp(AliSurveyObj) | |
37 | ||
38 | ||
39 | const TString AliSurveyObj::fgkStorage = "alien://alice.cern.ch"; | |
40 | const TString AliSurveyObj::fgkBaseFolder = "/alice/data/Reference"; | |
41 | const TString AliSurveyObj::fgkValidDetectors = "ACORDE,BABYFRAME,BACKFRAME,\ | |
42 | EMCAL,FMD,HMPID,ITS,L3 MAGNET,MUON,MUON ABSORBERS,MUON DIPOLE,PHOS,PMD,\ | |
43 | SPACEFRAME,SUPERSTRUCTURE,T0,TOF,TPC,TRD,VZERO,ZDC,GRP"; | |
44 | const TString AliSurveyObj::fgkGRPDetectors = "BABYFRAME,BACKFRAME,L3 MAGNET,\ | |
45 | SPACEFRAME,MUON DIPOLE,MUON ABSORBERS,GRP"; | |
46 | const TString AliSurveyObj::fgkMUONDetectors = "MUON,SUPERSTRUCTURE"; | |
47 | ||
48 | ||
49 | //_____________________________________________________________________________ | |
50 | AliSurveyObj::AliSurveyObj(): | |
51 | TObject(), | |
52 | fTitle(""), | |
53 | fDate(""), | |
54 | fDetector(""), | |
55 | fURL("http://edms.cern.ch/"), | |
56 | fReportNr(-1), | |
57 | fVersion(-1), | |
58 | fObs(""), | |
59 | fCoordSys(""), | |
60 | fUnits(""), | |
61 | fNrColumns(-1), | |
62 | fColNames(""), | |
63 | fIsValid(kFALSE), | |
64 | fGridUser(""), | |
65 | fDataPoints(new TObjArray(1)) | |
66 | { | |
67 | // constructor | |
68 | fDataPoints->SetOwner(kTRUE); | |
69 | } | |
70 | ||
71 | ||
72 | //_____________________________________________________________________________ | |
73 | AliSurveyObj::~AliSurveyObj() { | |
74 | //destructor | |
75 | if (fDataPoints) { | |
76 | fDataPoints->Delete(); | |
77 | fDataPoints = 0; | |
78 | } | |
79 | } | |
80 | ||
81 | ||
82 | //_____________________________________________________________________________ | |
83 | AliSurveyObj::AliSurveyObj(const AliSurveyObj& surveyObj): | |
84 | TObject(), | |
85 | fTitle(surveyObj.fTitle), | |
86 | fDate(surveyObj.fDate), | |
87 | fDetector(surveyObj.fDetector), | |
88 | fURL(surveyObj.fURL), | |
89 | fReportNr(surveyObj.fReportNr), | |
90 | fVersion(surveyObj.fVersion), | |
91 | fObs(surveyObj.fObs), | |
92 | fCoordSys(surveyObj.fCoordSys), | |
93 | fUnits(surveyObj.fUnits), | |
94 | fNrColumns(surveyObj.fNrColumns), | |
95 | fColNames(surveyObj.fColNames), | |
96 | fIsValid(surveyObj.fIsValid), | |
97 | fGridUser(surveyObj.fGridUser), | |
98 | fDataPoints(new TObjArray(1)) | |
99 | { | |
100 | // copy constructor | |
101 | TObject *curr = surveyObj.fDataPoints->First(); | |
102 | while (curr != 0) { | |
103 | fDataPoints->Add(curr); | |
104 | curr = surveyObj.fDataPoints->After(curr); | |
105 | } | |
106 | } | |
107 | ||
108 | ||
109 | //_____________________________________________________________________________ | |
110 | AliSurveyObj& AliSurveyObj::operator=(const AliSurveyObj& surveyObj) | |
111 | { | |
112 | // assignment operator | |
113 | if (this != &surveyObj) { | |
114 | fTitle = surveyObj.fTitle; | |
115 | fDate = surveyObj.fDate; | |
116 | fDetector = surveyObj.fDetector; | |
117 | fURL = surveyObj.fURL; | |
118 | fReportNr = surveyObj.fReportNr; | |
119 | fVersion = surveyObj.fVersion; | |
120 | fObs = surveyObj.fObs; | |
121 | fCoordSys = surveyObj.fCoordSys; | |
122 | fUnits = surveyObj.fUnits; | |
123 | fNrColumns = surveyObj.fNrColumns; | |
124 | fColNames = surveyObj.fColNames; | |
125 | fIsValid = surveyObj.fIsValid; | |
126 | fGridUser = surveyObj.fGridUser; | |
127 | TObject *curr = surveyObj.fDataPoints->First(); | |
128 | while (curr != 0) { | |
129 | fDataPoints->Add(curr); | |
130 | curr = surveyObj.fDataPoints->After(curr); | |
131 | } | |
132 | } | |
133 | return *this; | |
134 | } | |
135 | ||
136 | ||
137 | //_____________________________________________________________________________ | |
138 | void AliSurveyObj::AddPoint(AliSurveyPoint* point) { | |
139 | // Adds a point to the TObjArray which containst the list of points | |
140 | fDataPoints->Add(point); | |
141 | return; | |
142 | } | |
143 | ||
144 | ||
145 | //_____________________________________________________________________________ | |
146 | Bool_t AliSurveyObj::Connect(const char *gridUrl, const char *user) { | |
147 | // Connects to the grid | |
148 | ||
149 | // If the same "Grid" is alreay active, skip connection | |
150 | if (!gGrid || gridUrl != gGrid->GridUrl() || | |
151 | (( strcmp(user,"") ) && ( strcmp(user,gGrid->GetUser()) )) ) { | |
152 | // connection to the Grid | |
153 | AliInfo("\nConnecting to the Grid..."); | |
154 | if (gGrid) { | |
155 | AliInfo(Form("gGrid = %p; GridUrl = %s; gGrid->GridUrl() = %s", | |
156 | gGrid, gridUrl, gGrid->GridUrl())); | |
157 | AliInfo(Form("User = %s; gGrid->GetUser() = %s", | |
158 | user, gGrid->GetUser())); | |
159 | } | |
160 | TGrid::Connect(gridUrl,user); | |
161 | } | |
162 | ||
163 | if(!gGrid) { | |
164 | AliError("Connection failed!"); | |
165 | return kFALSE; | |
166 | } | |
167 | return kTRUE; | |
168 | } | |
169 | ||
170 | ||
171 | //_____________________________________________________________________________ | |
172 | Bool_t AliSurveyObj::OpenFile(TString openString) { | |
173 | // Opens the file and reads it to a buffer | |
174 | ||
175 | AliInfo(Form("Opening file \"%s\"\n for survey data", openString.Data())); | |
176 | ||
177 | if (openString.BeginsWith("alien://")) | |
178 | if (!Connect(fgkStorage.Data(), fGridUser.Data())) { | |
179 | AliError(Form("Error connecting to GRID")); | |
180 | return kFALSE; | |
181 | } | |
182 | ||
183 | TFile *file = TFile::Open(openString.Data(), "READ"); | |
184 | if ( !file ) { | |
185 | AliError(Form("Error opening file \"%s\"", openString.Data())); | |
186 | return kFALSE; | |
187 | } | |
188 | ||
189 | Int_t size = file->GetSize(); | |
190 | ||
191 | char *buf = new Char_t[size + 1]; | |
192 | memset(buf, '\0', size + 1); | |
193 | ||
194 | file->Seek(0); | |
195 | if ( file->ReadBuffer(buf, size) ) { | |
196 | AliError("Error reading file contents to buffer!"); | |
197 | return kFALSE; | |
198 | } | |
199 | AliInfo(Form("%l bytes read!\n", file->GetBytesRead())); | |
200 | ||
201 | ParseBuffer(buf); | |
202 | ||
203 | file->Close(); | |
204 | delete[] buf; | |
205 | return kTRUE; | |
206 | } | |
207 | ||
208 | ||
209 | //_____________________________________________________________________________ | |
210 | Bool_t AliSurveyObj::FillFromLocalFile(const Char_t* filename) { | |
211 | // Fills the object from a file in a local filesystem | |
212 | ||
213 | TString fullOpenString = "file://" + TString(filename) + "?filetype=raw"; | |
214 | ||
215 | return OpenFile(fullOpenString); | |
216 | } | |
217 | ||
218 | ||
219 | //_____________________________________________________________________________ | |
220 | Bool_t AliSurveyObj::IsValidDetector(TString detector) const { | |
221 | // Checks if the detector name is valid | |
222 | ||
223 | detector.ToUpper(); | |
224 | ||
225 | TObjArray *dets = fgkValidDetectors.Tokenize(','); | |
226 | TObject *found = dets->FindObject(detector); | |
227 | dets->Delete(); | |
228 | dets = 0; | |
229 | ||
230 | if (!found) return kFALSE; | |
231 | else return kTRUE; | |
232 | } | |
233 | ||
234 | ||
235 | //_____________________________________________________________________________ | |
236 | TString AliSurveyObj::RealFolderName(TString detector) const { | |
237 | // Returns the actual folder name for a given detector | |
238 | // Some "detectors" don't have a folder of their own | |
239 | ||
240 | detector.ToUpper(); | |
241 | TString folderName = detector; | |
242 | ||
243 | TObjArray *dets = fgkGRPDetectors.Tokenize(','); | |
244 | if (dets->FindObject(detector)) folderName = "GRP"; | |
245 | dets->Delete(); | |
246 | dets = 0; | |
247 | ||
248 | dets = fgkMUONDetectors.Tokenize(','); | |
249 | if (dets->FindObject(detector)) folderName = "MUON"; | |
250 | dets->Delete(); | |
251 | ||
252 | ||
253 | ||
254 | dets = 0; | |
255 | ||
256 | return folderName; | |
257 | } | |
258 | ||
259 | //_____________________________________________________________________________ | |
260 | Bool_t AliSurveyObj::Fill(TString detector, Int_t reportNumber, | |
261 | TString username) { | |
262 | // Fills the object from a file in the default storage location in AliEn. | |
263 | // The highest version available is selected. | |
264 | ||
265 | return Fill(detector, reportNumber, -1, username); | |
266 | } | |
267 | ||
268 | //_____________________________________________________________________________ | |
269 | Bool_t AliSurveyObj::Fill(TString detector, Int_t reportNumber, | |
270 | Int_t reportVersion, TString username) { | |
271 | // Fills the object from a file in the default storage location in AliEn. | |
272 | // A specific version is selected. | |
273 | ||
274 | detector.ToUpper(); | |
275 | ||
276 | // Check if <detector> is valid | |
277 | if (!IsValidDetector(detector)) { | |
278 | AliWarning(Form("Detector '%s' is not a valid detector/structure!", detector.Data())); | |
279 | return kFALSE; | |
280 | } | |
281 | ||
282 | // Some "detectors" don't have a folder of their own | |
283 | // TString detectorFolder = RealFolderName(detector); | |
284 | ||
285 | // Check if <year>, <reportNumber> and <reportVersion> are valid (roughly) | |
286 | if ((reportNumber < 1) || (reportVersion < -1) || (0 == reportVersion)) { | |
287 | AliError("Invalid parameter values for AliSurveyObj::Fill. (Report Number or Report Version)"); | |
288 | return kFALSE; | |
289 | } | |
290 | ||
291 | // Check if the fGridUser is set, or specified | |
292 | if (username.Length() > 0) SetGridUser(username); | |
293 | else if (0 == fGridUser.Length()) { | |
294 | AliError("GRID username not specified and not previously set!"); | |
295 | return kFALSE; | |
296 | } | |
297 | ||
298 | // Query AliEn for the available reports | |
299 | TGridResult *res = QueryReports(detector, -1, reportNumber, reportVersion); | |
300 | if (!res) AliError(Form("Error querying AliEn for detector '%s', \ | |
301 | report number '%d' and report version '%d'.", | |
302 | detector.Data(), reportNumber, reportVersion)); | |
303 | Int_t numberEntries = res->GetEntries(); | |
304 | if (0 == numberEntries) { | |
305 | AliError(Form("No report found for detector '%s', report number '%d' and report version '%d'", | |
306 | detector.Data(), reportNumber, reportVersion)); | |
307 | return kFALSE; | |
308 | } | |
309 | ||
310 | TString fileNamePath = ""; | |
311 | if (1 == numberEntries) fileNamePath = res->GetFileNamePath(0); | |
312 | else if (numberEntries > 1) { | |
313 | TString higherVerFNP = res->GetFileNamePath(0); | |
314 | Int_t lastYear = FileNamePathToReportYear(higherVerFNP); | |
315 | for (Int_t i = 1; i < numberEntries; ++i) { | |
316 | TString currFNP = res->GetFileNamePath(i); | |
317 | if (FileNamePathToReportVersion(currFNP) > | |
318 | FileNamePathToReportVersion(higherVerFNP)) higherVerFNP = currFNP; | |
319 | if (lastYear != FileNamePathToReportYear(currFNP)) | |
320 | AliWarning("Inconsistency detected, year differs for reports with the same report number! Please inform the responsible and check the report against the one in DCDB."); | |
321 | } | |
322 | fileNamePath = higherVerFNP; | |
323 | } | |
324 | ||
325 | TString fullOpenString = "alien://" + fileNamePath + "?filetype=raw"; | |
326 | /* | |
327 | // Finally composes the full string | |
328 | TString fullOpenString = "alien://" + fgkBaseFolder + "/" + detectorFolder + "/RawSurvey/"; | |
329 | fullOpenString += Form("%d/%d_v%d.txt?filetype=raw", year, reportNumber, reportVersion); | |
330 | */ | |
331 | ||
332 | return OpenFile(fullOpenString); | |
333 | } | |
334 | ||
335 | ||
336 | //_____________________________________________________________________________ | |
337 | TString AliSurveyObj::FileNamePathToDetector(TString filename) const { | |
338 | // Get the report number from the complete path in the format: | |
339 | // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt | |
340 | ||
341 | TString ret = ""; | |
342 | ||
343 | if (filename.Length() > fgkBaseFolder.Length()) { | |
344 | ret = filename.Remove(0, fgkBaseFolder.Length()); | |
345 | ret.Remove(TString::kLeading, '/'); | |
346 | ret = ret(0, ret.First('/')); | |
347 | if (!IsValidDetector(ret)) ret = ""; | |
348 | } | |
349 | return ret; | |
350 | } | |
351 | ||
352 | ///alice/cern.ch/user/r/rsilva/TRD/RawSurvey/2007/.816582_v2.txt/v1.0 | |
353 | ||
354 | //_____________________________________________________________________________ | |
355 | Int_t AliSurveyObj::FileNamePathToReportYear(TString filename) const { | |
356 | // Get the report year from the complete path in the format: | |
357 | // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt | |
358 | ||
359 | TString ret = ""; | |
360 | ||
361 | if (filename.Length() > fgkBaseFolder.Length()) { | |
362 | ret = filename.Remove(0, fgkBaseFolder.Length()); | |
363 | ret.Remove(TString::kLeading, '/'); | |
364 | Int_t beg = ret.First('/') + TString("RawSurvey/").Length() + 1; | |
365 | ret = ret(beg, ret.Last('/') - beg); | |
366 | return ret.Atoi(); | |
367 | } | |
368 | return -1; | |
369 | } | |
370 | ||
371 | ||
372 | //_____________________________________________________________________________ | |
373 | Int_t AliSurveyObj::FileNamePathToReportNumber(TString filename) const { | |
374 | // Get the report number from the complete path in the format: | |
375 | // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt | |
376 | ||
377 | TString ret = ""; | |
378 | ||
379 | if (filename.Length() > fgkBaseFolder.Length()) { | |
380 | ret = filename.Remove(0, fgkBaseFolder.Length()); | |
381 | ret.Remove(TString::kLeading, '/'); | |
382 | if ((ret.CountChar('/') > 3) || (ret.CountChar('.') > 1)) { | |
383 | AliWarning("Error getting the Report Number from the filename path!"); | |
384 | return -1; | |
385 | } | |
386 | ret = ret(ret.Last('/') + 1 , ret.Last('_') - ret.Last('/') - 1); | |
387 | return ret.Atoi(); | |
388 | } | |
389 | AliWarning("Error getting the Report Number from the filename path!"); | |
390 | return -1; | |
391 | } | |
392 | ||
393 | ||
394 | //_____________________________________________________________________________ | |
395 | Int_t AliSurveyObj::FileNamePathToReportVersion(TString filename) const { | |
396 | // Get the report version from the complete path in the format: | |
397 | // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt | |
398 | ||
399 | TString ret = ""; | |
400 | ||
401 | if (filename.Length() > fgkBaseFolder.Length()) { | |
402 | ret = filename.Remove(0, fgkBaseFolder.Length()); | |
403 | ret.Remove(TString::kLeading, '/'); | |
404 | if ((ret.CountChar('/') > 3) || (ret.CountChar('.') > 1)) { | |
405 | AliWarning("Error getting the Report Version from the filename path!"); | |
406 | return -1; | |
407 | } | |
408 | ret = ret(ret.Last('_') + 1 + 1 , ret.Last('.') - ret.Last('_') - 1 - 1); | |
409 | return ret.Atoi(); | |
410 | } | |
411 | AliWarning("Error getting the Report Version from the filename path!"); | |
412 | return -1; | |
413 | } | |
414 | ||
415 | ||
416 | //_____________________________________________________________________________ | |
417 | void AliSurveyObj::ListValidDetectors() { | |
418 | // List the valid detector names | |
419 | Printf("Listing all valid detectors:\n"); | |
420 | TObjArray *dets = fgkValidDetectors.Tokenize(','); | |
421 | for (int i = 0; i < dets->GetEntries(); ++i) | |
422 | Printf("%s", ((TObjString *) dets->At(i))->GetString().Data()); | |
423 | dets->Delete(); | |
424 | dets = 0; | |
425 | Printf("Some reports are stored in more general folders.\n" | |
426 | "These reports can be opened using either name, the original or the\n" | |
427 | "folder name. Example: 'SPACEFRAME' or 'GRP' are both valid when\n" | |
428 | "opening a report for the Spaceframe.\n\n" | |
429 | "Detectors stored in 'MUON' folder:"); | |
430 | dets = fgkMUONDetectors.Tokenize(','); | |
431 | for (int i = 0; i < dets->GetEntries(); ++i) | |
432 | Printf("%s", ((TObjString *) dets->At(i))->GetString().Data()); | |
433 | dets->Delete(); | |
434 | dets = 0; | |
435 | Printf("Detectors stored in 'GRP' folder:"); | |
436 | dets = fgkGRPDetectors.Tokenize(','); | |
437 | for (int i = 0; i < dets->GetEntries(); ++i) | |
438 | Printf("%s", ((TObjString *) dets->At(i))->GetString().Data()); | |
439 | dets->Delete(); | |
440 | dets = 0; | |
441 | return; | |
442 | } | |
443 | ||
444 | ||
445 | //_____________________________________________________________________________ | |
446 | TGridResult * AliSurveyObj::QueryReports(TString detector, Int_t year, | |
447 | Int_t reportNumber, | |
448 | Int_t reportVersion) { | |
449 | // Queries AliEn for existing reports matching the specified conditions | |
450 | TString lsArg = fgkBaseFolder; | |
451 | ||
452 | TString detectorFolder = ""; | |
453 | if (detector.Length() > 0) { | |
454 | detector.ToUpper(); | |
455 | // Check if <detector> is valid | |
456 | if (!IsValidDetector(detector)) { | |
457 | AliError(Form("Detector '%s' is not a valid detector/structure!", | |
458 | detector.Data())); | |
459 | return 0; | |
460 | } | |
461 | // Some "detectors" don't have a folder of their own | |
462 | detectorFolder = "/" + RealFolderName(detector); | |
463 | } else detectorFolder = "/*"; | |
464 | ||
465 | lsArg += detectorFolder + "/RawSurvey"; | |
466 | ||
467 | TString yearFolder = ""; | |
468 | if (year > 1950) yearFolder.Form("/%d", year); | |
469 | else yearFolder = "/*"; | |
470 | ||
471 | TString reportFolder = ""; | |
472 | if (reportNumber > 0) reportFolder.Form("/%d", reportNumber); | |
473 | else reportFolder = "/*"; | |
474 | ||
475 | TString versionFolder = ""; | |
476 | if (reportVersion > 0) versionFolder.Form("_v%d", reportVersion); | |
477 | else versionFolder = "_v*"; | |
478 | ||
479 | lsArg += yearFolder + reportFolder + versionFolder + ".txt"; | |
480 | ||
481 | AliInfo(Form("\nLooking for: %s \n", lsArg.Data())); | |
482 | ||
483 | // Check if fGridUser is set and Connect to AliEn | |
484 | if (0 == fGridUser.Length()) { | |
485 | AliError("To use this method it's necessary to call SetGridUser(...) in advance."); | |
486 | return 0; | |
487 | } else if (!Connect(fgkStorage.Data(), fGridUser.Data())) { | |
488 | AliError(Form("Error connecting to GRID")); | |
489 | return 0; | |
490 | } | |
491 | return gGrid->Ls(lsArg); | |
492 | } | |
493 | ||
494 | ||
495 | //_____________________________________________________________________________ | |
496 | Int_t AliSurveyObj::ListReports(TString detector, Int_t year, | |
497 | Int_t reportNumber, | |
498 | Int_t reportVersion) { | |
499 | // Lists all available reports matching the specified conditions | |
500 | // Returns the number of reports found | |
501 | ||
502 | TGridResult *res = QueryReports(detector, year, reportNumber, reportVersion); | |
503 | ||
504 | if (0 == res) { | |
505 | AliError("Query failed."); | |
506 | return 0; | |
507 | } | |
508 | ||
509 | TString fn = ""; | |
510 | Int_t numberEntries = res->GetEntries(); | |
511 | ||
512 | if (numberEntries > 0) { | |
513 | Printf(Form("%d reports found:", numberEntries)); | |
514 | for (int i = 0; i < res->GetEntries(); ++i) { | |
515 | fn = res->GetFileNamePath(i); | |
516 | Printf(Form("Detector:%s\tYear:%d\tEDMS Report Number:%d\tVersion:%d", | |
517 | FileNamePathToDetector(fn).Data(), | |
518 | FileNamePathToReportYear(fn), | |
519 | FileNamePathToReportNumber(fn), | |
520 | FileNamePathToReportVersion(fn))); | |
521 | } | |
522 | delete res; | |
523 | return numberEntries; | |
524 | } else { | |
525 | AliInfo("No results found for the requested query."); | |
526 | delete res; | |
527 | return 0; | |
528 | } | |
529 | } | |
530 | ||
531 | ||
532 | //_____________________________________________________________________________ | |
533 | void AliSurveyObj::SetGridUser(TString username){ | |
534 | // Set the username used to connect to the GRID | |
535 | fGridUser = username; | |
536 | return; | |
537 | } | |
538 | ||
539 | ||
540 | //_____________________________________________________________________________ | |
541 | TString &AliSurveyObj::Sanitize(TString str) { | |
542 | // Cleans up a line of new line and carriage return characters. | |
543 | // (Specially usefull for files created in Windows.) | |
544 | ||
545 | str.Remove(TString::kTrailing, '\r'); | |
546 | str.Remove(TString::kTrailing, '\n'); | |
547 | str.Remove(TString::kTrailing, '\r'); | |
548 | ||
549 | if (!str.IsAscii()) { | |
550 | AliWarning("Warning: Non-ASCII characters!\n"); | |
551 | str = ""; | |
552 | } | |
553 | return str.Remove(TString::kBoth, ' '); | |
554 | } | |
555 | ||
556 | ||
557 | //_____________________________________________________________________________ | |
558 | Bool_t AliSurveyObj::ParseBuffer(const Char_t* buf) { | |
559 | // Parses a character buffer assuming the format defined with the TS/SU | |
560 | // http://aliceinfo/Offline/Activities/Alignment/SurveyInformation.html | |
561 | ||
562 | // If the object is already filled clean it up | |
563 | if (fIsValid) Reset(); | |
564 | ||
565 | // Copy the buffer to a TString to use Tokenize | |
566 | TString buffer = TString(buf); | |
567 | TObjArray *linesRaw = buffer.Tokenize('\n'); | |
568 | // replace the array of lines with an array of sanitized lines | |
569 | // in the process we remove empty lines, particularly disturbing | |
570 | // in case of dos fileformat | |
571 | TString oneLine = ""; | |
572 | TObjString* oneLineObj = 0; | |
573 | TObjArray *lines = new TObjArray(); | |
574 | for(Int_t i=0; i<linesRaw->GetEntries(); i++) | |
575 | { | |
576 | oneLine = ((TObjString *)(linesRaw->At(i)))->GetString().Data(); | |
577 | oneLine = Sanitize(oneLine); | |
578 | if (oneLine.Length() == 0) continue; | |
579 | oneLineObj = new TObjString(oneLine); | |
580 | lines->Add(oneLineObj); | |
581 | } | |
582 | ||
583 | linesRaw->Delete(); | |
584 | delete linesRaw; | |
585 | linesRaw = NULL; | |
586 | ||
587 | TObjArray *dataLine = NULL; // Used to Tokenize each point/line read | |
588 | TObjArray *colLine = NULL; // Used to Tokenize the column names | |
589 | ||
590 | // Some local variables declarations and initializations | |
591 | const Int_t kFieldCheck = 10; | |
592 | Bool_t check[kFieldCheck]; // used to check that mandatory column names are not missing | |
593 | for (Int_t i = 0; i < kFieldCheck; ++i) check[i] = kFALSE; | |
594 | TString tmpname = ""; | |
595 | Float_t tmpx = 0.0, tmpy = 0.0, tmpz = 0.0; | |
596 | Float_t tmpprecX = -1., tmpprecY = -1., tmpprecZ = -1.; | |
597 | Char_t tmptype = '\0'; | |
598 | Bool_t tmptarg = kTRUE; | |
599 | AliSurveyPoint *dp = 0; | |
600 | TString *orderedValues[9] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}; | |
601 | TString value[9]; | |
602 | ||
603 | Int_t nrLines = lines->GetEntries(); | |
604 | Printf("Lines in file: %d\n", nrLines); | |
605 | ||
606 | // The main cycle, the buffer is parsed a line at a time | |
607 | TString currLine = "", nextLine = ""; | |
608 | for (Int_t i = 0; i < nrLines; ++i) { | |
609 | ||
610 | // Get the next line | |
611 | currLine = ((TObjString *)(lines->At(i)))->GetString().Data(); | |
612 | nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : ""); | |
613 | // Printf("%d: \"%s\"", i, currLine.Data()); | |
614 | // Printf("%d: \"%s\"\n", i+1, nextLine.Data()); | |
615 | ||
616 | // The line contains a keyword | |
617 | if (currLine.BeginsWith(">") && !nextLine.BeginsWith(">")) { | |
618 | currLine.Remove(TString::kLeading, '>'); | |
619 | currLine.Remove(TString::kTrailing, ':'); | |
620 | currLine.Remove(TString::kBoth, ' '); | |
621 | nextLine.Remove(TString::kBoth, ' '); | |
622 | AliDebug(2, Form(" -> field line: \"%s\"\n", currLine.Data())); | |
623 | AliDebug(2, Form(" -> value line: \"%s\"\n", nextLine.Data())); | |
624 | ||
625 | if (currLine.BeginsWith("Title", TString::kIgnoreCase)) { | |
626 | // Report Title | |
627 | fTitle = nextLine; | |
628 | ++i; | |
629 | } else if (currLine.BeginsWith("Date", TString::kIgnoreCase)) { | |
630 | // Report(measurement) Date | |
631 | fDate = nextLine; | |
632 | ++i; | |
633 | } else if (currLine.BeginsWith("Subdetector", TString::kIgnoreCase)) { | |
634 | // Subdetector or structure | |
635 | fDetector = nextLine; | |
636 | ++i; | |
637 | } else if (currLine.BeginsWith("Report URL", TString::kIgnoreCase)) { | |
638 | // Report URL in EDMS | |
639 | if (nextLine.BeginsWith("http://edms.cern.ch/document/", TString::kIgnoreCase) || | |
640 | nextLine.BeginsWith("https://edms.cern.ch/document/", TString::kIgnoreCase)) { | |
641 | fURL = nextLine; | |
642 | nextLine.Remove(TString::kTrailing, '/'); | |
643 | nextLine = nextLine(nextLine.Last('/') + 1, nextLine.Length() - nextLine.Last('/') + 1); | |
644 | ||
645 | Int_t sscanftmp = 0; | |
646 | if (1 != sscanf(nextLine.Data(), "%d", &sscanftmp)) { | |
647 | AliError("Survey text file sintax error! (incorrectly formatted Report URL)"); | |
648 | lines->Delete(); | |
649 | delete lines; lines = NULL; | |
650 | return kFALSE; | |
651 | } | |
652 | fReportNr = nextLine.Atoi(); | |
653 | //Printf(" $$ %d $$\n", fReportNr); | |
654 | ++i; | |
655 | } else { | |
656 | // URL incorrectly formatted | |
657 | AliError("Survey text file sintax error! (incorrectly formatted Report URL)"); | |
658 | return kFALSE; | |
659 | } | |
660 | } else if (currLine.BeginsWith("Version", TString::kIgnoreCase)) { | |
661 | // Report version | |
662 | if (!nextLine.IsDigit()) { | |
663 | lines->Delete(); | |
664 | delete lines; lines = NULL; | |
665 | AliError("Survey text file sintax error! (incorrectly formatted Report Version)"); | |
666 | return kFALSE; | |
667 | } | |
668 | fVersion = nextLine.Atoi(); | |
669 | ++i; | |
670 | } else if (currLine.BeginsWith("General Observations", TString::kIgnoreCase)) { | |
671 | // Observations | |
672 | fObs = ""; | |
673 | // Can be more than 1 line. Loop until another keyword is found | |
674 | while (('>' != nextLine[0]) && (nextLine.Length() > 0) && (i < nrLines)) { | |
675 | fObs += (0 == fObs.Length()) ? nextLine : " / " + nextLine; | |
676 | ++i; | |
677 | nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : ""); | |
678 | } | |
679 | } else if (currLine.BeginsWith("Coordinate System", TString::kIgnoreCase)) { | |
680 | // Coordinate System | |
681 | fCoordSys = nextLine; | |
682 | ++i; | |
683 | } else if (currLine.BeginsWith("Units", TString::kIgnoreCase)) { | |
684 | // Measurement Unit | |
685 | fUnits = nextLine; | |
686 | ++i; | |
687 | } else if (currLine.BeginsWith("Nr Columns", TString::kIgnoreCase)) { | |
688 | // Number of columns in the "Data" section | |
689 | if (!nextLine.IsDigit()) { | |
690 | lines->Delete(); | |
691 | delete lines; lines = NULL; | |
692 | AliError("Survey text file sintax error! (incorrectly formatted Number of Columns)"); | |
693 | return kFALSE; | |
694 | } | |
695 | fNrColumns = nextLine.Atoi(); | |
696 | ++i; | |
697 | } else if (currLine.BeginsWith("Column Names", TString::kIgnoreCase)) { | |
698 | // Column names separated by commas | |
699 | fColNames = nextLine; | |
700 | colLine = nextLine.Tokenize(','); | |
701 | if (colLine->GetEntries() != fNrColumns) { | |
702 | AliError("Survey text file sintax error! (Declared number of Columns doesn't match number of column names)"); | |
703 | colLine->Delete(); | |
704 | lines->Delete(); | |
705 | delete lines; lines = NULL; | |
706 | return kFALSE; | |
707 | } | |
708 | ++i; | |
709 | ||
710 | // booleans to track if precision for 1 axis is defined in more than one column | |
711 | Bool_t prX = kFALSE; | |
712 | Bool_t prY = kFALSE; | |
713 | Bool_t prZ = kFALSE; | |
714 | ||
715 | for (Int_t j = 0; j < fNrColumns; ++j) { | |
716 | TString cn = ((TObjString *)(colLine->At(j)))->GetString(); | |
717 | if (cn.BeginsWith("Point Name", TString::kIgnoreCase)) { | |
718 | orderedValues[0] = &value[j]; | |
719 | check[0] = kTRUE; | |
720 | } else if (cn.BeginsWith("X", TString::kIgnoreCase)) { | |
721 | orderedValues[1] = &value[j]; | |
722 | check[1] = kTRUE; | |
723 | } else if (cn.BeginsWith("Y", TString::kIgnoreCase)) { | |
724 | orderedValues[2] = &value[j]; | |
725 | check[2] = kTRUE; | |
726 | } else if (cn.BeginsWith("Z", TString::kIgnoreCase)) { | |
727 | orderedValues[3] = &value[j]; | |
728 | check[3] = kTRUE; | |
729 | } else if (cn.BeginsWith("Precision", TString::kIgnoreCase)) { | |
730 | TString tmpCN = cn(0, cn.First('(')); | |
731 | Int_t precLength = TString("Precision").Length(); | |
732 | if (precLength == tmpCN.Length()) { | |
733 | if(!orderedValues[6]){ | |
734 | orderedValues[6] = &value[j]; | |
735 | check[6] = kTRUE; | |
736 | }else{ | |
737 | AliWarning("Global precision will not be used for X axis"); | |
738 | } | |
739 | if(!orderedValues[7]){ | |
740 | orderedValues[7] = &value[j]; | |
741 | check[7] = kTRUE; | |
742 | }else{ | |
743 | AliWarning("Global precision will not be used for Y axis"); | |
744 | } | |
745 | if(!orderedValues[8]){ | |
746 | orderedValues[8] = &value[j]; | |
747 | check[8] = kTRUE; | |
748 | }else{ | |
749 | AliWarning("Global precision will not be used for Z axis"); | |
750 | } | |
751 | } else { | |
752 | Bool_t orXYZ = kFALSE; | |
753 | TString axis = cn(precLength, tmpCN.Length() - precLength); | |
754 | if (axis.Contains('X', TString::kIgnoreCase)) { | |
755 | if(!prX){ | |
756 | orderedValues[6] = &value[j]; | |
757 | check[6] = kTRUE; | |
758 | orXYZ = kTRUE; | |
759 | prX = kTRUE; | |
760 | }else{ | |
761 | AliError("Precision for X axis was already set!"); | |
762 | return kFALSE; | |
763 | } | |
764 | } | |
765 | if (axis.Contains('Y', TString::kIgnoreCase)) { | |
766 | if(!prY){ | |
767 | orderedValues[7] = &value[j]; | |
768 | check[7] = kTRUE; | |
769 | orXYZ = kTRUE; | |
770 | prY = kTRUE; | |
771 | }else{ | |
772 | AliError("Precision for Y axis was already set!"); | |
773 | return kFALSE; | |
774 | } | |
775 | } | |
776 | if (axis.Contains('Z', TString::kIgnoreCase)) { | |
777 | if(!prZ){ | |
778 | orderedValues[8] = &value[j]; | |
779 | check[8] = kTRUE; | |
780 | orXYZ = kTRUE; | |
781 | prZ = kTRUE; | |
782 | }else{ | |
783 | AliError("Precision for Z axis was already set!"); | |
784 | return kFALSE; | |
785 | } | |
786 | } | |
787 | if(!orXYZ) | |
788 | { | |
789 | AliError("Survey text file sintax error: precision column name does not refer to any axis!"); | |
790 | return kFALSE; | |
791 | } | |
792 | } | |
793 | } else if (cn.BeginsWith("Point Type", TString::kIgnoreCase)) { | |
794 | orderedValues[4] = &value[j]; | |
795 | check[4] = kTRUE; | |
796 | } else if (cn.BeginsWith("Target Used", TString::kIgnoreCase)) { | |
797 | orderedValues[5] = &value[j]; | |
798 | check[5] = kTRUE; | |
799 | } | |
800 | } | |
801 | ||
802 | // Check if all the mandatory fields exist in the line with column names | |
803 | if(!check[0]){ | |
804 | AliError("Missing mandatory column \"Point Name\"!"); | |
805 | return kFALSE; | |
806 | } | |
807 | if(!(check[1]&&check[2]&&check[3])){ | |
808 | AliError("Missing one or more mandatory columns for coordinates \"X\",\"Y\",\"Z\""); | |
809 | return kFALSE; | |
810 | } | |
811 | if(!check[4]){ | |
812 | AliError("Missing mandatory column \"Point Type\"!"); | |
813 | return kFALSE; | |
814 | } | |
815 | if(!(check[6]&&check[7]&&check[8])){ | |
816 | AliError("Missing one or more mandatory columns for precision along \"X\",\"Y\",\"Z\" axes"); | |
817 | return kFALSE; | |
818 | } | |
819 | ||
820 | } else if (currLine.BeginsWith("Data", TString::kIgnoreCase)) { | |
821 | // Data section! | |
822 | while ((nextLine.Length() > 0) && ('>' != nextLine[0])) { | |
823 | ||
824 | // Printf("Data LINE: \"%s\": %d\n", nextLine.Data(), nextLine.Length()); | |
825 | ||
826 | // What is the separator used between fields? | |
827 | // The allowed are: comma (','), tab ('\t'), and space (' ') | |
828 | if (fNrColumns == nextLine.CountChar(',') + 1) dataLine = nextLine.Tokenize(','); | |
829 | else if (fNrColumns == nextLine.CountChar('\t') + 1) dataLine = nextLine.Tokenize('\t'); | |
830 | else if (fNrColumns == nextLine.CountChar(' ') + 1) dataLine = nextLine.Tokenize(' '); | |
831 | else { | |
832 | // Error (No separator was found!) | |
833 | AliError("Survey text file syntax error! Error processing data line!"); | |
834 | lines->Delete(); | |
835 | delete lines; lines = NULL; | |
836 | return kFALSE; | |
837 | } | |
838 | ||
839 | if (dataLine->GetEntries() != fNrColumns) { | |
840 | // The number of columns doesn't match the number specified in the header | |
841 | AliError("Survey text file sintax error! (Number of entries in line is different from number of Columns)"); | |
842 | dataLine->Delete(); | |
843 | lines->Delete(); | |
844 | delete lines; lines = NULL; | |
845 | return kFALSE; | |
846 | } | |
847 | ||
848 | // Process the data line using the column names as index | |
849 | for (Int_t j = 0; j < dataLine->GetEntries(); ++j) { | |
850 | value[j] = ((TObjString *)(dataLine->At(j)))->GetString(); | |
851 | } | |
852 | tmpname = *orderedValues[0]; | |
853 | tmpx = orderedValues[1]->Atof(); | |
854 | tmpy = orderedValues[2]->Atof(); | |
855 | tmpz = orderedValues[3]->Atof(); | |
856 | tmpprecX = orderedValues[6]->Atof(); | |
857 | tmpprecY = orderedValues[7]->Atof(); | |
858 | tmpprecZ = orderedValues[8]->Atof(); | |
859 | tmptype = orderedValues[4]->Data()[0]; | |
860 | if(orderedValues[5]) tmptarg = (orderedValues[5]->Data()[0] == 'Y') ? kTRUE : kFALSE; | |
861 | ||
862 | dp = new AliSurveyPoint(tmpname, tmpx, tmpy, tmpz, tmpprecX, tmpprecY, tmpprecZ, tmptype, tmptarg); | |
863 | if(AliLog::GetDebugLevel("","AliSurveyObj")>1) dp->PrintPoint(); | |
864 | AddPoint(dp); | |
865 | ||
866 | dataLine->Delete(); | |
867 | dataLine = NULL; | |
868 | ++i; | |
869 | nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : ""); | |
870 | } | |
871 | } | |
872 | } else { | |
873 | AliError("Survey text file sintax error!"); | |
874 | lines->Delete(); | |
875 | delete lines; lines = NULL; | |
876 | return kFALSE; | |
877 | } | |
878 | } | |
879 | lines->Delete(); | |
880 | delete lines; lines = NULL; | |
881 | fIsValid = kTRUE; | |
882 | return kTRUE; | |
883 | } | |
884 | ||
885 | //_____________________________________________________________________________ | |
886 | void AliSurveyObj::Reset() { | |
887 | // Resets the AliSurveyObj to a clean object. | |
888 | // Used if the same object is filled more than once | |
889 | ||
890 | if (fDataPoints) { | |
891 | fDataPoints->Delete(); | |
892 | fDataPoints = 0; | |
893 | } | |
894 | fTitle = ""; | |
895 | fDate = ""; | |
896 | fDetector = ""; | |
897 | fURL = "http://edms.cern.ch/"; | |
898 | fReportNr = -1; | |
899 | fVersion = -1; | |
900 | fObs = ""; | |
901 | fCoordSys = ""; | |
902 | fUnits = ""; | |
903 | fNrColumns = -1; | |
904 | fColNames = ""; | |
905 | fIsValid = kFALSE; | |
906 | fDataPoints = new TObjArray(1); | |
907 | fDataPoints->SetOwner(kTRUE); | |
908 | return; | |
909 | } | |
910 |