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 <sstream>
19 #include <stdexcept>
20 // ============================================================================
21 // GaudiKernel
22 // ============================================================================
24 #include "GaudiKernel/DataObject.h"
27 #include "GaudiKernel/Property.h"
28 // ============================================================================
29 // Local
30 // ============================================================================
31 #include "HistogramSvc.h"
32 // ============================================================================
33 // Instantiation of a factory class used by clients
35 // ============================================================================
36 using namespace AIDA;
37 // ============================================================================
38 namespace
39 {
40  // ==========================================================================
41  inline std::string histoAddr( const std::string& name )
42  {
43  if ( 0 == name.find( "/stat/" ) ) {
44  return std::string( name, 6 );
45  }
46  return name;
47  }
48  // ==========================================================================
49  inline std::string histoAddr( const DataObject* obj, const std::string& rel )
50  {
51  if ( !obj ) {
52  return rel;
53  }
54  IRegistry* reg = obj->registry();
55  if ( !reg ) {
56  return rel;
57  }
58  const std::string& name = reg->identifier();
59  //
60  if ( rel.empty() ) {
61  return histoAddr( name );
62  }
63  if ( '/' == name[name.size() - 1] || '/' == rel[0] ) {
64  return histoAddr( name + rel );
65  }
66  return histoAddr( name + "/" + rel );
67  }
68  // ==========================================================================
69 }
70 //------------------------------------------------------------------------------
71 StatusCode HistogramSvc::registerObject( CSTR full, IBaseHistogram* obj )
72 {
74  return registerObject( split.first, split.second, obj );
75 }
76 //------------------------------------------------------------------------------
77 StatusCode HistogramSvc::registerObject( DataObject* pPar, CSTR obj, IBaseHistogram* hObj )
78 {
79  // Set the histogram id
80  if ( obj[0] == SEPARATOR ) {
81  // hObj->setTitle(obj.substr(1) + "|" + hObj->title());
82  if ( !hObj->annotation().addItem( "id", obj.substr( 1 ) ) ) hObj->annotation().setValue( "id", obj.substr( 1 ) );
83  } else {
84  // hObj->setTitle(obj + "|" + hObj->title());
85  if ( !hObj->annotation().addItem( "id", obj ) ) hObj->annotation().setValue( "id", obj );
86  }
87  // Register the histogram in the histogram data store
88  return DataSvc::registerObject( pPar, obj, __cast( hObj ) );
89 }
90 
91 // Helper for 2D projections
92 AIDA::IHistogram2D* HistogramSvc::i_project( CSTR nameAndTitle, const IHistogram3D& h, CSTR dir )
93 {
94  TH3D* h3d = Gaudi::getRepresentation<IHistogram3D, TH3D>( h );
95  if ( h3d ) {
96  TH2D* h2d = dynamic_cast<TH2D*>( h3d->Project3D( dir.c_str() ) );
97  if ( h2d ) {
99  if ( r.second && registerObject( nameAndTitle, r.second ).isSuccess() ) {
100  return r.second;
101  }
102  }
103  }
104  return nullptr;
105 }
106 
107 //------------------------------------------------------------------------------
108 // ASCII output
109 //------------------------------------------------------------------------------
110 std::ostream& HistogramSvc::print( IBaseHistogram* h, std::ostream& s ) const
111 {
112  Gaudi::HistogramBase* b = dynamic_cast<Gaudi::HistogramBase*>( h );
113  if ( b ) return b->print( s );
114  error() << "Unknown histogram type: Cannot cast to Gaudi::HistogramBase." << endmsg;
115  return s;
116 }
117 //------------------------------------------------------------------------------
118 std::ostream& HistogramSvc::write( IBaseHistogram* h, std::ostream& s ) const
119 {
120  Gaudi::HistogramBase* b = dynamic_cast<Gaudi::HistogramBase*>( h );
121  if ( b ) return b->write( s );
122  error() << "Unknown histogram type: Cannot cast to Gaudi::HistogramBase." << endmsg;
123  return s;
124 }
125 //------------------------------------------------------------------------------
126 int HistogramSvc::write( IBaseHistogram* h, const char* file_name ) const
127 {
128  Gaudi::HistogramBase* b = dynamic_cast<Gaudi::HistogramBase*>( h );
129  if ( b ) return b->write( file_name );
130  error() << "Unknown histogram type: Cannot cast to Gaudi::HistogramBase." << endmsg;
131  return 0;
132 }
133 //------------------------------------------------------------------------------
135 {
136  std::string tmp = full;
137  if ( tmp[0] != SEPARATOR ) {
138  tmp.insert( tmp.begin(), SEPARATOR );
139  tmp.insert( tmp.begin(), m_rootName.begin(), m_rootName.end() );
140  }
141  // Remove trailing "/" from newPath if it exists
142  if ( tmp.rfind( SEPARATOR ) == tmp.length() - 1 ) {
143  tmp.erase( tmp.rfind( SEPARATOR ), 1 );
144  }
145  int sep = tmp.rfind( SEPARATOR );
146  return {tmp.substr( 0, sep ), tmp.substr( sep )};
147 }
148 //------------------------------------------------------------------------------
150 {
151  std::string tmpPath = newPath;
152  if ( tmpPath[0] != SEPARATOR ) {
153  tmpPath.insert( tmpPath.begin(), SEPARATOR );
154  tmpPath.insert( tmpPath.begin(), m_rootName.begin(), m_rootName.end() );
155  }
156  // Remove trailing "/" from newPath if it exists
157  if ( tmpPath.rfind( SEPARATOR ) == tmpPath.length() - 1 ) {
158  tmpPath.erase( tmpPath.rfind( SEPARATOR ), 1 );
159  }
160  DataObject* pObject = nullptr;
161  StatusCode sc = DataSvc::findObject( tmpPath, pObject );
162  if ( sc.isSuccess() ) {
163  return pObject;
164  }
165  int sep = tmpPath.rfind( SEPARATOR );
166  std::string rest( tmpPath, sep + 1, tmpPath.length() - sep );
167  std::string subPath( tmpPath, 0, sep );
168  if ( 0 != sep ) {
169  createPath( subPath );
170  } else {
171  error() << "Unable to create the histogram path" << endmsg;
172  return nullptr;
173  }
174  pObject = createDirectory( subPath, rest );
175  return pObject;
176 }
177 //------------------------------------------------------------------------------
179 {
180  std::unique_ptr<DataObject> directory{new DataObject()};
181  if ( directory ) {
182  DataObject* pnode;
183  StatusCode status = DataSvc::retrieveObject( parentDir, pnode );
184  if ( status.isSuccess() ) {
185  status = DataSvc::registerObject( pnode, subDir, directory.get() );
186  if ( !status.isSuccess() ) {
187  error() << "Unable to create the histogram directory: " << parentDir << "/" << subDir << endmsg;
188  return nullptr;
189  }
190  } else {
191  error() << "Unable to create the histogram directory: " << parentDir << "/" << subDir << endmsg;
192  return nullptr;
193  }
194  }
195  return directory.release();
196 }
197 //------------------------------------------------------------------------------
199 {
200  setDataLoader( nullptr ).ignore();
201  clearStore().ignore();
202 }
203 //------------------------------------------------------------------------------
205 {
206  using Parser = Gaudi::Utils::AttribStringParser;
207  DataObject* pO = nullptr;
208  StatusCode status = this->findObject( m_rootName, pO );
209  if ( status.isSuccess() ) {
210  std::string::size_type loc = ident.find( " " );
211  std::string filename, auth, svc = "", typ = "";
212  std::string logname = ident.substr( 0, loc );
213  for ( auto attrib : Parser( ident.substr( loc + 1 ) ) ) {
214  switch (::toupper( attrib.tag[0] ) ) {
215  case 'F': // FILE='<file name>'
216  case 'D': // DATAFILE='<file name>'
217  filename = std::move( attrib.value );
218  break;
219  case 'T': // TYP='<HBOOK,ROOT,OBJY,...>'
220  typ = std::move( attrib.value );
221  break;
222  default:
223  break;
224  }
225  }
226  if ( typ.length() > 0 ) {
227  // Now add the registry entry to the store
228  std::string entryname = m_rootName;
229  entryname += '/';
230  entryname += logname;
231  GenericAddress* pA = nullptr;
232  switch (::toupper( typ[0] ) ) {
233  case 'H':
234  pA = new GenericAddress( HBOOK_StorageType, CLID_StatisticsFile, filename, entryname, 0, 'O' );
235  break;
236  case 'R':
237  pA = new GenericAddress( ROOT_StorageType, CLID_StatisticsFile, filename, entryname, 0, 'O' );
238  break;
239  }
240  if ( pA ) {
241  status = registerAddress( pO, logname, pA );
242  if ( status.isSuccess() ) {
243  info() << "Added stream file:" << filename << " as " << logname << endmsg;
244  return status;
245  }
246  pA->release();
247  }
248  }
249  }
250  error() << "Cannot add " << ident << " invalid filename!" << endmsg;
251  return StatusCode::FAILURE;
252 }
253 //------------------------------------------------------------------------------
255 {
256  StatusCode status = DataSvc::initialize();
257  // Set root object
258  if ( status.isSuccess() ) {
260  status = setRoot( "/stat", rootObj.get() );
261  if ( status.isSuccess() ) {
262  rootObj.release();
263  } else {
264  error() << "Unable to set hstogram data store root." << endmsg;
265  return status;
266  }
267  auto svc = service<IConversionSvc>( "HistogramPersistencySvc", true );
268  if ( svc ) {
269  setDataLoader( svc.get() ).ignore();
270  } else {
271  error() << "Could not find HistogramPersistencySvc." << endmsg;
272  return StatusCode::FAILURE;
273  }
274  // Connect all input streams (if any)
275  for ( auto& j : m_input ) {
276  status = connectInput( j );
277  if ( !status.isSuccess() ) return status;
278  }
279  }
280  if ( !m_defs1D.empty() ) {
281  info() << " Predefined 1D-Histograms: " << endmsg;
282  for ( const auto& ih : m_defs1D ) {
283  info() << " Path='" << ih.first << "'"
284  << " Description " << ih.second << endmsg;
285  }
286  }
287  return status;
288 }
289 //------------------------------------------------------------------------------
291 //------------------------------------------------------------------------------
292 IHistogram1D* HistogramSvc::sliceX( CSTR name, const IHistogram2D& h, int idxY1, int idxY2 )
293 {
294  std::pair<DataObject*, IHistogram1D*> o( nullptr, nullptr );
295  try {
296  int firstbin = Gaudi::Axis::toRootIndex( idxY1, h.yAxis().bins() );
297  int lastbin = Gaudi::Axis::toRootIndex( idxY2, h.yAxis().bins() );
298  o = Gaudi::slice1DX( name, h, firstbin, lastbin );
299  } catch ( ... ) {
300  throw GaudiException( "Cannot cast 2D histogram to H2D to create sliceX `" + name + "'!", "HistogramSvc",
302  }
303  if ( o.first && registerObject( name, (IBaseHistogram*)o.second ).isSuccess() ) {
304  return o.second;
305  }
306  delete o.first;
307  throw GaudiException( "Cannot create sliceX `" + name + "' of 2D histogram!", "HistogramSvc", StatusCode::FAILURE );
308 }
309 //------------------------------------------------------------------------------
310 IHistogram1D* HistogramSvc::sliceY( CSTR name, const IHistogram2D& h, int indexX1, int indexX2 )
311 {
312  std::pair<DataObject*, IHistogram1D*> o( nullptr, nullptr );
313  try {
314  int firstbin = Gaudi::Axis::toRootIndex( indexX1, h.xAxis().bins() );
315  int lastbin = Gaudi::Axis::toRootIndex( indexX2, h.xAxis().bins() );
316  o = Gaudi::slice1DY( name, h, firstbin, lastbin );
317  } catch ( ... ) {
318  throw GaudiException( "Cannot create sliceY `" + name + "'!", "HistogramSvc", StatusCode::FAILURE );
319  }
320  // name stands here for the fullPath of the histogram
321  if ( o.first && registerObject( name, (IBaseHistogram*)o.second ).isSuccess() ) {
322  return o.second;
323  }
324  delete o.first;
325  throw GaudiException( "Cannot create sliceY `" + name + "' of 2D histogram!", "HistogramSvc", StatusCode::FAILURE );
326 }
327 //------------------------------------------------------------------------------
328 bool HistogramSvc::destroy( IBaseHistogram* hist )
329 {
330  StatusCode sc = unregisterObject( dynamic_cast<IHistogram*>( hist ) );
331  if ( !sc.isSuccess() ) return false;
332  delete hist;
333  return true;
334 }
335 // ============================================================================
336 AIDA::IHistogram1D* HistogramSvc::book( DataObject* pPar, CSTR rel, CSTR title, DBINS( x ) )
337 {
338  if ( m_defs1D.empty() ) {
339  return i_book( pPar, rel, title, Gaudi::createH1D( title, BINS( x ) ) );
340  }
341  std::string hn = histoAddr( pPar, rel );
342  auto ifound = m_defs1D.find( hn );
343  if ( m_defs1D.end() == ifound ) {
344  return i_book( pPar, rel, title, Gaudi::createH1D( title, BINS( x ) ) );
345  }
346  if ( msgLevel( MSG::DEBUG ) ) {
347  debug() << " Redefine the parameters for the histogram '" + hn + "' to be " << ifound->second << endmsg;
348  }
349  m_mods1D.insert( hn );
350  return i_book( pPar, rel, ifound->second.title(),
351  Gaudi::createH1D( ifound->second.title(), ifound->second.bins(), ifound->second.lowEdge(),
352  ifound->second.lowEdge() ) );
353 }
354 // ============================================================================
355 // constructor
356 // ============================================================================
358 {
359  // Properties can be declared here
360  m_rootName = "/stat";
361  m_rootCLID = CLID_DataObject;
362  m_defs1D.declareUpdateHandler( &HistogramSvc::update1Ddefs, this );
363 }
364 // ============================================================================
365 // handler to be invoked for updating property m_defs1D
366 // ============================================================================
367 namespace
368 {
369  inline size_t removeLeading( HistogramSvc::Histo1DMap& m, const std::string& lead = "/stat/" )
370  {
371  for ( auto it = m.begin(); m.end() != it; ++it ) {
372  if ( 0 == it->first.find( lead ) ) {
373  std::string addr = std::string( it->first, lead.size() );
374  Gaudi::Histo1DDef hdef = it->second;
375  m.erase( it ); // remove
376  m[addr] = hdef; // insert
377  return 1 + removeLeading( m, lead ); // return
378  }
379  }
380  return 0;
381  }
382 }
383 // ============================================================================
385 {
386  // check and remove the leading '/stat/'
387  removeLeading( m_defs1D.value(), "/stat/" );
388 }
389 // ============================================================================
390 // finalize the service
392 {
393  if ( !m_mods1D.empty() ) {
394  if ( msgLevel( MSG::DEBUG ) ) debug() << " Substituted histograms #" << m_mods1D.size() << " : " << endmsg;
395  for ( const auto& ih : m_mods1D ) {
396  if ( msgLevel( MSG::DEBUG ) ) debug() << " Path='" << ih << "'";
397  auto im = m_defs1D.find( ih );
398  if ( m_defs1D.end() != im ) {
399  debug() << " " << im->second;
400  }
401  }
402  m_mods1D.clear();
403  }
404  return DataSvc::finalize();
405 }
406 // ============================================================================
407 // The END
408 // ============================================================================
Parse attribute strings allowing iteration over the various attributes.
Gaudi::Property< CLID > m_rootCLID
Definition: DataSvc.h:56
virtual std::ostream & write(std::ostream &s) const =0
Write (binary) histogram to output stream.
Gaudi::Property< Histo1DMap > m_defs1D
std::pair< DataObject *, AIDA::IHistogram1D * > slice1DY(const std::string &name, const AIDA::IHistogram2D &h, int firstbin, int lastbin)
Create 1D slice from 2D histogram.
T empty(T...args)
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 long HBOOK_StorageType
Definition: ClassID.h:56
std::set< std::string > m_mods1D
H1D * book(CSTR par, CSTR rel, CSTR title, DBINS(x)) override
Book histogram and register it with the histogram data store.
Definition: HistogramSvc.h:222
constexpr char SEPARATOR
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
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:74
unsigned long release() override
release reference to object
StatusCode setRoot(std::string root_name, DataObject *pRootObj) override
Initialize data store for new event by giving new event path and root object.
Definition: DataSvc.cpp:153
StatusCode findObject(IRegistry *pReg, CSTR path, P1D *&obj) override
Definition: HistogramSvc.h:901
StatusCode setDataLoader(IConversionSvc *svc, IDataProviderSvc *dpsvc=nullptr) override
IDataManagerSvc: IDataManagerSvc: Pass a default data loader to the service and optionally a data pro...
Definition: DataSvc.cpp:202
T rfind(T...args)
Gaudi::Property< std::string > m_rootName
Definition: DataSvc.h:57
~HistogramSvc() override
Destructor.
T * i_book(DataObject *pPar, CSTR rel, CSTR title, const std::pair< DataObject *, T * > &o)
Definition: HistogramSvc.h:172
StatusCode unregisterObject(Base *obj) override
Definition: HistogramSvc.h:729
T end(T...args)
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.
StatusCode registerAddress(const std::string &fullPath, IOpaqueAddress *pAddress) override
IDataManagerSvc: Register object address with the data store.
Definition: DataSvc.cpp:244
virtual std::ostream & print(std::ostream &s) const =0
Print histogram to output stream.
STL class.
StatusCode initialize() override
Initialise the service.
StatusCode connectInput(CSTR ident)
Connect input histogram file to the service.
GaudiKernel.
Definition: Fill.h:8
IRegistry * registry() const
Get pointer to Registry.
Definition: DataObject.h:74
#define DECLARE_COMPONENT(type)
Definition: PluginService.h:36
StatusCode finalize() override
finalize the service
STL class.
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
std::pair< std::string, std::string > i_splitPath(CSTR full)
Split full path into its components.
#define BINS(x)
Definition: HistogramSvc.h:40
std::ostream & print(Base *h, std::ostream &s=std::cout) const override
Print (ASCII) the 1D histogram into the output stream.
DataObject * createPath(CSTR newPath) override
Create all directories in a given full path.
virtual const id_type & identifier() const =0
Full identifier (or key)
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
H1D * sliceY(CSTR name, const H2D &h, int indexX) override
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
T erase(T...args)
std::pair< DataObject *, AIDA::IHistogram2D * > createH2D(const AIDA::IHistogram2D &hist)
Copy constructor.
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:180
The IRegistry represents the entry door to the environment any data object residing in a transient da...
Definition: IRegistry.h:22
const long ROOT_StorageType
Definition: ClassID.h:52
StatusCode finalize() override
Service initialization.
Definition: DataSvc.cpp:1188
PropertyBase base class allowing PropertyBase* collections to be "homogeneous".
Definition: Property.h:32
std::ostream & write(Base *h, std::ostream &s=std::cout) const override
Write (ASCII) the 1D histogram table into the output stream.
StatusCode registerObject(CSTR parent, CSTR rel, Base *obj) override
Definition: HistogramSvc.h:704
StatusCode retrieveObject(IRegistry *pDirectory, const std::string &path, DataObject *&pObject) override
Retrieve object from data store.
Definition: DataSvc.cpp:763
T move(T...args)
void update1Ddefs(Gaudi::Details::PropertyBase &)
handler to be invoked for updating property m_defs1D
T insert(T...args)
T find(T...args)
T size(T...args)
#define DBINS(x)
Definition: HistogramSvc.h:39
Common base class for all histograms Use is solely functional to minimize dynamic_casts inside Histog...
Definition: HistogramBase.h:22
STL class.
HistogramSvc(const std::string &name, ISvcLocator *svc)
Statndard Constructor.
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
StatusCode initialize() override
Service initialization.
Definition: DataSvc.cpp:1153
T begin(T...args)
T c_str(T...args)
H1D * sliceX(CSTR name, const H2D &h, int indexY) override
string s
Definition: gaudirun.py:245
T substr(T...args)
static int toRootIndex(int index, int nbins)
Definition: Axis.h:37
Gaudi::Property< DBaseEntries > m_input
DataObject * createDirectory(CSTR parentDir, CSTR subDir) override
Create a sub-directory in a directory.
void ignore() const
Definition: StatusCode.h:106
StatusCode reinitialize() override
Initialise the service.
MSG::Level msgLevel() const
get the output level from the embedded MsgStream
A DataObject is the base class of any identifiable object on any data store.
Definition: DataObject.h:30
STL class.
void toupper(std::string &s)
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:244
StatusCode clearStore() override
IDataManagerSvc: Remove all data objects in the data store.
Definition: DataSvc.cpp:114
HistogramSvc class definition.
Definition: HistogramSvc.h:52