From 59df2224ba7d6e994e04f02109bcb7b5486611ff Mon Sep 17 00:00:00 2001 From: nemu Date: Tue, 13 Mar 2012 07:47:00 +0000 Subject: [PATCH] handles now updating properly --- src/tests/MusrRoot/MusrRoot.xsd | 13 +- src/tests/MusrRoot/MusrRootLEM.xsd | 221 ++++++++++++ src/tests/MusrRoot/TMusrRunHeader.cpp | 322 ++++++++++-------- src/tests/MusrRoot/TMusrRunHeader.h | 17 +- src/tests/MusrRoot/root2xml.C | 10 +- .../MusrRoot/write_musrRoot_runHeader.cpp | 4 - 6 files changed, 420 insertions(+), 167 deletions(-) create mode 100644 src/tests/MusrRoot/MusrRootLEM.xsd diff --git a/src/tests/MusrRoot/MusrRoot.xsd b/src/tests/MusrRoot/MusrRoot.xsd index a672ad26..1d1b849c 100644 --- a/src/tests/MusrRoot/MusrRoot.xsd +++ b/src/tests/MusrRoot/MusrRoot.xsd @@ -3,7 +3,7 @@ This XSD document describes the muSR file structure for CERN/ROOT based files. - In the following it will be called MusrROOT. + In the following it will be called MusrRoot. It is currently the default standard for writting muSR data files at the Paul Scherrer Institute. @@ -55,7 +55,7 @@ - + @@ -118,7 +118,8 @@ - + + @@ -147,6 +148,12 @@ + + + + + + diff --git a/src/tests/MusrRoot/MusrRootLEM.xsd b/src/tests/MusrRoot/MusrRootLEM.xsd new file mode 100644 index 00000000..91423193 --- /dev/null +++ b/src/tests/MusrRoot/MusrRootLEM.xsd @@ -0,0 +1,221 @@ + + + + + This XSD document describes the muSR file structure of CERN/ROOT based files for LEM. + In the following it will be called MusrRootLEM. + It is an extension of MusrRoot.xsd and describes the additional LEM specific entries. + + Author: Andreas Suter, andreas.suter@psi.ch + $Id$ + + + + + + + + + + + + + + + + + The histos folder is containing potentially various subfolders. + At least two subfolders, called DecayAnaModule, and SlowControlAnaModule, + which holds the muSR decay histograms, must be present. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/tests/MusrRoot/TMusrRunHeader.cpp b/src/tests/MusrRoot/TMusrRunHeader.cpp index f7ac76ef..79daa86b 100644 --- a/src/tests/MusrRoot/TMusrRunHeader.cpp +++ b/src/tests/MusrRoot/TMusrRunHeader.cpp @@ -213,8 +213,10 @@ ClassImp(TMusrRunHeader) //-------------------------------------------------------------------------- /** *

Constructor. + * + * \param quite if set to true, warnings will be omited. Default is false. */ -TMusrRunHeader::TMusrRunHeader() +TMusrRunHeader::TMusrRunHeader(bool quite) : fQuite(quite) { Init(); } @@ -224,9 +226,13 @@ TMusrRunHeader::TMusrRunHeader() //-------------------------------------------------------------------------- /** *

Constructor. + * + * \param fileName file name of the MusrRoot file. + * \param quite if set to true, warnings will be omited. Default is false. */ -TMusrRunHeader::TMusrRunHeader(const char *fileName) +TMusrRunHeader::TMusrRunHeader(const char *fileName, bool quite) { + fQuite = quite; Init(TString(fileName)); } @@ -243,6 +249,11 @@ void TMusrRunHeader::Init(TString fileName) fFileName = fileName; fVersion = TString("$Id$"); Set("RunInfo/Version", fVersion); + Set("RunInfo/Generic Validator URL", "http://lmu.web.psi.ch/facilities/software/MusrRoot/validation/MusrRoot.xsd"); + Set("DetectorInfo/Detector000/Name", "n/a"); + Set("SampleEnvironmentInfo/Cryo", "n/a"); + Set("MagneticFieldEnvironmentInfo/Magnet Name", "n/a"); + Set("BeamlineInfo/Name", "n/a"); } //-------------------------------------------------------------------------- @@ -280,83 +291,68 @@ void TMusrRunHeader::CleanUp() //-------------------------------------------------------------------------- /** *

Fills the RunHeader folder. This is needed to write it to a ROOT file. - * It walks through all information and attaches it to folder. + * It walks through all information and attaches it to the folder or replaces + * it, if it is already present. * * \param folder to be filled */ Bool_t TMusrRunHeader::FillFolder(TFolder *folder) { - TObjArray *oarray, *tokens; - vector content; - TObjString ostr; - TString path, name, pathName; + TObjArray *oarray; + TObjString ostr, *p_ostr; + TString path, name, str; + Ssiz_t pos=0; + bool found=false; if (folder == 0) { cerr << endl << ">> TMusrRunHeader::FillFolder(): **ERROR** folder == 0!!" << endl; return false; } - folder->SetOwner(); // folder takes ownership of all added objects! + folder->SetOwner(); // folder takes ownership of all added objects! This means that the folder object does the cleanup + // update/generate tree structure in folder for (UInt_t i=0; i> TMusrRunHeader::FillFolder(): **ERROR** couldn't tokenize string " << fPathNameOrder[i] << endl; + path=fPathNameOrder[i]; + + if (!UpdateFolder(folder, path)) + return false; + } + + // update/generate tree content + for (UInt_t i=0; i> TMusrRunHeader::FillFolder(): **ERROR** somethig is wrong with the path=" << path << " !!" << endl; + return false; + } + path.Remove(pos); // remove the value from the path + + oarray = (TObjArray*)FindObject(folder, path); + if (!oarray) { + cerr << endl << ">> TMusrRunHeader::FillFolder(): **ERROR** couldn't create header structure!!" << endl; return false; } - Int_t idx; - if (tokens->GetEntries() == 2) { // / - path = ((TObjString*)tokens->At(0))->GetString(); - idx = ObjectPresent(content, path); - if (idx == -1) { - // add object array - oarray = new TObjArray(); - oarray->SetName(path); - content.push_back(oarray); - idx = content.size()-1; + // check if is already found in oarray + ostr = GetHeaderString(i); // encode the string for the MusrRoot file + name = ostr.GetString(); // convert to TString + str = GetFirst(name, ':'); // get the first part of the encoded string, i.e. - + found = false; + for (Int_t j=0; jGetEntriesFast(); j++) { + p_ostr = (TObjString*) oarray->At(j); + if (p_ostr->GetString().BeginsWith(str)) { // present hence replace + oarray->AddAt(ostr.Clone(), j); + found = true; + break; } - // add value - ostr = GetHeaderString(i); - content[idx]->AddLast(ostr.Clone()); - } else { // /..// - path = ((TObjString*)tokens->At(0))->GetString(); - idx = ObjectPresent(content, path); - if (idx == -1) { - // add object array - oarray = new TObjArray(); - oarray->SetName(path); - content.push_back(oarray); - idx = content.size()-1; - } - - // add necessary sub object arrays - pathName = fPathNameOrder[i]; - RemoveFirst(pathName, '/'); - AddSubTrees(content[idx], pathName); - - // get header string - ostr = GetHeaderString(i); - - // set object string on the right position within content - SetSubTreeObject(content[idx], ostr, i); } - - // clean up - if (tokens) { - delete tokens; - tokens = 0; + if (!found) { + oarray->AddLast(ostr.Clone()); } } - // fill folder with all run header information - for (UInt_t i=0; iAdd(content[i]); - } - - // clean up - content.clear(); - return true; } @@ -525,11 +521,12 @@ void TMusrRunHeader::GetValue(TString pathName, TDoubleVector &value, Bool_t &ok */ void TMusrRunHeader::Set(TString pathName, TString value) { - // check if pathName is already set, and if not add it as a new entry + // check if pathName is already set, if not add it as a new entry, otherwise replace it UInt_t i=0; for (i=0; i> **WARNING** " << pathName.Data() << " already exists, will replace it." << endl; + if (!fQuite) + cerr << endl << ">> **WARNING** " << pathName.Data() << " already exists, will replace it." << endl; fStringObj[i].SetType("TString"); fStringObj[i].SetValue(value); break; @@ -558,11 +555,12 @@ void TMusrRunHeader::Set(TString pathName, TString value) */ void TMusrRunHeader::Set(TString pathName, Int_t value) { - // check if pathName is already set, and if not add it as a new entry + // check if pathName is already set, if not add it as a new entry, otherwise replace it UInt_t i=0; for (i=0; i> **WARNING** " << pathName.Data() << " already exists, will replace it." << endl; + if (!fQuite) + cerr << endl << ">> **WARNING** " << pathName.Data() << " already exists, will replace it." << endl; fIntObj[i].SetType("Int_t"); fIntObj[i].SetValue(value); break; @@ -591,11 +589,12 @@ void TMusrRunHeader::Set(TString pathName, Int_t value) */ void TMusrRunHeader::Set(TString pathName, Double_t value) { - // check if pathName is already set, and if not add it as a new entry + // check if pathName is already set, if not add it as a new entry, otherwise replace it UInt_t i=0; for (i=0; i> **WARNING** " << pathName.Data() << " already exists, will replace it." << endl; + if (!fQuite) + cerr << endl << ">> **WARNING** " << pathName.Data() << " already exists, will replace it." << endl; fDoubleObj[i].SetType("Double_t"); fDoubleObj[i].SetValue(value); break; @@ -624,11 +623,12 @@ void TMusrRunHeader::Set(TString pathName, Double_t value) */ void TMusrRunHeader::Set(TString pathName, TMusrRunPhysicalQuantity value) { - // check if pathName is already set, and if not add it as a new entry + // check if pathName is already set, if not add it as a new entry, otherwise replace it UInt_t i=0; for (i=0; i> **WARNING** " << pathName.Data() << " already exists, will replace it." << endl; + if (!fQuite) + cerr << endl << ">> **WARNING** " << pathName.Data() << " already exists, will replace it." << endl; fMusrRunPhysQuantityObj[i].SetType("TMusrRunHeader"); fMusrRunPhysQuantityObj[i].SetValue(value); break; @@ -657,11 +657,12 @@ void TMusrRunHeader::Set(TString pathName, TMusrRunPhysicalQuantity value) */ void TMusrRunHeader::Set(TString pathName, TStringVector value) { - // check if pathName is already set, and if not add it as a new entry + // check if pathName is already set, if not add it as a new entry, otherwise replace it UInt_t i=0; for (i=0; i> **WARNING** " << pathName.Data() << " already exists, will replace it." << endl; + if (!fQuite) + cerr << endl << ">> **WARNING** " << pathName.Data() << " already exists, will replace it." << endl; fStringVectorObj[i].SetType("TStringVector"); fStringVectorObj[i].SetValue(value); break; @@ -690,11 +691,12 @@ void TMusrRunHeader::Set(TString pathName, TStringVector value) */ void TMusrRunHeader::Set(TString pathName, TIntVector value) { - // check if pathName is already set, and if not add it as a new entry + // check if pathName is already set, if not add it as a new entry, otherwise replace it UInt_t i=0; for (i=0; i> **WARNING** " << pathName.Data() << " already exists, will replace it." << endl; + if (!fQuite) + cerr << endl << ">> **WARNING** " << pathName.Data() << " already exists, will replace it." << endl; fIntVectorObj[i].SetType("TIntVector"); fIntVectorObj[i].SetValue(value); break; @@ -723,11 +725,12 @@ void TMusrRunHeader::Set(TString pathName, TIntVector value) */ void TMusrRunHeader::Set(TString pathName, TDoubleVector value) { - // check if pathName is already set, and if not add it as a new entry + // check if pathName is already set, if not add it as a new entry, otherwise replace it UInt_t i=0; for (i=0; i> **WARNING** " << pathName.Data() << " already exists, will replace it." << endl; + if (!fQuite) + cerr << endl << ">> **WARNING** " << pathName.Data() << " already exists, will replace it." << endl; fDoubleVectorObj[i].SetType("TDoubleVector"); fDoubleVectorObj[i].SetValue(value); break; @@ -1365,23 +1368,89 @@ TString TMusrRunHeader::GetType(TString str) } //-------------------------------------------------------------------------- -// ObjectPresent (private) +// UpdateFolder (private) //-------------------------------------------------------------------------- /** - *

+ *

Update folder structure * - * \param content - * \param path + *

return: + * - true if everything is all right + * - false otherwise + * + * \param treeObj to be updated + * \param path to be added within 'treeObj' */ -Int_t TMusrRunHeader::ObjectPresent(vector &content, TString &path) +bool TMusrRunHeader::UpdateFolder(TObject *treeObj, TString path) { - for (UInt_t i=0; iGetName() == path) { - return (Int_t)i; - } + if (path.First('/') == -1) // only value element left, hence nothing to be done + return true; + + TString str = GetFirst(path, '/'); + + TObject *obj = treeObj->FindObject(str); + + // remove the first path element + if (!RemoveFirst(path, '/')) { + cerr << endl << ">> TMusrRunHeader::FillFolder(): **ERROR** couldn't tokenize path!!" << endl; + return false; } - return -1; + if (!obj) { // required object not present, create it + TObjArray *oarray = new TObjArray(); + if (!oarray) { + cerr << endl << ">> TMusrRunHeader::FillFolder(): **ERROR** couldn't create header structure!!" << endl; + return false; + } + // set the name of the new TObjArray + oarray->SetName(str); + + if (!strcmp(treeObj->ClassName(), "TFolder")) + ((TFolder*)treeObj)->Add(oarray); + else // it is a TObjArray + ((TObjArray*)treeObj)->AddLast(oarray); + + return UpdateFolder(oarray, path); + } else { // object present, hence check rest of the path + return UpdateFolder(obj, path); + } +} + +//-------------------------------------------------------------------------- +// FindObject (private) +//-------------------------------------------------------------------------- +/** + *

Check if 'path' is present in 'treeObj' + * + *

return: + * - pointer to the 'path' object if present + * - otherwise return 0 + * + * \param treeObj to be searched + * \param path searched for within 'treeObj' + */ +TObject* TMusrRunHeader::FindObject(TObject *treeObj, TString path) +{ + Ssiz_t pos; + TObject *obj=0; + + // make sure that treeObj is either TFolder or TObjArray + if (strcmp(treeObj->ClassName(), "TFolder") && strcmp(treeObj->ClassName(), "TObjArray")) + return obj; + + pos = path.First('/'); + if (pos == -1) { // i.e. no sub-paths anymore + obj = treeObj->FindObject(path); + return obj; + } else { // sub-paths present + TString objName = GetFirst(path, '/'); // get first token of the path //.../ + obj = treeObj->FindObject(objName); + if (obj) { // object found, check for subPath object + RemoveFirst(path, '/'); // remove first tokens of the path + return FindObject(obj, path); + } else { // object not found + return obj; + } + } } //-------------------------------------------------------------------------- @@ -1536,22 +1605,36 @@ TObjString TMusrRunHeader::GetHeaderString(UInt_t idx) // RemoveFirst (private) //-------------------------------------------------------------------------- /** - *

+ *

Removes the first junk of a string up to 'splitter'. If 'splitter' is + * NOT present in the string, the string stays untouched and the routine + * returns false. * - * \param str - * \param splitter + * \param str string to be truncated + * \param splitter the start of the string up to the splitter character removed */ -void TMusrRunHeader::RemoveFirst(TString &str, const char splitter) +bool TMusrRunHeader::RemoveFirst(TString &str, const char splitter) { Ssiz_t idx = str.First(splitter); + if (idx == -1) + return false; + str.Remove(0, idx+1); + + return true; } //-------------------------------------------------------------------------- // GetFirst (private) //-------------------------------------------------------------------------- /** - *

+ *

Assuming a string built like 'this/is/a/string:with:diffrent:splitters'. + * Using as splitter '/', this routine would return 'this', it means get from str + * everything up to the first occurance of splitter. If splitter would be ':' + * in this example, the return string would be 'this/is/a/string'. + * + *

If splitter is not present in str the original str is returned. + * + *

return: first part of up to the splitter in struct * * \param str * \param splitter @@ -1561,71 +1644,10 @@ TString TMusrRunHeader::GetFirst(TString &str, const char splitter) TString result = str; Ssiz_t idx = str.First(splitter); - result.Remove(idx, str.Length()); + if (idx != -1) + result.Remove(idx, str.Length()); return result; } -//-------------------------------------------------------------------------- -// AddSubTrees (private) -//-------------------------------------------------------------------------- -/** - *

- * - * \param content - * \param pathName - */ -void TMusrRunHeader::AddSubTrees(TObjArray *content, TString pathName) -{ - // check if element is already present - TString objName = GetFirst(pathName, '/'); - if (!content->FindObject(objName.Data())) { // object array not present yet, add it - TObjArray *oarray = new TObjArray(); - oarray->SetName(objName); - content->AddLast(oarray); - } - - // check if more sub trees are needed - TObjArray *tok = pathName.Tokenize('/'); - - if (tok->GetEntries() > 2) { // still sub trees present - RemoveFirst(pathName, '/'); - AddSubTrees((TObjArray*)content->FindObject(objName.Data()), pathName); - } - - if (tok) - delete tok; -} - -//-------------------------------------------------------------------------- -// SetSubTreeObject (private) -//-------------------------------------------------------------------------- -/** - *

- * - * \param content - * \param ostr - */ -void TMusrRunHeader::SetSubTreeObject(TObjArray *content, TObjString ostr, Int_t idx) -{ - TObjArray *tok = fPathNameOrder[idx].Tokenize('/'); - TObjArray *pos = content; - - for (Int_t i=1; iGetEntries()-1; i++) { - pos = (TObjArray*)pos->FindObject(((TObjString*)tok->At(i))->GetString()); // go down the proper tree - if (pos == 0) { - cerr << endl << "TMusrRunHeader::SetSubTreeObject(): **ERROR** couldn't reach requested path: " << fPathNameOrder[idx]; - if (tok) - delete tok; - return; - } - } - TObjString *value = new TObjString(); - value = (TObjString*)ostr.Clone(); - pos->AddLast(value); - - if (tok) - delete tok; -} - // end --------------------------------------------------------------------- diff --git a/src/tests/MusrRoot/TMusrRunHeader.h b/src/tests/MusrRoot/TMusrRunHeader.h index cd642028..d997c253 100644 --- a/src/tests/MusrRoot/TMusrRunHeader.h +++ b/src/tests/MusrRoot/TMusrRunHeader.h @@ -32,6 +32,9 @@ #ifndef TMUSRRUNHEADER_H #define TMUSRRUNHEADER_H +#include +using namespace std; + #include #include #include @@ -122,8 +125,8 @@ private: class TMusrRunHeader : public TObject { public: - TMusrRunHeader(); - TMusrRunHeader(const char *fileName); + TMusrRunHeader(bool quite=false); + TMusrRunHeader(const char *fileName, bool quite=false); virtual ~TMusrRunHeader(); virtual TString GetFileName() { return fFileName; } @@ -155,6 +158,7 @@ public: virtual void DrawHeader(); private: + bool fQuite; TString fFileName; TString fVersion; @@ -166,7 +170,7 @@ private: vector< TMusrRunObject > fIntVectorObj; vector< TMusrRunObject > fDoubleVectorObj; - vector< TString > fPathNameOrder; ///< keeps the path-name as they or set and hence its ordering + vector< TString > fPathNameOrder; ///< keeps the path-name as they were created in ordered to keep ordering virtual void Init(TString str="n/a"); virtual void CleanUp(); @@ -179,13 +183,12 @@ private: virtual TString GetStrValue(TString str); virtual TString GetType(TString str); - virtual Int_t ObjectPresent(vector &content, TString &path); + virtual bool UpdateFolder(TObject *treeObj, TString path); + virtual TObject* FindObject(TObject *treeObj, TString path); virtual TObjString GetHeaderString(UInt_t idx); - virtual void RemoveFirst(TString &str, const char splitter); + virtual bool RemoveFirst(TString &str, const char splitter); virtual TString GetFirst(TString &str, const char splitter); - virtual void AddSubTrees(TObjArray *content, TString pathName); - virtual void SetSubTreeObject(TObjArray *content, TObjString ostr, Int_t idx); ClassDef(TMusrRunHeader, 1) }; diff --git a/src/tests/MusrRoot/root2xml.C b/src/tests/MusrRoot/root2xml.C index 2ddfb7c2..09584f93 100644 --- a/src/tests/MusrRoot/root2xml.C +++ b/src/tests/MusrRoot/root2xml.C @@ -135,7 +135,6 @@ void dumpObjArray(TObjArray *obj, UInt_t offset) xmlLabel = TString(obj->GetName()); if (xmlLabel.BeginsWith("Detector")) { xmlLabel.Remove(0, 8); // remove 'Detector' - cout << endl << "debug>> xmlLablel=" << xmlLabel; if (xmlLabel.IsDigit()) xmlLabel = "Detector"; else @@ -309,6 +308,11 @@ void getLabel(TString entry, TString &label) label.Remove(0, start+2); label.Remove(end-start-2, label.Length()); - // replace spaces through underscores - label.ReplaceAll(' ', '_'); + label.ReplaceAll(' ', '_'); // replace spaces through underscores + label.ReplaceAll('(', '_'); // replace '(' through underscores + label.ReplaceAll(')', '_'); // replace ')' through underscores + label.ReplaceAll('[', '_'); // replace '[' through underscores + label.ReplaceAll(']', '_'); // replace ']' through underscores + label.ReplaceAll('{', '_'); // replace '[' through underscores + label.ReplaceAll('}', '_'); // replace ']' through underscores } diff --git a/src/tests/MusrRoot/write_musrRoot_runHeader.cpp b/src/tests/MusrRoot/write_musrRoot_runHeader.cpp index 155101ed..b9592349 100644 --- a/src/tests/MusrRoot/write_musrRoot_runHeader.cpp +++ b/src/tests/MusrRoot/write_musrRoot_runHeader.cpp @@ -220,10 +220,6 @@ int main(int argc, char *argv[]) } // root file header related things -/* - TFolder *runHeader = gROOT->GetRootFolder()->AddFolder("RunHeader", "MusrRoot Run Header Info"); - gROOT->GetListOfBrowsables()->Add(runHeader, "RunHeader"); -*/ TFolder *runHeader = new TFolder("RunHeader", "MusrRoot Run Header Info"); if (header->FillFolder(runHeader)) {