ATLAS Offline Software
Loading...
Searching...
No Matches
VectorFillerToolBase.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
10
11
16#include "GaudiKernel/System.h"
17#include "TClass.h"
18#include "TROOT.h"
19#include "TDataType.h"
20#include "TVirtualCollectionProxy.h"
21#include <cstring>
22#include <cassert>
23
24
25namespace D3PD {
26
27
31inline
36
37
41inline
43{
44 for (Var& v : *this) {
45 v.next();
46 }
47}
48
49
57 const std::string& name,
58 const IInterface* parent)
59 : AthAlgTool (type, name, parent),
60 m_metadata (),
61 m_prefix (),
62 m_blockFillers (this),
63 m_tree (0),
64 m_nrow (0),
65 m_nobj (0),
66 m_objIndex (0)
67{
68 declareProperty ("BlockFillers", m_blockFillers,
69 "List of contained block filler tools.");
70 declareProperty ("Prefix", m_prefix = "",
71 "Variable name prefix for the contained blocks.");
72 declareProperty ("NrowName", m_nrowName = "n",
73 "Name of the variable for the count of rows. "
74 "Omitted if empty.");
75 declareProperty ("NobjName", m_nobjName = "",
76 "Name of the variable for the count of objects. "
77 "Omitted if empty.");
78 declareProperty ("ObjIndexName", m_objIndexName = "",
79 "Name of the variable for the object index. "
80 "Omitted if empty.");
81}
82
83
87StatusCode
89{
90 CHECK( AthAlgTool::initialize() );
91 CHECK( m_blockFillers.retrieve() );
92 return StatusCode::SUCCESS;
93}
94
95
100{
101 // Don't clear the m_vars variable, because some memory will never be freed
102 // in that case...
103 return StatusCode::SUCCESS;
104}
105
106
113{
114 // Create the count/index variables.
115 if (!m_nrowName.empty()) {
116 CHECK( m_metadata.addVariable (m_prefix + m_nrowName, m_nrow,
117 "Number of ntuple rows.") );
118 CHECK( m_tree->addVariable (m_prefix + m_nrowName, m_nrow,
119 "Number of ntuple rows.") );
120 }
121 if (!m_nobjName.empty()) {
122 CHECK( m_metadata.addVariable (m_prefix + m_nobjName, m_nobj,
123 "Number of objects.") );
124 CHECK( m_tree->addVariable (m_prefix + m_nobjName, m_nobj,
125 "Number of objects.") );
126 }
127 if (!m_objIndexName.empty())
129 "Index of this object.") );
130
131 // Book child variables.
132 for (size_t i = 0; i < m_blockFillers.size(); i++)
133 CHECK( m_blockFillers[i]->book() );
134
135 return StatusCode::SUCCESS;
136}
137
138
146StatusCode
148{
149 m_tree = tree;
150
151 // Get the type of object we'll get from the iteration.
152 const std::type_info& ti = it.elementTypeinfo();
153
154 // Configure all child tools.
155 for (size_t i = 0; i < m_blockFillers.size(); i++)
156 CHECK( m_blockFillers[i]->configureD3PD (this, ti) );
157
158 return StatusCode::SUCCESS;
159}
160
161
167void VectorFillerToolBase::maybeExtend (size_t& n, size_t& sz)
168{
169 if (n >= sz) {
170 sz = std::max(static_cast<size_t>(16), 2*sz);
171 m_vars.resize_all (sz, n);
172 }
173}
174
175
195StatusCode
197 size_t objndx,
198 size_t& n,
199 size_t& sz,
200 const std::vector<unsigned long>& codes_in,
201 std::vector<unsigned long>& codes_out)
202{
203 codes_out.resize (m_blockFillers.size());
204
205 // Extend vectors if needed.
206 maybeExtend (n, sz);
207
208 // Loop over block fillers.
209 bool all_empty = true;
210 for (size_t j = 0; j < m_blockFillers.size(); j++) {
211 StatusCode scode =
212 m_blockFillers[j]->fillUntyped(obj,
213 codes_in[j] == IBlockFillerTool::AGAIN);
214 codes_out[j] = scode.getCode();
215 if (codes_out[j] != IBlockFillerTool::EMPTY)
216 all_empty = false;
218 }
219
220 // If all tools returned empty, then ignore this row.
221 // But don't ignore it if there are no block fillers at all
222 // (it may be that an associator tool will be filling variables).
223 if (!all_empty || m_blockFillers.empty()) {
224 if (m_objIndex)
225 *m_objIndex = objndx;
226
227 // Count rows and update variable pointers.
228 ++n;
229 m_vars.next_all();
230 }
231
232 return StatusCode::SUCCESS;
233}
234
235
243StatusCode
245{
246 // Set variable vectors to the expected size.
247 m_vars.resize_all (sizeHint);
248 size_t n = 0;
249 size_t nobj = 0;
250 size_t sz = sizeHint;
251
252 std::vector<unsigned long> codes_in;
253 std::vector<unsigned long> codes_out;
254
255 // Loop over objects.
256 // Note: @c nextUntyped may try to fill variables. Make sure there's space.
257 maybeExtend (n, sz);
258 while (const void* obj = it.nextUntyped() ) {
259 // AGAIN processing.
260 codes_in.clear();
261 codes_in.resize (m_blockFillers.size(), StatusCode(StatusCode::SUCCESS).getCode());
262 CHECK( fillOnce (obj, nobj, n, sz, codes_in, codes_out) );
263 codes_in = codes_out;
264 while (std::find (codes_out.begin(), codes_out.end(),
265 (unsigned long)IBlockFillerTool::AGAIN)
266 != codes_out.end())
267 {
268 CHECK( fillOnce (obj, nobj, n, sz, codes_in, codes_out) );
269 }
270
271 ++nobj;
272
273 it.releaseElementUntyped (obj);
274 maybeExtend (n, sz);
275 }
276
277 // Set vectors to the proper final size.
278 if (sz != n)
279 m_vars.resize_all (n);
280
281 // Save the counts.
282 if (m_nrow)
283 *m_nrow = n;
284 if (m_nobj)
285 *m_nobj = nobj;
286
287 return StatusCode::SUCCESS;
288}
289
290
305StatusCode
306VectorFillerToolBase::addVariable (const std::string& name,
307 const std::type_info& ti,
308 void* & ptr,
309 const std::string& docstring /*= ""*/,
310 const void* defval /*= 0*/)
311{
312 if (!m_tree) {
313 // Called from constructor --- just initialize pointer.
314 ptr = 0;
315 return StatusCode::SUCCESS;
316 }
317
318 // Default value handling.
319 size_t defsize = 0;
320 char* defcopied = 0;
321 if (defval) {
322 EDataType dt = TDataType::GetType (ti);
323 switch (dt) {
324 case kChar_t:
325 case kUChar_t:
326 case kShort_t:
327 case kUShort_t:
328 case kInt_t:
329 case kUInt_t:
330 case kLong_t:
331 case kULong_t:
332 case kFloat_t:
333 case kDouble_t:
334 case kDouble32_t:
335 case kchar:
336 case kBool_t:
337 case kLong64_t:
338 case kULong64_t:
339 case kFloat16_t:
340 // ok
341 break;
342
343 default:
344 REPORT_MESSAGE (MSG::ERROR)
345 << "Requested a default value for variable " << name
346 << " of type " << System::typeinfoName (ti)
347 << "; but default values are only supported for basic types.";
348 return StatusCode::FAILURE;
349 }
350
351 TDataType* tdt = gROOT->GetType (TDataType::GetTypeName (dt));
352 assert (tdt != 0);
353 defsize = tdt->Size();
354 defcopied = new char[defsize];
355 std::memcpy (defcopied, defval, defsize);
356 }
357
358 m_vars.push_back (Var (name, ti, ptr, docstring, defcopied, defsize));
359 CHECK( m_vars.back().init (&m_metadata, m_prefix) );
360 CHECK( m_vars.back().init (m_tree, m_prefix) );
361
362 return StatusCode::SUCCESS;
363}
364
365
382StatusCode
384 const std::type_info& /*ti*/,
385 void* & /*ptr*/,
386 const std::string& /*dim*/,
387 const std::string& /*docstring = ""*/,
388 const void* /*defval = 0*/)
389{
390 REPORT_MESSAGE(MSG::ERROR) << "addDimensionedVariable not yet implemented.";
391 return StatusCode::FAILURE;
392}
393
394
408VectorFillerToolBase::Var::Var (const std::string& name,
409 const std::type_info& ti,
410 void* & ptr,
411 const std::string& docstring,
412 char* defval,
413 size_t defsize)
414 : m_name (name),
415 m_ti (&ti),
416 m_addr (reinterpret_cast<char**> (&ptr)),
417 m_docstring (docstring),
418 m_proxy (0),
419 m_valdiff (0),
420 m_contptr (0),
421 m_default (defval),
422 m_defsize (defsize)
423{
424}
425
426
433 const std::string& prefix)
434{
435 // Get the name of the element variable.
436 std::string eltname = typeinfoToName (*m_ti);
437
438 // Use vector<int> instead of vector<bool>.
439 if (eltname == "bool")
440 eltname = "int";
441
442 // Construct the vector name.
443 std::string vname = "std::vector<" + eltname;
444 if (vname[vname.size()-1] == '>')
445 vname += ' ';
446 vname += '>';
447
448 // Fetch the root dictionary for the vector and find the proxy.
449 TClass* cls = TClass::GetClass (vname.c_str());
450 if (!cls) {
451 REPORT_MESSAGE(MSG::ERROR) << "Can't find TClass for type "
452 << vname
453 << " for variable "
454 << prefix + m_name;
455 return StatusCode::FAILURE;
456 }
457 m_proxy = cls->GetCollectionProxy();
458
459 if (!m_proxy) {
460 REPORT_MESSAGE(MSG::ERROR) << "Can't find root collection proxy for type "
461 << vname
462 << " for variable "
463 << prefix + m_name;
464 return StatusCode::FAILURE;
465 }
466
467 if (!m_proxy->GetCollectionClass() ||
468 !m_proxy->GetCollectionClass()->GetTypeInfo())
469 {
470 REPORT_MESSAGE(MSG::ERROR) << "Dictionary error for collection class "
471 << vname
472 << " for variable "
473 << prefix + m_name;
474 return StatusCode::FAILURE;
475 }
476
477 // Will be set at the first resize().
478 m_valdiff = 0;
479
480 // Create the vector.
481 m_contptr = 0;
482 return tree->addVariable (prefix + m_name,
483 *m_proxy->GetCollectionClass()->GetTypeInfo(),
484 m_contptr,
486}
487
488
494void VectorFillerToolBase::Var::resize (size_t sz, size_t pos)
495{
496 // Resize the vector.
497 TVirtualCollectionProxy::TPushPop pushcont (m_proxy, m_contptr);
498 size_t oldsz = m_proxy->Size();
499 m_proxy->Allocate (sz, false);
500 if (sz == 0) {
501 *m_addr = 0;
502 return;
503 }
504
505 char* begin = static_cast<char*> (m_proxy->At(0));
506
507 // Calculate the element offset, if needed.
508 // We do this by finding the difference between the first two
509 // elements, so we can only do this if there are at least two elements
510 // in the vector. But if there are less than two elements, then
511 // the offset doesn't matter anyway.
512 if (m_valdiff == 0 && sz >= 2)
513 m_valdiff = static_cast<char*> (m_proxy->At(1)) - begin;
514
515 // Set the pointer properly.
516 *m_addr = begin + pos * m_valdiff;
517
518 // Fill in default value if requested.
519 if (m_default && sz > oldsz) {
520 if (sz == 1) {
521 std::memcpy (begin, m_default, m_defsize);
522 }
523 else {
524 assert (m_defsize <= m_valdiff);
525 for (char* p = begin + oldsz * m_valdiff;
526 p < begin + sz * m_valdiff;
527 p += m_valdiff)
528 {
529 std::memcpy (p, m_default, m_defsize);
530 }
531 }
532 }
533}
534
535
542{
543 delete [] m_default;
544}
545
546
551{
552 for (Var& v : *this) {
553 v.free();
554 }
555}
556
557
563void VectorFillerToolBase::Vars::resize_all (size_t sz, size_t pos /*= 0*/)
564{
565 for (Var& v : *this) {
566 v.resize (sz, pos);
567 }
568}
569
570
571} // namespace D3PD
Helpers for checking error return status codes and reporting errors.
#define REPORT_MESSAGE(LVL)
Report a message.
#define CHECK(...)
Evaluate an expression and check for errors.
Abstract interface for iterating over a set of things.
static Double_t sz
Utility functions for converting between type names, type_info, and CLIDs.
Common code for wrapping filled variables up into a vector.
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
Common interface for adding a variable to a tuple.
StatusCode addVariable(const std::string &name, T *&ptr, const std::string &docstring="")
Add a variable to the tuple.
static StatusCode againok(StatusCode sc)
StatusCode check helper: change AGAIN or EMPTY to SUCCESS.
Abstract interface for iterating over a set of things.
Definition IIteration.h:41
Description for a single variable.
std::string m_docstring
Documentation string.
void resize(size_t sz, size_t pos)
Resize the vector.
std::string m_name
The variable name.
Var(const std::string &name, const std::type_info &ti, void *&ptr, const std::string &dim, char *defval, size_t defsize)
Constructor.
TVirtualCollectionProxy * m_proxy
The root collection proxy.
char * m_default
Pointer to the default value for this variable, if one has been requested.
StatusCode init(IAddVariable *tree, const std::string &prefix)
Initialize the variable.
size_t m_valdiff
Offset between collection elements.
void free()
Free allocated storage.
void next()
Move the variable pointer to the next element.
const std::type_info * m_ti
The type of the variable element (for each object).
char ** m_addr
Pointer to the variable pointer.
size_t m_defsize
Size of the object pointed to by m_default.
void * m_contptr
Pointer to the vector instance.
void maybeExtend(size_t &n, size_t &sz)
Extend vectors if needed.
IAddVariable * m_tree
The parent tree.
StatusCode doFill(IIteration &it, size_t sizeHint)
Fill objects from an IIteration.
Vars m_vars
All booked variables.
int * m_objIndex
Variable for the object index.
StatusCode doBook()
Declare tuple variables.
virtual StatusCode addDimensionedVariable(const std::string &name, const std::type_info &ti, void *&ptr, const std::string &dim, const std::string &docstring="", const void *defval=0)
Add a variable to the tuple.
StatusCode doConfigure(IAddVariable *tree, IIteration &it)
Configure the tool.
std::string m_nrowName
Property: Name of the variable for the count of rows.
int * m_nobj
Variable for the object count.
ObjectMetadata m_metadata
Metadata about the variables created by this tool.
virtual StatusCode addVariable(const std::string &name, const std::type_info &ti, void *&ptr, const std::string &docstring="", const void *defval=0)
Add a variable to the tuple.
ToolHandleArray< IBlockFillerTool > m_blockFillers
Property: The list of block filler tools.
virtual StatusCode initialize()
Standard Gaudi initialize method.
std::string m_prefix
Property: Variable prefix for this block.
StatusCode fillOnce(const void *obj, size_t objndx, size_t &n, size_t &sz, const std::vector< unsigned long > &codes_in, std::vector< unsigned long > &codes_out)
Make one loop over block filler tools.
virtual StatusCode finalize()
Standard Gaudi finalize method.
std::string m_objIndexName
Property: Name of the variable for the object index.
VectorFillerToolBase(const std::string &type, const std::string &name, const IInterface *parent)
Standard Gaudi tool constructor.
std::string m_nobjName
Property: Name of the variable for the count of objects.
int * m_nrow
Variable for the row count.
Block filler tool for noisy FEB information.
std::string typeinfoToName(const std::type_info &ti)
Convert from a type_info to a name.
void next_all()
Move all variable pointers to the next element.
void resize_all(size_t sz, size_t pos=0)
Resize all vector.
TChain * tree