HistogramSvc.cpp
Go to the documentation of this file.
1 #ifdef __ICC
2 // disable icc remark #2259: non-pointer conversion from "X" to "Y" may lose significant bits
3 // TODO: To be removed, since it comes from ROOT TMathBase.h
4 #pragma warning(disable:2259)
5 #endif
6 #ifdef WIN32
7 // Disable warning
8 // warning C4996: 'sprintf': This function or variable may be unsafe.
9 // coming from TString.h
10 #pragma warning(disable:4996)
11 #endif
12 // ============================================================================
13 // Include files
14 // ============================================================================
15 // STD&STL
16 // ============================================================================
17 #include <cstdlib>
18 #include <stdexcept>
19 #include <sstream>
20 // ============================================================================
21 // GaudiKernel
22 // ============================================================================
23 #include "GaudiKernel/Property.h"
24 #include "GaudiKernel/AttribStringParser.h"
25 #include "GaudiKernel/MsgStream.h"
26 #include "GaudiKernel/DataObject.h"
27 #include "GaudiKernel/IConversionSvc.h"
28 #include "GaudiKernel/GenericAddress.h"
29 // ============================================================================
30 // Local
31 // ============================================================================
32 #include "HistogramSvc.h"
33 // ============================================================================
34 // Instantiation of a factory class used by clients
36 // ============================================================================
37 using namespace AIDA;
38 // ============================================================================
39 namespace
40 {
41  // ==========================================================================
42  inline std::string histoAddr
43  ( const std::string& name)
44  {
45  if ( 0 == name.find ( "/stat/" ) ){ return std::string( name , 6 ) ; }
46  return name ;
47  }
48  // ==========================================================================
49  inline std::string histoAddr
50  ( const DataObject* obj ,
51  const std::string& rel )
52  {
53  if ( !obj ) { return rel ; }
54  IRegistry* reg = obj->registry() ;
55  if ( !reg ) { return rel ; }
56  const std::string& name = reg->identifier() ;
57  //
58  if ( rel .empty() ) { return histoAddr ( name ) ; }
59  if ( '/' == name[name.size()-1] ||
60  '/' == rel[0] ) { return histoAddr ( name + rel ) ; }
61  return histoAddr ( name + "/" + rel ) ;
62  }
63  // ==========================================================================
64 }
65 //------------------------------------------------------------------------------
66 StatusCode HistogramSvc::registerObject(CSTR full, IBaseHistogram* obj) {
67  std::pair<std::string,std::string> split=i_splitPath(full);
68  return registerObject(split.first, split.second, obj);
69 }
70 //------------------------------------------------------------------------------
72 (DataObject* pPar,CSTR obj,IBaseHistogram* hObj) {
73  // Set the histogram id
74  if (obj[0] == SEPARATOR) {
75  // hObj->setTitle(obj.substr(1) + "|" + hObj->title());
76  if (!hObj->annotation().addItem("id", obj.substr(1)))
77  hObj->annotation().setValue("id", obj.substr(1));
78  }
79  else {
80  // hObj->setTitle(obj + "|" + hObj->title());
81  if (!hObj->annotation().addItem("id", obj))
82  hObj->annotation().setValue("id", obj);
83  }
84  // Register the histogram in the histogram data store
85  return DataSvc::registerObject(pPar,obj,__cast(hObj));
86 }
87 
88 // Helper for 2D projections
89 AIDA::IHistogram2D*
90 HistogramSvc::i_project(CSTR nameAndTitle,const IHistogram3D& h, CSTR dir) {
91  TH3D *h3d = Gaudi::getRepresentation<IHistogram3D,TH3D>(h);
92  if ( h3d ) {
93  TH2D *h2d = dynamic_cast<TH2D*>(h3d->Project3D(dir.c_str()));
94  if ( h2d ) {
95  std::pair<DataObject*,H2D*> r=Gaudi::createH2D(h2d);
96  if ( r.second && registerObject(nameAndTitle,r.second).isSuccess() ) {
97  return r.second;
98  }
99  }
100  }
101  return nullptr;
102 }
103 
104 //------------------------------------------------------------------------------
105 // ASCII output
106 //------------------------------------------------------------------------------
107 std::ostream& HistogramSvc::print(IBaseHistogram* h, std::ostream& s) const {
108  Gaudi::HistogramBase* b = dynamic_cast<Gaudi::HistogramBase*>(h);
109  if (b) return b->print(s);
110  MsgStream log(msgSvc(), name());
111  log << MSG::ERROR << "Unknown histogram type: Cannot cast to Gaudi::HistogramBase."
112  << endmsg;
113  return s;
114 }
115 //------------------------------------------------------------------------------
116 std::ostream& HistogramSvc::write(IBaseHistogram* h, std::ostream& s) const {
117  Gaudi::HistogramBase* b = dynamic_cast<Gaudi::HistogramBase*>(h);
118  if (b) return b->write(s);
119  MsgStream log(msgSvc(), name());
120  log << MSG::ERROR << "Unknown histogram type: Cannot cast to Gaudi::HistogramBase."
121  << endmsg;
122  return s;
123 }
124 //------------------------------------------------------------------------------
125 int HistogramSvc::write(IBaseHistogram* h, const char* file_name) const {
126  Gaudi::HistogramBase* b = dynamic_cast<Gaudi::HistogramBase*>(h);
127  if (b) return b->write(file_name);
128  MsgStream log(msgSvc(), name());
129  log << MSG::ERROR << "Unknown histogram type: Cannot cast to Gaudi::HistogramBase."
130  << endmsg;
131  return 0;
132 }
133 //------------------------------------------------------------------------------
134 std::pair<std::string,std::string> HistogramSvc::i_splitPath(CSTR full) {
135  std::string tmp = full;
136  if (tmp[0] != SEPARATOR) {
137  tmp.insert(tmp.begin(), SEPARATOR);
138  tmp.insert(tmp.begin(), m_rootName.begin(), m_rootName.end());
139  }
140  // Remove trailing "/" from newPath if it exists
141  if (tmp.rfind(SEPARATOR) == tmp.length()-1) {
142  tmp.erase(tmp.rfind(SEPARATOR),1);
143  }
144  int sep = tmp.rfind(SEPARATOR);
145  return { tmp.substr(0,sep), tmp.substr(sep) };
146 }
147 //------------------------------------------------------------------------------
149  std::string tmpPath = newPath;
150  if (tmpPath[0] != SEPARATOR) {
151  tmpPath.insert(tmpPath.begin(), SEPARATOR);
152  tmpPath.insert(tmpPath.begin(), m_rootName.begin(), m_rootName.end());
153  }
154  // Remove trailing "/" from newPath if it exists
155  if (tmpPath.rfind(SEPARATOR) == tmpPath.length()-1) {
156  tmpPath.erase(tmpPath.rfind(SEPARATOR),1);
157  }
158  DataObject* pObject = nullptr;
159  StatusCode sc = DataSvc::findObject(tmpPath, pObject);
160  if(sc.isSuccess()) {
161  return pObject;
162  }
163  int sep = tmpPath.rfind(SEPARATOR);
164  std::string rest(tmpPath, sep+1, tmpPath.length()-sep);
165  std::string subPath(tmpPath, 0, sep);
166  if(0 != sep) {
167  createPath(subPath);
168  }
169  else {
170  MsgStream log(msgSvc(), name());
171  log << MSG::ERROR << "Unable to create the histogram path" << endmsg;
172  return nullptr;
173  }
174  pObject = createDirectory(subPath, rest);
175  return pObject;
176 }
177 //------------------------------------------------------------------------------
179  std::unique_ptr<DataObject> directory{ new DataObject() };
180  if (directory) {
181  DataObject* pnode;
182  StatusCode status = DataSvc::retrieveObject(parentDir, pnode);
183  if(status.isSuccess()) {
184  status = DataSvc::registerObject(pnode, subDir, directory.get());
185  if (!status.isSuccess()) {
186  MsgStream log(msgSvc(), name());
187  log << MSG::ERROR << "Unable to create the histogram directory: "
188  << parentDir << "/" << subDir << endmsg;
189  return nullptr;
190  }
191  }
192  else {
193  MsgStream log(msgSvc(), name());
194  log << MSG::ERROR << "Unable to create the histogram directory: "
195  << parentDir << "/" << subDir << endmsg;
196  return nullptr;
197  }
198  }
199  return directory.release();
200 }
201 //------------------------------------------------------------------------------
203  setDataLoader( nullptr ).ignore();
204  clearStore().ignore();
205 }
206 //------------------------------------------------------------------------------
208  using Parser = Gaudi::Utils::AttribStringParser;
209  MsgStream log (msgSvc(), name());
210  DataObject* pO = nullptr;
211  StatusCode status = this->findObject(m_rootName, pO);
212  if (status.isSuccess()) {
213  std::string::size_type loc = ident.find(" ");
214  std::string filename, auth, svc = "", typ = "";
215  std::string logname = ident.substr(0, loc);
216  for (auto attrib: Parser(ident.substr(loc+1))) {
217  switch(::toupper(attrib.tag[0])) {
218  case 'F': // FILE='<file name>'
219  case 'D': // DATAFILE='<file name>'
220  filename = std::move(attrib.value);
221  break;
222  case 'T': // TYP='<HBOOK,ROOT,OBJY,...>'
223  typ = std::move(attrib.value);
224  break;
225  default:
226  break;
227  }
228  }
229  if (typ.length() > 0) {
230  // Now add the registry entry to the store
231  std::string entryname = m_rootName;
232  entryname += '/';
233  entryname += logname;
234  GenericAddress* pA = nullptr;
235  switch(::toupper(typ[0])) {
236  case 'H':
237  pA=new GenericAddress(HBOOK_StorageType,CLID_StatisticsFile,
238  filename,entryname,0,'O');
239  break;
240  case 'R':
241  pA=new GenericAddress(ROOT_StorageType,CLID_StatisticsFile,
242  filename,entryname,0,'O');
243  break;
244  }
245  if (pA) {
246  status = registerAddress(pO, logname, pA);
247  if (status.isSuccess()) {
248  log << MSG::INFO << "Added stream file:" << filename
249  << " as " << logname << endmsg;
250  return status;
251  }
252  pA->release();
253  }
254  }
255  }
256  log << MSG::ERROR << "Cannot add " << ident << " invalid filename!" << endmsg;
257  return StatusCode::FAILURE;
258 }
259 //------------------------------------------------------------------------------
261  MsgStream log(msgSvc(), name());
262  StatusCode status = DataSvc::initialize();
263  // Set root object
264  if (status.isSuccess()) {
265  std::unique_ptr<DataObject> rootObj{ new DataObject() };
266  status = setRoot("/stat", rootObj.get());
267  if (status.isSuccess()) {
268  rootObj.release();
269  } else {
270  log << MSG::ERROR << "Unable to set hstogram data store root." << endmsg;
271  return status;
272  }
273  auto svc = service<IConversionSvc>("HistogramPersistencySvc",true);
274  if ( svc ) {
275  setDataLoader( svc.get() ).ignore();
276  } else {
277  log << MSG::ERROR << "Could not find HistogramPersistencySvc." << endmsg;
278  return StatusCode::FAILURE;
279  }
280  // Connect all input streams (if any)
281  for (auto & j : m_input) {
282  status = connectInput(j);
283  if (!status.isSuccess()) return status;
284  }
285  }
286  if ( !m_defs1D.empty() )
287  {
288  log << MSG::INFO << " Predefined 1D-Histograms: " << endmsg ;
289  for ( const auto& ih : m_defs1D )
290  {
291  log << MSG::INFO
292  << " Path='" << ih.first << "'"
293  << " Description " << ih.second << endmsg ;
294  }
295  }
296  return status;
297 }
298 //------------------------------------------------------------------------------
300  return StatusCode::SUCCESS;
301 }
302 //------------------------------------------------------------------------------
303 IHistogram1D* HistogramSvc::sliceX
304 (CSTR name,const IHistogram2D& h,int idxY1,int idxY2) {
305  std::pair<DataObject*,IHistogram1D*> o(nullptr,nullptr);
306  try {
307  int firstbin = Gaudi::Axis::toRootIndex(idxY1,h.yAxis().bins());
308  int lastbin = Gaudi::Axis::toRootIndex(idxY2,h.yAxis().bins());
309  o = Gaudi::slice1DX(name, h, firstbin, lastbin);
310  }
311  catch ( ... ) {
312  throw GaudiException("Cannot cast 2D histogram to H2D to create sliceX `"
313  + name + "'!", "HistogramSvc", StatusCode::FAILURE);
314  }
315  if ( o.first && registerObject(name,(IBaseHistogram*)o.second).isSuccess() ) {
316  return o.second;
317  }
318  delete o.first;
319  throw GaudiException("Cannot create sliceX `" + name + "' of 2D histogram!",
320  "HistogramSvc", StatusCode::FAILURE);
321 }
322 //------------------------------------------------------------------------------
323 IHistogram1D*
324 HistogramSvc::sliceY(CSTR name,const IHistogram2D& h,int indexX1,int indexX2) {
325  std::pair<DataObject*,IHistogram1D*> o(nullptr,nullptr);
326  try {
327  int firstbin = Gaudi::Axis::toRootIndex( indexX1, h.xAxis().bins() );
328  int lastbin = Gaudi::Axis::toRootIndex( indexX2, h.xAxis().bins() );
329  o = Gaudi::slice1DY(name, h, firstbin, lastbin);
330  }
331  catch ( ... ) {
332  throw GaudiException("Cannot create sliceY `"+name+"'!",
333  "HistogramSvc",StatusCode::FAILURE);
334  }
335  // name stands here for the fullPath of the histogram
336  if ( o.first && registerObject(name,(IBaseHistogram*)o.second).isSuccess() ) {
337  return o.second;
338  }
339  delete o.first;
340  throw GaudiException("Cannot create sliceY `"+name+"' of 2D histogram!",
341  "HistogramSvc", StatusCode::FAILURE);
342 }
343 //------------------------------------------------------------------------------
344 bool HistogramSvc::destroy( IBaseHistogram* hist ) {
345  StatusCode sc = unregisterObject( dynamic_cast<IHistogram*>(hist) );
346  if ( !sc.isSuccess() ) return false;
347  delete hist;
348  return true;
349 }
350 // ============================================================================
351 AIDA::IHistogram1D* HistogramSvc::book
352 (DataObject* pPar, CSTR rel, CSTR title, DBINS(x))
353 {
354  if ( m_defs1D.empty () )
355  { return i_book(pPar,rel,title,Gaudi::createH1D(title, BINS(x))); }
356  std::string hn = histoAddr ( pPar , rel ) ;
357  auto ifound = m_defs1D.find( hn ) ;
358  if ( m_defs1D.end() == ifound )
359  { return i_book(pPar,rel,title,Gaudi::createH1D(title, BINS(x))); }
360  if (msgLevel(MSG::DEBUG)) {
361  MsgStream log ( msgSvc() , name() ) ;
362  log << MSG::DEBUG
363  << " Redefine the parameters for the histogram '" + hn + "' to be "
364  << ifound->second
365  << endmsg;
366  }
367  m_mods1D.insert ( hn ) ;
368  return i_book ( pPar , rel , ifound -> second.title () ,
370  ( ifound -> second.title () ,
371  ifound -> second.bins () ,
372  ifound -> second.lowEdge () ,
373  ifound -> second.lowEdge () ) ) ;
374 }
375 // ============================================================================
376 // constructor
377 // ============================================================================
378 HistogramSvc::HistogramSvc(const std::string& nam, ISvcLocator* svc)
379  : base_class(nam, svc)
380 {
381  // Properties can be declared here
382  m_rootName = "/stat";
383  m_rootCLID = CLID_DataObject;
384  declareProperty ( "Input", m_input);
385  declareProperty ( "Predefined1DHistos" , m_defs1D ,
386  "Histograms with predefined parameters" ) ;
387  // update handler
388  Property* p = Gaudi::Utils::getProperty ( this , "Predefined1DHistos" ) ;
390 
391 }
392 // ============================================================================
393 // handler to be invoked for updating property m_defs1D
394 // ============================================================================
395 namespace
396 {
397  inline size_t removeLeading
398  ( HistogramSvc::Histo1DMap& m , const std::string& lead = "/stat/")
399  {
400  for ( auto it = m.begin() ; m.end() != it ; ++it )
401  {
402  if ( 0 == it->first.find ( lead ) )
403  {
404  std::string addr = std::string( it->first , lead.size() ) ;
405  Gaudi::Histo1DDef hdef = it->second ;
406  m.erase ( it ) ; // remove
407  m[addr] = hdef ; // insert
408  return 1 + removeLeading ( m , lead ) ; // return
409  }
410  }
411  return 0 ;
412  }
413 }
414 // ============================================================================
416 {
417  // check and remove the leading '/stat/'
418  removeLeading ( m_defs1D , "/stat/" ) ;
419 }
420 // ============================================================================
421 // finalize the service
423 {
424  if ( !m_mods1D.empty() )
425  {
426  MsgStream log ( msgSvc () , name () ) ;
427  if (msgLevel(MSG::DEBUG))
428  log << MSG::DEBUG
429  << " Substituted histograms #" << m_mods1D.size() << " : " << endmsg;
430  for ( const auto& ih : m_mods1D )
431  {
432  if (msgLevel(MSG::DEBUG))
433  log << MSG::DEBUG << " Path='" << ih << "'" ;
434  auto im = m_defs1D.find( ih ) ;
435  if ( m_defs1D.end() != im ) { log << " " << im->second ; }
436  }
437  m_mods1D.clear() ;
438  }
439  return DataSvc::finalize () ;
440 }
441 // ============================================================================
442 // The END
443 // ============================================================================
std::pair< DataObject *, AIDA::IHistogram1D * > slice1DY(const std::string &name, const AIDA::IHistogram2D &h, int firstbin, int lastbin)
Create 1D slice from 2D histogram.
Definition of the MsgStream class used to transmit messages.
Definition: MsgStream.h:24
Define general base for Gaudi exception.
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition: ISvcLocator.h:25
const std::string & CSTR
Definition: HistogramSvc.h:58
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:244
std::set< std::string > m_mods1D
Definition: HistogramSvc.h:969
std::ostream & write(Base *h, std::ostream &s=std::cout) const override
Write (ASCII) the 1D histogram table into the output stream.
H1D * book(CSTR par, CSTR rel, CSTR title, DBINS(x)) override
Book histogram and register it with the histogram data store.
Definition: HistogramSvc.h:211
constexpr char SEPARATOR
virtual Property & declareUpdateHandler(std::function< void(Property &)> fun)
set new callback for update
Definition: Property.cpp:72
std::pair< DataObject *, AIDA::IHistogram1D * > createH1D(const AIDA::IHistogram1D &hist)
Copy constructor.
bool isSuccess() const
Test for a status code of SUCCESS.
Definition: StatusCode.h:76
unsigned long release() override
release reference to object
StatusCode findObject(IRegistry *pReg, CSTR path, P1D *&obj) override
Definition: HistogramSvc.h:676
virtual std::ostream & print(std::ostream &s) const =0
Print histogram to output stream.
virtual std::ostream & write(std::ostream &s) const =0
Write (binary) histogram to output stream.
~HistogramSvc() override
Destructor.
StatusCode unregisterObject(Base *obj) override
Definition: HistogramSvc.h:572
Generic Transient Address.
StatusCode registerObject(const std::string &fullPath, DataObject *pObject) override
Register object with the data store.
Definition: DataSvc.cpp:356
H2D * i_project(CSTR nameAndTitle, const H3D &h, CSTR dir)
Helper for 2D projections.
DBaseEntries m_input
Input streams.
Definition: HistogramSvc.h:138
StatusCode initialize() override
Initialise the service.
StatusCode connectInput(CSTR ident)
Connect input histogram file to the service.
GaudiKernel.
Definition: Fill.h:8
Histo1DMap m_defs1D
Definition: HistogramSvc.h:966
IRegistry * registry() const
Get pointer to Registry.
Definition: DataObject.h:74
StatusCode finalize() override
finalize the service
constexpr double second
std::pair< std::string, std::string > i_splitPath(CSTR full)
Split full path into its components.
#define BINS(x)
Definition: HistogramSvc.h:39
DataObject * createPath(CSTR newPath) override
Create all directories in a given full path.
bool destroy(IBaseHistogram *hist) override
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:26
constexpr double m
Definition: SystemOfUnits.h:93
void clear(STATE_TYPE _i=std::ios_base::failbit)
Definition: MsgStream.h:222
#define DECLARE_COMPONENT(type)
Definition: PluginService.h:36
H1D * sliceY(CSTR name, const H2D &h, int indexX) override
Definition: HistogramSvc.h:773
Simple helper class for description of 1D-histogram The class is targeted to act as the primary "hist...
Definition: HistoDef.h:30
StatusCode findObject(const std::string &fullPath, DataObject *&pObject) override
Find object identified by its full path in the data store.
Definition: DataSvc.cpp:828
std::pair< DataObject *, AIDA::IHistogram2D * > createH2D(const AIDA::IHistogram2D &hist)
Copy constructor.
void update1Ddefs(Property &)
handler to be invoked for updating property m_defs1D
std::pair< DataObject *, AIDA::IHistogram1D * > slice1DX(const std::string &name, const AIDA::IHistogram2D &h, int firstbin, int lastbin)
Create 1D slice from 2D histogram.
static DataObject * __cast(T *p)
Definition: HistogramSvc.h:170
The IRegistry represents the entry door to the environment any data object residing in a transient da...
Definition: IRegistry.h:22
const std::string CSTR
std::ostream & print(Base *h, std::ostream &s=std::cout) const override
Print (ASCII) the 1D histogram into the output stream.
StatusCode finalize() override
Service initialization.
Definition: DataSvc.cpp:1188
StatusCode registerObject(CSTR parent, CSTR rel, Base *obj) override
Definition: HistogramSvc.h:557
StatusCode retrieveObject(IRegistry *pDirectory, const std::string &path, DataObject *&pObject) override
Retrieve object from data store.
Definition: DataSvc.cpp:763
GAUDI_API Property * getProperty(const IProperty *p, const std::string &name)
simple function which gets the property with given name from the component
Definition: Property.cpp:278
const long HBOOK_StorageType
Definition: ClassID.h:56
Property base class allowing Property* collections to be "homogeneous".
Definition: Property.h:38
#define DBINS(x)
Definition: HistogramSvc.h:38
Common base class for all histograms Use is solely functional to minimize dynamic_casts inside Histog...
Definition: HistogramBase.h:22
HistogramSvc(const std::string &name, ISvcLocator *svc)
Statndard Constructor.
Base class used to extend a class implementing other interfaces.
Definition: extends.h:10
StatusCode initialize() override
Service initialization.
Definition: DataSvc.cpp:1153
H1D * sliceX(CSTR name, const H2D &h, int indexY) override
Definition: HistogramSvc.h:771
string s
Definition: gaudirun.py:245
static int toRootIndex(int index, int nbins)
Definition: Axis.h:37
virtual const id_type & identifier() const =0
Full identifier (or key)
DataObject * createDirectory(CSTR parentDir, CSTR subDir) override
Create a sub-directory in a directory.
StatusCode reinitialize() override
Initialise the service.
A DataObject is the base class of any identifiable object on any data store.
Definition: DataObject.h:30
void toupper(std::string &s)
std::map< std::string, Gaudi::Histo1DDef > Histo1DMap
Definition: HistogramSvc.h:961
const long ROOT_StorageType
Definition: ClassID.h:52
HistogramSvc class definition.
Definition: HistogramSvc.h:47