]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - STEER/AliSurveyObj.cxx
ITS cluster multiplicity and TPC standalone multiplicity in AODHeader
[u/mrichter/AliRoot.git] / STEER / AliSurveyObj.cxx
index 39749650b0375d9e49a774dd67c37919fa5b50d1..0afda085ef5e58b4d677ce22c109f98e122c3e01 100644 (file)
 #include "AliSurveyObj.h"
 
 //ROOT includes
-#include "TROOT.h"
-#include "Riostream.h"
 #include "TObjArray.h"
 #include "TGrid.h"
+#include "TGridResult.h"
 #include "TFile.h"
 #include "TObjString.h"
 
 //AliROOT includes
 #include "AliLog.h"
-
-//System includes
-//#include <time.h> //for sleep(3); // not used anymore!?
+#include "AliSurveyPoint.h"
 
 ClassImp(AliSurveyObj)
+
+
+const TString AliSurveyObj::fgkStorage = "alien://alice.cern.ch";  
+const TString AliSurveyObj::fgkBaseFolder = "/alice/data/Reference";
+const TString AliSurveyObj::fgkValidDetectors = "ACORDE,BABYFRAME,BACKFRAME,\
+EMCAL,FMD,HMPID,ITS,L3 MAGNET,MUON,MUON ABSORBERS,MUON DIPOLE,PHOS,PMD,\
+SPACEFRAME,SUPERSTRUCTURE,T0,TOF,TPC,TRD,VZERO,ZDC,GRP";
+const TString AliSurveyObj::fgkGRPDetectors = "BABYFRAME,BACKFRAME,L3 MAGNET,\
+SPACEFRAME,MUON DIPOLE,MUON ABSORBERS,GRP";
+const TString AliSurveyObj::fgkMUONDetectors = "MUON,SUPERSTRUCTURE";
+
   
 //_____________________________________________________________________________
 AliSurveyObj::AliSurveyObj():
@@ -53,6 +61,7 @@ AliSurveyObj::AliSurveyObj():
   fNrColumns(-1),
   fColNames(""),
   fIsValid(kFALSE),
+  fGridUser(""),
   fDataPoints(new TObjArray(1))
 {
   // constructor
@@ -63,7 +72,10 @@ AliSurveyObj::AliSurveyObj():
 //_____________________________________________________________________________
 AliSurveyObj::~AliSurveyObj() {
   //destructor
-  
+  if (fDataPoints) {
+    fDataPoints->Delete();
+    fDataPoints = 0;
+  }
 }
 
 
@@ -82,6 +94,7 @@ AliSurveyObj::AliSurveyObj(const AliSurveyObj& surveyObj):
   fNrColumns(surveyObj.fNrColumns),
   fColNames(surveyObj.fColNames),
   fIsValid(surveyObj.fIsValid),
+  fGridUser(surveyObj.fGridUser),
   fDataPoints(new TObjArray(1))
 {
   // copy constructor
@@ -92,6 +105,7 @@ AliSurveyObj::AliSurveyObj(const AliSurveyObj& surveyObj):
   }
 }
 
+
 //_____________________________________________________________________________
 AliSurveyObj& AliSurveyObj::operator=(const AliSurveyObj& surveyObj)
 {
@@ -109,20 +123,20 @@ AliSurveyObj& AliSurveyObj::operator=(const AliSurveyObj& surveyObj)
     fNrColumns = surveyObj.fNrColumns;
     fColNames = surveyObj.fColNames;
     fIsValid = surveyObj.fIsValid;
-    
+    fGridUser = surveyObj.fGridUser;
     TObject *curr = surveyObj.fDataPoints->First();
     while (curr != 0) {
       fDataPoints->Add(curr);
       curr = surveyObj.fDataPoints->After(curr);
     }
   }
-  
   return *this;
 }
 
 
 //_____________________________________________________________________________
 void AliSurveyObj::AddPoint(AliSurveyPoint* point) {
+  // Adds a point to the TObjArray which containst the list of points
   fDataPoints->Add(point);
   return;
 }
@@ -130,36 +144,41 @@ void AliSurveyObj::AddPoint(AliSurveyPoint* point) {
 
 //_____________________________________________________________________________
 Bool_t AliSurveyObj::Connect(const char *gridUrl, const char *user) {
-
-   // if the same Grid is alreay active, skip connection
-       if ( !gGrid || gridUrl != gGrid->GridUrl() ||
-            (( user != "" ) && ( user != gGrid->GetUser() )) ) {
-       // connection to the Grid
-          AliInfo("\nConnecting to the Grid...");
-          if(gGrid){
-                  AliInfo(Form("gGrid = %x; GridUrl = %s; gGrid->GridUrl() = %s", 
-                                gGrid, gridUrl, gGrid->GridUrl()));
-             AliInfo(Form("User = %s; gGrid->GetUser() = %s",
-                           user, gGrid->GetUser()));
-          }
-          TGrid::Connect(gridUrl,user);
-       }
+  // Connects to the grid
+
+  // If the same "Grid" is alreay active, skip connection
+  if (!gGrid || gridUrl != gGrid->GridUrl() ||
+      (( strcmp(user,"") ) && ( strcmp(user,gGrid->GetUser()) )) ) {
+    // connection to the Grid
+    AliInfo("\nConnecting to the Grid...");
+    if (gGrid) {
+      AliInfo(Form("gGrid = %p; GridUrl = %s; gGrid->GridUrl() = %s", 
+                  gGrid, gridUrl, gGrid->GridUrl()));
+      AliInfo(Form("User = %s; gGrid->GetUser() = %s",
+                  user, gGrid->GetUser()));
+    }
+    TGrid::Connect(gridUrl,user);
+  }
        
-       if(!gGrid) {
-               AliError("Connection failed!");
-               return kFALSE;
-       }
-   return kTRUE;
+  if(!gGrid) {
+    AliError("Connection failed!");
+    return kFALSE;
+  }
+  return kTRUE;
 }
 
 
 //_____________________________________________________________________________
 Bool_t AliSurveyObj::OpenFile(TString openString) {
-  TString storage = "alien://alice.cern.ch";
+  // Opens the file and reads it to a buffer
 
-  Printf("TFile::Open string: \n -> \"%s\"\n", openString.Data());
+  AliInfo(Form("Opening file \"%s\"\n for survey data", openString.Data()));
 
-  if (openString.BeginsWith("alien://")) Connect(storage.Data(), "rsilva");
+  if (openString.BeginsWith("alien://"))
+    if (!Connect(fgkStorage.Data(), fGridUser.Data())) {
+      AliError(Form("Error connecting to GRID"));
+      return kFALSE;
+    }
 
   TFile *file = TFile::Open(openString.Data(), "READ");
   if ( !file ) {
@@ -169,59 +188,364 @@ Bool_t AliSurveyObj::OpenFile(TString openString) {
 
   Int_t size = file->GetSize();
 
-  char *buf = new Char_t[size];
-  memset(buf, '\0', size);
-
-  //--size;
+  char *buf = new Char_t[size + 1];
+  memset(buf, '\0', size + 1);
 
   file->Seek(0);  
   if ( file->ReadBuffer(buf, size) ) {
     AliError("Error reading file contents to buffer!");
     return kFALSE;
   }
-
-  // Printf("%d bytes read!\n", size);
-  Printf("%d bytes read!\n", file->GetBytesRead());
+  AliInfo(Form("%lld bytes read!\n", file->GetBytesRead()));
   
-  // Printf("->\n%s\n<- ", buf);
-
-  // Printf("%d AQUI!\n", size);
-
-  ParseBuffer(buf);
+  Bool_t goodParsing = ParseBuffer(buf);
 
   file->Close();
   delete[] buf;
-  return kTRUE;
+  return goodParsing;
+}
+
+
+//_____________________________________________________________________________
+Bool_t AliSurveyObj::FillFromLocalFile(const Char_t* filename) {
+  // Fills the object from a file in a local filesystem
+
+  TString fullOpenString = "file://" + TString(filename) + "?filetype=raw";
+
+  return OpenFile(fullOpenString);
 }
 
 
+//_____________________________________________________________________________
+Bool_t AliSurveyObj::IsValidDetector(TString detector) const {
+  // Checks if the detector name is valid
+
+  detector.ToUpper();
+
+  TObjArray *dets = fgkValidDetectors.Tokenize(',');
+  TObject *found = dets->FindObject(detector);
+  dets->Delete();
+  dets = 0;
+
+  if (!found) return kFALSE;
+  else return kTRUE;
+}
+
+
+//_____________________________________________________________________________
+TString AliSurveyObj::RealFolderName(TString detector) const {
+  // Returns the actual folder name for a given detector 
+  // Some "detectors" don't have a folder of their own
+
+  detector.ToUpper();
+  TString folderName = detector;
+
+  TObjArray *dets = fgkGRPDetectors.Tokenize(',');
+  if (dets->FindObject(detector)) folderName = "GRP";
+  dets->Delete();
+  dets = 0;
+
+  dets = fgkMUONDetectors.Tokenize(',');
+  if (dets->FindObject(detector)) folderName = "MUON";
+  dets->Delete();  
+
+
+  dets = 0;
+
+  return folderName;
+}
+
+//_____________________________________________________________________________
+Bool_t AliSurveyObj::Fill(TString detector, Int_t reportNumber,
+                          TString username) {
+  // Fills the object from a file in the default storage location in AliEn.
+  // The highest version available is selected.
+
+  return Fill(detector, reportNumber, -1, username);
+}
 
 //_____________________________________________________________________________
 Bool_t AliSurveyObj::Fill(TString detector, Int_t reportNumber,
-                         Int_t reportVersion) {
-  TString baseFolder = "/alice/cern.ch/user/r/rsilva/";
+                          Int_t reportVersion, TString username) {
+  // Fills the object from a file in the default storage location in AliEn.
+  // A specific version is selected.
+
+  detector.ToUpper();
+  
+  // Check if <detector> is valid
+  if (!IsValidDetector(detector)) {
+    AliWarning(Form("Detector '%s' is not a valid detector/structure!", detector.Data()));
+    return kFALSE;
+  }
+
+  // Some "detectors" don't have a folder of their own
+  // TString detectorFolder = RealFolderName(detector);
+
+  // Check if <year>, <reportNumber> and <reportVersion> are valid (roughly)
+  if ((reportNumber < 1) || (reportVersion < -1) || (0 == reportVersion)) {
+    AliError("Invalid parameter values for AliSurveyObj::Fill. (Report Number or Report Version)");
+    return kFALSE;
+  }
+
+  // Check if the fGridUser is set, or specified
+  if (username.Length() > 0) SetGridUser(username);
+  else if (0 == fGridUser.Length()) {
+    AliError("GRID username not specified and not previously set!");
+    return kFALSE;
+  }
+
+  // Query AliEn for the available reports
+  TGridResult *res = QueryReports(detector, -1, reportNumber, reportVersion);
+  if (!res) AliError(Form("Error querying AliEn for detector '%s', \
+                           report number '%d' and report version '%d'.",
+                         detector.Data(), reportNumber, reportVersion));
+  Int_t numberEntries = res->GetEntries();
+  if (0 == numberEntries) {
+    AliError(Form("No report found for detector '%s', report number '%d' and report version '%d'",
+                 detector.Data(), reportNumber, reportVersion));
+    return kFALSE;
+  }
+
+  TString fileNamePath = "";
+  if (1 == numberEntries) fileNamePath = res->GetFileNamePath(0);
+  else if (numberEntries > 1) {
+    TString higherVerFNP = res->GetFileNamePath(0);
+    Int_t lastYear = FileNamePathToReportYear(higherVerFNP);
+    for (Int_t i = 1; i < numberEntries; ++i) {
+      TString currFNP = res->GetFileNamePath(i);
+      if (FileNamePathToReportVersion(currFNP) >
+         FileNamePathToReportVersion(higherVerFNP)) higherVerFNP = currFNP;
+      if (lastYear != FileNamePathToReportYear(currFNP))
+       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.");
+    }
+    fileNamePath = higherVerFNP;
+  }
 
-  TString fullOpenString = "alien://" + baseFolder + detector + '/';
-  fullOpenString += Form("%d_v%d.txt?filetype=raw", reportNumber, reportVersion);
-  // !Still need to check it's a valid path before actually using it
+  TString fullOpenString = "alien://" + fileNamePath + "?filetype=raw";
+  /*
+  // Finally composes the full string
+  TString fullOpenString = "alien://" + fgkBaseFolder + "/" + detectorFolder + "/RawSurvey/";
+  fullOpenString += Form("%d/%d_v%d.txt?filetype=raw", year, reportNumber, reportVersion);
+  */
 
   return OpenFile(fullOpenString);
 }
 
 
 //_____________________________________________________________________________
-Bool_t AliSurveyObj::FillFromLocalFile(const Char_t* filename) {
-  TString fullOpenString = "file://" + TString(filename) + "?filetype=raw";
+TString AliSurveyObj::FileNamePathToDetector(TString filename) const {
+  // Get the report number from the complete path in the format:
+  // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt
+
+  TString ret = "";
+
+  if (filename.Length() > fgkBaseFolder.Length()) {
+    ret = filename.Remove(0, fgkBaseFolder.Length());
+    ret.Remove(TString::kLeading, '/');
+    ret = ret(0, ret.First('/'));
+    if (!IsValidDetector(ret)) ret = "";
+  } 
+  return ret;
+}
 
-  return OpenFile(fullOpenString);
+///alice/cern.ch/user/r/rsilva/TRD/RawSurvey/2007/.816582_v2.txt/v1.0
+
+//_____________________________________________________________________________
+Int_t AliSurveyObj::FileNamePathToReportYear(TString filename) const {
+  // Get the report year from the complete path in the format:
+  // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt
+
+  TString ret = "";
+
+  if (filename.Length() > fgkBaseFolder.Length()) {
+    ret = filename.Remove(0, fgkBaseFolder.Length());
+    ret.Remove(TString::kLeading, '/');
+    Int_t beg = ret.First('/') + TString("RawSurvey/").Length() + 1;
+    ret = ret(beg, ret.Last('/') - beg);
+    return ret.Atoi();
+  } 
+  return -1;
+}
+
+
+//_____________________________________________________________________________
+Int_t AliSurveyObj::FileNamePathToReportNumber(TString filename) const {
+  // Get the report number from the complete path in the format:
+  // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt
+
+  TString ret = "";
+
+  if (filename.Length() > fgkBaseFolder.Length()) {
+    ret = filename.Remove(0, fgkBaseFolder.Length());
+    ret.Remove(TString::kLeading, '/');
+    if ((ret.CountChar('/') > 3) || (ret.CountChar('.') > 1)) {
+      AliWarning("Error getting the Report Number from the filename path!");
+      return -1;
+    }
+    ret = ret(ret.Last('/') + 1 , ret.Last('_') - ret.Last('/') - 1);
+    return ret.Atoi();
+  } 
+  AliWarning("Error getting the Report Number from the filename path!");
+  return -1;
+}
+
+
+//_____________________________________________________________________________
+Int_t AliSurveyObj::FileNamePathToReportVersion(TString filename) const {
+  // Get the report version from the complete path in the format:
+  // /alice/data/Reference/HMPID/RawSurvey/2006/781282_v1.txt
+
+  TString ret = "";
+
+  if (filename.Length() > fgkBaseFolder.Length()) {
+    ret = filename.Remove(0, fgkBaseFolder.Length());
+    ret.Remove(TString::kLeading, '/');
+    if ((ret.CountChar('/') > 3) || (ret.CountChar('.') > 1)) {
+      AliWarning("Error getting the Report Version from the filename path!");
+      return -1;
+    }
+    ret = ret(ret.Last('_') + 1 + 1 , ret.Last('.') - ret.Last('_') - 1 - 1);
+    return ret.Atoi();
+  } 
+  AliWarning("Error getting the Report Version from the filename path!");
+  return -1;
+}
+
+
+//_____________________________________________________________________________
+void AliSurveyObj::ListValidDetectors() {
+    // List the valid detector names
+    Printf("Listing all valid detectors:\n");
+    TObjArray *dets = fgkValidDetectors.Tokenize(',');
+    for (int i = 0; i < dets->GetEntries(); ++i) 
+       Printf("%s", ((TObjString *) dets->At(i))->GetString().Data());
+    dets->Delete();
+    dets = 0;
+    Printf("Some reports are stored in more general folders.\n"
+           "These reports can be opened using either name, the original or the\n"
+           "folder name. Example: 'SPACEFRAME' or 'GRP' are both valid when\n"
+           "opening a report for the Spaceframe.\n\n"
+           "Detectors stored in 'MUON' folder:");
+    dets = fgkMUONDetectors.Tokenize(',');
+    for (int i = 0; i < dets->GetEntries(); ++i) 
+       Printf("%s", ((TObjString *) dets->At(i))->GetString().Data());
+    dets->Delete();
+    dets = 0;
+    Printf("Detectors stored in 'GRP' folder:");
+    dets = fgkGRPDetectors.Tokenize(',');
+    for (int i = 0; i < dets->GetEntries(); ++i) 
+       Printf("%s", ((TObjString *) dets->At(i))->GetString().Data());
+    dets->Delete();
+    dets = 0;
+    return;
+}
+
+
+//_____________________________________________________________________________
+TGridResult * AliSurveyObj::QueryReports(TString detector, Int_t year,
+                                        Int_t reportNumber,
+                                        Int_t reportVersion) {
+  // Queries AliEn for existing reports matching the specified conditions
+  TString lsArg = fgkBaseFolder;
+  
+  TString detectorFolder = "";
+  if (detector.Length() > 0) {
+    detector.ToUpper();
+    // Check if <detector> is valid
+    if (!IsValidDetector(detector)) {
+      AliError(Form("Detector '%s' is not a valid detector/structure!",
+                   detector.Data()));
+      return 0;
+    }
+    // Some "detectors" don't have a folder of their own
+    detectorFolder = "/" + RealFolderName(detector);
+  } else detectorFolder = "/*";
+
+  lsArg += detectorFolder + "/RawSurvey";
+
+  TString yearFolder = "";
+  if (year > 1950) yearFolder.Form("/%d", year);
+  else yearFolder = "/*";
+
+  TString reportFolder = "";
+  if (reportNumber > 0) reportFolder.Form("/%d", reportNumber);
+  else reportFolder = "/*";
+
+  TString versionFolder = "";
+  if (reportVersion > 0) versionFolder.Form("_v%d", reportVersion);
+  else versionFolder = "_v*";
+
+  lsArg += yearFolder + reportFolder + versionFolder + ".txt";
+
+  AliInfo(Form("\nLooking for:  %s \n", lsArg.Data()));
+  
+  // Check if fGridUser is set and Connect to AliEn
+  if (0 == fGridUser.Length()) {
+    AliError("To use this method it's necessary to call SetGridUser(...) in advance.");
+    return 0;
+  } else if (!Connect(fgkStorage.Data(), fGridUser.Data())) {
+    AliError(Form("Error connecting to GRID"));
+    return 0;
+  }
+  return gGrid->Ls(lsArg);
+}
+
+
+//_____________________________________________________________________________
+Int_t AliSurveyObj::ListReports(TString detector, Int_t year, 
+                               Int_t reportNumber,
+                               Int_t reportVersion) {
+  // Lists all available reports matching the specified conditions
+  // Returns the number of reports found
+
+  TGridResult *res = QueryReports(detector, year, reportNumber, reportVersion);
+  
+  if (0 == res) {
+    AliError("Query failed.");
+    return 0;
+  }
+
+  TString fn = "";
+  Int_t numberEntries = res->GetEntries();
+
+  if (numberEntries > 0) {
+    Printf("%d reports found:", numberEntries);
+    for (int i = 0; i < res->GetEntries(); ++i) {
+      fn = res->GetFileNamePath(i);
+      Printf("Detector:%s\tYear:%d\tEDMS Report Number:%d\tVersion:%d",
+                 FileNamePathToDetector(fn).Data(),
+                 FileNamePathToReportYear(fn),
+                 FileNamePathToReportNumber(fn),
+                 FileNamePathToReportVersion(fn));
+    }
+    delete res;
+    return numberEntries;
+  } else {
+    AliInfo("No results found for the requested query.");
+    delete res;
+    return 0;
+  }
+}
+
+
+//_____________________________________________________________________________
+void AliSurveyObj::SetGridUser(TString username){
+  // Set the username used to connect to the GRID
+  fGridUser = username;
+  return;
 }
 
 
 //_____________________________________________________________________________
 TString &AliSurveyObj::Sanitize(TString str) {
+  // Cleans up a line of new line and carriage return characters.
+  // (Specially usefull for files created in Windows.)
+
   str.Remove(TString::kTrailing, '\r');
   str.Remove(TString::kTrailing, '\n');
   str.Remove(TString::kTrailing, '\r');
+
   if (!str.IsAscii()) {
     AliWarning("Warning: Non-ASCII characters!\n");
     str = "";
@@ -232,41 +556,71 @@ TString &AliSurveyObj::Sanitize(TString str) {
 
 //_____________________________________________________________________________
 Bool_t AliSurveyObj::ParseBuffer(const Char_t* buf) {
+  // Parses a character buffer assuming the format defined with the TS/SU
+  // http://aliceinfo/Offline/Activities/Alignment/SurveyInformation.html
+
+  // If the object is already filled clean it up
+  if (fIsValid) Reset();
+
+  // Copy the buffer to a TString to use Tokenize
   TString buffer = TString(buf);
-  TObjArray *lines = buffer.Tokenize('\n');
-  TObjArray *dataLine = NULL; // Used to Tokenize each point read
+  TObjArray *linesRaw = buffer.Tokenize('\n');
+  // replace the array of lines with an array of sanitized lines
+  // in the process we remove empty lines, particularly disturbing
+  // in case of dos fileformat
+  TString oneLine = "";
+  TObjString* oneLineObj = 0;
+  TObjArray *lines = new TObjArray();
+  for(Int_t i=0; i<linesRaw->GetEntries(); i++)
+  {
+         oneLine = ((TObjString *)(linesRaw->At(i)))->GetString().Data();
+         oneLine = Sanitize(oneLine);
+         if (oneLine.Length() == 0) continue;
+         oneLineObj = new TObjString(oneLine);
+         lines->Add(oneLineObj);
+  }
+
+  linesRaw->Delete();
+  delete linesRaw;
+  linesRaw = NULL;
+
+  TObjArray *dataLine = NULL; // Used to Tokenize each point/line read
   TObjArray *colLine = NULL; // Used to Tokenize the column names
 
+  // Some local variables declarations and initializations
   const Int_t kFieldCheck = 10;
-  Bool_t check[kFieldCheck];
-  TString tmp_name = "";
-  Float_t tmp_x = 0.0, tmp_y = 0.0, tmp_z = 0.0;
-  Float_t tmp_precX = 0.0, tmp_precY = 0.0, tmp_precZ = 0.0;
-  Char_t tmp_type = '\0';
-  Bool_t tmp_targ = kTRUE;
-  AliSurveyPoint *dp = 0;
-  
+  Bool_t check[kFieldCheck]; // used to check that mandatory column names are not missing
   for (Int_t i = 0; i < kFieldCheck; ++i) check[i] = kFALSE;
+  TString tmpname = "";
+  Float_t tmpx = 0.0, tmpy = 0.0, tmpz = 0.0;
+  Float_t tmpprecX = -1., tmpprecY = -1., tmpprecZ = -1.;
+  Char_t tmptype = '\0';
+  Bool_t tmptarg = kTRUE;
+  AliSurveyPoint *dp = 0;
+  TString *orderedValues[9] = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0};
+  TString value[9];
 
   Int_t nrLines = lines->GetEntries();
   Printf("Lines in file: %d\n", nrLines); 
 
+  // The main cycle, the buffer is parsed a line at a time
   TString currLine = "", nextLine = "";
   for (Int_t i = 0; i < nrLines; ++i) {
+
+    // Get the next line
     currLine = ((TObjString *)(lines->At(i)))->GetString().Data();
     nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : "");
-    currLine = Sanitize(currLine);
-    nextLine = Sanitize(nextLine);
-    //Printf("\n%d: \"\"%s\"\"\"\n", i + 1, currLine.Data());
+    // Printf("%d: \"%s\"", i, currLine.Data());
+    // Printf("%d:  \"%s\"\n", i+1, nextLine.Data());
     
-    if (0 == currLine.Length()) {
-      Printf("Info: Empty line skipped\n\n");
-    } else if (currLine.BeginsWith(">") && !nextLine.BeginsWith(">")) {
+    // The line contains a keyword
+    if (currLine.BeginsWith(">") && !nextLine.BeginsWith(">")) {
       currLine.Remove(TString::kLeading, '>');
       currLine.Remove(TString::kTrailing, ':');
       currLine.Remove(TString::kBoth, ' ');
       nextLine.Remove(TString::kBoth, ' ');
-      // Printf(" -> Field: \"%s\"\n", currLine.Data());
+      AliDebug(2, Form(" -> field line: \"%s\"\n", currLine.Data()));
+      AliDebug(2, Form(" -> value line: \"%s\"\n", nextLine.Data()));
       
       if (currLine.BeginsWith("Title", TString::kIgnoreCase)) {
        // Report Title
@@ -288,179 +642,269 @@ Bool_t AliSurveyObj::ParseBuffer(const Char_t* buf) {
          nextLine.Remove(TString::kTrailing, '/');
          nextLine = nextLine(nextLine.Last('/') + 1, nextLine.Length() - nextLine.Last('/') + 1);
          
-         Printf("## %s ##\n", nextLine.Data());
-         Int_t sscanf_tmp = 0;
-         //if (!nextLine.IsDigit()) {
-         if (1 != sscanf(nextLine.Data(), "%d", &sscanf_tmp)) {
-           AliError("Survey text file sintax error! (incorrectly formated Report URL)");
+         if (!nextLine.IsDigit()) {
+           AliError("Survey text file sintax error! (incorrectly formatted Report URL)");
+           AliError(Form("Wrong report number string: \"%s\"",nextLine.Data()));
            lines->Delete();
+           delete lines; lines = NULL;
            return kFALSE;
          }
          fReportNr = nextLine.Atoi();
          //Printf(" $$ %d $$\n", fReportNr);
          ++i;
-       } else { // URL incorrectly formated
-         AliError("Survey text file sintax error! (incorrectly formated Report URL)");
+       } else { 
+         // URL incorrectly formatted
+         AliError("Survey text file sintax error! (incorrectly formatted Report URL)");
          return kFALSE;
        }
       } else if (currLine.BeginsWith("Version", TString::kIgnoreCase)) {
+       // Report version
        if (!nextLine.IsDigit()) {
          lines->Delete();
-         AliError("Survey text file sintax error! (incorrectly formated Report Version)");
+         delete lines; lines = NULL;
+         AliError("Survey text file sintax error! (incorrectly formatted Report Version)");
          return kFALSE;
        }
        fVersion = nextLine.Atoi();
        ++i;
       } else if (currLine.BeginsWith("General Observations", TString::kIgnoreCase)) {
+       // Observations
        fObs = "";
-       while (('>' != nextLine[0]) && nextLine.Length() > 0) { 
+       // Can be more than 1 line. Loop until another keyword is found
+       while (('>' != nextLine[0]) && (nextLine.Length() > 0) && (i < nrLines)) {      
          fObs += (0 == fObs.Length()) ? nextLine : " / " + nextLine;
          ++i;
          nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : "");
-         nextLine = Sanitize(nextLine);
        }
-       // Printf("->%s<-\n", fObs.Data());
       } else if (currLine.BeginsWith("Coordinate System", TString::kIgnoreCase)) {
+       // Coordinate System
        fCoordSys = nextLine;
        ++i;
       } else if (currLine.BeginsWith("Units", TString::kIgnoreCase)) {
+       // Measurement Unit
        fUnits = nextLine;
        ++i;
       } else if (currLine.BeginsWith("Nr Columns", TString::kIgnoreCase)) {
+       // Number of columns in the "Data" section
        if (!nextLine.IsDigit()) {
          lines->Delete();
-         AliError("Survey text file sintax error! (incorrectly formated Number of Columns)");
+         delete lines; lines = NULL;
+         AliError("Survey text file sintax error! (incorrectly formatted Number of Columns)");
          return kFALSE;
        }
        fNrColumns = nextLine.Atoi();
        ++i;
       } else if (currLine.BeginsWith("Column Names", TString::kIgnoreCase)) {
+       // Column names separated by commas
        fColNames = nextLine;
        colLine = nextLine.Tokenize(',');
        if (colLine->GetEntries() != fNrColumns) {
          AliError("Survey text file sintax error! (Declared number of Columns doesn't match number of column names)");
          colLine->Delete();
          lines->Delete();
+         delete lines; lines = NULL;
          return kFALSE;
        }
        ++i;
-      } else if (currLine.BeginsWith("Data", TString::kIgnoreCase)) {
-       while ((nextLine.Length() > 0) && ('>' != nextLine[0])) {
-         Printf("Data LINE: \"%s\": %d\n", nextLine.Data(), nextLine.Length());
-         if (2 == nextLine.Length()) for(Int_t g = 0; g < 2; ++g) Printf("'%c'", nextLine[g]);
-
-          if (fNrColumns == nextLine.CountChar(' ') + 1) dataLine = nextLine.Tokenize(' ');
-          else if (fNrColumns == nextLine.CountChar(',') + 1) dataLine = nextLine.Tokenize(',');
-          else if (fNrColumns == nextLine.CountChar('\t') + 1) dataLine = nextLine.Tokenize('\t');
-          else {
-            //Error
-            AliError("Survey text file syntax error! Error processing data line!");
-            lines->Delete();
-            return kFALSE;
-          }
-
-         if (dataLine->GetEntries() != fNrColumns) {
-           AliError("Survey text file sintax error! (Number of entries in line is different from declared Number of Columns)");
-           dataLine->Delete();
-           lines->Delete();
-           return kFALSE;
-         }
-
-         for (Int_t t = 0; t < kFieldCheck; ++t) check[t] = 0;
-
-         for (Int_t j = 0; j < dataLine->GetEntries(); ++j) {
-           TString cn = ((TObjString *)(colLine->At(j)))->GetString();
-           TString value = ((TObjString *)(dataLine->At(j)))->GetString();
-           if (cn.BeginsWith("Point Name", TString::kIgnoreCase)) {
-             tmp_name = value;
-             check[0] = kTRUE;
-           } else if (cn.BeginsWith("X", TString::kIgnoreCase)) {
-             tmp_x = value.Atof();
-             check[1] = kTRUE;
-           } else if (cn.BeginsWith("Y", TString::kIgnoreCase)) {
-             tmp_y = value.Atof();
-             check[2] = kTRUE;
-           } else if (cn.BeginsWith("Z", TString::kIgnoreCase)) {
-             tmp_z = value.Atof();
-             check[3] = kTRUE;
-           } else if (cn.BeginsWith("Precision", TString::kIgnoreCase)) {
-             TString tmpCN = cn(0, cn.First('('));
-             Int_t precLength = TString("Precision").Length();
-             //Printf(" ====== %d ======= %d ====== \n", precLength, tmpCN.Length());
-             //Printf(" ====== %s ======= \n", tmpCN.Data());
-             if (precLength == tmpCN.Length()) {
-               tmp_precX = tmp_precY = tmp_precZ = value.Atof();
-               check[6] = kTRUE;
-             } else {
-               TString axis = cn(precLength, tmpCN.Length() - precLength);
-               if (axis.Contains('X', TString::kIgnoreCase)) {
-                 tmp_precX = value.Atof();
+       
+       // booleans to track if precision for 1 axis is defined in more than one column
+       Bool_t prX = kFALSE;
+       Bool_t prY = kFALSE;
+       Bool_t prZ = kFALSE;
+       
+       for (Int_t j = 0; j < fNrColumns; ++j) {
+         TString cn = ((TObjString *)(colLine->At(j)))->GetString();
+         if (cn.BeginsWith("Point Name", TString::kIgnoreCase)) {
+           orderedValues[0] = &value[j];
+           check[0] = kTRUE;
+         } else if (cn.BeginsWith("X", TString::kIgnoreCase)) {
+           orderedValues[1] = &value[j];
+           check[1] = kTRUE;
+         } else if (cn.BeginsWith("Y", TString::kIgnoreCase)) {
+           orderedValues[2] = &value[j];
+           check[2] = kTRUE;
+         } else if (cn.BeginsWith("Z", TString::kIgnoreCase)) {
+           orderedValues[3] = &value[j];
+           check[3] = kTRUE;
+         } else if (cn.BeginsWith("Precision", TString::kIgnoreCase)) {
+           TString tmpCN = cn(0, cn.First('('));
+           Int_t precLength = TString("Precision").Length();
+           if (precLength == tmpCN.Length()) {
+             if(!orderedValues[6]){
+               orderedValues[6] = &value[j];
+               check[6] = kTRUE;
+             }else{
+               AliWarning("Global precision will not be used for X axis");
+             }
+             if(!orderedValues[7]){
+               orderedValues[7] = &value[j];
+               check[7] = kTRUE;
+             }else{
+               AliWarning("Global precision will not be used for Y axis");
+             }
+             if(!orderedValues[8]){
+               orderedValues[8] = &value[j];
+               check[8] = kTRUE;
+             }else{
+               AliWarning("Global precision will not be used for Z axis");
+             }
+           } else {
+             Bool_t orXYZ = kFALSE;
+             TString axis = cn(precLength, tmpCN.Length() - precLength);
+             if (axis.Contains('X', TString::kIgnoreCase)) {
+               if(!prX){
+                 orderedValues[6] = &value[j];
+                 check[6] = kTRUE;
+                 orXYZ = kTRUE;
+                 prX = kTRUE;
+               }else{
+                 AliError("Precision for X axis was already set!");
+                 return kFALSE;
+               }
+             }
+             if (axis.Contains('Y', TString::kIgnoreCase)) {
+               if(!prY){
+                 orderedValues[7] = &value[j];
                  check[7] = kTRUE;
-               } else if (axis.Contains('Y', TString::kIgnoreCase)) {
-                 tmp_precY = value.Atof();
+                 orXYZ = kTRUE;
+                 prY = kTRUE;
+               }else{
+                 AliError("Precision for Y axis was already set!");
+                 return kFALSE;
+               }
+             }
+             if (axis.Contains('Z', TString::kIgnoreCase)) {
+               if(!prZ){
+                 orderedValues[8] = &value[j];
                  check[8] = kTRUE;
-               } else if (axis.Contains('Z', TString::kIgnoreCase)) {
-                 tmp_precZ = value.Atof();
-                 check[9] = kTRUE;
-               } else {
-                 AliError("Survey text file sintax error! (Precision column name invalid)");
-                 dataLine->Delete();
-                 lines->Delete();
+                 orXYZ = kTRUE;
+                 prZ = kTRUE;
+               }else{
+                 AliError("Precision for Z axis was already set!");
                  return kFALSE;
                }
              }
-           } else if (cn.BeginsWith("Point Type", TString::kIgnoreCase)) {
-             tmp_type = value.Data()[0];
-             check[4] = kTRUE;
-           } else if (cn.BeginsWith("Target Used", TString::kIgnoreCase)) {
-             tmp_targ = (value.Data()[0] == 'Y') ? kTRUE : kFALSE;
-             check[5] = kTRUE;
+             if(!orXYZ)
+             {
+               AliError("Survey text file sintax error: precision column name does not refer to any axis!");
+               return kFALSE;
+             }
            }
-
-           //Printf("--> %s\n", ((TObjString *)(dataLine->At(j)))->GetString().Data());
-         }
-         Bool_t res = kTRUE, precInd = kTRUE;
-
-         // Target
-         if (kFALSE == check[5]) {
-           tmp_targ = kTRUE;
+         } else if (cn.BeginsWith("Point Type", TString::kIgnoreCase)) {
+           orderedValues[4] = &value[j];
+           check[4] = kTRUE;
+         } else if (cn.BeginsWith("Target Used", TString::kIgnoreCase)) {
+           orderedValues[5] = &value[j];
            check[5] = kTRUE;
          }
-         
-         // Individual axis precisions
-         for (Int_t t = 7; t < 10; ++t) precInd &= check[t];
-         if ((kFALSE == check[6]) && (kTRUE == precInd)) check[6] = kTRUE;
+       }
 
-         for (Int_t t = 0; t < kFieldCheck - 3; ++t) {
-           //Printf("RES(%d): %d\n", t, check[t]);
-           res &= check[t];
+       // Check if all the mandatory fields exist in the line with column names
+       if(!check[0]){
+         AliError("Missing mandatory column \"Point Name\"!");
+         return kFALSE;
+       }
+       if(!(check[1]&&check[2]&&check[3])){
+         AliError("Missing one or more mandatory columns for coordinates \"X\",\"Y\",\"Z\"");
+         return kFALSE;
+       }
+       if(!check[4]){
+         AliError("Missing mandatory column \"Point Type\"!");
+         return kFALSE;
+       }
+       if(!(check[6]&&check[7]&&check[8])){
+         AliError("Missing one or more mandatory columns for precision along \"X\",\"Y\",\"Z\" axes");
+         return kFALSE;
+       }
+
+      } else if (currLine.BeginsWith("Data", TString::kIgnoreCase)) {
+       // Data section!
+       while ((nextLine.Length() > 0) && ('>' != nextLine[0])) {
+
+         // Printf("Data LINE: \"%s\": %d\n", nextLine.Data(), nextLine.Length());
+
+         // What is the separator used between fields?
+         // The allowed are: comma (','), tab ('\t'), and space (' ')
+         if (fNrColumns == nextLine.CountChar(',') + 1) dataLine = nextLine.Tokenize(',');
+         else if (fNrColumns == nextLine.CountChar('\t') + 1) dataLine = nextLine.Tokenize('\t');
+         else if (fNrColumns == nextLine.CountChar(' ') + 1) dataLine = nextLine.Tokenize(' ');
+         else {
+           // Error (No separator was found!)
+           AliError("Survey text file syntax error! Error processing data line!");
+           lines->Delete();
+           delete lines; lines = NULL;
+           return kFALSE;
          }
-         if (kTRUE == res) {
-           dp = new AliSurveyPoint(tmp_name, tmp_x, tmp_y, tmp_z, tmp_precX, tmp_precY, tmp_precZ, tmp_type, tmp_targ);
-           dp->PrintPoint();
-           AddPoint(dp);
-         } else {
-           AliError("Parsing error processing data line!");
+
+         if (dataLine->GetEntries() != fNrColumns) {
+           // The number of columns doesn't match the number specified in the header
+           AliError("Survey text file sintax error! (Number of entries in line is different from number of Columns)");
            dataLine->Delete();
            lines->Delete();
+           delete lines; lines = NULL;
            return kFALSE;
          }
-         
+
+         // Process the data line using the column names as index
+         for (Int_t j = 0; j < dataLine->GetEntries(); ++j) {
+           value[j] = ((TObjString *)(dataLine->At(j)))->GetString();
+         }
+         tmpname = *orderedValues[0];
+         tmpx = orderedValues[1]->Atof();
+         tmpy = orderedValues[2]->Atof();
+         tmpz = orderedValues[3]->Atof();
+         tmpprecX = orderedValues[6]->Atof();
+         tmpprecY = orderedValues[7]->Atof();
+         tmpprecZ = orderedValues[8]->Atof();
+         tmptype = orderedValues[4]->Data()[0];
+         if(orderedValues[5]) tmptarg = (orderedValues[5]->Data()[0] == 'Y') ? kTRUE : kFALSE;
+
+         dp = new AliSurveyPoint(tmpname, tmpx, tmpy, tmpz, tmpprecX, tmpprecY, tmpprecZ, tmptype, tmptarg);
+         if(AliLog::GetDebugLevel("","AliSurveyObj")>1) dp->PrintPoint();
+         AddPoint(dp);
+
          dataLine->Delete();
          dataLine = NULL;
          ++i;
          nextLine = ((i + 1) < nrLines ? ((TObjString *)(lines->At(i + 1)))->GetString().Data() : "");
-         nextLine = Sanitize(nextLine);
        }
       }
     } else {
       AliError("Survey text file sintax error!");
       lines->Delete();
+      delete lines; lines = NULL;
       return kFALSE;
     }
   }
   lines->Delete();
+  delete lines; lines = NULL;
   fIsValid = kTRUE;
   return kTRUE;
 }
 
+//_____________________________________________________________________________
+void AliSurveyObj::Reset() {
+  // Resets the AliSurveyObj to a clean object.
+  // Used if the same object is filled more than once
+  
+  if (fDataPoints) {
+    fDataPoints->Delete();
+    fDataPoints = 0;
+  }
+  fTitle = "";
+  fDate = "";
+  fDetector = "";
+  fURL = "http://edms.cern.ch/";
+  fReportNr = -1;
+  fVersion = -1;
+  fObs = "";
+  fCoordSys = "";
+  fUnits = "";
+  fNrColumns = -1;
+  fColNames = "";
+  fIsValid = kFALSE;
+  fDataPoints = new TObjArray(1);
+  fDataPoints->SetOwner(kTRUE);
+  return;
+}
+