diff --git a/ChangeLog b/ChangeLog index 46a6e108..4b6b756b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ changes since 0.10.0 =================================== +NEW 2012-03-28 added a validator program (musrRootValidation) for MusrRoot files. NEW 2012-03-22 added a first version of MusrRoot, the next muSR file format at PSI. At the same time a rewrite of the low run data handling has been done which enables a proper Red/Green handling with histogram sets addressable either via the histogram number or the index in the data vector. diff --git a/configure.ac b/configure.ac index bfe11f7d..e5b03472 100644 --- a/configure.ac +++ b/configure.ac @@ -366,6 +366,57 @@ AC_SUBST(BOOST_LIBS) AC_SUBST(BOOST_CFLAGS) +dnl ----------------------------------------------- +dnl Ask user for path to libxml2 +dnl ----------------------------------------------- +LIBXML2_FOUND=0 +AC_ARG_WITH([libxml2], + [AC_HELP_STRING([--with-libxml2],[path to the header files of the libxml2 installation, e.g. /usr/local/include])], + [LIBXML2_INCLUDE=$with_libxml2 + AC_MSG_CHECKING([whether libxml2 can be found at the specified location]) + if !(test -r ${LIBXML2_INCLUDE}/libxml/xmlreader.h) && !(test -r ${LIBXML2_INCLUDE}/libxml/parser.h) && !(test -r ${LIBXML2_INCLUDE}/libxml/xmlschemas.h); then + AC_MSG_RESULT([no]) + AC_MSG_ERROR([libxml2 cannot be found at the specified path!]) + fi + AC_MSG_RESULT([${LIBXML2_INCLUDE}])], + [PKG_CHECK_MODULES(LIBXML2, libxml2 >= 2.6.26, [LIBXML2_FOUND=1], + [AC_MSG_CHECKING([whether libxml2 is installed in a standard location]) + if test -r /usr/local/include/libxml2/libxml/xmlreader.h || test -r /usr/local/include/libxml2/libxml/parser.h || \ + test -r /usr/local/include/libxml2/libxml/xmlschemas.h; then + LIBXML2_INCLUDE="/usr/local/include/libxml2" + AC_MSG_RESULT([${LIBXML2_INCLUDE}]) + elif test -r /usr/include/libxml2/libxml/xmlreader.h || test -r /usr/include/libxml2/libxml/parser.h || \ + test -r /usr/include/libxml2/libxml/xmlschemas.h; then + LIBXML2_INCLUDE="/usr/include/libxml2" + AC_MSG_RESULT([${LIBXML2_INCLUDE}]) + elif test -r /sw/include/libxml2/libxml/xmlreader.h || test -r /sw/include/libxml2/libxml/parser.h || \ + test -r /sw/include/libxml2/libxml/xmlschemas.h; then + LIBXML2_INCLUDE="/sw/include/libxml2" + AC_MSG_RESULT([${LIBXML2_INCLUDE}]) + elif test -r /opt/local/include/libxml2/libxml/xmlreader.h || test -r /opt/local/include/libxml2/libxml/parser.h || \ + test -r /opt/local/include/libxml2/libxml/xmlschemas.h; then + LIBXML2_INCLUDE="/opt/local/include/libxml2" + AC_MSG_RESULT([${LIBXML2_INCLUDE}]) + else + AC_MSG_RESULT([no]) + AC_MSG_ERROR( + [libxml2 not found. Please call configure with the --with-libxml2 option. + This tells configure where to find the libxml2 headers, + e.g. --with-libxml2=/usr/local/include or --with-libxml2=/usr/include/libxml2] + ) + fi + ] + ) + ] +) +AC_SUBST(LIBXML2_INCLUDE) +if test "${LIBXML2_FOUND}" != "1"; then + LIBXML2_LIBS="" + LIBXML2_CFLAGS="-I${LIBXML2_INCLUDE}" +fi +AC_SUBST(LIBXML2_LIBS) +AC_SUBST(LIBXML2_CFLAGS) + dnl ----------------------------------------------- dnl Check for ROOT dnl ----------------------------------------------- @@ -1119,6 +1170,11 @@ if test "${BOOST_FOUND}" = "1"; then else echo " BOOST header files found in ${BOOST_INCLUDE}" fi +if test "${LIBXML2_FOUND}" = "1"; then + echo " LIBXML2 found in $(pkg-config --variable=prefix libxml2)" +else + echo " LIBXML2 found in ${LIBXML2_INCLUDE}" +fi echo " ROOT found in ${ROOTLIBDIR%/lib}" echo "" if test "${PNEXUS_ENABLED}" -eq 1; then diff --git a/src/Makefile.am b/src/Makefile.am index a93f0821..e401cb49 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -34,7 +34,7 @@ bin_PROGRAMS = musrfit musrview musrt0 msr2msr msr2data any2many if PNEXUS_ENABLED bin_PROGRAMS += nexus_dump endif -bin_PROGRAMS += read_musrRoot_runHeader write_musrRoot_runHeader +bin_PROGRAMS += read_musrRoot_runHeader write_musrRoot_runHeader musrRootValidation musrfit_SOURCES = musrfit.cpp musrview_SOURCES = musrview.cpp @@ -47,6 +47,7 @@ nexus_dump_SOURCES = nexus_dump.cpp endif read_musrRoot_runHeader_SOURCES = read_musrRoot_runHeader.cpp write_musrRoot_runHeader_SOURCES = write_musrRoot_runHeader.cpp +musrRootValidation_SOURCES = musrRootValidation.cpp xmldir = $(bindir) xml_DATA = musrfit_startup.xml @@ -55,13 +56,14 @@ LIBADD = $(PMUSR_LIBS) $(MUSR_ROOT_LIBS) $(LEM_LIBS) $(PSIBIN_LIBS) $(MUD_LIBS) AM_CXXFLAGS = $(LOCAL_BIN_CXXFLAGS) AM_LDFLAGS = $(LOCAL_BIN_LDFLAGS) -INCLUDES = $(MUSR_ROOT_CFLAGS) $(PMUSR_CFLAGS) $(FFTW3_CFLAGS) $(GSL_CFLAGS) $(BOOST_CFLAGS) $(ROOT_CFLAGS) +INCLUDES = $(MUSR_ROOT_CFLAGS) $(PMUSR_CFLAGS) $(FFTW3_CFLAGS) $(GSL_CFLAGS) $(BOOST_CFLAGS) $(ROOT_CFLAGS) \ + $(LIBXML2_CFLAGS) if PNEXUS_ENABLED INCLUDES += $(HDF5_CFLAGS) $(NEXUS_CFLAGS) $(PNEXUS_CXXFLAGS) endif LIBS = $(PMUSR_LIBS) $(USERFCN_LIBS) $(MUSR_ROOT_LIBS) $(LEM_LIBS) $(PSIBIN_LIBS) $(MUD_LIBS) $(PNEXUS_LIBS) \ - $(FFTW3_LIBS) $(GSL_LIBS) $(ROOT_LIBS) + $(FFTW3_LIBS) $(GSL_LIBS) $(ROOT_LIBS) $(LIBXML2_LIBS) install-xmlDATA: $(xml_DATA) test -z "$(xmldir)" || $(mkdir_p) "$(DESTDIR)$(xmldir)" diff --git a/src/external/MusrRoot/root2xml.C b/src/external/MusrRoot/root2xml.C deleted file mode 100644 index f24a5e08..00000000 --- a/src/external/MusrRoot/root2xml.C +++ /dev/null @@ -1,318 +0,0 @@ -// quick and dirty ROOT -> XML converter for MusrRoot -// needs to be rewritten as proper program. -// -// Andreas Suter -// -// $Id: root2xml.C 5092 2012-03-13 07:47:00Z nemu $ - -vector xml_data; - -enum EFolderTag {eUnkown, eDecayAnaModule, eSlowControlAnaModule}; -enum ERunHeaderTag {eUnkown, eRunInfo, eSampleEnvironmentInfo, eMagneticFieldEnvironmentInfo, eBeamlineInfo, eScalerInfo}; -EFolderTag folderTag = eUnkown; -ERunHeaderTag runHeaderTag = eUnkown; - -void root2xml(const char *filename, const char *xmlFilename) -{ - TFile f(filename); - - if (f.IsZombie()) { - cout << endl << "**ERROR** couldn't open file " << filename << endl; - return; - } - - xml_data.clear(); - - xml_data.push_back(""); - xml_data.push_back(""); - - TIter next = f.GetListOfKeys(); - TKey *key; - TFolder *folder; - TString str, tag; - - UInt_t offset = 2; - - while (key = (TKey*) next()) { - cout << endl << "name: " << key->GetName() << ", class name: " << key->GetClassName(); - str = key->GetClassName(); - if (str == "TFolder") { - folder = (TFolder*)key->ReadObj(); - checkClass(folder, str, offset); - } - } - cout << endl; - - f.Close(); - - xml_data.push_back(""); - - // the sort_histo_folders is needed since XML-Schema is not flexible enough to handle - // histos -| - // |- DecayAnaModule - // ... (any other analyzer module sub-folder - // |- SCAnaModule - // Hence SCAnaModule has artificially moved up, just to follow DecayAnaModule - sort_histo_folders(); - - ofstream fout(xmlFilename); - - for (UInt_t i=0; i temp_xml_data; - - // first make a copy of the original xml_data - for (unsigned int i=0; i") != string::npos) - start = i; - if (temp_xml_data[i].find("") != string::npos) - end = i+1; - } - if ((start > 0) && (end > 0)) - temp_xml_data.erase(temp_xml_data.begin()+start, temp_xml_data.begin()+end); - else // no SCAnaModule present, hence nothing to be done - return; - - // insert SCAnaModule just after DecayAnaModule - // 1st find end of DecayAnaModule - unsigned int pos = 0; - for (unsigned int i=0; i") != string::npos) { - pos = i+1; - break; - } - } - if (pos == 0) // something is wrong, hence to not do anything - return; - temp_xml_data.insert(temp_xml_data.begin()+pos, xml_data.begin()+start, xml_data.begin()+end); - - // copy temp_xml_data back into xml_data - xml_data.clear(); - for (unsigned int i=0; iGetListOfFolders(); - TObject *obj; - TString str; - while (obj = (TObject*) next()) { - cout << endl << offsetStr << "name: " << obj->GetName() << ", class name: " << obj->ClassName(); - str = obj->ClassName(); - checkClass(obj, str, offset); - } - -} - -void dumpObjArray(TObjArray *obj, UInt_t offset) -{ - TString offsetStr=""; - for (UInt_t i=0; iGetName()); - if (xmlLabel.BeginsWith("Detector")) { - xmlLabel.Remove(0, 8); // remove 'Detector' - if (xmlLabel.IsDigit()) - xmlLabel = "Detector"; - else - xmlLabel = TString(obj->GetName()); - } - - cout << endl << offsetStr << obj->GetName() << " (# " << obj->GetEntries() << ")"; - - xmlStr = offsetStr + "<" + xmlLabel + ">"; - xml_data.push_back(xmlStr.Data()); - - for (UInt_t i=0; iGetEntries(); i++) { - // check if entry is a TObjArray - type = obj->At(i)->ClassName(); - if (type == "TObjArray") { - dumpObjArray((TObjArray*)(obj->At(i)), offset+2); - } else { // not a TObjArray - tstr = (TObjString*) obj->At(i); - str = tstr->GetString(); - str.Remove(TString::kTrailing, '\n'); - - getType(str, type); - getLabel(str, label); - - cout << endl << offsetStr << i << ": " << str; - - xmlStr = offsetStr + " " + "<" + label + ">" + type + "" ; - xml_data.push_back(xmlStr.Data()); - } - } - - xmlStr = offsetStr + ""; - xml_data.push_back(xmlStr.Data()); -} - -void dumpEntry(TObject *obj, UInt_t offset) -{ - TString offsetStr=""; - for (UInt_t i=0; i"; - str += obj->GetName(); - str += ""; - xml_data.push_back(str.Data()); - - str = offsetStr + "<" + typeTag + ">"; - str += obj->ClassName(); - str += ""; - xml_data.push_back(str.Data()); -} - -void checkClass(TObject *obj, TString str, UInt_t offset) -{ - TString offsetStr=""; - for (UInt_t i=0; iGetName())); - - // set folder tag - if (!xmlTagName.CompareTo("DecayAnaModule")) - folderTag = eDecayAnaModule; - else if (!xmlTagName.CompareTo("SCAnaModule")) - folderTag = eSlowControlAnaModule; - else if (!xmlTagName.CompareTo("SCAnaModule")) - folderTag = eSlowControlAnaModule; - else - folderTag = eUnkown; - - offset += 2; - str = offsetStr + "<" + xmlTagName + ">"; - xml_data.push_back(str.Data()); - - dumpFolder((TFolder*)obj, offset); - - str = offsetStr + ""; - xml_data.push_back(str.Data()); - } else if (str == "TObjArray") { - offset += 2; - dumpObjArray((TObjArray*)obj, offset); - } else { - // filter out the proper entry tag - TString entryTag(""); - switch (folderTag) { - case eDecayAnaModule: - entryTag = TString("DecayHistoEntry"); - break; - case eSlowControlAnaModule: - entryTag = TString("SlowControlHistoEntry"); - break; - case eUnkown: - default: - entryTag = TString("Entry"); - break; - } - - offset += 2; - str = offsetStr + "<" + entryTag + ">"; - xml_data.push_back(str.Data()); - dumpEntry((TObjArray*)obj, offset); - str = offsetStr + ""; - xml_data.push_back(str.Data()); - } -} - -void getType(TString entry, TString &type) -{ - if (entry.Contains("-@0")) { - type = "TString"; - } else if (entry.Contains("-@1")) { - type = "Int_t"; - } else if (entry.Contains("-@2")) { - type = "Double_t"; - } else if (entry.Contains("-@3")) { - type = "TMusrRunPhysicalQuantity"; - } else if (entry.Contains("-@4")) { - type = "TStringVector"; - } else if (entry.Contains("-@5")) { - type = "TIntVector"; - } else if (entry.Contains("-@6")) { - type = "TDoubleVector"; - } else { - type = "TString"; - } - -} - -void getLabel(TString entry, TString &label) -{ - label="no_idea"; - - Ssiz_t start = entry.First('-'); - Ssiz_t end = entry.First(':'); - - if ((start == -1) || (end == -1)) - return; - - if (end - start < 2) - return; - - // check that '-@' is present in the string, otherwise it is NOT a known label - Ssiz_t pos = entry.First('@'); - if (pos < 1) - return; - if (entry(pos-1) != '-') - return; - - // cut out value - label = entry; - label.Remove(0, start+2); - label.Remove(end-start-2, label.Length()); - - 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/musrRootValidation.cpp b/src/musrRootValidation.cpp new file mode 100644 index 00000000..329e41e0 --- /dev/null +++ b/src/musrRootValidation.cpp @@ -0,0 +1,626 @@ +/*************************************************************************** + + musrRootValidation.cpp + + Author: Andreas Suter + e-mail: andreas.suter@psi.ch + + $Id$ + +***************************************************************************/ + +/*************************************************************************** + * Copyright (C) 2007-2012 by Andreas Suter * + * andreas.suter@psi.ch * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include +#include +#include +#include +using namespace std; + +#include "TString.h" +#include "TFile.h" +#include "TFolder.h" +#include "TKey.h" +#include "TObjArray.h" +#include "TObjString.h" +#include "TSystemFile.h" + +#include +#include +#include + +#include "PMusr.h" + +//----------------------------------------------------------------------- +/** + *

class which converts the structure of a ROOT file into a XML file. + */ +class PMusrRoot2Xml +{ + public: + PMusrRoot2Xml(const char *fileName, bool quiet, bool keep); + virtual ~PMusrRoot2Xml(); + + virtual Bool_t IsValid() { return fValid; } + virtual TString GetXmlDumpFileName() { return fXmlDumpFileName; } + virtual UInt_t GetNoOfDecayHistos() { return fNoOfDecayHistos; } + virtual UInt_t GetNoOfExpectedHistos() { return fNoOfRedGreenOffsets*fNoOfHistos; } + virtual UInt_t GetNoOfHistos() { return fNoOfHistos; } + virtual UInt_t GetNoOfRedGreenOffsets() { return fNoOfRedGreenOffsets; } + virtual UInt_t GetNoOfDetectors() { return fNoOfDetectors; } + + private: + enum EFolderTag {eUnkown, eDecayAnaModule, eSlowControlAnaModule}; + + vector fXmlData; ///< keeps the XML structure dump of the ROOT file + + Bool_t fQuiet; ///< true = suppress output while converting + Bool_t fKeep; ///< true = keep the XML dump file + Bool_t fValid; ///< true if the conversion was fine + TString fFileName; ///< file name of the ROOT file + TString fXmlDumpFileName; ///< file name of the XML dump file + EFolderTag fFolderTag; ///< switch indicating which kind of TFolder object is found + + UInt_t fNoOfDecayHistos; ///< number of decay histos in the DecayAnaModule + UInt_t fNoOfHistos; ///< number of histos from run header + UInt_t fNoOfRedGreenOffsets; ///< number of RedGreen offsets + UInt_t fNoOfDetectors; ///< number of detector entries in the header + + virtual void SortHistoFolders(); + virtual void DumpFolder(TFolder *folder, UInt_t offset); + virtual void DumpObjArray(TObjArray *obj, UInt_t offset); + virtual void DumpEntry(TObject *obj, UInt_t offset); + virtual void CheckClass(TObject *obj, TString str, UInt_t offset); + virtual void GetType(TString entry, TString &type); + virtual void GetLabel(TString entry, TString &label); +}; + +//----------------------------------------------------------------------- +/** + *

Constructor. Reads the ROOT file and converts its structure to an XML dump file. + */ +PMusrRoot2Xml::PMusrRoot2Xml(const char *fileName, bool quiet, bool keep) : fQuiet(quiet), fKeep(keep), fFileName(fileName) +{ + fXmlDumpFileName = "__MusrRootXmlDump.xml"; + fFolderTag = eUnkown; + fValid = false; + fXmlData.clear(); + fNoOfDecayHistos = 0; + fNoOfHistos = 0; + fNoOfRedGreenOffsets = 0; + fNoOfDetectors = 0; + + // read assumed MusrRoot file + TFile f(fFileName.Data()); + + if (f.IsZombie()) { + cerr << endl << "**ERROR** couldn't open file " << fFileName << endl; + return; + } + + fXmlData.push_back(""); + fXmlData.push_back(""); + + TIter next = f.GetListOfKeys(); + TKey *key; + TFolder *folder; + TString str, tag; + + UInt_t offset = 2; + + while ((key = (TKey*) next()) != 0) { + if (!fQuiet) cout << endl << "name: " << key->GetName() << ", class name: " << key->GetClassName(); + str = key->GetClassName(); + if (str == "TFolder") { + folder = (TFolder*)key->ReadObj(); + CheckClass(folder, str, offset); + } + } + if (!fQuiet) cout << endl; + + f.Close(); + + fXmlData.push_back(""); + + // the sort_histo_folders is needed since XML-Schema is not flexible enough to handle + // histos -| + // |- DecayAnaModule + // ... (any other analyzer module sub-folder + // |- SCAnaModule + // Hence SCAnaModule has artificially moved up, just to follow DecayAnaModule + SortHistoFolders(); + + ofstream fout(fXmlDumpFileName.Data()); + + for (UInt_t i=0; iDestructor. + */ +PMusrRoot2Xml::~PMusrRoot2Xml() +{ + if (!fKeep) { + TSystemFile sf(fXmlDumpFileName.Data(), "./"); + sf.Delete(); + } +} + +//----------------------------------------------------------------------- +/** + *

Sorts the folders of the 'histos' TFolder in order to enforce the order + * according to: + * -# DecayAnaModule + * -# SCAnaModule + * -# all the rest + *

This is needed to the limited abilities of XML-Schema validation. + */ +void PMusrRoot2Xml::SortHistoFolders() +{ + vector temp_xml_data; + + // first make a copy of the original fXmlData + for (unsigned int i=0; i") != string::npos) + start = i; + if (temp_xml_data[i].find("") != string::npos) + end = i+1; + } + if ((start > 0) && (end > 0)) + temp_xml_data.erase(temp_xml_data.begin()+start, temp_xml_data.begin()+end); + else // no SCAnaModule present, hence nothing to be done + return; + + // insert SCAnaModule just after DecayAnaModule + // 1st find end of DecayAnaModule + unsigned int pos = 0; + for (unsigned int i=0; i") != string::npos) { + pos = i+1; + break; + } + } + if (pos == 0) // something is wrong, hence to not do anything + return; + temp_xml_data.insert(temp_xml_data.begin()+pos, fXmlData.begin()+start, fXmlData.begin()+end); + + // copy temp_xml_data back into fXmlData + fXmlData.clear(); + for (unsigned int i=0; iDump folder structure. + * + * \param folder TFolder object found in the ROOT file + * \param offset needed to indent dump info + */ +void PMusrRoot2Xml::DumpFolder(TFolder *folder, UInt_t offset) +{ + TString offsetStr=""; + for (UInt_t i=0; iGetListOfFolders(); + TObject *obj; + TString str; + while ((obj = (TObject*) next()) != 0) { + if (!fQuiet) cout << endl << offsetStr << "name: " << obj->GetName() << ", class name: " << obj->ClassName(); + str = obj->ClassName(); + CheckClass(obj, str, offset); + } +} + +//----------------------------------------------------------------------- +/** + *

Dump object array content structure. + * + * \param obj object array found in the ROOT file + * \param offset needed to indent dump info + */ +void PMusrRoot2Xml::DumpObjArray(TObjArray *obj, UInt_t offset) +{ + TString offsetStr=""; + for (UInt_t i=0; iGetName()); + if (xmlLabel.BeginsWith("Detector")) { + xmlLabel.Remove(0, 8); // remove 'Detector' + if (xmlLabel.IsDigit()) + xmlLabel = "Detector"; + else + xmlLabel = TString(obj->GetName()); + } + + if (!fQuiet) cout << endl << offsetStr << obj->GetName() << " (# " << obj->GetEntries() << ")"; + if (!strcmp(obj->GetName(), "DetectorInfo")) + fNoOfDetectors = obj->GetEntries(); + + xmlStr = offsetStr + "<" + xmlLabel + ">"; + fXmlData.push_back(xmlStr.Data()); + + for (UInt_t i=0; i<(UInt_t)obj->GetEntries(); i++) { + // check if entry is a TObjArray + type = obj->At(i)->ClassName(); + if (type == "TObjArray") { + DumpObjArray((TObjArray*)(obj->At(i)), offset+2); + } else { // not a TObjArray + tstr = (TObjString*) obj->At(i); + str = tstr->GetString(); + str.Remove(TString::kTrailing, '\n'); + + GetType(str, type); + GetLabel(str, label); + + if (!fQuiet) cout << endl << offsetStr << i << ": " << str; + + // filter out the number of histograms according to the RunInfo + if (str.Contains("- No of Histos: ")) { + TString histoStr = str; + Ssiz_t pos = histoStr.Last(':'); + histoStr.Remove(0, pos+1); + pos = histoStr.Last('-'); + histoStr.Remove(pos); + fNoOfHistos = histoStr.Atoi(); + } + + // filter out the number of Red/Green offsets + if (str.Contains("- RedGreen Offsets: ")) { + TString redGreenStr = str; + Ssiz_t pos = redGreenStr.Last(':'); + redGreenStr.Remove(0, pos+1); + pos = redGreenStr.Last('-'); + redGreenStr.Remove(pos); + TObjArray *tokens = redGreenStr.Tokenize(";"); + if (tokens) + fNoOfRedGreenOffsets = tokens->GetEntries(); + if (tokens) delete tokens; + } + + xmlStr = offsetStr + " " + "<" + label + ">" + type + "" ; + fXmlData.push_back(xmlStr.Data()); + } + } + + xmlStr = offsetStr + ""; + fXmlData.push_back(xmlStr.Data()); +} + +//----------------------------------------------------------------------- +/** + *

Dump content. + * + * \param obj object found in the ROOT file to be dumped + * \param offset needed to indent dump info + */ +void PMusrRoot2Xml::DumpEntry(TObject *obj, UInt_t offset) +{ + TString offsetStr=""; + for (UInt_t i=0; i"; + str += obj->GetName(); + str += ""; + fXmlData.push_back(str.Data()); + + str = offsetStr + "<" + typeTag + ">"; + str += obj->ClassName(); + str += ""; + fXmlData.push_back(str.Data()); +} + +//----------------------------------------------------------------------- +/** + *

+ * + * \param obj object to be checked + * \param str tag telling what kind of object it is + * \param offset needed to indent dump info + */ +void PMusrRoot2Xml::CheckClass(TObject *obj, TString str, UInt_t offset) +{ + TString offsetStr=""; + for (UInt_t i=0; iGetName())); + + // set folder tag + if (!xmlTagName.CompareTo("DecayAnaModule")) + fFolderTag = eDecayAnaModule; + else if (!xmlTagName.CompareTo("SCAnaModule")) + fFolderTag = eSlowControlAnaModule; + else if (!xmlTagName.CompareTo("SCAnaModule")) + fFolderTag = eSlowControlAnaModule; + else + fFolderTag = eUnkown; + + offset += 2; + str = offsetStr + "<" + xmlTagName + ">"; + fXmlData.push_back(str.Data()); + + DumpFolder((TFolder*)obj, offset); + + str = offsetStr + ""; + fXmlData.push_back(str.Data()); + } else if (str == "TObjArray") { + offset += 2; + DumpObjArray((TObjArray*)obj, offset); + } else { + // filter out the proper entry tag + TString entryTag(""); + switch (fFolderTag) { + case eDecayAnaModule: + entryTag = TString("DecayHistoEntry"); + break; + case eSlowControlAnaModule: + entryTag = TString("SlowControlHistoEntry"); + break; + case eUnkown: + default: + entryTag = TString("Entry"); + break; + } + + offset += 2; + str = offsetStr + "<" + entryTag + ">"; + fXmlData.push_back(str.Data()); + DumpEntry((TObjArray*)obj, offset); + str = offsetStr + ""; + fXmlData.push_back(str.Data()); + } +} + +//----------------------------------------------------------------------- +/** + *

Checks to TMusrRunHeader type of the RunHeader entries. + * + * \param entry to be checked. + * \param type repesentation of the entry + */ +void PMusrRoot2Xml::GetType(TString entry, TString &type) +{ + if (entry.Contains("-@0")) { + type = "TString"; + } else if (entry.Contains("-@1")) { + type = "Int_t"; + } else if (entry.Contains("-@2")) { + type = "Double_t"; + } else if (entry.Contains("-@3")) { + type = "TMusrRunPhysicalQuantity"; + } else if (entry.Contains("-@4")) { + type = "TStringVector"; + } else if (entry.Contains("-@5")) { + type = "TIntVector"; + } else if (entry.Contains("-@6")) { + type = "TDoubleVector"; + } else { + type = "TString"; + } +} + +//----------------------------------------------------------------------- +/** + *

Filters from a TMusrRunHeader RunHeader entry the label. + * + * \param entry to be filtered + * \param label extracted from entry + */ +void PMusrRoot2Xml::GetLabel(TString entry, TString &label) +{ + label="no_idea"; + + Ssiz_t start = entry.First('-'); + Ssiz_t end = entry.First(':'); + + if ((start == -1) || (end == -1)) + return; + + if (end - start < 2) + return; + + // check that '-@' is present in the string, otherwise it is NOT a known label + Ssiz_t pos = entry.First('@'); + if (pos < 1) + return; + if (entry(pos-1) != '-') + return; + + // cut out value + label = entry; + label.Remove(0, start+2); + label.Remove(end-start-2, label.Length()); + + 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 +} + +//----------------------------------------------------------------------- +/** + *

Dump help information. + */ +void mrv_syntax() +{ + cout << endl << "usage: musrRootValidation [--quiet] [--keep] | --help | --version"; + cout << endl << " --quiet: do not dump the MusrRoot file info while validating"; + cout << endl << " --keep: do NOT delete the intermediate XML-file"; + cout << endl << " --help: shows this help"; + cout << endl << " --version: shows the current version"; + cout << endl << endl; +} + +//----------------------------------------------------------------------- +/** + *

Validates an XML file against a Schema. + * + * \param doc XML file object representation + * \param schema_filename Schema file name + */ +int is_valid(const xmlDocPtr doc, const char *schema_filename) +{ + xmlDocPtr schema_doc = xmlReadFile(schema_filename, NULL, XML_PARSE_NONET); + if (schema_doc == NULL) { + cerr << endl << "**ERROR** the schema (" << schema_filename << ") cannot be loaded or is not well-formed" << endl << endl; + return -1; + } + xmlSchemaParserCtxtPtr parser_ctxt = xmlSchemaNewDocParserCtxt(schema_doc); + if (parser_ctxt == NULL) { + cerr << endl << "**ERROR** unable to create a parser context for the schema." << endl << endl; + xmlFreeDoc(schema_doc); + return -2; + } + xmlSchemaPtr schema = xmlSchemaParse(parser_ctxt); + if (schema == NULL) { + cerr << endl << "**ERROR** the schema itself is not valid." << endl << endl; + xmlSchemaFreeParserCtxt(parser_ctxt); + xmlFreeDoc(schema_doc); + return -3; + } + xmlSchemaValidCtxtPtr valid_ctxt = xmlSchemaNewValidCtxt(schema); + if (valid_ctxt == NULL) { + cerr << endl << "**ERROR** unable to create a validation context for the schema." << endl << endl; + xmlSchemaFree(schema); + xmlSchemaFreeParserCtxt(parser_ctxt); + xmlFreeDoc(schema_doc); + return -4; + } + int is_valid = (xmlSchemaValidateDoc(valid_ctxt, doc) == 0); + xmlSchemaFreeValidCtxt(valid_ctxt); + xmlSchemaFree(schema); + xmlSchemaFreeParserCtxt(parser_ctxt); + xmlFreeDoc(schema_doc); + // force the return value to be non-negative on success + return is_valid ? 1 : 0; +} + +//----------------------------------------------------------------------- +/** + *

+ */ +int main(int argc, char *argv[]) +{ + if (argc==1) { + mrv_syntax(); + return -1; + } else if (argc==2) { + if (!strcmp(argv[1], "--version")) { + cout << endl << "musrRootValidation version: " << PMUSR_VERSION << " / $Id$" << endl << endl; + return 0; + } else { + mrv_syntax(); + return -1; + } + } + + // filter out possible options + bool quiet=false, keep=false; + for (int i=1; iGetListOfBrowsables()->Add(histosFolder, "histos"); decayAnaModule = histosFolder->AddFolder("DecayAnaModule", "muSR decay histograms"); - UInt_t runNo = 3000; + UInt_t runNo = 2001; TString fileName, tstr, label, tstr1; fileName.Form("0%d.root", (Int_t)runNo); - Double_t t0[8] = {3419.0, 3520.0, 3520.0, 3421.0, 3517.0, 3418.0, 3522.0, 3623.0}; // runNo: 1000 & 2000 -// Double_t t0[8] = {3519.0, 3420.0, 3520.0, 3621.0, 3417.0, 3518.0, 3422.0, 3423.0}; // runNo: 1001 & 2001 +// Double_t t0[8] = {3419.0, 3520.0, 3520.0, 3421.0, 3517.0, 3418.0, 3522.0, 3623.0}; // runNo: 1000 & 2000 + Double_t t0[8] = {3519.0, 3420.0, 3520.0, 3621.0, 3417.0, 3518.0, 3422.0, 3423.0}; // runNo: 1001 & 2001 if (!type.CompareTo("TLemRunHeader")) { // feed run info header @@ -169,8 +169,10 @@ void analyticFakeData(const TString type) const Double_t tau = 2197.019; // ns // asymmetry related stuff const Double_t timeResolution = 0.1953125; // ns - Double_t a0[8] = {0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12}; - Double_t a1[8] = {0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05}; +// Double_t a0[8] = {0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12}; + Double_t a0[8] = {0.22, 0.22, 0.22, 0.22, 0.22, 0.22, 0.22, 0.22}; +// Double_t a1[8] = {0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05, 0.05}; + Double_t a1[8] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; Double_t phase[8] = {5.0*TMath::Pi()/180.0, 50.0*TMath::Pi()/180.0, 95.0*TMath::Pi()/180.0, 140.0*TMath::Pi()/180.0, 185.0*TMath::Pi()/180.0, 230.0*TMath::Pi()/180.0, 275.0*TMath::Pi()/180.0, 320.0*TMath::Pi()/180.0,}; const Double_t gamma = 0.00001355; // gamma/(2pi)