added a validator program (musrRootValidation) for MusrRoot files.

This commit is contained in:
suter_a 2012-03-28 07:48:36 +00:00
parent 01696e3994
commit 5db90af1dc
6 changed files with 695 additions and 326 deletions

View File

@ -6,6 +6,7 @@
changes since 0.10.0 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 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 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. either via the histogram number or the index in the data vector.

View File

@ -366,6 +366,57 @@ AC_SUBST(BOOST_LIBS)
AC_SUBST(BOOST_CFLAGS) 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 -----------------------------------------------
dnl Check for ROOT dnl Check for ROOT
dnl ----------------------------------------------- dnl -----------------------------------------------
@ -1119,6 +1170,11 @@ if test "${BOOST_FOUND}" = "1"; then
else else
echo " BOOST header files found in ${BOOST_INCLUDE}" echo " BOOST header files found in ${BOOST_INCLUDE}"
fi 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 " ROOT found in ${ROOTLIBDIR%/lib}"
echo "" echo ""
if test "${PNEXUS_ENABLED}" -eq 1; then if test "${PNEXUS_ENABLED}" -eq 1; then

View File

@ -34,7 +34,7 @@ bin_PROGRAMS = musrfit musrview musrt0 msr2msr msr2data any2many
if PNEXUS_ENABLED if PNEXUS_ENABLED
bin_PROGRAMS += nexus_dump bin_PROGRAMS += nexus_dump
endif endif
bin_PROGRAMS += read_musrRoot_runHeader write_musrRoot_runHeader bin_PROGRAMS += read_musrRoot_runHeader write_musrRoot_runHeader musrRootValidation
musrfit_SOURCES = musrfit.cpp musrfit_SOURCES = musrfit.cpp
musrview_SOURCES = musrview.cpp musrview_SOURCES = musrview.cpp
@ -47,6 +47,7 @@ nexus_dump_SOURCES = nexus_dump.cpp
endif endif
read_musrRoot_runHeader_SOURCES = read_musrRoot_runHeader.cpp read_musrRoot_runHeader_SOURCES = read_musrRoot_runHeader.cpp
write_musrRoot_runHeader_SOURCES = write_musrRoot_runHeader.cpp write_musrRoot_runHeader_SOURCES = write_musrRoot_runHeader.cpp
musrRootValidation_SOURCES = musrRootValidation.cpp
xmldir = $(bindir) xmldir = $(bindir)
xml_DATA = musrfit_startup.xml 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_CXXFLAGS = $(LOCAL_BIN_CXXFLAGS)
AM_LDFLAGS = $(LOCAL_BIN_LDFLAGS) 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 if PNEXUS_ENABLED
INCLUDES += $(HDF5_CFLAGS) $(NEXUS_CFLAGS) $(PNEXUS_CXXFLAGS) INCLUDES += $(HDF5_CFLAGS) $(NEXUS_CFLAGS) $(PNEXUS_CXXFLAGS)
endif endif
LIBS = $(PMUSR_LIBS) $(USERFCN_LIBS) $(MUSR_ROOT_LIBS) $(LEM_LIBS) $(PSIBIN_LIBS) $(MUD_LIBS) $(PNEXUS_LIBS) \ 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) install-xmlDATA: $(xml_DATA)
test -z "$(xmldir)" || $(mkdir_p) "$(DESTDIR)$(xmldir)" test -z "$(xmldir)" || $(mkdir_p) "$(DESTDIR)$(xmldir)"

View File

@ -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<string> 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 version=\"1.0\" encoding=\"UTF-8\"?>");
xml_data.push_back("<MusrRoot xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"file:MusrRoot.xsd\">");
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("</MusrRoot>");
// 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<xml_data.size(); i++)
fout << xml_data[i] << endl;
fout.close();
}
void sort_histo_folders()
{
vector<string> temp_xml_data;
// first make a copy of the original xml_data
for (unsigned int i=0; i<xml_data.size(); i++)
temp_xml_data.push_back(xml_data[i]);
// remove SCAnaModule from temp_xml_data
unsigned int start = 0, end = 0;
for (unsigned int i=0; i<temp_xml_data.size(); i++) {
if (temp_xml_data[i].find("<SCAnaModule>") != string::npos)
start = i;
if (temp_xml_data[i].find("</SCAnaModule>") != 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<temp_xml_data.size(); i++) {
if (temp_xml_data[i].find("</DecayAnaModule>") != 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; i<temp_xml_data.size(); i++)
xml_data.push_back(temp_xml_data[i]);
// clean up
temp_xml_data.clear();
}
void dumpFolder(TFolder *folder, UInt_t offset)
{
TString offsetStr="";
for (UInt_t i=0; i<offset; i++)
offsetStr += " ";
TIter next = folder->GetListOfFolders();
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; i<offset; i++)
offsetStr += " ";
TObjString *tstr;
TString str, xmlStr, type, label, xmlLabel;
// check if the obj name is anything like DetectorXXX, where XXX is a number
xmlLabel = TString(obj->GetName());
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; i<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);
cout << endl << offsetStr << i << ": " << str;
xmlStr = offsetStr + " " + "<" + label + ">" + type + "</" + label + ">" ;
xml_data.push_back(xmlStr.Data());
}
}
xmlStr = offsetStr + "</" + xmlLabel + ">";
xml_data.push_back(xmlStr.Data());
}
void dumpEntry(TObject *obj, UInt_t offset)
{
TString offsetStr="";
for (UInt_t i=0; i<offset; i++)
offsetStr += " ";
TString nameTag(""), typeTag("");
switch (folderTag) {
case eDecayAnaModule:
nameTag = "HistoName";
typeTag = "HistoType";
break;
case eSlowControlAnaModule:
nameTag = "SlowControlName";
typeTag = "SlowControlType";
break;
case eUnkown:
default:
nameTag = "Name";
typeTag = "Type";
break;
}
TString str;
str = offsetStr + "<" + nameTag + ">";
str += obj->GetName();
str += "</" + nameTag + ">";
xml_data.push_back(str.Data());
str = offsetStr + "<" + typeTag + ">";
str += obj->ClassName();
str += "</" + typeTag + ">";
xml_data.push_back(str.Data());
}
void checkClass(TObject *obj, TString str, UInt_t offset)
{
TString offsetStr="";
for (UInt_t i=0; i<offset; i++)
offsetStr += " ";
if (str == "TFolder") {
TString xmlTagName(TString(obj->GetName()));
// 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 + "</" + xmlTagName + ">";
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 + "</" + entryTag + ">";
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
}

626
src/musrRootValidation.cpp Normal file
View File

@ -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 <iostream>
#include <fstream>
#include <vector>
#include <string>
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 <libxml/xmlreader.h>
#include <libxml/parser.h>
#include <libxml/xmlschemas.h>
#include "PMusr.h"
//-----------------------------------------------------------------------
/**
* <p>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<string> 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);
};
//-----------------------------------------------------------------------
/**
* <p>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("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
fXmlData.push_back("<MusrRoot xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"file:MusrRoot.xsd\">");
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("</MusrRoot>");
// 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; i<fXmlData.size(); i++)
fout << fXmlData[i] << endl;
fout.close();
fValid = true;
}
//-----------------------------------------------------------------------
/**
* <p>Destructor.
*/
PMusrRoot2Xml::~PMusrRoot2Xml()
{
if (!fKeep) {
TSystemFile sf(fXmlDumpFileName.Data(), "./");
sf.Delete();
}
}
//-----------------------------------------------------------------------
/**
* <p>Sorts the folders of the 'histos' TFolder in order to enforce the order
* according to:
* -# DecayAnaModule
* -# SCAnaModule
* -# all the rest
* <p>This is needed to the limited abilities of XML-Schema validation.
*/
void PMusrRoot2Xml::SortHistoFolders()
{
vector<string> temp_xml_data;
// first make a copy of the original fXmlData
for (unsigned int i=0; i<fXmlData.size(); i++)
temp_xml_data.push_back(fXmlData[i]);
// remove SCAnaModule from temp_xml_data
unsigned int start = 0, end = 0;
for (unsigned int i=0; i<temp_xml_data.size(); i++) {
if (temp_xml_data[i].find("<SCAnaModule>") != string::npos)
start = i;
if (temp_xml_data[i].find("</SCAnaModule>") != 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<temp_xml_data.size(); i++) {
if (temp_xml_data[i].find("</DecayAnaModule>") != 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; i<temp_xml_data.size(); i++)
fXmlData.push_back(temp_xml_data[i]);
// clean up
temp_xml_data.clear();
}
//-----------------------------------------------------------------------
/**
* <p>Dump 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; i<offset; i++)
offsetStr += " ";
TIter next = folder->GetListOfFolders();
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);
}
}
//-----------------------------------------------------------------------
/**
* <p>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; i<offset; i++)
offsetStr += " ";
TObjString *tstr;
TString str, xmlStr, type, label, xmlLabel;
// check if the obj name is anything like DetectorXXX, where XXX is a number
xmlLabel = TString(obj->GetName());
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 + "</" + label + ">" ;
fXmlData.push_back(xmlStr.Data());
}
}
xmlStr = offsetStr + "</" + xmlLabel + ">";
fXmlData.push_back(xmlStr.Data());
}
//-----------------------------------------------------------------------
/**
* <p>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<offset; i++)
offsetStr += " ";
TString nameTag(""), typeTag("");
switch (fFolderTag) {
case eDecayAnaModule:
nameTag = "HistoName";
typeTag = "HistoType";
break;
case eSlowControlAnaModule:
nameTag = "SlowControlName";
typeTag = "SlowControlType";
break;
case eUnkown:
default:
nameTag = "Name";
typeTag = "Type";
break;
}
if (fFolderTag == eDecayAnaModule)
fNoOfDecayHistos++;
TString str;
str = offsetStr + "<" + nameTag + ">";
str += obj->GetName();
str += "</" + nameTag + ">";
fXmlData.push_back(str.Data());
str = offsetStr + "<" + typeTag + ">";
str += obj->ClassName();
str += "</" + typeTag + ">";
fXmlData.push_back(str.Data());
}
//-----------------------------------------------------------------------
/**
* <p>
*
* \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; i<offset; i++)
offsetStr += " ";
if (str == "TFolder") {
TString xmlTagName(TString(obj->GetName()));
// 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 + "</" + xmlTagName + ">";
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 + "</" + entryTag + ">";
fXmlData.push_back(str.Data());
}
}
//-----------------------------------------------------------------------
/**
* <p>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";
}
}
//-----------------------------------------------------------------------
/**
* <p>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
}
//-----------------------------------------------------------------------
/**
* <p>Dump help information.
*/
void mrv_syntax()
{
cout << endl << "usage: musrRootValidation <musrRootFile> <musrRootSchema> [--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;
}
//-----------------------------------------------------------------------
/**
* <p>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;
}
//-----------------------------------------------------------------------
/**
* <p>
*/
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; i<argc; i++) {
if (!strcmp(argv[i], "--quiet"))
quiet = true;
if (!strcmp(argv[i], "--keep"))
keep = true;
}
PMusrRoot2Xml dump(argv[1], quiet, keep);
if (!dump.IsValid()) {
cerr << endl << "**ERROR** " << argv[1] << " is not a valid MusrRoot file." << endl << endl;
return -1;
}
xmlDocPtr doc = xmlParseFile(dump.GetXmlDumpFileName().Data());
if (doc == 0) {
cerr << endl << "**ERROR** couldn't get xmlDocPtr for xml-file " << argv[1] << "." << endl << endl;
return -1;
}
if (is_valid(doc, argv[2])) {
cout << endl << "xml-file " << argv[1] << " validates against xml-schema " << argv[2] << endl << endl;
} else {
cerr << endl << "**ERROR** xml-file " << argv[1] << " fails to validate against xml-schema " << argv[2] << endl << endl;
}
// do some further consistency checks
if (dump.GetNoOfDecayHistos() != dump.GetNoOfExpectedHistos()) {
cerr << endl << "**ERROR** number of histogram found in the DecayAnaModule is inconsistent";
cerr << endl << " with the header; found " << dump.GetNoOfDecayHistos() << " histograms in the DecayAnaModule,";
cerr << endl << " but in the header: No of Histos = " << dump.GetNoOfHistos() << "; # RedGreen Offsets = " << dump.GetNoOfRedGreenOffsets();
cerr << endl << endl;
}
if (dump.GetNoOfDecayHistos() != dump.GetNoOfDetectors()) {
cerr << endl << "**ERROR** number of histogram found in the DecayAnaModule is inconsistent";
cerr << endl << " with number of Detector entries in the RunHeader.";
cerr << endl << " Found " << dump.GetNoOfDecayHistos() << " histograms in the DecayAnaModule,";
cerr << endl << " but " << dump.GetNoOfDetectors() << " number of Detector entries.";
cerr << endl << endl;
}
return 0;
}

View File

@ -47,12 +47,12 @@ void analyticFakeData(const TString type)
gROOT->GetListOfBrowsables()->Add(histosFolder, "histos"); gROOT->GetListOfBrowsables()->Add(histosFolder, "histos");
decayAnaModule = histosFolder->AddFolder("DecayAnaModule", "muSR decay histograms"); decayAnaModule = histosFolder->AddFolder("DecayAnaModule", "muSR decay histograms");
UInt_t runNo = 3000; UInt_t runNo = 2001;
TString fileName, tstr, label, tstr1; TString fileName, tstr, label, tstr1;
fileName.Form("0%d.root", (Int_t)runNo); 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] = {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] = {3519.0, 3420.0, 3520.0, 3621.0, 3417.0, 3518.0, 3422.0, 3423.0}; // runNo: 1001 & 2001
if (!type.CompareTo("TLemRunHeader")) { if (!type.CompareTo("TLemRunHeader")) {
// feed run info header // feed run info header
@ -169,8 +169,10 @@ void analyticFakeData(const TString type)
const Double_t tau = 2197.019; // ns const Double_t tau = 2197.019; // ns
// asymmetry related stuff // asymmetry related stuff
const Double_t timeResolution = 0.1953125; // ns 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 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.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, 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,}; 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) const Double_t gamma = 0.00001355; // gamma/(2pi)