330def _py_init_THistSvc():
331 import cppyy
332
333 _load_dict( "libGaudiKernelDict" )
334
335
336
337 global ITHistSvc
338 ITHistSvc = cppyy.gbl.ITHistSvc
339
340 ROOT = _import_ROOT()
341 @property
342 def _py_cache(self):
343 try:
344 return self.__py_cache
345 except AttributeError:
346 self.__py_cache = dict()
347 return self.__py_cache
348 ITHistSvc._py_cache = _py_cache
349
350
351
352 ITHistSvc._cpp_regHist = ITHistSvc.regHist
353 ITHistSvc._cpp_regGraph = ITHistSvc.regGraph
354 ITHistSvc._cpp_regEfficiency = ITHistSvc.regEfficiency
355 ITHistSvc._cpp_regTree = ITHistSvc.regTree
356
357 _cpp_getHist = ROOT.AthenaInternal.getHist
358 _cpp_getGraph = ROOT.AthenaInternal.getGraph
359 _cpp_getEfficiency = ROOT.AthenaInternal.getEfficiency
360 _cpp_getTree = ROOT.AthenaInternal.getTree
361
362 def book(self, oid, obj=None, *args, **kw):
363 """book a histogram, profile or tree
364 @param oid is the unique object identifier even across streams,
365 ie: 'stream'+'id'
366 @param obj either an already full-fledge constructed ROOT object
367 or None (then `*args` or `**kw` need to be correctly setup)
368 @param *args list of arguments to give to the constructor of the
369 ROOT object one wants to book
370 @param **kw a dictionary containing a key 'args' being the list of
371 arguments to the constructor of the ROOT objects one wants to
372 book
373 examples:
374 >>> th.book('/temp/1d/h1', 'TH1D', args=('h1','h1',100,0.,100.))
375 >>> th.book('/temp/1d/h2', ROOT.TH1D, args=('h2','h2',100,0.,100.))
376 >>> th.book('/temp/1d/h3', ROOT.TH1D, 'h3','h3',100,0.,100.)
377 >>> th.book('/temp/1d/h4', ROOT.TH1D('h4','h4',100,0.,100.))
378 >>> th.book('/temp/1d/h5', obj=ROOT.TH1D('h5','h5',100,0.,100.))
379 >>> th.book('/temp/1d/h6', klass='TH1D', args=('h6','h6',100,0.,100.))
380
381 >>> th.book('/temp/tree/t1', ROOT.TTree('t1','t1'))
382 >>> th.book('/temp/tree/t2', obj=ROOT.TTree('t2','t2'))
383 >>> th.book('/temp/tree/t3', klass='TTree', args=('t3','t3'))
384 """
385 _err = "please provide _either_ an already constructed ROOT object or"\
386 "a class name/class type (with appropriate arguments)"
387 klass = kw.get('klass', None)
388 assert not (obj is None and klass is None), _err
389 assert not (obj is not None and klass is not None), _err
390
391 if isinstance(obj, (str,type)):
392 klass=obj
393 obj=None
394 if obj:
395 if isinstance(obj, ROOT.TH1):
396
397 meth = self._cpp_regHist
398 elif isinstance(obj, (ROOT.TGraph,)):
399 meth = self._cpp_regGraph
400 elif isinstance(obj, (ROOT.TEfficiency,)):
401 meth = self._cpp_regEfficiency
402 elif isinstance(obj, (ROOT.TTree,)):
403 meth = self._cpp_regTree
404 else:
405 raise TypeError(
"invalid type '%r'"%
type(obj))
406 if meth(oid, obj).isSuccess():
407 self._py_cache[oid]=obj
408 return obj
409 raise RuntimeError('could not book object [%r]'%obj)
410
411 if klass:
412 if isinstance(klass, str):
413 klass = getattr(ROOT, klass)
414 if args:
415 return self.book(oid, obj=klass(*args))
416 if kw and 'args' in kw:
417 return self.book(oid, obj=klass(*kw['args']))
418 err = "invalid arguments: either provide a valid `*args` or "\
419 "a `**kw` containing a 'args' key"
420 raise RuntimeError(err)
421 raise RuntimeError("unforseen case: oid='%r' obj='%r' args='%r' "
422 "kw='%r'"%(oid,obj,args,kw))
423
424 ITHistSvc.book = book
425
426 def get(self, oid, klass=None):
427 """retrieve an already booked ROOT object.
428 If the object was booked on the C++ side, try to use the `klass` hint
429 (the usual string or type) to find the object in the correct 'folder'
430 (histograms, graphs or trees).
431 If `klass` is None, then go through all the folders iteratively (slow)
432 """
433 try:
434 return self._py_cache[oid]
435 except KeyError:
436 pass
437 def _get_helper(hsvc, func, oid, update_cache=True):
438 sc, o = func(hsvc, oid)
439 if sc.isSuccess():
440 if update_cache:
441 hsvc._py_cache[oid] = o
442 return o
443 return
444 if klass:
445 if isinstance(klass, str):
446 klass = getattr(ROOT, klass)
447 if issubclass(klass, (ROOT.TH1,)):
448 return _get_helper(self, _cpp_getHist, oid)
449 if issubclass(klass, (ROOT.TGraph,)):
450 return _get_helper(self, _cpp_getGraph, oid)
451 if issubclass(klass, (ROOT.TEfficiency,)):
452 return _get_helper(self, _cpp_getEfficiency, oid)
453 if issubclass(klass, (ROOT.TTree,)):
454 return _get_helper(self, _cpp_getTree, oid)
455 raise RuntimeError('unsupported type [%r]'%klass)
456
457
458
459
460
461 oids = [n for n in self.getHists() if n not in self._py_cache.keys()]
462 for name in oids:
463 obj = _get_helper(self, _cpp_getHist, name, update_cache=False)
464 if obj:
465
466 klass = getattr(ROOT, obj.ClassName())
467 obj = _get_helper(self, _cpp_getHist, name)
468
469
470 oids = [n for n in self.getGraphs() if n not in self._py_cache.keys()]
471 for name in oids:
472 _get_helper(self, _cpp_getGraph, name)
473
474
475 oids = [n for n in self.getEfficiencies() if n not in self._py_cache.keys()]
476 for name in oids:
477 _get_helper(self, _cpp_getEfficiency, name)
478
479
480 oids = [n for n in self.getTrees() if n not in self._py_cache.keys()]
481 for name in oids:
482 _get_helper(self, _cpp_getTree, name)
483
484
485 return self._py_cache[oid]
486
487 ITHistSvc.get = get
488 del get
489
490 def getitem(self, oid):
491 return self.get(oid)
492 ITHistSvc.__getitem__ = getitem
493 del getitem
494
495 def delitem(self, oid):
496 if isinstance(oid, str):
497 self.get(oid)
498 del self._py_cache[oid]
499 assert self.deReg(oid).isSuccess(), \
500 "could not remove object [%r]"%oid
501 return
502 ITHistSvc.__delitem__ = delitem
503
504 def setitem(self, k, v):
505 return self.book(k, obj=v)
506 ITHistSvc.__setitem__ = setitem
507 del setitem
508
509 def regObject(self, regFcn, oid, oid_type=None):
510 """Helper method to register object 'oid' using 'regFcn'."""
511 if oid_type is not None:
512 return self.book(oid,obj=oid_type)
513 if regFcn(self,oid).isSuccess():
514
515 return self.get(oid)
516 err = ''.join(['invalid arguments oid=',repr(oid),' oid_type=',
517 repr(oid_type)])
518 raise ValueError(err)
519
520 ITHistSvc.regHist = partialmethod(regObject, ITHistSvc._cpp_regHist)
521 ITHistSvc.regTree = partialmethod(regObject, ITHistSvc._cpp_regTree)
522 ITHistSvc.regEfficiency = partialmethod(regObject, ITHistSvc._cpp_regEfficiency)
523 ITHistSvc.regGraph = partialmethod(regObject, ITHistSvc._cpp_regGraph)
524 del regObject
525
526 def load(self, oid, oid_type):
527 """Helper method to load a given object `oid' from a stream, knowing
528 its type. `oid_type' is a string whose value is either:
529 - 'hist', to load any THx and TProfiles
530 - 'tree', to load TTrees
531 - 'efficiency', to load TEfficiency
532 - 'graph', to load TGraph and TGraphErrors
533 """
534 if oid_type == 'hist':
535 return self.regHist(oid)
536 elif oid_type == 'tree':
537 return self.regTree(oid)
538 elif oid_type == 'efficiency':
539 return self.regEfficiency(oid)
540 elif oid_type == 'graph':
541 return self.regGraph(oid)
542 else:
543 raise ValueError(f'oid_type (={oid_type}) MUST be one of hist, tree, efficiency, graph')
544
545 ITHistSvc.load = load
546 del load
547
548
549
550 for n in ('__contains__',
551 '__iter__',
552 '__len__',
553 'has_key',
554 'items', 'iteritems',
555 'iterkeys', 'itervalues',
556 'keys', 'values'):
557 code = """\
558def %s(self, *args, **kw):
559 return self._py_cache.%s(*args,**kw)
560ITHistSvc.%s = %s
561del %s""" % (n,n,n,n,n)
562 exec (code, globals(),locals())
563
564
565 def __bool__(self):
566 return self is not None
567 ITHistSvc.__bool__ = __bool__
568 del __bool__
569
570 def pop(self, k):
571 obj = self.get(k)
572 assert self.deReg(obj).isSuccess(), \
573 "could not remove object [%r]"%k
574 return obj
575 ITHistSvc.pop = pop
576 del pop
577
578 def popitem(self):
579 k = self.iterkeys().next()
580 return (k, self.pop(k))
581 ITHistSvc.popitem = popitem
582 del popitem
583
584
585
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)